diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-04-07 23:42:04 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2011-04-07 23:42:04 +0000 |
| commit | 945ce419c806c73d70203dec33ececafbe108a92 (patch) | |
| tree | cfcdb59bf47e9db7f9e01f7eebb59924bdeaea94 /src | |
| parent | Merge from trunk (again) (diff) | |
| parent | Extensions. SVG+media fix (see Bug #400356). (diff) | |
| download | inkscape-945ce419c806c73d70203dec33ececafbe108a92.tar.gz inkscape-945ce419c806c73d70203dec33ececafbe108a92.zip | |
Merge from trunk
(bzr r9508.1.73)
Diffstat (limited to 'src')
626 files changed, 21636 insertions, 11383 deletions
diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index 7ded3a637..4f7c3b6ef 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -6,109 +6,110 @@ rm -f 2geom/lib2geom.a $(2geom_lib2geom_a_OBJECTS) 2geom_lib2geom_a_SOURCES = \ - 2geom/basic-intersection.cpp \ - 2geom/bezier-clipping.cpp \ - 2geom/utils.cpp \ - 2geom/bezier-utils.cpp \ - 2geom/circle-circle.cpp \ - 2geom/circle.cpp \ - 2geom/circle.h \ - 2geom/conjugate_gradient.cpp \ - 2geom/convex-cover.cpp \ - 2geom/crossing.cpp \ - 2geom/curve-helpers.cpp \ - 2geom/d2-sbasis.cpp \ - 2geom/ellipse.cpp \ - 2geom/elliptical-arc.cpp \ - 2geom/geom.cpp \ - 2geom/line.cpp \ - 2geom/matrix.cpp \ - 2geom/nearest-point.cpp \ - 2geom/path-intersection.cpp \ - 2geom/path.cpp \ - 2geom/pathvector.cpp \ - 2geom/piecewise.cpp \ - 2geom/point.cpp \ - 2geom/poly.cpp \ - 2geom/quadtree.cpp \ - 2geom/region.cpp \ - 2geom/sbasis-2d.cpp \ - 2geom/sbasis-geometric.cpp \ - 2geom/sbasis-math.cpp \ - 2geom/sbasis-poly.cpp \ - 2geom/sbasis-roots.cpp \ - 2geom/sbasis-to-bezier.cpp \ - 2geom/sbasis.cpp \ - 2geom/shape.cpp \ - 2geom/solve-bezier-one-d.cpp \ - 2geom/solve-bezier-parametric.cpp \ - 2geom/svg-elliptical-arc.cpp \ - 2geom/svg-path-parser.cpp \ - 2geom/svg-path.cpp \ - 2geom/sweep.cpp \ - 2geom/transforms.cpp \ + 2geom/affine.h \ + 2geom/affine.cpp \ 2geom/angle.h \ + 2geom/basic-intersection.cpp \ 2geom/basic-intersection.h \ + 2geom/bezier-clipping.cpp \ + 2geom/bezier-curve.cpp \ 2geom/bezier-curve.h \ + 2geom/bezier.h \ 2geom/bezier-to-sbasis.h \ + 2geom/bezier-utils.cpp \ 2geom/bezier-utils.h \ - 2geom/bezier.h \ 2geom/choose.h \ + 2geom/circle-circle.cpp \ + 2geom/circle.cpp \ + 2geom/circle.h \ 2geom/circulator.h \ 2geom/concepts.h \ + 2geom/conjugate_gradient.cpp \ 2geom/conjugate_gradient.h \ + 2geom/convex-cover.cpp \ 2geom/convex-cover.h \ 2geom/coord.h \ + 2geom/crossing.cpp \ 2geom/crossing.h \ + 2geom/curve.cpp \ 2geom/curve.h \ 2geom/curves.h \ - 2geom/d2-sbasis.h \ 2geom/d2.h \ + 2geom/d2-sbasis.cpp \ + 2geom/d2-sbasis.h \ + 2geom/ellipse.cpp \ 2geom/ellipse.h \ + 2geom/elliptical-arc.cpp \ 2geom/elliptical-arc.h \ 2geom/exception.h \ 2geom/forward.h \ + 2geom/geom.cpp \ 2geom/geom.h \ 2geom/hvlinesegment.h \ 2geom/interval.h \ 2geom/isnan.h \ - 2geom/line.h \ 2geom/linear.h \ - 2geom/matrix.h \ + 2geom/line.cpp \ + 2geom/line.h \ + 2geom/nearest-point.cpp \ 2geom/nearest-point.h \ + 2geom/numeric/fitting-model.h \ + 2geom/numeric/fitting-tool.h \ + 2geom/numeric/linear_system.h \ + 2geom/numeric/matrix.cpp \ + 2geom/numeric/matrix.h \ + 2geom/numeric/vector.h \ 2geom/ord.h \ - 2geom/path-intersection.h \ + 2geom/path.cpp \ 2geom/path.h \ + 2geom/path-intersection.cpp \ + 2geom/path-intersection.h \ + 2geom/pathvector.cpp \ 2geom/pathvector.h \ + 2geom/piecewise.cpp \ 2geom/piecewise.h \ + 2geom/point.cpp \ + 2geom/point.h \ 2geom/point-l.h \ 2geom/point-ops.h \ - 2geom/point.h \ + 2geom/poly.cpp \ 2geom/poly.h \ + 2geom/quadtree.cpp \ 2geom/quadtree.h \ 2geom/ray.h \ 2geom/rect.h \ + 2geom/region.cpp \ 2geom/region.h \ + 2geom/sbasis-2d.cpp \ 2geom/sbasis-2d.h \ + 2geom/sbasis.cpp \ 2geom/sbasis-curve.h \ + 2geom/sbasis-geometric.cpp \ 2geom/sbasis-geometric.h \ + 2geom/sbasis.h \ + 2geom/sbasis-math.cpp \ 2geom/sbasis-math.h \ + 2geom/sbasis-poly.cpp \ 2geom/sbasis-poly.h \ + 2geom/sbasis-roots.cpp \ + 2geom/sbasis-to-bezier.cpp \ 2geom/sbasis-to-bezier.h \ - 2geom/sbasis.h \ + 2geom/shape.cpp \ 2geom/shape.h \ + 2geom/solve-bezier-one-d.cpp \ + 2geom/solve-bezier-parametric.cpp \ 2geom/solver.h \ 2geom/sturm.h \ + 2geom/svg-elliptical-arc.cpp \ 2geom/svg-elliptical-arc.h \ - 2geom/svg-path-parser.h \ + 2geom/svg-path.cpp \ 2geom/svg-path.h \ + 2geom/svg-path-parser.cpp \ + 2geom/svg-path-parser.h \ + 2geom/sweep.cpp \ 2geom/sweep.h \ + 2geom/transforms.cpp \ 2geom/transforms.h \ - 2geom/utils.h \ - 2geom/numeric/matrix.cpp \ - 2geom/numeric/fitting-model.h \ - 2geom/numeric/fitting-tool.h \ - 2geom/numeric/linear_system.h \ - 2geom/numeric/matrix.h \ - 2geom/numeric/vector.h + 2geom/utils.cpp \ + 2geom/utils.h diff --git a/src/2geom/affine.cpp b/src/2geom/affine.cpp new file mode 100644 index 000000000..925f43820 --- /dev/null +++ b/src/2geom/affine.cpp @@ -0,0 +1,489 @@ +#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 <2geom/utils.h> +#include <2geom/affine.h> +#include <2geom/point.h> + +namespace Geom { + +/** Creates a Affine 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 Affine. + */ +//NOTE: Inkscape's version is broken, so when including this version, you'll have to search for code with this func +Affine from_basis(Point const x_basis, Point const y_basis, Point const offset) { + return Affine(x_basis[X], x_basis[Y], + y_basis[X], y_basis[Y], + offset [X], offset [Y]); +} + +Point Affine::xAxis() const { + return Point(_c[0], _c[1]); +} + +Point Affine::yAxis() const { + return Point(_c[2], _c[3]); +} + +/** Gets the translation imparted by the Affine. + */ +Point Affine::translation() const { + return Point(_c[4], _c[5]); +} + +void Affine::setXAxis(Point const &vec) { + for(int i = 0; i < 2; i++) + _c[i] = vec[i]; +} + +void Affine::setYAxis(Point const &vec) { + for(int i = 0; i < 2; i++) + _c[i + 2] = vec[i]; +} + +/** Sets the translation imparted by the Affine. + */ +void Affine::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 Affine. 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 Affine::expansionX() const { + return sqrt(_c[0] * _c[0] + _c[1] * _c[1]); +} + +/** Calculates the amount of y-scaling imparted by the Affine. 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 Affine::expansionY() const { + return sqrt(_c[2] * _c[2] + _c[3] * _c[3]); +} + +void Affine::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 Affine::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 Affine. */ +void Affine::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; +} + +/** @brief Check whether this matrix is an identity matrix. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + 1 & 0 & 0 \\ + 0 & 1 & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$ */ +bool Affine::isIdentity(Coord eps) const { + return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) && + are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents a pure translation. + * Will return true for the identity matrix, which represents a zero translation. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + 1 & 0 & 0 \\ + 0 & 1 & 0 \\ + a & b & 1 \end{array}\right]\f$ */ +bool Affine::isTranslation(Coord eps) const { + return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) && + are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps); +} +/** @brief Check whether this matrix represents a pure nonzero translation. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + 1 & 0 & 0 \\ + 0 & 1 & 0 \\ + a & b & 1 \end{array}\right]\f$ and \f$a, b \neq 0\f$ */ +bool Affine::isNonzeroTranslation(Coord eps) const { + return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) && + are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) && + (!are_near(_c[4], 0.0, eps) || !are_near(_c[5], 0.0, eps)); +} + +/** @brief Check whether this matrix represents pure scaling. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & 0 & 0 \\ + 0 & b & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$. */ +bool Affine::isScale(Coord eps) const { + return are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents pure, nonzero scaling. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & 0 & 0 \\ + 0 & b & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$ and \f$a, b \neq 1\f$. */ +bool Affine::isNonzeroScale(Coord eps) const { + 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 + are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents pure uniform scaling. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & 0 & 0 \\ + 0 & a & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$. */ +bool Affine::isUniformScale(Coord eps) const { + return are_near(_c[0], _c[3], eps) && + are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents pure, nonzero uniform scaling. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & 0 & 0 \\ + 0 & a & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$ and \f$a \neq 1\f$. */ +bool Affine::isNonzeroUniformScale(Coord eps) const { + return !are_near(_c[0], 1.0, eps) && are_near(_c[0], _c[3], eps) && + are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents a pure rotation. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & b & 0 \\ + -b & a & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$ and \f$a^2 + b^2 = 1\f$. */ +bool Affine::isRotation(Coord eps) const { + return are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps) && + are_near(_c[0]*_c[0] + _c[1]*_c[1], 1.0, eps); +} + +/** @brief Check whether this matrix represents a pure, nonzero rotation. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & b & 0 \\ + -b & a & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$, \f$a^2 + b^2 = 1\f$ and \f$a \neq 1\f$. */ +bool Affine::isNonzeroRotation(Coord eps) const { + return !are_near(_c[0], 1.0, eps) && + are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps) && + are_near(_c[0]*_c[0] + _c[1]*_c[1], 1.0, eps); +} + +/** @brief Check whether this matrix represents pure horizontal shearing. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + 1 & 0 & 0 \\ + k & 1 & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$. */ +bool Affine::isHShear(Coord eps) const { + return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) && + are_near(_c[3], 1.0, eps) && are_near(_c[4], 0.0, eps) && + are_near(_c[5], 0.0, eps); +} +/** @brief Check whether this matrix represents pure, nonzero horizontal shearing. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + 1 & 0 & 0 \\ + k & 1 & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$ and \f$k \neq 0\f$. */ +bool Affine::isNonzeroHShear(Coord eps) const { + return are_near(_c[0], 1.0, eps) && are_near(_c[1], 0.0, eps) && + !are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents pure vertical shearing. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + 1 & k & 0 \\ + 0 & 1 & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$. */ +bool Affine::isVShear(Coord eps) const { + return are_near(_c[0], 1.0, eps) && are_near(_c[2], 0.0, eps) && + are_near(_c[3], 1.0, eps) && are_near(_c[4], 0.0, eps) && + are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents pure, nonzero vertical shearing. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + 1 & k & 0 \\ + 0 & 1 & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$ and \f$k \neq 0\f$. */ +bool Affine::isNonzeroVShear(Coord eps) const { + return are_near(_c[0], 1.0, eps) && !are_near(_c[1], 0.0, eps) && + are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) && + are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); +} + +/** @brief Check whether this matrix represents zooming. + * Zooming is any combination of translation and uniform scaling. It preserves angles, ratios + * of distances between arbitrary points and unit vectors of line segments. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & 0 & 0 \\ + 0 & a & 0 \\ + b & c & 1 \end{array}\right]\f$. */ +bool Affine::isZoom(Coord eps) const { + return are_near(_c[0], _c[3], eps) && are_near(_c[1], 0, eps) && are_near(_c[2], 0, eps); +} + +/** @brief Check whether the transformation preserves areas of polygons. + * This means that the transformation can be any combination of translation, rotation, + * shearing and squeezing (non-uniform scaling such that the absolute value of the product + * of Y-scale and X-scale is 1). + * @param eps Numerical tolerance + * @return True iff \f$|\det A| = 1\f$. */ +bool Affine::preservesArea(Coord eps) const +{ + return are_near(descrim2(), 1.0, eps); +} + +/** @brief Check whether the transformation preserves angles between lines. + * This means that the transformation can be any combination of translation, uniform scaling + * and rotation. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & b & 0 \\ + -b & a & 0 \\ + c & d & 1 \end{array}\right]\f$. */ +bool Affine::preservesAngles(Coord eps) const +{ + return are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps); +} + +/** @brief Check whether the transformation preserves distances between points. + * This means that the transformation can be any combination of translation and rotation. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & b & 0 \\ + -b & a & 0 \\ + c & d & 1 \end{array}\right]\f$ and \f$a^2 + b^2 = 1\f$. */ +bool Affine::preservesDistances(Coord eps) const +{ + return are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps) && + are_near(_c[0] * _c[0] + _c[1] * _c[1], 1.0, eps); +} + +/** @brief Check whether this transformation flips objects. + * A transformation flips objects if it has a negative scaling component. */ +bool Affine::flips() const { + // TODO shouldn't this be det() < 0? + return cross(xAxis(), yAxis()) > 0; +} + +/** @brief Check whether this matrix is singular. + * Singular matrices have no inverse, which means that applying them to a set of points + * results in a loss of information. + * @param eps Numerical tolerance + * @return True iff the determinant is near zero. */ +bool Affine::isSingular(Coord eps) const { + return are_near(det(), 0.0, eps); +} + +/** @brief Compute the inverse matrix. + * Inverse is a matrix (denoted \f$A^{-1}) such that \f$AA^{-1} = A^{-1}A = I\f$. + * Singular matrices have no inverse (for example a matrix that has two of its columns equal). + * For such matrices, the identity matrix will be returned instead. + * @param eps Numerical tolerance + * @return Inverse of the matrix, or the identity matrix if the inverse is undefined. + * @post (m * m.inverse()).isIdentity() == true */ +Affine Affine::inverse() const { + Affine d; + + double mx = std::max(fabs(_c[0]) + fabs(_c[1]), + fabs(_c[2]) + fabs(_c[3])); // a random matrix norm (either l1 or linfty + if(mx > 0) { + Geom::Coord const determ = det(); + if (!rel_error_bound(determ, mx*mx)) { + 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(); + } + } else { + d.setIdentity(); + } + + return d; +} + +/** @brief Calculate the determinant. + * @return \f$\det A\f$. */ +Coord Affine::det() const { + // TODO this can overflow + return _c[0] * _c[3] - _c[1] * _c[2]; +} + +/** @brief Calculate the square of the descriminant. + * This is simply the absolute value of the determinant. + * @return \f$|\det A|\f$. */ +Coord Affine::descrim2() const { + return fabs(det()); +} + +/** @brief Calculate the descriminant. + * If the matrix doesn't contain a non-uniform scaling or shearing component, this value says + * how will the length any line segment change after applying this transformation + * to arbitrary objects on a plane (the new length will be + * @code line_seg.length() * m.descrim()) @endcode. + * @return \f$\sqrt{|\det A|}\f$. */ +Coord Affine::descrim() const { + return sqrt(descrim2()); +} + +/** @brief Combine this transformation with another one. + * After this operation, the matrix will correspond to the transformation + * obtained by first applying the original version of this matrix, and then + * applying @a m. */ +Affine &Affine::operator*=(Affine const &o) { + Coord nc[6]; + for(int a = 0; a < 5; a += 2) { + for(int b = 0; b < 2; b++) { + nc[a + b] = _c[a] * o._c[b] + _c[a + 1] * o._c[b + 2]; + } + } + for(int a = 0; a < 6; ++a) { + _c[a] = nc[a]; + } + _c[4] += o._c[4]; + _c[5] += o._c[5]; + return *this; +} + +//TODO: What's this!?! +Affine elliptic_quadratic_form(Affine const &m) { + double od = m[0] * m[1] + m[2] * m[3]; + Affine ret (m[0]*m[0] + m[1]*m[1], od, + od, m[2]*m[2] + m[3]*m[3], + 0, 0); + return ret; // allow NRVO +} + +Eigen::Eigen(Affine 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]))); + } +} + +static void quadratic_roots(double q0, double q1, double q2, int &n, double&r0, double&r1) { + std::vector<double> r; + if(q2 == 0) { + if(q1 == 0) { // zero or infinite roots + n = 0; + } else { + n = 1; + r0 = -q0/q1; + } + } else { + double desc = q1*q1 - 4*q2*q0; + if (desc < 0) + n = 0; + else if (desc == 0) { + n = 1; + r0 = -q1/(2*q2); + } else { + n = 2; + desc = std::sqrt(desc); + double t = -0.5*(q1+sgn(q1)*desc); + r0 = t/q2; + r1 = q0/t; + } + } +} + +Eigen::Eigen(double m[2][2]) { + double const B = -m[0][0] - m[1][1]; + double const C = m[0][0]*m[1][1] - m[1][0]*m[0][1]; + //double const desc = B*B-4*C; + //double t = -0.5*(B+sgn(B)*desc); + int n; + values[0] = values[1] = 0; + quadratic_roots(C, B, 1, n, values[0], values[1]); + for (int i = 0; i < n; i++) + vectors[i] = unit_vector(rot90(Point(m[0][0]-values[i], m[0][1]))); + for (int i = n; i < 2; i++) + vectors[i] = Point(0,0); +} + +} //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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/affine.h b/src/2geom/affine.h new file mode 100644 index 000000000..277d8b4ee --- /dev/null +++ b/src/2geom/affine.h @@ -0,0 +1,252 @@ +/** \file + * \brief 3x3 affine transformation matrix. + *//* + * Main authors: + * Lauris Kaplinski <lauris@kaplinski.com> (Original NRAffine definition and related macros) + * Nathan Hurst <njh@mail.csse.monash.edu.au> (Geom::Affine class version of the above) + * Michael G. Sloan <mgsloan@gmail.com> (reorganization and additions) + * Krzysztof KosiĆski <tweenk.pl@gmail.com> (removal of boilerplate, docs) + * + * This code is in public domain. + */ + +#ifndef SEEN_LIB2GEOM_MATRIX_H +#define SEEN_LIB2GEOM_MATRIX_H + +#include <boost/operators.hpp> +#include <2geom/forward.h> +#include <2geom/point.h> +#include <2geom/utils.h> + +namespace Geom { + +/** + * @brief 3x3 matrix representing an affine transformation. + * + * Affine transformations on elements of a vector space are transformations which can be + * expressed in terms of matrix multiplication followed by addition + * (\f$x \mapsto A x + b\f$). They can be thought of as generalizations of linear functions + * (\f$y = a x + b\f$) to vector spaces. Affine transformations of points on a 2D plane preserve + * the following properties: + * + * - Colinearity: if three points lie on the same line, they will still be colinear after + * an affine transformation. + * - Ratios of distances between points on the same line are preserved + * - Parallel lines remain parallel. + * + * All affine transformations on 2D points can be written as combinations of scaling, rotation, + * shearing and translation. They can be represented as a combination of a vector and a 2x2 matrix, + * but this form is inconvenient to work with. A better solution is to represent all affine + * transformations on the 2D plane as 3x3 matrices, where the last column has fixed values. + * \f[ A = \left[ \begin{array}{ccc} + c_0 & c_1 & 0 \\ + c_2 & c_3 & 0 \\ + c_4 & c_5 & 1 \end{array} \right]\f] + * + * We then interpret points as row vectors of the form \f$[p_X, p_Y, 1]\f$. Applying a + * transformation to a point can be written as right-multiplication by a 3x3 matrix + * (\f$p' = pA\f$). This subset of matrices is closed under multiplication - combination + * of any two transforms can be expressed as the multiplication of their matrices. + * In this representation, the \f$c_4\f$ and \f$c_5\f$ coefficients represent + * the translation component of the transformation. + * + * Matrices can be multiplied by other more specific transformations. When multiplying, + * the transformations are applied from left to right, so for example <code>m = a * b</code> + * means: @a m first transforms by a, then by b. + * + * @ingroup Transforms + */ +class Affine + : boost::equality_comparable< Affine // generates operator!= from operator== + , boost::multipliable1< Affine + , MultipliableNoncommutative< Affine, Translate + , MultipliableNoncommutative< Affine, Scale + , MultipliableNoncommutative< Affine, Rotate + , MultipliableNoncommutative< Affine, HShear + , MultipliableNoncommutative< Affine, VShear + > > > > > > > +{ + Coord _c[6]; +public: + Affine() { + _c[0] = _c[3] = 1; + _c[1] = _c[2] = _c[4] = _c[5] = 0; + } + + Affine(Affine const &m) { + for(int i = 0; i < 6; i++) { + _c[i] = m[i]; + } + } + + /** @brief Create a matrix from its coefficient values. + * It's rather inconvenient to directly create matrices in this way. Use transform classes + * if your transformation has a geometric interpretation. + * @see Translate + * @see Scale + * @see Rotate + * @see HShear + * @see VShear */ + Affine(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5) { + _c[0] = c0; _c[1] = c1; + _c[2] = c2; _c[3] = c3; + _c[4] = c4; _c[5] = c5; + } + + Affine &operator=(Affine const &m) { + for(int i = 0; i < 6; i++) + _c[i] = m._c[i]; + return *this; + } + + /** @brief Access a coefficient by its index. */ + inline Coord operator[](unsigned i) const { return _c[i]; } + inline Coord &operator[](unsigned i) { return _c[i]; } + + /// @name Combine with other transformations + /// @{ + Affine &operator*=(Affine const &m); + // implemented in transforms.cpp + Affine &operator*=(Translate const &t); + Affine &operator*=(Scale const &s); + Affine &operator*=(Rotate const &r); + Affine &operator*=(HShear const &h); + Affine &operator*=(VShear const &v); + /// @} + + bool operator==(Affine const &o) const { + for(unsigned i = 0; i < 6; ++i) { + if ( _c[i] != o._c[i] ) return false; + } + return true; + } + + /// @name Get the parameters of the matrix's transform + /// @{ + Point xAxis() const; + Point yAxis() const; + Point translation() const; + Coord expansionX() const; + Coord expansionY() const; + Point expansion() const { return Point(expansionX(), expansionY()); } + /// @} + + /// @name Modify the matrix + /// @{ + void setXAxis(Point const &vec); + void setYAxis(Point const &vec); + + void setTranslation(Point const &loc); + + void setExpansionX(Coord val); + void setExpansionY(Coord val); + void setIdentity(); + /// @} + + /// @name Inspect the matrix's transform + /// @{ + bool isIdentity(Coord eps = EPSILON) const; + + bool isTranslation(Coord eps = EPSILON) const; + bool isScale(Coord eps = EPSILON) const; + bool isUniformScale(Coord eps = EPSILON) const; + bool isRotation(Coord eps = EPSILON) const; + bool isHShear(Coord eps = EPSILON) const; + bool isVShear(Coord eps = EPSILON) const; + + bool isNonzeroTranslation(Coord eps = EPSILON) const; + bool isNonzeroScale(Coord eps = EPSILON) const; + bool isNonzeroUniformScale(Coord eps = EPSILON) const; + bool isNonzeroRotation(Coord eps = EPSILON) const; + bool isNonzeroHShear(Coord eps = EPSILON) const; + bool isNonzeroVShear(Coord eps = EPSILON) const; + + bool isZoom(Coord eps = EPSILON) const; + bool preservesArea(Coord eps = EPSILON) const; + bool preservesAngles(Coord eps = EPSILON) const; + bool preservesDistances(Coord eps = EPSILON) const; + bool flips() const; + + bool isSingular(Coord eps = EPSILON) const; + /// @} + + /// @name Compute other matrices + /// @{ + Affine withoutTranslation() const { + Affine ret(*this); + ret.setTranslation(Point(0,0)); + return ret; + } + Affine inverse() const; + /// @} + + /// @name Compute scalar values + /// @{ + Coord det() const; + Coord descrim2() const; + Coord descrim() const; + /// @} + inline static Affine identity(); +}; + +/** @brief Print out the Affine (for debugging). + * @relates Affine */ +inline std::ostream &operator<< (std::ostream &out_file, const Geom::Affine &m) { + out_file << "A: " << m[0] << " C: " << m[2] << " E: " << m[4] << "\n"; + out_file << "B: " << m[1] << " D: " << m[3] << " F: " << m[5] << "\n"; + return out_file; +} + +/** Given a matrix m such that unit_circle = m*x, this returns the + * quadratic form x*A*x = 1. + * @relates Affine */ +Affine elliptic_quadratic_form(Affine const &m); + +/** Given a matrix (ignoring the translation) this returns the eigen + * values and vectors. */ +class Eigen{ +public: + Point vectors[2]; + double values[2]; + Eigen(Affine const &m); + Eigen(double M[2][2]); +}; + +// Affine factories +Affine from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0)); + +/** @brief Create an identity matrix. + * This is a convenience function identical to Affine::identity(). */ +inline Affine identity() { + Affine ret(Affine::identity()); + return ret; // allow NRVO +} + +/** @brief Create an identity matrix. + * @return The matrix + * \f$\left[\begin{array}{ccc} + 1 & 0 & 0 \\ + 0 & 1 & 0 \\ + 0 & 0 & 1 \end{array}\right]\f$. + * @relates Affine */ +inline Affine Affine::identity() { + Affine ret(1.0, 0.0, + 0.0, 1.0, + 0.0, 0.0); + return ret; // allow NRVO +} + +} /* namespace Geom */ + +#endif /* !__Geom_MATRIX_H__ */ + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/angle.h b/src/2geom/angle.h index c950dd803..42e3531f3 100644 --- a/src/2geom/angle.h +++ b/src/2geom/angle.h @@ -1,11 +1,13 @@ /** - * \file angle.h + * \file * \brief Various trigoniometric helper functions - * + *//* * Authors: * Johan Engelen <goejendaagh@zonnet.nl> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright (C) 2007 authors + * Copyright (C) 2007-2010 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -35,12 +37,177 @@ #ifndef LIB2GEOM_SEEN_ANGLE_H #define LIB2GEOM_SEEN_ANGLE_H +#include <cmath> +#include <boost/operators.hpp> +#include <2geom/exception.h> +#include <2geom/coord.h> +#include <2geom/point.h> + namespace Geom { #ifndef M_PI # define M_PI 3.14159265358979323846 #endif +/** @brief Wrapper for angular values. + * + * This class is a convenience wrapper that implements the behavior generally expected of angles, + * like addition modulo \f$2\pi\f$. The value returned from the default conversion + * to <tt>double</tt> is in the range \f$[-\pi, \pi)\f$ - the convention used by C's + * math library. + * + * @ingroup Primitives + */ +class Angle + : boost::additive< Angle + , boost::equality_comparable< Angle + > > +{ +public: + Angle(Coord v) : _angle(v) { _normalize(); } // this can be called implicitly + explicit Angle(Point p) : _angle(atan2(p)) { _normalize(); } + Angle(Point a, Point b) : _angle(angle_between(a, b)) { _normalize(); } + operator Coord() const { return radians(); } + Angle &operator+=(Angle const &o) { + _angle += o._angle; + _normalize(); + return *this; + } + Angle &operator-=(Angle const &o) { + _angle -= o._angle; + _normalize(); + return *this; + } + bool operator==(Angle const &o) const { + return _angle == o._angle; + } + + /** @brief Get the angle as radians. + * @return Number in range \f$[-\pi, \pi)\f$. */ + Coord radians() const { + return _angle > M_PI ? _angle - 2*M_PI : _angle; + } + /** @brief Get the angle as positive radians. + * @return Number in range \f$[0, 2\pi)\f$. */ + Coord radians0() const { + return _angle; + } + /** @brief Get the angle as degrees in math convention. + * @return Number in range [-180, 180) obtained by scaling the result of radians() + * by \f$180/\pi\f$. */ + Coord degrees() const { return radians() / M_PI * 180.0; } + /** @brief Get the angle as degrees in clock convention. + * This method converts the angle to the "clock convention": angles start from the +Y axis + * and grow clockwise. This means that 0 corresponds to \f$\pi/2\f$ radians, + * 90 to 0 radians, 180 to \f$-\pi/2\f$ radians, and 270 to \f$\pi\f$ radians. + * @return A number in the range [0, 360). + */ + Coord degreesClock() const { + Coord ret = 90.0 - _angle / M_PI * 180.0; + if (ret < 0) ret += 360; + return ret; + } + + static Angle from_degrees(Coord d) { + Angle a(d * M_PI / 180); + return a; + } + static Angle from_degrees_clock(Coord d) { + // first make sure d is in [0, 360) + d = std::fmod(d, 360.0); + if (d < 0) d += 360.0; + Coord rad = M_PI/2 - d * M_PI / 180.0; + if (rad < 0) rad += 2*M_PI; + Angle a; + a._angle = rad; + return a; + } +private: + Angle() {} + void _normalize() { + _angle -= floor(_angle / (2*M_PI)) * 2*M_PI; + } + Coord _angle; // this is always in [0, 2pi) + friend class AngleInterval; +}; + +/** @brief Directed angular interval. + * + * Wrapper for directed angles with defined start and end values. Useful e.g. for representing + * the portion of an ellipse in an elliptical arc. Both extreme angles are contained + * in the interval (it is a closed interval). Angular intervals can also be interptered + * as functions \f$f: [0, 1] \to [-\pi, \pi)\f$, which return the start angle for 0, + * the end angle for 1, and interpolate linearly for other values. Note that such functions + * are not continuous if the interval contains the zero angle. + * + * This class is immutable - you cannot change the values of start and end angles + * without creating a new instance of this class. + * + * @ingroup Primitives + */ +class AngleInterval { +public: + AngleInterval(Angle const &s, Angle const &e, bool cw = false) + : _start_angle(s), _end_angle(e), _sweep(cw) + {} + AngleInterval(double s, double e, bool cw = false) + : _start_angle(s), _end_angle(e), _sweep(cw) + {} + /** @brief Get the angular coordinate of the interval's initial point + * @return Angle in range \f$[0,2\pi)\f$ corresponding to the start of arc */ + Angle const &initialAngle() const { return _start_angle; } + /** @brief Get the angular coordinate of the interval's final point + * @return Angle in range \f$[0,2\pi)\f$ corresponding to the end of arc */ + Angle const &finalAngle() const { return _end_angle; } + bool isDegenerate() const { return initialAngle() == finalAngle(); } + /** @brief Get an angle corresponding to the specified time value. */ + Angle angleAt(Coord t) const { + Coord span = extent(); + Angle ret = _start_angle.radians0() + span * (_sweep ? t : -t); + return ret; + } + Angle operator()(Coord t) const { return angleAt(t); } +#if 0 + /** @brief Find an angle nearest to the specified time value. + * @param a Query angle + * @return If the interval contains the query angle, a number from the range [0, 1] + * such that a = angleAt(t); otherwise, 0 or 1, depending on which extreme + * angle is nearer. */ + Coord nearestAngle(Angle const &a) const { + Coord dist = distance(_start_angle, a, _sweep).radians0(); + Coord span = distance(_start_angle, _end_angle, _sweep).radians0(); + if (dist <= span) return dist / span; + else return distance_abs(_start_angle, a).radians0() > distance_abs(_end_angle, a).radians0() ? 1.0 : 0.0; + } +#endif + /** @brief Check whether the interval includes the given angle. */ + bool contains(Angle const &a) const { + Coord s = _start_angle.radians0(); + Coord e = _end_angle.radians0(); + Coord x = a.radians0(); + if (_sweep) { + if (s < e) return x >= s && x <= e; + return x >= s || x <= e; + } else { + if (s > e) return x <= s && x >= e; + return x <= s || x >= e; + } + } + /** @brief Extent of the angle interval. + * @return Extent in range \f$[0, 2\pi)\f$ */ + Coord extent() const { + Coord d = _end_angle - _start_angle; + if (!_sweep) d = -d; + if (d < 0) d += 2*M_PI; + return d; + } +protected: + AngleInterval() {} + Angle _start_angle; + Angle _end_angle; + bool _sweep; +}; + inline double deg_to_rad(double deg) { return deg*M_PI/180.0;} inline double rad_to_deg(double rad) { return rad*180.0/M_PI;} @@ -89,9 +256,44 @@ Coord map_unit_interval_on_circular_arc(Coord t, double start_angle, double end_ return angle; } +/* + * Return true if the given angle is contained in the circular arc determined + * by the passed angles. + * + * a: the angle to be tested + * sa: the angle the arc start from + * ia: an angle strictly inner to the arc + * ea: the angle the arc end to + * + * prerequisite: the inner angle has to be not equal (mod 2PI) to the start + * or the end angle, except when they are equal each other, too. + * warning: when sa == ea (mod 2PI) they define a whole circle + * if ia != sa (mod 2PI), on the contrary if ia == sa == ea (mod 2PI) + * they define a single point. + */ +inline +bool arc_contains (double a, double sa, double ia, double ea) +{ + a -= sa; + a = std::fmod(a, 2*M_PI); + if (a < 0) a += 2*M_PI; + ia -= sa; + ia = std::fmod(ia, 2*M_PI); + if (ia < 0) ia += 2*M_PI; + ea -= sa; + ea = std::fmod(ea, 2*M_PI); + if (ea < 0) ea += 2*M_PI; + if (ia == 0 && ea == 0) return (a == 0); + if (ia == 0 || ia == ea) + { + THROW_RANGEERROR ("arc_contains: passed angles do not define an arc"); + } + return (ia < ea && a <= ea) || (ia > ea && (a >= ea || a == 0)); } +} // end namespace Geom + #endif diff --git a/src/2geom/basic-intersection.cpp b/src/2geom/basic-intersection.cpp index 66f174da6..3be6792b9 100644 --- a/src/2geom/basic-intersection.cpp +++ b/src/2geom/basic-intersection.cpp @@ -202,7 +202,7 @@ static void intersect_polish_root (D2<SBasis> const &A, double &s, // We're using the standard transformation matricies, which is numerically rather poor. Much better to solve the equation using elimination. - Matrix jack(as[1][0], as[1][1], + Affine jack(as[1][0], as[1][1], -bs[1][0], -bs[1][1], 0, 0); Point soln = (F)*jack.inverse(); diff --git a/src/2geom/bezier-curve.cpp b/src/2geom/bezier-curve.cpp new file mode 100644 index 000000000..bde0e3ef1 --- /dev/null +++ b/src/2geom/bezier-curve.cpp @@ -0,0 +1,265 @@ +/** + * \file + * \brief Bezier curve + * + *//* + * Authors: + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright 2007-2009 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include <2geom/bezier-curve.h> + +namespace Geom +{ + +/** + * @class BezierCurve + * @brief Two-dimensional Bezier curve of arbitrary order. (this is an abstract class) + * + * Bezier curves are an expansion of the concept of linear interpolation to n points. + * Linear segments in 2Geom are in fact Bezier curves of order 1. + * + * Let \f$\mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\ldots\mathbf{p}_n}\f$ denote a Bezier curve + * of order \f$n\f$ defined by the points \f$\mathbf{p}_0, \mathbf{p}_1, \ldots, \mathbf{p}_n\f$. + * Bezier curve of order 1 is a linear interpolation curve between two points, defined as + * \f[ \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1}(t) = (1-t)\mathbf{p}_0 + t\mathbf{p}_1 \f] + * If we now substitute points \f$\mathbf{p_0}\f$ and \f$\mathbf{p_1}\f$ in this definition + * by linear interpolations, we get the definition of a Bezier curve of order 2, also called + * a quadratic Bezier curve. + * \f{align*}{ \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\mathbf{p}_2}(t) + &= (1-t) \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1}(t) + t \mathbf{B}_{\mathbf{p}_1\mathbf{p}_2}(t) \\ + \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\mathbf{p}_2}(t) + &= (1-t)^2\mathbf{p}_0 + 2(1-t)t\mathbf{p}_1 + t^2\mathbf{p}_2 \f} + * By substituting points for quadratic Bezier curves in the original definition, + * we get a Bezier curve of order 3, called a cubic Bezier curve. + * \f{align*}{ \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\mathbf{p}_2\mathbf{p}_3}(t) + &= (1-t) \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\mathbf{p}_2}(t) + + t \mathbf{B}_{\mathbf{p}_1\mathbf{p}_2\mathbf{p}_3}(t) \\ + \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\mathbf{p}_2\mathbf{p}_3}(t) + &= (1-t)^3\mathbf{p}_0+3(1-t)^2t\mathbf{p}_1+3(1-t)t^2\mathbf{p}_2+t^3\mathbf{p}_3 \f} + * In general, a Bezier curve or order \f$n\f$ can be recursively defined as + * \f[ \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\ldots\mathbf{p}_n}(t) + = (1-t) \mathbf{B}_{\mathbf{p}_0\mathbf{p}_1\ldots\mathbf{p}_{n-1}}(t) + + t \mathbf{B}_{\mathbf{p}_1\mathbf{p}_2\ldots\mathbf{p}_n}(t) \f] + * + * This substitution can be repeated an arbitrary number of times. To picture this, imagine + * the evaluation of a point on the curve as follows: first, all control points are joined with + * straight lines, and a point corresponding to the selected time value is marked on them. + * Then, the marked points are joined with straight lines and the point corresponding to + * the time value is marked. This is repeated until only one marked point remains, which is the + * point at the selected time value. + * + * @image html bezier-curve-evaluation.png "Evaluation of the Bezier curve" + * + * An important property of the Bezier curves is that their parameters (control points) + * have an intutive geometric interpretation. Because of this, they are frequently used + * in vector graphics editors. + * + * Every bezier curve is contained in its control polygon (the convex polygon composed + * of its control points). This fact is useful for sweepline algorithms and intersection. + * + * Bezier curves of order 1, 2 and 3 are common enough to have their own more specific subclasses: + * LineSegment, QuadraticBezier, and CubicBezier. + * Note that you cannot create a generic BezierCurve, you can only create a BezierCurve of a + * specific order, by creating a BezierCurveN. + * + * @relates BezierCurveN + * @ingroup Curves + */ + + /** + * @class BezierCurveN + * @tparam degree unsigned value indicating the order of the bezier curve + * @brief Two-dimensional Bezier curve of specific order. + * + * @relates BezierCurve + * @ingroup Curves + */ + + +Coord BezierCurve::length(Coord tolerance) const +{ + switch (order()) + { + case 0: + return 0.0; + case 1: + return distance(initialPoint(), finalPoint()); + case 2: + { + std::vector<Point> pts = points(); + return bezier_length(pts[0], pts[1], pts[2], tolerance); + } + case 3: + { + std::vector<Point> pts = points(); + return bezier_length(pts[0], pts[1], pts[2], pts[3], tolerance); + } + default: + return bezier_length(points(), tolerance); + } +} + +static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance) +{ + /* The Bezier length algorithm used in 2Geom utilizes a simple fact: + * the Bezier curve is longer than the distance between its endpoints + * but shorter than the length of the polyline formed by its control + * points. When the difference between the two values is smaller than the + * error tolerance, we can be sure that the true value is no further than + * 2*tolerance from their arithmetic mean. When it's larger, we recursively + * subdivide the Bezier curve into two parts and add their lengths. + */ + Coord lower = distance(v1.front(), v1.back()); + Coord upper = 0.0; + for (size_t i = 0; i < v1.size() - 1; ++i) { + upper += distance(v1[i], v1[i+1]); + } + if (upper - lower < 2*tolerance) { + return (lower + upper) / 2; + } + + + std::vector<Point> v2 = v1; + + /* Compute the right subdivision directly in v1 and the left one in v2. + * Explanation of the algorithm used: + * We have to compute the left and right edges of this triangle in which + * the top row are the control points of the Bezier curve, and each cell + * is equal to the arithmetic mean of the cells directly above it + * to the right and left. This corresponds to subdividing the Bezier curve + * at time value 0.5: the left edge has the control points of the first + * portion of the Bezier curve and the right edge - the second one. + * In the example we subdivide a curve with 5 control points (order 4). + * + * Start: + * 0 1 2 3 4 + * ? ? ? ? + * ? ? ? + * ? ? + * ? + * # means we have overwritten the value, ? means we don't know + * the value yet. Numbers mean the value is at i-th position in the vector. + * + * After loop with i==1 + * # 1 2 3 4 + * 0 ? ? ? -> write 0 to v2[1] + * ? ? ? + * ? ? + * ? + * + * After loop with i==2 + * # # 2 3 4 + * # 1 ? ? + * 0 ? ? -> wirte 0 to v2[2] + * ? ? + * ? + * + * After loop with i==3 + * # # # 3 4 + * # # 2 ? + * # 1 ? + * 0 ? -> write 0 to v2[3] + * ? + * + * After loop with i==4, we have the right edge of the triangle in v1, + * and we write the last value needed for the left edge in v2[4]. + */ + + for (size_t i = 1; i < v1.size(); ++i) { + for (size_t j = i; j > 0; --j) { + v1[j-1] = 0.5 * (v1[j-1] + v1[j]); + } + v2[i] = v1[0]; + } + + return bezier_length_internal(v1, 0.5*tolerance) + bezier_length_internal(v2, 0.5*tolerance); +} + +/** @brief Compute the length of a bezier curve given by a vector of its control points + * @relates BezierCurve */ +Coord bezier_length(std::vector<Point> const &points, Coord tolerance) +{ + if (points.size() < 2) return 0.0; + std::vector<Point> v1 = points; + return bezier_length_internal(v1, tolerance); +} + +/** @brief Compute the length of a quadratic bezier curve given by its control points + * @relates QuadraticBezier */ +Coord bezier_length(Point a0, Point a1, Point a2, Coord tolerance) +{ + Coord lower = distance(a0, a2); + Coord upper = distance(a0, a1) + distance(a1, a2); + + if (upper - lower < 2*tolerance) return (lower + upper)/2; + + Point // Casteljau subdivision + // b0 = a0, + // c0 = a2, + b1 = 0.5*(a0 + a1), + c1 = 0.5*(a1 + a2), + b2 = 0.5*(b1 + c1); // == c2 + return bezier_length(a0, b1, b2, 0.5*tolerance) + bezier_length(b2, c1, a2, 0.5*tolerance); +} + +/** @brief Compute the length of a cubic bezier curve given by its control points + * @relates CubicBezier */ +Coord bezier_length(Point a0, Point a1, Point a2, Point a3, Coord tolerance) +{ + Coord lower = distance(a0, a3); + Coord upper = distance(a0, a1) + distance(a1, a2) + distance(a2, a3); + + if (upper - lower < 2*tolerance) return (lower + upper)/2; + + Point // Casteljau subdivision + // b0 = a0, + // c0 = a3, + b1 = 0.5*(a0 + a1), + t0 = 0.5*(a1 + a2), + c1 = 0.5*(a2 + a3), + b2 = 0.5*(b1 + t0), + c2 = 0.5*(t0 + c1), + b3 = 0.5*(b2 + c2); // == c3 + return bezier_length(a0, b1, b2, b3, 0.5*tolerance) + bezier_length(b3, c2, c1, a3, 0.5*tolerance); +} + +} // end 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/bezier-curve.h b/src/2geom/bezier-curve.h index c943512c7..40da6f366 100644 --- a/src/2geom/bezier-curve.h +++ b/src/2geom/bezier-curve.h @@ -1,12 +1,14 @@ /** * \file - * \brief Bezier-Curve + * \brief Bezier curve * + *//* * Authors: - * MenTaLguY <mental@rydia.net> - * Marco Cecchetti <mrcekets at gmail.com> + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright 2007-2008 authors + * Copyright 2007-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,217 +34,250 @@ * the specific language governing rights and limitations. */ - - - -#ifndef _2GEOM_BEZIER_CURVE_H_ -#define _2GEOM_BEZIER_CURVE_H_ - +#ifndef SEEN_LIB2GEOM_BEZIER_CURVE_H +#define SEEN_LIB2GEOM_BEZIER_CURVE_H #include <2geom/curve.h> #include <2geom/sbasis-curve.h> // for non-native winding method #include <2geom/bezier.h> -#include <algorithm> - - namespace Geom { +class BezierCurve : public Curve { +protected: + D2<Bezier> inner; + +public: + /// No constructors allowed! + + /// @name Access and modify control points + /// @{ + /** @brief Get the order of the Bezier curve. + * A Bezier curve has order() + 1 control points. */ + unsigned order() const { return inner[X].order(); } + /** @brief Get the control points. + * @return Vector with order() + 1 control points. */ + std::vector<Point> points() const { return bezier_points(inner); } + /** @brief Modify a control point. + * @param ix The zero-based index of the point to modify. Note that the caller is responsible for checking that this value is <= order(). + * @param v The new value of the point */ + void setPoint(unsigned ix, Point v) { + inner[X].setPoint(ix, v[X]); + inner[Y].setPoint(ix, v[Y]); + } + /** @brief Set new control points for this curve. + * @param ps Vector which must contain order() + 1 points. Note that the caller is responsible for checking the size of this vector. */ + virtual void setPoints(std::vector<Point> const &ps) { + // must be virtual, because HLineSegment will need to redefine it + if (ps.size() != order() + 1) + THROW_LOGICALERROR("BezierCurve::setPoints: incorrect number of points in vector"); + for(unsigned i = 0; i <= order(); i++) { + setPoint(i, ps[i]); + } + } + /** Access control points of the curve. + * @param ix The (zero-based) index of the control point. Note that the caller is responsible for checking that this value is <= order(). + * @return The control point. No-reference return, use setPoint() to modify control points. */ + Point const operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); } + /// @} + + // implementation of virtual methods goes here +#ifndef DOXYGEN_SHOULD_SKIP_THIS + virtual Point initialPoint() const { return inner.at0(); } + virtual Point finalPoint() const { return inner.at1(); } + virtual bool isDegenerate() const { return inner.isConstant(); } + virtual void setInitial(Point const &v) { setPoint(0, v); } + virtual void setFinal(Point const &v) { setPoint(order(), v); } + virtual Rect boundsFast() const { return *bounds_fast(inner); } + virtual Rect boundsExact() const { return *bounds_exact(inner); } + virtual OptRect boundsLocal(OptInterval const &i, unsigned deg) const { + if (!i) return OptRect(); + if(i->min() == 0 && i->max() == 1) return boundsFast(); + if(deg == 0) return bounds_local(inner, i); + // TODO: UUUUUUGGGLLY + if(deg == 1 && order() > 1) return OptRect(bounds_local(Geom::derivative(inner[X]), i), + bounds_local(Geom::derivative(inner[Y]), i)); + return OptRect(); + } + virtual int degreesOfFreedom() const { + return 2 * (order() + 1); + } + virtual std::vector<Coord> roots(Coord v, Dim2 d) const { + return (inner[d] - v).roots(); + } + virtual Coord length(Coord tolerance) const; + virtual Point pointAt(Coord t) const { return inner.valueAt(t); } + virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); } + virtual Coord valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); } + virtual D2<SBasis> toSBasis() const {return inner.toSBasis(); } +#endif +}; +template <unsigned degree> +class BezierCurveN : public BezierCurve { -template <unsigned order> -class BezierCurve : public Curve { - -private: - D2<Bezier > inner; - public: template <unsigned required_degree> - static void assert_degree(BezierCurve<required_degree> const *) {} - - BezierCurve() : inner(Bezier::Order(order), Bezier::Order(order)) { - } - - explicit BezierCurve(D2<Bezier > const &x) : inner(x) {} - - BezierCurve(Bezier x, Bezier y) : inner(x, y) {} - - // default copy - // default assign - - BezierCurve(Point c0, Point c1) { - assert_degree<1>(this); - for(unsigned d = 0; d < 2; d++) - inner[d] = Bezier(c0[d], c1[d]); - } - - BezierCurve(Point c0, Point c1, Point c2) { - assert_degree<2>(this); - for(unsigned d = 0; d < 2; d++) - inner[d] = Bezier(c0[d], c1[d], c2[d]); - } - - BezierCurve(Point c0, Point c1, Point c2, Point c3) { - assert_degree<3>(this); - for(unsigned d = 0; d < 2; d++) - inner[d] = Bezier(c0[d], c1[d], c2[d], c3[d]); - } - - unsigned degree() const { return order; } - - Curve *duplicate() const { return new BezierCurve(*this); } - - Point initialPoint() const { return inner.at0(); } - Point finalPoint() const { return inner.at1(); } - - bool isDegenerate() const { return inner.isConstant(); } - - void setInitial(Point v) { setPoint(0, v); } - void setFinal(Point v) { setPoint(order, v); } - - void setPoint(unsigned ix, Point v) { inner[X].setPoint(ix, v[X]); inner[Y].setPoint(ix, v[Y]); } - Point const operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); } - - virtual OptRect boundsFast() const { return bounds_fast(inner); } - virtual OptRect boundsExact() const { return bounds_exact(inner); } - virtual OptRect boundsLocal(OptInterval i, unsigned deg) const { - if (!i) return OptRect(); - if(i->min() == 0 && i->max() == 1) return boundsFast(); - if(deg == 0) return bounds_local(inner, i); - // TODO: UUUUUUGGGLLY - if(deg == 1 && order > 1) return OptRect(bounds_local(Geom::derivative(inner[X]), i), - bounds_local(Geom::derivative(inner[Y]), i)); - return OptRect(); - } -//TODO: local - -//TODO: implement next 3 natively - int winding(Point p) const { - return SBasisCurve(toSBasis()).winding(p); - } - - virtual int degreesOfFreedom() const { - return 2*order; - } - - std::vector<double> - roots(double v, Dim2 d) const { - return (inner[d] - v).roots(); - } - - double nearestPoint( Point const& p, double from = 0, double to = 1 ) const - { - return Curve::nearestPoint(p, from, to); - } - - void setPoints(std::vector<Point> ps) { - for(unsigned i = 0; i <= order; i++) { - setPoint(i, ps[i]); - } - } - std::vector<Point> points() const { return bezier_points(inner); } - - std::pair<BezierCurve<order>, BezierCurve<order> > subdivide(Coord t) const { - std::pair<Bezier, Bezier > sx = inner[X].subdivide(t), sy = inner[Y].subdivide(t); - return std::pair<BezierCurve<order>, BezierCurve<order> >( - BezierCurve<order>(sx.first, sy.first), - BezierCurve<order>(sx.second, sy.second)); - } - - Curve *portion(double f, double t) const { - return new BezierCurve(Geom::portion(inner, f, t)); - } - - Curve *reverse() const { - return new BezierCurve(Geom::reverse(inner)); - } - - Curve *transformed(Matrix const &m) const { - BezierCurve *ret = new BezierCurve(); - std::vector<Point> ps = points(); - for(unsigned i = 0; i <= order; i++) ps[i] = ps[i] * m; - ret->setPoints(ps); - return ret; - } - - Curve *derivative() const; - - Point pointAt(double t) const { return inner.valueAt(t); } - std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); } - - double valueAt(double t, Dim2 d) const { return inner[d].valueAt(t); } - - D2<SBasis> toSBasis() const {return inner.toSBasis(); } + static void assert_degree(BezierCurveN<required_degree> const *) {} -protected: - BezierCurve(Point c[]) { - Coord x[order+1], y[order+1]; - for(unsigned i = 0; i <= order; i++) { - x[i] = c[i][X]; y[i] = c[i][Y]; + /// @name Construct the curve + /// @{ + /** @brief Construct a Bezier curve of the specified order with all points zero. */ + BezierCurveN() { + inner = D2<Bezier> (Bezier::Order(degree), Bezier::Order(degree)); } - inner = Bezier(x, y); - } -}; -// BezierCurve<0> is meaningless; specialize it out -template<> class BezierCurve<0> : public BezierCurve<1> { public: BezierCurve();}; + /** @brief Construct from 2D Bezier polynomial. */ + explicit BezierCurveN(D2<Bezier > const &x) { + inner = x; + } -typedef BezierCurve<1> LineSegment; -typedef BezierCurve<2> QuadraticBezier; -typedef BezierCurve<3> CubicBezier; + /** @brief Construct from two 1D Bezier polynomials of the same order. */ + BezierCurveN(Bezier x, Bezier y) { + inner = D2<Bezier > (x,y); + } + /** @brief Construct a Bezier curve from a vector of its control points. */ + BezierCurveN(std::vector<Point> const &points) { + unsigned ord = points.size() - 1; + if (ord != degree) THROW_LOGICALERROR("BezierCurve<degree> does not match number of points"); + for (unsigned d = 0; d < 2; ++d) { + inner[d] = Bezier(Bezier::Order(ord)); + for(unsigned i = 0; i <= ord; i++) + inner[d][i] = points[i][d]; + } + } -template<> + /** @brief Construct a linear segment from its endpoints. */ + BezierCurveN(Point c0, Point c1) { + assert_degree<1>(this); + for(unsigned d = 0; d < 2; d++) + inner[d] = Bezier(c0[d], c1[d]); + } + + /** @brief Construct a quadratic Bezier curve from its control points. */ + BezierCurveN(Point c0, Point c1, Point c2) { + assert_degree<2>(this); + for(unsigned d = 0; d < 2; d++) + inner[d] = Bezier(c0[d], c1[d], c2[d]); + } + + /** @brief Construct a cubic Bezier curve from its control points. */ + BezierCurveN(Point c0, Point c1, Point c2, Point c3) { + assert_degree<3>(this); + for(unsigned d = 0; d < 2; d++) + inner[d] = Bezier(c0[d], c1[d], c2[d], c3[d]); + } + + // default copy + // default assign + + /// @} + + + virtual Curve *duplicate() const { + return new BezierCurveN(*this); + } + virtual Curve *portion(Coord f, Coord t) const { + if (degree == 1) { + return new BezierCurveN<1>(pointAt(f), pointAt(t)); + } else { + return new BezierCurveN(Geom::portion(inner, f, t)); + } + } + virtual Curve *reverse() const { + if (degree == 1) { + return new BezierCurveN<1>(finalPoint(), initialPoint()); + } else { + return new BezierCurveN(Geom::reverse(inner)); + } + } + virtual Curve *transformed(Affine const &m) const { + if (degree == 1) { + return new BezierCurveN<1>(initialPoint() * m, finalPoint() * m); + } else { + BezierCurveN *ret = new BezierCurveN(); + std::vector<Point> ps = points(); + for (unsigned i = 0; i <= degree; i++) { + ps[i] = ps[i] * m; + } + ret->setPoints(ps); + return ret; + } + } + virtual Curve *derivative() const; + + /** @brief Divide a Bezier curve into two curves + * @param t Time value + * @return Pair of Bezier curves \f$(\mathbf{D}, \mathbf{E})\f$ such that + * \f$\mathbf{D}[ [0,1] ] = \mathbf{C}[ [0,t] ]\f$ and + * \f$\mathbf{E}[ [0,1] ] = \mathbf{C}[ [t,1] ]\f$ */ + std::pair<BezierCurveN, BezierCurveN> subdivide(Coord t) const { + std::pair<Bezier, Bezier> sx = inner[X].subdivide(t), sy = inner[Y].subdivide(t); + return std::make_pair( + BezierCurveN(sx.first, sy.first), + BezierCurveN(sx.second, sy.second)); + } + + double nearestPoint( Point const& p, double from = 0, double to = 1 ) const { + return Curve::nearestPoint(p, from, to); + } + +}; + +// BezierCurveN<0> is meaningless; specialize it out +template<> class BezierCurveN<0> : public BezierCurveN<1> { public: BezierCurveN();}; + +// provide convenient names for common degree bezier curves +typedef BezierCurveN<1> LineSegment; +typedef BezierCurveN<2> QuadraticBezier; +typedef BezierCurveN<3> CubicBezier; + +template <unsigned degree> inline -double LineSegment::nearestPoint(Point const& p, double from, double to) const -{ - if ( from > to ) std::swap(from, to); - Point ip = pointAt(from); - Point fp = pointAt(to); - Point v = fp - ip; - double l2v = L2sq(v); - if(l2v == 0) return 0; - double t = dot( p - ip, v ) / l2v; - if ( t <= 0 ) return from; - else if ( t >= 1 ) return to; - else return from + t*(to-from); +Curve *BezierCurveN<degree>::derivative() const { + return new BezierCurveN<degree-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y])); } - +template <> inline -Point middle_point(LineSegment const& _segment) -{ - return ( _segment.initialPoint() + _segment.finalPoint() ) / 2; +Curve *BezierCurveN<1>::derivative() const { + double dx = inner[X][1] - inner[X][0], dy = inner[Y][1] - inner[Y][0]; + return new BezierCurveN<1>(Point(dx,dy),Point(dx,dy)); } +template<> inline -double length(LineSegment const& _segment) +double LineSegment::nearestPoint(Point const& p, double from, double to) const { - return distance(_segment.initialPoint(), _segment.finalPoint()); + if ( from > to ) std::swap(from, to); + Point ip = pointAt(from); + Point fp = pointAt(to); + Point v = fp - ip; + Coord l2v = L2sq(v); + if (l2v == 0) return 0; + Coord t = dot( p - ip, v ) / l2v; + if ( t <= 0 ) return from; + else if ( t >= 1 ) return to; + else return from + t*(to-from); } -template <unsigned order> -inline -Curve *BezierCurve<order>::derivative() const { - return new BezierCurve<order-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y])); +inline Point middle_point(LineSegment const& _segment) { + return ( _segment.initialPoint() + _segment.finalPoint() ) / 2; } -template <> -inline -Curve *BezierCurve<1>::derivative() const { - double dx = inner[X][1] - inner[X][0], dy = inner[Y][1] - inner[Y][0]; - return new BezierCurve<1>(Point(dx,dy),Point(dx,dy)); +inline Coord length(LineSegment const& seg) { + return distance(seg.initialPoint(), seg.finalPoint()); } +Coord bezier_length(std::vector<Point> const &points, Coord tolerance = 0.01); +Coord bezier_length(Point p0, Point p1, Point p2, Coord tolerance = 0.01); +Coord bezier_length(Point p0, Point p1, Point p2, Point p3, Coord tolerance = 0.01); } // end namespace Geom - #endif // _2GEOM_BEZIER_CURVE_H_ - - - /* Local Variables: mode:c++ diff --git a/src/2geom/bezier-utils.cpp b/src/2geom/bezier-utils.cpp index dc8025115..eb317940f 100644 --- a/src/2geom/bezier-utils.cpp +++ b/src/2geom/bezier-utils.cpp @@ -56,9 +56,7 @@ #include <2geom/isnan.h> #include <assert.h> -namespace Geom{ - -typedef Point BezierCurve[]; +namespace Geom { /* Forward declarations */ static void generate_bezier(Point b[], Point const d[], double const u[], unsigned len, @@ -68,16 +66,16 @@ static void estimate_lengths(Point bezier[], Point const &tHat1, Point const &tHat2); static void estimate_bi(Point b[4], unsigned ei, Point const data[], double const u[], unsigned len); -static void reparameterize(Point const d[], unsigned len, double u[], BezierCurve const bezCurve); -static double NewtonRaphsonRootFind(BezierCurve const Q, Point const &P, double u); +static void reparameterize(Point const d[], unsigned len, double u[], Point const bezCurve[]); +static double NewtonRaphsonRootFind(Point const Q[], Point const &P, double u); static Point darray_center_tangent(Point const d[], unsigned center, unsigned length); static Point darray_right_tangent(Point const d[], unsigned const len); static unsigned copy_without_nans_or_adjacent_duplicates(Point const src[], unsigned src_len, Point dest[]); static void chord_length_parameterize(Point const d[], double u[], unsigned len); static double compute_max_error_ratio(Point const d[], double const u[], unsigned len, - BezierCurve const bezCurve, double tolerance, + Point const bezCurve[], double tolerance, unsigned *splitPoint); -static double compute_hook(Point const &a, Point const &b, double const u, BezierCurve const bezCurve, +static double compute_hook(Point const &a, Point const &b, double const u, Point const bezCurve[], double const tolerance); @@ -546,7 +544,7 @@ static void reparameterize(Point const d[], unsigned const len, double u[], - BezierCurve const bezCurve) + Point const bezCurve[]) { assert( 2 <= len ); @@ -572,7 +570,7 @@ reparameterize(Point const d[], * \return Improved u */ static double -NewtonRaphsonRootFind(BezierCurve const Q, Point const &P, double const u) +NewtonRaphsonRootFind(Point const Q[], Point const &P, double const u) { assert( 0.0 <= u ); assert( u <= 1.0 ); @@ -904,7 +902,7 @@ chord_length_parameterize(Point const d[], double u[], unsigned const len) */ static double compute_max_error_ratio(Point const d[], double const u[], unsigned const len, - BezierCurve const bezCurve, double const tolerance, + Point const bezCurve[], double const tolerance, unsigned *const splitPoint) { assert( 2 <= len ); @@ -974,7 +972,7 @@ compute_max_error_ratio(Point const d[], double const u[], unsigned const len, * distance.) */ static double -compute_hook(Point const &a, Point const &b, double const u, BezierCurve const bezCurve, +compute_hook(Point const &a, Point const &b, double const u, Point const bezCurve[], double const tolerance) { Point const P = bezier_pt(3, bezCurve, u); diff --git a/src/2geom/bezier.h b/src/2geom/bezier.h index 2a06d44f5..a7d75da45 100644 --- a/src/2geom/bezier.h +++ b/src/2geom/bezier.h @@ -46,7 +46,7 @@ namespace Geom { inline Coord subdivideArr(Coord t, Coord const *v, Coord *left, Coord *right, unsigned order) { /* * Bernstein : - * Evaluate a Bernstein function at a particular parameter value + * Evaluate a Bernstein function at a particular parameter value * Fill in control points for resulting sub-curves. * */ @@ -248,7 +248,7 @@ public: // initialize temp storage variables std::valarray<Coord> d_(order()+1); - for (unsigned i = 0; i < size(); i++) { + for(unsigned i = 0; i < size(); i++) { d_[i] = c_[i]; } @@ -256,10 +256,10 @@ public: if(n_derivs > order()) { nn = order()+1; // only calculate the non zero derivs } - for (unsigned di = 0; di < nn; di++) { + for(unsigned di = 0; di < nn; di++) { //val_n_der[di] = (subdivideArr(t, &d_[0], NULL, NULL, order() - di)); val_n_der[di] = bernsteinValueAt(t, &d_[0], order() - di); - for (unsigned i = 0; i < order() - di; i++) { + for(unsigned i = 0; i < order() - di; i++) { d_[i] = (order()-di)*(d_[i+1] - d_[i]); } } @@ -381,7 +381,8 @@ inline Bezier integral(const Bezier & a) { } inline OptInterval bounds_fast(Bezier const & b) { - return Interval::fromArray(&const_cast<Bezier&>(b).c_[0], b.size()); + OptInterval ret = Interval::from_array(&const_cast<Bezier&>(b).c_[0], b.size()); + return ret; } //TODO: better bounds exact diff --git a/src/2geom/chebyshev.cpp b/src/2geom/chebyshev.cpp deleted file mode 100644 index d0d6edab4..000000000 --- a/src/2geom/chebyshev.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include <2geom/chebyshev.h> - -#include <2geom/sbasis.h> -#include <2geom/sbasis-poly.h> - -#include <vector> -using std::vector; - -#include <gsl/gsl_math.h> -#include <gsl/gsl_chebyshev.h> - -namespace Geom{ - -SBasis cheb(unsigned n) { - static std::vector<SBasis> basis; - if(basis.empty()) { - basis.push_back(Linear(1,1)); - basis.push_back(Linear(0,1)); - } - for(unsigned i = basis.size(); i <= n; i++) { - basis.push_back(Linear(0,2)*basis[i-1] - basis[i-2]); - } - - return basis[n]; -} - -SBasis cheb_series(unsigned n, double* cheb_coeff) { - SBasis r; - for(unsigned i = 0; i < n; i++) { - double cof = cheb_coeff[i]; - //if(i == 0) - //cof /= 2; - r += cheb(i)*cof; - } - - return r; -} - -SBasis clenshaw_series(unsigned m, double* cheb_coeff) { - /** b_n = a_n - b_n-1 = 2*x*b_n + a_n-1 - b_n-k = 2*x*b_{n-k+1} + a_{n-k} - b_{n - k + 2} - b_0 = x*b_1 + a_0 - b_2 - */ - - double a = -1, b = 1; - SBasis d, dd; - SBasis y = (Linear(0, 2) - (a+b)) / (b-a); - SBasis y2 = 2*y; - for(int j = m - 1; j >= 1; j--) { - SBasis sv = d; - d = y2*d - dd + cheb_coeff[j]; - dd = sv; - } - - return y*d - dd + 0.5*cheb_coeff[0]; -} - -SBasis chebyshev_approximant (double (*f)(double,void*), int order, Interval in, void* p) { - gsl_cheb_series *cs = gsl_cheb_alloc (order+2); - - gsl_function F; - - F.function = f; - F.params = p; - - gsl_cheb_init (cs, &F, in[0], in[1]); - - SBasis r = compose(clenshaw_series(order, cs->c), Linear(-1,1)); - - gsl_cheb_free (cs); - return r; -} - -struct wrap { - double (*f)(double,void*); - void* pp; - double fa, fb; - Interval in; -}; - -double f_interp(double x, void* p) { - struct wrap *wr = (struct wrap *)p; - double z = (x - wr->in[0]) / (wr->in[1] - wr->in[0]); - return (wr->f)(x, wr->pp) - ((1 - z)*wr->fa + z*wr->fb); -} - -SBasis chebyshev_approximant_interpolating (double (*f)(double,void*), - int order, Interval in, void* p) { - double fa = f(in[0], p); - double fb = f(in[1], p); - struct wrap wr; - wr.fa = fa; - wr.fb = fb; - wr.in = in; - //printf("%f %f\n", fa, fb); - wr.f = f; - wr.pp = p; - return compose(Linear(in[0], in[1]), Linear(fa, fb)) + chebyshev_approximant(f_interp, order, in, &wr) + Linear(fa, fb); -} - -SBasis chebyshev(unsigned n) { - static std::vector<SBasis> basis; - if(basis.empty()) { - basis.push_back(Linear(1,1)); - basis.push_back(Linear(0,1)); - } - for(unsigned i = basis.size(); i <= n; i++) { - basis.push_back(Linear(0,2)*basis[i-1] - basis[i-2]); - } - - return basis[n]; -} - -}; - -/* - 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/chebyshev.h b/src/2geom/chebyshev.h deleted file mode 100644 index f729e1f07..000000000 --- a/src/2geom/chebyshev.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _CHEBYSHEV -#define _CHEBYSHEV - -#include <2geom/sbasis.h> -#include <2geom/interval.h> - -/*** Conversion between Chebyshev approximation and SBasis. - * - */ - -namespace Geom{ - -SBasis chebyshev_approximant (double (*f)(double,void*), int order, Interval in, void* p=0); -SBasis chebyshev_approximant_interpolating (double (*f)(double,void*), int order, Interval in, void* p=0); -SBasis chebyshev(unsigned n); - -}; - -/* - 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:fileencoding=utf-8:textwidth=99 : - -#endif diff --git a/src/2geom/choose.h b/src/2geom/choose.h index 579c46718..3fecf1ba2 100644 --- a/src/2geom/choose.h +++ b/src/2geom/choose.h @@ -33,7 +33,7 @@ #define _CHOOSE_H #include <vector> -// XXX: Can we keep only the left terms easily? +// XXX: Can we keep only the left terms easily? // this would more than halve the array // row index becomes n2 = n/2, row2 = n2*(n2+1)/2, row = row2*2+(n&1)?n2:0 // we could also leave off the ones @@ -54,7 +54,7 @@ T choose(unsigned n, unsigned k) { unsigned p = pascals_triangle.size() - rows_done; pascals_triangle.push_back(1); for(unsigned i = 0; i < rows_done-1; i++) { - pascals_triangle.push_back(pascals_triangle[p] + pascals_triangle.push_back(pascals_triangle[p] + pascals_triangle[p+1]); p++; } @@ -75,6 +75,58 @@ T choose(unsigned n, unsigned k) { return r; }*/ + + +template <typename ValueType> +class BinomialCoefficient +{ + public: + typedef ValueType value_type; + typedef std::vector<value_type> container_type; + + BinomialCoefficient(unsigned int _n) + : n(_n), m(n >> 1) + { + coefficients.reserve(m+1); + coefficients.push_back(1); + int h = m + 1; + value_type bct = 1; + for (int i = 1; i < h; ++i) + { + bct *= (n-i+1); + bct /= i; + coefficients.push_back(bct); + } + } + + unsigned int size() const + { + return degree() +1; + } + + unsigned int degree() const + { + return n; + } + + value_type operator[] (unsigned int k) const + { + if (k > m) k = n - k; + return coefficients[k]; + } + + private: + const int n; + const unsigned int m; + container_type coefficients; +}; + + + + + + + #endif /* diff --git a/src/2geom/circle.cpp b/src/2geom/circle.cpp index 8a0704735..06eb4c2a1 100644 --- a/src/2geom/circle.cpp +++ b/src/2geom/circle.cpp @@ -89,10 +89,11 @@ void Circle::set(std::vector<Point> const& points) } -SVGEllipticalArc +EllipticalArc * Circle::arc(Point const& initial, Point const& inner, Point const& final, bool _svg_compliant) { + // TODO native implementation! Ellipse e(center(X), center(Y), ray(), ray(), 0); return e.arc(initial, inner, final, _svg_compliant); } diff --git a/src/2geom/circle.h b/src/2geom/circle.h index 987570b62..ec58e163a 100644 --- a/src/2geom/circle.h +++ b/src/2geom/circle.h @@ -39,11 +39,12 @@ #include <2geom/point.h> #include <2geom/exception.h> #include <2geom/path.h> +#include <vector> namespace Geom { -class SVGEllipticalArc; +class EllipticalArc; class Circle { @@ -87,12 +88,11 @@ class Circle // prerequisite: at least 3 points must be passed void set(std::vector<Point> const& points); - SVGEllipticalArc + EllipticalArc * arc(Point const& initial, Point const& inner, Point const& final, bool _svg_compliant = true); - void - getPath(std::vector<Path> &path_out); + void getPath(std::vector<Path> &path_out); Point center() const { diff --git a/src/2geom/conic_section_clipper.h b/src/2geom/conic_section_clipper.h new file mode 100644 index 000000000..a02cda4d3 --- /dev/null +++ b/src/2geom/conic_section_clipper.h @@ -0,0 +1,59 @@ +/** + * \file + * \brief Conic section clipping with respect to a rectangle + * + * Authors: + * Marco Cecchetti <mrcekets at gmail> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + + + +#ifndef _2GEOM_CONIC_SECTION_CLIPPER_H_ +#define _2GEOM_CONIC_SECTION_CLIPPER_H_ + + +#undef CLIP_WITH_CAIRO_SUPPORT +#include <2geom/conic_section_clipper_impl.h> + + +#endif // _2GEOM_CONIC_SECTION_CLIPPER_H_ + + + + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/conic_section_clipper_cr.h b/src/2geom/conic_section_clipper_cr.h new file mode 100644 index 000000000..31f5a4269 --- /dev/null +++ b/src/2geom/conic_section_clipper_cr.h @@ -0,0 +1,65 @@ +/** + * \file + * \brief Conic section clipping with respect to a rectangle + * + * Authors: + * Marco Cecchetti <mrcekets at gmail> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + + + +//////////////////////////////////////////////////////////////////////////////// +// This header should be used for graphical debugging purpuse only. // +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef _2GEOM_CONIC_SECTION_CLIPPER_CR_H_ +#define _2GEOM_CONIC_SECTION_CLIPPER_CR_H_ + + +#define CLIP_WITH_CAIRO_SUPPORT +#include "conic_section_clipper_impl.h" +#include "conic_section_clipper_impl.cpp" + + +#endif // _2GEOM_CONIC_SECTION_CLIPPER_CR_H_ + + + + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/conic_section_clipper_impl.cpp b/src/2geom/conic_section_clipper_impl.cpp new file mode 100644 index 000000000..edfafb11c --- /dev/null +++ b/src/2geom/conic_section_clipper_impl.cpp @@ -0,0 +1,590 @@ +/** + * \file + * \brief Conic section clipping with respect to a rectangle + * + * Authors: + * Marco Cecchetti <mrcekets at gmail> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + + + +#ifndef CLIP_WITH_CAIRO_SUPPORT + #include <2geom/conic_section_clipper.h> +#endif + + + + +namespace Geom +{ + +struct lex_lesser +{ + bool operator() (const Point & P, const Point & Q) const + { + if (P[X] < Q[X]) return true; + if (P[X] == Q[X] && P[Y] < Q[Y]) return true; + return false; + } +}; + + +/* + * Find rectangle-conic crossing points. They are returned in the + * "crossing_points" parameter. + * The method returns true if the conic section intersects at least one + * of the four lines passing through rectangle edges, else it returns false. + */ +bool CLIPPER_CLASS::intersect (std::vector<Point> & crossing_points) const +{ + crossing_points.clear(); + + std::vector<double> rts; + std::vector<Point> cpts; + // rectangle corners + enum {TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT}; + + bool no_crossing = true; + + // rigth edge + cs.roots (rts, R.right(), X); + if (rts.size() != 0) + { + no_crossing = false; + DBGPRINT ("CLIP: right: rts[0] = ", rts[0]) + DBGPRINTIF ((rts.size() == 2), "CLIP: right: rts[1] = ", rts[1]) + + Point corner1 = R.corner(TOP_RIGHT); + Point corner2 = R.corner(BOTTOM_RIGHT); + + for (size_t i = 0; i < rts.size(); ++i) + { + if (rts[i] < R.top() || rts[i] > R.bottom()) continue; + Point P (R.right(), rts[i]); + if (are_near (P, corner1)) + P = corner1; + else if (are_near (P, corner2)) + P = corner2; + + cpts.push_back (P); + } + if (cpts.size() == 2 && are_near (cpts[0], cpts[1])) + { + cpts[0] = middle_point (cpts[0], cpts[1]); + cpts.pop_back(); + } + } + + // top edge + cs.roots (rts, R.top(), Y); + if (rts.size() != 0) + { + no_crossing = false; + DBGPRINT ("CLIP: top: rts[0] = ", rts[0]) + DBGPRINTIF ((rts.size() == 2), "CLIP: top: rts[1] = ", rts[1]) + + Point corner1 = R.corner(TOP_RIGHT); + Point corner2 = R.corner(TOP_LEFT); + + for (size_t i = 0; i < rts.size(); ++i) + { + if (rts[i] < R.left() || rts[i] > R.right()) continue; + Point P (rts[i], R.top()); + if (are_near (P, corner1)) + P = corner1; + else if (are_near (P, corner2)) + P = corner2; + + cpts.push_back (P); + } + if (cpts.size() == 2 && are_near (cpts[0], cpts[1])) + { + cpts[0] = middle_point (cpts[0], cpts[1]); + cpts.pop_back(); + } + } + + // left edge + cs.roots (rts, R.left(), X); + if (rts.size() != 0) + { + no_crossing = false; + DBGPRINT ("CLIP: left: rts[0] = ", rts[0]) + DBGPRINTIF ((rts.size() == 2), "CLIP: left: rts[1] = ", rts[1]) + + Point corner1 = R.corner(TOP_LEFT); + Point corner2 = R.corner(BOTTOM_LEFT); + + for (size_t i = 0; i < rts.size(); ++i) + { + if (rts[i] < R.top() || rts[i] > R.bottom()) continue; + Point P (R.left(), rts[i]); + if (are_near (P, corner1)) + P = corner1; + else if (are_near (P, corner2)) + P = corner2; + + cpts.push_back (P); + } + if (cpts.size() == 2 && are_near (cpts[0], cpts[1])) + { + cpts[0] = middle_point (cpts[0], cpts[1]); + cpts.pop_back(); + } + } + + // bottom edge + cs.roots (rts, R.bottom(), Y); + if (rts.size() != 0) + { + no_crossing = false; + DBGPRINT ("CLIP: bottom: rts[0] = ", rts[0]) + DBGPRINTIF ((rts.size() == 2), "CLIP: bottom: rts[1] = ", rts[1]) + + Point corner1 = R.corner(BOTTOM_RIGHT); + Point corner2 = R.corner(BOTTOM_LEFT); + + for (size_t i = 0; i < rts.size(); ++i) + { + if (rts[i] < R.left() || rts[i] > R.right()) continue; + Point P (rts[i], R.bottom()); + if (are_near (P, corner1)) + P = corner1; + else if (are_near (P, corner2)) + P = corner2; + + cpts.push_back (P); + } + if (cpts.size() == 2 && are_near (cpts[0], cpts[1])) + { + cpts[0] = middle_point (cpts[0], cpts[1]); + cpts.pop_back(); + } + } + + DBGPRINT ("CLIP: intersect: crossing_points.size (with duplicates) = ", + cpts.size()) + + // remove duplicates + std::sort (cpts.begin(), cpts.end(), lex_lesser()); + cpts.erase (std::unique (cpts.begin(), cpts.end()), cpts.end()); + + + // Order crossing points on the rectangle edge clockwise, so two consecutive + // crossing points would be the end points of a conic arc all inside or all + // outside the rectangle. + std::map<double, size_t> cp_angles; + for (size_t i = 0; i < cpts.size(); ++i) + { + cp_angles.insert (std::make_pair (cs.angle_at (cpts[i]), i)); + } + + std::map<double, size_t>::const_iterator pos; + for (pos = cp_angles.begin(); pos != cp_angles.end(); ++pos) + { + crossing_points.push_back (cpts[pos->second]); + } + + DBGPRINT ("CLIP: intersect: crossing_points.size = ", crossing_points.size()) + DBGPRINTCOLL ("CLIP: intersect: crossing_points:", crossing_points) + + return no_crossing; +} // end function intersect + + + +inline +double signed_triangle_area (Point const& p1, Point const& p2, Point const& p3) +{ + return (cross(p3, p2) - cross(p3, p1) + cross(p2, p1)); +} + + +/* + * Test if two crossing points are the end points of a conic arc inner to the + * rectangle. In such a case the method returns true, else it returns false. + * Moreover by the parameter "M" it returns a point inner to the conic arc + * with the given end-points. + * + */ +bool CLIPPER_CLASS::are_paired (Point& M, const Point & P1, const Point & P2) const +{ + /* + * we looks for the points on the conic whose tangent is parallel to the + * arc chord P1P2, they will be extrema of the conic arc P1P2 wrt the + * direction orthogonal to the chord + */ + Point dir = P2 - P1; + DBGPRINT ("CLIP: are_paired: first point: ", P1) + DBGPRINT ("CLIP: are_paired: second point: ", P2) + + double grad0 = 2 * cs.coeff(0) * dir[0] + cs.coeff(1) * dir[1]; + double grad1 = cs.coeff(1) * dir[0] + 2 * cs.coeff(2) * dir[1]; + double grad2 = cs.coeff(3) * dir[0] + cs.coeff(4) * dir[1]; + + + /* + * such points are found intersecating the conic section with the line + * orthogonal to "grad": the derivative wrt the "dir" direction + */ + Line gl (grad0, grad1, grad2); + std::vector<double> rts; + rts = cs.roots (gl); + DBGPRINT ("CLIP: are_paired: extrema: rts.size() = ", rts.size()) + + + + std::vector<Point> extrema; + for (size_t i = 0; i < rts.size(); ++i) + { + extrema.push_back (gl.pointAt (rts[i])); + } + + if (extrema.size() == 2) + { + // in case we are dealing with an hyperbola we could have two extrema + // on the same side wrt the line passing through P1 and P2, but + // only the nearer extremum is on the arc P1P2 + double side0 = signed_triangle_area (P1, extrema[0], P2); + double side1 = signed_triangle_area (P1, extrema[1], P2); + + if (sgn(side0) == sgn(side1)) + { + if (std::fabs(side0) > std::fabs(side1)) + { + std::swap (extrema[0], extrema[1]); + } + extrema.pop_back(); + } + } + + std::vector<Point> inner_points; + for (size_t i = 0; i < extrema.size(); ++i) + { + if (!R.contains (extrema[i])) continue; + // in case we are dealing with an ellipse tangent to two orthogonal + // rectangle edges we could have two extrema on opposite sides wrt the + // line passing through P1P2 and both inner the rectangle; anyway, since + // we order the crossing points clockwise we have only one extremum + // that follows such an ordering wrt P1 and P2; + // remark: the other arc will be selected when we test for the arc P2P1. + double P1angle = cs.angle_at (P1); + double P2angle = cs.angle_at (P2); + double Qangle = cs.angle_at (extrema[i]); + if (P1angle < P2angle && !(P1angle <= Qangle && Qangle <= P2angle)) + continue; + if (P1angle > P2angle && !(P1angle <= Qangle || Qangle <= P2angle)) + continue; + + inner_points.push_back (extrema[i]); + } + + if (inner_points.size() > 1) + { + THROW_LOGICALERROR ("conic section clipper: " + "more than one extremum found"); + } + else if (inner_points.size() == 1) + { + M = inner_points.front(); + return true; + } + + return false; +} + + +/* + * Pair the points contained in the "crossing_points" vector; the paired points + * are put in the paired_points vector so that given a point with an even index + * and the next one they are the end points of a conic arc that is inner to the + * rectangle. In the "inner_points" are returned points that are inner to the + * arc, where the inner point with index k is related to the arc with end + * points with indexes 2k, 2k+1. In case there are unpaired points the are put + * in to the "single_points" vector. + */ +void CLIPPER_CLASS::pairing (std::vector<Point> & paired_points, + std::vector<Point> & inner_points, + const std::vector<Point> & crossing_points) +{ + paired_points.clear(); + paired_points.reserve (crossing_points.size()); + + inner_points.clear(); + inner_points.reserve (crossing_points.size() / 2); + + single_points.clear(); + + // to keep trace of which crossing points have been paired + std::vector<bool> paired (crossing_points.size(), false); + + Point M; + + // by the way we have ordered crossing points we need to test one point wrt + // the next point only, for pairing; moreover the last point need to be + // tested wrt the first point; pay attention: one point can be paired both + // with the previous and the next one: this is not an error, think of + // crossing points that are tangent to the rectangle edge (and inner); + for (size_t i = 0; i < crossing_points.size(); ++i) + { + // we need to test the last point wrt the first one + size_t j = (i == 0) ? (crossing_points.size() - 1) : (i-1); + if (are_paired (M, crossing_points[j], crossing_points[i])) + { +#ifdef CLIP_WITH_CAIRO_SUPPORT + cairo_set_source_rgba(cr, 0.1, 0.1, 0.8, 1.0); + draw_line_seg (cr, crossing_points[j], crossing_points[i]); + draw_handle (cr, crossing_points[j]); + draw_handle (cr, crossing_points[i]); + draw_handle (cr, M); + cairo_stroke (cr); +#endif + paired[j] = paired[i] = true; + paired_points.push_back (crossing_points[j]); + paired_points.push_back (crossing_points[i]); + inner_points.push_back (M); + } + } + + // some point are not paired with any point, e.g. a crossing point tangent + // to a rectangle edge but with the conic arc outside the rectangle + for (size_t i = 0; i < paired.size(); ++i) + { + if (!paired[i]) + single_points.push_back (crossing_points[i]); + } + DBGPRINTCOLL ("single_points", single_points) + +} + + +/* + * This method clip the section conic wrt the rectangle and returns the inner + * conic arcs as a vector of RatQuad objects by the "arcs" parameter. + */ +bool CLIPPER_CLASS::clip (std::vector<RatQuad> & arcs) +{ + arcs.clear(); + std::vector<Point> crossing_points; + std::vector<Point> paired_points; + std::vector<Point> inner_points; + + Line l1, l2; + if (cs.decompose (l1, l2)) + { + bool inner_empty = true; + + DBGINFO ("CLIP: degenerate section conic") + + boost::optional<LineSegment> ls1 = Geom::clip (l1, R); + if (ls1) + { + if (ls1->isDegenerate()) + { + single_points.push_back (ls1->initialPoint()); + } + else + { + Point M = middle_point (*ls1); + arcs.push_back + (RatQuad (ls1->initialPoint(), M, ls1->finalPoint(), 1)); + inner_empty = false; + } + } + + boost::optional<LineSegment> ls2 = Geom::clip (l2, R); + if (ls2) + { + if (ls2->isDegenerate()) + { + single_points.push_back (ls2->initialPoint()); + } + else + { + Point M = middle_point (*ls2); + arcs.push_back + (RatQuad (ls2->initialPoint(), M, ls2->finalPoint(), 1)); + inner_empty = false; + } + } + + return !inner_empty; + } + + + bool no_crossing = intersect (crossing_points); + + // if the only crossing point is a rectangle corner than the section conic + // is all outside the rectangle + if (crossing_points.size() == 1) + { + for (size_t i = 0; i < 4; ++i) + { + if (crossing_points[0] == R.corner(i)) + { + single_points.push_back (R.corner(i)); + return false; + } + } + } + + // if the conic does not cross any line passing through a rectangle edge or + // it is tangent to only one edge then it is an ellipse + if (no_crossing + || (crossing_points.size() == 1 && single_points.size() == 0)) + { + // if the ellipse centre is inside the rectangle + // then so it is the ellipse + boost::optional<Point> c = cs.centre(); + if (c && R.contains (*c)) + { + DBGPRINT ("CLIP: ellipse with centre", *c) + // we set paired and inner points by finding the ellipse + // intersection with its axes; this choice let us having a more + // accurate RatQuad parametric arc + paired_points.resize(4); + std::vector<double> rts; + double angle = cs.axis_angle(); + Line axis1 (*c, angle); + rts = cs.roots (axis1); + if (rts[0] > rts[1]) std::swap (rts[0], rts[1]); + paired_points[0] = axis1.pointAt (rts[0]); + paired_points[1] = axis1.pointAt (rts[1]); + paired_points[2] = paired_points[1]; + paired_points[3] = paired_points[0]; + Line axis2 (*c, angle + M_PI/2); + rts = cs.roots (axis2); + if (rts[0] > rts[1]) std::swap (rts[0], rts[1]); + inner_points.push_back (axis2.pointAt (rts[0])); + inner_points.push_back (axis2.pointAt (rts[1])); + } + else if (crossing_points.size() == 1) + { + // so we have a tangent crossing point but the ellipse is outside + // the rectangle + single_points.push_back (crossing_points[0]); + } + } + else + { + // in case the conic section intersects any of the four lines passing + // through the rectangle edges but it does not cross any rectangle edge + // then the conic is all outer of the rectangle + if (crossing_points.size() == 0) return false; + // else we need to pair crossing points, and to find an arc inner point + // in order to generate a RatQuad object + pairing (paired_points, inner_points, crossing_points); + } + + + // we split arcs until the end-point distance is less than a given value, + // in this way the RatQuad parametrization is enough accurate + std::list<Point> points; + std::list<Point>::iterator sp, ip, fp; + for (size_t i = 0, j = 0; i < paired_points.size(); i += 2, ++j) + { + //DBGPRINT ("CLIP: clip: P = ", paired_points[i]) + //DBGPRINT ("CLIP: clip: M = ", inner_points[j]) + //DBGPRINT ("CLIP: clip: Q = ", paired_points[i+1]) + + // in case inner point and end points are near is better not split + // the conic arc further or we could get a degenerate RatQuad object + if (are_near (paired_points[i], inner_points[j], 1e-4) + && are_near (paired_points[i+1], inner_points[j], 1e-4)) + { + arcs.push_back (cs.toRatQuad (paired_points[i], + inner_points[j], + paired_points[i+1])); + continue; + } + + // populate the list + points.push_back(paired_points[i]); + points.push_back(inner_points[j]); + points.push_back(paired_points[i+1]); + + // an initial unconditioned splitting + sp = points.begin(); + ip = sp; ++ip; + fp = ip; ++fp; + rsplit (points, sp, ip, size_t(1u)); + rsplit (points, ip, fp, size_t(1u)); + + // length conditioned split + sp = points.begin(); + fp = sp; ++fp; + while (fp != points.end()) + { + rsplit (points, sp, fp, 100.0); + sp = fp; + ++fp; + } + + sp = points.begin(); + ip = sp; ++ip; + fp = ip; ++fp; + //DBGPRINT ("CLIP: points ", j) + //DBGPRINT ("CLIP: points.size = ", points.size()) + while (ip != points.end()) + { +#ifdef CLIP_WITH_CAIRO_SUPPORT + cairo_set_source_rgba(cr, 0.1, 0.1, 0.8, 1.0); + draw_handle (cr, *sp); + draw_handle (cr, *ip); + cairo_stroke (cr); +#endif + //std::cerr << "CLIP: arc: [" << *sp << ", " << *ip << ", " + // << *fp << "]" << std::endl; + arcs.push_back (cs.toRatQuad (*sp, *ip, *fp)); + sp = fp; + ip = sp; ++ip; + fp = ip; ++fp; + } + points.clear(); + } + DBGPRINT ("CLIP: arcs.size() = ", arcs.size()) + return (arcs.size() != 0); +} // end method clip + + +} // end 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/conic_section_clipper_impl.h b/src/2geom/conic_section_clipper_impl.h new file mode 100644 index 000000000..7db4fca9f --- /dev/null +++ b/src/2geom/conic_section_clipper_impl.h @@ -0,0 +1,356 @@ +/** + * \file + * \brief Conic section clipping with respect to a rectangle + * + * Authors: + * Marco Cecchetti <mrcekets at gmail> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + + + +#ifndef _2GEOM_CONIC_SECTION_CLIPPER_IMPL_H_ +#define _2GEOM_CONIC_SECTION_CLIPPER_IMPL_H_ + + +#include <2geom/conicsec.h> +#include <2geom/line.h> + +#include <list> +#include <map> + + + +#ifdef CLIP_WITH_CAIRO_SUPPORT + #include <2geom/toys/path-cairo.h> + #define CLIPPER_CLASS clipper_cr +#else + #define CLIPPER_CLASS clipper +#endif + +//#define CLIPDBG + +#ifdef CLIPDBG +#include <2geom/toys/path-cairo.h> +#define DBGINFO(msg) \ + std::cerr << msg << std::endl; +#define DBGPRINT(msg, var) \ + std::cerr << msg << var << std::endl; +#define DBGPRINTIF(cond, msg, var) \ + if (cond) \ + std::cerr << msg << var << std::endl; + +#define DBGPRINT2(msg1, var1, msg2, var2) \ + std::cerr << msg1 << var1 << msg2 << var2 << std::endl; + +#define DBGPRINTCOLL(msg, coll) \ + if (coll.size() != 0) \ + std::cerr << msg << ":\n"; \ + for (size_t i = 0; i < coll.size(); ++i) \ + { \ + std::cerr << i << ": " << coll[i] << "\n"; \ + } + +#else +#define DBGINFO(msg) +#define DBGPRINT(msg, var) +#define DBGPRINTIF(cond, msg, var) +#define DBGPRINT2(msg1, var1, msg2, var2) +#define DBGPRINTCOLL(msg, coll) +#endif + + + + +namespace Geom +{ + +class CLIPPER_CLASS +{ + + public: + +#ifdef CLIP_WITH_CAIRO_SUPPORT + clipper_cr (cairo_t* _cr, const xAx & _cs, const Rect & _R) + : cr(_cr), cs(_cs), R(_R) + { + DBGPRINT ("CLIP: right side: ", R.right()) + DBGPRINT ("CLIP: top side: ", R.top()) + DBGPRINT ("CLIP: left side: ", R.left()) + DBGPRINT ("CLIP: bottom side: ", R.bottom()) + } +#else + clipper (const xAx & _cs, const Rect & _R) + : cs(_cs), R(_R) + { + } +#endif + + bool clip (std::vector<RatQuad> & arcs); + + bool found_any_isolated_point() const + { + return (single_points.size() != 0); + } + + const std::vector<Point> & isolated_points() const + { + return single_points; + } + + + private: + bool intersect (std::vector<Point> & crossing_points) const; + + bool are_paired (Point & M, const Point & P1, const Point & P2) const; + void pairing (std::vector<Point> & paired_points, + std::vector<Point> & inner_points, + const std::vector<Point> & crossing_points); + + Point find_inner_point_by_bisector_line (const Point & P, + const Point & Q) const; + Point find_inner_point (const Point & P, const Point & Q) const; + + std::list<Point>::iterator split (std::list<Point> & points, + std::list<Point>::iterator sp, + std::list<Point>::iterator fp) const; + void rsplit (std::list<Point> & points, + std::list<Point>::iterator sp, + std::list<Point>::iterator fp, + size_t k) const; + + void rsplit (std::list<Point> & points, + std::list<Point>::iterator sp, + std::list<Point>::iterator fp, + double length) const; + + private: +#ifdef CLIP_WITH_CAIRO_SUPPORT + cairo_t* cr; +#endif + const xAx & cs; + const Rect & R; + std::vector<Point> single_points; +}; + + + + +/* + * Given two point "P", "Q" on the conic section the method computes + * a third point inner to the arc with end-point "P", "Q". + * The new point is found by intersecting the conic with the bisector line + * of the PQ line segment. + */ +inline +Point CLIPPER_CLASS::find_inner_point_by_bisector_line (const Point & P, + const Point & Q) const +{ + DBGPRINT ("CLIP: find_inner_point_by_bisector_line: P = ", P) + DBGPRINT ("CLIP: find_inner_point_by_bisector_line: Q = ", Q) + Line bl = make_bisector_line (LineSegment (P, Q)); + std::vector<double> rts = cs.roots (bl); + //DBGPRINT ("CLIP: find_inner_point: rts.size = ", rts.size()) + double t; + if (rts.size() == 0) + { + THROW_LOGICALERROR ("clipper::find_inner_point_by_bisector_line: " + "no conic-bisector line intersection point"); + } + if (rts.size() == 2) + { + // we suppose that the searched point is the nearest + // to the line segment PQ + t = (std::fabs(rts[0]) < std::fabs(rts[1])) ? rts[0] : rts[1]; + } + else + { + t = rts[0]; + } + return bl.pointAt (t); +} + + +/* + * Given two point "P", "Q" on the conic section the method computes + * a third point inner to the arc with end-point "P", "Q". + * The new point is found by intersecting the conic with the line + * passing through the middle point of the PQ line segment and + * the intersection point of the tangent lines at points P and Q. + */ +inline +Point CLIPPER_CLASS::find_inner_point (const Point & P, const Point & Q) const +{ + + Line l1 = cs.tangent (P); + Line l2 = cs.tangent (Q); + Line l; + // in case we fail to find a crossing point we fall back to the bisector + // method + try + { + OptCrossing oc = intersection(l1, l2); + if (!oc) + { + return find_inner_point_by_bisector_line (P, Q); + } + l.setPoints (l1.pointAt (oc->ta), middle_point (P, Q)); + } + catch (Geom::InfiniteSolutions e) + { + return find_inner_point_by_bisector_line (P, Q); + } + + std::vector<double> rts = cs.roots (l); + double t; + if (rts.size() == 0) + { + return find_inner_point_by_bisector_line (P, Q); + } + // the line "l" origin is set to the tangent crossing point so in case + // we find two intersection points only the nearest belongs to the given arc + // pay attention: in case we are dealing with an hyperbola (remember that + // end points are on the same branch, because they are paired) the tangent + // crossing point belongs to the angle delimited by hyperbola asymptotes + // and containing the given hyperbola branch, so the previous statement is + // still true + if (rts.size() == 2) + { + t = (std::fabs(rts[0]) < std::fabs(rts[1])) ? rts[0] : rts[1]; + } + else + { + t = rts[0]; + } + return l.pointAt (t); +} + + +/* + * Given a list of points on the conic section, and given two consecutive + * points belonging to the list and passed by two list iterators, the method + * finds a new point that is inner to the conic arc which has the two passed + * points as initial and final point. This new point is inserted into the list + * between the two passed points and an iterator pointing to the new point + * is returned. + */ +inline +std::list<Point>::iterator CLIPPER_CLASS::split (std::list<Point> & points, + std::list<Point>::iterator sp, + std::list<Point>::iterator fp) const +{ + Point new_point = find_inner_point (*sp, *fp); + std::list<Point>::iterator ip = points.insert (fp, new_point); + //std::cerr << "CLIP: split: [" << *sp << ", " << *ip << ", " + // << *fp << "]" << std::endl; + return ip; +} + + +/* + * Given a list of points on the conic section, and given two consecutive + * points belonging to the list and passed by two list iterators, the method + * recursively finds new points that are inner to the conic arc which has + * the two passed points as initial and final point. The recursion stop after + * "k" recursive calls. These new points are inserted into the list between + * the two passed points, and in the order we cross them going from + * the initial to the final arc point. + */ +inline +void CLIPPER_CLASS::rsplit (std::list<Point> & points, + std::list<Point>::iterator sp, + std::list<Point>::iterator fp, + size_t k) const +{ + if (k == 0) + { + //DBGINFO("CLIP: split: no further split") + return; + } + + std::list<Point>::iterator ip = split (points, sp, fp); + --k; + rsplit (points, sp, ip, k); + rsplit (points, ip, fp, k); +} + + +/* + * Given a list of points on the conic section, and given two consecutive + * points belonging to the list and passed by two list iterators, the method + * recursively finds new points that are inner to the conic arc which has + * the two passed points as initial and final point. The recursion stop when + * the max distance between the new computed inner point and the two passed + * arc end-points is less then the value specified by the "length" parameter. + * These new points are inserted into the list between the two passed points, + * and in the order we cross them going from the initial to the final arc point. + */ +inline +void CLIPPER_CLASS::rsplit (std::list<Point> & points, + std::list<Point>::iterator sp, + std::list<Point>::iterator fp, + double length) const +{ + std::list<Point>::iterator ip = split (points, sp, fp); + double d1 = distance (*sp, *ip); + double d2 = distance (*ip, *fp); + double mdist = std::max (d1, d2); + + if (mdist < length) + { + //DBGINFO("CLIP: split: no further split") + return; + } + + // they have to be called both to keep the number of points in the list + // in the form 2k+1 where k are the sub-arcs the initial arc is splitted in. + rsplit (points, sp, ip, length); + rsplit (points, ip, fp, length); +} + + +} // end namespace Geom + + + + +#endif // _2GEOM_CONIC_SECTION_CLIPPER_IMPL_H_ + + + + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp new file mode 100644 index 000000000..2a537a1f0 --- /dev/null +++ b/src/2geom/conicsec.cpp @@ -0,0 +1,1564 @@ +/** + * \file + * \brief Circle Curve + * + * Authors: + * Nathan Hurst <njh@njhurst.com + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#include <2geom/conicsec.h> +#include <2geom/conic_section_clipper.h> +#include <2geom/numeric/fitting-tool.h> +#include <2geom/numeric/fitting-model.h> + + +// File: convert.h +#include <utility> +#include <sstream> +#include <stdexcept> + + + + + +namespace Geom +{ + +LineSegment intersection(Line l, Rect r) { + Point p0, p1; + double a,b,c; + std::vector<double> ifc = l.coefficients(); + a = ifc[0]; + b = ifc[1]; + c = ifc[2]; + if (fabs(b) > fabs(a)) { + p0 = Point(r[0][0], (-c - a*r[0][0])/b); + if (p0[1] < r[1][0]) + p0 = Point((-c - b*r[1][0])/a, r[1][0]); + if (p0[1] > r[1][1]) + p0 = Point((-c - b*r[1][1])/a, r[1][1]); + p1 = Point(r[0][1], (-c - a*r[0][1])/b); + if (p1[1] < r[1][0]) + p1 = Point((-c - b*r[1][0])/a, r[1][0]); + if (p1[1] > r[1][1]) + p1 = Point((-c - b*r[1][1])/a, r[1][1]); + } else { + p0 = Point((-c - b*r[1][0])/a, r[1][0]); + if (p0[0] < r[0][0]) + p0 = Point(r[0][0], (-c - a*r[0][0])/b); + if (p0[0] > r[0][1]) + p0 = Point(r[0][1], (-c - a*r[0][1])/b); + p1 = Point((-c - b*r[1][1])/a, r[1][1]); + if (p1[0] < r[0][0]) + p1 = Point(r[0][0], (-c - a*r[0][0])/b); + if (p1[0] > r[0][1]) + p1 = Point(r[0][1], (-c - a*r[0][1])/b); + } + return LineSegment(p0, p1); +} + +static double det(Point a, Point b) { + return a[0]*b[1] - a[1]*b[0]; +} + +template <typename T> +static T det(T a, T b, T c, T d) { + return a*d - b*c; +} + +template <typename T> +static T det(T M[2][2]) { + return M[0][0]*M[1][1] - M[1][0]*M[0][1]; +} + +template <typename T> +static T det3(T M[3][3]) { + return ( M[0][0] * det(M[1][1], M[1][2], + M[2][1], M[2][2]) + -M[1][0] * det(M[0][1], M[0][2], + M[2][1], M[2][2]) + +M[2][0] * det(M[0][1], M[0][2], + M[1][1], M[1][2])); +} + +static double boxprod(Point a, Point b, Point c) { + return det(a,b) - det(a,c) + det(b,c); +} + + +/** + * Find the roots of (q2x + q1)x+q0 = 0 + * Tries to be numerically robust. + */ +template <typename T> +static std::vector<T> quadratic_roots(T q0, T q1, T q2) { + std::vector<double> r; + if(q2 == 0) { + if(q1 == 0) { // zero or infinite roots + return r; + } + r.push_back(-q0/q1); + } else { + double desc = q1*q1 - 4*q2*q0; + /*cout << q2 << ", " + << q1 << ", " + << q0 << "; " + << desc << "\n";*/ + if (desc < 0) + return r; + else if (desc == 0) + r.push_back(-q1/(2*q2)); + else { + desc = std::sqrt(desc); + double t = -0.5*(q1+sgn(q1)*desc); + r.push_back(t/q2); + r.push_back(q0/t); + } + } + return r; +} + + + +class BadConversion : public std::runtime_error { +public: + BadConversion(const std::string& s) + : std::runtime_error(s) + { } +}; + +template <typename T> +inline std::string stringify(T x) +{ + std::ostringstream o; + if (!(o << x)) + throw BadConversion("stringify(T)"); + return o.str(); +} + + /* A G4 continuous cubic parametric approximation for rational quadratics. + See + An analysis of cubic approximation schemes for conic sections + Michael Floater + SINTEF + + This is less accurate overall than some of his other schemes, but + produces very smooth joins and is still optimally h^-6 + convergent. + */ + +double RatQuad::lambda() const { + return 2*(6*w*w +1 -std::sqrt(3*w*w+1))/(12*w*w+3); +} + +RatQuad RatQuad::fromPointsTangents(Point P0, Point dP0, + Point P, + Point P2, Point dP2) { + Line Line0 = Line::from_origin_and_versor(P0, dP0); + Line Line2 = Line::from_origin_and_versor(P2, dP2); + try { + OptCrossing oc = intersection(Line0, Line2); + if(!oc) // what to do? + return RatQuad(Point(), Point(), Point(), 0); // need opt really + //assert(0); + Point P1 = Line0.pointAt((*oc).ta); + double triarea = boxprod(P0, P1, P2); +// std::cout << "RatQuad::fromPointsTangents: triarea = " << triarea << std::endl; + if (triarea == 0) + { + return RatQuad(P0, 0.5*(P0+P2), P2, 1); + } + double tau0 = boxprod(P, P1, P2)/triarea; + double tau1 = boxprod(P0, P, P2)/triarea; + double tau2 = boxprod(P0, P1, P)/triarea; + if (tau0 == 0 || tau1 == 0 || tau2 == 0) + { + return RatQuad(P0, 0.5*(P0+P2), P2, 1); + } + double w = tau1/(2*std::sqrt(tau0*tau2)); +// std::cout << "RatQuad::fromPointsTangents: tau0 = " << tau0 << std::endl; +// std::cout << "RatQuad::fromPointsTangents: tau1 = " << tau1 << std::endl; +// std::cout << "RatQuad::fromPointsTangents: tau2 = " << tau2 << std::endl; +// std::cout << "RatQuad::fromPointsTangents: w = " << w << std::endl; + return RatQuad(P0, P1, P2, w); + } catch(Geom::InfiniteSolutions) { + return RatQuad(P0, 0.5*(P0+P2), P2, 1); + } + return RatQuad(Point(), Point(), Point(), 0); // need opt really +} + +RatQuad RatQuad::circularArc(Point P0, Point P1, Point P2) { + Line Line0 = Line::from_origin_and_versor(P0, P1 - P0); + Line Line2 = Line::from_origin_and_versor(P2, P1 - P2); + return RatQuad(P0, P1, P2, dot(unit_vector(P0 - P1), unit_vector(P0 - P2))); +} + + +CubicBezier RatQuad::toCubic() const { + return toCubic(lambda()); +} + +CubicBezier RatQuad::toCubic(double lamb) const { + return CubicBezier(P[0], + (1-lamb)*P[0] + lamb*P[1], + (1-lamb)*P[2] + lamb*P[1], + P[2]); +} + +Point RatQuad::pointAt(double t) const { + Bezier xt(P[0][0], P[1][0]*w, P[2][0]); + Bezier yt(P[0][1], P[1][1]*w, P[2][1]); + double wt = Bezier(1, w, 1).valueAt(t); + return Point(xt.valueAt(t)/wt, + yt.valueAt(t)/wt); +} + +void RatQuad::split(RatQuad &a, RatQuad &b) const { + a.P[0] = P[0]; + b.P[2] = P[2]; + a.P[1] = (P[0]+w*P[1])/(1+w); + b.P[1] = (w*P[1]+P[2])/(1+w); + a.w = b.w = std::sqrt((1+w)/2); + a.P[2] = b.P[0] = (0.5*a.P[1]+0.5*b.P[1]); +} + + +D2<SBasis> RatQuad::hermite() const { + SBasis t = Linear(0, 1); + SBasis omt = Linear(1, 0); + + D2<SBasis> out(omt*omt*P[0][0]+2*omt*t*P[1][0]*w+t*t*P[2][0], + omt*omt*P[0][1]+2*omt*t*P[1][1]*w+t*t*P[2][1]); + for(int dim = 0; dim < 2; dim++) { + out[dim] = divide(out[dim], (omt*omt+2*omt*t*w+t*t), 2); + } + return out; +} + + std::vector<SBasis> RatQuad::homogenous() const { + std::vector<SBasis> res(3, SBasis()); + Bezier xt(P[0][0], P[1][0]*w, P[2][0]); + bezier_to_sbasis(res[0],xt); + Bezier yt(P[0][1], P[1][1]*w, P[2][1]); + bezier_to_sbasis(res[1],yt); + Bezier wt(1, w, 1); + bezier_to_sbasis(res[2],wt); + return res; +} + +#if 0 + std::string xAx::categorise() const { + double M[3][3] = {{c[0], c[1], c[3]}, + {c[1], c[2], c[4]}, + {c[3], c[4], c[5]}}; + double D = det3(M); + if (c[0] == 0 && c[1] == 0 && c[2] == 0) + return "line"; + std::string res = stringify(D); + double descr = c[1]*c[1] - c[0]*c[2]; + if (descr < 0) { + if (c[0] == c[2] && c[1] == 0) + return res + "circle"; + return res + "ellipse"; + } else if (descr == 0) { + return res + "parabola"; + } else if (descr > 0) { + if (c[0] + c[2] == 0) { + if (D == 0) + return res + "two lines"; + return res + "rectangular hyperbola"; + } + return res + "hyperbola"; + + } + return "no idea!"; +} +#endif + + +std::vector<Point> decompose_degenerate(xAx const & C1, xAx const & C2, xAx const & xC0) { + std::vector<Point> res; + double A[2][2] = {{2*xC0.c[0], xC0.c[1]}, + {xC0.c[1], 2*xC0.c[2]}}; +//Point B0 = xC0.bottom(); + double const determ = det(A); + //std::cout << determ << "\n"; + if (fabs(determ) >= 1e-20) { // hopeful, I know + Geom::Coord const ideterm = 1.0 / determ; + + double b[2] = {-xC0.c[3], -xC0.c[4]}; + Point B0((A[1][1]*b[0] -A[0][1]*b[1]), + (-A[1][0]*b[0] + A[0][0]*b[1])); + B0 *= ideterm; + Point n0, n1; + // Are these just the eigenvectors of A11? + if(xC0.c[0] == xC0.c[2]) { + double b = 0.5*xC0.c[1]/xC0.c[0]; + double c = xC0.c[2]/xC0.c[0]; + //assert(fabs(b*b-c) > 1e-10); + double d = std::sqrt(b*b-c); + //assert(fabs(b-d) > 1e-10); + n0 = Point(1, b+d); + n1 = Point(1, b-d); + } else if(fabs(xC0.c[0]) > fabs(xC0.c[2])) { + double b = 0.5*xC0.c[1]/xC0.c[0]; + double c = xC0.c[2]/xC0.c[0]; + //assert(fabs(b*b-c) > 1e-10); + double d = std::sqrt(b*b-c); + //assert(fabs(b-d) > 1e-10); + n0 = Point(1, b+d); + n1 = Point(1, b-d); + } else { + double b = 0.5*xC0.c[1]/xC0.c[2]; + double c = xC0.c[0]/xC0.c[2]; + //assert(fabs(b*b-c) > 1e-10); + double d = std::sqrt(b*b-c); + //assert(fabs(b-d) > 1e-10); + n0 = Point(b+d, 1); + n1 = Point(b-d, 1); + } + + Line L0 = Line::from_origin_and_versor(B0, rot90(n0)); + Line L1 = Line::from_origin_and_versor(B0, rot90(n1)); + + std::vector<double> rts = C1.roots(L0); + for(unsigned i = 0; i < rts.size(); i++) { + Point P = L0.pointAt(rts[i]); + res.push_back(P); + } + rts = C1.roots(L1); + for(unsigned i = 0; i < rts.size(); i++) { + Point P = L1.pointAt(rts[i]); + res.push_back(P); + } + } else { + // single or double line + // check for completely zero case (what to do?) + assert(xC0.c[0] || xC0.c[1] || + xC0.c[2] || xC0.c[3] || + xC0.c[4] || xC0.c[5]); + Point trial_pt(0,0); + Point g = xC0.gradient(trial_pt); + if(L2sq(g) == 0) { + trial_pt[0] += 1; + g = xC0.gradient(trial_pt); + if(L2sq(g) == 0) { + trial_pt[1] += 1; + g = xC0.gradient(trial_pt); + if(L2sq(g) == 0) { + trial_pt[0] += 1; + g = xC0.gradient(trial_pt); + if(L2sq(g) == 0) { + trial_pt = Point(1.5,0.5); + g = xC0.gradient(trial_pt); + } + } + } + } + //std::cout << trial_pt << ", " << g << "\n"; + /** + * At this point we have tried up to 4 points: 0,0, 1,0, 1,1, 2,1, 1.5,1.5 + * + * No degenerate conic can pass through these points, so we can assume + * that we've found a perpendicular to the double line. + * Proof: + * any degenerate must consist of at most 2 lines. 1.5,0.5 is not on any pair of lines + * passing through the previous 4 trials. + * + * alternatively, there may be a way to determine this directly from xC0 + */ + assert(L2sq(g) != 0); + + Line Lx = Line::from_origin_and_versor(trial_pt, g); // a line along the gradient + std::vector<double> rts = xC0.roots(Lx); + for(unsigned i = 0; i < rts.size(); i++) { + Point P0 = Lx.pointAt(rts[i]); + //std::cout << P0 << "\n"; + Line L = Line::from_origin_and_versor(P0, rot90(g)); + std::vector<double> cnrts; + // It's very likely that at least one of the conics is degenerate, this will hopefully pick the more generate of the two. + if(fabs(C1.hessian().det()) > fabs(C2.hessian().det())) + cnrts = C1.roots(L); + else + cnrts = C2.roots(L); + for(unsigned j = 0; j < cnrts.size(); j++) { + Point P = L.pointAt(cnrts[j]); + res.push_back(P); + } + } + } + return res; +} + +double xAx_descr(xAx const & C) { + double mC[3][3] = {{C.c[0], (C.c[1])/2, (C.c[3])/2}, + {(C.c[1])/2, C.c[2], (C.c[4])/2}, + {(C.c[3])/2, (C.c[4])/2, C.c[5]}}; + + return det3(mC); +} + + +std::vector<Point> intersect(xAx const & C1, xAx const & C2) { + // You know, if either of the inputs are degenerate we should use them first! + if(xAx_descr(C1) == 0) { + return decompose_degenerate(C1, C2, C1); + } + if(xAx_descr(C2) == 0) { + return decompose_degenerate(C1, C2, C2); + } + std::vector<Point> res; + SBasis T(Linear(-1,1)); + SBasis S(Linear(1,1)); + SBasis C[3][3] = {{T*C1.c[0]+S*C2.c[0], (T*C1.c[1]+S*C2.c[1])/2, (T*C1.c[3]+S*C2.c[3])/2}, + {(T*C1.c[1]+S*C2.c[1])/2, T*C1.c[2]+S*C2.c[2], (T*C1.c[4]+S*C2.c[4])/2}, + {(T*C1.c[3]+S*C2.c[3])/2, (T*C1.c[4]+S*C2.c[4])/2, T*C1.c[5]+S*C2.c[5]}}; + + SBasis D = det3(C); + std::vector<double> rts = Geom::roots(D); + if(rts.empty()) { + T = Linear(1,1); + S = Linear(-1,1); + SBasis C[3][3] = {{T*C1.c[0]+S*C2.c[0], (T*C1.c[1]+S*C2.c[1])/2, (T*C1.c[3]+S*C2.c[3])/2}, + {(T*C1.c[1]+S*C2.c[1])/2, T*C1.c[2]+S*C2.c[2], (T*C1.c[4]+S*C2.c[4])/2}, + {(T*C1.c[3]+S*C2.c[3])/2, (T*C1.c[4]+S*C2.c[4])/2, T*C1.c[5]+S*C2.c[5]}}; + + D = det3(C); + rts = Geom::roots(D); + } + // at this point we have a T and S and perhaps some roots that represent our degenerate conic + // Let's just pick one randomly (can we do better?) + //for(unsigned i = 0; i < rts.size(); i++) { + if(!rts.empty()) { + unsigned i = 0; + double t = T.valueAt(rts[i]); + double s = S.valueAt(rts[i]); + xAx xC0 = C1*t + C2*s; + //::draw(cr, xC0, screen_rect); // degen + + return decompose_degenerate(C1, C2, xC0); + + + } else { + std::cout << "What?\n"; + ;//std::cout << D << "\n"; + } + return res; +} + + +xAx xAx::fromPoint(Point p) { + return xAx(1., 0, 1., -2*p[0], -2*p[1], dot(p,p)); +} + +xAx xAx::fromDistPoint(Point /*p*/, double /*d*/) { + return xAx();//1., 0, 1., -2*(1+d)*p[0], -2*(1+d)*p[1], dot(p,p)+d*d); +} + +xAx xAx::fromLine(Point n, double d) { + return xAx(n[0]*n[0], 2*n[0]*n[1], n[1]*n[1], 2*d*n[0], 2*d*n[1], d*d); +} + +xAx xAx::fromLine(Line l) { + double dist; + Point norm = l.normalAndDist(dist); + + return fromLine(norm, dist); +} + +xAx xAx::fromPoints(std::vector<Geom::Point> const &pt) { + Geom::NL::Vector V(pt.size(), -1.0); + Geom::NL::Matrix M(pt.size(), 5); + for(unsigned i = 0; i < pt.size(); i++) { + Geom::Point P = pt[i]; + Geom::NL::VectorView vv = M.row_view(i); + vv[0] = P[0]*P[0]; + vv[1] = P[0]*P[1]; + vv[2] = P[1]*P[1]; + vv[3] = P[0]; + vv[4] = P[1]; + } + + Geom::NL::LinearSystem ls(M, V); + + Geom::NL::Vector x = ls.SV_solve(); + return Geom::xAx(x[0], x[1], x[2], x[3], x[4], 1); + +} + + + +double xAx::valueAt(Point P) const { + return evaluate_at(P[0], P[1]); +} + +xAx xAx::scale(double sx, double sy) const { + return xAx(c[0]*sx*sx, c[1]*sx*sy, c[2]*sy*sy, + c[3]*sx, c[4]*sy, c[5]); +} + +Point xAx::gradient(Point p) const{ + double x = p[0]; + double y = p[1]; + return Point(2*c[0]*x + c[1]*y + c[3], + c[1]*x + 2*c[2]*y + c[4]); +} + +xAx xAx::operator-(xAx const &b) const { + xAx res; + for(int i = 0; i < 6; i++) { + res.c[i] = c[i] - b.c[i]; + } + return res; +} +xAx xAx::operator+(xAx const &b) const { + xAx res; + for(int i = 0; i < 6; i++) { + res.c[i] = c[i] + b.c[i]; + } + return res; +} +xAx xAx::operator+(double const &b) const { + xAx res; + for(int i = 0; i < 5; i++) { + res.c[i] = c[i]; + } + res.c[5] = c[5] + b; + return res; +} + +xAx xAx::operator*(double const &b) const { + xAx res; + for(int i = 0; i < 6; i++) { + res.c[i] = c[i] * b; + } + return res; +} + + std::vector<Point> xAx::crossings(Rect r) const { + std::vector<Point> res; + for(int ei = 0; ei < 4; ei++) { + Geom::LineSegment ls(r.corner(ei), r.corner(ei+1)); + D2<SBasis> lssb = ls.toSBasis(); + SBasis edge_curve = evaluate_at(lssb[0], lssb[1]); + std::vector<double> rts = Geom::roots(edge_curve); + for(unsigned eci = 0; eci < rts.size(); eci++) { + res.push_back(lssb.valueAt(rts[eci])); + } + } + return res; +} + + boost::optional<RatQuad> xAx::toCurve(Rect const & bnd) const { + std::vector<Point> crs = crossings(bnd); + if(crs.size() == 1) { + Point A = crs[0]; + Point dA = rot90(gradient(A)); + if(L2sq(dA) <= 1e-10) { // perhaps a single point? + return boost::optional<RatQuad> (); + } + LineSegment ls = intersection(Line::from_origin_and_versor(A, dA), bnd); + return RatQuad::fromPointsTangents(A, dA, ls.pointAt(0.5), ls[1], dA); + } + else if(crs.size() >= 2 and crs.size() < 4) { + Point A = crs[0]; + Point C = crs[1]; + if(crs.size() == 3) { + if(distance(A, crs[2]) > distance(A, C)) + C = crs[2]; + else if(distance(C, crs[2]) > distance(A, C)) + A = crs[2]; + } + Line bisector = make_bisector_line(LineSegment(A, C)); + std::vector<double> bisect_rts = this->roots(bisector); + if(bisect_rts.size() > 0) { + int besti = -1; + for(unsigned i =0; i < bisect_rts.size(); i++) { + Point p = bisector.pointAt(bisect_rts[i]); + if(bnd.contains(p)) { + besti = i; + } + } + if(besti >= 0) { + Point B = bisector.pointAt(bisect_rts[besti]); + + Point dA = gradient(A); + Point dC = gradient(C); + if(L2sq(dA) <= 1e-10 or L2sq(dC) <= 1e-10) { + return RatQuad::fromPointsTangents(A, C-A, B, C, A-C); + } + + RatQuad rq = RatQuad::fromPointsTangents(A, rot90(dA), + B, C, rot90(dC)); + return rq; + //std::vector<SBasis> hrq = rq.homogenous(); + /*SBasis vertex_poly = evaluate_at(hrq[0], hrq[1], hrq[2]); + std::vector<double> rts = roots(vertex_poly); + for(unsigned i = 0; i < rts.size(); i++) { + //draw_circ(cr, Point(rq.pointAt(rts[i]))); + }*/ + } + } + } + return boost::optional<RatQuad>(); +} + + std::vector<double> xAx::roots(Point d, Point o) const { + // Find the roots on line l + // form the quadratic Q(t) = 0 by composing l with xAx + double q2 = c[0]*d[0]*d[0] + c[1]*d[0]*d[1] + c[2]*d[1]*d[1]; + double q1 = (2*c[0]*d[0]*o[0] + + c[1]*(d[0]*o[1]+d[1]*o[0]) + + 2*c[2]*d[1]*o[1] + + c[3]*d[0] + c[4]*d[1]); + double q0 = c[0]*o[0]*o[0] + c[1]*o[0]*o[1] + c[2]*o[1]*o[1] + c[3]*o[0] + c[4]*o[1] + c[5]; + std::vector<double> r; + if(q2 == 0) { + if(q1 == 0) { + return r; + } + r.push_back(-q0/q1); + } else { + double desc = q1*q1 - 4*q2*q0; + /*std::cout << q2 << ", " + << q1 << ", " + << q0 << "; " + << desc << "\n";*/ + if (desc < 0) + return r; + else if (desc == 0) + r.push_back(-q1/(2*q2)); + else { + desc = std::sqrt(desc); + double t; + if (q1 == 0) + { + t = -0.5 * desc; + } + else + { + t = -0.5 * (q1 + sgn(q1) * desc); + } + r.push_back(t/q2); + r.push_back(q0/t); + } + } + return r; +} + +std::vector<double> xAx::roots(Line const &l) const { + return roots(l.versor(), l.origin()); +} + +Interval xAx::quad_ex(double a, double b, double c, Interval ivl) { + double cx = -b*0.5/a; + Interval bnds((a*ivl[0]+b)*ivl[0]+c, (a*ivl[1]+b)*ivl[1]+c); + if(ivl.contains(cx)) + bnds.expandTo((a*cx+b)*cx+c); + return bnds; +} + +Geom::Affine xAx::hessian() const { + Geom::Affine m(2*c[0], c[1], + c[1], 2*c[2], + 0, 0); + return m; +} + + +boost::optional<Point> solve(double A[2][2], double b[2]) { + double const determ = det(A); + if (determ != 0.0) { // hopeful, I know + Geom::Coord const ideterm = 1.0 / determ; + + return Point ((A[1][1]*b[0] -A[0][1]*b[1]), + (-A[1][0]*b[0] + A[0][0]*b[1]))* ideterm; + } else { + return boost::optional<Point>(); + } +} + +boost::optional<Point> xAx::bottom() const { + double A[2][2] = {{2*c[0], c[1]}, + {c[1], 2*c[2]}}; + double b[2] = {-c[3], -c[4]}; + return solve(A, b); + //return Point(-c[3], -c[4])*hessian().inverse(); +} + +Interval xAx::extrema(Rect r) const { + if (c[0] == 0 and c[1] == 0 and c[2] == 0) { + Interval ext(valueAt(r.corner(0))); + for(int i = 1; i < 4; i++) + ext |= Interval(valueAt(r.corner(i))); + return ext; + } + double k = r[0][0]; + Interval ext = quad_ex(c[2], c[1]*k+c[4], (c[0]*k + c[3])*k + c[5], r[1]); + k = r[0][1]; + ext |= quad_ex(c[2], c[1]*k+c[4], (c[0]*k + c[3])*k + c[5], r[1]); + k = r[1][0]; + ext |= quad_ex(c[0], c[1]*k+c[3], (c[2]*k + c[4])*k + c[5], r[0]); + k = r[1][1]; + ext |= quad_ex(c[0], c[1]*k+c[3], (c[2]*k + c[4])*k + c[5], r[0]); + boost::optional<Point> B0 = bottom(); + if (B0 and r.contains(*B0)) + ext.expandTo(0); + return ext; +} + + + + + + + + + +/* + * helper functions + */ + +bool at_infinity (Point const& p) +{ + if (p[X] == infinity() || p[X] == -infinity() + || p[Y] == infinity() || p[Y] == -infinity()) + { + return true; + } + return false; +} + +inline +double signed_triangle_area (Point const& p1, Point const& p2, Point const& p3) +{ + return (cross(p3, p2) - cross(p3, p1) + cross(p2, p1)); +} + + + +/* + * Define a conic section by computing the one that fits better with + * N points. + * + * points: points to fit + * + * precondition: there must be at least 5 non-overlapping points + */ +void xAx::set(std::vector<Point> const& points) +{ + size_t sz = points.size(); + if (sz < 5) + { + THROW_RANGEERROR("fitting error: too few points passed"); + } + NL::LFMConicSection model; + NL::least_squeares_fitter<NL::LFMConicSection> fitter(model, sz); + + for (size_t i = 0; i < sz; ++i) + { + fitter.append(points[i]); + } + fitter.update(); + + NL::Vector z(sz, 0.0); + model.instance(*this, fitter.result(z)); +} + +/* + * Define a section conic by providing the coordinates of one of its vertex, + * the major axis inclination angle and the coordinates of its foci + * with respect to the unidimensional system defined by the major axis with + * origin set at the provided vertex. + * + * _vertex : section conic vertex V + * _angle : section conic major axis angle + * _dist1: +/-distance btw V and nearest focus + * _dist2: +/-distance btw V and farest focus + * + * prerequisite: _dist1 <= _dist2 + */ +void xAx::set (const Point& _vertex, double _angle, double _dist1, double _dist2) +{ + if (_dist2 == infinity() || _dist2 == -infinity()) // parabola + { + if (_dist1 == infinity()) // degenerate to a line + { + Line l(_vertex, _angle); + std::vector<double> lcoeff = l.coefficients(); + coeff(3) = lcoeff[0]; + coeff(4) = lcoeff[1]; + coeff(5) = lcoeff[2]; + return; + } + + // y^2 - 4px == 0 + double cD = -4 * _dist1; + + double cosa = std::cos (_angle); + double sina = std::sin (_angle); + double cca = cosa * cosa; + double ssa = sina * sina; + double csa = cosa * sina; + + coeff(0) = ssa; + coeff(1) = -2 * csa; + coeff(2) = cca; + coeff(3) = cD * cosa; + coeff(4) = cD * sina; + + double VxVx = _vertex[X] * _vertex[X]; + double VxVy = _vertex[X] * _vertex[Y]; + double VyVy = _vertex[Y] * _vertex[Y]; + + coeff(5) = coeff(0) * VxVx + coeff(1) * VxVy + coeff(2) * VyVy + - coeff(3) * _vertex[X] - coeff(4) * _vertex[Y]; + coeff(3) -= (2 * coeff(0) * _vertex[X] + coeff(1) * _vertex[Y]); + coeff(4) -= (2 * coeff(2) * _vertex[Y] + coeff(1) * _vertex[X]); + + return; + } + + if (std::fabs(_dist1) > std::fabs(_dist2)) + { + std::swap (_dist1, _dist2); + } + if (_dist1 < 0) + { + _angle -= M_PI; + _dist1 = -_dist1; + _dist2 = -_dist2; + } + + // ellipse and hyperbola + double lin_ecc = (_dist2 - _dist1) / 2; + double rx = (_dist2 + _dist1) / 2; + + double cA = rx * rx - lin_ecc * lin_ecc; + double cC = rx * rx; + double cF = - cA * cC; +// std::cout << "cA: " << cA << std::endl; +// std::cout << "cC: " << cC << std::endl; +// std::cout << "cF: " << cF << std::endl; + + double cosa = std::cos (_angle); + double sina = std::sin (_angle); + double cca = cosa * cosa; + double ssa = sina * sina; + double csa = cosa * sina; + + coeff(0) = cca * cA + ssa * cC; + coeff(2) = ssa * cA + cca * cC; + coeff(1) = 2 * csa * (cA - cC); + + Point C (rx * cosa + _vertex[X], rx * sina + _vertex[Y]); + double CxCx = C[X] * C[X]; + double CxCy = C[X] * C[Y]; + double CyCy = C[Y] * C[Y]; + + coeff(3) = -2 * coeff(0) * C[X] - coeff(1) * C[Y]; + coeff(4) = -2 * coeff(2) * C[Y] - coeff(1) * C[X]; + coeff(5) = cF + coeff(0) * CxCx + coeff(1) * CxCy + coeff(2) * CyCy; +} + +/* + * Define a conic section by providing one of its vertex and its foci. + * + * _vertex: section conic vertex + * _focus1: section conic focus + * _focus2: section conic focus + */ +void xAx::set (const Point& _vertex, const Point& _focus1, const Point& _focus2) +{ + if (at_infinity(_vertex)) + { + THROW_RANGEERROR("case not handled: vertex at infinity"); + } + if (at_infinity(_focus2)) + { + if (at_infinity(_focus1)) + { + THROW_RANGEERROR("case not handled: both focus at infinity"); + } + Point VF = _focus1 - _vertex; + double dist1 = L2(VF); + double angle = atan2(VF); + set(_vertex, angle, dist1, infinity()); + return; + } + else if (at_infinity(_focus1)) + { + Point VF = _focus2 - _vertex; + double dist1 = L2(VF); + double angle = atan2(VF); + set(_vertex, angle, dist1, infinity()); + return; + } + assert (are_collinear (_vertex, _focus1, _focus2)); + if (!are_near(_vertex, _focus1)) + { + Point VF = _focus1 - _vertex; + Line axis(_vertex, _focus1); + double angle = atan2(VF); + double dist1 = L2(VF); + double dist2 = distance (_vertex, _focus2); + double t = axis.timeAt(_focus2); + if (t < 0) dist2 = -dist2; +// std::cout << "t = " << t << std::endl; +// std::cout << "dist2 = " << dist2 << std::endl; + set (_vertex, angle, dist1, dist2); + } + else if (!are_near(_vertex, _focus2)) + { + Point VF = _focus2 - _vertex; + double angle = atan2(VF); + double dist1 = 0; + double dist2 = L2(VF); + set (_vertex, angle, dist1, dist2); + } + else + { + coeff(0) = coeff(2) = 1; + coeff(1) = coeff(3) = coeff(4) = coeff(5) = 0; + } +} + +/* + * Define a conic section by passing a focus, the related directrix, + * and the eccentricity (e) + * (e < 1 -> ellipse; e = 1 -> parabola; e > 1 -> hyperbola) + * + * _focus: a focus of the conic section + * _directrix: the directrix related to the given focus + * _eccentricity: the eccentricity parameter of the conic section + */ +void xAx::set (const Point & _focus, const Line & _directrix, double _eccentricity) +{ + Point O = _directrix.pointAt (_directrix.timeAtProjection (_focus)); + //std::cout << "O = " << O << std::endl; + Point OF = _focus - O; + double p = L2(OF); + + coeff(0) = 1 - _eccentricity * _eccentricity; + coeff(1) = 0; + coeff(2) = 1; + coeff(3) = -2 * p; + coeff(4) = 0; + coeff(5) = p * p; + + double angle = atan2 (OF); + + (*this) = rotate (angle); + //std::cout << "O = " << O << std::endl; + (*this) = translate (O); +} + +/* + * Made up a degenerate conic section as a pair of lines + * + * l1, l2: lines that made up the conic section + */ +void xAx::set (const Line& l1, const Line& l2) +{ + std::vector<double> cl1 = l1.coefficients(); + std::vector<double> cl2 = l2.coefficients(); + + coeff(0) = cl1[0] * cl2[0]; + coeff(2) = cl1[1] * cl2[1]; + coeff(5) = cl1[2] * cl2[2]; + coeff(1) = cl1[0] * cl2[1] + cl1[1] * cl2[0]; + coeff(3) = cl1[0] * cl2[2] + cl1[2] * cl2[0]; + coeff(4) = cl1[1] * cl2[2] + cl1[2] * cl2[1]; +} + + + +/* + * Return the section conic kind + */ +xAx::kind_t xAx::kind () const +{ + + xAx conic(*this); + NL::SymmetricMatrix<3> C = conic.get_matrix(); + NL::ConstSymmetricMatrixView<2> A = C.main_minor_const_view(); + + double t1 = trace(A); + double t2 = det(A); + //double T3 = det(C); + int st1 = trace_sgn(A); + int st2 = det_sgn(A); + int sT3 = det_sgn(C); + + //std::cout << "T3 = " << T3 << std::endl; + //std::cout << "sT3 = " << sT3 << std::endl; + //std::cout << "t2 = " << t2 << std::endl; + //std::cout << "t1 = " << t1 << std::endl; + //std::cout << "st2 = " << st2 << std::endl; + + if (sT3 != 0) + { + if (st2 == 0) + { + return PARABOLA; + } + else if (st2 == 1) + { + + if (sT3 * st1 < 0) + { + NL::SymmetricMatrix<2> discr; + discr(0,0) = 4; discr(1,1) = t2; discr(1,0) = t1; + int discr_sgn = - det_sgn (discr); + //std::cout << "t1 * t1 - 4 * t2 = " + // << (t1 * t1 - 4 * t2) << std::endl; + //std::cout << "discr_sgn = " << discr_sgn << std::endl; + if (discr_sgn == 0) + { + return CIRCLE; + } + else + { + return REAL_ELLIPSE; + } + } + else // sT3 * st1 > 0 + { + return IMAGINARY_ELLIPSE; + } + } + else // t2 < 0 + { + if (st1 == 0) + { + return RECTANGULAR_HYPERBOLA; + } + else + { + return HYPERBOLA; + } + } + } + else // T3 == 0 + { + if (st2 == 0) + { + //double T2 = NL::trace<2>(C); + int sT2 = NL::trace_sgn<2>(C); + //std::cout << "T2 = " << T2 << std::endl; + //std::cout << "sT2 = " << sT2 << std::endl; + + if (sT2 == 0) + { + return DOUBLE_LINE; + } + if (sT2 == -1) + { + return TWO_REAL_PARALLEL_LINES; + } + else // T2 > 0 + { + return TWO_IMAGINARY_PARALLEL_LINES; + } + } + else if (st2 == -1) + { + return TWO_REAL_CROSSING_LINES; + } + else // t2 > 0 + { + return TWO_IMAGINARY_CROSSING_LINES; + } + } + return UNKNOWN; +} + +/* + * Return a string representing the conic section kind + */ +std::string xAx::categorise() const +{ + kind_t KIND = kind(); + + switch (KIND) + { + case PARABOLA : + return "parabola"; + case CIRCLE : + return "circle"; + case REAL_ELLIPSE : + return "real ellispe"; + case IMAGINARY_ELLIPSE : + return "imaginary ellispe"; + case RECTANGULAR_HYPERBOLA : + return "rectangular hyperbola"; + case HYPERBOLA : + return "hyperbola"; + case DOUBLE_LINE : + return "double line"; + case TWO_REAL_PARALLEL_LINES : + return "two real parallel lines"; + case TWO_IMAGINARY_PARALLEL_LINES : + return "two imaginary parallel lines"; + case TWO_REAL_CROSSING_LINES : + return "two real crossing lines"; + case TWO_IMAGINARY_CROSSING_LINES : + return "two imaginary crossing lines"; + default : + return "unknown"; + } +} + +/* + * Compute the solutions of the conic section algebraic equation with respect to + * one coordinate after substituting to the other coordinate the passed value + * + * sol: the computed solutions + * v: the provided value + * d: the index of the coordinate the passed value have to be substituted to + */ +void xAx::roots (std::vector<double>& sol, Coord v, Dim2 d) const +{ + sol.clear(); + if (d < 0 || d > Y) + { + THROW_RANGEERROR("dimension parameter out of range"); + } + + // p*t^2 + q*t + r = 0; + double p, q, r; + + if (d == X) + { + p = coeff(2); + q = coeff(4) + coeff(1) * v; + r = coeff(5) + (coeff(0) * v + coeff(3)) * v; + } + else + { + p = coeff(0); + q = coeff(3) + coeff(1) * v; + r = coeff(5) + (coeff(2) * v + coeff(4)) * v; + } + + if (p == 0) + { + if (q == 0) return; + double t = -r/q; + sol.push_back(t); + return; + } + + if (q == 0) + { + if ((p > 0 && r > 0) || (p < 0 && r < 0)) return; + double t = -r / p; + t = std::sqrt (t); + sol.push_back(-t); + sol.push_back(t); + return; + } + + if (r == 0) + { + double t = -q/p; + sol.push_back(0); + sol.push_back(t); + return; + } + + + //std::cout << "p = " << p << ", q = " << q << ", r = " << r << std::endl; + double delta = q * q - 4 * p * r; + if (delta < 0) return; + if (delta == 0) + { + double t = -q / (2 * p); + sol.push_back(t); + return; + } + // else + double srd = std::sqrt(delta); + double t = - (q + sgn(q) * srd) / 2; + sol.push_back (t/p); + sol.push_back (r/t); + +} + +/* + * Return the inclination angle of the major axis of the conic section + */ +double xAx::axis_angle() const +{ + if (coeff(0) == 0 && coeff(1) == 0 && coeff(2) == 0) + { + Line l (coeff(3), coeff(4), coeff(5)); + return l.angle(); + } + if (coeff(1) == 0 && (coeff(0) == coeff(2))) return 0; + + double angle; + + int sgn_discr = det_sgn (get_matrix().main_minor_const_view()); + if (sgn_discr == 0) + { + //std::cout << "rotation_angle: sgn_discr = " + // << sgn_discr << std::endl; + angle = std::atan2 (-coeff(1), 2 * coeff(2)); + if (angle < 0) angle += 2*M_PI; + if (angle >= M_PI) angle -= M_PI; + + } + else + { + angle = std::atan2 (coeff(1), coeff(0) - coeff(2)); + if (angle < 0) angle += 2*M_PI; + angle -= M_PI; + if (angle < 0) angle += 2*M_PI; + angle /= 2; + if (angle >= M_PI) angle -= M_PI; + } + //std::cout << "rotation_angle : angle = " << angle << std::endl; + return angle; +} + +/* + * Translate the conic section by the given vector offset + * + * _offset: represent the vector offset + */ +xAx xAx::translate (const Point & _offset) const +{ + double B = coeff(1) / 2; + double D = coeff(3) / 2; + double E = coeff(4) / 2; + + Point T = - _offset; + + xAx cs; + cs.coeff(0) = coeff(0); + cs.coeff(1) = coeff(1); + cs.coeff(2) = coeff(2); + + Point DE; + DE[0] = coeff(0) * T[0] + B * T[1]; + DE[1] = B * T[0] + coeff(2) * T[1]; + + cs.coeff(3) = (DE[0] + D) * 2; + cs.coeff(4) = (DE[1] + E) * 2; + + cs.coeff(5) = dot (T, DE) + 2 * (T[0] * D + T[1] * E) + coeff(5); + + return cs; +} + + +/* + * Rotate the conic section by the given angle wrt the point (0,0) + * + * angle: represent the rotation angle + */ +xAx xAx::rotate (double angle) const +{ + double c = std::cos(-angle); + double s = std::sin(-angle); + double cc = c * c; + double ss = s * s; + double cs = c * s; + + xAx result; + result.coeff(5) = coeff(5); + + // quadratic terms + double Bcs = coeff(1) * cs; + + result.coeff(0) = coeff(0) * cc + Bcs + coeff(2) * ss; + result.coeff(2) = coeff(0) * ss - Bcs + coeff(2) * cc; + result.coeff(1) = coeff(1) * (cc - ss) + 2 * (coeff(2) - coeff(0)) * cs; + + // linear terms + result.coeff(3) = coeff(3) * c + coeff(4) * s; + result.coeff(4) = coeff(4) * c - coeff(3) * s; + + return result; +} + + +/* + * Decompose a degenerate conic in two lines the conic section is made by. + * Return true if the decomposition is successfull, else if it fails. + * + * l1, l2: out parameters where the decomposed conic section is returned + */ +bool xAx::decompose (Line& l1, Line& l2) const +{ + NL::SymmetricMatrix<3> C = get_matrix(); + if (!is_quadratic() || !isDegenerate()) + { + return false; + } + NL::Matrix M(C); + NL::SymmetricMatrix<3> D = -adj(C); + + if (!D.is_zero()) // D == 0 <=> rank(C) < 2 + { + + //if (D.get<0,0>() < 0 || D.get<1,1>() < 0 || D.get<2,2>() < 0) + //{ + //std::cout << "C: \n" << C << std::endl; + //std::cout << "D: \n" << D << std::endl; + + /* + * This case should be impossible because any diagonal element + * of D is a square, but due to non exact aritmethic computation + * it can actually happen; however the algorithm seems to work + * correctly even if some diagonal term is negative, the only + * difference is that we should compute the absolute value of + * diagonal elements. So until we elaborate a better degenerate + * test it's better not rising exception when we have a negative + * diagonal element. + */ + //} + + NL::Vector d(3); + d[0] = std::fabs (D.get<0,0>()); + d[1] = std::fabs (D.get<1,1>()); + d[2] = std::fabs (D.get<2,2>()); + + size_t idx = d.max_index(); + if (d[idx] == 0) + { + THROW_LOGICALERROR ("xAx::decompose: " + "rank 2 but adjoint with null diagonal"); + } + d[0] = D(idx,0); d[1] = D(idx,1); d[2] = D(idx,2); + d.scale (1 / std::sqrt (std::fabs (D(idx,idx)))); + M(1,2) += d[0]; M(2,1) -= d[0]; + M(0,2) -= d[1]; M(2,0) += d[1]; + M(0,1) += d[2]; M(1,0) -= d[2]; + + //std::cout << "C: \n" << C << std::endl; + //std::cout << "D: \n" << D << std::endl; + //std::cout << "d = " << d << std::endl; + //std::cout << "M = " << M << std::endl; + } + + std::pair<size_t, size_t> max_ij = M.max_index(); + std::pair<size_t, size_t> min_ij = M.min_index(); + double abs_max = std::fabs (M(max_ij.first, max_ij.second)); + double abs_min = std::fabs (M(min_ij.first, min_ij.second)); + size_t i_max, j_max; + if (abs_max > abs_min) + { + i_max = max_ij.first; + j_max = max_ij.second; + } + else + { + i_max = min_ij.first; + j_max = min_ij.second; + } + l1.setCoefficients (M(i_max,0), M(i_max,1), M(i_max,2)); + l2.setCoefficients (M(0, j_max), M(1,j_max), M(2,j_max)); + + return true; +} + + +/* + * Return the rectangle that bound the conic section arc characterized by + * the passed points. + * + * P1: the initial point of the arc + * Q: the inner point of the arc + * P2: the final point of the arc + * + * prerequisite: the passed points must lie on the conic + */ +Rect xAx::arc_bound (const Point & P1, const Point & Q, const Point & P2) const +{ + //std::cout << "BOUND: P1 = " << P1 << std::endl; + //std::cout << "BOUND: Q = " << Q << std::endl; + //std::cout << "BOUND: P2 = " << P2 << std::endl; + + Rect B(P1, P2); + double Qside = signed_triangle_area (P1, Q, P2); + //std::cout << "BOUND: Qside = " << Qside << std::endl; + + Line gl[2]; + bool empty[2] = {false, false}; + + try // if the passed coefficients lead to an equation 0x + 0y + c == 0, + { // with c != 0 the setCoefficients rise an exception + gl[0].setCoefficients (coeff(1), 2 * coeff(2), coeff(4)); + } + catch(Geom::LogicalError e) + { + empty[0] = true; + } + + try + { + gl[1].setCoefficients (2 * coeff(0), coeff(1), coeff(3)); + } + catch(Geom::LogicalError e) + { + empty[1] = true; + } + + std::vector<double> rts; + std::vector<Point> M; + for (size_t dim = 0; dim < 2; ++dim) + { + if (empty[dim]) continue; + rts = roots (gl[dim]); + M.clear(); + for (size_t i = 0; i < rts.size(); ++i) + M.push_back (gl[dim].pointAt (rts[i])); + if (M.size() == 1) + { + double Mside = signed_triangle_area (P1, M[0], P2); + if (sgn(Mside) == sgn(Qside)) + { + //std::cout << "BOUND: M.size() == 1" << std::endl; + if (M[0][dim] > B[dim][1]) + B[dim][1] = M[0][dim]; + else if (M[0][dim] < B[dim][0]) + B[dim][0] = M[0][dim]; + } + } + else if (M.size() == 2) + { + //std::cout << "BOUND: M.size() == 2" << std::endl; + if (M[0][dim] > M[1][dim]) + std::swap (M[0], M[1]); + + if (M[0][dim] > B[dim][1]) + { + double Mside = signed_triangle_area (P1, M[0], P2); + if (sgn(Mside) == sgn(Qside)) + B[dim][1] = M[0][dim]; + } + else if (M[1][dim] < B[dim][0]) + { + double Mside = signed_triangle_area (P1, M[1], P2); + if (sgn(Mside) == sgn(Qside)) + B[dim][0] = M[1][dim]; + } + else + { + double Mside = signed_triangle_area (P1, M[0], P2); + if (sgn(Mside) == sgn(Qside)) + B[dim][0] = M[0][dim]; + Mside = signed_triangle_area (P1, M[1], P2); + if (sgn(Mside) == sgn(Qside)) + B[dim][1] = M[1][dim]; + } + } + } + + return B; +} + +/* + * Return all points on the conic section nearest to the passed point "P". + * + * P: the point to compute the nearest one + */ +std::vector<Point> xAx::allNearestPoints (const Point P) const +{ + // TODO: manage the circle - centre case + std::vector<Point> points; + + // named C the conic we look for points (x,y) on C such that + // dot (grad (C(x,y)), rot90 (P -(x,y))) == 0; the set of points satisfying + // this equation is still a conic G, so the wanted points can be found by + // intersecting C with G + xAx G (-coeff(1), + 2 * (coeff(0) - coeff(2)), + coeff(1), + -coeff(4) + coeff(1) * P[X] - 2 * coeff(0) * P[Y], + coeff(3) - coeff(1) * P[Y] + 2 * coeff(2) * P[X], + -coeff(3) * P[Y] + coeff(4) * P[X]); + + std::vector<Point> crs = intersect (*this, G); + + //std::cout << "NEAREST POINT: crs.size = " << crs.size() << std::endl; + if (crs.size() == 0) return points; + + size_t idx = 0; + double mindist = distanceSq (crs[0], P); + std::vector<double> dist; + dist.push_back (mindist); + + for (size_t i = 1; i < crs.size(); ++i) + { + dist.push_back (distanceSq (crs[i], P)); + if (mindist > dist.back()) + { + idx = i; + mindist = dist.back(); + } + } + + points.push_back (crs[idx]); + for (size_t i = 0; i < crs.size(); ++i) + { + if (i == idx) continue; + if (dist[i] == mindist) + points.push_back (crs[i]); + } + + return points; +} + + + +bool clip (std::vector<RatQuad> & rq, const xAx & cs, const Rect & R) +{ + clipper aclipper (cs, R); + return aclipper.clip (rq); +} + + +} // end 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/conicsec.h b/src/2geom/conicsec.h new file mode 100644 index 000000000..be9a68bfa --- /dev/null +++ b/src/2geom/conicsec.h @@ -0,0 +1,525 @@ +/** + * \file + * \brief Conic Section + * + * Authors: + * Nathan Hurst <njh@njhurst.com> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#ifndef _2GEOM_CONIC_SECTION_H_ +#define _2GEOM_CONIC_SECTION_H_ + +#include <2geom/exception.h> +#include <2geom/angle.h> +#include <2geom/rect.h> +#include <2geom/affine.h> +#include <2geom/point.h> +#include <2geom/line.h> +#include <2geom/bezier-curve.h> +#include <2geom/numeric/linear_system.h> +#include <2geom/numeric/symmetric-matrix-fs.h> +#include <2geom/numeric/symmetric-matrix-fs-operation.h> + +#include <boost/optional/optional.hpp> + +#include <string> +#include <vector> +#include <ostream> + + + + +namespace Geom +{ + +class RatQuad{ + /** + * A curve of the form B02*A + B12*B*w + B22*C/(B02 + B12*w + B22) + * These curves can exactly represent a piece conic section less than a certain angle (find out) + * + **/ + +public: + Point P[3]; + double w; + RatQuad() {} + RatQuad(Point a, Point b, Point c, double w) : w(w) { + P[0] = a; + P[1] = b; + P[2] = c; + } + double lambda() const; + + static RatQuad fromPointsTangents(Point P0, Point dP0, + Point P, + Point P2, Point dP2); + static RatQuad circularArc(Point P0, Point P1, Point P2); + + CubicBezier toCubic() const; + CubicBezier toCubic(double lam) const; + + Point pointAt(double t) const; + Point at0() const {return P[0];} + Point at1() const {return P[2];} + + void split(RatQuad &a, RatQuad &b) const; + + D2<SBasis> hermite() const; + std::vector<SBasis> homogenous() const; +}; + + + + +class xAx{ +public: + double c[6]; + + enum kind_t + { + PARABOLA, + CIRCLE, + REAL_ELLIPSE, + IMAGINARY_ELLIPSE, + RECTANGULAR_HYPERBOLA, + HYPERBOLA, + DOUBLE_LINE, + TWO_REAL_PARALLEL_LINES, + TWO_IMAGINARY_PARALLEL_LINES, + TWO_REAL_CROSSING_LINES, + TWO_IMAGINARY_CROSSING_LINES, // crossing at a real point + SINGLE_POINT = TWO_IMAGINARY_CROSSING_LINES, + UNKNOWN + }; + + + xAx() {} + + /* + * Define the conic section by its algebraic equation coefficients + * + * c0, .., c5: equation coefficients + */ + xAx (double c0, double c1, double c2, double c3, double c4, double c5) + { + set (c0, c1, c2, c3, c4, c5); + } + + /* + * Define a conic section by its related symmetric matrix + */ + xAx (const NL::ConstSymmetricMatrixView<3> & C) + { + set(C); + } + + /* + * Define a conic section by computing the one that fits better with + * N points. + * + * points: points to fit + * + * precondition: there must be at least 5 non-overlapping points + */ + xAx (std::vector<Point> const& points) + { + set (points); + } + + /* + * Define a section conic by providing the coordinates of one of its + * vertex,the major axis inclination angle and the coordinates of its foci + * with respect to the unidimensional system defined by the major axis with + * origin set at the provided vertex. + * + * _vertex : section conic vertex V + * _angle : section conic major axis angle + * _dist1: +/-distance btw V and nearest focus + * _dist2: +/-distance btw V and farest focus + * + * prerequisite: _dist1 <= _dist2 + */ + xAx (const Point& _vertex, double _angle, double _dist1, double _dist2) + { + set (_vertex, _angle, _dist1, _dist2); + } + + /* + * Define a conic section by providing one of its vertex and its foci. + * + * _vertex: section conic vertex + * _focus1: section conic focus + * _focus2: section conic focus + */ + xAx (const Point& _vertex, const Point& _focus1, const Point& _focus2) + { + set(_vertex, _focus1, _focus2); + } + + /* + * Define a conic section by passing a focus, the related directrix, + * and the eccentricity (e) + * (e < 1 -> ellipse; e = 1 -> parabola; e > 1 -> hyperbola) + * + * _focus: a focus of the conic section + * _directrix: the directrix related to the given focus + * _eccentricity: the eccentricity parameter of the conic section + */ + xAx (const Point & _focus, const Line & _directrix, double _eccentricity) + { + set (_focus, _directrix, _eccentricity); + } + + /* + * Made up a degenerate conic section as a pair of lines + * + * l1, l2: lines that made up the conic section + */ + xAx (const Line& l1, const Line& l2) + { + set (l1, l2); + } + + /* + * Define the conic section by its algebraic equation coefficients + * c0, ..., c5: equation coefficients + */ + void set (double c0, double c1, double c2, double c3, double c4, double c5) + { + c[0] = c0; c[1] = c1; c[2] = c2; // xx, xy, yy + c[3] = c3; c[4] = c4; // x, y + c[5] = c5; // 1 + } + + /* + * Define a conic section by its related symmetric matrix + */ + void set (const NL::ConstSymmetricMatrixView<3> & C) + { + set(C(0,0), 2*C(1,0), C(1,1), 2*C(2,0), 2*C(2,1), C(2,2)); + } + + void set (std::vector<Point> const& points); + + void set (const Point& _vertex, double _angle, double _dist1, double _dist2); + + void set (const Point& _vertex, const Point& _focus1, const Point& _focus2); + + void set (const Point & _focus, const Line & _directrix, double _eccentricity); + + void set (const Line& l1, const Line& l2); + + + static xAx fromPoint(Point p); + static xAx fromDistPoint(Point p, double d); + static xAx fromLine(Point n, double d); + static xAx fromLine(Line l); + static xAx fromPoints(std::vector<Point> const &pts); + + + template<typename T> + T evaluate_at(T x, T y) const { + return c[0]*x*x + c[1]*x*y + c[2]*y*y + c[3]*x + c[4]*y + c[5]; + } + + double valueAt(Point P) const; + + std::vector<double> implicit_form_coefficients() const { + return std::vector<double>(c, c+6); + } + + template<typename T> + T evaluate_at(T x, T y, T w) const { + return c[0]*x*x + c[1]*x*y + c[2]*y*y + c[3]*x*w + c[4]*y*w + c[5]*w*w; + } + + xAx scale(double sx, double sy) const; + + Point gradient(Point p) const; + + xAx operator-(xAx const &b) const; + xAx operator+(xAx const &b) const; + xAx operator+(double const &b) const; + xAx operator*(double const &b) const; + + std::vector<Point> crossings(Rect r) const; + boost::optional<RatQuad> toCurve(Rect const & bnd) const; + std::vector<double> roots(Point d, Point o) const; + + std::vector<double> roots(Line const &l) const; + + static Interval quad_ex(double a, double b, double c, Interval ivl); + + Geom::Affine hessian() const; + + boost::optional<Point> bottom() const; + + Interval extrema(Rect r) const; + + + /* + * Return the symmetric matrix related to the conic section. + * Modifying the matrix does not modify the conic section + */ + NL::SymmetricMatrix<3> get_matrix() const + { + NL::SymmetricMatrix<3> C(c); + C(1,0) *= 0.5; C(2,0) *= 0.5; C(2,1) *= 0.5; + return C; + } + + /* + * Return the i-th coefficient of the conic section algebraic equation + * Modifying the returned value does not modify the conic section coefficient + */ + double coeff (size_t i) const + { + return c[i]; + } + + /* + * Return the i-th coefficient of the conic section algebraic equation + * Modifying the returned value modifies the conic section coefficient + */ + double& coeff (size_t i) + { + return c[i]; + } + + kind_t kind () const; + + std::string categorise() const; + + /* + * Return true if the equation: + * c0*x^2 + c1*xy + c2*y^2 + c3*x + c4*y +c5 == 0 + * really defines a conic, false otherwise + */ + bool is_quadratic() const + { + return (coeff(0) != 0 || coeff(1) != 0 || coeff(2) != 0); + } + + /* + * Return true if the conic is degenerate, i.e. if the related matrix + * determinant is null, false otherwise + */ + bool isDegenerate() const + { + return (det_sgn (get_matrix()) == 0); + } + + /* + * Compute the centre of simmetry of the conic section when it exists, + * else it return an unitialized boost::optional<Point> instance. + */ + boost::optional<Point> centre() const + { + typedef boost::optional<Point> opt_point_t; + + double d = coeff(1) * coeff(1) - 4 * coeff(0) * coeff(2); + if (are_near (d, 0)) return opt_point_t(); + NL::Matrix Q(2, 2); + Q(0,0) = coeff(0); + Q(1,1) = coeff(2); + Q(0,1) = Q(1,0) = coeff(1) * 0.5; + NL::Vector T(2); + T[0] = - coeff(3) * 0.5; + T[1] = - coeff(4) * 0.5; + + NL::LinearSystem ls (Q, T); + NL::Vector sol = ls.SV_solve(); + Point C; + C[0] = sol[0]; + C[1] = sol[1]; + + return opt_point_t(C); + } + + double axis_angle() const; + + void roots (std::vector<double>& sol, Coord v, Dim2 d) const; + + xAx translate (const Point & _offset) const; + + xAx rotate (double angle) const; + + /* + * Rotate the conic section by the given angle wrt the provided point. + * + * _rot_centre: the rotation centre + * _angle: the rotation angle + */ + xAx rotate (const Point & _rot_centre, double _angle) const + { + xAx result + = translate (-_rot_centre).rotate (_angle).translate (_rot_centre); + return result; + } + + /* + * Compute the tangent line of the conic section at the provided point + * + * _point: the conic section point the tangent line pass through + */ + Line tangent (const Point & _point) const + { + NL::Vector pp(3); + pp[0] = _point[0]; pp[1] = _point[1]; pp[2] = 1; + NL::SymmetricMatrix<3> C = get_matrix(); + NL::Vector line = C * pp; + return Line(line[0], line[1], line[2]); + } + + /* + * For a non degenerate conic compute the dual conic. + * TODO: investigate degenerate case + */ + xAx dual () const + { + //assert (! isDegenerate()); + NL::SymmetricMatrix<3> C = get_matrix(); + NL::SymmetricMatrix<3> D = adj(C); + xAx dc(D); + return dc; + } + + bool decompose (Line& l1, Line& l2) const; + + /* + * Generate a RatQuad object from a conic arc. + * + * p0: the initial point of the arc + * p1: the inner point of the arc + * p2: the final point of the arc + */ + RatQuad toRatQuad (const Point & p0, + const Point & p1, + const Point & p2) const + { + Point dp0 = gradient (p0); + Point dp2 = gradient (p2); + return + RatQuad::fromPointsTangents (p0, rot90 (dp0), p1, p2, rot90 (dp2)); + } + + /* + * Return the angle related to the normal gradient computed at the passed + * point. + * + * _point: the point at which computes the angle + * + * prerequisite: the passed point must lie on the conic + */ + double angle_at (const Point & _point) const + { + double angle = atan2 (gradient (_point)); + if (angle < 0) angle += (2*M_PI); + return angle; + } + + /* + * Return true if the given point is contained in the conic arc determined + * by the passed points. + * + * _point: the point to be tested + * _initial: the initial point of the arc + * _inner: an inner point of the arc + * _final: the final point of the arc + * + * prerequisite: the passed points must lie on the conic, the inner point + * has to be strictly contained in the arc, except when the + * initial and final points are equal: in such a case if the + * inner point is also equal to them, then they define an arc + * made up by a single point. + * + */ + bool arc_contains (const Point & _point, const Point & _initial, + const Point & _inner, const Point & _final) const + { + double pa = angle_at (_point); + double sa = angle_at (_initial); + double ia = angle_at (_inner); + double ea = angle_at (_final); + // we test if _point and _inner have the same position + // wrt _initial and _final + return Geom::arc_contains (pa, sa, ia, ea); + } + + Rect arc_bound (const Point & P1, const Point & Q, const Point & P2) const; + + std::vector<Point> allNearestPoints (const Point P) const; + + /* + * Return the point on the conic section nearest to the passed point "P". + * + * P: the point to compute the nearest one + */ + Point nearestPoint (const Point P) const + { + std::vector<Point> points = allNearestPoints (P); + if (points.size() != 0) + { + return points.front(); + } + // else + THROW_LOGICALERROR ("nearestPoint: no nearest point found"); + return Point(); + } + +}; + +std::vector<Point> intersect(const xAx & C1, const xAx & C2); + +bool clip (std::vector<RatQuad> & rq, const xAx & cs, const Rect & R); + +inline std::ostream &operator<< (std::ostream &out_file, const xAx &x) { + for(int i = 0; i < 6; i++) { + out_file << x.c[i] << ", "; + } + return out_file; +} + +}; + + +#endif // _2GEOM_CONIC_SECTION_H_ + + +/* + 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:fileencoding=utf-8:textwidth=99 : + diff --git a/src/2geom/convex-cover.cpp b/src/2geom/convex-cover.cpp index db8094540..21a5c3107 100644 --- a/src/2geom/convex-cover.cpp +++ b/src/2geom/convex-cover.cpp @@ -33,6 +33,7 @@ #include <2geom/exception.h> #include <algorithm> #include <map> +#include <assert.h> /** Todo: + modify graham scan to work top to bottom, rather than around angles @@ -48,6 +49,7 @@ using std::vector; using std::map; using std::pair; +using std::make_pair; namespace Geom{ @@ -338,40 +340,74 @@ ConvexHull::is_degenerate() const { } -/* Here we really need a rotating calipers implementation. This implementation is slow and incorrect. - This incorrectness is a problem because it throws off the algorithms. Perhaps I will come up with - something better tomorrow. The incorrectness is in the order of the bridges - they must be in the - order of traversal around. Since the a->b and b->a bridges are seperated, they don't need to be merge - order, just the order of the traversal of the host hull. Currently some situations make a n->0 bridge - first.*/ -pair< map<int, int>, map<int, int> > -bridges(ConvexHull a, ConvexHull b) { - map<int, int> abridges; - map<int, int> bbridges; - - for(unsigned ia = 0; ia < a.boundary.size(); ia++) { - for(unsigned ib = 0; ib < b.boundary.size(); ib++) { - Point d = b[ib] - a[ia]; - Geom::Coord e = cross(d, a[ia - 1] - a[ia]), f = cross(d, a[ia + 1] - a[ia]); - Geom::Coord g = cross(d, b[ib - 1] - a[ia]), h = cross(d, b[ib + 1] - a[ia]); - if (e > 0 && f > 0 && g > 0 && h > 0) abridges[ia] = ib; - else if(e < 0 && f < 0 && g < 0 && h < 0) bbridges[ib] = ia; - } - } - - return make_pair(abridges, bbridges); +int sgn(double x) { + if(x == 0) return 0; + return (x<0)?-1:1; } -std::vector<Point> bridge_points(ConvexHull a, ConvexHull b) { - vector<Point> ret; - pair< map<int, int>, map<int, int> > indices = bridges(a, b); - for(map<int, int>::iterator it = indices.first.begin(); it != indices.first.end(); it++) { - ret.push_back(a[it->first]); - ret.push_back(b[it->second]); +bool same_side(Point L[2], Point xs[4]) { + int side = 0; + for(int i = 0; i < 4; i++) { + int sn = sgn(SignedTriangleArea(L[0], L[1], xs[i])); + if(sn and not side) + side = sn; + else if(sn != side) return false; } - for(map<int, int>::iterator it = indices.second.begin(); it != indices.second.end(); it++) { - ret.push_back(b[it->first]); - ret.push_back(a[it->second]); + return true; +} + +/** find bridging pairs between two convex hulls. + * this code is based on Hormoz Pirzadeh's masters thesis. There is room for optimisation: + * 1. reduce recomputation + * 2. use more efficient angle code + * 3. write as iterator + */ +std::vector<pair<int, int> > bridges(ConvexHull a, ConvexHull b) { + vector<pair<int, int> > ret; + + // 1. find maximal points on a and b + int ai = 0, bi = 0; + // 2. find first copodal pair + double ap_angle = atan2(a[ai+1] - a[ai]); + double bp_angle = atan2(b[bi+1] - b[bi]); + Point L[2] = {a[ai], b[bi]}; + while(ai < int(a.size()) or bi < int(b.size())) { + if(ap_angle == bp_angle) { + // In the case of parallel support lines, we must consider all four pairs of copodal points + { + assert(0); // untested + Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + xs[2] = b[bi]; + xs[3] = b[bi+2]; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + xs[0] = a[ai]; + xs[1] = a[ai+2]; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + xs[2] = b[bi-1]; + xs[3] = b[bi+1]; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + } + ai++; + ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]); + L[0] = a[ai]; + bi++; + bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]); + L[1] = b[bi]; + std::cout << "parallel\n"; + } else if(ap_angle < bp_angle) { + ai++; + ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]); + L[0] = a[ai]; + Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + } else { + bi++; + bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]); + L[1] = b[bi]; + Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + } } return ret; } @@ -428,16 +464,48 @@ ConvexHull intersection(ConvexHull /*a*/, ConvexHull /*b*/) { return ret; } +template <typename T> +T idx_to_pair(pair<T, T> p, int idx) { + return idx?p.second:p.first; +} + /*** ConvexHull merge(ConvexHull a, ConvexHull b); * find the smallest convex hull that surrounds a and b. */ ConvexHull merge(ConvexHull a, ConvexHull b) { ConvexHull ret; - pair< map<int, int>, map<int, int> > bpair = bridges(a, b); - map<int, int> ab = bpair.first; - map<int, int> bb = bpair.second; + std::cout << "---\n"; + std::vector<pair<int, int> > bpair = bridges(a, b); + + // Given our list of bridges {(pb1, qb1), ..., (pbk, qbk)} + // we start with the highest point in p0, q0, say it is p0. + // then the merged hull is p0, ..., pb1, qb1, ..., qb2, pb2, ... + // In other words, either of the two polygons vertices are added in order until the vertex coincides with a bridge point, at which point we swap. + + unsigned state = (a[0][Y] < b[0][Y])?0:1; + ret.boundary.reserve(a.size() + b.size()); + ConvexHull chs[2] = {a, b}; + unsigned idx = 0; + + for(unsigned k = 0; k < bpair.size(); k++) { + unsigned limit = idx_to_pair(bpair[k], state); + std::cout << bpair[k].first << " , " << bpair[k].second << "; " + << idx << ", " << limit << ", s: " + << state + << " \n"; + while(idx <= limit) { + ret.boundary.push_back(chs[state][idx++]); + } + state = 1-state; + idx = idx_to_pair(bpair[k], state); + } + while(idx < chs[state].size()) { + ret.boundary.push_back(chs[state][idx++]); + } + return ret; + /* ab[-1] = 0; bb[-1] = 0; @@ -460,6 +528,7 @@ ConvexHull merge(ConvexHull a, ConvexHull b) { if(bb[i] == 0 && i != -1) break; i = bb[i]; } + */ return ret; } diff --git a/src/2geom/convex-cover.h b/src/2geom/convex-cover.h index 8a5124019..d5e2dee44 100644 --- a/src/2geom/convex-cover.h +++ b/src/2geom/convex-cover.h @@ -67,6 +67,7 @@ public: bool contains_point(Point p); bool strict_contains_point(Point p); + inline size_t size() const { return boundary.size();} inline Point operator[](int i) const { int l = boundary.size(); @@ -133,7 +134,7 @@ public: // do two convex hulls intersect? bool intersectp(ConvexHull a, ConvexHull b); -std::vector<Point> bridge_points(ConvexHull a, ConvexHull b); +std::vector<std::pair<int, int> > bridges(ConvexHull a, ConvexHull b); // find the convex hull intersection ConvexHull intersection(ConvexHull a, ConvexHull b); diff --git a/src/2geom/coord.h b/src/2geom/coord.h index 481723413..9c42f6bfc 100644 --- a/src/2geom/coord.h +++ b/src/2geom/coord.h @@ -37,8 +37,11 @@ namespace Geom { +/** @brief Axis enum (X or Y). */ +enum Dim2 { X=0, Y=1 }; + /** - * A "real" type with sufficient precision for coordinates. + * @brief Floating point type used to store coordinates. * * You may safely assume that double (or even float) provides enough precision for storing * on-canvas points, and hence that double provides enough precision for dot products of @@ -51,7 +54,11 @@ const Coord EPSILON = 1e-5; //1e-18; inline Coord infinity() { return std::numeric_limits<Coord>::infinity(); } //IMPL: NearConcept -inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return fabs(a-b) <= eps; } +inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return a-b <= eps && a-b >= -eps; } +inline bool rel_error_bound(Coord a, Coord b, double eps=EPSILON) { return a <= eps*b && a >= -eps*b; } + + +typedef long IntCoord; } /* namespace Geom */ diff --git a/src/2geom/curve-helpers.cpp b/src/2geom/curve.cpp index 0ecd7d425..49e011a8b 100644 --- a/src/2geom/curve-helpers.cpp +++ b/src/2geom/curve.cpp @@ -1,10 +1,14 @@ -/* - * +/** + * \file + * \brief Abstract curve type - implementation of default methods + * + *//* * Authors: - * MenTaLguY <mental@rydia.net> - * Marco Cecchetti <mrcekets at gmail.com> + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright 2007-2008 authors + * Copyright 2007-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -30,11 +34,11 @@ * the specific language governing rights and limitations. */ - #include <2geom/curve.h> +#include <2geom/nearest-point.h> +#include <2geom/sbasis-geometric.h> #include <2geom/ord.h> - namespace Geom { @@ -79,8 +83,35 @@ int CurveHelpers::root_winding(Curve const &c, Point p) { return wind; } +Coord Curve::nearestPoint(Point const& p, Coord a, Coord b) const +{ + return nearest_point(p, toSBasis(), a, b); +} + +std::vector<Coord> Curve::allNearestPoints(Point const& p, Coord from, Coord to) const +{ + return all_nearest_points(p, toSBasis(), from, to); +} + +Coord Curve::length(Coord tolerance) const +{ + return ::Geom::length(toSBasis(), tolerance); +} + +Point Curve::unitTangentAt(Coord t, unsigned n) const +{ + std::vector<Point> derivs = pointAndDerivatives(t, n); + for (unsigned deriv_n = 1; deriv_n < derivs.size(); deriv_n++) { + Coord length = derivs[deriv_n].length(); + if ( ! are_near(length, 0) ) { + // length of derivative is non-zero, so return unit vector + return derivs[deriv_n] / length; + } + } + return Point (0,0); +}; -} // end namespace Geom +} // namespace Geom /* Local Variables: diff --git a/src/2geom/curve.h b/src/2geom/curve.h index 65bf86ef6..77f6808e1 100644 --- a/src/2geom/curve.h +++ b/src/2geom/curve.h @@ -1,12 +1,14 @@ /** * \file - * \brief Abstract Curve Type + * \brief Abstract curve type * + *//* * Authors: - * MenTaLguY <mental@rydia.net> - * Marco Cecchetti <mrcekets at gmail.com> + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright 2007-2008 authors + * Copyright 2007-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -33,23 +35,16 @@ */ - - #ifndef _2GEOM_CURVE_H_ #define _2GEOM_CURVE_H_ - +#include <vector> #include <2geom/coord.h> #include <2geom/point.h> #include <2geom/interval.h> -#include <2geom/nearest-point.h> #include <2geom/sbasis.h> #include <2geom/d2.h> -#include <2geom/matrix.h> -#include <2geom/exception.h> - -#include <vector> - +#include <2geom/affine.h> namespace Geom { @@ -61,99 +56,230 @@ protected: static int root_winding(Curve const &c, Point p); }; + +/** + * @brief Abstract continuous curve on a plane defined on [0,1]. + * + * Formally, a curve in 2Geom is defined as a function + * \f$\mathbf{C}: [0, 1] \to \mathbb{R}^2\f$ + * (a function that maps the unit interval to points on a 2D plane). Its image (the set of points + * the curve passes through) will be denoted \f$\mathcal{C} = \mathbf{C}[ [0, 1] ]\f$. + * All curve types available in 2Geom are continuous and differentiable on their + * interior, e.g. \f$(0, 1)\f$. Sometimes the curve's image (value set) is referred to as the curve + * itself for simplicity, but keep in mind that it's not strictly correct. + * + * It is common to think of the parameter as time. The curve can then be interpreted as + * describing the position of some moving object from time \f$t=0\f$ to \f$t=1\f$. + * Because of this, the parameter is frequently called the time value. + * + * Some methods return pointers to newly allocated curves. They are expected to be freed + * by the caller when no longer used. Default implementations are provided for some methods. + * + * @ingroup Curves + */ class Curve : private CurveHelpers { public: - virtual ~Curve() {} - - virtual Point initialPoint() const = 0; - virtual Point finalPoint() const = 0; - - /* isDegenerate returns true if the curve has "zero length". - * For a bezier curve this means for example that all handles are at the same point */ - virtual bool isDegenerate() const = 0; - - virtual Curve *duplicate() const = 0; - - virtual OptRect boundsFast() const = 0; - virtual OptRect boundsExact() const = 0; - virtual OptRect boundsLocal(OptInterval i, unsigned deg) const = 0; - OptRect boundsLocal(OptInterval i) const { return boundsLocal(i, 0); } - - virtual std::vector<double> roots(double v, Dim2 d) const = 0; - - virtual int winding(Point p) const { return root_winding(*this, p); } - - virtual int degreesOfFreedom() const { return 0;} - - //mental: review these - virtual Curve *portion(double f, double t) const = 0; - virtual Curve *reverse() const { return portion(1, 0); } - virtual Curve *derivative() const = 0; - - virtual void setInitial(Point v) = 0; - virtual void setFinal(Point v) = 0; - - virtual - double nearestPoint( Point const& p, double from = 0, double to = 1 ) const - { - return nearest_point(p, toSBasis(), from, to); - } - - virtual - std::vector<double> - allNearestPoints( Point const& p, double from = 0, double to = 1 ) const - { - return all_nearest_points(p, toSBasis(), from, to); - } - - /* - Path operator*=(Matrix) - This is not possible, because: - A Curve can be many things, for example a HLineSegment. - Such a segment cannot be transformed and stay a HLineSegment in general (take for example rotations). - This means that these curves become a different type of curve, hence one should use "transformed(Matrix). - */ - - virtual Curve *transformed(Matrix const &m) const = 0; - - virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 0).front(); } - virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; } - virtual Point operator() (double t) const { return pointAt(t); } - - /* pointAndDerivatives returns a vector that looks like the following: - * [ point at t, 1st derivative at t, 2nd derivative at t, ... , n'th derivative at t] */ - virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0; - - /* unitTangentAt returns the unit vector tangent to the curve at position t - * (in the direction of increasing t). The method uses l'Hopital's rule when the derivative - * is (0,0), parameter n determines the maximum nr of iterations (for when higher derivatives are also (0,0) ). - * Point(0,0) is returned if no non-zero derivative could be found. - * Note that unitTangentAt(1) will probably not give the desired result. Probably one should do: - * Curve * c_reverse = c.reverse(); - * Point tangent = - c_reverse->unitTangentAt(0); - * delete c_reverse; - */ - virtual Point unitTangentAt(Coord t, unsigned n = 3) const - { - std::vector<Point> derivs = pointAndDerivatives(t, n); - for (unsigned deriv_n = 1; deriv_n < derivs.size(); deriv_n++) { - Coord length = derivs[deriv_n].length(); - if ( ! are_near(length, 0) ) { - // length of derivative is non-zero, so return unit vector - return derivs[deriv_n] / length; - } + virtual ~Curve() {} + + /// @name Evaluate the curve + /// @{ + /** @brief Retrieve the start of the curve. + * @return The point corresponding to \f$\mathbf{C}(0)\f$. */ + virtual Point initialPoint() const = 0; + /** Retrieve the end of the curve. + * @return The point corresponding to \f$\mathbf{C}(1)\f$. */ + virtual Point finalPoint() const = 0; + /** @brief Check whether the curve has exactly zero length. + * @return True if the curve's initial point is exactly the same as its final point, and it contains + * no other points (its value set contains only one element). + */ + virtual bool isDegenerate() const = 0; + /** @brief Evaluate the curve at a specified time value. + * @param t Time value + * @return \f$\mathbf{C}(t)\f$ */ + virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 0).front(); } + /** @brief Evaluate one of the coordinates at the specified time value. + * @param t Time value + * @param d The dimension to evaluate + * @return The specified coordinate of \f$\mathbf{C}(t)\f$ */ + virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; } + /** @brief Evaluate the function at the specified time value. Allows curves to be used + * as functors. */ + virtual Point operator() (Coord t) const { return pointAt(t); } + /** @brief Evaluate the curve and its derivatives. + * This will return a vector that contains the value of the curve and the specified number + * of derivatives. However, the returned vector might contain less elements than specified + * if some derivatives do not exist. + * @param t Time value + * @param n The number of derivatives to compute + * @return Vector of at most \f$n+1\f$ elements of the form \f$[\mathbf{C}(t), + \mathbf{C}'(t), \mathbf{C}''(t), \ldots]\f$ */ + virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const = 0; + /// @} + + /// @name Change the curve's endpoints + /// @{ + /** @brief Change the starting point of the curve. + * After calling this method, it is guaranteed that \f$\mathbf{C}(0) = \mathbf{p}\f$, + * and the curve is still continuous. The precise new shape of the curve varies with curve + * type. + * @param p New starting point of the curve */ + virtual void setInitial(Point const &v) = 0; + /** @brief Change the ending point of the curve. + * After calling this method, it is guaranteed that \f$\mathbf{C}(0) = \mathbf{p}\f$, + * and the curve is still continuous. The precise new shape of the curve varies + * with curve type. + * @param p New ending point of the curve */ + virtual void setFinal(Point const &v) = 0; + /// @} + + /// @name Compute the bounding box + /// @{ + /** @brief Quickly compute the curve's approximate bounding box. + * The resulting rectangle is guaranteed to contain all points belonging to the curve, + * but it might not be the smallest such rectangle. This method is usually fast. + * @return A rectangle that contains all points belonging to the curve. */ + virtual Rect boundsFast() const = 0; + /** @brief Compute the curve's exact bounding box. + * This method can be dramatically slower than boundsExact() depending on the curve type. + * @return The smallest possible rectangle containing all of the curve's points. */ + virtual Rect boundsExact() const = 0; + // I have no idea what the 'deg' parameter is for, so this is undocumented for now. + virtual OptRect boundsLocal(OptInterval const &i, unsigned deg) const = 0; + /** @brief Compute the bounding box of a part of the curve. + * Since this method returns the smallest possible bounding rectangle of the specified portion, + * it can also be rather slow. + * @param a An interval specifying a part of the curve, or nothing. + * If \f$[0, 1] \subseteq a\f$, then the bounding box for the entire curve + * is calculated. + * @return The smallest possible rectangle containing all points in \f$\mathbf{C}[a]\f$, + * or nothing if the supplied interval is empty. */ + OptRect boundsLocal(OptInterval const &a) const { return boundsLocal(a, 0); } + /// @} + + /// @name Create new curves based on this one + /// @{ + /** @brief Create an exact copy of this curve. + * @return Pointer to a newly allocated curve, identical to the original */ + virtual Curve *duplicate() const = 0; + /** @brief Create a curve transformed by an affine transformation. + * This method returns a new curve instead modifying the existing one, because some curve + * types are not closed under affine transformations. The returned curve may be of different + * underlying type (as is the case for horizontal and vertical line segments). + * @param m Affine describing the affine transformation + * @return Pointer to a new, transformed curve */ + virtual Curve *transformed(Affine const &m) const = 0; + /** @brief Create a curve that corresponds to a part of this curve. + * For \f$a > b\f$, the returned portion will be reversed with respect to the original. + * The returned curve will always be of the same type. + * @param a Beginning of the interval specifying the portion of the curve + * @param b End of the interval + * @return New curve \f$\mathbf{D}\f$ such that: + * - \f$\mathbf{D}(0) = \mathbf{C}(a)\f$ + * - \f$\mathbf{D}(1) = \mathbf{C}(b)\f$ + * - \f$\mathbf{D}[ [0, 1] ] = \mathbf{C}[ [a?b] ]\f$, + * where \f$[a?b] = [\min(a, b), \max(a, b)]\f$ */ + virtual Curve *portion(Coord a, Coord b) const = 0; + /** @brief A version of that accepts an Interval. */ + Curve *portion(Interval const &i) const { return portion(i.min(), i.max()); } + /** @brief Create a reversed version of this curve. + * The result corresponds to <code>portion(1, 0)</code>, but this method might be faster. + * @return Pointer to a new curve \f$\mathbf{D}\f$ such that + * \f$\forall_{x \in [0, 1]} \mathbf{D}(x) = \mathbf{C}(1-x)\f$ */ + virtual Curve *reverse() const { return portion(1, 0); } + /** @brief Create a derivative of this curve. + * It's best to think of the derivative in physical terms: if the curve describes + * the position of some object on the plane from time \f$t=0\f$ to \f$t=1\f$ as said in the + * introduction, then the curve's derivative describes that object's speed at the same times. + * The second derivative refers to its acceleration, the third to jerk, etc. + * @return New curve \f$\mathbf{D} = \mathbf{C}'\f$. */ + virtual Curve *derivative() const = 0; + /// @} + + /// @name Advanced operations + /// @{ + /** @brief Compute a time value at which the curve comes closest to a specified point. + * The first value with the smallest distance is returned if there are multiple such points. + * @param p Query point + * @param a Minimum time value to consider + * @param b Maximum time value to consider; \f$a < b\f$ + * @return \f$q \in [a, b]: ||\mathbf{C}(q) - \mathbf{p}|| = + \inf(\{r \in \mathbb{R} : ||\mathbf{C}(r) - \mathbf{p}||\})\f$ */ + virtual Coord nearestPoint( Point const& p, Coord a = 0, Coord b = 1 ) const; + /** @brief A version that takes an Interval. */ + Coord nearestPoint(Point const &p, Interval const &i) const { + return nearestPoint(p, i.min(), i.max()); } - return Point (0,0); - }; - - virtual D2<SBasis> toSBasis() const = 0; - virtual bool operator==(Curve const &c) const { return this == &c;} + /** @brief Compute time values at which the curve comes closest to a specified point. + * @param p Query point + * @param a Minimum time value to consider + * @param b Maximum time value to consider; \f$a < b\f$ + * @return Vector of points closest and equally far away from the query point */ + virtual std::vector<Coord> allNearestPoints( Point const& p, Coord from = 0, + Coord to = 1 ) const; + /** @brief A version that takes an Interval. */ + std::vector<Coord> allNearestPoints(Point const &p, Interval const &i) { + return allNearestPoints(p, i.min(), i.max()); + } + /** @brief Compute the arc length of this curve. + * For a curve \f$\mathbf{C}(t) = (C_x(t), C_y(t))\f$, arc length is defined for 2D curves as + * \f[ \ell = \int_{0}^{1} \sqrt { [C_x'(t)]^2 + [C_y'(t)]^2 }\, \text{d}t \f] + * In other words, we divide the curve into infinitely small linear segments + * and add together their lengths. Of course we can't subdivide the curve into + * infinitely many segments on a computer, so this method returns an approximation. + * Not that there is usually no closed form solution to such integrals, so this + * method might be slow. + * @param tolerance Maximum allowed error + * @return Total distance the curve's value travels on the plane when going from 0 to 1 */ + virtual Coord length(Coord tolerance=0.01) const; + /** @brief Computes time values at which the curve intersects an axis-aligned line. + * @param v The coordinate of the line + * @param d Which axis the coordinate is on. X means a vertical line, Y a horizontal line. */ + virtual std::vector<Coord> roots(Coord v, Dim2 d) const = 0; + /** @brief Compute the winding number of the curve at the specified point. + * @todo Does this makes sense for curves at all? */ + virtual int winding(Point const &p) const { return root_winding(*this, p); } + /** @brief Compute a vector tangent to the curve. + * This will return an unit vector (a Point with length() equal to 1) that denotes a vector + * tangent to the curve. This vector is defined as + * \f$ \mathbf{v}(t) = \frac{\mathbf{C}'(t)}{||\mathbf{C}'(t)||} \f$. It is pointed + * in the direction of increasing \f$t\f$, at the specfied time value. The method uses + * l'Hopital's rule when the derivative is zero. A zero vector is returned if no non-zero + * derivative could be found. + * @param t Time value + * @param n The maximum order of derivative to consider + * @return Unit tangent vector \f$\mathbf{v}(t)\f$ + * @bug This method might currently break for the case of t being exactly 1. A workaround + * is to reverse the curve and use the negated unit tangent at 0 like this: + * @code + Curve *c_reverse = c.reverse(); + Point tangent = - c_reverse->unitTangentAt(0); + delete c_reverse; @endcode */ + virtual Point unitTangentAt(Coord t, unsigned n = 3) const; + /** @brief Convert the curve to a symmetric power basis polynomial. + * Symmetric power basis polynomials (S-basis for short) are numerical representations + * of curves with excellent numerical properties. Most high level operations provided by 2Geom + * are implemented in terms of S-basis operations, so every curve has to provide a method + * to convert it to an S-basis polynomial on two variables. See SBasis class reference + * for more information. */ + virtual D2<SBasis> toSBasis() const = 0; + /// @} + + /// @name Miscellaneous + /// @{ + /** Return the number of independent parameters required to represent all variations + * of this curve. For example, for Bezier curves it returns the curve's order + * multiplied by 2. */ + virtual int degreesOfFreedom() const { return 0;} + /** @brief Test equality of two curves. + * @return True if the curves are identical, false otherwise */ + virtual bool operator==(Curve const &c) const { return this == &c;} + /// @} }; inline -Coord nearest_point(Point const& p, Curve const& c) -{ - return c.nearestPoint(p); +Coord nearest_point(Point const& p, Curve const& c) { + return c.nearestPoint(p); } } // end namespace Geom @@ -161,8 +287,6 @@ Coord nearest_point(Point const& p, Curve const& c) #endif // _2GEOM_CURVE_H_ - - /* Local Variables: mode:c++ diff --git a/src/2geom/curves.h b/src/2geom/curves.h index 6c8435387..64cf3d4fb 100644 --- a/src/2geom/curves.h +++ b/src/2geom/curves.h @@ -1,7 +1,7 @@ /** * \file - * \brief this file is only a helper header to include all curve types at once - * + * \brief Include all curve types + *//* * Authors: * MenTaLguY <mental@rydia.net> * Marco Cecchetti <mrcekets at gmail.com> @@ -32,9 +32,6 @@ * the specific language governing rights and limitations. */ - - - #ifndef _2GEOM_CURVES_H_ #define _2GEOM_CURVES_H_ @@ -43,15 +40,11 @@ #include <2geom/sbasis-curve.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> -//#include <2geom/elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/svg-elliptical-arc.h> - #endif // _2GEOM_CURVES_H_ - - - /* Local Variables: mode:c++ diff --git a/src/2geom/d2-sbasis.cpp b/src/2geom/d2-sbasis.cpp index 4f5a53cd2..697a9d84e 100644 --- a/src/2geom/d2-sbasis.cpp +++ b/src/2geom/d2-sbasis.cpp @@ -121,7 +121,7 @@ Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, return result; } -Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Matrix const &m) { +Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Affine const &m) { Piecewise<D2<SBasis> > result; if(a.empty()) return result; result.push_cut(a.cuts[0]); @@ -259,6 +259,57 @@ std::vector<Piecewise<D2<SBasis> > > fuse_nearby_ends(std::vector<Piecewise<D2<S return f; } +/* + * Computes the intersection of two sets given as (ordered) union of intervals. + */ +static std::vector<Interval> intersect( std::vector<Interval> const &a, std::vector<Interval> const &b){ + std::vector<Interval> result; + //TODO: use order! + for (unsigned i=0; i < a.size(); i++){ + for (unsigned j=0; j < b.size(); j++){ + OptInterval c( a[i] ); + c &= b[j]; + if ( c ) { + result.push_back( *c ); + } + } + } + return result; +} + +std::vector<Interval> level_set( D2<SBasis> const &f, Rect region){ + std::vector<Rect> regions( 1, region ); + return level_sets( f, regions ).front(); +} +std::vector<Interval> level_set( D2<SBasis> const &f, Point p, double tol){ + Rect region(p, p); + region.expandBy( tol ); + return level_set( f, region ); +} +std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Rect> regions){ + std::vector<Interval> regsX (regions.size(), Interval() ); + std::vector<Interval> regsY (regions.size(), Interval() ); + for ( unsigned i=0; i < regions.size(); i++ ){ + regsX[i] = regions[i][X]; + regsY[i] = regions[i][Y]; + } + std::vector<std::vector<Interval> > x_in_regs = level_sets( f[X], regsX ); + std::vector<std::vector<Interval> > y_in_regs = level_sets( f[Y], regsY ); + std::vector<std::vector<Interval> >result(regions.size(), std::vector<Interval>() ); + for (unsigned i=0; i<regions.size(); i++){ + result[i] = intersect ( x_in_regs[i], y_in_regs[i] ); + } + return result; +} +std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Point> pts, double tol){ + std::vector<Rect> regions( pts.size(), Rect() ); + for (unsigned i=0; i<pts.size(); i++){ + regions[i] = Rect( pts[i], pts[i] ); + regions[i].expandBy( tol ); + } + return level_sets( f, regions ); +} + } // namespace Geom diff --git a/src/2geom/d2-sbasis.h b/src/2geom/d2-sbasis.h index 2b087bda6..bd6c35805 100644 --- a/src/2geom/d2-sbasis.h +++ b/src/2geom/d2-sbasis.h @@ -45,7 +45,7 @@ #include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> #include <2geom/piecewise.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> //TODO: implement intersect @@ -76,7 +76,7 @@ Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > co Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Point const &b); Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b); -Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Matrix const &m); +Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Affine const &m); Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, double tol=0, bool closed=false); @@ -138,6 +138,11 @@ inline OptRect bounds_local(D2<SBasis> const & s, OptInterval i, unsigned order= return retval; } +std::vector<Interval> level_set( D2<SBasis> const &f, Rect region); +std::vector<Interval> level_set( D2<SBasis> const &f, Point p, double tol); +std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Rect> regions); +std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Point> pts, double tol); + } #endif diff --git a/src/2geom/d2.h b/src/2geom/d2.h index bdf042806..3e4de430e 100644 --- a/src/2geom/d2.h +++ b/src/2geom/d2.h @@ -34,7 +34,7 @@ #include <2geom/point.h> #include <2geom/interval.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <boost/concept_check.hpp> #include <2geom/concepts.h> @@ -251,7 +251,7 @@ template <typename T> inline D2<T> operator/=(D2<T> & a, double b) { a[0] /= b; a[1] /= b; return a; } template<typename T> -D2<T> operator*(D2<T> const &v, Matrix const &m) { +D2<T> operator*(D2<T> const &v, Affine const &m) { boost::function_requires<AddableConcept<T> >(); boost::function_requires<ScalableConcept<T> >(); D2<T> ret; diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 8030ea517..bea99e5dd 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -170,7 +170,7 @@ void Ellipse::set(std::vector<Point> const& points) } -SVGEllipticalArc +EllipticalArc * Ellipse::arc(Point const& initial, Point const& inner, Point const& final, bool _svg_compliant) { @@ -212,21 +212,27 @@ Ellipse::arc(Point const& initial, Point const& inner, Point const& final, } } - SVGEllipticalArc ea( initial, ray(X), ray(Y), rot_angle(), - large_arc_flag, sweep_flag, final, _svg_compliant); - return ea; + EllipticalArc *ret_arc; + if (_svg_compliant) { + ret_arc = new SVGEllipticalArc(initial, ray(X), ray(Y), rot_angle(), + large_arc_flag, sweep_flag, final); + } else { + ret_arc = new EllipticalArc(initial, ray(X), ray(Y), rot_angle(), + large_arc_flag, sweep_flag, final); + } + return ret_arc; } -Ellipse Ellipse::transformed(Matrix const& m) const +Ellipse Ellipse::transformed(Affine const& m) const { double cosrot = std::cos(rot_angle()); double sinrot = std::sin(rot_angle()); - Matrix A( ray(X) * cosrot, ray(X) * sinrot, + Affine A( ray(X) * cosrot, ray(X) * sinrot, -ray(Y) * sinrot, ray(Y) * cosrot, 0, 0 ); Point new_center = center() * m; - Matrix M = m.without_translation(); - Matrix AM = A * M; + Affine M = m.withoutTranslation(); + Affine AM = A * M; if ( are_near(AM.det(), 0) ) { double angle; @@ -250,11 +256,11 @@ Ellipse Ellipse::transformed(Matrix const& m) const } std::vector<double> coeff = implicit_form_coefficients(); - Matrix Q( coeff[0], coeff[1]/2, + Affine Q( coeff[0], coeff[1]/2, coeff[1]/2, coeff[2], 0, 0 ); - Matrix invm = M.inverse(); + Affine invm = M.inverse(); Q = invm * Q ; std::swap( invm[1], invm[2] ); Q *= invm; diff --git a/src/2geom/ellipse.h b/src/2geom/ellipse.h index 8e44f3395..297254366 100644 --- a/src/2geom/ellipse.h +++ b/src/2geom/ellipse.h @@ -35,15 +35,15 @@ #ifndef _2GEOM_ELLIPSE_H_ #define _2GEOM_ELLIPSE_H_ - +#include <vector> #include <2geom/point.h> #include <2geom/exception.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> namespace Geom { -class SVGEllipticalArc; +class EllipticalArc; class Circle; class Ellipse @@ -88,9 +88,8 @@ class Ellipse // prerequisite: at least 5 points must be passed void set(std::vector<Point> const& points); - SVGEllipticalArc - arc(Point const& initial, Point const& inner, Point const& final, - bool _svg_compliant = true); + EllipticalArc * + arc(Point const& initial, Point const& inner, Point const& final, bool svg_compliant = true); Point center() const { @@ -114,7 +113,7 @@ class Ellipse std::vector<double> implicit_form_coefficients() const; - Ellipse transformed(Matrix const& m) const; + Ellipse transformed(Affine const& m) const; private: Point m_centre, m_ray; diff --git a/src/2geom/elliptical-arc.cpp b/src/2geom/elliptical-arc.cpp index fd0e7cf9b..acaad82cf 100644 --- a/src/2geom/elliptical-arc.cpp +++ b/src/2geom/elliptical-arc.cpp @@ -1,7 +1,10 @@ /* * SVG Elliptical Arc Class * - * Copyright 2008 Marco Cecchetti <mrcekets at gmail.com> + * Authors: + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * Copyright 2008-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -27,896 +30,881 @@ * the specific language governing rights and limitations. */ +#include <cfloat> +#include <limits> +#include <memory> #include <2geom/elliptical-arc.h> +#include <2geom/ellipse.h> +#include <2geom/sbasis-geometric.h> #include <2geom/bezier-curve.h> #include <2geom/poly.h> -#include <2geom/sbasis-math.h> - -#include <cfloat> -#include <limits> - +#include <2geom/transforms.h> +#include <2geom/utils.h> +#include <2geom/numeric/vector.h> +#include <2geom/numeric/fitting-tool.h> +#include <2geom/numeric/fitting-model.h> namespace Geom { +/** + * @class EllipticalArc + * @brief Elliptical arc curve + * + * Elliptical arc is a curve taking the shape of a section of an ellipse. + * + * The arc function has two forms: the regular one, mapping the unit interval to points + * on 2D plane (the linear domain), and a second form that maps some interval + * \f$A \subseteq [0,2\pi)\f$ to the same points (the angular domain). The interval \f$A\f$ + * determines which part of the ellipse forms the arc. The arc is said to contain an angle + * if its angular domain includes that angle (and therefore it is defined for that angle). + * + * The angular domain considers each ellipse to be + * a rotated, scaled and translated unit circle: 0 corresponds to \f$(1,0)\f$ on the unit circle, + * \f$\pi/2\f$ corresponds to \f$(0,1)\f$, \f$\pi\f$ to \f$(-1,0)\f$ and \f$3\pi/2\f$ + * to \f$(0,-1)\f$. After the angle is mapped to a point from a unit circle, the point is + * transformed using a matrix of this form + * \f[ M = \left[ \begin{array}{ccc} + r_X \cos(\theta) & -r_Y \sin(\theta) & 0 \\ + r_X \sin(\theta) & r_Y \cos(\theta) & 0 \\ + c_X & c_Y & 1 \end{array} \right] \f] + * where \f$r_X, r_Y\f$ are the X and Y rays of the ellipse, \f$\theta\f$ is its angle of rotation, + * and \f$c_X, c_Y\f$ the coordinates of the ellipse's center - thus mapping the angle + * to some point on the ellipse. Note that for example the point at angluar coordinate 0, + * the center and the point at angular coordinate \f$\pi/4\f$ do not necessarily + * create an angle of \f$\pi/4\f$ radians; it is only the case if both axes of the ellipse + * are of the same length (i.e. it is a circle). + * + * @image html ellipse-angular-coordinates.png "An illustration of the angular domain" + * + * Each arc is defined by five variables: The initial and final point, the ellipse's rays, + * and the ellipse's rotation. Each set of those parameters corresponds to four different arcs, + * with two of them larger than half an ellipse and two of them turning clockwise while traveling + * from initial to final point. The two flags disambiguate between them: "large arc flag" selects + * the bigger arc, while the "sweep flag" selects the clockwise arc. + * + * @image html elliptical-arc-flags.png "The four possible arcs and the meaning of flags" + * + * @ingroup Curves + */ -OptRect EllipticalArc::boundsExact() const +Rect EllipticalArc::boundsExact() const { - std::vector<double> extremes(4); - double cosrot = std::cos(rotation_angle()); - double sinrot = std::sin(rotation_angle()); - extremes[0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot ); - extremes[1] = extremes[0] + M_PI; - if ( extremes[0] < 0 ) extremes[0] += 2*M_PI; - extremes[2] = std::atan2( ray(Y) * cosrot, ray(X) * sinrot ); - extremes[3] = extremes[2] + M_PI; - if ( extremes[2] < 0 ) extremes[2] += 2*M_PI; - - - std::vector<double>arc_extremes(4); - arc_extremes[0] = initialPoint()[X]; - arc_extremes[1] = finalPoint()[X]; - if ( arc_extremes[0] < arc_extremes[1] ) - std::swap(arc_extremes[0], arc_extremes[1]); - arc_extremes[2] = initialPoint()[Y]; - arc_extremes[3] = finalPoint()[Y]; - if ( arc_extremes[2] < arc_extremes[3] ) - std::swap(arc_extremes[2], arc_extremes[3]); - - - if ( start_angle() < end_angle() ) - { - if ( sweep_flag() ) - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() < extremes[i] && extremes[i] < end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - else - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() > extremes[i] || extremes[i] > end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - } - else - { - if ( sweep_flag() ) - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() < extremes[i] || extremes[i] < end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - else - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() > extremes[i] && extremes[i] > end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - } - - return Rect( Point(arc_extremes[1], arc_extremes[3]) , - Point(arc_extremes[0], arc_extremes[2]) ); + double extremes[4]; + double sinrot, cosrot; + sincos(_rot_angle, sinrot, cosrot); + + extremes[0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot ); + extremes[1] = extremes[0] + M_PI; + if ( extremes[0] < 0 ) extremes[0] += 2*M_PI; + extremes[2] = std::atan2( ray(Y) * cosrot, ray(X) * sinrot ); + extremes[3] = extremes[2] + M_PI; + if ( extremes[2] < 0 ) extremes[2] += 2*M_PI; + + + double arc_extremes[4]; + arc_extremes[0] = initialPoint()[X]; + arc_extremes[1] = finalPoint()[X]; + if ( arc_extremes[0] < arc_extremes[1] ) + std::swap(arc_extremes[0], arc_extremes[1]); + arc_extremes[2] = initialPoint()[Y]; + arc_extremes[3] = finalPoint()[Y]; + if ( arc_extremes[2] < arc_extremes[3] ) + std::swap(arc_extremes[2], arc_extremes[3]); + + for (unsigned i = 0; i < 4; ++i) { + if (containsAngle(extremes[i])) { + arc_extremes[i] = valueAtAngle(extremes[i], i >> 1 ? Y : X); + } + } + return Rect( Point(arc_extremes[1], arc_extremes[3]) , + Point(arc_extremes[0], arc_extremes[2]) ); } -std::vector<double> -EllipticalArc::roots(double v, Dim2 d) const +Point EllipticalArc::pointAtAngle(Coord t) const { - if ( d > Y ) - { - THROW_RANGEERROR("dimention out of range"); - } - - std::vector<double> sol; - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { - if ( center(d) == v ) - sol.push_back(0); - return sol; - } - - const char* msg[2][2] = - { - { "d == X; ray(X) == 0; " - "s = (v - center(X)) / ( -ray(Y) * std::sin(rotation_angle()) ); " - "s should be contained in [-1,1]", - "d == X; ray(Y) == 0; " - "s = (v - center(X)) / ( ray(X) * std::cos(rotation_angle()) ); " - "s should be contained in [-1,1]" - }, - { "d == Y; ray(X) == 0; " - "s = (v - center(X)) / ( ray(Y) * std::cos(rotation_angle()) ); " - "s should be contained in [-1,1]", - "d == Y; ray(Y) == 0; " - "s = (v - center(X)) / ( ray(X) * std::sin(rotation_angle()) ); " - "s should be contained in [-1,1]" - }, - }; - - for ( unsigned int dim = 0; dim < 2; ++dim ) - { - if ( are_near(ray(dim), 0) ) - { - - if ( initialPoint()[d] == v && finalPoint()[d] == v ) - { - THROW_INFINITESOLUTIONS(0); - } - if ( (initialPoint()[d] < finalPoint()[d]) - && (initialPoint()[d] > v || finalPoint()[d] < v) ) - { - return sol; - } - if ( (initialPoint()[d] > finalPoint()[d]) - && (finalPoint()[d] > v || initialPoint()[d] < v) ) - { - return sol; - } - double ray_prj; - switch(d) - { - case X: - switch(dim) - { - case X: ray_prj = -ray(Y) * std::sin(rotation_angle()); - break; - case Y: ray_prj = ray(X) * std::cos(rotation_angle()); - break; - } - break; - case Y: - switch(dim) - { - case X: ray_prj = ray(Y) * std::cos(rotation_angle()); - break; - case Y: ray_prj = ray(X) * std::sin(rotation_angle()); - break; - } - break; - } - - double s = (v - center(d)) / ray_prj; - if ( s < -1 || s > 1 ) - { - THROW_LOGICALERROR(msg[d][dim]); - } - switch(dim) - { - case X: - s = std::asin(s); // return a value in [-PI/2,PI/2] - if ( logical_xor( sweep_flag(), are_near(start_angle(), M_PI/2) ) ) - { - if ( s < 0 ) s += 2*M_PI; - } - else - { - s = M_PI - s; - if (!(s < 2*M_PI) ) s -= 2*M_PI; - } - break; - case Y: - s = std::acos(s); // return a value in [0,PI] - if ( logical_xor( sweep_flag(), are_near(start_angle(), 0) ) ) - { - s = 2*M_PI - s; - if ( !(s < 2*M_PI) ) s -= 2*M_PI; - } - break; - } - - //std::cerr << "s = " << rad_to_deg(s); - s = map_to_01(s); - //std::cerr << " -> t: " << s << std::endl; - if ( !(s < 0 || s > 1) ) - sol.push_back(s); - return sol; - } - } - - double rotx, roty; - switch(d) - { - case X: - rotx = std::cos(rotation_angle()); - roty = -std::sin(rotation_angle()); - break; - case Y: - rotx = std::sin(rotation_angle()); - roty = std::cos(rotation_angle()); - break; - } - double rxrotx = ray(X) * rotx; - double c_v = center(d) - v; - - double a = -rxrotx + c_v; - double b = ray(Y) * roty; - double c = rxrotx + c_v; - //std::cerr << "a = " << a << std::endl; - //std::cerr << "b = " << b << std::endl; - //std::cerr << "c = " << c << std::endl; - - if ( are_near(a,0) ) - { - sol.push_back(M_PI); - if ( !are_near(b,0) ) - { - double s = 2 * std::atan(-c/(2*b)); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - } - } - else - { - double delta = b * b - a * c; - //std::cerr << "delta = " << delta << std::endl; - if ( are_near(delta, 0) ) - { - double s = 2 * std::atan(-b/a); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - } - else if ( delta > 0 ) - { - double sq = std::sqrt(delta); - double s = 2 * std::atan( (-b - sq) / a ); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - s = 2 * std::atan( (-b + sq) / a ); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - } - } - - std::vector<double> arc_sol; - for (unsigned int i = 0; i < sol.size(); ++i ) - { - //std::cerr << "s = " << rad_to_deg(sol[i]); - sol[i] = map_to_01(sol[i]); - //std::cerr << " -> t: " << sol[i] << std::endl; - if ( !(sol[i] < 0 || sol[i] > 1) ) - arc_sol.push_back(sol[i]); - } - return arc_sol; - - -// return SBasisCurve(toSBasis()).roots(v, d); + Point ret = Point::polar(t) * unitCircleTransform(); + return ret; } -// D(E(t,C),t) = E(t+PI/2,O) -Curve* EllipticalArc::derivative() const +Coord EllipticalArc::valueAtAngle(Coord t, Dim2 d) const { - EllipticalArc* result = new EllipticalArc(*this); - result->m_center[X] = result->m_center[Y] = 0; - result->m_start_angle += M_PI/2; - if( !( result->m_start_angle < 2*M_PI ) ) - { - result->m_start_angle -= 2*M_PI; - } - result->m_end_angle += M_PI/2; - if( !( result->m_end_angle < 2*M_PI ) ) - { - result->m_end_angle -= 2*M_PI; - } - result->m_initial_point = result->pointAtAngle( result->start_angle() ); - result->m_final_point = result->pointAtAngle( result->end_angle() ); - return result; + Coord sinrot, cosrot, cost, sint; + sincos(_rot_angle, sinrot, cosrot); + sincos(t, sint, cost); + if ( d == X ) { + return ray(X) * cosrot * cost + - ray(Y) * sinrot * sint + + center(X); + } else { + return ray(X) * sinrot * cost + + ray(Y) * cosrot * sint + + center(Y); + } } -std::vector<Point> -EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const +Affine EllipticalArc::unitCircleTransform() const { - unsigned int nn = n+1; // nn represents the size of the result vector. - std::vector<Point> result; - result.reserve(nn); - double angle = map_unit_interval_on_circular_arc(t, start_angle(), - end_angle(), sweep_flag()); - EllipticalArc ea(*this); - ea.m_center = Point(0,0); - unsigned int m = std::min(nn, 4u); - for ( unsigned int i = 0; i < m; ++i ) - { - result.push_back( ea.pointAtAngle(angle) ); - angle += M_PI/2; - if ( !(angle < 2*M_PI) ) angle -= 2*M_PI; - } - m = nn / 4; - for ( unsigned int i = 1; i < m; ++i ) - { - for ( unsigned int j = 0; j < 4; ++j ) - result.push_back( result[j] ); - } - m = nn - 4 * m; - for ( unsigned int i = 0; i < m; ++i ) - { - result.push_back( result[i] ); - } - if ( !result.empty() ) // nn != 0 - result[0] = pointAtAngle(angle); - return result; + Affine ret = Scale(ray(X), ray(Y)) * Rotate(_rot_angle); + ret.setTranslation(center()); + return ret; } -D2<SBasis> EllipticalArc::toSBasis() const +std::vector<Coord> EllipticalArc::roots(Coord v, Dim2 d) const { - // the interval of parametrization has to be [0,1] - Coord et = start_angle() + ( sweep_flag() ? sweep_angle() : -sweep_angle() ); - Linear param(start_angle(), et); - Coord cos_rot_angle = std::cos(rotation_angle()); - Coord sin_rot_angle = std::sin(rotation_angle()); - // order = 4 seems to be enough to get a perfect looking elliptical arc - // should it be choosen in function of the arc length anyway ? - // or maybe a user settable parameter: toSBasis(unsigned int order) ? - SBasis arc_x = ray(X) * cos(param,4); - SBasis arc_y = ray(Y) * sin(param,4); - D2<SBasis> arc; - arc[0] = arc_x * cos_rot_angle - arc_y * sin_rot_angle + Linear(center(X),center(X)); - arc[1] = arc_x * sin_rot_angle + arc_y * cos_rot_angle + Linear(center(Y),center(Y)); - return arc; + std::vector<Coord> sol; + + if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) { + if ( center(d) == v ) + sol.push_back(0); + return sol; + } + + static const char* msg[2][2] = + { + { "d == X; ray(X) == 0; " + "s = (v - center(X)) / ( -ray(Y) * std::sin(_rot_angle) ); " + "s should be contained in [-1,1]", + "d == X; ray(Y) == 0; " + "s = (v - center(X)) / ( ray(X) * std::cos(_rot_angle) ); " + "s should be contained in [-1,1]" + }, + { "d == Y; ray(X) == 0; " + "s = (v - center(X)) / ( ray(Y) * std::cos(_rot_angle) ); " + "s should be contained in [-1,1]", + "d == Y; ray(Y) == 0; " + "s = (v - center(X)) / ( ray(X) * std::sin(_rot_angle) ); " + "s should be contained in [-1,1]" + }, + }; + + for ( unsigned int dim = 0; dim < 2; ++dim ) + { + if ( are_near(ray((Dim2) dim), 0) ) + { + if ( initialPoint()[d] == v && finalPoint()[d] == v ) + { + THROW_INFINITESOLUTIONS(0); + } + if ( (initialPoint()[d] < finalPoint()[d]) + && (initialPoint()[d] > v || finalPoint()[d] < v) ) + { + return sol; + } + if ( (initialPoint()[d] > finalPoint()[d]) + && (finalPoint()[d] > v || initialPoint()[d] < v) ) + { + return sol; + } + double ray_prj; + switch(d) + { + case X: + switch(dim) + { + case X: ray_prj = -ray(Y) * std::sin(_rot_angle); + break; + case Y: ray_prj = ray(X) * std::cos(_rot_angle); + break; + } + break; + case Y: + switch(dim) + { + case X: ray_prj = ray(Y) * std::cos(_rot_angle); + break; + case Y: ray_prj = ray(X) * std::sin(_rot_angle); + break; + } + break; + } + + double s = (v - center(d)) / ray_prj; + if ( s < -1 || s > 1 ) + { + THROW_LOGICALERROR(msg[d][dim]); + } + switch(dim) + { + case X: + s = std::asin(s); // return a value in [-PI/2,PI/2] + if ( logical_xor( _sweep, are_near(initialAngle(), M_PI/2) ) ) + { + if ( s < 0 ) s += 2*M_PI; + } + else + { + s = M_PI - s; + if (!(s < 2*M_PI) ) s -= 2*M_PI; + } + break; + case Y: + s = std::acos(s); // return a value in [0,PI] + if ( logical_xor( _sweep, are_near(initialAngle(), 0) ) ) + { + s = 2*M_PI - s; + if ( !(s < 2*M_PI) ) s -= 2*M_PI; + } + break; + } + + //std::cerr << "s = " << rad_to_deg(s); + s = map_to_01(s); + //std::cerr << " -> t: " << s << std::endl; + if ( !(s < 0 || s > 1) ) + sol.push_back(s); + return sol; + } + } + + double rotx, roty; + sincos(_rot_angle, roty, rotx); + if (d == X) roty = -roty; + + double rxrotx = ray(X) * rotx; + double c_v = center(d) - v; + + double a = -rxrotx + c_v; + double b = ray(Y) * roty; + double c = rxrotx + c_v; + //std::cerr << "a = " << a << std::endl; + //std::cerr << "b = " << b << std::endl; + //std::cerr << "c = " << c << std::endl; + + if ( are_near(a,0) ) + { + sol.push_back(M_PI); + if ( !are_near(b,0) ) + { + double s = 2 * std::atan(-c/(2*b)); + if ( s < 0 ) s += 2*M_PI; + sol.push_back(s); + } + } + else + { + double delta = b * b - a * c; + //std::cerr << "delta = " << delta << std::endl; + if ( are_near(delta, 0) ) + { + double s = 2 * std::atan(-b/a); + if ( s < 0 ) s += 2*M_PI; + sol.push_back(s); + } + else if ( delta > 0 ) + { + double sq = std::sqrt(delta); + double s = 2 * std::atan( (-b - sq) / a ); + if ( s < 0 ) s += 2*M_PI; + sol.push_back(s); + s = 2 * std::atan( (-b + sq) / a ); + if ( s < 0 ) s += 2*M_PI; + sol.push_back(s); + } + } + + std::vector<double> arc_sol; + for (unsigned int i = 0; i < sol.size(); ++i ) + { + //std::cerr << "s = " << rad_to_deg(sol[i]); + sol[i] = map_to_01(sol[i]); + //std::cerr << " -> t: " << sol[i] << std::endl; + if ( !(sol[i] < 0 || sol[i] > 1) ) + arc_sol.push_back(sol[i]); + } + return arc_sol; } -bool EllipticalArc::containsAngle(Coord angle) const +// D(E(t,C),t) = E(t+PI/2,O), where C is the ellipse center +// the derivative doesn't rotate the ellipse but there is a translation +// of the parameter t by an angle of PI/2 so the ellipse points are shifted +// of such an angle in the cw direction +Curve *EllipticalArc::derivative() const { - if ( sweep_flag() ) - if ( start_angle() < end_angle() ) - return ( !( angle < start_angle() || angle > end_angle() ) ); - else - return ( !( angle < start_angle() && angle > end_angle() ) ); - else - if ( start_angle() > end_angle() ) - return ( !( angle > start_angle() || angle < end_angle() ) ); - else - return ( !( angle > start_angle() && angle < end_angle() ) ); + EllipticalArc *result = static_cast<EllipticalArc*>(duplicate()); + result->_center[X] = result->_center[Y] = 0; + result->_start_angle += M_PI/2; + if( !( result->_start_angle < 2*M_PI ) ) + { + result->_start_angle -= 2*M_PI; + } + result->_end_angle += M_PI/2; + if( !( result->_end_angle < 2*M_PI ) ) + { + result->_end_angle -= 2*M_PI; + } + result->_initial_point = result->pointAtAngle( result->initialAngle() ); + result->_final_point = result->pointAtAngle( result->finalAngle() ); + return result; } -double EllipticalArc::valueAtAngle(Coord t, Dim2 d) const +std::vector<Point> +EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const { - double sin_rot_angle = std::sin(rotation_angle()); - double cos_rot_angle = std::cos(rotation_angle()); - if ( d == X ) + unsigned int nn = n+1; // nn represents the size of the result vector. + std::vector<Point> result; + result.reserve(nn); + double angle = map_unit_interval_on_circular_arc(t, initialAngle(), + finalAngle(), _sweep); + std::auto_ptr<EllipticalArc> ea( static_cast<EllipticalArc*>(duplicate()) ); + ea->_center = Point(0,0); + unsigned int m = std::min(nn, 4u); + for ( unsigned int i = 0; i < m; ++i ) { - return ray(X) * cos_rot_angle * std::cos(t) - - ray(Y) * sin_rot_angle * std::sin(t) - + center(X); + result.push_back( ea->pointAtAngle(angle) ); + angle += M_PI/2; + if ( !(angle < 2*M_PI) ) angle -= 2*M_PI; } - else if ( d == Y ) + m = nn / 4; + for ( unsigned int i = 1; i < m; ++i ) { - return ray(X) * sin_rot_angle * std::cos(t) - + ray(Y) * cos_rot_angle * std::sin(t) - + center(Y); + for ( unsigned int j = 0; j < 4; ++j ) + result.push_back( result[j] ); + } + m = nn - 4 * m; + for ( unsigned int i = 0; i < m; ++i ) + { + result.push_back( result[i] ); } - THROW_RANGEERROR("dimension parameter out of range"); + if ( !result.empty() ) // nn != 0 + result[0] = pointAtAngle(angle); + return result; } +bool EllipticalArc::containsAngle(Coord angle) const +{ + return AngleInterval::contains(angle); +} Curve* EllipticalArc::portion(double f, double t) const { - if (f < 0) f = 0; - if (f > 1) f = 1; - if (t < 0) t = 0; - if (t > 1) t = 1; - if ( are_near(f, t) ) - { - EllipticalArc* arc = new EllipticalArc(); - arc->m_center = arc->m_initial_point = arc->m_final_point = pointAt(f); - arc->m_start_angle = arc->m_end_angle = m_start_angle; - arc->m_rot_angle = m_rot_angle; - arc->m_sweep = m_sweep; - arc->m_large_arc = m_large_arc; - } - EllipticalArc* arc = new EllipticalArc( *this ); - arc->m_initial_point = pointAt(f); - arc->m_final_point = pointAt(t); - double sa = sweep_flag() ? sweep_angle() : -sweep_angle(); - arc->m_start_angle = m_start_angle + sa * f; - if ( !(arc->m_start_angle < 2*M_PI) ) - arc->m_start_angle -= 2*M_PI; - if ( arc->m_start_angle < 0 ) - arc->m_start_angle += 2*M_PI; - arc->m_end_angle = m_start_angle + sa * t; - if ( !(arc->m_end_angle < 2*M_PI) ) - arc->m_end_angle -= 2*M_PI; - if ( arc->m_end_angle < 0 ) - arc->m_end_angle += 2*M_PI; - if ( f > t ) arc->m_sweep = !sweep_flag(); - if ( large_arc_flag() && (arc->sweep_angle() < M_PI) ) - arc->m_large_arc = false; + // fix input arguments + if (f < 0) f = 0; + if (f > 1) f = 1; + if (t < 0) t = 0; + if (t > 1) t = 1; + + if ( are_near(f, t) ) + { + EllipticalArc *arc = static_cast<EllipticalArc*>(duplicate()); + arc->_center = arc->_initial_point = arc->_final_point = pointAt(f); + arc->_start_angle = arc->_end_angle = _start_angle; + arc->_rot_angle = _rot_angle; + arc->_sweep = _sweep; + arc->_large_arc = _large_arc; + return arc; + } + + EllipticalArc *arc = static_cast<EllipticalArc*>(duplicate()); + arc->_initial_point = pointAt(f); + arc->_final_point = pointAt(t); + if ( f > t ) arc->_sweep = !_sweep; + if ( _large_arc && fabs(sweepAngle() * (t-f)) < M_PI) + arc->_large_arc = false; + arc->_updateCenterAndAngles(arc->isSVGCompliant()); //TODO: be more clever return arc; } -// NOTE: doesn't work with 360 deg arcs -void EllipticalArc::calculate_center_and_extreme_angles() +// the arc is the same but traversed in the opposite direction +Curve *EllipticalArc::reverse() const { + EllipticalArc *rarc = static_cast<EllipticalArc*>(duplicate()); + rarc->_sweep = !_sweep; + rarc->_initial_point = _final_point; + rarc->_final_point = _initial_point; + rarc->_start_angle = _end_angle; + rarc->_end_angle = _start_angle; + rarc->_updateCenterAndAngles(rarc->isSVGCompliant()); + return rarc; +} + +#ifdef HAVE_GSL // GSL is required for function "solve_reals" +std::vector<double> EllipticalArc::allNearestPoints( Point const& p, double from, double to ) const { - // as stated in the svg standard the rotation angle parameter - // value must be modulo 2*PI - m_rot_angle = std::fmod(m_rot_angle, 2*M_PI); - if (m_rot_angle < 0) m_rot_angle += 2*M_PI; + std::vector<double> result; + + if ( from > to ) std::swap(from, to); + if ( from < 0 || to > 1 ) + { + THROW_RANGEERROR("[from,to] interval out of range"); + } - if ( are_near(initialPoint(), finalPoint()) ) + if ( ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) || are_near(from, to) ) { - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { - m_start_angle = m_end_angle = 0; - m_center = initialPoint(); - return; - } - else - { - THROW_RANGEERROR("initial and final point are the same"); - } - } - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { // but initialPoint != finalPoint - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 && ray(Y) == 0 but initialPoint != finalPoint" - ); - } - if ( are_near(ray(Y), 0) ) - { - Point v = initialPoint() - finalPoint(); - if ( are_near(L2sq(v), 4*ray(X)*ray(X)) ) - { - double angle = std::atan2(v[Y], v[X]); - if (angle < 0) angle += 2*M_PI; - if ( are_near( angle, rotation_angle() ) ) - { - m_start_angle = 0; - m_end_angle = M_PI; - m_center = v/2 + finalPoint(); - return; - } - angle -= M_PI; - if ( angle < 0 ) angle += 2*M_PI; - if ( are_near( angle, rotation_angle() ) ) - { - m_start_angle = M_PI; - m_end_angle = 0; - m_center = v/2 + finalPoint(); - return; - } - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(Y) == 0 " - "and slope(initialPoint - finalPoint) != rotation_angle " - "and != rotation_angle + PI" - ); - } - if ( L2sq(v) > 4*ray(X)*ray(X) ) - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(Y) == 0 and distance(initialPoint, finalPoint) > 2*ray(X)" - ); - } - else - { - THROW_RANGEERROR( - "there is infinite ellipses that satisfy the given constraints: " - "ray(Y) == 0 and distance(initialPoint, finalPoint) < 2*ray(X)" - ); - } - - } - - if ( are_near(ray(X), 0) ) - { - Point v = initialPoint() - finalPoint(); - if ( are_near(L2sq(v), 4*ray(Y)*ray(Y)) ) - { - double angle = std::atan2(v[Y], v[X]); - if (angle < 0) angle += 2*M_PI; - double rot_angle = rotation_angle() + M_PI/2; - if ( !(rot_angle < 2*M_PI) ) rot_angle -= 2*M_PI; - if ( are_near( angle, rot_angle ) ) - { - m_start_angle = M_PI/2; - m_end_angle = 3*M_PI/2; - m_center = v/2 + finalPoint(); - return; - } - angle -= M_PI; - if ( angle < 0 ) angle += 2*M_PI; - if ( are_near( angle, rot_angle ) ) - { - m_start_angle = 3*M_PI/2; - m_end_angle = M_PI/2; - m_center = v/2 + finalPoint(); - return; - } - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 " - "and slope(initialPoint - finalPoint) != rotation_angle + PI/2 " - "and != rotation_angle + (3/2)*PI" - ); - } - if ( L2sq(v) > 4*ray(Y)*ray(Y) ) - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 and distance(initialPoint, finalPoint) > 2*ray(Y)" - ); - } - else - { - THROW_RANGEERROR( - "there is infinite ellipses that satisfy the given constraints: " - "ray(X) == 0 and distance(initialPoint, finalPoint) < 2*ray(Y)" - ); - } - - } - - double sin_rot_angle = std::sin(rotation_angle()); - double cos_rot_angle = std::cos(rotation_angle()); - - Point sp = sweep_flag() ? initialPoint() : finalPoint(); - Point ep = sweep_flag() ? finalPoint() : initialPoint(); - - Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle, - -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle, - 0, 0 ); - Matrix im = m.inverse(); - Point sol = (ep - sp) * im; - double half_sum_angle = std::atan2(-sol[X], sol[Y]); - double half_diff_angle; - if ( are_near(std::fabs(half_sum_angle), M_PI/2) ) + result.push_back(from); + return result; + } + else if ( are_near(ray(X), 0) || are_near(ray(Y), 0) ) { - double anti_sgn_hsa = (half_sum_angle > 0) ? -1 : 1; - double arg = anti_sgn_hsa * sol[X] / 2; - // if |arg| is a little bit > 1 acos returns nan - if ( are_near(arg, 1) ) - half_diff_angle = 0; - else if ( are_near(arg, -1) ) - half_diff_angle = M_PI; + LineSegment seg(pointAt(from), pointAt(to)); + Point np = seg.pointAt( seg.nearestPoint(p) ); + if ( are_near(ray(Y), 0) ) + { + if ( are_near(_rot_angle, M_PI/2) + || are_near(_rot_angle, 3*M_PI/2) ) + { + result = roots(np[Y], Y); + } + else + { + result = roots(np[X], X); + } + } else { - if ( !(-1 < arg && arg < 1) ) - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints" - ); - // assert( -1 < arg && arg < 1 ); - // if it fails - // => there is no ellipse that satisfies the given constraints - half_diff_angle = std::acos( arg ); + if ( are_near(_rot_angle, M_PI/2) + || are_near(_rot_angle, 3*M_PI/2) ) + { + result = roots(np[X], X); + } + else + { + result = roots(np[Y], Y); + } } + return result; + } + else if ( are_near(ray(X), ray(Y)) ) + { + Point r = p - center(); + if ( are_near(r, Point(0,0)) ) + { + THROW_INFINITESOLUTIONS(0); + } + // TODO: implement case r != 0 +// Point np = ray(X) * unit_vector(r); +// std::vector<double> solX = roots(np[X],X); +// std::vector<double> solY = roots(np[Y],Y); +// double t; +// if ( are_near(solX[0], solY[0]) || are_near(solX[0], solY[1])) +// { +// t = solX[0]; +// } +// else +// { +// t = solX[1]; +// } +// if ( !(t < from || t > to) ) +// { +// result.push_back(t); +// } +// else +// { +// +// } + } - half_diff_angle = M_PI/2 - half_diff_angle; + // solve the equation <D(E(t),t)|E(t)-p> == 0 + // that provides min and max distance points + // on the ellipse E wrt the point p + // after the substitutions: + // cos(t) = (1 - s^2) / (1 + s^2) + // sin(t) = 2t / (1 + s^2) + // where s = tan(t/2) + // we get a 4th degree equation in s + /* + * ry s^4 ((-cy + py) Cos[Phi] + (cx - px) Sin[Phi]) + + * ry ((cy - py) Cos[Phi] + (-cx + px) Sin[Phi]) + + * 2 s^3 (rx^2 - ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) + + * 2 s (-rx^2 + ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) + */ + + Point p_c = p - center(); + double rx2_ry2 = (ray(X) - ray(Y)) * (ray(X) + ray(Y)); + double sinrot, cosrot; + sincos(_rot_angle, sinrot, cosrot); + double expr1 = ray(X) * (p_c[X] * cosrot + p_c[Y] * sinrot); + Poly coeff; + coeff.resize(5); + coeff[4] = ray(Y) * ( p_c[Y] * cosrot - p_c[X] * sinrot ); + coeff[3] = 2 * ( rx2_ry2 + expr1 ); + coeff[2] = 0; + coeff[1] = 2 * ( -rx2_ry2 + expr1 ); + coeff[0] = -coeff[4]; + +// for ( unsigned int i = 0; i < 5; ++i ) +// std::cerr << "c[" << i << "] = " << coeff[i] << std::endl; + + std::vector<double> real_sol; + // gsl_poly_complex_solve raises an error + // if the leading coefficient is zero + if ( are_near(coeff[4], 0) ) + { + real_sol.push_back(0); + if ( !are_near(coeff[3], 0) ) + { + double sq = -coeff[1] / coeff[3]; + if ( sq > 0 ) + { + double s = std::sqrt(sq); + real_sol.push_back(s); + real_sol.push_back(-s); + } + } } else { - double arg = sol[Y] / ( 2 * std::cos(half_sum_angle) ); - // if |arg| is a little bit > 1 asin returns nan - if ( are_near(arg, 1) ) - half_diff_angle = M_PI/2; - else if ( are_near(arg, -1) ) - half_diff_angle = -M_PI/2; - else + real_sol = solve_reals(coeff); + } + + for ( unsigned int i = 0; i < real_sol.size(); ++i ) + { + real_sol[i] = 2 * std::atan(real_sol[i]); + if ( real_sol[i] < 0 ) real_sol[i] += 2*M_PI; + } + // when s -> Infinity then <D(E)|E-p> -> 0 iff coeff[4] == 0 + // so we add M_PI to the solutions being lim arctan(s) = PI when s->Infinity + if ( (real_sol.size() % 2) != 0 ) + { + real_sol.push_back(M_PI); + } + + double mindistsq1 = std::numeric_limits<double>::max(); + double mindistsq2 = std::numeric_limits<double>::max(); + double dsq; + unsigned int mi1, mi2; + for ( unsigned int i = 0; i < real_sol.size(); ++i ) + { + dsq = distanceSq(p, pointAtAngle(real_sol[i])); + if ( mindistsq1 > dsq ) { - if ( !(-1 < arg && arg < 1) ) - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints" - ); - // assert( -1 < arg && arg < 1 ); - // if it fails - // => there is no ellipse that satisfies the given constraints - half_diff_angle = std::asin( arg ); + mindistsq2 = mindistsq1; + mi2 = mi1; + mindistsq1 = dsq; + mi1 = i; + } + else if ( mindistsq2 > dsq ) + { + mindistsq2 = dsq; + mi2 = i; } } - if ( ( m_large_arc && half_diff_angle > 0 ) - || (!m_large_arc && half_diff_angle < 0 ) ) + double t = map_to_01( real_sol[mi1] ); + if ( !(t < from || t > to) ) { - half_diff_angle = -half_diff_angle; - } - if ( half_sum_angle < 0 ) half_sum_angle += 2*M_PI; - if ( half_diff_angle < 0 ) half_diff_angle += M_PI; - - m_start_angle = half_sum_angle - half_diff_angle; - m_end_angle = half_sum_angle + half_diff_angle; - // 0 <= m_start_angle, m_end_angle < 2PI - if ( m_start_angle < 0 ) m_start_angle += 2*M_PI; - if( !(m_end_angle < 2*M_PI) ) m_end_angle -= 2*M_PI; - sol[0] = std::cos(m_start_angle); - sol[1] = std::sin(m_start_angle); - m_center = sp - sol * m; - if ( !sweep_flag() ) + result.push_back(t); + } + + bool second_sol = false; + t = map_to_01( real_sol[mi2] ); + if ( real_sol.size() == 4 && !(t < from || t > to) ) { - double angle = m_start_angle; - m_start_angle = m_end_angle; - m_end_angle = angle; + if ( result.empty() || are_near(mindistsq1, mindistsq2) ) + { + result.push_back(t); + second_sol = true; + } } + + // we need to test extreme points too + double dsq1 = distanceSq(p, pointAt(from)); + double dsq2 = distanceSq(p, pointAt(to)); + if ( second_sol ) + { + if ( mindistsq2 > dsq1 ) + { + result.clear(); + result.push_back(from); + mindistsq2 = dsq1; + } + else if ( are_near(mindistsq2, dsq) ) + { + result.push_back(from); + } + if ( mindistsq2 > dsq2 ) + { + result.clear(); + result.push_back(to); + } + else if ( are_near(mindistsq2, dsq2) ) + { + result.push_back(to); + } + + } + else + { + if ( result.empty() ) + { + if ( are_near(dsq1, dsq2) ) + { + result.push_back(from); + result.push_back(to); + } + else if ( dsq2 > dsq1 ) + { + result.push_back(from); + } + else + { + result.push_back(to); + } + } + } + + return result; } +#endif -Coord EllipticalArc::map_to_02PI(Coord t) const +/* + * NOTE: this implementation follows Standard SVG 1.1 implementation guidelines + * for elliptical arc curves. See Appendix F.6. + */ +void EllipticalArc::_updateCenterAndAngles(bool svg) { - if ( sweep_flag() ) + Point d = initialPoint() - finalPoint(); + + // TODO move this to SVGElipticalArc? + if (svg) { - Coord angle = start_angle() + sweep_angle() * t; - if ( !(angle < 2*M_PI) ) - angle -= 2*M_PI; - return angle; + if ( initialPoint() == finalPoint() ) + { + _rot_angle = _start_angle = _end_angle = 0; + _center = initialPoint(); + _rays = Geom::Point(0,0); + _large_arc = _sweep = false; + return; + } + + _rays[X] = std::fabs(_rays[X]); + _rays[Y] = std::fabs(_rays[Y]); + + if ( are_near(ray(X), 0) || are_near(ray(Y), 0) ) + { + _rays[X] = L2(d) / 2; + _rays[Y] = 0; + _rot_angle = std::atan2(d[Y], d[X]); + _start_angle = 0; + _end_angle = M_PI; + _center = middle_point(initialPoint(), finalPoint()); + _large_arc = false; + _sweep = false; + return; + } } else { - Coord angle = start_angle() - sweep_angle() * t; - if ( angle < 0 ) angle += 2*M_PI; - return angle; + if ( are_near(initialPoint(), finalPoint()) ) + { + if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) + { + _start_angle = _end_angle = 0; + _center = initialPoint(); + return; + } + else + { + THROW_RANGEERROR("initial and final point are the same"); + } + } + if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) + { // but initialPoint != finalPoint + THROW_RANGEERROR( + "there is no ellipse that satisfies the given constraints: " + "ray(X) == 0 && ray(Y) == 0 but initialPoint != finalPoint" + ); + } + if ( are_near(ray(Y), 0) ) + { + Point v = initialPoint() - finalPoint(); + if ( are_near(L2sq(v), 4*ray(X)*ray(X)) ) + { + Angle angle(v); + if ( are_near( angle, _rot_angle ) ) + { + _start_angle = 0; + _end_angle = M_PI; + _center = v/2 + finalPoint(); + return; + } + angle -= M_PI; + if ( are_near( angle, _rot_angle ) ) + { + _start_angle = M_PI; + _end_angle = 0; + _center = v/2 + finalPoint(); + return; + } + THROW_RANGEERROR( + "there is no ellipse that satisfies the given constraints: " + "ray(Y) == 0 " + "and slope(initialPoint - finalPoint) != rotation_angle " + "and != rotation_angle + PI" + ); + } + if ( L2sq(v) > 4*ray(X)*ray(X) ) + { + THROW_RANGEERROR( + "there is no ellipse that satisfies the given constraints: " + "ray(Y) == 0 and distance(initialPoint, finalPoint) > 2*ray(X)" + ); + } + else + { + THROW_RANGEERROR( + "there is infinite ellipses that satisfy the given constraints: " + "ray(Y) == 0 and distance(initialPoint, finalPoint) < 2*ray(X)" + ); + } + + } + + if ( are_near(ray(X), 0) ) + { + Point v = initialPoint() - finalPoint(); + if ( are_near(L2sq(v), 4*ray(Y)*ray(Y)) ) + { + double angle = std::atan2(v[Y], v[X]); + if (angle < 0) angle += 2*M_PI; + double rot_angle = _rot_angle.radians() + M_PI/2; + if ( !(rot_angle < 2*M_PI) ) rot_angle -= 2*M_PI; + if ( are_near( angle, rot_angle ) ) + { + _start_angle = M_PI/2; + _end_angle = 3*M_PI/2; + _center = v/2 + finalPoint(); + return; + } + angle -= M_PI; + if ( angle < 0 ) angle += 2*M_PI; + if ( are_near( angle, rot_angle ) ) + { + _start_angle = 3*M_PI/2; + _end_angle = M_PI/2; + _center = v/2 + finalPoint(); + return; + } + THROW_RANGEERROR( + "there is no ellipse that satisfies the given constraints: " + "ray(X) == 0 " + "and slope(initialPoint - finalPoint) != rotation_angle + PI/2 " + "and != rotation_angle + (3/2)*PI" + ); + } + if ( L2sq(v) > 4*ray(Y)*ray(Y) ) + { + THROW_RANGEERROR( + "there is no ellipse that satisfies the given constraints: " + "ray(X) == 0 and distance(initialPoint, finalPoint) > 2*ray(Y)" + ); + } + else + { + THROW_RANGEERROR( + "there is infinite ellipses that satisfy the given constraints: " + "ray(X) == 0 and distance(initialPoint, finalPoint) < 2*ray(Y)" + ); + } + + } + } + + Rotate rm(_rot_angle); + Affine m(rm); + m[1] = -m[1]; + m[2] = -m[2]; + + Point p = (d / 2) * m; + double rx2 = _rays[X] * _rays[X]; + double ry2 = _rays[Y] * _rays[Y]; + double rxpy = _rays[X] * p[Y]; + double rypx = _rays[Y] * p[X]; + double rx2py2 = rxpy * rxpy; + double ry2px2 = rypx * rypx; + double num = rx2 * ry2; + double den = rx2py2 + ry2px2; + assert(den != 0); + double rad = num / den; + Point c(0,0); + if (rad > 1) + { + rad -= 1; + rad = std::sqrt(rad); + + if (_large_arc == _sweep) rad = -rad; + c = rad * Point(rxpy / ray(Y), -rypx / ray(X)); + + _center = c * rm + middle_point(initialPoint(), finalPoint()); + } + else if (rad == 1 || svg) + { + double lamda = std::sqrt(1 / rad); + _rays[X] *= lamda; + _rays[Y] *= lamda; + _center = middle_point(initialPoint(), finalPoint()); + } + else + { + THROW_RANGEERROR( + "there is no ellipse that satisfies the given constraints" + ); + } + + Point sp((p[X] - c[X]) / ray(X), (p[Y] - c[Y]) / ray(Y)); + Point ep((-p[X] - c[X]) / ray(X), (-p[Y] - c[Y]) / ray(Y)); + Point v(1, 0); + _start_angle = angle_between(v, sp); + double sweep_angle = angle_between(sp, ep); + if (!_sweep && sweep_angle > 0) sweep_angle -= 2*M_PI; + if (_sweep && sweep_angle < 0) sweep_angle += 2*M_PI; + + _end_angle = _start_angle; + _end_angle += sweep_angle; } -Coord EllipticalArc::map_to_01(Coord angle) const +D2<SBasis> EllipticalArc::toSBasis() const { - return map_circular_arc_on_unit_interval(angle, start_angle(), - end_angle(), sweep_flag()); + D2<SBasis> arc; + // the interval of parametrization has to be [0,1] + Coord et = initialAngle().radians() + ( _sweep ? sweepAngle() : -sweepAngle() ); + Linear param(initialAngle(), et); + Coord cos_rot_angle, sin_rot_angle; + sincos(_rot_angle, sin_rot_angle, cos_rot_angle); + + // order = 4 seems to be enough to get a perfect looking elliptical arc + SBasis arc_x = ray(X) * cos(param,4); + SBasis arc_y = ray(Y) * sin(param,4); + arc[0] = arc_x * cos_rot_angle - arc_y * sin_rot_angle + Linear(center(X),center(X)); + arc[1] = arc_x * sin_rot_angle + arc_y * cos_rot_angle + Linear(center(Y),center(Y)); + + // ensure that endpoints remain exact + for ( int d = 0 ; d < 2 ; d++ ) { + arc[d][0][0] = initialPoint()[d]; + arc[d][0][1] = finalPoint()[d]; + } + + return arc; } -std::vector<double> EllipticalArc:: -allNearestPoints( Point const& p, double from, double to ) const +Curve *EllipticalArc::transformed(Affine const& m) const { - if ( from > to ) std::swap(from, to); - if ( from < 0 || to > 1 ) - { - THROW_RANGEERROR("[from,to] interval out of range"); - } - std::vector<double> result; - if ( ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) || are_near(from, to) ) - { - result.push_back(from); - return result; - } - else if ( are_near(ray(X), 0) || are_near(ray(Y), 0) ) - { - LineSegment seg(pointAt(from), pointAt(to)); - Point np = seg.pointAt( seg.nearestPoint(p) ); - if ( are_near(ray(Y), 0) ) - { - if ( are_near(rotation_angle(), M_PI/2) - || are_near(rotation_angle(), 3*M_PI/2) ) - { - result = roots(np[Y], Y); - } - else - { - result = roots(np[X], X); - } - } - else - { - if ( are_near(rotation_angle(), M_PI/2) - || are_near(rotation_angle(), 3*M_PI/2) ) - { - result = roots(np[X], X); - } - else - { - result = roots(np[Y], Y); - } - } - return result; - } - else if ( are_near(ray(X), ray(Y)) ) - { - Point r = p - center(); - if ( are_near(r, Point(0,0)) ) - { - THROW_INFINITESOLUTIONS(0); - } - // TODO: implement case r != 0 -// Point np = ray(X) * unit_vector(r); -// std::vector<double> solX = roots(np[X],X); -// std::vector<double> solY = roots(np[Y],Y); -// double t; -// if ( are_near(solX[0], solY[0]) || are_near(solX[0], solY[1])) -// { -// t = solX[0]; -// } -// else -// { -// t = solX[1]; -// } -// if ( !(t < from || t > to) ) -// { -// result.push_back(t); -// } -// else -// { -// -// } - } - - // solve the equation <D(E(t),t)|E(t)-p> == 0 - // that provides min and max distance points - // on the ellipse E wrt the point p - // after the substitutions: - // cos(t) = (1 - s^2) / (1 + s^2) - // sin(t) = 2t / (1 + s^2) - // where s = tan(t/2) - // we get a 4th degree equation in s - /* - * ry s^4 ((-cy + py) Cos[Phi] + (cx - px) Sin[Phi]) + - * ry ((cy - py) Cos[Phi] + (-cx + px) Sin[Phi]) + - * 2 s^3 (rx^2 - ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) + - * 2 s (-rx^2 + ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) - */ - - Point p_c = p - center(); - double rx2_ry2 = (ray(X) - ray(Y)) * (ray(X) + ray(Y)); - double cosrot = std::cos( rotation_angle() ); - double sinrot = std::sin( rotation_angle() ); - double expr1 = ray(X) * (p_c[X] * cosrot + p_c[Y] * sinrot); - Poly coeff; - coeff.resize(5); - coeff[4] = ray(Y) * ( p_c[Y] * cosrot - p_c[X] * sinrot ); - coeff[3] = 2 * ( rx2_ry2 + expr1 ); - coeff[2] = 0; - coeff[1] = 2 * ( -rx2_ry2 + expr1 ); - coeff[0] = -coeff[4]; - -// for ( unsigned int i = 0; i < 5; ++i ) -// std::cerr << "c[" << i << "] = " << coeff[i] << std::endl; - - std::vector<double> real_sol; - // gsl_poly_complex_solve raises an error - // if the leading coefficient is zero - if ( are_near(coeff[4], 0) ) - { - real_sol.push_back(0); - if ( !are_near(coeff[3], 0) ) - { - double sq = -coeff[1] / coeff[3]; - if ( sq > 0 ) - { - double s = std::sqrt(sq); - real_sol.push_back(s); - real_sol.push_back(-s); - } - } - } - else - { - real_sol = solve_reals(coeff); - } -// else -// { -// double sol[8]; -// gsl_poly_complex_workspace * w = gsl_poly_complex_workspace_alloc(5); -// gsl_poly_complex_solve(coeff, 5, w, sol ); -// gsl_poly_complex_workspace_free(w); -// -// for ( unsigned int i = 0; i < 4; ++i ) -// { -// if ( sol[2*i+1] == 0 ) real_sol.push_back(sol[2*i]); -// } -// } - - for ( unsigned int i = 0; i < real_sol.size(); ++i ) - { - real_sol[i] = 2 * std::atan(real_sol[i]); - if ( real_sol[i] < 0 ) real_sol[i] += 2*M_PI; - } - // when s -> Infinity then <D(E)|E-p> -> 0 iff coeff[4] == 0 - // so we add M_PI to the solutions being lim arctan(s) = PI when s->Infinity - if ( (real_sol.size() % 2) != 0 ) - { - real_sol.push_back(M_PI); - } - - double mindistsq1 = std::numeric_limits<double>::max(); - double mindistsq2 = std::numeric_limits<double>::max(); - double dsq; - unsigned int mi1, mi2; - for ( unsigned int i = 0; i < real_sol.size(); ++i ) - { - dsq = distanceSq(p, pointAtAngle(real_sol[i])); - if ( mindistsq1 > dsq ) - { - mindistsq2 = mindistsq1; - mi2 = mi1; - mindistsq1 = dsq; - mi1 = i; - } - else if ( mindistsq2 > dsq ) - { - mindistsq2 = dsq; - mi2 = i; - } - } - - double t = map_to_01( real_sol[mi1] ); - if ( !(t < from || t > to) ) - { - result.push_back(t); - } - - bool second_sol = false; - t = map_to_01( real_sol[mi2] ); - if ( real_sol.size() == 4 && !(t < from || t > to) ) - { - if ( result.empty() || are_near(mindistsq1, mindistsq2) ) - { - result.push_back(t); - second_sol = true; - } - } - - // we need to test extreme points too - double dsq1 = distanceSq(p, pointAt(from)); - double dsq2 = distanceSq(p, pointAt(to)); - if ( second_sol ) - { - if ( mindistsq2 > dsq1 ) - { - result.clear(); - result.push_back(from); - mindistsq2 = dsq1; - } - else if ( are_near(mindistsq2, dsq) ) - { - result.push_back(from); - } - if ( mindistsq2 > dsq2 ) - { - result.clear(); - result.push_back(to); - } - else if ( are_near(mindistsq2, dsq2) ) - { - result.push_back(to); - } - - } - else - { - if ( result.empty() ) - { - if ( are_near(dsq1, dsq2) ) - { - result.push_back(from); - result.push_back(to); - } - else if ( dsq2 > dsq1 ) - { - result.push_back(from); - } - else - { - result.push_back(to); - } - } - } - - return result; + Ellipse e(center(X), center(Y), ray(X), ray(Y), _rot_angle); + Ellipse et = e.transformed(m); + Point inner_point = pointAt(0.5); + return et.arc( initialPoint() * m, + inner_point * m, + finalPoint() * m, + isSVGCompliant() ); } +Coord EllipticalArc::map_to_01(Coord angle) const +{ + return map_circular_arc_on_unit_interval(angle, initialAngle(), + finalAngle(), _sweep); +} } // end namespace Geom - /* Local Variables: mode:c++ @@ -928,4 +916,3 @@ allNearestPoints( Point const& p, double from, double to ) const */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : - diff --git a/src/2geom/elliptical-arc.h b/src/2geom/elliptical-arc.h index 002735944..e1e757207 100644 --- a/src/2geom/elliptical-arc.h +++ b/src/2geom/elliptical-arc.h @@ -1,12 +1,14 @@ /** * \file - * \brief Elliptical Arc - implementation of the svg elliptical arc path element + * \brief Elliptical arc curve * + *//* * Authors: - * MenTaLguY <mental@rydia.net> - * Marco Cecchetti <mrcekets at gmail.com> + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright 2007-2008 authors + * Copyright 2007-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,272 +34,234 @@ * the specific language governing rights and limitations. */ - - - #ifndef _2GEOM_ELLIPTICAL_ARC_H_ #define _2GEOM_ELLIPTICAL_ARC_H_ - -#include <2geom/curve.h> +#include <algorithm> #include <2geom/angle.h> -#include <2geom/utils.h> +#include <2geom/bezier-curve.h> +#include <2geom/curve.h> +#include <2geom/affine.h> #include <2geom/sbasis-curve.h> // for non-native methods - -#include <algorithm> - +#include <2geom/utils.h> namespace Geom { -class EllipticalArc : public Curve +class EllipticalArc : public Curve, public AngleInterval { - public: - EllipticalArc() - : m_initial_point(Point(0,0)), m_final_point(Point(0,0)), - m_rx(0), m_ry(0), m_rot_angle(0), - m_large_arc(true), m_sweep(true) - { - m_start_angle = m_end_angle = 0; - m_center = Point(0,0); - } - - EllipticalArc( Point _initial_point, double _rx, double _ry, - double _rot_angle, bool _large_arc, bool _sweep, - Point _final_point - ) - : m_initial_point(_initial_point), m_final_point(_final_point), - m_rx(_rx), m_ry(_ry), m_rot_angle(_rot_angle), - m_large_arc(_large_arc), m_sweep(_sweep) - { - calculate_center_and_extreme_angles(); - } - - void set( Point _initial_point, double _rx, double _ry, - double _rot_angle, bool _large_arc, bool _sweep, - Point _final_point - ) +public: + /** @brief Creates an arc with all variables set to zero, and both flags to true. */ + EllipticalArc() + : AngleInterval(0, 0, true) + , _initial_point(0,0) + , _final_point(0,0) + , _rays(0,0) + , _center(0,0) + , _rot_angle(0) + , _large_arc(true) + {} + /** @brief Create a new elliptical arc. + * @param ip Initial point of the arc + * @param rx First ray of the ellipse + * @param ry Second ray of the ellipse + * @param rot Angle of rotation of the X axis of the ellipse in radians + * @param large If true, the large arc is chosen (always >= 180 degrees), otherwise + * the smaller arc is chosen + * @param sweep If true, the clockwise arc is chosen, otherwise the counter-clockwise + * arc is chosen + * @param fp Final point of the arc */ + EllipticalArc( Point ip, Coord rx, Coord ry, + Coord rot_angle, bool large_arc, bool sweep, + Point fp + ) + : AngleInterval(0,0,sweep) + , _initial_point(ip) + , _final_point(fp) + , _rays(rx, ry) + , _rot_angle(rot_angle) + , _large_arc(large_arc) { - m_initial_point = _initial_point; - m_final_point = _final_point; - m_rx = _rx; - m_ry = _ry; - m_rot_angle = _rot_angle; - m_large_arc = _large_arc; - m_sweep = _sweep; - calculate_center_and_extreme_angles(); + _updateCenterAndAngles(false); } - Curve* duplicate() const - { - return new EllipticalArc(*this); - } - - double center(unsigned int i) const - { - return m_center[i]; + // methods new to EllipticalArc go here + + /// @name Retrieve and modify parameters + /// @{ + /** @brief Get the interval of angles the arc contains + * @return The interval between the final and initial angles of the arc */ + Interval angleInterval() const { return Interval(initialAngle(), finalAngle()); } + /** @brief Get a coordinate of the elliptical arc's center. + * @param d The dimension to retrieve + * @return The selected coordinate of the center */ + /** @brief Get the defining ellipse's rotation + * @return Angle between the +X ray of the ellipse and the +X axis */ + Angle rotationAngle() const { + return _rot_angle; } - - Point center() const + /** @brief Get one of the ellipse's rays + * @param d Dimension to retrieve + * @return The selected ray of the ellipse */ + Coord ray(Dim2 d) const { return _rays[d]; } + /** @brief Get both rays as a point + * @return Point with X equal to the X ray and Y to Y ray */ + Point rays() const { return _rays; } + /** @brief Whether the arc is larger than half an ellipse. + * @return True if the arc is larger than \f$\pi\f$, false otherwise */ + bool largeArc() const { return _large_arc; } + /** @brief Whether the arc turns clockwise + * @return True if the arc makes a clockwise turn when going from initial to final + * point, false otherwise */ + bool sweep() const { return _sweep; } + /** @brief Get the line segment connecting the arc's endpoints. + * @return A linear segment with initial and final point correspoding to those of the arc. */ + LineSegment chord() const { return LineSegment(_initial_point, _final_point); } + /** @brief Change the arc's parameters. */ + void set( Point const &ip, double rx, double ry, + double rot_angle, bool large_arc, bool sweep, + Point const &fp + ) { - return m_center; + _initial_point = ip; + _final_point = fp; + _rays[X] = rx; + _rays[Y] = ry; + _rot_angle = Angle(rot_angle); + _large_arc = large_arc; + _sweep = sweep; + _updateCenterAndAngles(isSVGCompliant()); } - - Point initialPoint() const - { - return m_initial_point; + /** @brief Change the initial and final point in one operation. + * This method exists because modifying any of the endpoints causes rather costly + * recalculations of the center and extreme angles. + * @param ip New initial point + * @param fp New final point */ + void setExtremes(Point const &ip, Point const &fp) { + _initial_point = ip; + _final_point = fp; + _updateCenterAndAngles(isSVGCompliant()); } - - Point finalPoint() const - { - return m_final_point; + /// @} + + /// @name Access computed parameters of the arc + /// @{ + Coord center(Dim2 d) const { return _center[d]; } + /** @brief Get the arc's center + * @return The arc's center, situated on the intersection of the ellipse's rays */ + Point center() const { return _center; } + /** @brief Get the extent of the arc + * @return The angle between the initial and final point, in arc's angular coordinates */ + Coord sweepAngle() const { + return extent(); } - - double start_angle() const - { - return m_start_angle; - } - - double end_angle() const - { - return m_end_angle; - } - - double ray(unsigned int i) const - { - return (i == 0) ? m_rx : m_ry; - } - - bool large_arc_flag() const - { - return m_large_arc; - } - - bool sweep_flag() const - { - return m_sweep; - } - - double rotation_angle() const - { - return m_rot_angle; - } - - void setInitial( const Point _point) - { - m_initial_point = _point; - calculate_center_and_extreme_angles(); + /// @} + + /// @name Angular evaluation + /// @{ + /** Check whether the arc contains the given angle + * @param t The angle to check + * @return True if the arc contains the angle, false otherwise */ + bool containsAngle(Coord angle) const; + /** @brief Evaluate the arc at the specified angular coordinate + * @param t Angle + * @return Point corresponding to the given angle */ + Point pointAtAngle(Coord t) const; + /** @brief Evaluate one of the arc's coordinates at the specified angle + * @param t Angle + * @param d The dimension to retrieve + * @return Selected coordinate of the arc at the specified angle */ + Coord valueAtAngle(Coord t, Dim2 d) const; + /** @brief Retrieve the unit circle transform. + * Each ellipse can be interpreted as a translated, scaled and rotate unit circle. + * This function returns the transform that maps the unit circle to the arc's ellipse. + * @return Transform from unit circle to the arc's ellipse */ + Affine unitCircleTransform() const; + /// @} + + /** @brief Check whether the arc adheres to SVG 1.1 implementation guidelines */ + virtual bool isSVGCompliant() const { return false; } + + std::pair<EllipticalArc, EllipticalArc> subdivide(Coord t) const { + EllipticalArc* arc1 = static_cast<EllipticalArc*>(portion(0, t)); + EllipticalArc* arc2 = static_cast<EllipticalArc*>(portion(t, 1)); + assert( arc1 != NULL && arc2 != NULL); + std::pair<EllipticalArc, EllipticalArc> arc_pair(*arc1, *arc2); + delete arc1; + delete arc2; + return arc_pair; } - void setFinal( const Point _point) - { - m_final_point = _point; - calculate_center_and_extreme_angles(); + // implementation of overloads goes here +#ifndef DOXYGEN_SHOULD_SKIP_THIS + virtual Point initialPoint() const { return _initial_point; } + virtual Point finalPoint() const { return _final_point; } + virtual Curve* duplicate() const { return new EllipticalArc(*this); } + virtual void setInitial(Point const &p) { + _initial_point = p; + _updateCenterAndAngles(isSVGCompliant()); } - - void setExtremes( const Point& _initial_point, const Point& _final_point ) - { - m_initial_point = _initial_point; - m_final_point = _final_point; - calculate_center_and_extreme_angles(); + virtual void setFinal(Point const &p) { + _final_point = p; + _updateCenterAndAngles(isSVGCompliant()); } - - bool isDegenerate() const - { + virtual bool isDegenerate() const { return ( are_near(ray(X), 0) || are_near(ray(Y), 0) ); } - - - virtual OptRect boundsFast() const - { + virtual Rect boundsFast() const { return boundsExact(); } - - virtual OptRect boundsExact() const; - + virtual Rect boundsExact() const; // TODO: native implementation of the following methods - virtual OptRect boundsLocal(OptInterval i, unsigned int deg) const - { + virtual OptRect boundsLocal(OptInterval const &i, unsigned int deg) const { return SBasisCurve(toSBasis()).boundsLocal(i, deg); } - - std::vector<double> roots(double v, Dim2 d) const; - - std::vector<double> - allNearestPoints( Point const& p, double from = 0, double to = 1 ) const; - - double nearestPoint( Point const& p, double from = 0, double to = 1 ) const - { - if ( are_near(ray(X), ray(Y)) && are_near(center(), p) ) - { - return from; - } - return allNearestPoints(p, from, to).front(); - } - - // TODO: native implementation of the following methods - int winding(Point p) const - { - return SBasisCurve(toSBasis()).winding(p); - } - - int degreesOfFreedom() const { return 7;} - - Curve *derivative() const; - - // TODO: native implementation of the following methods - Curve *transformed(Matrix const &m) const - { - return SBasisCurve(toSBasis()).transformed(m); - } - - std::vector<Point> pointAndDerivatives(Coord t, unsigned int n) const; - - D2<SBasis> toSBasis() const; - - bool containsAngle(Coord angle) const; - - double valueAtAngle(Coord t, Dim2 d) const; - - Point pointAtAngle(Coord t) const - { - double sin_rot_angle = std::sin(rotation_angle()); - double cos_rot_angle = std::cos(rotation_angle()); - Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle, - -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle, - center(X), center(Y) ); - Point p( std::cos(t), std::sin(t) ); - return p * m; + virtual std::vector<double> roots(double v, Dim2 d) const; +#ifdef HAVE_GSL + virtual std::vector<double> allNearestPoints( Point const& p, double from = 0, double to = 1 ) const; +#endif + virtual double nearestPoint( Point const& p, double from = 0, double to = 1 ) const { + if ( are_near(ray(X), ray(Y)) && are_near(center(), p) ) { + return from; + } + return allNearestPoints(p, from, to).front(); } - - double valueAt(Coord t, Dim2 d) const - { - Coord tt = map_to_02PI(t); - return valueAtAngle(tt, d); + virtual int degreesOfFreedom() const { return 7; } + virtual Curve *derivative() const; + virtual Curve *transformed(Affine const &m) const; + + /** + * The size of the returned vector equals n+1. + */ + virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned int n) const; + + virtual D2<SBasis> toSBasis() const; + virtual double valueAt(Coord t, Dim2 d) const { + return valueAtAngle(angleAt(t), d); } - - Point pointAt(Coord t) const - { - Coord tt = map_to_02PI(t); - return pointAtAngle(tt); + virtual Point pointAt(Coord t) const { + return pointAtAngle(angleAt(t)); } + virtual Curve* portion(double f, double t) const; + virtual Curve* reverse() const; +#endif - std::pair<EllipticalArc, EllipticalArc> - subdivide(Coord t) const - { - EllipticalArc* arc1 = static_cast<EllipticalArc*>(portion(0, t)); - EllipticalArc* arc2 = static_cast<EllipticalArc*>(portion(t, 1)); - assert( arc1 != NULL && arc2 != NULL); - std::pair<EllipticalArc, EllipticalArc> arc_pair(*arc1, *arc2); - delete arc1; - delete arc2; - return arc_pair; - } +protected: + void _updateCenterAndAngles(bool svg); - Curve* portion(double f, double t) const; - - // the arc is the same but traversed in the opposite direction - Curve* reverse() const - { - EllipticalArc* rarc = new EllipticalArc( *this ); - rarc->m_sweep = !m_sweep; - rarc->m_initial_point = m_final_point; - rarc->m_final_point = m_initial_point; - rarc->m_start_angle = m_end_angle; - rarc->m_end_angle = m_start_angle; - return rarc; - } + Point _initial_point, _final_point; + Point _rays, _center; + Angle _rot_angle; + bool _large_arc; - double sweep_angle() const - { - Coord d = end_angle() - start_angle(); - if ( !sweep_flag() ) d = -d; - if ( d < 0 ) - d += 2*M_PI; - return d; - } - - private: - Coord map_to_02PI(Coord t) const; +private: Coord map_to_01(Coord angle) const; - void calculate_center_and_extreme_angles(); - private: - Point m_initial_point, m_final_point; - double m_rx, m_ry, m_rot_angle; - bool m_large_arc, m_sweep; - double m_start_angle, m_end_angle; - Point m_center; - }; // end class EllipticalArc - } // end namespace Geom #endif // _2GEOM_ELLIPTICAL_ARC_H_ - - - /* Local Variables: mode:c++ diff --git a/src/2geom/exception.h b/src/2geom/exception.h index fd92ca5e1..12736d639 100644 --- a/src/2geom/exception.h +++ b/src/2geom/exception.h @@ -1,11 +1,17 @@ -#ifndef LIB2GEOM_EXCEPTION_HEADER -#define LIB2GEOM_EXCEPTION_HEADER - /** * \file * \brief Defines the different types of exceptions that 2geom can throw. * - * Copyright 2007 Johan Engelen <goejendaagh@zonnet.nl> + * There are two main exception classes: LogicalError and RangeError. + * Logical errors are 2geom faults/bugs; RangeErrors are 'user' faults, + * e.g. invalid arguments to lib2geom methods. + * This way, the 'user' can distinguish between groups of exceptions + * ('user' is the coder that uses lib2geom) + * + * Several macro's are defined for easily throwing exceptions + * (e.g. THROW_CONTINUITYERROR). + */ +/* Copyright 2007 Johan Engelen <goejendaagh@zonnet.nl> * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,13 +38,18 @@ * */ +#ifndef LIB2GEOM_EXCEPTION_HEADER +#define LIB2GEOM_EXCEPTION_HEADER + #include <exception> #include <sstream> #include <string> namespace Geom { -// Base exception class, all 2geom exceptions should be derived from this one. +/** + * Base exception class, all 2geom exceptions should be derived from this one. + */ class Exception : public std::exception { public: Exception(const char * message, const char *file, const int line) { @@ -58,10 +69,7 @@ protected: #define THROW_EXCEPTION(message) throw(Geom::Exception(message, __FILE__, __LINE__)) //----------------------------------------------------------------------- -// Two main exception classes: LogicalError and RangeError. -// Logical errors are 2geom faults/bugs, RangeErrors are 'user' faults. -// This way, the 'user' can distinguish between groups of exceptions -// ('user' is the coder that uses lib2geom) + class LogicalError : public Exception { public: LogicalError(const char * message, const char *file, const int line) diff --git a/src/2geom/forward.h b/src/2geom/forward.h index adc099379..399344dda 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -1,11 +1,12 @@ /** * \file * \brief Contains forward declarations of 2geom types - * + *//* * Authors: * Johan Engelen <goejendaagh@zonnet.nl> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright 2008 authors + * Copyright (C) 2008-2010 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -38,21 +39,37 @@ namespace Geom { +// basic types +typedef double Coord; +class Point; +class Interval; +class OptInterval; +class Line; +class Ray; + +// fragments +class Linear; class Bezier; -template <unsigned> class BezierCurve; -template<> class BezierCurve<0>; -typedef BezierCurve<2> QuadraticBezier; -typedef BezierCurve<1> LineSegment; -typedef BezierCurve<3> CubicBezier; -class EllipticalArc; -class SVGEllipticalArc; +class SBasis; +// curves +class Curve; +class SBasisCurve; +class BezierCurve; class HLineSegment; class VLineSegment; +template <unsigned degree> class BezierCurveN; +typedef BezierCurveN<1> LineSegment; +typedef BezierCurveN<2> QuadraticBezier; +typedef BezierCurveN<3> CubicBezier; +class EllipticalArc; +class SVGEllipticalArc; -typedef double Coord; -class Point; +// paths and path sequences +class Path; +typedef std::vector<Path> PathVector; +// errors class Exception; class LogicalError; class RangeError; @@ -61,32 +78,27 @@ class InvariantsViolation; class NotInvertible; class ContinuityError; -class Interval; -class OptInterval; -class Linear; -class Hat; -class Tri; - -class Matrix; +// transforms +class Affine; class Translate; class Rotate; class Scale; +class HShear; +class VShear; -class Curve; -class Path; -typedef std::vector<Path> PathVector; - -template <class> class D2; +// templates +template <typename> class D2; template <typename> class Piecewise; -class SBasis; -class SBasisCurve; typedef D2<Interval> Rect; class OptRect; class Shape; class Region; +class Hat; +class Tri; +// misc class SVGPathSink; template <typename> class SVGPathGenerator; diff --git a/src/2geom/hvlinesegment.h b/src/2geom/hvlinesegment.h index 6a9edbcea..9419be8f6 100644 --- a/src/2geom/hvlinesegment.h +++ b/src/2geom/hvlinesegment.h @@ -39,127 +39,37 @@ namespace Geom { -class HLineSegment : public Curve +template <Dim2 axis> +class AxisLineSegment : public LineSegment { - public: - HLineSegment() - {} - - HLineSegment(Coord _x0, Coord _x1, Coord _y) - : m_line_seg(Point(_x0, _y), Point(_x1, _y)) - { - } - - HLineSegment(Point const& _p, double _length) - : m_line_seg(_p, Point(_p[X] + _length, _p[Y])) - { - } - - HLineSegment(Point const& _p0, Point const& _p1) - : m_line_seg(_p0, _p1) - { - if ( _p0[Y] != _p1[Y] ) - { - THROW_RANGEERROR("HLineSegment::HLineSegment passed points should " - "have the same Y value"); - } - } - - Curve* duplicate() const - { - return new HLineSegment(*this); - } - - bool isDegenerate() const - { - return m_line_seg.isDegenerate(); - } - - Point initialPoint() const - { - return m_line_seg.initialPoint(); - } - - Point finalPoint() const - { - return m_line_seg.finalPoint(); - } - - Coord getY() - { - return initialPoint()[Y]; - } - - void setInitial(Point _p) - { - m_line_seg.setInitial( Point(_p[X], initialPoint()[Y]) ); - } - - void setFinal(Point _p) - { - m_line_seg.setFinal( Point(_p[X], finalPoint()[Y]) ); - } - - void setX0(Coord _x) - { - m_line_seg.setInitial( Point(_x, initialPoint()[Y]) ); - } - - void setX1(Coord _x) - { - m_line_seg.setFinal( Point(_x, finalPoint()[Y]) ); - } - - void setY(Coord _y) - { - m_line_seg.setInitial( Point(initialPoint()[X], _y) ); - m_line_seg.setFinal( Point(finalPoint()[X], _y) ); - } - - virtual OptRect boundsFast() const - { - return boundsExact(); - } - - virtual OptRect boundsExact() const - { - return Rect( initialPoint(), finalPoint() ); - } - - virtual OptRect boundsLocal(OptInterval i, unsigned deg) const - { - return m_line_seg.boundsLocal(i, deg); - } - - int winding(Point p) const - { - return m_line_seg.winding(p); - } - - int degreesOfFreedom() const { return 3;} - - std::vector<double> - roots(double v, Dim2 d) const - { - if (d < 0 || d > 1) - { - THROW_RANGEERROR("dimension argument out of range"); - } - std::vector<double> result; - if (d == X) - { - if ( v >= initialPoint()[X] && v <= finalPoint()[X] ) - { - double t = 0; +public: + static const Dim2 other_axis = static_cast<Dim2>((axis + 1) % 2); + virtual void setInitial(Point const &p) { + Point f = finalPoint(); + f[axis] = p[axis]; + LineSegment::setInitial(p); + LineSegment::setFinal(f); + } + virtual void setFinal(Point const &p) { + Point i = initialPoint(); + i[axis] = p[axis]; + LineSegment::setFinal(p); + LineSegment::setInitial(i); + } + virtual Rect boundsFast() const { return boundsExact(); } + virtual Rect boundsExact() const { Rect r(initialPoint(), finalPoint()); return r; } + virtual int degreesOfFreedom() const { return 3; } + virtual std::vector<Coord> roots(Coord v, Dim2 d) const { + std::vector<Coord> result; + if (d == axis) { + if ( v >= initialPoint()[axis] && v <= finalPoint()[axis] ) { + Coord t = 0; if (!isDegenerate()) - t = (v - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]); + t = (v - initialPoint()[axis]) / (finalPoint()[axis] - initialPoint()[axis]); result.push_back(t); } - } - else - { - if (v == initialPoint()[Y]) - { + } else { + if (v == initialPoint()[other_axis]) { if (!isDegenerate()) THROW_INFINITESOLUTIONS(0); result.push_back(0); @@ -167,270 +77,161 @@ class HLineSegment : public Curve } return result; } - - double nearestPoint( Point const& p, double from = 0, double to = 1 ) const - { + virtual Coord nearestPoint( Point const &p, Coord from = 0, Coord to = 1 ) const { if ( from > to ) std::swap(from, to); - double xfrom = pointAt(from)[X]; - double xto = pointAt(to)[X]; - if ( xfrom > xto ) - { + Coord xfrom = valueAt(from, axis); + Coord xto = valueAt(to, axis); + if ( xfrom > xto ) { std::swap(xfrom, xto); std::swap(from, to); } - if ( p[X] > xfrom && p[X] < xto ) - { - return (p[X] - initialPoint()[X]) / (finalPoint()[X] - initialPoint()[X]); + if ( p[axis] > xfrom && p[axis] < xto ) { + return (p[axis] - initialPoint()[axis]) / (finalPoint()[axis] - initialPoint()[axis]); } else if ( p[X] <= xfrom ) return from; else return to; } - - std::pair<HLineSegment, HLineSegment> subdivide(Coord t) const - { - std::pair<HLineSegment, HLineSegment> result; - Point p = pointAt(t); - result.first.setInitial(initialPoint()); - result.first.setFinal(p); - result.second.setInitial(p); - result.second.setFinal(finalPoint()); - return result; - } - - Curve* portion(double f, double t) const - { - Point ip = pointAt(f); - Point ep = pointAt(t); - return new HLineSegment(ip[X], ep[X], ip[Y]); - } - - Curve* reverse() const - { - return - new HLineSegment(finalPoint()[X], initialPoint()[X], initialPoint()[Y]); - } - - Curve* transformed(Matrix const & m) const - { - Point ip = initialPoint() * m; - Point ep = finalPoint() * m; - if (ip[Y] == ep[Y]) { - return new HLineSegment(ip[X], ep[X], ip[Y]); - } else { - return new LineSegment(ip, ep); - } - } - - Curve* derivative() const - { - double x = finalPoint()[X] - initialPoint()[X]; - return new HLineSegment(x, x, 0); - } - - Point pointAt(double t) const - { + virtual Point pointAt(Coord t) const { if ( t < 0 || t > 1 ) - THROW_RANGEERROR("domain parameter out of range"); - double x = initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]); - return Point(x, initialPoint()[Y]); + THROW_RANGEERROR("HLineSegment: Time value out of range"); + Coord x = initialPoint()[axis] + t * (finalPoint()[axis] - initialPoint()[axis]); + Point ret(x, initialPoint()[other_axis]); + return ret; } - - double valueAt(double t, Dim2 d) const - { - if (d < 0 || d > 1) - { - THROW_RANGEERROR("dimension argument out of range"); - } + virtual Coord valueAt(Coord t, Dim2 d) const { if ( t < 0 || t > 1 ) - THROW_RANGEERROR("domain parameter out of range"); - - if (d == Y) return initialPoint()[Y]; - - return initialPoint()[X] + t * (finalPoint()[X] - initialPoint()[X]); + THROW_RANGEERROR("HLineSegment: Time value out of range"); + if (d != axis) return initialPoint()[other_axis]; + return initialPoint()[axis] + t * (finalPoint()[axis] - initialPoint()[axis]); } - std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const - { + /** + * The size of the returned vector equals n+1. + */ + virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { std::vector<Point> result; result.push_back(pointAt(t)); - if (n > 0) - { - double x = finalPoint()[X] - initialPoint()[X]; + if (n > 0) { + Coord x = finalPoint()[axis] - initialPoint()[axis]; result.push_back( Point(x, 0) ); } - if (n > 1) - { + if (n > 1) { /* higher order derivatives are zero, * so the other n-1 vector elements are (0,0) */ result.insert( result.end(), n-1, Point(0, 0) ); } return result; } +protected: + AxisLineSegment(Point const &p0, Point const &p1) : LineSegment(p0, p1) {} + AxisLineSegment() {} +}; - D2<SBasis> toSBasis() const - { - return m_line_seg.toSBasis(); - } - - private: - LineSegment m_line_seg; - -}; // end class HLineSegment - - -class VLineSegment : public Curve +class HLineSegment : public AxisLineSegment<X> { - public: - VLineSegment() +public: + HLineSegment() {} + HLineSegment(Coord x0, Coord x1, Coord y) + : AxisLineSegment<X>(Point(x0, y), Point(x1, y)) {} - VLineSegment(Coord _x, Coord _y0, Coord _y1) - : m_line_seg(Point(_x, _y0), Point(_x, _y1)) - { - } - - VLineSegment(Point const& _p, double _length) - : m_line_seg(_p, Point(_p[X], _p[Y] + _length)) - { - } + HLineSegment(Point const& p, Coord len) + : AxisLineSegment<X>(p, Point(p[X] + len, p[Y])) + {} - VLineSegment(Point const& _p0, Point const& _p1) - : m_line_seg(_p0, _p1) + HLineSegment(Point const& p0, Point const& p1) + : AxisLineSegment<X>(p0, p1) { - if ( _p0[X] != _p1[X] ) - { - THROW_RANGEERROR("VLineSegment::VLineSegment passed points should " - "have the same X value"); + if ( p0[Y] != p1[Y] ) { + THROW_RANGEERROR("HLineSegment::HLineSegment passed points should " + "have the same Y value"); } } - Curve* duplicate() const - { - return new VLineSegment(*this); + Coord getY() { return initialPoint()[Y]; } + void setInitialX(Coord x) { + LineSegment::setInitial(Point(x, initialPoint()[Y])); } - - bool isDegenerate() const - { - return m_line_seg.isDegenerate(); + void setFinalX(Coord x) { + LineSegment::setFinal(Point(x, initialPoint()[Y])); } - - Point initialPoint() const - { - return m_line_seg.initialPoint(); - } - - Point finalPoint() const - { - return m_line_seg.finalPoint(); + void setY(Coord y) { + LineSegment::setInitial( Point(initialPoint()[X], y) ); + LineSegment::setFinal( Point(finalPoint()[X], y) ); } - - Coord getX() - { - return initialPoint()[X]; + std::pair<HLineSegment, HLineSegment> subdivide(Coord t) const { + std::pair<HLineSegment, HLineSegment> result; + Point p = pointAt(t); + result.first.setInitial(initialPoint()); + result.first.setFinal(p); + result.second.setInitial(p); + result.second.setFinal(finalPoint()); + return result; } - void setInitial(Point _p) - { - m_line_seg.setInitial( Point(initialPoint()[X], _p[Y]) ); + virtual Curve* duplicate() const { return new HLineSegment(*this); } + virtual Curve *portion(Coord f, Coord t) const { + Point ip = pointAt(f); + Point ep = pointAt(t); + return new HLineSegment(ip[X], ep[X], ip[Y]); } - - void setFinal(Point _p) - { - m_line_seg.setFinal( Point(finalPoint()[X], _p[Y]) ); + virtual Curve *reverse() const { + Point ip = initialPoint(); + return new HLineSegment(finalPoint()[X], ip[X], ip[Y]); } - - void setY0(Coord _y) - { - m_line_seg.setInitial( Point(initialPoint()[X], _y) ); + virtual Curve *transformed(Affine const & m) const { + Point ip = initialPoint() * m; + Point ep = finalPoint() * m; + // cannot afford to lose precision here since it can lead to discontinuous paths + if (m.isZoom(0)) { + return new HLineSegment(ip[X], ep[X], ip[Y]); + } else { + return new LineSegment(ip, ep); + } } - - void setY1(Coord _y) - { - m_line_seg.setFinal( Point(finalPoint()[Y], _y) ); + virtual Curve *derivative() const { + Coord x = finalPoint()[X] - initialPoint()[X]; + return new HLineSegment(x, x, 0); } +}; // end class HLineSegment - void setX(Coord _x) - { - m_line_seg.setInitial( Point(_x, initialPoint()[Y]) ); - m_line_seg.setFinal( Point(_x, finalPoint()[Y]) ); - } - virtual OptRect boundsFast() const - { - return boundsExact(); - } +class VLineSegment : public AxisLineSegment<Y> +{ +public: + VLineSegment() {} - virtual OptRect boundsExact() const - { - return Rect( initialPoint(), finalPoint() ); - } + VLineSegment(Coord x, Coord y0, Coord y1) + : AxisLineSegment<Y>(Point(x, y0), Point(x, y1)) + {} - virtual OptRect boundsLocal(OptInterval i, unsigned deg) const - { - return m_line_seg.boundsLocal(i, deg); - } + VLineSegment(Point const& _p, Coord _length) + : AxisLineSegment<Y>(_p, Point(_p[X], _p[Y] + _length)) + {} - int winding(Point p) const + VLineSegment(Point const& _p0, Point const& _p1) + : AxisLineSegment<Y>(_p0, _p1) { - return m_line_seg.winding(p); + if ( _p0[X] != _p1[X] ) { + THROW_RANGEERROR("VLineSegment::VLineSegment passed points should " + "have the same X value"); + } } - - int degreesOfFreedom() const { return 3;} - std::vector<double> - roots(double v, Dim2 d) const - { - if (d < 0 || d > 1) - { - THROW_RANGEERROR("dimension argument out of range"); - } - std::vector<double> result; - if (d == Y) - { - if ( v >= initialPoint()[Y] && v <= finalPoint()[Y] ) - { - double t = 0; - if (!isDegenerate()) - t = (v - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]); - result.push_back(t); - } - } - else - { - if (v == initialPoint()[X]) - { - if (!isDegenerate()) - THROW_INFINITESOLUTIONS(0); - result.push_back(0); - } - } - return result; + Coord getX() { return initialPoint()[X]; } + void setInitialY(Coord _y) { + LineSegment::setInitial( Point(initialPoint()[X], _y) ); } - - double nearestPoint( Point const& p, double from = 0, double to = 1 ) const - { - if ( from > to ) std::swap(from, to); - double yfrom = pointAt(from)[Y]; - double yto = pointAt(to)[Y]; - if (yfrom > yto) - { - std::swap(yfrom, yto); - std::swap(from, to); - } - if ( p[Y] > yfrom && p[Y] < yto ) - { - return (p[Y] - initialPoint()[Y]) / (finalPoint()[Y] - initialPoint()[Y]); - } - else if ( p[Y] <= yfrom ) - return from; - else - return to; + void setFinalY(Coord _y) { + LineSegment::setFinal( Point(finalPoint()[Y], _y) ); } - - std::pair<VLineSegment, VLineSegment> subdivide(Coord t) const - { + void setX(Coord _x) { + LineSegment::setInitial( Point(_x, initialPoint()[Y]) ); + LineSegment::setFinal( Point(_x, finalPoint()[Y]) ); + } + std::pair<VLineSegment, VLineSegment> subdivide(Coord t) const { std::pair<VLineSegment, VLineSegment> result; Point p = pointAt(t); result.first.setInitial(initialPoint()); @@ -440,88 +241,31 @@ class VLineSegment : public Curve return result; } - Curve* portion(double f, double t) const - { + virtual Curve *duplicate() const { return new VLineSegment(*this); } + virtual Curve *portion(Coord f, Coord t) const { Point ip = pointAt(f); - Point ep = pointAt(t); - return new VLineSegment(ip[X], ip[Y], ep[Y]); + Coord epy = valueAt(t, Y); + return new VLineSegment(ip[X], ip[Y], epy); } - - Curve* reverse() const - { - return - new VLineSegment(initialPoint()[X], finalPoint()[Y], initialPoint()[Y]); + virtual Curve *reverse() const { + Point ip = initialPoint(); + return new VLineSegment(ip[X], finalPoint()[Y], ip[Y]); } - - Curve* transformed(Matrix const & m) const - { + virtual Curve *transformed(Affine const & m) const { Point ip = initialPoint() * m; Point ep = finalPoint() * m; - if (ip[X] == ep[X]) { + if (m.isZoom()) { return new VLineSegment(ip[X], ip[Y], ep[Y]); } else { return new LineSegment(ip, ep); } } - - Curve* derivative() const - { - double y = finalPoint()[Y] - initialPoint()[Y]; + virtual Curve* derivative() const { + Coord y = finalPoint()[Y] - initialPoint()[Y]; return new VLineSegment(0, y, y); } - - Point pointAt(double t) const - { - if ( t < 0 || t > 1 ) - THROW_RANGEERROR("domain parameter out of range"); - double y = initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]); - return Point(initialPoint()[X], y); - } - - double valueAt(double t, Dim2 d) const - { - if (d < 0 || d > 1) - { - THROW_RANGEERROR("dimension argument out of range"); - } - if ( t < 0 || t > 1 ) - THROW_RANGEERROR("domain parameter out of range"); - - if (d == X) return initialPoint()[X]; - - return initialPoint()[Y] + t * (finalPoint()[Y] - initialPoint()[Y]); - } - - std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const - { - std::vector<Point> result; - result.push_back(pointAt(t)); - if (n > 0) - { - double y = finalPoint()[Y] - initialPoint()[Y]; - result.push_back( Point(0, y) ); - } - if (n > 1) - { - /* higher order derivatives are zero, - * so the other n-1 vector elements are (0,0) */ - result.insert( result.end(), n-1, Point(0, 0) ); - } - return result; - } - - D2<SBasis> toSBasis() const - { - return m_line_seg.toSBasis(); - } - - private: - LineSegment m_line_seg; - }; // end class VLineSegment - - } // end namespace Geom diff --git a/src/2geom/interval.h b/src/2geom/interval.h index 68a406318..a790a6c3b 100644 --- a/src/2geom/interval.h +++ b/src/2geom/interval.h @@ -1,7 +1,7 @@ /** * \file * \brief Simple closed interval class - * + *//* * Copyright 2007 Michael Sloan <mgsloan@gmail.com> * * Original Rect/Range code by: @@ -34,216 +34,295 @@ * the specific language governing rights and limitations. * */ -#ifndef SEEN_INTERVAL_H -#define SEEN_INTERVAL_H +#ifndef LIB2GEOM_SEEN_INTERVAL_H +#define LIB2GEOM_SEEN_INTERVAL_H #include <assert.h> +#include <boost/none.hpp> +#include <boost/optional.hpp> +#include <boost/operators.hpp> #include <2geom/coord.h> - -#include <boost/optional/optional.hpp> +#include <2geom/isnan.h> namespace Geom { -class Interval; +class OptInterval; /** - * \brief This class represents a range of numbers that is never empty. + * @brief Range of numbers that is never empty. + * + * Intervals are closed ranges \f$[a, b]\f$, which means they include their endpoints. + * To use them as open ranges, you can use the interiorContains() methods. * - * The endpoints are included in the range. + * @ingroup Primitives */ -class Interval { +class Interval + : boost::equality_comparable< Interval + , boost::additive< Interval + , boost::multipliable< Interval + , boost::arithmetic< Interval, Coord + , boost::orable< Interval + > > > > > +{ private: + /// @invariant _b[0] <= _b[1] Coord _b[2]; public: - /// The default constructor creates an interval [0,0] DO NOT RELY ON THIS, BEST NOT TO USE THIS CONSTRUCTOR + /// @name Create intervals. + /// @{ + /** @brief Create an interval that contains only zero. */ explicit Interval() { _b[0] = 0; _b[1] = 0; } + /** @brief Create an interval that contains a single point. */ explicit Interval(Coord u) { _b[0] = _b[1] = u; } - /* When creating an Interval using the constructor specifying the exact range, the created interval - * will be [u,v] when u<=v ; and will be [v,u] when v < u !!! - */ + /** @brief Create an interval that contains all points between @c u and @c v. */ Interval(Coord u, Coord v) { - if(u < v) { + if (u <= v) { _b[0] = u; _b[1] = v; } else { _b[0] = v; _b[1] = u; } } - - double operator[](unsigned i) const { - assert(i < 2); - return _b[i]; - } - inline double& operator[](unsigned i) { return _b[i]; } //Trust the user... - - inline Coord min() const { return _b[0]; } - inline Coord max() const { return _b[1]; } - inline Coord extent() const { return _b[1] - _b[0]; } - inline Coord middle() const { return (_b[1] + _b[0]) * 0.5; } - -// inline bool isEmpty() const { return _b[0] > _b[1]; } - inline bool isSingular() const { return _b[0] == _b[1]; } - inline bool contains(Coord val) const { return _b[0] <= val && val <= _b[1]; } - bool contains(const Interval & val) const { return _b[0] <= val._b[0] && val._b[1] <= _b[1]; } - bool intersects(const Interval & val) const { - return contains(val._b[0]) || contains(val._b[1]) || val.contains(*this); - } - - inline bool operator==(Interval other) const { return _b[0] == other._b[0] && _b[1] == other._b[1]; } - inline bool operator!=(Interval other) const { return _b[0] != other._b[0] || _b[1] != other._b[1]; } - - //IMPL: OffsetableConcept - //TODO: rename output_type to something else in the concept - typedef Coord output_type; - inline Interval operator+(Coord amnt) { - return Interval(_b[0] + amnt, _b[1] + amnt); - } - inline Interval operator-(Coord amnt) { - return Interval(_b[0] - amnt, _b[1] - amnt); + + /** @brief Create an interval containing a range of values. + * The resulting interval will contain all values from the given range. + * The return type of iterators must be convertible to Coord. The given range + * must not be empty. For potentially empty ranges, see OptInterval. + * @param start Beginning of the range + * @param end End of the range + * @return Interval that contains all values from [start, end). */ + template <typename InputIterator> + static Interval from_range(InputIterator start, InputIterator end) { + assert(start != end); + Interval result(*start++); + for (; start != end; ++start) result.expandTo(*start); + return result; } - inline Interval operator+=(Coord amnt) { - _b[0] += amnt; _b[1] += amnt; - return *this; + /** @brief Create an interval from a C-style array of values it should contain. */ + static Interval from_array(Coord const *c, unsigned n) { + Interval result = from_range(c, c+n); + return result; } - inline Interval operator-=(Coord amnt) { - _b[0] -= amnt; _b[1] -= amnt; - return *this; + /// @} + + /// @name Inspect endpoints. + /// @{ + Coord operator[](unsigned i) const { return _b[i]; } + Coord& operator[](unsigned i) { return _b[i]; } + + Coord min() const { return _b[0]; } + Coord max() const { return _b[1]; } + Coord extent() const { return _b[1] - _b[0]; } + Coord middle() const { return (_b[1] + _b[0]) * 0.5; } + bool isSingular() const { return _b[0] == _b[1]; } + bool isFinite() const { + return IS_FINITE(_b[0]) && IS_FINITE(_b[1]); } - - //IMPL: ScalableConcept - inline Interval operator-() const { return Interval(*this); } - inline Interval operator*(Coord s) const { return Interval(_b[0]*s, _b[1]*s); } - inline Interval operator/(Coord s) const { return Interval(_b[0]/s, _b[1]/s); } - Interval operator*=(Coord s) { - if(s < 0) { - Coord temp = _b[0]; - _b[0] = _b[1]*s; - _b[1] = temp*s; - } else { - _b[0] *= s; - _b[1] *= s; - } - return *this; + /// @} + + /// @name Test coordinates and other intervals for inclusion. + /// @{ + /** @brief Check whether the interval includes this number. */ + bool contains(Coord val) const { return _b[0] <= val && val <= _b[1]; } + /** @brief Check whether the interior of the interval includes this number. + * Interior means all numbers in the interval except its ends. */ + bool interiorContains(Coord val) const { return _b[0] < val && val < _b[1]; } + /** @brief Check whether the interval includes the given interval. */ + bool contains(Interval const &val) const { return _b[0] <= val._b[0] && val._b[1] <= _b[1]; } + /** @brief Check whether the interior of the interval includes the given interval. + * Interior means all numbers in the interval except its ends. */ + bool interiorContains(Interval const &val) const { return _b[0] < val._b[0] && val._b[1] < _b[1]; } + /** @brief Check whether the intervals have any common elements. */ + bool intersects(Interval const &val) const { + return contains(val._b[0]) || contains(val._b[1]) || val.contains(*this); } - Interval operator/=(Coord s) { - //TODO: what about s=0? - if(s < 0) { - Coord temp = _b[0]; - _b[0] = _b[1]/s; - _b[1] = temp/s; - } else { - _b[0] /= s; - _b[1] /= s; - } - return *this; + /** @brief Check whether the interiors of the intervals have any common elements. */ + bool interiorIntersects(Interval const &val) const { + return interiorContains(val._b[0]) || interiorContains(val._b[1]) || val.interiorContains(*this); } - + /// @} + + /// @name Modify the interval. + /// @{ //TODO: NaN handleage for the next two? - //TODO: Evaluate if wrap behaviour is proper. - //If val > max, then rather than becoming a min==max range, it 'wraps' over + /** @brief Set the lower boundary of the interval. + * When the given number is larger than the interval's largest element, + * it will be reduced to the single number @c val. */ void setMin(Coord val) { if(val > _b[1]) { - _b[0] = _b[1]; - _b[1] = val; + _b[0] = _b[1] = val; } else { _b[0] = val; } } - //If val < min, then rather than becoming a min==max range, it 'wraps' over + /** @brief Set the upper boundary of the interval. + * When the given number is smaller than the interval's smallest element, + * it will be reduced to the single number @c val. */ void setMax(Coord val) { if(val < _b[0]) { - _b[1] = _b[0]; - _b[0] = val; + _b[1] = _b[0] = val; } else { _b[1] = val; } } - - inline void extendTo(Coord val) { + /** @brief Extend the interval to include the given number. */ + void expandTo(Coord val) { if(val < _b[0]) _b[0] = val; if(val > _b[1]) _b[1] = val; //no else, as we want to handle NaN } - - static Interval fromArray(const Coord* c, int n) { - assert(n > 0); - Interval result(c[0]); - for(int i = 1; i < n; i++) result.extendTo(c[i]); - return result; - } - - /** When this would create an empty interval, the interval will be the centerpoint of the old range only. - */ - inline void expandBy(double amnt) { - _b[0] -= amnt; - _b[1] += amnt; + /** @brief Expand or shrink the interval in both directions by the given amount. + * After this method, the interval's length (extent) will be increased by + * <code>amount * 2</code>. Negative values can be given; they will shrink the interval. + * Shrinking by a value larger than half the interval's length will create a degenerate + * interval containing only the midpoint of the original. */ + void expandBy(double amount) { + _b[0] -= amount; + _b[1] += amount; if (_b[0] > _b[1]) { Coord halfway = (_b[0]+_b[1])/2; _b[0] = _b[1] = halfway; } } - - inline void unionWith(const Interval & a) { + /** @brief Union the interval with another one. + * The resulting interval will contain all points of both intervals. + * It might also contain some points which didn't belong to either - this happens + * when the intervals did not have any common elements. */ + void unionWith(const Interval & a) { if(a._b[0] < _b[0]) _b[0] = a._b[0]; if(a._b[1] > _b[1]) _b[1] = a._b[1]; } -}; - -//IMPL: AddableConcept -inline Interval operator+(const Interval & a, const Interval & b) { - return Interval(a.min() + b.min(), a.max() + b.max()); -} -inline Interval operator-(const Interval & a, const Interval & b) { - return Interval(a.min() - b.max(), a.max() - b.min()); -} -inline Interval operator+=(Interval & a, const Interval & b) { a = a + b; return a; } -inline Interval operator-=(Interval & a, const Interval & b) { a = a - b; return a; } - -//There might be impls of this based off sign checks -inline Interval operator*(const Interval & a, const Interval & b) { - Interval res(a.min() * b.min()); - res.extendTo(a.min() * b.max()); - res.extendTo(a.max() * b.min()); - res.extendTo(a.max() * b.max()); - return res; -} -inline Interval operator*=(Interval & a, const Interval & b) { a = a * b; return a; } + /// @} -/* reinstate if useful (doesn't do the proper thing for 0 inclusion) -inline Interval operator/(const Interval & a, const Interval & b) { - Interval res(a.min() / b.min()); - res.extendTo(a.min() / b.max()); - res.extendTo(a.max() / b.min()); - res.extendTo(a.max() / b.max()); - return res; -} -inline Interval operator/=(Interval & a, const Interval & b) { a = a / b; return a; } -*/ + /// @name Operators + /// @{ + inline operator OptInterval(); + bool operator==(Interval const &other) const { return _b[0] == other._b[0] && _b[1] == other._b[1]; } + + //IMPL: OffsetableConcept + //TODO: rename output_type to something else in the concept + typedef Coord output_type; + /** @brief Offset the interval by a specified amount */ + Interval &operator+=(Coord amnt) { + _b[0] += amnt; _b[1] += amnt; + return *this; + } + /** @brief Offset the interval by the negation of the specified amount */ + Interval &operator-=(Coord amnt) { + _b[0] -= amnt; _b[1] -= amnt; + return *this; + } + + // IMPL: ScalableConcept + /** @brief Return an interval mirrored about 0 */ + Interval operator-() const { return Interval(-_b[1], -_b[0]); } + /** @brief Scale an interval */ + Interval &operator*=(Coord s) { + _b[0] *= s; + _b[1] *= s; + if(s < 0) std::swap(_b[0], _b[1]); + return *this; + } + /** @brief Scale an interval by the inverse of the specified value */ + Interval &operator/=(Coord s) { + _b[0] /= s; + _b[1] /= s; + if(s < 0) std::swap(_b[0], _b[1]); + return *this; + } + // IMPL: AddableConcept + /** @brief Add two intervals. + * Sum is defined as the set of points that can be obtained by adding any two values + * from both operands: \f$S = \{x \in A, y \in B: x + y\}\f$ */ + Interval &operator+=(Interval const &o) { + _b[0] += o._b[0]; + _b[1] += o._b[1]; + return *this; + } + /** @brief Subtract two intervals. + * Difference is defined as the set of points that can be obtained by subtracting + * any value from the second operand from any value from the first operand: + * \f$S = \{x \in A, y \in B: x - y\}\f$ */ + Interval &operator-=(Interval const &o) { + // equal to *this += -o + _b[0] -= o._b[1]; + _b[1] -= o._b[0]; + return *this; + } + /** @brief Multiply two intervals. + * Product is defined as the set of points that can be obtained by multiplying + * any value from the second operand by any value from the first operand: + * \f$S = \{x \in A, y \in B: x * y\}\f$ */ + Interval &operator*=(Interval const &o) { + // TODO implement properly + Coord mn = min(), mx = max(); + expandTo(mn * o.min()); + expandTo(mn * o.max()); + expandTo(mx * o.min()); + expandTo(mx * o.max()); + return *this; + } + /** @brief Union two intervals. + * Note that intersection is only defined for OptIntervals, because the result + * of an intersection can be empty, while an Interval cannot. */ + Interval &operator|=(Interval const &o) { + unionWith(o); + return *this; + } + /// @} +}; -// 'union' conflicts with C keyword -inline Interval unify(const Interval & a, const Interval & b) { - return Interval(std::min(a.min(), b.min()), - std::max(a.max(), b.max())); +/** @brief Union two intervals + * @relates Interval */ +inline Interval unify(Interval const &a, Interval const &b) { + return a | b; } /** - * \brief OptInterval is an Interval that can be empty. + * @brief A range of numbers that can be empty. + * @ingroup Primitives */ -class OptInterval : public boost::optional<Interval> { +class OptInterval + : public boost::optional<Interval> + , boost::orable< OptInterval + , boost::andable< OptInterval + > > +{ public: + /// @name Create optionally empty intervals. + /// @{ + /** @brief Create an empty interval. */ OptInterval() : boost::optional<Interval>() {}; + /** @brief Wrap an existing interval. */ OptInterval(Interval const &a) : boost::optional<Interval>(a) {}; + /** @brief Create an interval containing a single point. */ OptInterval(Coord u) : boost::optional<Interval>(Interval(u)) {}; + /** @brief Create an interval containing a range of numbers. */ OptInterval(Coord u, Coord v) : boost::optional<Interval>(Interval(u,v)) {}; - /** - * Check whether this OptInterval is empty or not. - */ - inline bool isEmpty() { return (*this == false); }; - - /** - * If \c this is empty, copy argument \c a. Otherwise, union with it (and do nothing when \c a is empty) - */ - inline void unionWith(const OptInterval & a) { + /** @brief Create a possibly empty interval containing a range of values. + * The resulting interval will contain all values from the given range. + * The return type of iterators must be convertible to double. The given range + * may be empty. + * @param start Beginning of the range + * @param end End of the range + * @return Interval that contains all values from [start, end), or nothing if the range + * is empty. */ + template <typename InputIterator> + static OptInterval from_range(InputIterator start, InputIterator end) { + if (start == end) { + OptInterval ret; + return ret; + } + OptInterval ret(Interval::from_range(start, end)); + return ret; + } + /// @} + + /** @brief Check whether this OptInterval is empty. */ + bool isEmpty() { return !*this; }; + + /** @brief Union with another interval, gracefully handling empty ones. */ + inline void unionWith(OptInterval const &a) { if (a) { if (*this) { // check that we are not empty (*this)->unionWith(*a); @@ -252,14 +331,41 @@ public: } } } + inline void intersectWith(OptInterval const &o) { + if (o && *this) { + Coord u, v; + u = std::max((*this)->min(), o->min()); + v = std::min((*this)->max(), o->max()); + if (u <= v) { + *this = Interval(u, v); + return; + } + } + (*static_cast<boost::optional<Interval>*>(this)) = boost::none; + } + OptInterval &operator|=(OptInterval const &o) { + unionWith(o); + return *this; + } + OptInterval &operator&=(OptInterval const &o) { + intersectWith(o); + return *this; + } }; -inline OptInterval intersect(const Interval & a, const Interval & b) { - Coord u = std::max(a.min(), b.min()), - v = std::min(a.max(), b.max()); - //technically >= might be incorrect, but singulars suck - return u > v ? OptInterval() - : OptInterval(Interval(u, v)); +/** @brief Intersect two intervals and return a possibly empty range of numbers + * @relates OptInterval */ +inline OptInterval intersect(Interval const &a, Interval const &b) { + return OptInterval(a) & OptInterval(b); +} +/** @brief Intersect two intervals and return a possibly empty range of numbers + * @relates OptInterval */ +inline OptInterval operator&(Interval const &a, Interval const &b) { + return OptInterval(a) & OptInterval(b); +} + +inline Interval::operator OptInterval() { + return OptInterval(*this); } #ifdef _GLIBCXX_IOSTREAM diff --git a/src/2geom/line.cpp b/src/2geom/line.cpp index a91ff03a3..5ef8dfddc 100644 --- a/src/2geom/line.cpp +++ b/src/2geom/line.cpp @@ -37,6 +37,90 @@ namespace Geom { +/** + * @class Line + * @brief Infinite line on a plane. + * + * Every line in 2Geom has a special point on it, called the origin. The direction of the line + * is stored as a unit vector (versor). This way a line can be interpreted as a function + * \f$ f: (-\infty, \infty) \to \mathbb{R}^2\f$. Zero corresponds to the origin point, + * positive values to the points in the direction of the unit vector, and negative values + * to points in the opposite direction. + * + * @ingroup Primitives + */ + +/** @brief Set the line by solving the line equation. + * A line is a set of points that satisfies the line equation + * \f$Ax + By + C = 0\f$. This function changes the line so that its points + * satisfy the line equation with the given coefficients. */ +void Line::setCoefficients (double a, double b, double c) { + if (a == 0 && b == 0) { + if (c != 0) { + THROW_LOGICALERROR("the passed coefficients gives the empty set"); + } + m_versor = Point(0,0); + m_origin = Point(0,0); + } else { + double l = hypot(a,b); + a /= l; + b /= l; + c /= l; + Point N(a, b); + m_versor = N.ccw(); + m_origin = -c * N; + } +} + +/** @brief Get the line equation coefficients of this line. + * @return Vector with three values corresponding to the A, B and C + * coefficients of the line equation for this line. */ +std::vector<double> Line::coefficients() const { + std::vector<double> coeff; + coeff.reserve(3); + Point N = versor().cw(); + coeff.push_back (N[X]); + coeff.push_back (N[Y]); + double d = - dot (N, origin()); + coeff.push_back (d); + return coeff; +} + +/** @brief Find intersection with an axis-aligned line. + * @param v Coordinate of the axis-aligned line + * @param d Which axis the coordinate is on. X means a vertical line, Y means a horizontal line. + * @return Time values at which this line intersects the query line. */ +std::vector<Coord> Line::roots(Coord v, Dim2 d) const { + if (d < 0 || d > 1) + THROW_RANGEERROR("Line::roots, dimension argument out of range"); + std::vector<Coord> result; + if ( m_versor[d] != 0 ) + { + result.push_back( (v - m_origin[d]) / m_versor[d] ); + } + // TODO: else ? + return result; +} + +/** @brief Get a time value corresponding to a point. + * @param p Point on the line. If the point is not on the line, + * the returned value will be meaningless. + * @return Time value t such that \f$f(t) = p\f$. + * @see timeAtProjection */ +Coord Line::timeAt(Point const& _point) const { + Coord t; + if ( m_versor[X] != 0 ) { + t = (_point[X] - m_origin[X]) / m_versor[X]; + } + else if ( m_versor[Y] != 0 ) { + t = (_point[Y] - m_origin[Y]) / m_versor[Y]; + } + else { // degenerate case + t = 0; + } + return t; +} + namespace detail { @@ -55,18 +139,18 @@ OptCrossing intersection_impl(Point const& V1, Point const O1, Crossing c; c.ta = detBV2 * inv_detV1V2; c.tb = detV1B * inv_detV1V2; -// std::cerr << "ta = " << solution.ta << std::endl; -// std::cerr << "tb = " << solution.tb << std::endl; +// std::cerr << "ta = " << c.ta << std::endl; +// std::cerr << "tb = " << c.tb << std::endl; return OptCrossing(c); } OptCrossing intersection_impl(Ray const& r1, Line const& l2, unsigned int i) { - OptCrossing crossing = + OptCrossing crossing = intersection_impl(r1.versor(), r1.origin(), l2.versor(), l2.origin() ); - + if (crossing) { if (crossing->ta < 0) @@ -97,7 +181,7 @@ OptCrossing intersection_impl( LineSegment const& ls1, Line const& l2, unsigned int i ) { - OptCrossing crossing = + OptCrossing crossing = intersection_impl(ls1.finalPoint() - ls1.initialPoint(), ls1.initialPoint(), l2.versor(), @@ -135,7 +219,7 @@ OptCrossing intersection_impl( LineSegment const& ls1, unsigned int i ) { Point direction = ls1.finalPoint() - ls1.initialPoint(); - OptCrossing crossing = + OptCrossing crossing = intersection_impl( direction, ls1.initialPoint(), r2.versor(), @@ -143,9 +227,9 @@ OptCrossing intersection_impl( LineSegment const& ls1, if (crossing) { - if ( crossing->getTime(0) < 0 - || crossing->getTime(0) > 1 - || crossing->getTime(1) < 0 ) + if ( (crossing->getTime(0) < 0) + || (crossing->getTime(0) > 1) + || (crossing->getTime(1) < 0) ) { return OptCrossing(); } @@ -203,7 +287,7 @@ OptCrossing intersection_impl( LineSegment const& ls1, OptCrossing intersection(Line const& l1, Line const& l2) { - OptCrossing crossing = + OptCrossing crossing = detail::intersection_impl( l1.versor(), l1.origin(), l2.versor(), l2.origin() ); if (crossing) @@ -223,7 +307,7 @@ OptCrossing intersection(Line const& l1, Line const& l2) OptCrossing intersection(Ray const& r1, Ray const& r2) { - OptCrossing crossing = + OptCrossing crossing = detail::intersection_impl( r1.versor(), r1.origin(), r2.versor(), r2.origin() ); @@ -333,6 +417,62 @@ OptCrossing intersection( LineSegment const& ls1, LineSegment const& ls2 ) } +boost::optional<LineSegment> clip (Line const& l, Rect const& r) +{ + typedef boost::optional<LineSegment> opt_linesegment; + LineSegment result; + //size_t index = 0; + std::vector<Point> points; + LineSegment ls (r.corner(0), r.corner(1)); + try + { + OptCrossing oc = intersection (ls, l); + if (oc) + { + points.push_back (l.pointAt (oc->tb)); + } + } + catch (InfiniteSolutions e) + { + return opt_linesegment(ls); + } + + for (size_t i = 2; i < 5; ++i) + { + ls.setInitial (ls[1]); + ls.setFinal (r.corner(i)); + try + { + OptCrossing oc = intersection (ls, l); + if (oc) + { + points.push_back (l.pointAt (oc->tb)); + if (points.size() > 1) + { + size_t sz = points.size(); + if (!are_near (points[sz - 2], points[sz - 1], 1e-10)) + { + result.setInitial (points[sz - 2]); + result.setFinal (points[sz - 1]); + return opt_linesegment(result); + } + } + } + } + catch (InfiniteSolutions e) + { + return opt_linesegment(ls); + } + } + if (points.size() != 0) + { + result.setInitial (points[0]); + result.setFinal (points[0]); + return opt_linesegment(result); + } + return opt_linesegment(); +} + Line make_angle_bisector_line(Line const& l1, Line const& l2) { @@ -359,6 +499,8 @@ Line make_angle_bisector_line(Line const& l1, Line const& l2) } + + } // end namespace Geom diff --git a/src/2geom/line.h b/src/2geom/line.h index a7e6a54bb..ccb0ae6c5 100644 --- a/src/2geom/line.h +++ b/src/2geom/line.h @@ -35,265 +35,278 @@ #include <cmath> #include <2geom/bezier-curve.h> // for LineSegment +#include <2geom/rect.h> #include <2geom/crossing.h> #include <2geom/exception.h> #include <2geom/ray.h> +#include <boost/optional.hpp> + namespace Geom { -class Line -{ - public: - Line() - : m_origin(0,0), m_versor(1,0) - { - } - - Line(Point const& _origin, Coord angle ) - : m_origin(_origin), m_versor(std::cos(angle), std::sin(angle)) - { - } - - Line(Point const& A, Point const& B) - { - setBy2Points(A, B); - } - - explicit - Line(LineSegment const& _segment) - { - setBy2Points(_segment.initialPoint(), _segment.finalPoint()); - } - - explicit - Line(Ray const& _ray) - : m_origin(_ray.origin()), m_versor(_ray.versor()) - { - } - - static Line fromNormalDistance(Point n, double c) { - Point P = n*c/(dot(n,n)); - - return Line(P, P+rot90(n)); +class Line { +private: + Point m_origin; + Point m_versor; +public: + /// @name Creating lines. + /// @{ + /** @brief Create a default horizontal line. */ + Line() + : m_origin(0,0), m_versor(1,0) + {} + /** @brief Create a line with the specified inclination. + * @param _origin One of the points on the line + * @param angle Angle of the line in mathematical convention */ + Line(Point const& _origin, Coord angle ) + : m_origin(_origin) + { + sincos(angle, m_versor[Y], m_versor[X]); + } + + /** @brief Create a line going through two points. + * @param A First point + * @param B Second point */ + Line(Point const& A, Point const& B) { + setPoints(A, B); } - static Line fromPointDirection(Point o, Point v) { + + /** @brief Create a line based on the coefficients of its equation. + @see Line::setCoefficients() */ + Line(double a, double b, double c) { + setCoefficients(a, b, c); + } + + /** @brief Create a line by extending a line segment. */ + explicit Line(LineSegment const& _segment) { + setPoints(_segment.initialPoint(), _segment.finalPoint()); + } + + /** @brief Create a line by extending a ray. */ + explicit Line(Ray const& _ray) + : m_origin(_ray.origin()), m_versor(_ray.versor()) + {} + + // huh? + static Line from_normal_distance(Point n, double c) { + Point P = n * c / dot(n,n); + Line l(P, P+rot90(n)); + return l; + } + /** @brief Create a line from origin and unit vector. + * Note that each line direction has two possible unit vectors. + * @param o Point through which the line will pass + * @param v Unit vector of the line's direction */ + static Line from_origin_and_versor(Point o, Point v) { Line l; l.m_origin = o; l.m_versor = v; return l; } - Line* duplicate() const - { - return new Line(*this); - } - - Point origin() const - { - return m_origin; - } - - Point versor() const - { - return m_versor; - } - - void origin(Point const& _point) - { - m_origin = _point; - } - - void versor(Point const& _versor) - { - m_versor = _versor; - } - - // return the angle described by rotating the X-axis in cw direction - // until it overlaps the line - // the returned value is in the interval [0, PI[ - Coord angle() const - { - double a = std::atan2(m_versor[Y], m_versor[X]); - if (a < 0) a += M_PI; - if (a == M_PI) a = 0; - return a; - } - - void angle(Coord _angle) - { - m_versor[X] = std::cos(_angle); - m_versor[Y] = std::sin(_angle); - } - - void setBy2Points(Point const& A, Point const& B) - { - m_origin = A; - m_versor = B - A; - if ( are_near(m_versor, Point(0,0)) ) - m_versor = Point(0,0); - else - m_versor.normalize(); - } - - bool isDegenerate() const - { - return ( m_versor[X] == 0 && m_versor[Y] == 0 ); - } - - Point pointAt(Coord t) const - { - return m_origin + m_versor * t; - } - - Coord valueAt(Coord t, Dim2 d) const - { - if (d < 0 || d > 1) - THROW_RANGEERROR("Ray::valueAt, dimension argument out of range"); - return m_origin[d] + m_versor[d] * t; - } - - std::vector<Coord> roots(Coord v, Dim2 d) const - { - if (d < 0 || d > 1) - THROW_RANGEERROR("Ray::roots, dimension argument out of range"); - std::vector<Coord> result; - if ( m_versor[d] != 0 ) - { - result.push_back( (v - m_origin[d]) / m_versor[d] ); - } - // TODO: else ? - return result; - } - - // require are_near(_point, *this) - // on the contrary the result value is meaningless - Coord timeAt(Point const& _point) const - { - Coord t; - if ( m_versor[X] != 0 ) - { - t = (_point[X] - m_origin[X]) / m_versor[X]; - } - else if ( m_versor[Y] != 0 ) - { - t = (_point[Y] - m_origin[Y]) / m_versor[Y]; - } - else // degenerate case - { - t = 0; - } - return t; - } - - Coord timeAtProjection(Point const& _point) const - { - if ( isDegenerate() ) return 0; - return dot( _point - m_origin, m_versor ); - } - - Coord nearestPoint(Point const& _point) const - { - return timeAtProjection(_point); - } - - Line reverse() const - { - Line result; - result.origin(m_origin); - result.versor(-m_versor); - return result; - } - - Curve* portion(Coord f, Coord t) const - { - LineSegment* seg = new LineSegment(pointAt(f), pointAt(t)); - return seg; - } - - LineSegment segment(Coord f, Coord t) const - { - return LineSegment(pointAt(f), pointAt(t)); - } - - Ray ray(Coord t) - { - Ray result; - result.origin(pointAt(t)); - result.versor(m_versor); - return result; - } - - Line derivative() const - { - Line result; - result.origin(m_versor); - result.versor(Point(0,0)); - return result; - } - - Line transformed(Matrix const& m) const - { - return Line(m_origin * m, (m_origin + m_versor) * m); - } - - static Line from_normal_and_dist(Point const &n, double d) { - return Line(n*d, n*d + rot90(n)); + Line* duplicate() const { + return new Line(*this); + } + /// @} + + /// @name Retrieve and set the line's parameters. + /// @{ + /** @brief Get the line's origin point. */ + Point origin() const { return m_origin; } + /** @brief Get the line's direction unit vector. */ + Point versor() const { return m_versor; } + // return the angle described by rotating the X-axis in cw direction + // until it overlaps the line + // the returned value is in the interval [0, PI[ + Coord angle() const { + double a = std::atan2(m_versor[Y], m_versor[X]); + if (a < 0) a += M_PI; + if (a == M_PI) a = 0; + return a; } - private: - Point m_origin; - Point m_versor; + void setOrigin(Point const& _point) { + m_origin = _point; + } + void setVersor(Point const& _versor) { + m_versor = _versor; + } + + void setAngle(Coord _angle) { + sincos(_angle, m_versor[Y], m_versor[X]); + } + + /** @brief Set a line based on two points it should pass through. */ + void setPoints(Point const& A, Point const& B) { + m_origin = A; + if ( are_near(A, B) ) + m_versor = Point(0,0); + else + m_versor = B - A; + m_versor.normalize(); + } + void setCoefficients (double a, double b, double c); + std::vector<double> coefficients() const; + + /** @brief Check if the line has any points. + * A degenerate line can be created if the line is created from a line equation + * that has no solutions. + * @return True if the line has no points */ + bool isDegenerate() const { + return ( m_versor[X] == 0 && m_versor[Y] == 0 ); + } + /// @} + + /// @name Evaluate the line as a function. + ///@{ + Point pointAt(Coord t) const { + return m_origin + m_versor * t; + } + + Coord valueAt(Coord t, Dim2 d) const { + if (d < 0 || d > 1) + THROW_RANGEERROR("Line::valueAt, dimension argument out of range"); + return m_origin[d] + m_versor[d] * t; + } + + Coord timeAt(Point const &p) const; + + /** @brief Get a time value corresponding to a projection of a point on the line. + * @param p Arbitrary point. + * @return Time value corresponding to a point closest to @c p. */ + Coord timeAtProjection(Point const& p) const { + if ( isDegenerate() ) return 0; + return dot( p - m_origin, m_versor ); + } + + /** @brief Find a point on the line closest to the query point. + * This is an alias for timeAtProjection(). */ + Coord nearestPoint(Point const& _point) const { + return timeAtProjection(_point); + } + + std::vector<Coord> roots(Coord v, Dim2 d) const; + /// @} + + /// @name Create other objects based on this line. + /// @{ + /** @brief Create a line containing the same points, but with negated time values. + * @return Line \f$g\f$ such that \f$g(t) = f(-t)\f$ */ + Line reverse() const + { + Line result; + result.setOrigin(m_origin); + result.setVersor(-m_versor); + return result; + } + + /** @brief Same as segment(), but allocate the line segment dynamically. */ + // TODO remove this? + Curve* portion(Coord f, Coord t) const { + LineSegment* seg = new LineSegment(pointAt(f), pointAt(t)); + return seg; + } + + /** @brief Create a segment of this line. + * @param f Time value for the initial point of the segment + * @param t Time value for the final point of the segment + * @return Created line segment */ + LineSegment segment(Coord f, Coord t) const { + return LineSegment(pointAt(f), pointAt(t)); + } + + /** @brief Create a ray starting at the specified time value. + * The created ray will go in the direction of the line's versor (in the direction + * of increasing time values). + * @param t Time value where the ray should start + * @return Ray starting at t and going in the direction of the versor */ + Ray ray(Coord t) { + Ray result; + result.origin(pointAt(t)); + result.versor(m_versor); + return result; + } + + /** @brief Create a derivative of the line. + * The new line will always be degenerate. Its origin will be equal to this + * line's versor. */ + Line derivative() const { + Line result; + result.setOrigin(m_versor); + result.setVersor(Point(0,0)); + return result; + } + + /** @brief Create a line transformed by an affine transformation. */ + Line transformed(Affine const& m) const { + return Line(m_origin * m, (m_origin + m_versor) * m); + } + + /** @brief Get a vector normal to the line. + * If Y grows upwards, then this is the left normal. If Y grows downwards, + * then this is the right normal. */ + Point normal() const { + return rot90(m_versor); + } + + // what does this do? + Point normalAndDist(double & dist) const { + Point n = normal(); + dist = -dot(n, m_origin); + return n; + } + /// @} }; // end class Line inline double distance(Point const& _point, Line const& _line) { - if ( _line.isDegenerate() ) - { - return distance( _point, _line.origin() ); - } - else - { - return fabs( dot(_point - _line.origin(), _line.versor().ccw()) ); - } + if ( _line.isDegenerate() ) + { + return ::Geom::distance( _point, _line.origin() ); + } + else + { + return fabs( dot(_point - _line.origin(), _line.versor().ccw()) ); + } } inline bool are_near(Point const& _point, Line const& _line, double eps = EPSILON) { - return are_near(distance(_point, _line), 0, eps); + return are_near(distance(_point, _line), 0, eps); } inline bool are_parallel(Line const& l1, Line const& l2, double eps = EPSILON) { - return ( are_near(l1.versor(), l2.versor(), eps) - || are_near(l1.versor(), -l2.versor(), eps) ); + return ( are_near(l1.versor(), l2.versor(), eps) + || are_near(l1.versor(), -l2.versor(), eps) ); } inline bool are_same(Line const& l1, Line const& l2, double eps = EPSILON) { - return are_parallel(l1, l2, eps) && are_near(l1.origin(), l2, eps); + return are_parallel(l1, l2, eps) && are_near(l1.origin(), l2, eps); } inline bool are_orthogonal(Line const& l1, Line const& l2, double eps = EPSILON) { - return ( are_near(l1.versor(), l2.versor().cw(), eps) - || are_near(l1.versor(), l2.versor().ccw(), eps) ); + return ( are_near(l1.versor(), l2.versor().cw(), eps) + || are_near(l1.versor(), l2.versor().ccw(), eps) ); } inline bool are_collinear(Point const& p1, Point const& p2, Point const& p3, - double eps = EPSILON) + double eps = EPSILON) { - return are_near( cross(p3, p2) - cross(p3, p1) + cross(p2, p1), 0, eps); + return are_near( cross(p3, p2) - cross(p3, p1) + cross(p2, p1), 0, eps); } // evaluate the angle between l1 and l2 rotating l1 in cw direction @@ -302,10 +315,10 @@ bool are_collinear(Point const& p1, Point const& p2, Point const& p3, inline double angle_between(Line const& l1, Line const& l2) { - double angle = angle_between(l1.versor(), l2.versor()); - if (angle < 0) angle += M_PI; - if (angle == M_PI) angle = 0; - return angle; + double angle = angle_between(l1.versor(), l2.versor()); + if (angle < 0) angle += M_PI; + if (angle == M_PI) angle = 0; + return angle; } inline @@ -317,60 +330,60 @@ double distance(Point const& _point, LineSegment const& _segment) inline bool are_near(Point const& _point, LineSegment const& _segment, - double eps = EPSILON) + double eps = EPSILON) { - return are_near(distance(_point, _segment), 0, eps); + return are_near(distance(_point, _segment), 0, eps); } // build a line passing by _point and orthogonal to _line inline Line make_orthogonal_line(Point const& _point, Line const& _line) { - Line l; - l.origin(_point); - l.versor(_line.versor().cw()); - return l; + Line l; + l.setOrigin(_point); + l.setVersor(_line.versor().cw()); + return l; } // build a line passing by _point and parallel to _line inline Line make_parallel_line(Point const& _point, Line const& _line) { - Line l(_line); - l.origin(_point); - return l; + Line l(_line); + l.setOrigin(_point); + return l; } // build a line passing by the middle point of _segment and orthogonal to it. inline Line make_bisector_line(LineSegment const& _segment) { - return make_orthogonal_line( middle_point(_segment), Line(_segment) ); + return make_orthogonal_line( middle_point(_segment), Line(_segment) ); } // build the bisector line of the angle between ray(O,A) and ray(O,B) inline Line make_angle_bisector_line(Point const& A, Point const& O, Point const& B) { - Point M = middle_point(A,B); - return Line(O,M); + Point M = middle_point(A,B); + return Line(O,M); } // prj(P) = rot(v, Point( rot(-v, P-O)[X], 0 )) + O inline Point projection(Point const& _point, Line const& _line) { - return _line.pointAt( _line.nearestPoint(_point) ); + return _line.pointAt( _line.nearestPoint(_point) ); } inline LineSegment projection(LineSegment const& _segment, Line const& _line) { - return _line.segment( _line.nearestPoint(_segment.initialPoint()), - _line.nearestPoint(_segment.finalPoint()) ); + return _line.segment( _line.nearestPoint(_segment.initialPoint()), + _line.nearestPoint(_segment.finalPoint()) ); } - +boost::optional<LineSegment> clip (Line const& l, Rect const& r); namespace detail diff --git a/src/2geom/math-utils.h b/src/2geom/math-utils.h new file mode 100644 index 000000000..2c348f54b --- /dev/null +++ b/src/2geom/math-utils.h @@ -0,0 +1,108 @@ +#ifndef LIB2GEOM_MATH_UTILS_HEADER +#define LIB2GEOM_MATH_UTILS_HEADER + +/** + * \file + * \brief Low level math functions and compatibility wrappers + *//* + * Authors: + * Johan Engelen <goejendaagh@zonnet.nl> + * Michael G. Sloan <mgsloan@gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * Copyright 2006-2009 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#include "config.h" +#include <math.h> // sincos is usually only available in math.h +#include <cmath> +#include <utility> // for std::pair + +namespace Geom { + +/** @brief Sign function - indicates the sign of a numeric type. + * Mathsy people will know this is basically the derivative of abs, except for the fact + * that it is defined on 0. + * @return -1 when x is negative, 1 when positive, and 0 if equal to 0. */ +template <class T> inline int sgn(const T& x) { + return (x < 0 ? -1 : (x > 0 ? 1 : 0) ); +} + +template <class T> inline T sqr(const T& x) {return x * x;} +template <class T> inline T cube(const T& x) {return x * x * x;} + +/** Between function - returns true if a number x is within a range: (min < x) && (max > x). + * The values delimiting the range and the number must have the same type. + */ +template <class T> inline const T& between (const T& min, const T& max, const T& x) + { return (min < x) && (max > x); } + +/** @brief Returns @a x rounded to the nearest multiple of \f$10^{p}\f$. + + Implemented in terms of round, i.e. we make no guarantees as to what happens if x is + half way between two rounded numbers. + + Note: places is the number of decimal places without using scientific (e) notation, not the + number of significant figures. This function may not be suitable for values of x whose + magnitude is so far from 1 that one would want to use scientific (e) notation. + + places may be negative: e.g. places = -2 means rounding to a multiple of .01 +**/ +inline double decimal_round(double x, int p) { + //TODO: possibly implement with modulus instead? + double const multiplier = ::pow(10.0, p); + return ::round( x * multiplier ) / multiplier; +} + +/** @brief Simultaneously compute a sine and a cosine of the same angle. + * This function can be up to 2 times faster than separate computation, depending + * on the platform. It uses the standard library function sincos() if available. + * @param angle Angle + * @param sin_ Variable that will store the sine + * @param cos_ Variable that will store the cosine */ +inline void sincos(double angle, double &sin_, double &cos_) { +#ifdef HAVE_SINCOS + ::sincos(angle, &sin_, &cos_); +#else + sin_ = ::sin(angle); + cos_ = ::cos(angle); +#endif +} + +} + +#endif + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/matrix.cpp b/src/2geom/matrix.cpp deleted file mode 100644 index e130d2027..000000000 --- a/src/2geom/matrix.cpp +++ /dev/null @@ -1,258 +0,0 @@ -#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 <2geom/utils.h> -#include <2geom/matrix.h> -#include <2geom/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, eps) && are_near(_c[1], 0.0, eps) && - are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) && - are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); -} - -/** 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, eps) && are_near(_c[1], 0.0, eps) && - are_near(_c[2], 0.0, eps) && are_near(_c[3], 1.0, eps) && - (!are_near(_c[4], 0.0, eps) || !are_near(_c[5], 0.0, eps)); -} - -/** 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, eps) || !are_near(_c[3], 1.0, eps)) && //NOTE: these are the diags, and the next line opposite diags - are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) && - are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); -} - -/** 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, eps) && are_near(_c[0], _c[3], eps) && - are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) && - are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps); -} - -/** 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], eps) && are_near(_c[1], -_c[2], eps) && - are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps) && - are_near(_c[0]*_c[0] + _c[1]*_c[1], 1.0, eps); -} - -bool Matrix::onlyScaleAndTranslation(Coord const eps) const { - return are_near(_c[0], _c[3], eps) && are_near(_c[1], 0, eps) && are_near(_c[2], 0, eps); -} - -bool Matrix::isSingular(Coord const eps) const { - return are_near(det(), 0.0, eps); -} - -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(); - // the numerical precision of the determinant must be significant - if (fabs(determ) > 1e-18) { - 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/matrix.h b/src/2geom/matrix.h deleted file mode 100644 index 6a378dbf1..000000000 --- a/src/2geom/matrix.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef __Geom_MATRIX_H__ -#define __Geom_MATRIX_H__ - -/** \file - * \brief Definition of Geom::Matrix types. - * - * Main authors: - * Lauris Kaplinski <lauris@kaplinski.com>: - * Original NRMatrix definition and related macros. - * - * Nathan Hurst <njh@mail.csse.monash.edu.au>: - * Geom::Matrix class version of the above. - * - * Michael G. Sloan <mgsloan@gmail.com>: - * Reorganization and additions. - * - * This code is in public domain. - */ - -//#include <glib/gmessages.h> - -#include <2geom/point.h> - -namespace Geom { - -/** - * The Matrix class. - * - * For purposes of multiplication, points should be thought of as row vectors - * - * \f$(p_X p_Y 1)\f$ - * - * to be right-multiplied by transformation matrices of the form - * \f[ - \left[ - \begin{array}{ccc} - c_0&c_1&0 \\ - c_2&c_3&0 \\ - c_4&c_5&1 - \end{array} - \right] - \f] - * (so the columns of the matrix correspond to the columns (elements) of the result, - * and the rows of the matrix correspond to columns (elements) of the "input"). - */ -class Matrix { - private: - Coord _c[6]; - public: - Matrix() {} - - Matrix(Matrix const &m) { - for(int i = 0; i < 6; i++) { - _c[i] = m[i]; - } - } - - Matrix(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5) { - _c[0] = c0; _c[1] = c1; - _c[2] = c2; _c[3] = c3; - _c[4] = c4; _c[5] = c5; - } - - Matrix &operator=(Matrix const &m) { - for(int i = 0; i < 6; i++) - _c[i] = m._c[i]; - return *this; - } - - inline Coord operator[](unsigned const i) const { return _c[i]; } - inline Coord &operator[](unsigned const i) { return _c[i]; } - - - Point xAxis() const; - Point yAxis() const; - void setXAxis(Point const &vec); - void setYAxis(Point const &vec); - - Point translation() const; - void setTranslation(Point const &loc); - - double expansionX() const; - double expansionY() const; - inline Point expansion() const { return Point(expansionX(), expansionY()); } - void setExpansionX(double val); - void setExpansionY(double val); - - void setIdentity(); - - bool isIdentity(Coord eps = EPSILON) const; - bool isTranslation(Coord eps = EPSILON) const; - bool isRotation(double eps = EPSILON) const; - bool isScale(double eps = EPSILON) const; - bool isUniformScale(double eps = EPSILON) const; - bool onlyScaleAndTranslation(double eps = EPSILON) const; - bool isSingular(double eps = EPSILON) const; - - bool flips() const; - - Matrix without_translation() const; - - Matrix inverse() const; - - Coord det() const; - Coord descrim2() const; - Coord descrim() const; -}; - -Matrix operator*(Matrix const &a, Matrix const &b); -inline Matrix &operator*=(Matrix &a, Matrix const &b) { a = a * b; return a; } - -/** A function to print out the Matrix (for debugging) */ -inline std::ostream &operator<< (std::ostream &out_file, const Geom::Matrix &m) { - out_file << "A: " << m[0] << " C: " << m[2] << " E: " << m[4] << "\n"; - out_file << "B: " << m[1] << " D: " << m[3] << " F: " << m[5] << "\n"; - return out_file; -} - -/** Given a matrix m such that unit_circle = m*x, this returns the - * quadratic form x*A*x = 1. */ -Matrix elliptic_quadratic_form(Matrix const &m); - -/** Given a matrix (ignoring the translation) this returns the eigen - * values and vectors. */ -class Eigen{ -public: - Point vectors[2]; - double values[2]; - Eigen(Matrix const &m); -}; - -// Matrix factories -Matrix from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0)); - -/** Returns the Identity Matrix. */ -inline Matrix identity() { - return Matrix(1.0, 0.0, - 0.0, 1.0, - 0.0, 0.0); -} - -inline bool operator==(Matrix const &a, Matrix const &b) { - for(unsigned i = 0; i < 6; ++i) { - if ( a[i] != b[i] ) return false; - } - return true; -} -inline bool operator!=(Matrix const &a, Matrix const &b) { return !( a == b ); } - - - -} /* namespace Geom */ - -#endif /* !__Geom_MATRIX_H__ */ - -/* - 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/numeric/fitting-model.h b/src/2geom/numeric/fitting-model.h index dcf0e8e1d..a44c1ddac 100644 --- a/src/2geom/numeric/fitting-model.h +++ b/src/2geom/numeric/fitting-model.h @@ -43,6 +43,7 @@ #include <2geom/ellipse.h> #include <2geom/circle.h> #include <2geom/utils.h> +#include <2geom/conicsec.h> namespace Geom { namespace NL { @@ -83,6 +84,10 @@ namespace Geom { namespace NL { * instance type: the type of the objects produced by using * the fitting raw data solution */ + + + + template< typename ParameterType, typename ValueType, typename InstanceType > class LinearFittingModel { @@ -230,8 +235,32 @@ class LFMNormalizedPowerBasis // incomplete model, it can be inherited to make up different kinds of // instance type; the raw data is a vector of coefficients of the equation // of an ellipse curve +//template< typename InstanceType > +//class LFMEllipseEquation +// : public LinearFittingModelWithFixedTerms<Point, double, InstanceType> +//{ +// public: +// void feed( VectorView & coeff, double & fixed_term, Point const& p ) const +// { +// coeff[0] = p[X] * p[Y]; +// coeff[1] = p[Y] * p[Y]; +// coeff[2] = p[X]; +// coeff[3] = p[Y]; +// coeff[4] = 1; +// fixed_term = p[X] * p[X]; +// } +// +// size_t size() const +// { +// return 5; +// } +//}; + +// incomplete model, it can be inherited to make up different kinds of +// instance type; the raw data is a vector of coefficients of the equation +// of a conic section template< typename InstanceType > -class LFMEllipseEquation +class LFMConicEquation : public LinearFittingModelWithFixedTerms<Point, double, InstanceType> { public: @@ -251,10 +280,20 @@ class LFMEllipseEquation } }; +// this model generates Ellipse curves +class LFMConicSection + : public LFMConicEquation<xAx> +{ + public: + void instance(xAx & c, ConstVectorView const& coeff) const + { + c.set(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]); + } +}; // this model generates Ellipse curves class LFMEllipse - : public LFMEllipseEquation<Ellipse> + : public LFMConicEquation<Ellipse> { public: void instance(Ellipse & e, ConstVectorView const& coeff) const @@ -431,13 +470,13 @@ class LFMBezier // this model generates Bezier curves -template< unsigned int N > -class LFMBezierCurve - : public LinearFittingModel< double, Point, BezierCurve<N> > +template <unsigned degree> +class LFMBezierCurveN + : public LinearFittingModel< double, Point, BezierCurveN<degree> > { public: - LFMBezierCurve( size_t _order ) - : mob(_order) + LFMBezierCurveN() + : mob(degree+1) { } @@ -451,13 +490,13 @@ class LFMBezierCurve return mob.size(); } - void instance(BezierCurve<N> & bc, ConstMatrixView const& raw_data) const + void instance(BezierCurveN<degree> & bc, ConstMatrixView const& raw_data) const { - Bezier bx(size()-1); - Bezier by(size()-1); + Bezier bx(degree); + Bezier by(degree); mob.instance(bx, raw_data.column_const_view(X)); mob.instance(by, raw_data.column_const_view(Y)); - bc = BezierCurve<N>(bx, by); + bc = BezierCurveN<degree>(bx, by); } private: diff --git a/src/2geom/numeric/matrix.cpp b/src/2geom/numeric/matrix.cpp index 94a345fd5..98ff3b6ca 100644 --- a/src/2geom/numeric/matrix.cpp +++ b/src/2geom/numeric/matrix.cpp @@ -37,10 +37,8 @@ #include <2geom/numeric/vector.h> - namespace Geom { namespace NL { - Vector operator*( detail::BaseMatrixImpl const& A, detail::BaseVectorImpl const& v ) { @@ -101,6 +99,47 @@ Matrix pseudo_inverse(detail::BaseMatrixImpl const& A) return P; } + +double trace (detail::BaseMatrixImpl const& A) +{ + if (A.rows() != A.columns()) + { + THROW_RANGEERROR ("NL::Matrix: computing trace: " + "rows() != columns()"); + } + double t = 0; + for (size_t i = 0; i < A.rows(); ++i) + { + t += A(i,i); + } + return t; +} + + +double det (detail::BaseMatrixImpl const& A) +{ + if (A.rows() != A.columns()) + { + THROW_RANGEERROR ("NL::Matrix: computing determinant: " + "rows() != columns()"); + } + + Matrix LU(A); + int s; + gsl_permutation * p = gsl_permutation_alloc(LU.rows()); + gsl_linalg_LU_decomp (LU.get_gsl_matrix(), p, &s); + + double t = 1; + for (size_t i = 0; i < LU.rows(); ++i) + { + t *= LU(i,i); + } + + gsl_permutation_free(p); + return t; +} + + } } // end namespaces /* diff --git a/src/2geom/numeric/matrix.h b/src/2geom/numeric/matrix.h index f2a934235..a130bd748 100644 --- a/src/2geom/numeric/matrix.h +++ b/src/2geom/numeric/matrix.h @@ -38,6 +38,7 @@ #ifndef _NL_MATRIX_H_ #define _NL_MATRIX_H_ +#include <2geom/exception.h> #include <2geom/numeric/vector.h> #include <cassert> @@ -45,7 +46,6 @@ #include <algorithm> // for std::swap #include <sstream> #include <string> - #include <gsl/gsl_matrix.h> #include <gsl/gsl_linalg.h> @@ -232,13 +232,13 @@ class MatrixImpl : public BaseMatrixImpl gsl_matrix_set_identity(m_matrix); } - using base_type::operator(); // VSC legacy support - const double & operator() (size_t i, size_t j) const - { - return base_type::operator ()(i, j); - } + using base_type::operator(); // VSC legacy support + const double & operator() (size_t i, size_t j) const + { + return base_type::operator ()(i, j); + } - double & operator() (size_t i, size_t j) + double & operator() (size_t i, size_t j) { return *gsl_matrix_ptr(m_matrix, i, j); } @@ -310,6 +310,8 @@ using detail::operator==; using detail::operator<<; +template <size_t N> +class ConstBaseSymmetricMatrix; class Matrix: public detail::MatrixImpl @@ -352,6 +354,18 @@ class Matrix: public detail::MatrixImpl gsl_matrix_memcpy(m_matrix, _matrix.get_gsl_matrix()); } + template <size_t N> + explicit + Matrix(ConstBaseSymmetricMatrix<N> const& _smatrix) + { + m_rows = N; + m_columns = N; + m_matrix = gsl_matrix_alloc(N, N); + for (size_t i = 0; i < N; ++i) + for (size_t j = 0; j < N ; ++j) + (*gsl_matrix_ptr(m_matrix, i, j)) = _smatrix(i,j); + } + Matrix & operator=(Matrix const& _matrix) { assert( rows() == _matrix.rows() && columns() == _matrix.columns() ); @@ -366,6 +380,16 @@ class Matrix: public detail::MatrixImpl return *this; } + template <size_t N> + Matrix & operator=(ConstBaseSymmetricMatrix<N> const& _smatrix) + { + assert (rows() == N && columns() == N); + for (size_t i = 0; i < N; ++i) + for (size_t j = 0; j < N ; ++j) + (*this)(i,j) = _smatrix(i,j); + return *this; + } + virtual ~Matrix() { gsl_matrix_free(m_matrix); @@ -557,6 +581,10 @@ Matrix operator*( detail::BaseMatrixImpl const& A, Matrix pseudo_inverse(detail::BaseMatrixImpl const& A); +double trace (detail::BaseMatrixImpl const& A); + +double det (detail::BaseMatrixImpl const& A); + } } // end namespaces #endif /*_NL_MATRIX_H_*/ diff --git a/src/2geom/numeric/symmetric-matrix-fs-operation.h b/src/2geom/numeric/symmetric-matrix-fs-operation.h new file mode 100644 index 000000000..5222d2734 --- /dev/null +++ b/src/2geom/numeric/symmetric-matrix-fs-operation.h @@ -0,0 +1,107 @@ +/* + * SymmetricMatrix basic operation + * + * Authors: + * Marco Cecchetti <mrcekets at gmail.com> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#ifndef _NL_SYMMETRIC_MATRIX_FS_OPERATION_H_ +#define _NL_SYMMETRIC_MATRIX_FS_OPERATION_H_ + + +#include <2geom/numeric/symmetric-matrix-fs.h> +#include <2geom/numeric/symmetric-matrix-fs-trace.h> + + + + +namespace Geom { namespace NL { + +template <size_t N> +inline +SymmetricMatrix<N> adj(const ConstBaseSymmetricMatrix<N> & S) +{ + THROW_NOTIMPLEMENTED(); + return SymmetricMatrix<N>(); +} + +template <> +inline +SymmetricMatrix<2> adj(const ConstBaseSymmetricMatrix<2> & S) +{ + SymmetricMatrix<2> result; + result.get<0,0>() = S.get<1,1>(); + result.get<1,0>() = -S.get<1,0>(); + result.get<1,1>() = S.get<0,0>(); + return result; +} + +template <> +inline +SymmetricMatrix<3> adj(const ConstBaseSymmetricMatrix<3> & S) +{ + SymmetricMatrix<3> result; + + result.get<0,0>() = S.get<1,1>() * S.get<2,2>() - S.get<1,2>() * S.get<2,1>(); + result.get<1,0>() = S.get<0,2>() * S.get<2,1>() - S.get<0,1>() * S.get<2,2>(); + result.get<1,1>() = S.get<0,0>() * S.get<2,2>() - S.get<0,2>() * S.get<2,0>(); + result.get<2,0>() = S.get<0,1>() * S.get<1,2>() - S.get<0,2>() * S.get<1,1>(); + result.get<2,1>() = S.get<0,2>() * S.get<1,0>() - S.get<0,0>() * S.get<1,2>(); + result.get<2,2>() = S.get<0,0>() * S.get<1,1>() - S.get<0,1>() * S.get<1,0>(); + return result; +} + +template <size_t N> +inline +SymmetricMatrix<N> inverse(const ConstBaseSymmetricMatrix<N> & S) +{ + SymmetricMatrix<N> result = adj(S); + double d = det(S); + assert (d != 0); + result.scale (1/d); + return result; +} + +} /* end namespace NL*/ } /* end namespace Geom*/ + + +#endif // _NL_SYMMETRIC_MATRIX_FS_OPERATION_H_ + + + + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/numeric/symmetric-matrix-fs-trace.h b/src/2geom/numeric/symmetric-matrix-fs-trace.h new file mode 100644 index 000000000..099c834a8 --- /dev/null +++ b/src/2geom/numeric/symmetric-matrix-fs-trace.h @@ -0,0 +1,433 @@ +/* + * SymmetricMatrix trace + * + * Authors: + * Marco Cecchetti <mrcekets at gmail.com> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#ifndef _NL_TRACE_H_ +#define _NL_TRACE_H_ + + +#include <2geom/numeric/matrix.h> +#include <2geom/numeric/symmetric-matrix-fs.h> + + + + + +namespace Geom { namespace NL { + + +namespace detail +{ + +/* + * helper routines + */ + +inline +int sgn_prod (int x, int y) +{ + if (x == 0 || y == 0) return 0; + if (x == y) return 1; + return -1; +} + +inline +bool abs_less (double x, double y) +{ + return (std::fabs(x) < std::fabs(y)); +} + + +/* + * trace K-th of symmetric matrix S of order N + */ +template <size_t K, size_t N> +struct trace +{ + static + double evaluate (const ConstBaseSymmetricMatrix<N> & S) + { + THROW_NOTIMPLEMENTED(); + return K; + } + +}; + +template <size_t N> +struct trace<1,N> +{ + static + double evaluate (const ConstBaseSymmetricMatrix<N> & S) + { + double t = 0; + for (size_t i = 0; i < N; ++i) + { + t += S(i,i); + } + return t; + } +}; + +template <size_t N> +struct trace<N,N> +{ + static + double evaluate (const ConstBaseSymmetricMatrix<N> & S) + { + Matrix M(S); + return det(M); + } +}; + +/* + * trace for symmetric matrix of order 2 + */ +template <> +struct trace<1,2> +{ + static + double evaluate (const ConstBaseSymmetricMatrix<2> & S) + { + return (S.get<0,0>() + S.get<1,1>()); + } +}; + +template <> +struct trace<2,2> +{ + static + double evaluate (const ConstBaseSymmetricMatrix<2> & S) + { + return (S.get<0,0>() * S.get<1,1>() - S.get<0,1>() * S.get<1,0>()); + } +}; + + +/* + * trace for symmetric matrix of order 3 + */ +template <> +struct trace<1,3> +{ + static + double evaluate (const ConstBaseSymmetricMatrix<3> & S) + { + return (S.get<0,0>() + S.get<1,1>() + S.get<2,2>()); + } +}; + +template <> +struct trace<2,3> +{ + static + double evaluate (const ConstBaseSymmetricMatrix<3> & S) + { + double a00 = S.get<1,1>() * S.get<2,2>() - S.get<1,2>() * S.get<2,1>(); + double a11 = S.get<0,0>() * S.get<2,2>() - S.get<0,2>() * S.get<2,0>(); + double a22 = S.get<0,0>() * S.get<1,1>() - S.get<0,1>() * S.get<1,0>(); + return (a00 + a11 + a22); + } +}; + +template <> +struct trace<3,3> +{ + static + double evaluate (const ConstBaseSymmetricMatrix<3> & S) + { + double d = S.get<0,0>() * S.get<1,1>() * S.get<2,2>(); + d += (2 * S.get<1,0>() * S.get<2,0>() * S.get<2,1>()); + d -= (S.get<0,0>() * S.get<2,1>() * S.get<2,1>()); + d -= (S.get<1,1>() * S.get<2,0>() * S.get<2,0>()); + d -= (S.get<2,2>() * S.get<1,0>() * S.get<1,0>()); + return d; + } +}; + + +/* + * sign of trace K-th + */ +template <size_t K, size_t N> +struct trace_sgn +{ + static + int evaluate (const ConstBaseSymmetricMatrix<N> & S) + { + double d = trace<K, N>::evaluate(S); + return sgn(d); + } +}; + + +/* + * sign of trace for symmetric matrix of order 2 + */ +template <> +struct trace_sgn<2,2> +{ + static + int evaluate (const ConstBaseSymmetricMatrix<2> & S) + { + double m00 = S.get<0,0>(); + double m10 = S.get<1,0>(); + double m11 = S.get<1,1>(); + + int sm00 = sgn (m00); + int sm10 = sgn (m10); + int sm11 = sgn (m11); + + if (sm10 == 0) + { + return sgn_prod (sm00, sm11); + } + else + { + int sm00m11 = sgn_prod (sm00, sm11); + if (sm00m11 == 1) + { + int e00, e10, e11; + double f00 = std::frexp (m00, &e00); + double f10 = std::frexp (m10, &e10); + double f11 = std::frexp (m11, &e11); + + int e0011 = e00 + e11; + int e1010 = e10 << 1; + int ed = e0011 - e1010; + + if (ed > 1) + { + return 1; + } + else if (ed < -1) + { + return -1; + } + else + { + double d = std::ldexp (f00 * f11, ed) - f10 * f10; + //std::cout << "trace_sgn<2,2>: det = " << d << std::endl; + double eps = std::ldexp (1, -50); + if (std::fabs(d) < eps) return 0; + return sgn (d); + } + } + return -1; + } + } +}; + + +/* + * sign of trace for symmetric matrix of order 3 + */ +template <> +struct trace_sgn<2,3> +{ + static + int evaluate (const ConstBaseSymmetricMatrix<3> & S) + { + double eps = std::ldexp (1, -50); + double t[6]; + + t[0] = S.get<1,1>() * S.get<2,2>(); + t[1] = - S.get<1,2>() * S.get<2,1>(); + t[2] = S.get<0,0>() * S.get<2,2>(); + t[3] = - S.get<0,2>() * S.get<2,0>(); + t[4] = S.get<0,0>() * S.get<1,1>(); + t[5] = - S.get<0,1>() * S.get<1,0>(); + + + double* maxp = std::max_element (t, t+6, abs_less); + int em; + std::frexp(*maxp, &em); + double d = 0; + for (size_t i = 0; i < 6; ++i) + { + d += t[i]; + } + double r = std::fabs (std::ldexp (d, -em)); // relative error + //std::cout << "trace_sgn<2,3>: d = " << d << std::endl; + //std::cout << "trace_sgn<2,3>: r = " << r << std::endl; + if (r < eps) return 0; + if (d > 0) return 1; + return -1; + } +}; + +template <> +struct trace_sgn<3,3> +{ + static + int evaluate (const ConstBaseSymmetricMatrix<3> & S) + { + + double eps = std::ldexp (1, -48); + double t[5]; + + t[0] = S.get<0,0>() * S.get<1,1>() * S.get<2,2>(); + t[1] = 2 * S.get<1,0>() * S.get<2,0>() * S.get<2,1>(); + t[2] = -(S.get<0,0>() * S.get<2,1>() * S.get<2,1>()); + t[3] = -(S.get<1,1>() * S.get<2,0>() * S.get<2,0>()); + t[4] = -(S.get<2,2>() * S.get<1,0>() * S.get<1,0>()); + + double* maxp = std::max_element (t, t+5, abs_less); + int em; + std::frexp(*maxp, &em); + double d = 0; + for (size_t i = 0; i < 5; ++i) + { + d += t[i]; + } + //std::cout << "trace_sgn<3,3>: d = " << d << std::endl; + double r = std::fabs (std::ldexp (d, -em)); // relative error + //std::cout << "trace_sgn<3,3>: r = " << r << std::endl; + + if (r < eps) return 0; + if (d > 0) return 1; + return -1; + } +}; // end struct trace_sgn<3,3> + +} // end namespace detail + + +template <size_t K, size_t N> +inline +double trace (const ConstBaseSymmetricMatrix<N> & _matrix) +{ + return detail::trace<K, N>::evaluate(_matrix); +} + +template <size_t N> +inline +double trace (const ConstBaseSymmetricMatrix<N> & _matrix) +{ + return detail::trace<1, N>::evaluate(_matrix); +} + +template <size_t N> +inline +double det (const ConstBaseSymmetricMatrix<N> & _matrix) +{ + return detail::trace<N, N>::evaluate(_matrix); +} + + +template <size_t K, size_t N> +inline +int trace_sgn (const ConstBaseSymmetricMatrix<N> & _matrix) +{ + return detail::trace_sgn<K, N>::evaluate(_matrix); +} + +template <size_t N> +inline +int trace_sgn (const ConstBaseSymmetricMatrix<N> & _matrix) +{ + return detail::trace_sgn<1, N>::evaluate(_matrix); +} + +template <size_t N> +inline +int det_sgn (const ConstBaseSymmetricMatrix<N> & _matrix) +{ + return detail::trace_sgn<N, N>::evaluate(_matrix); +} + +/* +template <size_t N> +inline +size_t rank (const ConstBaseSymmetricMatrix<N> & S) +{ + THROW_NOTIMPLEMENTED(); + return 0; +} + +template <> +inline +size_t rank<2> (const ConstBaseSymmetricMatrix<2> & S) +{ + if (S.is_zero()) return 0; + double d = S.get<0,0>() * S.get<1,1>() - S.get<0,1>() * S.get<1,0>(); + if (d != 0) return 2; + return 1; +} + +template <> +inline +size_t rank<3> (const ConstBaseSymmetricMatrix<3> & S) +{ + if (S.is_zero()) return 0; + + double a20 = S.get<0,1>() * S.get<1,2>() - S.get<0,2>() * S.get<1,1>(); + double a21 = S.get<0,2>() * S.get<1,0>() - S.get<0,0>() * S.get<1,2>(); + double a22 = S.get<0,0>() * S.get<1,1>() - S.get<0,1>() * S.get<1,0>(); + double d = a20 * S.get<2,0>() + a21 * S.get<2,1>() + a22 * S.get<2,2>(); + + if (d != 0) return 3; + + if (a20 != 0 || a21 != 0 || a22 != 0) return 2; + + double a00 = S.get<1,1>() * S.get<2,2>() - S.get<1,2>() * S.get<2,1>(); + if (a00 != 0) return 2; + + double a10 = S.get<0,2>() * S.get<2,1>() - S.get<0,1>() * S.get<2,2>(); + if (a10 != 0) return 2; + + double a11 = S.get<0,0>() * S.get<2,2>() - S.get<0,2>() * S.get<2,0>(); + if (a11 != 0) return 2; + + return 1; +} +*/ + +} /* end namespace NL*/ } /* end namespace Geom*/ + + + + +#endif // _NL_TRACE_H_ + + + + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/numeric/symmetric-matrix-fs.h b/src/2geom/numeric/symmetric-matrix-fs.h new file mode 100644 index 000000000..c1de27afd --- /dev/null +++ b/src/2geom/numeric/symmetric-matrix-fs.h @@ -0,0 +1,730 @@ +/* + * SymmetricMatrix, ConstSymmetricMatrixView, SymmetricMatrixView template + * classes implement fixed size symmetric matrix; "views" mimic the semantic + * of C++ references: any operation performed on a "view" is actually performed + * on the "viewed object" + * + * Authors: + * Marco Cecchetti <mrcekets at gmail.com> + * + * Copyright 2009 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#ifndef _NL_SYMMETRIC_MATRIX_FS_H_ +#define _NL_SYMMETRIC_MATRIX_FS_H_ + + +#include <2geom/numeric/vector.h> +#include <2geom/numeric/matrix.h> +#include <2geom/utils.h> +#include <2geom/exception.h> + +#include <boost/static_assert.hpp> + +#include <cassert> +#include <utility> // for std::pair +#include <algorithm> // for std::swap, std::copy +#include <sstream> +#include <string> + + + +namespace Geom { namespace NL { + + +namespace detail +{ + +template <size_t I, size_t J, bool B = (I < J)> +struct index +{ + static const size_t K = index<J, I>::K; +}; + +template <size_t I, size_t J> +struct index<I, J, false> +{ + static const size_t K = (((I+1) * I) >> 1) + J; +}; + +} // end namespace detail + + + + +template <size_t N> +class ConstBaseSymmetricMatrix; + +template <size_t N> +class BaseSymmetricMatrix; + +template <size_t N> +class SymmetricMatrix; + +template <size_t N> +class ConstSymmetricMatrixView; + +template <size_t N> +class SymmetricMatrixView; + + + +// declaration needed for friend clause +template <size_t N> +bool operator== (ConstBaseSymmetricMatrix<N> const& _smatrix1, + ConstBaseSymmetricMatrix<N> const& _smatrix2); + + + + +template <size_t N> +class ConstBaseSymmetricMatrix +{ + public: + const static size_t DIM = N; + const static size_t DATA_SIZE = ((DIM+1) * DIM) / 2; + + public: + + ConstBaseSymmetricMatrix (VectorView const& _data) + : m_data(_data) + { + } + + double operator() (size_t i, size_t j) const + { + return m_data[get_index(i,j)]; + } + + template <size_t I, size_t J> + double get() const + { + BOOST_STATIC_ASSERT ((I < N && J < N)); + return m_data[detail::index<I, J>::K]; + } + + + size_t rows() const + { + return DIM; + } + + size_t columns() const + { + return DIM; + } + + bool is_zero() const + { + return m_data.is_zero(); + } + + bool is_positive() const + { + return m_data.is_positive(); + } + + bool is_negative() const + { + return m_data.is_negative(); + } + + bool is_non_negative() const + { + return m_data.is_non_negative(); + } + + double min() const + { + return m_data.min(); + } + + double max() const + { + return m_data.max(); + } + + std::pair<size_t, size_t> + min_index() const + { + std::pair<size_t, size_t> indices(0,0); + double min_value = m_data[0]; + for (size_t i = 1; i < DIM; ++i) + { + for (size_t j = 0; j <= i; ++j) + { + if (min_value > (*this)(i,j)) + { + min_value = (*this)(i,j); + indices.first = i; + indices.second = j; + } + } + } + return indices; + } + + std::pair<size_t, size_t> + max_index() const + { + std::pair<size_t, size_t> indices(0,0); + double max_value = m_data[0]; + for (size_t i = 1; i < DIM; ++i) + { + for (size_t j = 0; j <= i; ++j) + { + if (max_value < (*this)(i,j)) + { + max_value = (*this)(i,j); + indices.first = i; + indices.second = j; + } + } + } + return indices; + } + + size_t min_on_row_index (size_t i) const + { + size_t idx = 0; + double min_value = (*this)(i,0); + for (size_t j = 1; j < DIM; ++j) + { + if (min_value > (*this)(i,j)) + { + min_value = (*this)(i,j); + idx = j; + } + } + return idx; + } + + size_t max_on_row_index (size_t i) const + { + size_t idx = 0; + double max_value = (*this)(i,0); + for (size_t j = 1; j < DIM; ++j) + { + if (max_value < (*this)(i,j)) + { + max_value = (*this)(i,j); + idx = j; + } + } + return idx; + } + + size_t min_on_column_index (size_t j) const + { + return min_on_row_index(j); + } + + size_t max_on_column_index (size_t j) const + { + return max_on_row_index(j); + } + + size_t min_on_diag_index () const + { + size_t idx = 0; + double min_value = (*this)(0,0); + for (size_t i = 1; i < DIM; ++i) + { + if (min_value > (*this)(i,i)) + { + min_value = (*this)(i,i); + idx = i; + } + } + return idx; + } + + size_t max_on_diag_index () const + { + size_t idx = 0; + double max_value = (*this)(0,0); + for (size_t i = 1; i < DIM; ++i) + { + if (max_value < (*this)(i,i)) + { + max_value = (*this)(i,i); + idx = i; + } + } + return idx; + } + + std::string str() const; + + ConstSymmetricMatrixView<N-1> main_minor_const_view() const; + + SymmetricMatrix<N> operator- () const; + + Vector operator* (ConstVectorView _vector) const + { + assert (_vector.size() == DIM); + Vector result(DIM, 0.0); + + for (size_t i = 0; i < DIM; ++i) + { + for (size_t j = 0; j < DIM; ++j) + { + result[i] += (*this)(i,j) * _vector[j]; + } + } + return result; + } + + protected: + static size_t get_index (size_t i, size_t j) + { + if (i < j) return get_index (j, i); + size_t k = (i+1) * i; + k >>= 1; + k += j; + return k; + } + + protected: + ConstVectorView get_data() const + { + return m_data; + } + + friend + bool operator==<N> (ConstBaseSymmetricMatrix const& _smatrix1, + ConstBaseSymmetricMatrix const& _smatrix2); + + protected: + VectorView m_data; + +}; //end ConstBaseSymmetricMatrix + + +template <size_t N> +class BaseSymmetricMatrix : public ConstBaseSymmetricMatrix<N> +{ + public: + typedef ConstBaseSymmetricMatrix<N> base_type; + + + public: + + BaseSymmetricMatrix (VectorView const& _data) + : base_type(_data) + { + } + + using base_type::operator(); + + double& operator() (size_t i, size_t j) + { + return m_data[base_type::get_index(i,j)]; + } + + template <size_t I, size_t J> + double& get() + { + BOOST_STATIC_ASSERT ((I < N && J < N)); + return m_data[detail::index<I, J>::K]; + } + + void set_all (double x) + { + m_data.set_all(x); + } + + SymmetricMatrixView<N-1> main_minor_view(); + + BaseSymmetricMatrix& transpose() const + { + return (*this); + } + + BaseSymmetricMatrix& translate (double c) + { + m_data.translate(c); + return (*this); + } + + BaseSymmetricMatrix& scale (double c) + { + m_data.scale(c); + return (*this); + } + + BaseSymmetricMatrix& operator+= (base_type const& _smatrix) + { + m_data += (static_cast<const BaseSymmetricMatrix &>(_smatrix).m_data); + return (*this); + } + + BaseSymmetricMatrix& operator-= (base_type const& _smatrix) + { + m_data -= (static_cast<const BaseSymmetricMatrix &>(_smatrix).m_data); + return (*this); + } + + using base_type::DIM; + using base_type::DATA_SIZE; + using base_type::m_data; + using base_type::operator-; + using base_type::operator*; + +}; //end BaseSymmetricMatrix + + +template <size_t N> +class SymmetricMatrix : public BaseSymmetricMatrix<N> +{ + public: + typedef BaseSymmetricMatrix<N> base_type; + typedef typename base_type::base_type base_base_type; + + using base_type::DIM; + using base_type::DATA_SIZE; + using base_type::m_data; + + public: + SymmetricMatrix () + : base_type (VectorView(m_adata, DATA_SIZE)) + { + } + + explicit + SymmetricMatrix (ConstVectorView _data) + : base_type (VectorView(m_adata, DATA_SIZE)) + { + assert (_data.size() == DATA_SIZE); + m_data = _data; + } + + explicit + SymmetricMatrix (const double _data[DATA_SIZE]) + : base_type (VectorView(m_adata, DATA_SIZE)) + { + std::copy (_data, _data + DATA_SIZE, m_adata); + } + + SymmetricMatrix (SymmetricMatrix const& _smatrix) + : base_type (VectorView(m_adata, DATA_SIZE)) + { + m_data = _smatrix.m_data; + } + + explicit + SymmetricMatrix (base_base_type const& _smatrix) + : base_type (VectorView(m_adata, DATA_SIZE)) + { + m_data = static_cast<const ConstSymmetricMatrixView<DIM> &>(_smatrix).m_data; + } + + explicit + SymmetricMatrix (ConstMatrixView const& _matrix) + : base_type (VectorView(m_adata, DATA_SIZE)) + { + assert (_matrix.rows() == N && _matrix.columns() == N); + for (size_t i = 0; i < N; ++i) + for (size_t j = 0; j <= i ; ++j) + (*this)(i,j) = _matrix(i,j); + } + + SymmetricMatrix& operator= (SymmetricMatrix const& _smatrix) + { + m_data = _smatrix.m_data; + return (*this); + } + + SymmetricMatrix& operator= (base_base_type const& _smatrix) + { + + m_data = static_cast<const ConstSymmetricMatrixView<DIM> &>(_smatrix).m_data; + return (*this); + } + + SymmetricMatrix& operator= (ConstMatrixView const& _matrix) + { + assert (_matrix.rows() == N && _matrix.columns() == N); + for (size_t i = 0; i < N; ++i) + for (size_t j = 0; j <= i ; ++j) + (*this)(i,j) = _matrix(i,j); + + return (*this); + } + + // needed for accessing m_adata + friend class ConstSymmetricMatrixView<DIM>; + friend class SymmetricMatrixView<DIM>; + private: + double m_adata[DATA_SIZE]; +}; //end SymmetricMatrix + + +template <size_t N> +class ConstSymmetricMatrixView : public ConstBaseSymmetricMatrix<N> +{ + public: + typedef ConstBaseSymmetricMatrix<N> base_type; + + using base_type::DIM; + using base_type::DATA_SIZE; + using base_type::m_data; + + + public: + + explicit + ConstSymmetricMatrixView (ConstVectorView _data) + : base_type (const_vector_view_cast(_data)) + { + assert (_data.size() == DATA_SIZE); + } + + explicit + ConstSymmetricMatrixView (const double _data[DATA_SIZE]) + : base_type (const_vector_view_cast (ConstVectorView (_data, DATA_SIZE))) + { + } + + ConstSymmetricMatrixView (const ConstSymmetricMatrixView & _smatrix) + : base_type (_smatrix.m_data) + { + } + + ConstSymmetricMatrixView (const base_type & _smatrix) + : base_type (static_cast<const ConstSymmetricMatrixView &>(_smatrix).m_data) + { + } + +}; //end SymmetricMatrix + + +// declaration needed for friend clause +template <size_t N> +void swap_view(SymmetricMatrixView<N> & m1, SymmetricMatrixView<N> & m2); + + +template <size_t N> +class SymmetricMatrixView : public BaseSymmetricMatrix<N> +{ + public: + typedef BaseSymmetricMatrix<N> base_type; + typedef typename base_type::base_type base_base_type; + + using base_type::DIM; + using base_type::DATA_SIZE; + using base_type::m_data; + + public: + + explicit + SymmetricMatrixView (VectorView _data) + : base_type (_data) + { + assert (_data.size() == DATA_SIZE); + } + + explicit + SymmetricMatrixView (double _data[DATA_SIZE]) + : base_type (VectorView (_data, DATA_SIZE)) + { + } + + SymmetricMatrixView (const SymmetricMatrixView & _smatrix) + : base_type (_smatrix.m_data) + { + } + + SymmetricMatrixView (SymmetricMatrix<DIM> & _smatrix) + : base_type (VectorView (_smatrix.m_adata, DATA_SIZE)) + { + } + + SymmetricMatrixView& operator= (const SymmetricMatrixView & _smatrix) + { + m_data = _smatrix.m_data; + return (*this); + } + + SymmetricMatrixView& operator= (const base_base_type & _smatrix) + { + m_data = static_cast<const ConstSymmetricMatrixView<DIM> &>(_smatrix).m_data; + return (*this); + } + + friend + void swap_view<N>(SymmetricMatrixView & m1, SymmetricMatrixView & m2); + +}; //end SymmetricMatrix + + + + +/* + * class ConstBaseSymmetricMatrix methods + */ + +template <size_t N> +inline +std::string ConstBaseSymmetricMatrix<N>::str() const +{ + std::ostringstream oss; + oss << (*this); + return oss.str(); +} + +template <size_t N> +inline +ConstSymmetricMatrixView<N-1> +ConstBaseSymmetricMatrix<N>::main_minor_const_view() const +{ + ConstVectorView data(m_data.get_gsl_vector()->data, DATA_SIZE - DIM); + ConstSymmetricMatrixView<N-1> mm(data); + return mm; +} + +template <size_t N> +inline +SymmetricMatrix<N> ConstBaseSymmetricMatrix<N>::operator- () const +{ + SymmetricMatrix<N> result; + for (size_t i = 0; i < DATA_SIZE; ++i) + { + result.m_data[i] = -m_data[i]; + } + return result; +} + + +/* + * class ConstBaseSymmetricMatrix friend free functions + */ + +template <size_t N> +inline +bool operator== (ConstBaseSymmetricMatrix<N> const& _smatrix1, + ConstBaseSymmetricMatrix<N> const& _smatrix2) +{ + return (_smatrix1.m_data == _smatrix2.m_data); +} + +/* + * class ConstBaseSymmetricMatrix related free functions + */ + +template< size_t N, class charT > +inline +std::basic_ostream<charT> & +operator<< (std::basic_ostream<charT> & os, + const ConstBaseSymmetricMatrix<N> & _matrix) +{ + os << "[[" << _matrix(0,0); + for (size_t j = 1; j < N; ++j) + { + os << ", " << _matrix(0,j); + } + os << "]"; + for (size_t i = 1; i < N; ++i) + { + os << "\n [" << _matrix(i,0); + for (size_t j = 1; j < N; ++j) + { + os << ", " << _matrix(i,j); + } + os << "]"; + } + os << "]"; + return os; +} + + +/* + * class ConstBaseSymmetricMatrix specialized methods + */ + +template<> +inline +size_t ConstBaseSymmetricMatrix<2>::get_index (size_t i, size_t j) +{ + return (i+j); +} + +template<> +inline +size_t ConstBaseSymmetricMatrix<3>::get_index (size_t i, size_t j) +{ + size_t k = i + j; + if (i == 2 || j == 2) ++k; + return k; +} + + +/* + * class BaseSymmetricMatrix methods + */ + +template <size_t N> +inline +SymmetricMatrixView<N-1> BaseSymmetricMatrix<N>::main_minor_view() +{ + VectorView data(m_data.get_gsl_vector()->data, DATA_SIZE - DIM); + SymmetricMatrixView<N-1> mm(data); + return mm; +} + + +/* + * class SymmetricMatrixView friend free functions + */ + +template <size_t N> +inline +void swap_view(SymmetricMatrixView<N> & m1, SymmetricMatrixView<N> & m2) +{ + swap_view(m1.m_data, m2.m_data); +} + +} /* end namespace NL*/ } /* end namespace Geom*/ + + + + +#endif // _NL_SYMMETRIC_MATRIX_FS_H_ + + + + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/numeric/vector.h b/src/2geom/numeric/vector.h index 46701645a..6ab898f29 100644 --- a/src/2geom/numeric/vector.h +++ b/src/2geom/numeric/vector.h @@ -555,6 +555,24 @@ void swap_view(VectorView & v1, VectorView & v2) std::swap(v1.m_vector_view, v2.m_vector_view); // not swap m_vector too } +inline +const VectorView & const_vector_view_cast (const ConstVectorView & view) +{ + const detail::BaseVectorImpl & bvi + = static_cast<const detail::BaseVectorImpl &>(view); + const VectorView & vv = reinterpret_cast<const VectorView &>(bvi); + return vv; +} + +inline +VectorView & const_vector_view_cast (ConstVectorView & view) +{ + detail::BaseVectorImpl & bvi + = static_cast<detail::BaseVectorImpl &>(view); + VectorView & vv = reinterpret_cast<VectorView &>(bvi); + return vv; +} + } } // end namespaces diff --git a/src/2geom/path-intersection.cpp b/src/2geom/path-intersection.cpp index 5e58525c7..58ee6232b 100644 --- a/src/2geom/path-intersection.cpp +++ b/src/2geom/path-intersection.cpp @@ -28,7 +28,7 @@ int winding(Path const &path, Point p) { if(iter == path.end_closed()) { return 0; } if(iter->initialPoint()[Y]!=p[Y]) { start = iter; break; } if(iter->finalPoint()[Y]!=p[Y]) { start = iter; break; } - if(iter->boundsFast()->height()!=0.){ start = iter; break; } + if(iter->boundsFast().height()!=0.){ start = iter; break; } } int wind = 0; unsigned cnt = 0; @@ -39,18 +39,18 @@ int winding(Path const &path, Point p) { cnt++; if(cnt > path.size()) return wind; //some bug makes this required starting = false; - Rect bounds = *(iter->boundsFast()); + Rect bounds = (iter->boundsFast()); Coord x = p[X], y = p[Y]; - + if(x > bounds.right() || !bounds[Y].contains(y)) continue; //ray doesn't intersect box - + Point final = iter->finalPoint(); Point initial = iter->initialPoint(); Cmp final_to_ray = cmp(final[Y], y); Cmp initial_to_ray = cmp(initial[Y], y); - + // if y is included, these will have opposite values, giving order. - Cmp c = cmp(final_to_ray, initial_to_ray); + Cmp c = cmp(final_to_ray, initial_to_ray); if(x < bounds.left()) { // ray goes through bbox // winding delta determined by position of endpoints @@ -73,7 +73,7 @@ int winding(Path const &path, Point p) { next++; for(; ; next++) { if(next == path.end_closed()) next = path.begin(); - Rect bnds = *(next->boundsFast()); + Rect bnds = (next->boundsFast()); //TODO: X considerations if(bnds.height() > 0) { //It has diverged @@ -100,7 +100,7 @@ int winding(Path const &path, Point p) { //Looks like it looped, which means everything's flat return 0; } - + cont:(void)0; } return wind; @@ -135,10 +135,10 @@ bool path_direction(Path const &p) { } else if(final_to_ray == EQUAL_TO) goto doh; } return res < 0; - + doh: //Otherwise fallback on area - + Piecewise<D2<SBasis> > pw = p.toPwSb(); double area; Point centre; @@ -214,39 +214,41 @@ intersect_polish_f (const gsl_vector * x, void *params, { const double x0 = gsl_vector_get (x, 0); const double x1 = gsl_vector_get (x, 1); - - Geom::Point dx = ((struct rparams *) params)->A(x0) - + + Geom::Point dx = ((struct rparams *) params)->A(x0) - ((struct rparams *) params)->B(x1); - + gsl_vector_set (f, 0, dx[0]); gsl_vector_set (f, 1, dx[1]); - + return GSL_SUCCESS; } #endif -static void +static void intersect_polish_root (Curve const &A, double &s, Curve const &B, double &t) { + int status; + size_t iter = 0; std::vector<Point> as, bs; as = A.pointAndDerivatives(s, 2); bs = B.pointAndDerivatives(t, 2); Point F = as[0] - bs[0]; double best = dot(F, F); - + for(int i = 0; i < 4; i++) { - + /** we want to solve J*(x1 - x0) = f(x0) - + |dA(s)[0] -dB(t)[0]| (X1 - X0) = A(s) - B(t) - |dA(s)[1] -dB(t)[1]| + |dA(s)[1] -dB(t)[1]| **/ // We're using the standard transformation matricies, which is numerically rather poor. Much better to solve the equation using elimination. - Matrix jack(as[1][0], as[1][1], + Affine jack(as[1][0], as[1][1], -bs[1][0], -bs[1][1], 0, 0); Point soln = (F)*jack.inverse(); @@ -257,7 +259,7 @@ intersect_polish_root (Curve const &A, double &s, else if (ns>1) ns=1; if (nt<0) nt=0; else if (nt>1) nt=1; - + as = A.pointAndDerivatives(ns, 2); bs = B.pointAndDerivatives(nt, 2); F = as[0] - bs[0]; @@ -275,35 +277,33 @@ intersect_polish_root (Curve const &A, double &s, const size_t n = 2; struct rparams p = {A, B}; gsl_multiroot_function f = {&intersect_polish_f, n, &p}; - + double x_init[2] = {s, t}; gsl_vector *x = gsl_vector_alloc (n); - + gsl_vector_set (x, 0, x_init[0]); gsl_vector_set (x, 1, x_init[1]); - + const gsl_multiroot_fsolver_type *T = gsl_multiroot_fsolver_hybrids; gsl_multiroot_fsolver *sol = gsl_multiroot_fsolver_alloc (T, 2); gsl_multiroot_fsolver_set (sol, &f, x); - - int status = 0; - size_t iter = 0; + do { iter++; status = gsl_multiroot_fsolver_iterate (sol); - + if (status) /* check if solver is stuck */ break; - + status = gsl_multiroot_test_residual (sol->f, 1e-12); } while (status == GSL_CONTINUE && iter < 1000); - + s = gsl_vector_get (sol->x, 0); t = gsl_vector_get (sol->x, 1); - + gsl_multiroot_fsolver_free (sol); gsl_vector_free (x); } @@ -315,7 +315,7 @@ intersect_polish_root (Curve const &A, double &s, * It passes in the curves, time intervals, and keeps track of depth, while * returning the results through the Crossings parameter. */ -void pair_intersect(Curve const & A, double Al, double Ah, +void pair_intersect(Curve const & A, double Al, double Ah, Curve const & B, double Bl, double Bh, Crossings &ret, unsigned depth = 0) { // std::cout << depth << "(" << Al << ", " << Ah << ")\n"; @@ -324,15 +324,15 @@ void pair_intersect(Curve const & A, double Al, double Ah, OptRect Br = B.boundsLocal(Interval(Bl, Bh)); if (!Br) return; - + if(! Ar->intersects(*Br)) return; - + //Checks the general linearity of the function - if((depth > 12)) { // || (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1 + if((depth > 12)) { // || (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1 //&& B.boundsLocal(Interval(Bl, Bh), 1).maxExtent() < 0.1)) { double tA, tB, c; - if(linear_intersect(A.pointAt(Al), A.pointAt(Ah), - B.pointAt(Bl), B.pointAt(Bh), + if(linear_intersect(A.pointAt(Al), A.pointAt(Ah), + B.pointAt(Bl), B.pointAt(Bh), tA, tB, c)) { tA = tA * (Ah - Al) + Al; tB = tB * (Bh - Bl) + Bl; @@ -385,8 +385,8 @@ void mono_intersect(Curve const &A, double Al, double Ah, if(depth > 12 || (Ar.maxExtent() < tol && Ar.maxExtent() < tol)) { double tA, tB, c; - if(linear_intersect(A.pointAt(Al), A.pointAt(Ah), - B.pointAt(Bl), B.pointAt(Bh), + if(linear_intersect(A.pointAt(Al), A.pointAt(Ah), + B.pointAt(Bl), B.pointAt(Bh), tA, tB, c)) { tA = tA * (Ah - Al) + Al; tB = tB * (Bh - Bl) + Bl; @@ -483,7 +483,7 @@ std::vector<double> offset_doubles(std::vector<double> const &x, double offs) { std::vector<double> path_mono_splits(Path const &p) { std::vector<double> ret; if(p.empty()) return ret; - + bool pdx=2, pdy=2; //Previous derivative direction for(unsigned i = 0; i < p.size(); i++) { std::vector<double> spl = offset_doubles(curve_mono_splits(p[i]), i); @@ -502,7 +502,7 @@ std::vector<double> path_mono_splits(Path const &p) { } /** - * Applies path_mono_splits to multiple paths, and returns the results such that + * Applies path_mono_splits to multiple paths, and returns the results such that * time-set i corresponds to Path i. */ std::vector<std::vector<double> > paths_mono_splits(std::vector<Path> const &ps) { @@ -541,14 +541,14 @@ CrossingSet MonoCrosser::crossings(std::vector<Path> const &a, std::vector<Path> if(b.empty()) return CrossingSet(a.size(), Crossings()); CrossingSet results(a.size() + b.size(), Crossings()); if(a.empty()) return results; - + std::vector<std::vector<double> > splits_a = paths_mono_splits(a), splits_b = paths_mono_splits(b); std::vector<std::vector<Rect> > bounds_a = split_bounds(a, splits_a), bounds_b = split_bounds(b, splits_b); - - std::vector<Rect> bounds_a_union, bounds_b_union; + + std::vector<Rect> bounds_a_union, bounds_b_union; for(unsigned i = 0; i < bounds_a.size(); i++) bounds_a_union.push_back(union_list(bounds_a[i])); for(unsigned i = 0; i < bounds_b.size(); i++) bounds_b_union.push_back(union_list(bounds_b[i])); - + std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds_a_union, bounds_b_union); Crossings n; for(unsigned i = 0; i < cull.size(); i++) { @@ -556,7 +556,7 @@ CrossingSet MonoCrosser::crossings(std::vector<Path> const &a, std::vector<Path> unsigned j = cull[i][jx]; unsigned jc = j + a.size(); Crossings res; - + //Sweep of the monotonic portions std::vector<std::vector<unsigned> > cull2 = sweep_bounds(bounds_a[i], bounds_b[j]); for(unsigned k = 0; k < cull2.size(); k++) { @@ -567,9 +567,9 @@ CrossingSet MonoCrosser::crossings(std::vector<Path> const &a, std::vector<Path> res, .1); } } - + for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = jc; } - + merge_crossings(results[i], res, i); merge_crossings(results[i], res, jc); } @@ -583,22 +583,22 @@ CrossingSet MonoCrosser::crossings(std::vector<Path> const &a, std::vector<Path> CrossingSet crossings_among(std::vector<Path> const &p) { CrossingSet results(p.size(), Crossings()); if(p.empty()) return results; - + std::vector<std::vector<double> > splits = paths_mono_splits(p); std::vector<std::vector<Rect> > prs = split_bounds(p, splits); std::vector<Rect> rs; for(unsigned i = 0; i < prs.size(); i++) rs.push_back(union_list(prs[i])); - + std::vector<std::vector<unsigned> > cull = sweep_bounds(rs); - + //we actually want to do the self-intersections, so add em in: for(unsigned i = 0; i < cull.size(); i++) cull[i].push_back(i); - + for(unsigned i = 0; i < cull.size(); i++) { for(unsigned jx = 0; jx < cull[i].size(); jx++) { unsigned j = cull[i][jx]; Crossings res; - + //Sweep of the monotonic portions std::vector<std::vector<unsigned> > cull2 = sweep_bounds(prs[i], prs[j]); for(unsigned k = 0; k < cull2.size(); k++) { @@ -609,14 +609,14 @@ CrossingSet crossings_among(std::vector<Path> const &p) { res, .1); } } - + for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = j; } - + merge_crossings(results[i], res, i); merge_crossings(results[j], res, j); } } - + return results; } */ @@ -635,7 +635,7 @@ Crossings curve_self_crossings(Curve const &a) { } /* -void mono_curve_intersect(Curve const & A, double Al, double Ah, +void mono_curve_intersect(Curve const & A, double Al, double Ah, Curve const & B, double Bl, double Bh, Crossings &ret, unsigned depth=0) { // std::cout << depth << "(" << Al << ", " << Ah << ")\n"; @@ -643,9 +643,9 @@ void mono_curve_intersect(Curve const & A, double Al, double Ah, B0 = B.pointAt(Bl), B1 = B.pointAt(Bh); //inline code that this implies? (without rect/interval construction) if(!Rect(A0, A1).intersects(Rect(B0, B1)) || A0 == A1 || B0 == B1) return; - + //Checks the general linearity of the function - if((depth > 12) || (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1 + if((depth > 12) || (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1 && B.boundsLocal(Interval(Bl, Bh), 1).maxExtent() < 0.1)) { double tA, tB, c; if(linear_intersect(A0, A1, B0, B1, tA, tB, c)) { @@ -705,7 +705,7 @@ Crossings path_self_crossings(Path const &p) { for(unsigned jx = 0; jx < cull[i].size(); jx++) { unsigned j = cull[i][jx]; res.clear(); - + std::vector<std::vector<unsigned> > cull2 = sweep_bounds(bnds[i], bnds[j]); for(unsigned k = 0; k < cull2.size(); k++) { for(unsigned lx = 0; lx < cull2[k].size(); lx++) { @@ -713,7 +713,7 @@ Crossings path_self_crossings(Path const &p) { mono_curve_intersect(p[i], spl[i][k-1], spl[i][k], p[j], spl[j][l-1], spl[j][l], res); } } - + //if(fabs(int(i)-j) == 1 || fabs(int(i)-j) == p.size()-1) { Crossings res2; for(unsigned k = 0; k < res.size(); k++) { @@ -742,7 +742,7 @@ Crossings self_crossings(Path const &p) { unsigned j = cull[i][jx]; res.clear(); pair_intersect(p[i], 0, 1, p[j], 0, 1, res); - + //if(fabs(int(i)-j) == 1 || fabs(int(i)-j) == p.size()-1) { Crossings res2; for(unsigned k = 0; k < res.size(); k++) { @@ -767,9 +767,9 @@ void flip_crossings(Crossings &crs) { CrossingSet crossings_among(std::vector<Path> const &p) { CrossingSet results(p.size(), Crossings()); if(p.empty()) return results; - + SimpleCrosser cc; - + std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds(p)); for(unsigned i = 0; i < cull.size(); i++) { Crossings res = self_crossings(p[i]); @@ -779,7 +779,7 @@ CrossingSet crossings_among(std::vector<Path> const &p) { merge_crossings(results[i], res, i); for(unsigned jx = 0; jx < cull[i].size(); jx++) { unsigned j = cull[i][jx]; - + Crossings res = cc.crossings(p[i], p[j]); for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = j; } merge_crossings(results[i], res, i); diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index c47902649..58d6b9b5e 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -46,8 +46,9 @@ namespace Geom OptRect Path::boundsFast() const { OptRect bounds; if (empty()) return bounds; - bounds=front().boundsFast(); + bounds = front().boundsFast(); const_iterator iter = begin(); + // the closing path segment can be ignored, because it will always lie within the bbox of the rest of the path if ( iter != end() ) { for ( ++iter; iter != end() ; ++iter ) { bounds.unionWith(iter->boundsFast()); @@ -59,8 +60,9 @@ OptRect Path::boundsFast() const { OptRect Path::boundsExact() const { OptRect bounds; if (empty()) return bounds; - bounds=front().boundsExact(); + bounds = front().boundsExact(); const_iterator iter = begin(); + // the closing path segment can be ignored, because it will always lie within the bbox of the rest of the path if ( iter != end() ) { for ( ++iter; iter != end() ; ++iter ) { bounds.unionWith(iter->boundsExact()); @@ -77,7 +79,7 @@ iter inc(iter const &x, unsigned n) { return ret; } -Path &Path::operator*=(Matrix const &m) { +Path &Path::operator*=(Affine const &m) { unshare(); Sequence::iterator last = get_curves().end() - 1; Sequence::iterator it; @@ -146,7 +148,7 @@ Path::allNearestPoints(Point const& _point, double from, double to) const Rect bb(Geom::Point(0,0),Geom::Point(0,0)); for ( unsigned int i = si + 1; i < ei; ++i ) { - bb = *(_path[i].boundsFast()); + bb = (_path[i].boundsFast()); dsq = distanceSq(_point, bb); if ( mindistsq < dsq ) continue; all_t = _path[i].allNearestPoints(_point); @@ -165,7 +167,7 @@ Path::allNearestPoints(Point const& _point, double from, double to) const ni.push_back(i); } } - bb = *(_path[ei].boundsFast()); + bb = (_path[ei].boundsFast()); dsq = distanceSq(_point, bb); if ( mindistsq >= dsq ) { @@ -203,7 +205,7 @@ Path::nearestPointPerCurve(Point const& _point) const { //return a single nearest point for each curve in this path std::vector<double> np; - for (const_iterator it = begin() ; it != end_default(); ++it) + for (const_iterator it = begin() ; it != end_default() ; ++it) //for (std::vector<Path>::const_iterator it = _path.begin(); it != _path.end(), ++it){ { np.push_back(it->nearestPoint(_point)); @@ -256,7 +258,7 @@ double Path::nearestPoint(Point const &_point, double from, double to, double *d Rect bb(Geom::Point(0,0),Geom::Point(0,0)); for ( unsigned int i = si + 1; i < ei; ++i ) { - bb = *(_path[i].boundsFast()); + bb = (_path[i].boundsFast()); dsq = distanceSq(_point, bb); if ( mindistsq <= dsq ) continue; t = _path[i].nearestPoint(_point); @@ -268,7 +270,7 @@ double Path::nearestPoint(Point const &_point, double from, double to, double *d mindistsq = dsq; } } - bb = *(_path[ei].boundsFast()); + bb = (_path[ei].boundsFast()); dsq = distanceSq(_point, bb); if ( mindistsq > dsq ) { diff --git a/src/2geom/path.h b/src/2geom/path.h index 3167bb09e..cbd449248 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -291,13 +291,13 @@ public: return !( *this == other ); } - Path operator*(Matrix const &m) const { + Path operator*(Affine const &m) const { Path ret(*this); ret *= m; return ret; } - Path &operator*=(Matrix const &m); + Path &operator*=(Affine const &m); Point pointAt(double t) const { diff --git a/src/2geom/pathvector.cpp b/src/2geom/pathvector.cpp index 3d11dd48b..fc0ad75c4 100644 --- a/src/2geom/pathvector.cpp +++ b/src/2geom/pathvector.cpp @@ -38,7 +38,7 @@ #include <2geom/pathvector.h> #include <2geom/path.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> namespace Geom { diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index a531cc955..2f45b9d86 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -3,7 +3,8 @@ * \brief PathVector - std::vector containing Geom::Path * This file provides a set of operations that can be performed on PathVector, * e.g. an affine transform. - * + */ +/* * Authors: * Johan Engelen <goejendaagh@zonnet.nl> * @@ -46,13 +47,13 @@ typedef std::vector<Geom::Path> PathVector; /* general path transformation: */ inline -void operator*= (PathVector & path_in, Matrix const &m) { +void operator*= (PathVector & path_in, Affine const &m) { for(PathVector::iterator it = path_in.begin(); it != path_in.end(); ++it) { (*it) *= m; } } inline -PathVector operator*(PathVector const & path_in, Matrix const &m) { +PathVector operator*(PathVector const & path_in, Affine const &m) { PathVector ret(path_in); ret *= m; return ret; diff --git a/src/2geom/piecewise.cpp b/src/2geom/piecewise.cpp index fcecc13c1..ba1e60ea3 100644 --- a/src/2geom/piecewise.cpp +++ b/src/2geom/piecewise.cpp @@ -154,6 +154,54 @@ int compose_findSegIdx(std::map<double,unsigned>::iterator const &cut, return idx; } + +Piecewise<SBasis> pw_compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero){ + Piecewise<SBasis> result; + + assert( f.size()>0 && g.size()>0); + SBasis g01 = g; + bool flip = ( g01.at0() > g01.at1() ); + + //OptInterval g_range = bounds_exact(g); + OptInterval g_range( Interval( g.at0(), g.at1() )); + + g01 -= g_range->min(); + g01 /= g_range->extent(); + if ( flip ){ + g01 *= -1.; + g01 += 1.; + } +#if 1 + assert( std::abs( g01.at0() - 0. ) < zero ); + assert( std::abs( g01.at1() - 1. ) < zero ); + //g[0][0] = 0.; + //g[0][1] = 1.; +#endif + + SBasis foginv = compose_inverse( f, g01, order, zero ); + SBasis err = compose( foginv, g01) - f; + + if ( err.tailError(0) < zero ){ + result = Piecewise<SBasis> (foginv); + }else{ + SBasis g_portion = portion( g01, Interval(0.,.5) ); + SBasis f_portion = portion( f, Interval(0.,.5) ); + result = pw_compose_inverse(f_portion, g_portion, order, zero); + + g_portion = portion( g01, Interval(.5, 1.) ); + f_portion = portion( f, Interval(.5, 1.) ); + Piecewise<SBasis> result_next; + result_next = pw_compose_inverse(f_portion, g_portion, order, zero); + result.concat( result_next ); + } + if (flip) { + result = reverse(result); + } + result.setDomain(*g_range); + return result; +} + + std::vector<double> roots(Piecewise<SBasis> const &f){ std::vector<double> result; for (unsigned i=0; i<f.size(); i++){ @@ -179,6 +227,32 @@ std::vector<std::vector<double> > multi_roots(Piecewise<SBasis> const &f, std::v return result; } + +std::vector<Interval> level_set(Piecewise<SBasis> const &f, Interval const &level, double tol){ + std::vector<Interval> result; + for (unsigned i=0; i<f.size(); i++){ + std::vector<Interval> resulti = level_set( f[i], level, 0., 1., tol); + for (unsigned j=0; j<resulti.size(); j++){ + double a = f.cuts[i] + resulti[j].min() * ( f.cuts[i+1] - f.cuts[i] ); + double b = f.cuts[i] + resulti[j].max() * ( f.cuts[i+1] - f.cuts[i] ); + Interval domj( a, b ); + //Interval domj( f.mapToDomain(resulti[j].min(), i ), f.mapToDomain(resulti[j].max(), i ) ); + + if ( j==0 && result.size() > 0 && result.back().intersects(domj) ){ + result.back().unionWith(domj); + }else{ + result.push_back(domj); + } + } + } + return result; +} +std::vector<Interval> level_set(Piecewise<SBasis> const &f, double v, double vtol, double tol){ + Interval level ( v-vtol, v+vtol ); + return level_set( f, level, tol); +} + + } /* Local Variables: diff --git a/src/2geom/piecewise.h b/src/2geom/piecewise.h index 62185b472..19c66d8f0 100644 --- a/src/2geom/piecewise.h +++ b/src/2geom/piecewise.h @@ -265,6 +265,11 @@ class Piecewise { }; +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> inline typename FragmentConcept<T>::BoundsType bounds_fast(const Piecewise<T> &f) { boost::function_requires<FragmentConcept<T> >(); @@ -276,6 +281,11 @@ inline typename FragmentConcept<T>::BoundsType bounds_fast(const Piecewise<T> &f return ret; } +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> inline typename FragmentConcept<T>::BoundsType bounds_exact(const Piecewise<T> &f) { boost::function_requires<FragmentConcept<T> >(); @@ -287,6 +297,11 @@ inline typename FragmentConcept<T>::BoundsType bounds_exact(const Piecewise<T> & return ret; } +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> inline typename FragmentConcept<T>::BoundsType bounds_local(const Piecewise<T> &f, const OptInterval &_m) { boost::function_requires<FragmentConcept<T> >(); @@ -308,7 +323,10 @@ inline typename FragmentConcept<T>::BoundsType bounds_local(const Piecewise<T> & return ret; } -//returns a portion of a piece of a Piecewise<T>, given the piece's index and a to/from time. +/** + * Returns a portion of a piece of a Piecewise<T>, given the piece's index and a to/from time. + * \relates Piecewise + */ template<typename T> T elem_portion(const Piecewise<T> &a, unsigned i, double from, double to) { assert(i < a.size()); @@ -324,6 +342,8 @@ T elem_portion(const Piecewise<T> &a, unsigned i, double from, double to) { * Piecewise<T> ac = a.partition(b.cuts); * Piecewise<T> bc = b.partition(a.cuts); * //ac.cuts should be equivalent to bc.cuts + * + * \relates Piecewise */ template<typename T> Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c) { @@ -389,8 +409,9 @@ Piecewise<T> partition(const Piecewise<T> &pw, std::vector<double> const &c) { return ret; } -/**Piecewise<T> portion(const Piecewise<T> &pw, double from, double to); - * Returns a Piecewise<T> with a defined domain of [min(from, to), max(from, to)]. +/** + * Returns a Piecewise<T> with a defined domain of [min(from, to), max(from, to)]. + * \relates Piecewise */ template<typename T> Piecewise<T> portion(const Piecewise<T> &pw, double from, double to) { @@ -424,6 +445,11 @@ Piecewise<T> portion(const Piecewise<T> &pw, double from, double to) { } //TODO: seems like these should be mutating +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> Piecewise<T> remove_short_cuts(Piecewise<T> const &f, double tol) { if(f.empty()) return f; @@ -439,6 +465,11 @@ Piecewise<T> remove_short_cuts(Piecewise<T> const &f, double tol) { } //TODO: seems like these should be mutating +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> Piecewise<T> remove_short_cuts_extending(Piecewise<T> const &f, double tol) { if(f.empty()) return f; @@ -455,6 +486,11 @@ Piecewise<T> remove_short_cuts_extending(Piecewise<T> const &f, double tol) { return ret; } +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> std::vector<double> roots(const Piecewise<T> &pw) { std::vector<double> ret; @@ -467,6 +503,11 @@ std::vector<double> roots(const Piecewise<T> &pw) { } //IMPL: OffsetableConcept +/** + * ... + * \return \f$ a + b = \f$ + * \relates Piecewise + */ template<typename T> Piecewise<T> operator+(Piecewise<T> const &a, typename T::output_type b) { boost::function_requires<OffsetableConcept<T> >(); @@ -511,6 +552,11 @@ Piecewise<T>& operator-=(Piecewise<T>& a, typename T::output_type b) { } //IMPL: ScalableConcept +/** + * ... + * \return \f$ -a = \f$ + * \relates Piecewise + */ template<typename T> Piecewise<T> operator-(Piecewise<T> const &a) { boost::function_requires<ScalableConcept<T> >(); @@ -522,6 +568,11 @@ Piecewise<T> operator-(Piecewise<T> const &a) { ret.push_seg(- a[i]); return ret; } +/** + * ... + * \return \f$ a * b = \f$ + * \relates Piecewise + */ template<typename T> Piecewise<T> operator*(Piecewise<T> const &a, double b) { boost::function_requires<ScalableConcept<T> >(); @@ -535,6 +586,11 @@ Piecewise<T> operator*(Piecewise<T> const &a, double b) { ret.push_seg(a[i] * b); return ret; } +/** + * ... + * \return \f$ a * b = \f$ + * \relates Piecewise + */ template<typename T> Piecewise<T> operator*(Piecewise<T> const &a, T b) { boost::function_requires<ScalableConcept<T> >(); @@ -548,6 +604,11 @@ Piecewise<T> operator*(Piecewise<T> const &a, T b) { ret.push_seg(a[i] * b); return ret; } +/** + * ... + * \return \f$ a / b = \f$ + * \relates Piecewise + */ template<typename T> Piecewise<T> operator/(Piecewise<T> const &a, double b) { boost::function_requires<ScalableConcept<T> >(); @@ -582,6 +643,11 @@ Piecewise<T>& operator/=(Piecewise<T>& a, double b) { } //IMPL: AddableConcept +/** + * ... + * \return \f$ a + b = \f$ + * \relates Piecewise + */ template<typename T> Piecewise<T> operator+(Piecewise<T> const &a, Piecewise<T> const &b) { boost::function_requires<AddableConcept<T> >(); @@ -595,6 +661,11 @@ Piecewise<T> operator+(Piecewise<T> const &a, Piecewise<T> const &b) { ret.push_seg(pa[i] + pb[i]); return ret; } +/** + * ... + * \return \f$ a - b = \f$ + * \relates Piecewise + */ template<typename T> Piecewise<T> operator-(Piecewise<T> const &a, Piecewise<T> const &b) { boost::function_requires<AddableConcept<T> >(); @@ -619,6 +690,11 @@ inline Piecewise<T>& operator-=(Piecewise<T> &a, Piecewise<T> const &b) { return a; } +/** + * ... + * \return \f$ a \cdot b = \f$ + * \relates Piecewise + */ template<typename T1,typename T2> Piecewise<T2> operator*(Piecewise<T1> const &a, Piecewise<T2> const &b) { //function_requires<MultiplicableConcept<T1> >(); @@ -635,6 +711,11 @@ Piecewise<T2> operator*(Piecewise<T1> const &a, Piecewise<T2> const &b) { return ret; } +/** + * ... + * \return \f$ a \cdot b \f$ + * \relates Piecewise + */ template<typename T> inline Piecewise<T>& operator*=(Piecewise<T> &a, Piecewise<T> const &b) { a = a * b; @@ -661,9 +742,14 @@ int compose_findSegIdx(std::map<double,unsigned>::iterator const &cut, std::vector<double> const &levels, SBasis const &g); -//TODO: add concept check +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> Piecewise<T> compose(Piecewise<T> const &f, SBasis const &g){ + /// \todo add concept check Piecewise<T> result; if (f.empty()) return result; if (g.isZero()) return Piecewise<T>(f(0)); @@ -707,9 +793,14 @@ Piecewise<T> compose(Piecewise<T> const &f, SBasis const &g){ return(result); } -//TODO: add concept check for following composition functions +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> Piecewise<T> compose(Piecewise<T> const &f, Piecewise<SBasis> const &g){ +/// \todo add concept check Piecewise<T> result; for(unsigned i = 0; i < g.segs.size(); i++){ Piecewise<T> fgi=compose(f, g.segs[i]); @@ -721,6 +812,7 @@ Piecewise<T> compose(Piecewise<T> const &f, Piecewise<SBasis> const &g){ /* Piecewise<D2<SBasis> > compose(D2<SBasis2d> const &sb2d, Piecewise<D2<SBasis> > const &pwd2sb){ +/// \todo add concept check Piecewise<D2<SBasis> > result; result.push_cut(0.); for(unsigned i = 0; i < pwd2sb.size(); i++){ @@ -729,11 +821,26 @@ Piecewise<D2<SBasis> > compose(D2<SBasis2d> const &sb2d, Piecewise<D2<SBasis> > return result; }*/ +/** Compose an SBasis with the inverse of another. + * WARNING: It's up to the user to check that the second SBasis is indeed + * invertible (i.e. strictly increasing or decreasing). + * \return \f$ f \cdot g^{-1} \f$ + * \relates Piecewise + */ +Piecewise<SBasis> pw_compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double zero); + + + template <typename T> Piecewise<T> Piecewise<T>::operator()(SBasis f){return compose((*this),f);} template <typename T> Piecewise<T> Piecewise<T>::operator()(Piecewise<SBasis>f){return compose((*this),f);} +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> Piecewise<T> integral(Piecewise<T> const &a) { Piecewise<T> result; @@ -748,6 +855,11 @@ Piecewise<T> integral(Piecewise<T> const &a) { return result; } +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> Piecewise<T> derivative(Piecewise<T> const &a) { Piecewise<T> result; @@ -763,6 +875,19 @@ std::vector<double> roots(Piecewise<SBasis> const &f); std::vector<std::vector<double> >multi_roots(Piecewise<SBasis> const &f, std::vector<double> const &values); +//TODO: implement level_sets directly for pwsb instead of sb (and derive it fo sb). +//It should be faster than the reverse as the algorithm may jump over full cut intervals. +std::vector<Interval> level_set(Piecewise<SBasis> const &f, Interval const &level, double tol=1e-5); +std::vector<Interval> level_set(Piecewise<SBasis> const &f, double v, double vtol, double tol=1e-5); +//std::vector<Interval> level_sets(Piecewise<SBasis> const &f, std::vector<Interval> const &levels, double tol=1e-5); +//std::vector<Interval> level_sets(Piecewise<SBasis> const &f, std::vector<double> &v, double vtol, double tol=1e-5); + + +/** + * ... + * \return ... + * \relates Piecewise + */ template<typename T> Piecewise<T> reverse(Piecewise<T> const &f) { Piecewise<T> ret = Piecewise<T>(); diff --git a/src/2geom/point.cpp b/src/2geom/point.cpp index 45e035d4a..a9005ef61 100644 --- a/src/2geom/point.cpp +++ b/src/2geom/point.cpp @@ -1,25 +1,46 @@ -#include <2geom/point.h> #include <assert.h> -#include <2geom/coord.h> -#include <2geom/isnan.h> //temporary fix for isnan() +#include <math.h> +#include <2geom/point.h> #include <2geom/transforms.h> namespace Geom { -/** \brief Scales this vector to make it a unit vector (within rounding error). +/** + * @class Point + * @brief Two-dimensional point that doubles as a vector. + * + * Points in 2Geom are represented in Cartesian coordinates, e.g. as a pair of numbers + * that store the X and Y coordinates. Each point is also a vector in \f$\mathbb{R}^2\f$ + * from the origin (point at 0,0) to the stored coordinates, + * and has methods implementing several vector operations (like length()). * - * The current version tries to handle infinite coordinates gracefully, - * but it's not clear that any callers need that. + * \par Operator note + * \par + * Most operators are provided by Boost operator helpers, so they are not visible in this class. + * If @a p, @a q, @a r denote points, @a s a floating-point scalar, and @a m a transformation matrix, + * then the following operations are available: + * @code + p += q; p -= q; r = p + q; r = p - q; + p *= s; p /= s; q = p * s; q = s * p; q = p / s; + p *= m; p /= m; q = p * m; q = m * p; q = p / m; + @endcode + * It is possible to left-multiply a point by a matrix, even though mathematically speaking + * this is undefined. The result is a point identical to that obtained by right-multiplying. + * Division of points by matrices is defined as multiplication by their inverses. * - * \pre \f$this \neq (0, 0)\f$ - * \pre Neither component is NaN. - * \post \f$-\epsilon<\left|this\right|-1<\epsilon\f$ - */ + * @ingroup Primitives */ + +/** @brief Normalize the vector representing the point. + * After this method returns, the length of the vector will be 1 (unless both coordinates are + * zero - the zero point will be returned then). The function tries to handle infinite + * coordinates gracefully. If any of the coordinates are NaN, the function will do nothing. + * @post \f$-\epsilon < \left|this\right| - 1 < \epsilon\f$ + * @see unit_vector(Geom::Point const &) */ void Point::normalize() { double len = hypot(_pt[0], _pt[1]); if(len == 0) return; if(IS_NAN(len)) return; - static double const inf = 1e400; + static double const inf = HUGE_VAL; if(len != inf) { *this /= len; } else { @@ -58,7 +79,10 @@ void Point::normalize() { } } -/** Compute the L1 norm, or manhattan distance, of \a p. */ +/** @brief Compute the first norm (Manhattan distance) of @a p. + * This is equal to the sum of absolutes values of the coordinates. + * @return \f$|p_X| + |p_Y|\f$ + * @relates Point */ Coord L1(Point const &p) { Coord d = 0; for ( int i = 0 ; i < 2 ; i++ ) { @@ -67,7 +91,9 @@ Coord L1(Point const &p) { return d; } -/** Compute the L infinity, or maximum, norm of \a p. */ +/** @brief Compute the infinity norm (maximum norm) of @a p. + * @return \f$\max(p_X, p_Y)\f$ + * @relates Point */ Coord LInfty(Point const &p) { Coord const a(fabs(p[0])); Coord const b(fabs(p[1])); @@ -76,80 +102,89 @@ Coord LInfty(Point const &p) { : a ); } -/** Returns true iff p is a zero vector, i.e.\ Point(0, 0). - * - * (NaN is considered non-zero.) - */ -bool -is_zero(Point const &p) -{ +/** @brief True if the point has both coordinates zero. + * NaNs are treated as not equal to zero. + * @relates Point */ +bool is_zero(Point const &p) { return ( p[0] == 0 && p[1] == 0 ); } -bool -is_unit_vector(Point const &p) -{ - return fabs(1.0 - L2(p)) <= 1e-4; - /* The tolerance of 1e-4 is somewhat arbitrary. Point::normalize is believed to return - points well within this tolerance. I'm not aware of any callers that want a small - tolerance; most callers would be ok with a tolerance of 0.25. */ +/** @brief True if the point has a length near 1. The are_near() function is used. + * @relates Point */ +bool is_unit_vector(Point const &p) { + return are_near(L2(p), 1.0); } - -Coord atan2(Point const p) { +/** @brief Return the angle between the point and the +X axis. + * @return Angle in \f$(-\pi, \pi]\f$. + * @relates Point */ +Coord atan2(Point const &p) { return std::atan2(p[Y], p[X]); } -/** compute the angle turning from a to b. This should give \f$\pi/2\f$ for angle_between(a, rot90(a)); - * This works by projecting b onto the basis defined by a, rot90(a) - */ -Coord angle_between(Point const a, Point const b) { +/** @brief Compute the angle between a and b relative to the origin. + * The computation is done by projecting b onto the basis defined by a, rot90(a). + * @return Angle in \f$(-\pi, \pi]\f$. + * @relates Point */ +Coord angle_between(Point const &a, Point const &b) { return std::atan2(cross(b,a), dot(b,a)); } - - -/** Returns a version of \a a scaled to be a unit vector (within rounding error). - * - * The current version tries to handle infinite coordinates gracefully, - * but it's not clear that any callers need that. - * - * \pre a != Point(0, 0). - * \pre Neither coordinate is NaN. - * \post L2(ret) very near 1.0. - */ +/** @brief Create a normalized version of a point. + * This is equivalent to copying the point and calling its normalize() method. + * The returned point will be (0,0) if the argument has both coordinates equal to zero. + * If any coordinate is NaN, this function will do nothing. + * @param a Input point + * @return Point on the unit circle in the same direction from origin as a, or the origin + * if a has both coordinates equal to zero + * @relates Point */ Point unit_vector(Point const &a) { Point ret(a); ret.normalize(); return ret; } - +/** @brief Return the "absolute value" of the point's vector. + * This is defined in terms of the default lexicographical ordering. If the point is "larger" + * that the origin (0, 0), its negation is returned. You can check whether + * the points' vectors have the same direction (e.g. lie + * on the same line passing through the origin) using + * @code abs(a).normalize() == abs(b).normalize() @endcode. + * To check with some margin of error, use + * @code are_near(abs(a).normalize(), abs(b).normalize()) @endcode. + * Although naively this should take the absolute value of each coordinate, such an operation + * is not very useful. + * @return \f$p' = (p_X, -p_Y)\f$ + * @relates Point */ Point abs(Point const &b) { Point ret; - for ( int i = 0 ; i < 2 ; i++ ) { - ret[i] = fabs(b[i]); + if (b[Y] < 0.0) { + ret = -b; + } else if (b[Y] == 0.0) { + ret = b[X] < 0.0 ? -b : b; + } else { + ret = b; } return ret; } -Point operator*(Point const &v, Matrix const &m) { - Point ret; +/** @brief Transform the point by the specified matrix. */ +Point &Point::operator*=(Affine const &m) { + double x = _pt[X], y = _pt[Y]; for(int i = 0; i < 2; i++) { - ret[i] = v[X] * m[i] + v[Y] * m[i + 2] + m[i + 4]; + _pt[i] = x * m[i] + y * m[i + 2] + m[i + 4]; } - return ret; -} - -Point operator/(Point const &p, Matrix const &m) { return p * m.inverse(); } - -Point &Point::operator*=(Matrix const &m) -{ - *this = *this * m; return *this; } +/** @brief Snap the angle B - A - dir to miltiples of \f$2\pi/n\f$. + * The 'dir' argument must be normalized (have an unit length), otherwise the result + * is undefined. + * @return Point with the same distance from A as B, with a snapped angle. + * @post distance(A, B) == distance(A, result) + * @post angle_between(result - A, dir) == \f$2k\pi/n, k \in \mathbb{N}\f$ + * @relates Point */ Point constrain_angle(Point const &A, Point const &B, unsigned int n, Point const &dir) { // for special cases we could perhaps use explicit testing (which might be faster) diff --git a/src/2geom/point.h b/src/2geom/point.h index 562950525..3c6e12eff 100644 --- a/src/2geom/point.h +++ b/src/2geom/point.h @@ -1,241 +1,368 @@ -#ifndef SEEN_Geom_POINT_H -#define SEEN_Geom_POINT_H - /** * \file - * \brief Defines a Cartesian 2D Point class. + * \brief Cartesian point / 2D vector and related operations + *//* + * Authors: + * Michael G. Sloan <mgsloan@gmail.com> + * Nathan Hurst <njh@njhurst.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright (C) 2006-2009 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. */ -#include <iostream> +#ifndef SEEN_Geom_POINT_H +#define SEEN_Geom_POINT_H +#include "config.h" +#include <iostream> +#include <iterator> +#include <boost/operators.hpp> +#include <2geom/forward.h> #include <2geom/coord.h> -#include <2geom/isnan.h> +#include <2geom/isnan.h> //temporary fix for isnan() +#include <2geom/math-utils.h> #include <2geom/utils.h> namespace Geom { -enum Dim2 { X=0, Y=1 }; - -class Matrix; - -/// Cartesian 2D point. -class Point { +class Point + : boost::additive< Point + , boost::totally_ordered< Point + , boost::multiplicative< Point, Coord + , MultipliableNoncommutative< Point, Affine + , MultipliableNoncommutative< Point, Translate + , MultipliableNoncommutative< Point, Rotate + , MultipliableNoncommutative< Point, Scale + , MultipliableNoncommutative< Point, HShear + , MultipliableNoncommutative< Point, VShear + > > > > > > > > > // this uses chaining so it looks weird, but works +{ Coord _pt[2]; - public: - /// The default constructor creates an Point(0,0) DO NOT RELY ON THIS, BEST NOT TO USE THIS CONSTRUCTOR - inline Point() +public: + /** Construct a point on the origin. */ + Point() { _pt[X] = _pt[Y] = 0; } - inline Point(Coord x, Coord y) { + /** Construct a point from its coordinates. */ + Point(Coord x, Coord y) { _pt[X] = x; _pt[Y] = y; } - - inline Point(Point const &p) { + Point(Point const &p) { for (unsigned i = 0; i < 2; ++i) _pt[i] = p._pt[i]; } - - inline Point &operator=(Point const &p) { + Point &operator=(Point const &p) { for (unsigned i = 0; i < 2; ++i) _pt[i] = p._pt[i]; return *this; } - inline Coord operator[](unsigned i) const { return _pt[i]; } - inline Coord &operator[](unsigned i) { return _pt[i]; } + /// @name Access the coordinates of a point + /// @{ + Coord operator[](unsigned i) const { return _pt[i]; } + Coord &operator[](unsigned i) { return _pt[i]; } Coord operator[](Dim2 d) const throw() { return _pt[d]; } Coord &operator[](Dim2 d) throw() { return _pt[d]; } + /// @} - static inline Point polar(Coord angle, Coord radius) { - return Point(radius * std::cos(angle), radius * std::sin(angle)); - } - - inline Coord length() const { return hypot(_pt[0], _pt[1]); } + /// @name Vector operations + /// @{ + /** @brief Compute the distance from origin. + * @return Length of the vector from origin to this point */ + Coord length() const { return hypot(_pt[0], _pt[1]); } + void normalize(); - /** Return a point like this point but rotated -90 degrees. - (If the y axis grows downwards and the x axis grows to the - right, then this is 90 degrees counter-clockwise.) - **/ + /** @brief Return a point like this point but rotated -90 degrees. + * If the y axis grows downwards and the x axis grows to the + * right, then this is 90 degrees counter-clockwise. */ Point ccw() const { return Point(_pt[Y], -_pt[X]); } - /** Return a point like this point but rotated +90 degrees. - (If the y axis grows downwards and the x axis grows to the - right, then this is 90 degrees clockwise.) - **/ + /** @brief Return a point like this point but rotated +90 degrees. + * If the y axis grows downwards and the x axis grows to the + * right, then this is 90 degrees clockwise. */ Point cw() const { return Point(-_pt[Y], _pt[X]); } + /// @} - /** - \brief A function to lower the precision of the point - \param places The number of decimal places that should be in - the final number. - */ - inline void round (int places = 0) { - _pt[X] = (Coord)(decimal_round((double)_pt[X], places)); - _pt[Y] = (Coord)(decimal_round((double)_pt[Y], places)); - return; - } - - void normalize(); - - inline bool isFinite() const { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - if(!IS_FINITE(_pt[i])) return false; - } - return true; - } - - inline Point operator+(Point const &o) const { - return Point(_pt[X] + o._pt[X], _pt[Y] + o._pt[Y]); - } - inline Point operator-(Point const &o) const { - return Point(_pt[X] - o._pt[X], _pt[Y] - o._pt[Y]); + /// @name Vector-like arithmetic operations + /// @{ + Point operator-() const { + return Point(-_pt[X], -_pt[Y]); } - inline Point &operator+=(Point const &o) { + Point &operator+=(Point const &o) { for ( unsigned i = 0 ; i < 2 ; ++i ) { _pt[i] += o._pt[i]; } return *this; } - inline Point &operator-=(Point const &o) { + Point &operator-=(Point const &o) { for ( unsigned i = 0 ; i < 2 ; ++i ) { _pt[i] -= o._pt[i]; } return *this; } - - inline Point operator-() const { - return Point(-_pt[X], -_pt[Y]); - } - inline Point operator*(double const s) const { - return Point(_pt[X] * s, _pt[Y] * s); - } - inline Point operator/(double const s) const { - //TODO: s == 0? - return Point(_pt[X] / s, _pt[Y] / s); - } - inline Point &operator*=(double const s) { + Point &operator*=(Coord s) { for ( unsigned i = 0 ; i < 2 ; ++i ) _pt[i] *= s; return *this; } - inline Point &operator/=(double const s) { + Point &operator/=(Coord s) { //TODO: s == 0? for ( unsigned i = 0 ; i < 2 ; ++i ) _pt[i] /= s; return *this; } + /// @} + + /// @name Affine transformations + /// @{ + Point &operator*=(Affine const &m); + // implemented in transforms.cpp + Point &operator*=(Translate const &t); + Point &operator*=(Scale const &s); + Point &operator*=(Rotate const &r); + Point &operator*=(HShear const &s); + Point &operator*=(VShear const &s); + /** @brief Transform the point by the inverse of the specified matrix. */ + template <typename T> + Point &operator/=(T const &m) { + *this *= m.inverse(); + return *this; + } + /// @} + + /// @name Various utilities + /// @{ + /** @brief Lower the precision of the point. + * This will round both coordinates to multiples of \f$10^p\f$. */ + void round (int p = 0) { + _pt[X] = (Coord)(decimal_round((double)_pt[X], p)); + _pt[Y] = (Coord)(decimal_round((double)_pt[Y], p)); + return; + } - Point &operator*=(Matrix const &m); - - inline int operator == (const Point &in_pnt) { + /** @brief Check whether both coordinates are finite. + * @return True if neither coordinate is infinite. */ + bool isFinite() const { + for ( unsigned i = 0 ; i < 2 ; ++i ) { + if(!IS_FINITE(_pt[i])) return false; + } + return true; + } + /** @brief Equality operator. + * This tests for exact identity (as opposed to are_near()). Note that due to numerical + * errors, this test might return false even if the points should be identical. */ + bool operator==(const Point &in_pnt) const { return ((_pt[X] == in_pnt[X]) && (_pt[Y] == in_pnt[Y])); } + /** @brief Lexicographical ordering for points. + * Y coordinate is regarded as more significant. When sorting according to this + * ordering, the points will be sorted according to the Y coordinate, and within + * points with the same Y coordinate according to the X coordinate. */ + bool operator<(const Point &p) const { + return ( ( _pt[Y] < p[Y] ) || + (( _pt[Y] == p[Y] ) && ( _pt[X] < p[X] ))); + } + /// @} + + /// @name Point factories + /// @{ + /** @brief Construct a point from its polar coordinates. + * The angle is specified in radians, in the mathematical convention (increasing + * counter-clockwise from +X). */ + static Point polar(Coord angle, Coord radius) { + Point ret(polar(angle)); + ret *= radius; + return ret; + } + /** @brief Construct an unit vector from its angle. + * The angle is specified in radians, in the mathematical convention (increasing + * counter-clockwise from +X). */ + static Point polar(Coord angle) { + Point ret; + sincos(angle, ret[Y], ret[X]); + return ret; + } + /// @} + + /** @brief Lexicographical ordering functor. */ + template <Dim2 d> struct LexOrder; + /** @brief Lexicographical ordering functor with runtime dimension. */ + class LexOrderRt { + public: + LexOrderRt(Dim2 d) : dim(d) {} + inline bool operator()(Point const &a, Point const &b); + private: + Dim2 dim; + }; friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt); }; -inline Point operator*(double const s, Point const &p) { return p * s; } - -/** A function to print out the Point. It just prints out the coords - on the given output stream */ +/** @brief Output operator for points. + * Prints out the coordinates. + * @relates Point */ inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt) { out_file << "X: " << in_pnt[X] << " Y: " << in_pnt[Y]; return out_file; } -/** This is a rotation (sort of). */ -inline Point operator^(Point const &a, Point const &b) { - Point const ret(a[0] * b[0] - a[1] * b[1], - a[1] * b[0] + a[0] * b[1]); - return ret; +template<> struct Point::LexOrder<X> { + bool operator()(Point const &a, Point const &b) { + return a[X] < b[X] || (a[X] == b[X] && a[Y] < b[Y]); + } +}; +template<> struct Point::LexOrder<Y> { + bool operator()(Point const &a, Point const &b) { + return a[Y] < b[Y] || (a[Y] == b[Y] && a[X] < b[X]); + } +}; +inline bool Point::LexOrderRt::operator()(Point const &a, Point const &b) { + return dim ? Point::LexOrder<Y>()(a, b) : Point::LexOrder<X>()(a, b); } -//IMPL: boost::EqualityComparableConcept -inline bool operator==(Point const &a, Point const &b) { - return (a[X] == b[X]) && (a[Y] == b[Y]); -} -inline bool operator!=(Point const &a, Point const &b) { - return (a[X] != b[X]) || (a[Y] != b[Y]); +/** @brief Compute the second (Euclidean) norm of @a p. + * This corresponds to the length of @a p. The result will not overflow even if + * \f$p_X^2 + p_Y^2\f$ is larger that the maximum value that can be stored + * in a <code>double</code>. + * @return \f$\sqrt{p_X^2 + p_Y^2}\f$ + * @relates Point */ +inline Coord L2(Point const &p) +{ + return p.length(); } -/** This is a lexicographical ordering for points. It is remarkably useful for sweepline algorithms*/ -inline bool operator<=(Point const &a, Point const &b) { - return ( ( a[Y] < b[Y] ) || - (( a[Y] == b[Y] ) && ( a[X] < b[X] ))); +/** @brief Compute the square of the Euclidean norm of @a p. + * Warning: this can overflow where L2 won't. + * @return \f$p_X^2 + p_Y^2\f$ + * @relates Point */ +inline Coord L2sq(Point const &p) +{ + return p[0]*p[0] + p[1]*p[1]; } -Coord L1(Point const &p); - -/** Compute the L2, or euclidean, norm of \a p. */ -inline Coord L2(Point const &p) { return p.length(); } - -/** Compute the square of L2 norm of \a p. Warning: this can overflow where L2 won't.*/ -inline Coord L2sq(Point const &p) { return p[0]*p[0] + p[1]*p[1]; } - -double LInfty(Point const &p); -bool is_zero(Point const &p); -bool is_unit_vector(Point const &p); - -extern double atan2(Point const p); -/** compute the angle turning from a to b (signed). */ -extern double angle_between(Point const a, Point const b); - //IMPL: NearConcept -inline bool are_near(Point const &a, Point const &b, double const eps=EPSILON) { +/** @brief Nearness predicate for points. + * True if neither coordinate of @a a is further than @a eps from the corresponding + * coordinate of @a b. + * @relates Point */ +inline bool are_near(Point const &a, Point const &b, double const eps=EPSILON) +{ return ( are_near(a[X],b[X],eps) && are_near(a[Y],b[Y],eps) ); } -inline -Point middle_point(Point const& P1, Point const& P2) +/** @brief Return a point halfway between the specified ones. + * @relates Point */ +inline Point middle_point(Point const& P1, Point const& P2) { return (P1 + P2) / 2; } -/** Returns p * Geom::rotate_degrees(90), but more efficient. +/** @brief Returns p * Geom::rotate_degrees(90), but more efficient. * - * Angle direction in Inkscape code: If you use the traditional mathematics convention that y + * Angle direction in 2Geom: If you use the traditional mathematics convention that y * increases upwards, then positive angles are anticlockwise as per the mathematics convention. If * you take the common non-mathematical convention that y increases downwards, then positive angles * are clockwise, as is common outside of mathematics. * - * There is no rot_neg90 function: use -rot90(p) instead. - */ -inline Point rot90(Point const &p) { return Point(-p[Y], p[X]); } + * There is no function to rotate by -90 degrees: use -rot90(p) instead. + * @relates Point */ +inline Point rot90(Point const &p) +{ + return Point(-p[Y], p[X]); +} -/** Given two points and a parameter t \in [0, 1], return a point - * proportionally from a to b by t. Akin to 1 degree bezier.*/ -inline Point lerp(double const t, Point const a, Point const b) { return (a * (1 - t) + b * t); } +/** @brief Linear interpolation between two points. + * @param t Time value + * @param a First point + * @param b Second point + * @return Point on a line between a and b. The ratio of its distance from a + * and the distance between a and b will be equal to t. + * @relates Point */ +inline Point lerp(double const t, Point const &a, Point const &b) +{ + return (a * (1 - t) + b * t); +} -Point unit_vector(Point const &a); +/** @brief Compute the dot product of a and b. + * Dot product can be interpreted as a measure of how parallel the vectors are. + * For perpendicular vectors, it is zero. For parallel ones, its absolute value is highest, + * and the sign depends on whether they point in the same direction (+) or opposite ones (-). + * @return \f$a \cdot b = a_X b_X + a_Y b_Y\f$. + * @relates Point*/ +inline Coord dot(Point const &a, Point const &b) +{ + return a[0] * b[0] + a[1] * b[1]; +} -/** compute the dot product (inner product) between the vectors a and b. */ -inline Coord dot(Point const &a, Point const &b) { return a[0] * b[0] + a[1] * b[1]; } -/** Defined as dot(a, b.cw()). */ -inline Coord cross(Point const &a, Point const &b) { return dot(a, b.cw()); } +/** @brief Compute the 2D cross product. + * Defined as dot(a, b.cw()). This means it will be zero for parallel vectors, + * and its absolute value highest for perpendicular vectors. + * @relates Point*/ +inline Coord cross(Point const &a, Point const &b) +{ + return dot(a, b.cw()); +} -/** compute the euclidean distance between points a and b. TODO: hypot safer/faster? */ -inline Coord distance (Point const &a, Point const &b) { return L2(a - b); } +/** @brief Compute the (Euclidean) distance between points. + * @relates Point */ +inline Coord distance (Point const &a, Point const &b) +{ + return L2(a - b); +} -/** compute the square of the distance between points a and b. */ -inline Coord distanceSq (Point const &a, Point const &b) { return L2sq(a - b); } +/** @brief Compute the square of the distance between points. + * @relates Point */ +inline Coord distanceSq (Point const &a, Point const &b) +{ + return L2sq(a - b); +} +Point unit_vector(Point const &a); +Coord L1(Point const &p); +Coord LInfty(Point const &p); +bool is_zero(Point const &p); +bool is_unit_vector(Point const &p); +extern double atan2(Point const &p); +extern double angle_between(Point const &a, Point const &b); Point abs(Point const &b); - -Point operator*(Point const &v, Matrix const &m); - -Point operator/(Point const &p, Matrix const &m); - -/** Constrains the angle (with respect to dir) of the line - * joining A and B to a multiple of pi/n. - */ Point constrain_angle(Point const &A, Point const &B, unsigned int n = 4, Geom::Point const &dir = Geom::Point(1,0)); } /* namespace Geom */ +// This is required to fix a bug in GCC 4.3.3 (and probably others) that causes the compiler +// to try to instantiate the iterator_traits template and fail. Probably it thinks that Point +// is an iterator and tries to use std::distance instead of Geom::distance. +namespace std { +template <> class iterator_traits<Geom::Point> {}; +} + #endif /* !SEEN_Geom_POINT_H */ /* diff --git a/src/2geom/poly.cpp b/src/2geom/poly.cpp index 9fa8e47db..de0229172 100644 --- a/src/2geom/poly.cpp +++ b/src/2geom/poly.cpp @@ -1,6 +1,5 @@ #include <2geom/poly.h> -#define HAVE_GSL #ifdef HAVE_GSL #include <gsl/gsl_poly.h> #endif diff --git a/src/2geom/poly.h b/src/2geom/poly.h index e0ba0580f..3567bda6d 100644 --- a/src/2geom/poly.h +++ b/src/2geom/poly.h @@ -34,6 +34,7 @@ #ifndef LIB2GEOM_SEEN_POLY_H #define LIB2GEOM_SEEN_POLY_H + #include <assert.h> #include <vector> #include <iostream> @@ -205,11 +206,13 @@ Poly gcd(Poly const &a, Poly const &b, const double tol=1e-10); */ std::vector<std::complex<double> > solve(const Poly & p); +#ifdef HAVE_GSL /*** solve_reals(Poly p) * find all real solutions to Poly p. * currently we just use solve and pick out the suitably real looking values, there may be a better algorithm. */ std::vector<double> solve_reals(const Poly & p); +#endif double polish_root(Poly const & p, double guess, double tol); inline std::ostream &operator<< (std::ostream &out_file, const Poly &in_poly) { diff --git a/src/2geom/ray.h b/src/2geom/ray.h index 3156a944d..638b86195 100644 --- a/src/2geom/ray.h +++ b/src/2geom/ray.h @@ -28,21 +28,30 @@ * the specific language governing rights and limitations. */ -#ifndef _2GEOM_RAY_H_ -#define _2GEOM_RAY_H_ +#ifndef LIB2GEOM_SEEN_RAY_H +#define LIB2GEOM_SEEN_RAY_H +#include <vector> #include <2geom/point.h> #include <2geom/bezier-curve.h> // for LineSegment #include <2geom/exception.h> -#include <vector> - - namespace Geom { -class Ray -{ +/** + * @brief Straight ray from a specific point to infinity. + * + * Rays are "half-lines" - they begin at some specific point and extend in a straight line + * to infinity. + * + * @ingroup Primitives + */ +class Ray { +private: + Point m_origin; + Point m_versor; + public: Ray() : m_origin(0,0), m_versor(1,0) @@ -183,22 +192,17 @@ public: return LineSegment(pointAt(f), pointAt(t)); } - Ray transformed(Matrix const& m) const + Ray transformed(Affine const& m) const { return Ray(m_origin * m, (m_origin + m_versor) * m); } - -private: - Point m_origin; - Point m_versor; - }; // end class ray inline double distance(Point const& _point, Ray const& _ray) { double t = _ray.nearestPoint(_point); - return distance(_point, _ray.pointAt(t)); + return ::Geom::distance(_point, _ray.pointAt(t)); } inline diff --git a/src/2geom/rect.h b/src/2geom/rect.h index cce1d64f0..65bb1bb76 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -1,8 +1,7 @@ /** * \file - * \brief D2<Interval> specialization to Rect - */ -/* + * \brief Axis-aligned rectangle + *//* * Copyright 2007 Michael Sloan <mgsloan@gmail.com> * * This library is free software; you can redistribute it and/or @@ -28,9 +27,7 @@ * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * - */ - -/* Authors of original rect class: + * Authors of original rect class: * Lauris Kaplinski <lauris@kaplinski.com> * Nathan Hurst <njh@mail.csse.monash.edu.au> * bulia byak <buliabyak@users.sf.net> @@ -39,52 +36,81 @@ #include <2geom/d2.h> -#ifndef _2GEOM_RECT -#define _2GEOM_RECT +#ifndef LIB2GEOM_RECT_H +#define LIB2GEOM_RECT_H -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <boost/optional/optional.hpp> namespace Geom { -/** D2<Interval> specialization to Rect */ + +/** + * @brief Axis-aligned, non-empty rectangle - convenience typedef + * @ingroup Primitives + */ typedef D2<Interval> Rect; class OptRect; -Rect unify(const Rect &, const Rect &); +inline Rect unify(Rect const &, Rect const &); + /** - * %Rect class. - * The Rect class is actually a specialisation of D2<Interval>. - * + * @brief Axis aligned, non-empty rectangle. + * @ingroup Primitives */ template<> class D2<Interval> { - private: +private: Interval f[2]; - public: - /** Best not to use this constructor, do not rely on what it initializes the object to. - *The default constructor creates a rect of default intervals. - */ +public: + /// @name Create rectangles. + /// @{ + /** @brief Create a rectangle that contains only the point at (0,0). */ D2<Interval>() { f[X] = f[Y] = Interval(); } - - public: + /** @brief Create a rectangle from X and Y intervals. */ D2<Interval>(Interval const &a, Interval const &b) { f[X] = a; f[Y] = b; } - + /** @brief Create a rectangle from two points. */ D2<Interval>(Point const & a, Point const & b) { f[X] = Interval(a[X], b[X]); f[Y] = Interval(a[Y], b[Y]); } + /** @brief Create a rectangle from a range of points. + * The resulting rectangle will contain all ponts from the range. + * The return type of iterators must be convertible to Point. + * The range must not be empty. For possibly empty ranges, see OptRect. + * @param start Beginning of the range + * @param end End of the range + * @return Rectangle that contains all points from [start, end). */ + template <typename InputIterator> + static Rect from_range(InputIterator start, InputIterator end) { + assert(start != end); + Point p1 = *start++; + Rect result(p1, p1); + for (; start != end; ++start) { + result.expandTo(*start); + } + return result; + } + /** @brief Create a rectangle from a C-style array of points it should contain. */ + static Rect from_array(Point const *c, unsigned n) { + Rect result = Rect::from_range(c, c+n); + return result; + } + /// @} - inline Interval& operator[](unsigned i) { return f[i]; } - inline Interval const & operator[](unsigned i) const { return f[i]; } - - inline Point min() const { return Point(f[X].min(), f[Y].min()); } - inline Point max() const { return Point(f[X].max(), f[Y].max()); } + /// @name Inspect dimensions. + /// @{ + Interval& operator[](unsigned i) { return f[i]; } + Interval const & operator[](unsigned i) const { return f[i]; } - /** Returns the four corners of the rectangle in positive order - * (clockwise if +Y is up, anticlockwise if +Y is down) */ + Point min() const { return Point(f[X].min(), f[Y].min()); } + Point max() const { return Point(f[X].max(), f[Y].max()); } + /** @brief Return the n-th corner of the rectangle. + * If the Y axis grows upwards, this returns corners in clockwise order + * starting from the lower left. If Y grows downwards, it returns the corners + * in counter-clockwise order starting from the upper left. */ Point corner(unsigned i) const { switch(i % 4) { case 0: return Point(f[X].min(), f[Y].min()); @@ -95,17 +121,23 @@ class D2<Interval> { } //We should probably remove these - they're coord sys gnostic - inline double top() const { return f[Y].min(); } - inline double bottom() const { return f[Y].max(); } - inline double left() const { return f[X].min(); } - inline double right() const { return f[X].max(); } - - inline double width() const { return f[X].extent(); } - inline double height() const { return f[Y].extent(); } + /** @brief Return top coordinate of the rectangle (+Y is downwards). */ + Coord top() const { return f[Y].min(); } + /** @brief Return bottom coordinate of the rectangle (+Y is downwards). */ + Coord bottom() const { return f[Y].max(); } + /** @brief Return leftmost coordinate of the rectangle (+X is to the right). */ + Coord left() const { return f[X].min(); } + /** @brief Return rightmost coordinate of the rectangle (+X is to the right). */ + Coord right() const { return f[X].max(); } + + Coord width() const { return f[X].extent(); } + Coord height() const { return f[Y].extent(); } - /** Returns a vector from min to max. */ - inline Point dimensions() const { return Point(f[X].extent(), f[Y].extent()); } - inline Point midpoint() const { return Point(f[X].middle(), f[Y].middle()); } + /** @brief Get rectangle's width and height as a point. + * @return Point with X coordinate corresponding to the width and the Y coordinate + * corresponding to the height of the rectangle. */ + Point dimensions() const { return Point(f[X].extent(), f[Y].extent()); } + Point midpoint() const { return Point(f[X].middle(), f[Y].middle()); } /** * \brief Compute the area of this rectangle. @@ -113,39 +145,92 @@ class D2<Interval> { * Note that a zero area rectangle is not empty - just as the interval [0,0] contains one point, the rectangle [0,0] x [0,0] contains 1 point and no area. * \retval For a valid return value, the rect must be tested for emptyness first. */ - inline double area() const { return f[X].extent() * f[Y].extent(); } - inline bool hasZeroArea(double eps = EPSILON) const { return (area() <= eps); } + /** @brief Compute rectangle's area. */ + Coord area() const { return f[X].extent() * f[Y].extent(); } + /** @brief Check whether the rectangle has zero area up to specified tolerance. + * @param eps Maximum value of the area to consider empty + * @return True if rectangle has an area smaller than tolerance, false otherwise */ + bool hasZeroArea(double eps = EPSILON) const { return (area() <= eps); } - inline double maxExtent() const { return std::max(f[X].extent(), f[Y].extent()); } - inline double minExtent() const { return std::min(f[X].extent(), f[Y].extent()); } + /** @brief Get the larger extent (width or height) of the rectangle. */ + Coord maxExtent() const { return std::max(f[X].extent(), f[Y].extent()); } + /** @brief Get the smaller extent (width or height) of the rectangle. */ + Coord minExtent() const { return std::min(f[X].extent(), f[Y].extent()); } + /// @} -// inline bool isEmpty() const { -// return f[X].isEmpty() || f[Y].isEmpty(); -// } - inline bool intersects(Rect const &r) const { - return f[X].intersects(r[X]) && f[Y].intersects(r[Y]); + /// @name Test other rectangles and points for inclusion. + /// @{ + /** @brief Check whether the rectangles have any common points. */ + bool intersects(Rect const &r) const { + return f[X].intersects(r[X]) && f[Y].intersects(r[Y]); } - inline bool contains(Rect const &r) const { - return f[X].contains(r[X]) && f[Y].contains(r[Y]); + /** @brief Check whether the interiors of the rectangles have any common points. */ + bool interiorIntersects(Rect const &r) const { + return f[X].interiorIntersects(r[X]) && f[Y].interiorIntersects(r[Y]); } - inline bool contains(Point const &p) const { + /** @brief Check whether the rectangle includes all points in the given rectangle. */ + bool contains(Rect const &r) const { + return f[X].contains(r[X]) && f[Y].contains(r[Y]); + } + /** @brief Check whether the interior includes all points in the given rectangle. + * Interior of the rectangle is the entire rectangle without its borders. */ + bool interiorContains(Rect const &r) const { + return f[X].interiorContains(r[X]) && f[Y].interiorContains(r[Y]); + } + + /** @brief Check whether the rectangles have any common points. + * A non-empty rectangle will not intersect empty rectangles. */ + inline bool intersects(OptRect const &r) const; + /** @brief Check whether the rectangle includes all points in the given rectangle. + * A non-empty rectangle will contain any empty rectangle. */ + inline bool contains(OptRect const &r) const; + /** @brief Check whether the interior includes all points in the given rectangle. + * The interior of a non-empty rectangle will contain any empty rectangle. */ + inline bool interiorContains(OptRect const &r) const; + + /** @brief Check whether the given point is within the rectangle. */ + bool contains(Point const &p) const { return f[X].contains(p[X]) && f[Y].contains(p[Y]); } + /** @brief Check whether the given point is in the rectangle's interior. + * This means the point must lie within the rectangle but not on its border. */ + bool interiorContains(Point const &p) const { + return f[X].interiorContains(p[X]) && f[Y].interiorContains(p[Y]); + } + /// @} - inline void expandTo(Point p) { - f[X].extendTo(p[X]); f[Y].extendTo(p[Y]); + /// @name Modify the rectangle. + /// @{ + /** @brief Enlarge the rectangle to contain the given point. */ + void expandTo(Point p) { + f[X].expandTo(p[X]); f[Y].expandTo(p[Y]); } - inline void unionWith(Rect const &b) { - f[X].unionWith(b[X]); f[Y].unionWith(b[Y]); + /** @brief Enlarge the rectangle to contain the given rectangle. */ + void unionWith(Rect const &b) { + f[X].unionWith(b[X]); f[Y].unionWith(b[Y]); } + /** @brief Enlarge the rectangle to contain the given rectangle. + * Unioning with an empty rectangle results in no changes. */ void unionWith(OptRect const &b); - - inline void expandBy(double amnt) { - f[X].expandBy(amnt); f[Y].expandBy(amnt); + + //TODO: figure out how these work with negative values and OptRect + /** @brief Expand the rectangle in both directions by the specified amount. + * Note that this is different from scaling. Negative values wil shrink the + * rectangle. If <code>-amount</code> is larger than + * half of the width, the X interval will contain only the X coordinate + * of the midpoint; same for height. */ + void expandBy(Coord amount) { + f[X].expandBy(amount); f[Y].expandBy(amount); } - inline void expandBy(Point const p) { - f[X].expandBy(p[X]); f[Y].expandBy(p[Y]); + /** @brief Expand the rectangle by the coordinates of the given point. + * This will expand the width by the X coordinate of the point in both directions + * and the height by Y coordinate of the point. Negative coordinate values will + * shrink the rectangle. If <code>-p[X]</code> is larger than half of the width, + * the X interval will contain only the X coordinate of the midpoint; same for height. */ + void expandBy(Point const p) { + f[X].expandBy(p[X]); f[Y].expandBy(p[Y]); } + /// @} }; inline Rect unify(Rect const & a, Rect const & b) { @@ -161,7 +246,7 @@ inline Rect union_list(std::vector<Rect> const &r) { } inline -double distanceSq( Point const& p, Rect const& rect ) +Coord distanceSq( Point const& p, Rect const& rect ) { double dx = 0, dy = 0; if ( p[X] < rect.left() ) @@ -187,15 +272,14 @@ double distanceSq( Point const& p, Rect const& rect ) * Returns the smallest distance between p and rect. */ inline -double distance( Point const& p, Rect const& rect ) +Coord distance( Point const& p, Rect const& rect ) { return std::sqrt(distanceSq(p, rect)); } /** - * The OptRect class can represent and empty Rect and non-empty Rects. - * If OptRect is not empty, it means that both X and Y intervals are not empty. - * + * @brief Axis-aligned rectangle that can be empty. + * @ingroup Primitives */ class OptRect : public boost::optional<Rect> { public: @@ -212,22 +296,25 @@ public: // else, stay empty. } - /** - * Check whether this OptRect is empty or not. - */ + /** @brief Check for emptiness. */ inline bool isEmpty() const { return (*this == false); }; - /** - * If \c this is empty, copy argument \c b. Otherwise, union with it (and do nothing when \c b is empty) - */ + bool intersects(Rect const &r) const { return r.intersects(*this); } + bool contains(Rect const &r) const { return *this && (*this)->contains(r); } + bool interiorContains(Rect const &r) const { return *this && (*this)->interiorContains(r); } + + bool intersects(OptRect const &r) const { return *this && (*this)->intersects(r); } + bool contains(OptRect const &r) const { return *this && (*this)->contains(r); } + bool interiorContains(OptRect const &r) const { return *this && (*this)->interiorContains(r); } + + bool contains(Point const &p) const { return *this && (*this)->contains(p); } + bool interiorContains(Point const &p) const { return *this && (*this)->contains(p); } + inline void unionWith(OptRect const &b) { - if (b) { - if (*this) { // check that we are not empty - (**this)[X].unionWith((*b)[X]); - (**this)[Y].unionWith((*b)[Y]); - } else { - *this = b; - } + if (*this) { // check that we are not empty + (*this)->unionWith(b); + } else { + *this = b; } } }; @@ -256,6 +343,15 @@ inline void Rect::unionWith(OptRect const &b) { unionWith(*b); } } +inline bool Rect::intersects(OptRect const &r) const { + return r && intersects(*r); +} +inline bool Rect::contains(OptRect const &r) const { + return !r || contains(*r); +} +inline bool Rect::interiorContains(OptRect const &r) const { + return !r || interiorContains(*r); +} } // end namespace Geom diff --git a/src/2geom/recursive-bezier-intersection.cpp b/src/2geom/recursive-bezier-intersection.cpp index 421f61308..b4c81e08e 100644 --- a/src/2geom/recursive-bezier-intersection.cpp +++ b/src/2geom/recursive-bezier-intersection.cpp @@ -63,7 +63,7 @@ void find_intersections_bezier_recursive( std::vector<std::pair<double, double> > &xs, vector<Geom::Point> const & A, vector<Geom::Point> const & B, - double precision) { + double /*precision*/) { OldBezier a, b; a.p = A; b.p = B; @@ -317,9 +317,9 @@ double Lmax(Point p) { return std::max(fabs(p[X]), fabs(p[Y])); } -unsigned wangs_theorem(OldBezier a) { +unsigned wangs_theorem(OldBezier /*a*/) { return 6; // seems a good approximation! - double la1 = Lmax( ( a.p[2] - a.p[1] ) - (a.p[1] - a.p[0]) ); + /*double la1 = Lmax( ( a.p[2] - a.p[1] ) - (a.p[1] - a.p[0]) ); double la2 = Lmax( ( a.p[3] - a.p[2] ) - (a.p[2] - a.p[1]) ); double l0 = std::max(la1, la2); unsigned ra; @@ -328,7 +328,7 @@ unsigned wangs_theorem(OldBezier a) { else ra = (unsigned)ceil( log4( M_SQRT2 * 6.0 / 8.0 * INV_EPS * l0 ) ); //std::cout << ra << std::endl; - return ra; + return ra;*/ } struct rparams @@ -337,7 +337,7 @@ struct rparams OldBezier &B; }; -static int +/*static int intersect_polish_f (const gsl_vector * x, void *params, gsl_vector * f) { @@ -351,22 +351,22 @@ intersect_polish_f (const gsl_vector * x, void *params, gsl_vector_set (f, 1, dx[1]); return GSL_SUCCESS; -} +}*/ -union dbl_64{ +/*union dbl_64{ long long i64; double d64; -}; +};*/ -static double EpsilonBy(double value, int eps) +/*static double EpsilonBy(double value, int eps) { dbl_64 s; s.d64 = value; s.i64 += eps; return s.d64; -} - +}*/ +/* static void intersect_polish_root (OldBezier &A, double &s, OldBezier &B, double &t) { const gsl_multiroot_fsolver_type *T; @@ -394,7 +394,7 @@ static void intersect_polish_root (OldBezier &A, double &s, iter++; status = gsl_multiroot_fsolver_iterate (sol); - if (status) /* check if solver is stuck */ + if (status) // check if solver is stuck break; status = @@ -439,7 +439,7 @@ static void intersect_polish_root (OldBezier &A, double &s, best_v = trial_v; } } -} +}*/ void find_intersections_bezier_recursive( std::vector<std::pair<double, double> > &xs, diff --git a/src/2geom/region.cpp b/src/2geom/region.cpp index 3c8c7fd1c..8cfb1c68c 100644 --- a/src/2geom/region.cpp +++ b/src/2geom/region.cpp @@ -5,9 +5,9 @@ namespace Geom { -Region Region::operator*(Matrix const &m) const { +Region Region::operator*(Affine const &m) const { Region r((m.flips() ? boundary.reverse() : boundary) * m, fill); - if(box && m.onlyScaleAndTranslation()) r.box = (*box) * m; + if(box && m.isZoom()) r.box = (*box) * m; return r; } diff --git a/src/2geom/region.h b/src/2geom/region.h index 937817595..e23d6a158 100644 --- a/src/2geom/region.h +++ b/src/2geom/region.h @@ -81,7 +81,7 @@ class Region { Region inverse() const { return Region(boundary.reverse(), box, !fill); } - Region operator*(Matrix const &m) const; + Region operator*(Affine const &m) const; bool invariants() const; }; diff --git a/src/2geom/sbasis-curve.h b/src/2geom/sbasis-curve.h index 6641c0fe1..22fe4fc1f 100644 --- a/src/2geom/sbasis-curve.h +++ b/src/2geom/sbasis-curve.h @@ -1,12 +1,13 @@ /** * \file - * \brief Symmetric Power Basis Curve - * + * \brief Symmetric power basis curve + *//* * Authors: - * MenTaLguY <mental@rydia.net> - * Marco Cecchetti <mrcekets at gmail.com> + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright 2007-2008 authors + * Copyright 2007-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,75 +33,77 @@ * the specific language governing rights and limitations. */ - - - #ifndef _2GEOM_SBASIS_CURVE_H_ #define _2GEOM_SBASIS_CURVE_H_ - #include <2geom/curve.h> - +#include <2geom/nearest-point.h> +#include <2geom/sbasis-geometric.h> namespace Geom { +/** @brief Symmetric power basis curve. + * + * Symmetric power basis (S-basis for short) polynomials are a versatile numeric representation + * of arbitrary continuous curves. They combine the properties of Bezier curves + * (geometric interpretation of parameters, numerical stability near ends of the curve) + * and the monomial basis (fast evaluation). They are the main representation of curves + * in 2Geom. + * + * @ingroup Curves + */ class SBasisCurve : public Curve { - + private: - SBasisCurve(); - D2<SBasis> inner; + SBasisCurve(); + D2<SBasis> inner; public: - explicit SBasisCurve(D2<SBasis> const &sb) : inner(sb) {} - explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {} - Curve *duplicate() const { return new SBasisCurve(*this); } - - Point initialPoint() const { return inner.at0(); } - Point finalPoint() const { return inner.at1(); } - bool isDegenerate() const { return inner.isConstant(); } - Point pointAt(Coord t) const { return inner.valueAt(t); } - std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { - return inner.valueAndDerivatives(t, n); - } - double valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); } - - void setInitial(Point v) { for(unsigned d = 0; d < 2; d++) { inner[d][0][0] = v[d]; } } - void setFinal(Point v) { for(unsigned d = 0; d < 2; d++) { inner[d][0][1] = v[d]; } } - - virtual OptRect boundsFast() const { return bounds_fast(inner); } - virtual OptRect boundsExact() const { return bounds_exact(inner); } - virtual OptRect boundsLocal(OptInterval i, unsigned deg) const { return bounds_local(inner, i, deg); } - - std::vector<double> roots(double v, Dim2 d) const { return Geom::roots(inner[d] - v); } - - double nearestPoint( Point const& p, double from = 0, double to = 1 ) const - { - return nearest_point(p, inner, from, to); - } - - std::vector<double> - allNearestPoints( Point const& p, double from = 0, double to = 1 ) const - { - return all_nearest_points(p, inner, from, to); - } - - Curve *portion(double f, double t) const { - return new SBasisCurve(Geom::portion(inner, f, t)); - } - - Curve *transformed(Matrix const &m) const { - return new SBasisCurve(inner * m); - } - - Curve *derivative() const { - return new SBasisCurve(Geom::derivative(inner)); - } - - D2<SBasis> toSBasis() const { return inner; } - - virtual int degreesOfFreedom() const { return inner[0].degreesOfFreedom() + inner[1].degreesOfFreedom(); - } + explicit SBasisCurve(D2<SBasis> const &sb) : inner(sb) {} + explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {} + + virtual Curve *duplicate() const { return new SBasisCurve(*this); } + virtual Point initialPoint() const { return inner.at0(); } + virtual Point finalPoint() const { return inner.at1(); } + virtual bool isDegenerate() const { return inner.isConstant(); } + virtual Point pointAt(Coord t) const { return inner.valueAt(t); } + virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned n) const { + return inner.valueAndDerivatives(t, n); + } + virtual Coord valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); } + virtual void setInitial(Point const &v) { + for (unsigned d = 0; d < 2; d++) { inner[d][0][0] = v[d]; } + } + virtual void setFinal(Point const &v) { + for (unsigned d = 0; d < 2; d++) { inner[d][0][1] = v[d]; } + } + virtual Rect boundsFast() const { return *bounds_fast(inner); } + virtual Rect boundsExact() const { return *bounds_exact(inner); } + virtual OptRect boundsLocal(OptInterval const &i, unsigned deg) const { + return bounds_local(inner, i, deg); + } + virtual std::vector<Coord> roots(Coord v, Dim2 d) const { return Geom::roots(inner[d] - v); } + virtual Coord nearestPoint( Point const& p, Coord from = 0, Coord to = 1 ) const { + return nearest_point(p, inner, from, to); + } + virtual std::vector<Coord> allNearestPoints( Point const& p, Coord from = 0, + Coord to = 1 ) const + { + return all_nearest_points(p, inner, from, to); + } + virtual Coord length(Coord tolerance) const { return ::Geom::length(inner, tolerance); } + virtual Curve *portion(Coord f, Coord t) const { + return new SBasisCurve(Geom::portion(inner, f, t)); + } + virtual Curve *transformed(Affine const &m) const { return new SBasisCurve(inner * m); } + virtual Curve *derivative() const { + return new SBasisCurve(Geom::derivative(inner)); + } + virtual D2<SBasis> toSBasis() const { return inner; } + virtual int degreesOfFreedom() const { + return inner[0].degreesOfFreedom() + inner[1].degreesOfFreedom(); + } }; diff --git a/src/2geom/sbasis-geometric.cpp b/src/2geom/sbasis-geometric.cpp index 3fd667224..f4b445faa 100644 --- a/src/2geom/sbasis-geometric.cpp +++ b/src/2geom/sbasis-geometric.cpp @@ -151,7 +151,7 @@ Geom::cutAtRoots(Piecewise<D2<SBasis> > const &M, double ZERO){ \param vect a piecewise parameteric curve. \param tol the maximum error allowed. \param order the maximum degree to use for approximation - + \relates Piecewise */ Piecewise<SBasis> Geom::atan2(Piecewise<D2<SBasis> > const &vect, double tol, unsigned order){ @@ -182,7 +182,7 @@ Geom::atan2(Piecewise<D2<SBasis> > const &vect, double tol, unsigned order){ \param vect a piecewise parameteric curve. \param tol the maximum error allowed. \param order the maximum degree to use for approximation - + \relates Piecewise, D2 */ Piecewise<SBasis> Geom::atan2(D2<SBasis> const &vect, double tol, unsigned order){ @@ -193,7 +193,7 @@ Geom::atan2(D2<SBasis> const &vect, double tol, unsigned order){ \param angle a piecewise function of angle wrt t. \param tol the maximum error allowed. \param order the maximum degree to use for approximation - + \relates D2, SBasis */ D2<Piecewise<SBasis> > Geom::tan2(SBasis const &angle, double tol, unsigned order){ @@ -204,7 +204,7 @@ Geom::tan2(SBasis const &angle, double tol, unsigned order){ \param angle a piecewise function of angle wrt t. \param tol the maximum error allowed. \param order the maximum degree to use for approximation - + \relates Piecewise, D2 */ D2<Piecewise<SBasis> > Geom::tan2(Piecewise<SBasis> const &angle, double tol, unsigned order){ @@ -218,6 +218,8 @@ Geom::tan2(Piecewise<SBasis> const &angle, double tol, unsigned order){ unitVector(x,y) is computed as (b,-a) where a and b are solutions of: ax+by=0 (eqn1) and a^2+b^2=1 (eqn2) + + \relates Piecewise, D2 */ Piecewise<D2<SBasis> > Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){ @@ -296,6 +298,8 @@ Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){ unitVector(x,y) is computed as (b,-a) where a and b are solutions of: ax+by=0 (eqn1) and a^2+b^2=1 (eqn2) + + \relates Piecewise */ Piecewise<D2<SBasis> > Geom::unitVector(Piecewise<D2<SBasis> > const &V, double tol, unsigned order){ @@ -314,7 +318,7 @@ Geom::unitVector(Piecewise<D2<SBasis> > const &V, double tol, unsigned order){ /** returns a function giving the arclength at each point in M. \param M the Element. \param tol the maximum error allowed. - + \relates Piecewise */ Piecewise<SBasis> Geom::arcLengthSb(Piecewise<D2<SBasis> > const &M, double tol){ @@ -328,7 +332,7 @@ Geom::arcLengthSb(Piecewise<D2<SBasis> > const &M, double tol){ /** returns a function giving the arclength at each point in M. \param M the Element. \param tol the maximum error allowed. - + \relates Piecewise, D2 */ Piecewise<SBasis> Geom::arcLengthSb(D2<SBasis> const &M, double tol){ @@ -353,9 +357,8 @@ Geom::length(Piecewise<D2<SBasis> > const &M, /** returns a function giving the curvature at each point in M. \param M the Element. \param tol the maximum error allowed. - - Todo: - * claimed incomplete. Check. + \relates Piecewise, D2 + \todo claimed incomplete. Check. */ Piecewise<SBasis> Geom::curvature(D2<SBasis> const &M, double tol) { @@ -371,9 +374,8 @@ Geom::curvature(D2<SBasis> const &M, double tol) { /** returns a function giving the curvature at each point in M. \param M the Element. \param tol the maximum error allowed. - - Todo: - * claimed incomplete. Check. + \relates Piecewise + \todo claimed incomplete. Check. */ Piecewise<SBasis> Geom::curvature(Piecewise<D2<SBasis> > const &V, double tol){ @@ -395,7 +397,7 @@ Geom::curvature(Piecewise<D2<SBasis> > const &V, double tol){ \param M the Element. \param tol the maximum error allowed. \param order the maximum degree to use for approximation - + \relates Piecewise, D2 */ Piecewise<D2<SBasis> > Geom::arc_length_parametrization(D2<SBasis> const &M, @@ -424,7 +426,7 @@ Geom::arc_length_parametrization(D2<SBasis> const &M, \param M the Element. \param tol the maximum error allowed. \param order the maximum degree to use for approximation - + \relates Piecewise */ Piecewise<D2<SBasis> > Geom::arc_length_parametrization(Piecewise<D2<SBasis> > const &M, @@ -449,7 +451,7 @@ static double sb_length_integrating(double t, void* param) { \param tol the maximum error allowed. \param result variable to be incremented with the length of the path \param abs_error variable to be incremented with the estimated error - + \relates D2 If you only want the length, this routine may be faster/more accurate. */ void Geom::length_integrating(D2<SBasis> const &B, double &result, double &abs_error, double tol) { @@ -474,7 +476,7 @@ void Geom::length_integrating(D2<SBasis> const &B, double &result, double &abs_e /** Calculates the length of a D2<SBasis> through gsl integration. \param s the Element. \param tol the maximum error allowed. - + \relates D2 If you only want the total length, this routine faster and more accurate than constructing an arcLengthSb. */ double @@ -488,7 +490,7 @@ Geom::length(D2<SBasis> const &s, /** Calculates the length of a Piecewise<D2<SBasis> > through gsl integration. \param s the Element. \param tol the maximum error allowed. - + \relates Piecewise If you only want the total length, this routine faster and more accurate than constructing an arcLengthSb. */ double @@ -507,7 +509,7 @@ Geom::length(Piecewise<D2<SBasis> > const &s, \param p the Element. \param centroid on return contains the centroid of the shape \param area on return contains the signed area of the shape. - + \relates Piecewise This approach uses green's theorem to compute the area and centroid using integrals. For curved shapes this is much faster than converting to polyline. Note that without an uncross operation the output is not the absolute area. * Returned values: @@ -620,6 +622,8 @@ solve_lambda0(double a0,double a1,double c0,double c1, * proportional to the given ones. * If insist_on_speed_signs == 0, allow speeds to point in the opposite direction (both at the same time) * If insist_on_speed_signs == -1, allow speeds to point in both direction independantly. +* +* \relates D2 */ std::vector<D2<SBasis> > Geom::cubics_fitting_curvature(Point const &M0, Point const &M1, @@ -743,6 +747,7 @@ Geom::cubics_with_prescribed_curvature(Point const &M0, Point const &M1, /** * \brief returns all the parameter values of A whose tangent passes through P. +* \relates D2 */ std::vector<double> find_tangents(Point P, D2<SBasis> const &A) { SBasis crs (cross(A - P, derivative(A))); diff --git a/src/2geom/sbasis-roots.cpp b/src/2geom/sbasis-roots.cpp index 95fd0cf3b..1b870d88f 100644 --- a/src/2geom/sbasis-roots.cpp +++ b/src/2geom/sbasis-roots.cpp @@ -74,7 +74,7 @@ OptInterval bounds_exact(SBasis const &a) { SBasis df = derivative(a); vector<double>extrema = roots(df); for (unsigned i=0; i<extrema.size(); i++){ - result.extendTo(a(extrema[i])); + result.expandTo(a(extrema[i])); } return result; } @@ -326,6 +326,211 @@ std::vector<std::vector<double> > multi_roots(SBasis const &f, return(roots); } + + +static bool compareIntervalMin( Interval I, Interval J ){ + return I.min()<J.min(); +} +static bool compareIntervalMax( Interval I, Interval J ){ + return I.max()<J.max(); +} + +//find the first interval whose max is >= x +static unsigned upper_level(vector<Interval> const &levels, double x ){ + return( lower_bound( levels.begin(), levels.end(), Interval(x,x), compareIntervalMax) - levels.begin() ); +} + +static std::vector<Interval> fuseContiguous(std::vector<Interval> const &sets, double tol=0.){ + std::vector<Interval> result; + if (sets.size() == 0 ) return result; + result.push_back( sets.front() ); + for (unsigned i=1; i < sets.size(); i++ ){ + if ( result.back().max() + tol >= sets[i].min() ){ + result.back().unionWith( sets[i] ); + }else{ + result.push_back( sets[i] ); + } + } + return result; +} + +/** level_sets internal method. +* algorithm: (~adaptation of Newton method versus 'accroissements finis') + -compute f at both ends of the given segment [a,b]. + -compute bounds m<df(t)<M for df on the segment. + Suppose f(a) is between two 'levels' c and C. Then + f wont enter c before a + (f(a)-c.max())/m + f wont enter C before a + (C.min()-f(a))/M + From this we conclude nothing happens before a'=a+min((f(a)-c.max())/m,(C.min()-f(a))/M). + We do the same for b: compute some b' such that nothing happens in (b',b]. + -if [a',b'] is not empty, repeat the process with [a',(a'+b')/2] and [(a'+b')/2,b']. + + If f(a) or f(b) belongs to some 'level' C, then use the same argument to find a' or b' such + that f remains in C on [a,a'] or [b',b]. In case f is monotonic, we also know f won't enter another + level before or after some time, allowing us to restrict the search a little more. + + unfortunately, extra care is needed about rounding errors, and also to avoid the repetition of roots, + making things tricky and unpleasant... +*/ + +static void level_sets_internal(SBasis const &f, + SBasis const &df, + std::vector<Interval> const &levels, + std::vector<std::vector<Interval> > &solsets, + double a, + double fa, + double b, + double fb, + double tol=1e-5){ + + if (f.size()==0){ + unsigned idx; + idx=upper_level( levels, 0. ); + if (idx<levels.size() && levels[idx].contains(0.)){ + solsets[idx].push_back( Interval(a,b) ) ; + } + return; + } + + unsigned idxa=upper_level(levels,fa); + unsigned idxb=upper_level(levels,fb); + + Interval bs = *bounds_local(df,Interval(a,b)); + + //first times when a level (higher or lower) can be reached from a or b. + double ta_hi; // f remains below next level for t<ta_hi + double ta_lo; // f remains above prev level for t<ta_lo + double tb_hi; // f remains below next level for t>tb_hi + double tb_lo; // f remains above next level for t>tb_lo + + ta_hi=ta_lo=b+1;//default values => no root there. + tb_hi=tb_lo=a-1;//default values => no root there. + + //--- if f(a) belongs to a level.------- + if ( idxa < levels.size() && levels[idxa].contains( fa ) ){ + //find the first time when we may exit this level. + ta_lo = a + ( levels[idxa].min() - fa)/bs.min(); + ta_hi = a + ( levels[idxa].max() - fa)/bs.max(); + if ( ta_lo < a || ta_lo > b ) ta_lo = b; + if ( ta_hi < a || ta_hi > b ) ta_hi = b; + //move to that time for the next iteration. + solsets[idxa].push_back( Interval( a, std::min( ta_lo, ta_hi ) ) ); + }else{ + //--- if f(b) does not belong to a level.------- + if ( idxa == 0 ){ + ta_lo = b; + }else{ + ta_lo = a + ( levels[idxa-1].max() - fa)/bs.min(); + if ( ta_lo < a ) ta_lo = b; + } + if ( idxa == levels.size() ){ + ta_hi = b; + }else{ + ta_hi = a + ( levels[idxa].min() - fa)/bs.max(); + if ( ta_hi < a ) ta_hi = b; + } + } + + //--- if f(b) belongs to a level.------- + if (idxb<levels.size() && levels.at(idxb).contains(fb)){ + //find the first time from b when we may exit this level. + tb_lo = b + ( levels[idxb].min() - fb ) / bs.max(); + tb_hi = b + ( levels[idxb].max() - fb ) / bs.min(); + if ( tb_lo > b || tb_lo < a ) tb_lo = a; + if ( tb_hi > b || tb_hi < a ) tb_hi = a; + //move to that time for the next iteration. + solsets[idxb].push_back( Interval( std::max( tb_lo, tb_hi ), b) ); + }else{ + //--- if f(b) does not belong to a level.------- + if ( idxb == 0 ){ + tb_lo = a; + }else{ + tb_lo = b + ( levels[idxb-1].max() - fb)/bs.max(); + if ( tb_lo > b ) tb_lo = a; + } + if ( idxb == levels.size() ){ + tb_hi = a; + }else{ + tb_hi = b + ( levels[idxb].min() - fb)/bs.min(); + if ( tb_hi > b ) tb_hi = a; + } + + + if ( bs.min() < 0 && idxb < levels.size() ) + tb_hi = b + ( levels[idxb ].min() - fb ) / bs.min(); + if ( bs.max() > 0 && idxb > 0 ) + tb_lo = b + ( levels[idxb-1].max() - fb ) / bs.max(); + } + + //let [t0,t1] be the next interval where to search. + double t0=std::min(ta_hi,ta_lo); + double t1=std::max(tb_hi,tb_lo); + + if (t0>=t1) return;//no root here. + + //if the interval is smaller than our resolution: + //pretend f simultaneously meets all the levels between f(t0) and f(t1)... + if ( t1 - t0 <= tol ){ + Interval f_t0t1 ( f(t0), f(t1) ); + unsigned idxmin = std::min(idxa, idxb); + unsigned idxmax = std::max(idxa, idxb); + //push [t0,t1] into all crossed level. Cheat to avoid overlapping intervals on different levels? + if ( idxmax > idxmin ){ + for (unsigned idx = idxmin; idx < idxmax; idx++){ + solsets[idx].push_back( Interval( t0, t1 ) ); + } + } + if ( idxmax < levels.size() && f_t0t1.intersects( levels[idxmax] ) ){ + solsets[idxmax].push_back( Interval( t0, t1 ) ); + } + return; + } + + //To make sure we finally exit the level jump at least by tol: + t0 = std::min( std::max( t0, a + tol ), b ); + t1 = std::max( std::min( t1, b - tol ), a ); + + double t =(t0+t1)/2; + double ft=f(t); + level_sets_internal( f, df, levels, solsets, t0, f(t0), t, ft ); + level_sets_internal( f, df, levels, solsets, t, ft, t1, f(t1) ); +} + +std::vector<std::vector<Interval> > level_sets(SBasis const &f, + std::vector<Interval> const &levels, + double a, double b, double tol){ + + std::vector<std::vector<Interval> > solsets(levels.size(), std::vector<Interval>()); + + SBasis df=derivative(f); + level_sets_internal(f,df,levels,solsets,a,f(a),b,f(b),tol); + // Fuse overlapping intervals... + for (unsigned i=0; i<solsets.size(); i++){ + if ( solsets[i].size() == 0 ) continue; + std::sort( solsets[i].begin(), solsets[i].end(), compareIntervalMin ); + solsets[i] = fuseContiguous( solsets[i], tol ); + } + return solsets; +} + +std::vector<Interval> level_set (SBasis const &f, double level, double vtol, double a, double b, double tol){ + Interval fat_level( level - vtol, level + vtol ); + return level_set(f, fat_level, a, b, tol); +} +std::vector<Interval> level_set (SBasis const &f, Interval const &level, double a, double b, double tol){ + std::vector<Interval> levels(1,level); + return level_sets(f,levels, a, b, tol).front() ; +} +std::vector<std::vector<Interval> > level_sets (SBasis const &f, std::vector<double> const &levels, double vtol, double a, double b, double tol){ + std::vector<Interval> fat_levels( levels.size(), Interval()); + for (unsigned i = 0; i < levels.size(); i++){ + fat_levels[i] = Interval( levels[i]-vtol, levels[i]+vtol); + } + return level_sets(f, fat_levels, a, b, tol); +} + + +//------------------------------------- //------------------------------------- @@ -358,6 +563,17 @@ std::vector<double> roots1(SBasis const & s) { return res; } +std::vector<double> roots1(SBasis const & s, Interval const ivl) { + std::vector<double> res; + double d = s[0][0] - s[0][1]; + if(d != 0) { + double r = s[0][0] / d; + if(ivl.contains(r)) + res.push_back(r); + } + return res; +} + /** Find all t s.t s(t) = 0 \param a sbasis function \returns vector of zeros (roots) @@ -377,6 +593,20 @@ std::vector<double> roots(SBasis const & s) { } } } +std::vector<double> roots(SBasis const & s, Interval const ivl) { + switch(s.size()) { + case 0: + return std::vector<double>(); + case 1: + return roots1(s, ivl); + default: + { + Bezier bz; + sbasis_to_bezier(bz, s); + return bz.roots(ivl); + } + } +} }; diff --git a/src/2geom/sbasis.h b/src/2geom/sbasis.h index d7390c64d..b1b0b6c2a 100644 --- a/src/2geom/sbasis.h +++ b/src/2geom/sbasis.h @@ -63,7 +63,10 @@ class SBasis : public SBasisN<1>; namespace Geom{ -/*** An empty SBasis is identically 0. */ +/** +* \brief S-power basis function class +* +* An empty SBasis is identically 0. */ class SBasis{ std::vector<Linear> d; void push_back(Linear const&l) { d.push_back(l); } @@ -125,8 +128,9 @@ public: } inline bool isConstant() const { if (empty()) return true; - for (unsigned i = 0; i < size(); i++) { - if(!(*this)[i].isConstant()) return false; + if(!(*this)[0].isConstant()) return false; + for (unsigned i = 1; i < size(); i++) { + if(!(*this)[i].isZero()) return false; } return true; } @@ -188,6 +192,7 @@ OptInterval bounds_local(SBasis const &a, const OptInterval &t, int order = 0); /** Returns a function which reverses the domain of a. \param a sbasis function + \relates SBasis useful for reversing a parameteric curve. */ @@ -312,7 +317,8 @@ inline SBasis& operator*=(SBasis& a, SBasis const & b) { /** Returns the degree of the first non zero coefficient. \param a sbasis function \param tol largest abs val considered 0 - \returns first non zero coefficient + \return first non zero coefficient + \relates SBasis */ inline unsigned valuation(SBasis const &a, double tol=0){ @@ -333,10 +339,10 @@ SBasis inverse(SBasis a, int k); SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, double tol=1e-3); /** Returns the sbasis on domain [0,1] that was t on [from, to] - \param a sbasis function + \param t sbasis function \param from,to interval - \returns sbasis - + \return sbasis + \relates SBasis */ inline SBasis portion(const SBasis &t, double from, double to) { return compose(t, Linear(from, to)); } inline SBasis portion(const SBasis &t, Interval ivl) { return compose(t, Linear(ivl[0], ivl[1])); } @@ -364,13 +370,75 @@ SBasis sin(Linear bo, int k); SBasis cos(Linear bo, int k); std::vector<double> roots(SBasis const & s); +std::vector<double> roots(SBasis const & s, Interval const inside); std::vector<std::vector<double> > multi_roots(SBasis const &f, std::vector<double> const &levels, double htol=1e-7, double vtol=1e-7, double a=0, double b=1); - + +//--------- Levelset like functions ----------------------------------------------------- + +/** Solve f(t) = v +/- tolerance. The collection of intervals where + * v - vtol <= f(t) <= v+vtol + * is returned (with a precision tol on the boundaries). + \param f sbasis function + \param level the value of v. + \param vtol: error tolerance on v. + \param a, b limit search on domain [a,b] + \param tol: tolerance on the result bounds. + \returns a vector of intervals. +*/ +std::vector<Interval> level_set (SBasis const &f, + double level, + double vtol = 1e-5, + double a=0., + double b=1., + double tol = 1e-5); + +/** Solve f(t)\in I=[u,v], which defines a collection of intervals (J_k). More precisely, + * a collection (J'_k) is returned with J'_k = J_k up to a given tolerance. + \param f sbasis function + \param level: the given interval of deisred values for f. + \param a, b limit search on domain [a,b] + \param tol: tolerance on the bounds of the result. + \returns a vector of intervals. +*/ +std::vector<Interval> level_set (SBasis const &f, + Interval const &level, + double a=0., + double b=1., + double tol = 1e-5); + +/** 'Solve' f(t) = v +/- tolerance for several values of v at once. + \param f sbasis function + \param levels vector of values, that should be sorted. + \param vtol: error tolerance on v. + \param a, b limit search on domain [a,b] + \param tol: the bounds of the returned intervals are exact up to that tolerance. + \returns a vector of vectors of intervals. +*/ +std::vector<std::vector<Interval> > level_sets (SBasis const &f, + std::vector<double> const &levels, + double a=0., + double b=1., + double vtol = 1e-5, + double tol = 1e-5); + +/** 'Solve' f(t)\in I=[u,v] for several intervals I at once. + \param f sbasis function + \param levels vector of 'y' intervals, that should be disjoints and sorted. + \param a, b limit search on domain [a,b] + \param tol: the bounds of the returned intervals are exact up to that tolerance. + \returns a vector of vectors of intervals. +*/ +std::vector<std::vector<Interval> > level_sets (SBasis const &f, + std::vector<Interval> const &levels, + double a=0., + double b=1., + double tol = 1e-5); + } #endif diff --git a/src/2geom/shape.cpp b/src/2geom/shape.cpp index 92af814cb..e9f5e55dc 100644 --- a/src/2geom/shape.cpp +++ b/src/2geom/shape.cpp @@ -622,7 +622,7 @@ Shape sanitize(std::vector<Path> const & ps) { /* This transforms a shape by a matrix. In the case that the matrix flips * the shape, it reverses the paths in order to preserve the fill. */ -Shape Shape::operator*(Matrix const &m) const { +Shape Shape::operator*(Affine const &m) const { Shape ret; for(unsigned i = 0; i < size(); i++) ret.content.push_back(content[i] * m); diff --git a/src/2geom/shape.h b/src/2geom/shape.h index 960f9668b..0a7ee9709 100644 --- a/src/2geom/shape.h +++ b/src/2geom/shape.h @@ -89,7 +89,7 @@ class Shape { const Region &operator[](unsigned ix) const { return content[ix]; } Shape inverse() const; - Shape operator*(Matrix const &m) const; + Shape operator*(Affine const &m) const; bool contains(Point const &p) const; diff --git a/src/2geom/solve-bezier-one-d.cpp b/src/2geom/solve-bezier-one-d.cpp index 876c483fe..c74e3243c 100644 --- a/src/2geom/solve-bezier-one-d.cpp +++ b/src/2geom/solve-bezier-one-d.cpp @@ -1,7 +1,12 @@ + #include <2geom/solver.h> +#include <2geom/choose.h> +#include <2geom/bezier.h> #include <2geom/point.h> + +#include <cmath> #include <algorithm> -#include <valarray> +//#include <valarray> /*** Find the zeros of the bernstein function. The code subdivides until it is happy with the * linearity of the function. This requires an O(degree^2) subdivision for each step, even when @@ -11,176 +16,208 @@ namespace Geom{ template<class t> -static int SGN(t x) { return (x > 0 ? 1 : (x < 0 ? -1 : 0)); } +static int SGN(t x) { return (x > 0 ? 1 : (x < 0 ? -1 : 0)); } -const unsigned MAXDEPTH = 23; // Maximum depth for recursion. Using floats means 23 bits precision max +//const unsigned MAXDEPTH = 23; // Maximum depth for recursion. Using floats means 23 bits precision max -const double BEPSILON = ldexp(1.0,(-MAXDEPTH-1)); /*Flatness control value */ -const double SECANT_EPSILON = 1e-13; // secant method converges much faster, get a bit more precision +//const double BEPSILON = ldexp(1.0,(-MAXDEPTH-1)); /*Flatness control value */ +//const double SECANT_EPSILON = 1e-13; // secant method converges much faster, get a bit more precision /** * This function is called _a lot_. We have included various manual memory management stuff to reduce the amount of mallocing that goes on. In the future it is possible that this will hurt performance. **/ class Bernsteins{ public: - double *Vtemp; - unsigned N,degree; + static const size_t MAX_DEPTH = 22; + size_t degree, N; std::vector<double> &solutions; - bool use_secant; - Bernsteins(int degr, std::vector<double> &so) : N(degr+1), degree(degr),solutions(so), use_secant(false) { - Vtemp = new double[N*2]; - } - ~Bernsteins() { - delete[] Vtemp; + //std::vector<double> bc; + BinomialCoefficient<double> bc; + + Bernsteins(size_t _degree, std::vector<double> & sol) + : degree(_degree), N(degree+1), solutions(sol), bc(degree) + { } + void subdivide(double const *V, double t, double *Left, double *Right); - double horner(const double *b, double t); - - unsigned + unsigned control_poly_flat_enough(double const *V); + double horner(const double *b, double t); + + void find_bernstein_roots(double const *w, /* The control points */ unsigned depth, /* The depth of the recursion */ double left_t, double right_t); }; /* - * find_bernstein_roots : Given an equation in Bernstein-Bernstein form, find all + * find_bernstein_roots : Given an equation in Bernstein-Bernstein form, find all * of the roots in the open interval (0, 1). Return the number of roots found. */ void find_bernstein_roots(double const *w, /* The control points */ - unsigned degree, /* The degree of the polynomial */ + unsigned degree, /* The degree of the polynomial */ std::vector<double> &solutions, /* RETURN candidate t-values */ - unsigned depth, /* The depth of the recursion */ - double left_t, double right_t, bool use_secant) -{ + unsigned depth, /* The depth of the recursion */ + double left_t, double right_t, bool /*use_secant*/) +{ Bernsteins B(degree, solutions); - B.use_secant = use_secant; B.find_bernstein_roots(w, depth, left_t, right_t); } void -Bernsteins::find_bernstein_roots(double const *w, /* The control points */ - unsigned depth, /* The depth of the recursion */ - double left_t, double right_t) +find_bernstein_roots(std::vector<double> &solutions, /* RETURN candidate t-values */ + Geom::Bezier const& bz, /* The control points */ + double left_t, double right_t) +{ + Bernsteins B(bz.degree(), solutions); + Geom::Bezier& bzl = const_cast<Geom::Bezier&>(bz); + double* w = &(bzl[0]); + B.find_bernstein_roots(w, 0, left_t, right_t); +} + + + +void Bernsteins::find_bernstein_roots(double const *w, /* The control points */ + unsigned depth, /* The depth of the recursion */ + double left_t, + double right_t) { - unsigned n_crossings = 0; /* Number of zero-crossings */ - + size_t n_crossings = 0; + int old_sign = SGN(w[0]); - for (unsigned i = 1; i < N; i++) { - int sign = SGN(w[i]); - if (sign) { - if (sign != old_sign && old_sign) { - n_crossings++; + //std::cout << "w[0] = " << w[0] << std::endl; + int sign; + for (size_t i = 1; i < N; i++) + { + //std::cout << "w[" << i << "] = " << w[i] << std::endl; + sign = SGN(w[i]); + if (sign != 0) + { + if (sign != old_sign && old_sign != 0) + { + ++n_crossings; } old_sign = sign; } } - - if (n_crossings == 0) // no solutions here - return; - - if (n_crossings == 1) { - /* Unique solution */ - /* Stop recursion when the tree is deep enough */ + //std::cout << "n_crossings = " << n_crossings << std::endl; + if (n_crossings == 0) return; // no solutions here + + if (n_crossings == 1) /* Unique solution */ + { + //std::cout << "depth = " << depth << std::endl; + /* Stop recursion when the tree is deep enough */ /* if deep enough, return 1 solution at midpoint */ - if (depth >= MAXDEPTH) { + if (depth > MAX_DEPTH) + { //printf("bottom out %d\n", depth); const double Ax = right_t - left_t; const double Ay = w[degree] - w[0]; - + solutions.push_back(left_t - Ax*w[0] / Ay); return; - solutions.push_back((left_t + right_t) / 2.0); - return; } - - // I thought secant method would be faster here, but it'aint. -- njh - // Actually, it was, I just was using the wrong method for bezier evaluation. Horner's rule results in a very efficient algorithm - 10* faster (20080816) - // Future work: try using brent's method - if(use_secant) { // false position - double s = 0;double t = 1; - double e = 1e-10; - int n,side=0; - double r,fr,fs = w[0],ft = w[degree]; - - for (n = 1; n <= 100; n++) + + + double s = 0, t = 1; + double e = 1e-10; + int side = 0; + double r, fr, fs = w[0], ft = w[degree]; + + for (size_t n = 0; n < 100; ++n) + { + r = (fs*t - ft*s) / (fs - ft); + if (fabs(t-s) < e * fabs(t+s)) break; + + fr = horner(w, r); + + if (fr * ft > 0) { - r = (fs*t - ft*s) / (fs - ft); - if (fabs(t-s) < e*fabs(t+s)) break; - fr = horner(w, r); - - if (fr * ft > 0) - { - t = r; ft = fr; - if (side==-1) fs /= 2; - side = -1; - } - else if (fs * fr > 0) - { - s = r; fs = fr; - if (side==+1) ft /= 2; - side = +1; - } - else break; + t = r; ft = fr; + if (side == -1) fs /= 2; + side = -1; } - solutions.push_back(r*right_t + (1-r)*left_t); - return; + else if (fs * fr > 0) + { + s = r; fs = fr; + if (side == +1) ft /= 2; + side = +1; + } + else break; } + solutions.push_back(r*right_t + (1-r)*left_t); + return; + } /* Otherwise, solve recursively after subdividing control polygon */ - std::valarray<double> new_controls(2*N); // New left and right control polygons - const double t = 0.5; +// double Left[N], /* New left and right */ +// Right[N]; /* control polygons */ + //const double t = 0.5; + double* LR = new double[2*N]; + double* Left = LR; + double* Right = LR + N; + std::copy(w, w + N, Right); -/* - * Bernstein : - * Evaluate a Bernstein function at a particular parameter value - * Fill in control points for resulting sub-curves. - * - */ - for (unsigned i = 0; i < N; i++) - Vtemp[i] = w[i]; - - /* Triangle computation */ - const double omt = (1-t); - new_controls[0] = Vtemp[0]; - new_controls[N+degree] = Vtemp[degree]; - double *prev_row = Vtemp; - double *row = Vtemp + N; - for (unsigned i = 1; i < N; i++) { - for (unsigned j = 0; j < N - i; j++) { - row[j] = omt*prev_row[j] + t*prev_row[j+1]; + Left[0] = Right[0]; + for (size_t i = 1; i < N; ++i) + { + for (size_t j = 0; j < N-i; ++j) + { + Right[j] = (Right[j] + Right[j+1]) * 0.5; } - new_controls[i] = row[0]; - new_controls[N+degree-i] = row[degree-i]; - std::swap(prev_row, row); + Left[i] = Right[0]; } - - double mid_t = left_t*(1-t) + right_t*t; - - find_bernstein_roots(&new_controls[0], depth+1, left_t, mid_t); - + + double mid_t = (left_t + right_t) * 0.5; + + + find_bernstein_roots(Left, depth+1, left_t, mid_t); + + /* Solution is exactly on the subdivision point. */ - if (new_controls[N] == 0) + if (Right[0] == 0) + { solutions.push_back(mid_t); - - find_bernstein_roots(&new_controls[N], depth+1, mid_t, right_t); + } + + find_bernstein_roots(Right, depth+1, mid_t, right_t); + delete[] LR; } + +// suggested by Sederberg. +double Bernsteins::horner(const double *b, double t) +{ + double u, tn, tmp; + u = 1.0 - t; + tn = 1.0; + tmp = b[0] * u; + for(size_t i = 1; i < degree; ++i) + { + tn *= t; + tmp = (tmp + tn*bc[i]*b[i]) * u; + } + return (tmp + tn*t*b[degree]); +} + + + +#if 0 /* * control_poly_flat_enough : * Check if the control polygon of a Bernstein curve is flat enough * for recursive subdivision to bottom out. * */ -unsigned +unsigned Bernsteins::control_poly_flat_enough(double const *V) { /* Find the perpendicular distance from each interior control point to line connecting V[0] and @@ -204,7 +241,7 @@ Bernsteins::control_poly_flat_enough(double const *V) else max_distance_above = std::max(max_distance_above, dist); } - + const double abSquared = 1./((a * a) + 1); const double intercept_1 = (a - max_distance_above * abSquared); @@ -218,23 +255,7 @@ Bernsteins::control_poly_flat_enough(double const *V) //printf("error %g %g %g\n", error, a, BEPSILON * a); return error < BEPSILON * a; } - -// suggested by Sederberg. -double Bernsteins::horner(const double *b, double t) { - int n = degree; - double u, bc, tn, tmp; - int i; - u = 1.0 - t; - bc = 1; - tn = 1; - tmp = b[0]*u; - for(i=1; i<n; i++){ - tn = tn*t; - bc = bc*(n-i+1)/i; - tmp = (tmp + tn*bc*b[i])*u; - } - return (tmp + tn*t*b[n]); -} +#endif }; diff --git a/src/2geom/solver.h b/src/2geom/solver.h index 2aadaa476..5e77f13dc 100644 --- a/src/2geom/solver.h +++ b/src/2geom/solver.h @@ -4,7 +4,7 @@ * * Authors: * ? <?@?.?> - * + * * Copyright ?-? authors * * This library is free software; you can redistribute it and/or @@ -37,9 +37,14 @@ #include <2geom/point.h> #include <2geom/sbasis.h> + +#include <vector> + + namespace Geom{ class Point; + class Bezier; unsigned crossing_count(Geom::Point const *V, /* Control pts of Bezier curve */ @@ -55,6 +60,8 @@ unsigned crossing_count(double const *V, /* Control pts of Bezier curve */ unsigned degree, /* Degree of Bezier curve */ double left_t, double right_t); + + void find_bernstein_roots( double const *w, /* The control points */ @@ -64,6 +71,12 @@ find_bernstein_roots( double left_t=0, double right_t=1, bool use_secant=true); }; + +void +find_bernstein_roots(std::vector<double> &solutions, /* RETURN candidate t-values */ + Geom::Bezier const& bz, + double left_t, double right_t); + #endif /* diff --git a/src/2geom/svg-elliptical-arc.cpp b/src/2geom/svg-elliptical-arc.cpp index 877667b43..ae8a3192c 100644 --- a/src/2geom/svg-elliptical-arc.cpp +++ b/src/2geom/svg-elliptical-arc.cpp @@ -36,6 +36,7 @@ #include <cfloat> #include <limits> +#include <memory> #include <2geom/numeric/vector.h> #include <2geom/numeric/fitting-tool.h> @@ -46,929 +47,15 @@ namespace Geom { - -OptRect SVGEllipticalArc::boundsExact() const -{ - if (isDegenerate() && is_svg_compliant()) - return chord().boundsExact(); - - std::vector<double> extremes(4); - double cosrot = std::cos(rotation_angle()); - double sinrot = std::sin(rotation_angle()); - extremes[0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot ); - extremes[1] = extremes[0] + M_PI; - if ( extremes[0] < 0 ) extremes[0] += 2*M_PI; - extremes[2] = std::atan2( ray(Y) * cosrot, ray(X) * sinrot ); - extremes[3] = extremes[2] + M_PI; - if ( extremes[2] < 0 ) extremes[2] += 2*M_PI; - - - std::vector<double>arc_extremes(4); - arc_extremes[0] = initialPoint()[X]; - arc_extremes[1] = finalPoint()[X]; - if ( arc_extremes[0] < arc_extremes[1] ) - std::swap(arc_extremes[0], arc_extremes[1]); - arc_extremes[2] = initialPoint()[Y]; - arc_extremes[3] = finalPoint()[Y]; - if ( arc_extremes[2] < arc_extremes[3] ) - std::swap(arc_extremes[2], arc_extremes[3]); - - - if ( start_angle() < end_angle() ) - { - if ( sweep_flag() ) - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() < extremes[i] && extremes[i] < end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - else - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() > extremes[i] || extremes[i] > end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - } - else - { - if ( sweep_flag() ) - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() < extremes[i] || extremes[i] < end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - else - { - for ( unsigned int i = 0; i < extremes.size(); ++i ) - { - if ( start_angle() > extremes[i] && extremes[i] > end_angle() ) - { - arc_extremes[i] = pointAtAngle(extremes[i])[i >> 1]; - } - } - } - } - - return Rect( Point(arc_extremes[1], arc_extremes[3]) , - Point(arc_extremes[0], arc_extremes[2]) ); -} - - -double SVGEllipticalArc::valueAtAngle(Coord t, Dim2 d) const -{ - double sin_rot_angle = std::sin(rotation_angle()); - double cos_rot_angle = std::cos(rotation_angle()); - if ( d == X ) - { - return ray(X) * cos_rot_angle * std::cos(t) - - ray(Y) * sin_rot_angle * std::sin(t) - + center(X); - } - else if ( d == Y ) - { - return ray(X) * sin_rot_angle * std::cos(t) - + ray(Y) * cos_rot_angle * std::sin(t) - + center(Y); - } - THROW_RANGEERROR("dimension parameter out of range"); -} - - -std::vector<double> -SVGEllipticalArc::roots(double v, Dim2 d) const -{ - if ( d > Y ) - { - THROW_RANGEERROR("dimention out of range"); - } - - std::vector<double> sol; - - if (isDegenerate() && is_svg_compliant()) - { - return chord().roots(v, d); - } - else - { - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { - if ( center(d) == v ) - sol.push_back(0); - return sol; - } - - const char* msg[2][2] = - { - { "d == X; ray(X) == 0; " - "s = (v - center(X)) / ( -ray(Y) * std::sin(rotation_angle()) ); " - "s should be contained in [-1,1]", - "d == X; ray(Y) == 0; " - "s = (v - center(X)) / ( ray(X) * std::cos(rotation_angle()) ); " - "s should be contained in [-1,1]" - }, - { "d == Y; ray(X) == 0; " - "s = (v - center(X)) / ( ray(Y) * std::cos(rotation_angle()) ); " - "s should be contained in [-1,1]", - "d == Y; ray(Y) == 0; " - "s = (v - center(X)) / ( ray(X) * std::sin(rotation_angle()) ); " - "s should be contained in [-1,1]" - }, - }; - - for ( unsigned int dim = 0; dim < 2; ++dim ) - { - if ( are_near(ray(dim), 0) ) - { - if ( initialPoint()[d] == v && finalPoint()[d] == v ) - { - THROW_INFINITESOLUTIONS(0); - } - if ( (initialPoint()[d] < finalPoint()[d]) - && (initialPoint()[d] > v || finalPoint()[d] < v) ) - { - return sol; - } - if ( (initialPoint()[d] > finalPoint()[d]) - && (finalPoint()[d] > v || initialPoint()[d] < v) ) - { - return sol; - } - double ray_prj; - switch(d) - { - case X: - switch(dim) - { - case X: ray_prj = -ray(Y) * std::sin(rotation_angle()); - break; - case Y: ray_prj = ray(X) * std::cos(rotation_angle()); - break; - } - break; - case Y: - switch(dim) - { - case X: ray_prj = ray(Y) * std::cos(rotation_angle()); - break; - case Y: ray_prj = ray(X) * std::sin(rotation_angle()); - break; - } - break; - } - - double s = (v - center(d)) / ray_prj; - if ( s < -1 || s > 1 ) - { - THROW_LOGICALERROR(msg[d][dim]); - } - switch(dim) - { - case X: - s = std::asin(s); // return a value in [-PI/2,PI/2] - if ( logical_xor( sweep_flag(), are_near(start_angle(), M_PI/2) ) ) - { - if ( s < 0 ) s += 2*M_PI; - } - else - { - s = M_PI - s; - if (!(s < 2*M_PI) ) s -= 2*M_PI; - } - break; - case Y: - s = std::acos(s); // return a value in [0,PI] - if ( logical_xor( sweep_flag(), are_near(start_angle(), 0) ) ) - { - s = 2*M_PI - s; - if ( !(s < 2*M_PI) ) s -= 2*M_PI; - } - break; - } - - //std::cerr << "s = " << rad_to_deg(s); - s = map_to_01(s); - //std::cerr << " -> t: " << s << std::endl; - if ( !(s < 0 || s > 1) ) - sol.push_back(s); - return sol; - } - } - - } - - double rotx, roty; - switch(d) - { - case X: - rotx = std::cos(rotation_angle()); - roty = -std::sin(rotation_angle()); - break; - case Y: - rotx = std::sin(rotation_angle()); - roty = std::cos(rotation_angle()); - break; - } - double rxrotx = ray(X) * rotx; - double c_v = center(d) - v; - - double a = -rxrotx + c_v; - double b = ray(Y) * roty; - double c = rxrotx + c_v; - //std::cerr << "a = " << a << std::endl; - //std::cerr << "b = " << b << std::endl; - //std::cerr << "c = " << c << std::endl; - - if ( are_near(a,0) ) - { - sol.push_back(M_PI); - if ( !are_near(b,0) ) - { - double s = 2 * std::atan(-c/(2*b)); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - } - } - else - { - double delta = b * b - a * c; - //std::cerr << "delta = " << delta << std::endl; - if ( are_near(delta, 0) ) - { - double s = 2 * std::atan(-b/a); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - } - else if ( delta > 0 ) - { - double sq = std::sqrt(delta); - double s = 2 * std::atan( (-b - sq) / a ); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - s = 2 * std::atan( (-b + sq) / a ); - if ( s < 0 ) s += 2*M_PI; - sol.push_back(s); - } - } - - std::vector<double> arc_sol; - for (unsigned int i = 0; i < sol.size(); ++i ) - { - //std::cerr << "s = " << rad_to_deg(sol[i]); - sol[i] = map_to_01(sol[i]); - //std::cerr << " -> t: " << sol[i] << std::endl; - if ( !(sol[i] < 0 || sol[i] > 1) ) - arc_sol.push_back(sol[i]); - } - return arc_sol; -} - - -// D(E(t,C),t) = E(t+PI/2,O), where C is the ellipse center -// the derivative doesn't rotate the ellipse but there is a translation -// of the parameter t by an angle of PI/2 so the ellipse points are shifted -// of such an angle in the cw direction -Curve* SVGEllipticalArc::derivative() const -{ - if (isDegenerate() && is_svg_compliant()) - return chord().derivative(); - - SVGEllipticalArc* result = new SVGEllipticalArc(*this); - result->m_center[X] = result->m_center[Y] = 0; - result->m_start_angle += M_PI/2; - if( !( result->m_start_angle < 2*M_PI ) ) - { - result->m_start_angle -= 2*M_PI; - } - result->m_end_angle += M_PI/2; - if( !( result->m_end_angle < 2*M_PI ) ) - { - result->m_end_angle -= 2*M_PI; - } - result->m_initial_point = result->pointAtAngle( result->start_angle() ); - result->m_final_point = result->pointAtAngle( result->end_angle() ); - return result; -} - - -std::vector<Point> -SVGEllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const -{ - if (isDegenerate() && is_svg_compliant()) - return chord().pointAndDerivatives(t, n); - - unsigned int nn = n+1; // nn represents the size of the result vector. - std::vector<Point> result; - result.reserve(nn); - double angle = map_unit_interval_on_circular_arc(t, start_angle(), - end_angle(), sweep_flag()); - SVGEllipticalArc ea(*this); - ea.m_center = Point(0,0); - unsigned int m = std::min(nn, 4u); - for ( unsigned int i = 0; i < m; ++i ) - { - result.push_back( ea.pointAtAngle(angle) ); - angle += M_PI/2; - if ( !(angle < 2*M_PI) ) angle -= 2*M_PI; - } - m = nn / 4; - for ( unsigned int i = 1; i < m; ++i ) - { - for ( unsigned int j = 0; j < 4; ++j ) - result.push_back( result[j] ); - } - m = nn - 4 * m; - for ( unsigned int i = 0; i < m; ++i ) - { - result.push_back( result[i] ); - } - if ( !result.empty() ) // nn != 0 - result[0] = pointAtAngle(angle); - return result; -} - -bool SVGEllipticalArc::containsAngle(Coord angle) const -{ - if ( sweep_flag() ) - if ( start_angle() < end_angle() ) - return ( !( angle < start_angle() || angle > end_angle() ) ); - else - return ( !( angle < start_angle() && angle > end_angle() ) ); - else - if ( start_angle() > end_angle() ) - return ( !( angle > start_angle() || angle < end_angle() ) ); - else - return ( !( angle > start_angle() && angle < end_angle() ) ); -} - -Curve* SVGEllipticalArc::portion(double f, double t) const -{ - // fix input arguments - if (f < 0) f = 0; - if (f > 1) f = 1; - if (t < 0) t = 0; - if (t > 1) t = 1; - - if ( are_near(f, t) ) - { - SVGEllipticalArc* arc = new SVGEllipticalArc(); - arc->m_center = arc->m_initial_point = arc->m_final_point = pointAt(f); - arc->m_start_angle = arc->m_end_angle = m_start_angle; - arc->m_rot_angle = m_rot_angle; - arc->m_sweep = m_sweep; - arc->m_large_arc = m_large_arc; - } - - SVGEllipticalArc* arc = new SVGEllipticalArc( *this ); - arc->m_initial_point = pointAt(f); - arc->m_final_point = pointAt(t); - double sa = sweep_flag() ? sweep_angle() : -sweep_angle(); - arc->m_start_angle = m_start_angle + sa * f; - if ( !(arc->m_start_angle < 2*M_PI) ) - arc->m_start_angle -= 2*M_PI; - if ( arc->m_start_angle < 0 ) - arc->m_start_angle += 2*M_PI; - arc->m_end_angle = m_start_angle + sa * t; - if ( !(arc->m_end_angle < 2*M_PI) ) - arc->m_end_angle -= 2*M_PI; - if ( arc->m_end_angle < 0 ) - arc->m_end_angle += 2*M_PI; - if ( f > t ) arc->m_sweep = !sweep_flag(); - if ( large_arc_flag() && (arc->sweep_angle() < M_PI) ) - arc->m_large_arc = false; - return arc; -} - - -std::vector<double> SVGEllipticalArc:: -allNearestPoints( Point const& p, double from, double to ) const -{ - std::vector<double> result; - if (isDegenerate() && is_svg_compliant()) - { - result.push_back( chord().nearestPoint(p, from, to) ); - return result; - } - - if ( from > to ) std::swap(from, to); - if ( from < 0 || to > 1 ) - { - THROW_RANGEERROR("[from,to] interval out of range"); - } - - if ( ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) || are_near(from, to) ) - { - result.push_back(from); - return result; - } - else if ( are_near(ray(X), 0) || are_near(ray(Y), 0) ) - { - LineSegment seg(pointAt(from), pointAt(to)); - Point np = seg.pointAt( seg.nearestPoint(p) ); - if ( are_near(ray(Y), 0) ) - { - if ( are_near(rotation_angle(), M_PI/2) - || are_near(rotation_angle(), 3*M_PI/2) ) - { - result = roots(np[Y], Y); - } - else - { - result = roots(np[X], X); - } - } - else - { - if ( are_near(rotation_angle(), M_PI/2) - || are_near(rotation_angle(), 3*M_PI/2) ) - { - result = roots(np[X], X); - } - else - { - result = roots(np[Y], Y); - } - } - return result; - } - else if ( are_near(ray(X), ray(Y)) ) - { - Point r = p - center(); - if ( are_near(r, Point(0,0)) ) - { - THROW_INFINITESOLUTIONS(0); - } - // TODO: implement case r != 0 -// Point np = ray(X) * unit_vector(r); -// std::vector<double> solX = roots(np[X],X); -// std::vector<double> solY = roots(np[Y],Y); -// double t; -// if ( are_near(solX[0], solY[0]) || are_near(solX[0], solY[1])) -// { -// t = solX[0]; -// } -// else -// { -// t = solX[1]; -// } -// if ( !(t < from || t > to) ) -// { -// result.push_back(t); -// } -// else -// { -// -// } - } - - // solve the equation <D(E(t),t)|E(t)-p> == 0 - // that provides min and max distance points - // on the ellipse E wrt the point p - // after the substitutions: - // cos(t) = (1 - s^2) / (1 + s^2) - // sin(t) = 2t / (1 + s^2) - // where s = tan(t/2) - // we get a 4th degree equation in s - /* - * ry s^4 ((-cy + py) Cos[Phi] + (cx - px) Sin[Phi]) + - * ry ((cy - py) Cos[Phi] + (-cx + px) Sin[Phi]) + - * 2 s^3 (rx^2 - ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) + - * 2 s (-rx^2 + ry^2 + (-cx + px) rx Cos[Phi] + (-cy + py) rx Sin[Phi]) - */ - - Point p_c = p - center(); - double rx2_ry2 = (ray(X) - ray(Y)) * (ray(X) + ray(Y)); - double cosrot = std::cos( rotation_angle() ); - double sinrot = std::sin( rotation_angle() ); - double expr1 = ray(X) * (p_c[X] * cosrot + p_c[Y] * sinrot); - Poly coeff; - coeff.resize(5); - coeff[4] = ray(Y) * ( p_c[Y] * cosrot - p_c[X] * sinrot ); - coeff[3] = 2 * ( rx2_ry2 + expr1 ); - coeff[2] = 0; - coeff[1] = 2 * ( -rx2_ry2 + expr1 ); - coeff[0] = -coeff[4]; - -// for ( unsigned int i = 0; i < 5; ++i ) -// std::cerr << "c[" << i << "] = " << coeff[i] << std::endl; - - std::vector<double> real_sol; - // gsl_poly_complex_solve raises an error - // if the leading coefficient is zero - if ( are_near(coeff[4], 0) ) - { - real_sol.push_back(0); - if ( !are_near(coeff[3], 0) ) - { - double sq = -coeff[1] / coeff[3]; - if ( sq > 0 ) - { - double s = std::sqrt(sq); - real_sol.push_back(s); - real_sol.push_back(-s); - } - } - } - else - { - real_sol = solve_reals(coeff); - } - - for ( unsigned int i = 0; i < real_sol.size(); ++i ) - { - real_sol[i] = 2 * std::atan(real_sol[i]); - if ( real_sol[i] < 0 ) real_sol[i] += 2*M_PI; - } - // when s -> Infinity then <D(E)|E-p> -> 0 iff coeff[4] == 0 - // so we add M_PI to the solutions being lim arctan(s) = PI when s->Infinity - if ( (real_sol.size() % 2) != 0 ) - { - real_sol.push_back(M_PI); - } - - double mindistsq1 = std::numeric_limits<double>::max(); - double mindistsq2 = std::numeric_limits<double>::max(); - double dsq; - unsigned int mi1, mi2; - for ( unsigned int i = 0; i < real_sol.size(); ++i ) - { - dsq = distanceSq(p, pointAtAngle(real_sol[i])); - if ( mindistsq1 > dsq ) - { - mindistsq2 = mindistsq1; - mi2 = mi1; - mindistsq1 = dsq; - mi1 = i; - } - else if ( mindistsq2 > dsq ) - { - mindistsq2 = dsq; - mi2 = i; - } - } - - double t = map_to_01( real_sol[mi1] ); - if ( !(t < from || t > to) ) - { - result.push_back(t); - } - - bool second_sol = false; - t = map_to_01( real_sol[mi2] ); - if ( real_sol.size() == 4 && !(t < from || t > to) ) - { - if ( result.empty() || are_near(mindistsq1, mindistsq2) ) - { - result.push_back(t); - second_sol = true; - } - } - - // we need to test extreme points too - double dsq1 = distanceSq(p, pointAt(from)); - double dsq2 = distanceSq(p, pointAt(to)); - if ( second_sol ) - { - if ( mindistsq2 > dsq1 ) - { - result.clear(); - result.push_back(from); - mindistsq2 = dsq1; - } - else if ( are_near(mindistsq2, dsq) ) - { - result.push_back(from); - } - if ( mindistsq2 > dsq2 ) - { - result.clear(); - result.push_back(to); - } - else if ( are_near(mindistsq2, dsq2) ) - { - result.push_back(to); - } - - } - else - { - if ( result.empty() ) - { - if ( are_near(dsq1, dsq2) ) - { - result.push_back(from); - result.push_back(to); - } - else if ( dsq2 > dsq1 ) - { - result.push_back(from); - } - else - { - result.push_back(to); - } - } - } - - return result; -} - - -/* - * NOTE: this implementation follows Standard SVG 1.1 implementation guidelines - * for elliptical arc curves. See Appendix F.6. - */ -void SVGEllipticalArc::calculate_center_and_extreme_angles() -{ - Point d = initialPoint() - finalPoint(); - - if (is_svg_compliant()) - { - if ( initialPoint() == finalPoint() ) - { - m_rx = m_ry = m_rot_angle = m_start_angle = m_end_angle = 0; - m_center = initialPoint(); - m_large_arc = m_sweep = false; - return; - } - - m_rx = std::fabs(m_rx); - m_ry = std::fabs(m_ry); - - if ( are_near(ray(X), 0) || are_near(ray(Y), 0) ) - { - m_rx = L2(d) / 2; - m_ry = 0; - m_rot_angle = std::atan2(d[Y], d[X]); - if (m_rot_angle < 0) m_rot_angle += 2*M_PI; - m_start_angle = 0; - m_end_angle = M_PI; - m_center = middle_point(initialPoint(), finalPoint()); - m_large_arc = false; - m_sweep = false; - return; - } - } - else - { - if ( are_near(initialPoint(), finalPoint()) ) - { - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { - m_start_angle = m_end_angle = 0; - m_center = initialPoint(); - return; - } - else - { - THROW_RANGEERROR("initial and final point are the same"); - } - } - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { // but initialPoint != finalPoint - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 && ray(Y) == 0 but initialPoint != finalPoint" - ); - } - if ( are_near(ray(Y), 0) ) - { - Point v = initialPoint() - finalPoint(); - if ( are_near(L2sq(v), 4*ray(X)*ray(X)) ) - { - double angle = std::atan2(v[Y], v[X]); - if (angle < 0) angle += 2*M_PI; - if ( are_near( angle, rotation_angle() ) ) - { - m_start_angle = 0; - m_end_angle = M_PI; - m_center = v/2 + finalPoint(); - return; - } - angle -= M_PI; - if ( angle < 0 ) angle += 2*M_PI; - if ( are_near( angle, rotation_angle() ) ) - { - m_start_angle = M_PI; - m_end_angle = 0; - m_center = v/2 + finalPoint(); - return; - } - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(Y) == 0 " - "and slope(initialPoint - finalPoint) != rotation_angle " - "and != rotation_angle + PI" - ); - } - if ( L2sq(v) > 4*ray(X)*ray(X) ) - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(Y) == 0 and distance(initialPoint, finalPoint) > 2*ray(X)" - ); - } - else - { - THROW_RANGEERROR( - "there is infinite ellipses that satisfy the given constraints: " - "ray(Y) == 0 and distance(initialPoint, finalPoint) < 2*ray(X)" - ); - } - - } - - if ( are_near(ray(X), 0) ) - { - Point v = initialPoint() - finalPoint(); - if ( are_near(L2sq(v), 4*ray(Y)*ray(Y)) ) - { - double angle = std::atan2(v[Y], v[X]); - if (angle < 0) angle += 2*M_PI; - double rot_angle = rotation_angle() + M_PI/2; - if ( !(rot_angle < 2*M_PI) ) rot_angle -= 2*M_PI; - if ( are_near( angle, rot_angle ) ) - { - m_start_angle = M_PI/2; - m_end_angle = 3*M_PI/2; - m_center = v/2 + finalPoint(); - return; - } - angle -= M_PI; - if ( angle < 0 ) angle += 2*M_PI; - if ( are_near( angle, rot_angle ) ) - { - m_start_angle = 3*M_PI/2; - m_end_angle = M_PI/2; - m_center = v/2 + finalPoint(); - return; - } - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 " - "and slope(initialPoint - finalPoint) != rotation_angle + PI/2 " - "and != rotation_angle + (3/2)*PI" - ); - } - if ( L2sq(v) > 4*ray(Y)*ray(Y) ) - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 and distance(initialPoint, finalPoint) > 2*ray(Y)" - ); - } - else - { - THROW_RANGEERROR( - "there is infinite ellipses that satisfy the given constraints: " - "ray(X) == 0 and distance(initialPoint, finalPoint) < 2*ray(Y)" - ); - } - - } - - } - - double sin_rot_angle = std::sin(rotation_angle()); - double cos_rot_angle = std::cos(rotation_angle()); - - - Matrix m( cos_rot_angle, -sin_rot_angle, - sin_rot_angle, cos_rot_angle, - 0, 0 ); - - Point p = (d / 2) * m; - double rx2 = m_rx * m_rx; - double ry2 = m_ry * m_ry; - double rxpy = m_rx * p[Y]; - double rypx = m_ry * p[X]; - double rx2py2 = rxpy * rxpy; - double ry2px2 = rypx * rypx; - double num = rx2 * ry2; - double den = rx2py2 + ry2px2; - assert(den != 0); - double rad = num / den; - Point c(0,0); - if (rad > 1) - { - rad -= 1; - rad = std::sqrt(rad); - - if (m_large_arc == m_sweep) rad = -rad; - c = rad * Point(rxpy / m_ry, -rypx / m_rx); - - m[1] = -m[1]; - m[2] = -m[2]; - - m_center = c * m + middle_point(initialPoint(), finalPoint()); - } - else if (rad == 1 || is_svg_compliant()) - { - double lamda = std::sqrt(1 / rad); - m_rx *= lamda; - m_ry *= lamda; - m_center = middle_point(initialPoint(), finalPoint()); - } - else - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints" - ); - } - - Point sp((p[X] - c[X]) / m_rx, (p[Y] - c[Y]) / m_ry); - Point ep((-p[X] - c[X]) / m_rx, (-p[Y] - c[Y]) / m_ry); - Point v(1, 0); - m_start_angle = angle_between(v, sp); - double sweep_angle = angle_between(sp, ep); - if (!m_sweep && sweep_angle > 0) sweep_angle -= 2*M_PI; - if (m_sweep && sweep_angle < 0) sweep_angle += 2*M_PI; - - if (m_start_angle < 0) m_start_angle += 2*M_PI; - m_end_angle = m_start_angle + sweep_angle; - if (m_end_angle < 0) m_end_angle += 2*M_PI; - if (m_end_angle >= 2*M_PI) m_end_angle -= 2*M_PI; -} - - -D2<SBasis> SVGEllipticalArc::toSBasis() const -{ - - if (isDegenerate() && is_svg_compliant()) - return chord().toSBasis(); - - D2<SBasis> arc; - // the interval of parametrization has to be [0,1] - Coord et = start_angle() + ( sweep_flag() ? sweep_angle() : -sweep_angle() ); - Linear param(start_angle(), et); - Coord cos_rot_angle = std::cos(rotation_angle()); - Coord sin_rot_angle = std::sin(rotation_angle()); - // order = 4 seems to be enough to get a perfect looking elliptical arc - SBasis arc_x = ray(X) * cos(param,4); - SBasis arc_y = ray(Y) * sin(param,4); - arc[0] = arc_x * cos_rot_angle - arc_y * sin_rot_angle + Linear(center(X),center(X)); - arc[1] = arc_x * sin_rot_angle + arc_y * cos_rot_angle + Linear(center(Y),center(Y)); - - // ensure that endpoints remain exact - for ( int d = 0 ; d < 2 ; d++ ) { - arc[d][0][0] = initialPoint()[d]; - arc[d][0][1] = finalPoint()[d]; - } - - return arc; -} - - -Curve* SVGEllipticalArc::transformed(Matrix const& m) const -{ - Ellipse e(center(X), center(Y), ray(X), ray(Y), rotation_angle()); - Ellipse et = e.transformed(m); - Point inner_point = pointAt(0.5); - SVGEllipticalArc ea = et.arc( initialPoint() * m, - inner_point * m, - finalPoint() * m, - is_svg_compliant() ); - return ea.duplicate(); -} - -/* - * helper routine to convert the parameter t value - * btw [0,1] and [0,2PI] domain and back +/** + * @class SVGEllipticalArc + * @brief SVG 1.1-compliant elliptical arc. + * + * This class is almost identical to the normal elliptical arc, but it differs slightly + * in the handling of degenerate arcs to be compliant with SVG 1.1 implementation guidelines. * + * @ingroup Curves */ -Coord SVGEllipticalArc::map_to_02PI(Coord t) const -{ - Coord angle = start_angle(); - if ( sweep_flag() ) - { - angle += sweep_angle() * t; - } - else - { - angle -= sweep_angle() * t; - } - angle = std::fmod(angle, 2*M_PI); - if ( angle < 0 ) angle += 2*M_PI; - return angle; -} - -Coord SVGEllipticalArc::map_to_01(Coord angle) const -{ - return map_circular_arc_on_unit_interval(angle, start_angle(), - end_angle(), sweep_flag()); -} - namespace detail { @@ -1015,7 +102,7 @@ struct ellipse_equation } make_elliptical_arc:: -make_elliptical_arc( SVGEllipticalArc& _ea, +make_elliptical_arc( EllipticalArc& _ea, curve_type const& _curve, unsigned int _total_samples, double _tolerance ) @@ -1133,13 +220,16 @@ bool make_elliptical_arc::make_elliptiarc() if (svg_compliant_flag()) { - ea = e.arc(initial_point, inner_point, final_point); + std::auto_ptr<EllipticalArc> arc( e.arc(initial_point, inner_point, final_point, true) ); + ea = *arc; } else { try { - ea = e.arc(initial_point, inner_point, final_point, false); + std::auto_ptr<EllipticalArc> eap( + e.arc(initial_point, inner_point, final_point, false) ); + ea = *eap; } catch(RangeError exc) { diff --git a/src/2geom/svg-elliptical-arc.h b/src/2geom/svg-elliptical-arc.h index 34c51508b..79497cdb3 100644 --- a/src/2geom/svg-elliptical-arc.h +++ b/src/2geom/svg-elliptical-arc.h @@ -1,12 +1,14 @@ /** * \file - * \brief Elliptical Arc - implementation of the SVGEllipticalArc path element + * \brief SVG 1.1-compliant elliptical arc curve * + *//* * Authors: - * MenTaLguY <mental@rydia.net> - * Marco Cecchetti <mrcekets at gmail.com> - * - * Copyright 2007-2008 authors + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright 2007-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -36,339 +38,95 @@ #ifndef _2GEOM_SVG_ELLIPTICAL_ARC_H_ #define _2GEOM_SVG_ELLIPTICAL_ARC_H_ - #include <2geom/curve.h> #include <2geom/angle.h> #include <2geom/utils.h> #include <2geom/bezier-curve.h> +#include <2geom/elliptical-arc.h> #include <2geom/sbasis-curve.h> // for non-native methods #include <2geom/numeric/vector.h> #include <2geom/numeric/fitting-tool.h> #include <2geom/numeric/fitting-model.h> - - #include <algorithm> - - namespace Geom { -class SVGEllipticalArc : public Curve -{ - public: - SVGEllipticalArc(bool _svg_compliant = true) - : m_initial_point(Point(0,0)), m_final_point(Point(0,0)), - m_rx(0), m_ry(0), m_rot_angle(0), - m_large_arc(true), m_sweep(true), - m_svg_compliant(_svg_compliant), - m_start_angle(0), m_end_angle(0), - m_center(Point(0,0)) - { - } - - /** - * \brief constructor - * - * \param _initial_point: initial arc end point; - * \param _rx: ellipse x-axis ray length - * \param _ry: ellipse y-axis ray length - * \param _rot_angle: ellipse x-axis rotation angle in radians; - * \param _large_arc: if true the largest arc is chosen, - * if false the smallest arc is chosen; - * \param _sweep : if true the clockwise arc is chosen, - * if false the counter-clockwise arc is chosen; - * \param _final_point: final arc end point; - * \param _svg_compliant: if true the class behaviour follows the Standard - * SVG 1.1 implementation guidelines (see Appendix F.6) - * if false the class behavoiur is more strict - * on input parameter - * - * in case the initial and the final arc end-points overlaps - * a degenerate arc of zero length is generated - * - */ - SVGEllipticalArc( Point _initial_point, double _rx, double _ry, - double _rot_angle, bool _large_arc, bool _sweep, - Point _final_point, - bool _svg_compliant = true +class SVGEllipticalArc : public EllipticalArc { +public: + SVGEllipticalArc() + : EllipticalArc() + {} + SVGEllipticalArc( Point ip, double rx, double ry, + double rot_angle, bool large_arc, bool sweep, + Point fp ) - : m_initial_point(_initial_point), m_final_point(_final_point), - m_rx(_rx), m_ry(_ry), m_rot_angle(_rot_angle), - m_large_arc(_large_arc), m_sweep(_sweep), - m_svg_compliant(_svg_compliant) + : EllipticalArc() { - calculate_center_and_extreme_angles(); + _initial_point = ip; + _final_point = fp; + _rays[X] = rx; _rays[Y] = ry; + _rot_angle = rot_angle; + _large_arc = large_arc; + _sweep = sweep; + _updateCenterAndAngles(true); } - void set( Point _initial_point, double _rx, double _ry, - double _rot_angle, bool _large_arc, bool _sweep, - Point _final_point - ) - { - m_initial_point = _initial_point; - m_final_point = _final_point; - m_rx = _rx; - m_ry = _ry; - m_rot_angle = _rot_angle; - m_large_arc = _large_arc; - m_sweep = _sweep; - calculate_center_and_extreme_angles(); - } - - Curve* duplicate() const - { +#ifndef DOXYGEN_SHOULD_SKIP_THIS + virtual Curve *duplicate() const { return new SVGEllipticalArc(*this); } - - double center(unsigned int i) const - { - return m_center[i]; + virtual Coord valueAt(Coord t, Dim2 d) const { + if (isDegenerate()) return chord().valueAt(t, d); + return EllipticalArc::valueAt(t, d); } - - Point center() const - { - return m_center; + virtual Point pointAt(Coord t) const { + if (isDegenerate()) return chord().pointAt(t); + return EllipticalArc::pointAt(t); } - - Point initialPoint() const - { - return m_initial_point; + virtual std::vector<Point> pointAndDerivatives(Coord t, unsigned int n) const { + if (isDegenerate()) return chord().pointAndDerivatives(t, n); + return EllipticalArc::pointAndDerivatives(t, n); } - - Point finalPoint() const - { - return m_final_point; + virtual Rect boundsExact() const { + if (isDegenerate()) return chord().boundsExact(); + return EllipticalArc::boundsExact(); } - - double start_angle() const - { - return m_start_angle; + virtual OptRect boundsLocal(OptInterval const &i, unsigned int deg) const { + if (isDegenerate()) return chord().boundsLocal(i, deg); + return EllipticalArc::boundsLocal(i, deg); } - double end_angle() const - { - return m_end_angle; + virtual Curve *derivative() const { + if (isDegenerate()) return chord().derivative(); + return EllipticalArc::derivative(); } - double ray(unsigned int i) const - { - return (i == 0) ? m_rx : m_ry; + virtual std::vector<Coord> roots(Coord v, Dim2 d) const { + if (isDegenerate()) return chord().roots(v, d); + return EllipticalArc::roots(v, d); } - - bool large_arc_flag() const - { - return m_large_arc; - } - - bool sweep_flag() const - { - return m_sweep; - } - - double rotation_angle() const - { - return m_rot_angle; - } - - void setInitial( const Point _point) - { - m_initial_point = _point; - calculate_center_and_extreme_angles(); - } - - void setFinal( const Point _point) - { - m_final_point = _point; - calculate_center_and_extreme_angles(); - } - - void setExtremes( const Point& _initial_point, const Point& _final_point ) - { - m_initial_point = _initial_point; - m_final_point = _final_point; - calculate_center_and_extreme_angles(); - } - - bool isDegenerate() const - { - return ( are_near(ray(X), 0) || are_near(ray(Y), 0) ); - } - - bool is_svg_compliant() const - { - return m_svg_compliant; - } - - virtual OptRect boundsFast() const - { - return boundsExact(); - } - - virtual OptRect boundsExact() const; - - // TODO: native implementation of the following methods - virtual OptRect boundsLocal(OptInterval i, unsigned int deg) const - { - if (isDegenerate() && is_svg_compliant()) - return chord().boundsLocal(i, deg); - else - return SBasisCurve(toSBasis()).boundsLocal(i, deg); - } - - std::vector<double> roots(double v, Dim2 d) const; - - /* - * find all the points on the curve portion between "from" and "to" - * at the same smallest distance from the point "p" the points are returned - * as their parameter t value; - */ - std::vector<double> - allNearestPoints( Point const& p, double from = 0, double to = 1 ) const; - - /* - * find a point on the curve portion between "from" and "to" - * at the same smallest distance from the point "p"; - * the point is returned as its parameter t value; - */ - double nearestPoint( Point const& p, double from = 0, double to = 1 ) const - { - if ( are_near(ray(X), ray(Y)) && are_near(center(), p) ) - { - return from; +#ifdef HAVE_GSL + virtual std::vector<Coord> allNearestPoints( Point const& p, double from = 0, double to = 1 ) const { + if (isDegenerate()) { + std::vector<Coord> result; + result.push_back(chord().nearestPoint(p, from, to)); + return result; } - return allNearestPoints(p, from, to).front(); - } - - // TODO: native implementation of the following methods - int winding(Point p) const - { - if (isDegenerate() && is_svg_compliant()) - return chord().winding(p); - else - return SBasisCurve(toSBasis()).winding(p); - } - - int degreesOfFreedom() const { return 5;} - - Curve *derivative() const; - - Curve *transformed(Matrix const &m) const; - - std::vector<Point> pointAndDerivatives(Coord t, unsigned int n) const; - - D2<SBasis> toSBasis() const; - - /* - * return true if the angle argument (in radiants) is contained - * in the range [start_angle(), end_angle() ] - */ - bool containsAngle(Coord angle) const; - - /* - * return the value of the d-dimensional coordinate related to "t" - * here t belongs to the [0,2PI] domain - */ - double valueAtAngle(Coord t, Dim2 d) const; - - /* - * return the point related to the parameter value "t" - * here t belongs to the [0,2PI] domain - */ - Point pointAtAngle(Coord t) const - { - double sin_rot_angle = std::sin(rotation_angle()); - double cos_rot_angle = std::cos(rotation_angle()); - Matrix m( ray(X) * cos_rot_angle, ray(X) * sin_rot_angle, - -ray(Y) * sin_rot_angle, ray(Y) * cos_rot_angle, - center(X), center(Y) ); - Point p( std::cos(t), std::sin(t) ); - return p * m; - } - - /* - * return the value of the d-dimensional coordinate related to "t" - * here t belongs to the [0,1] domain - */ - double valueAt(Coord t, Dim2 d) const - { - if (isDegenerate() && is_svg_compliant()) - return chord().valueAt(t, d); - - Coord tt = map_to_02PI(t); - return valueAtAngle(tt, d); - } - - /* - * return the point related to the parameter value "t" - * here t belongs to the [0,1] domain - */ - Point pointAt(Coord t) const - { - if (isDegenerate() && is_svg_compliant()) - return chord().pointAt(t); - - Coord tt = map_to_02PI(t); - return pointAtAngle(tt); - } - - std::pair<SVGEllipticalArc, SVGEllipticalArc> - subdivide(Coord t) const - { - SVGEllipticalArc* arc1 = static_cast<SVGEllipticalArc*>(portion(0, t)); - SVGEllipticalArc* arc2 = static_cast<SVGEllipticalArc*>(portion(t, 1)); - assert( arc1 != NULL && arc2 != NULL); - std::pair<SVGEllipticalArc, SVGEllipticalArc> arc_pair(*arc1, *arc2); - delete arc1; - delete arc2; - return arc_pair; - } - - Curve* portion(double f, double t) const; - - // the arc is the same but traversed in the opposite direction - Curve* reverse() const - { - SVGEllipticalArc* rarc = new SVGEllipticalArc( *this ); - rarc->m_sweep = !m_sweep; - rarc->m_initial_point = m_final_point; - rarc->m_final_point = m_initial_point; - rarc->m_start_angle = m_end_angle; - rarc->m_end_angle = m_start_angle; - return rarc; - } - - - double sweep_angle() const - { - Coord d = end_angle() - start_angle(); - if ( !sweep_flag() ) d = -d; - if ( d < 0 ) - d += 2*M_PI; - return d; - } - - LineSegment chord() const - { - return LineSegment(initialPoint(), finalPoint()); - } - - private: - Coord map_to_02PI(Coord t) const; - Coord map_to_01(Coord angle) const; - void calculate_center_and_extreme_angles(); - - private: - Point m_initial_point, m_final_point; - double m_rx, m_ry, m_rot_angle; - bool m_large_arc, m_sweep; - bool m_svg_compliant; - double m_start_angle, m_end_angle; - Point m_center; - + return EllipticalArc::allNearestPoints(p, from, to); + } +#endif + virtual D2<SBasis> toSBasis() const { + if (isDegenerate()) return chord().toSBasis(); + return EllipticalArc::toSBasis(); + } + virtual bool isSVGCompliant() const { return true; } + // TODO move SVG-specific behavior here. +//protected: + //virtual void _updateCenterAndAngles(); +#endif }; // end class SVGEllipticalArc - /* * useful for testing and debugging */ @@ -379,9 +137,9 @@ operator<< (std::basic_ostream<charT> & os, const SVGEllipticalArc & ea) { os << "{ cx: " << ea.center(X) << ", cy: " << ea.center(Y) << ", rx: " << ea.ray(X) << ", ry: " << ea.ray(Y) - << ", rot angle: " << decimal_round(rad_to_deg(ea.rotation_angle()),2) - << ", start angle: " << decimal_round(rad_to_deg(ea.start_angle()),2) - << ", end angle: " << decimal_round(rad_to_deg(ea.end_angle()),2) + << ", rot angle: " << decimal_round(rad_to_deg(ea.rotationAngle()),2) + << ", start angle: " << decimal_round(rad_to_deg(ea.initialAngle()),2) + << ", end angle: " << decimal_round(rad_to_deg(ea.finalAngle()),2) << " }"; return os; @@ -396,6 +154,7 @@ namespace detail struct ellipse_equation; } +// TODO this needs to be rewritten and moved to EllipticalArc header /* * make_elliptical_arc * @@ -428,7 +187,7 @@ class make_elliptical_arc * and the generated elliptical arc; the smaller it is the * the tolerance the higher it is the likelihood. */ - make_elliptical_arc( SVGEllipticalArc& _ea, + make_elliptical_arc( EllipticalArc& _ea, curve_type const& _curve, unsigned int _total_samples, double _tolerance ); @@ -486,7 +245,7 @@ class make_elliptical_arc } private: - SVGEllipticalArc& ea; // output elliptical arc + EllipticalArc& ea; // output elliptical arc const curve_type & curve; // input curve Piecewise<D2<SBasis> > dcurve; // derivative of the input curve NL::LFMEllipse model; // model used for fitting diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp index 804284077..4d35ccb35 100644 --- a/src/2geom/svg-path-parser.cpp +++ b/src/2geom/svg-path-parser.cpp @@ -1,3 +1,4 @@ +#line 1 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" /** * \file * \brief parse SVG path specifications @@ -139,7 +140,7 @@ private: }; -#line 144 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.cpp" +#line 144 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" static const char _svg_path_actions[] = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 15, 1, @@ -1144,7 +1145,7 @@ static const int svg_path_first_final = 270; static const int svg_path_en_main = 1; -#line 144 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 144 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" void Parser::parse(char const *str) @@ -1157,12 +1158,12 @@ throw(SVGPathParseError) _reset(); -#line 1162 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1162 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" { cs = svg_path_start; } -#line 1167 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1167 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" { int _klen; unsigned int _trans; @@ -1235,13 +1236,13 @@ _match: switch ( *_acts++ ) { case 0: -#line 156 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 156 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { start = p; } break; case 1: -#line 160 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 160 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { char const *end=p; std::string buf(start, end); @@ -1250,55 +1251,55 @@ _match: } break; case 2: -#line 167 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 167 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _push(1.0); } break; case 3: -#line 171 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 171 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _push(0.0); } break; case 4: -#line 175 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 175 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = true; } break; case 5: -#line 179 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 179 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = false; } break; case 6: -#line 183 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 183 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _moveTo(_pop_point()); } break; case 7: -#line 187 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 187 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(_pop_point()); } break; case 8: -#line 191 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 191 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _hlineTo(Point(_pop_coord(X), _current[Y])); } break; case 9: -#line 195 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 195 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _vlineTo(Point(_current[X], _pop_coord(Y))); } break; case 10: -#line 199 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 199 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1307,7 +1308,7 @@ _match: } break; case 11: -#line 206 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 206 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1315,7 +1316,7 @@ _match: } break; case 12: -#line 212 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 212 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c = _pop_point(); @@ -1323,14 +1324,14 @@ _match: } break; case 13: -#line 218 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 218 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); _quadTo(_quad_tangent, p); } break; case 14: -#line 223 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 223 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { Point point = _pop_point(); bool sweep = _pop_flag(); @@ -1343,16 +1344,16 @@ _match: } break; case 15: -#line 234 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 234 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" { _closePath(); } break; case 16: -#line 370 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 370 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" {goto _out;} break; -#line 1357 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1357 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.cpp" } } @@ -1363,7 +1364,7 @@ _again: goto _resume; _out: {} } -#line 380 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" +#line 380 "/opt/shared/work/programming/eclipse/eclipse_3.4/lib2geom/src/2geom/svg-path-parser.rl" if ( cs < svg_path_first_final ) { diff --git a/src/2geom/svg-path.cpp b/src/2geom/svg-path.cpp index 3e4bf7bec..d459b3e1b 100644 --- a/src/2geom/svg-path.cpp +++ b/src/2geom/svg-path.cpp @@ -61,8 +61,8 @@ void output(QuadraticBezier const &curve, SVGPathSink &sink) { } void output(SVGEllipticalArc const &curve, SVGPathSink &sink) { - sink.arcTo( curve.ray(X), curve.ray(Y), curve.rotation_angle(), - curve.large_arc_flag(), curve.sweep_flag(), + sink.arcTo( curve.ray(X), curve.ray(Y), curve.rotationAngle(), + curve.largeArc(), curve.sweep(), curve.finalPoint() ); } diff --git a/src/2geom/sweep.h b/src/2geom/sweep.h index 299813244..1c73efee0 100644 --- a/src/2geom/sweep.h +++ b/src/2geom/sweep.h @@ -51,6 +51,9 @@ struct Event { if(x > other.x) return false; return closing < other.closing; } + bool operator==(Event const &other) const { + return other.x == x && other.ix == ix && other.closing == closing; + } }; std::vector<std::vector<unsigned> > sweep_bounds(std::vector<Rect>, Dim2 dim = X); diff --git a/src/2geom/transforms.cpp b/src/2geom/transforms.cpp index 8182ce16d..3a1866c13 100644 --- a/src/2geom/transforms.cpp +++ b/src/2geom/transforms.cpp @@ -1,106 +1,143 @@ +/** + * @file + * @brief Affine transformation classes + *//* + * Authors: + * ? <?@?.?> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright ?-2009 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (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.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include <boost/concept_check.hpp> +#include <2geom/point.h> #include <2geom/transforms.h> namespace Geom { -Matrix operator*(Translate const &t, Scale const &s) { - Matrix ret(s); - ret[4] = t[X] * s[X]; - ret[5] = t[Y] * s[Y]; - return ret; +// Point transformation methods. +Point &Point::operator*=(Translate const &t) +{ + _pt[X] += t.vec[X]; + _pt[Y] += t.vec[Y]; + return *this; } - -Matrix operator*(Translate const &t, Rotate const &r) { - Matrix ret(r); - ret.setTranslation(t.vec * ret); - return ret; +Point &Point::operator*=(Scale const &s) +{ + _pt[X] *= s.vec[X]; + _pt[Y] *= s.vec[Y]; + return *this; } - -Matrix operator*(Scale const &s, Translate const &t) { - return Matrix(s[0], 0, - 0 , s[1], - t[0], t[1]); +Point &Point::operator*=(Rotate const &r) +{ + double x = _pt[X], y = _pt[Y]; + _pt[X] = x * r.vec[X] - y * r.vec[Y]; + _pt[Y] = y * r.vec[X] + x * r.vec[Y]; + return *this; } - -Matrix operator*(Scale const &s, Matrix const &m) { - Matrix ret(m); - ret[0] *= s[X]; - ret[1] *= s[X]; - ret[2] *= s[Y]; - ret[3] *= s[Y]; - return ret; +Point &Point::operator*=(HShear const &h) +{ + _pt[X] += h.f * _pt[Y]; + return *this; } - -Matrix operator*(Matrix const &m, Translate const &t) { - Matrix ret(m); - ret[4] += t[X]; - ret[5] += t[Y]; - return ret; +Point &Point::operator*=(VShear const &v) +{ + _pt[Y] += v.f * _pt[X]; + return *this; } -Matrix operator*(Matrix const &m, Scale const &s) { - Matrix ret(m); - ret[0] *= s[X]; ret[1] *= s[Y]; - ret[2] *= s[X]; ret[3] *= s[Y]; - ret[4] *= s[X]; ret[5] *= s[Y]; - return ret; -} +// Affine multiplication methods. -Matrix operator*(Matrix const &m, Rotate const &r) { - // TODO: we just convert the Rotate to a matrix and use the existing operator*(); is there a better way? - Matrix ret(m); - ret *= (Matrix) r; - return ret; +/** @brief Combine this transformation with a translation. */ +Affine &Affine::operator*=(Translate const &t) { + _c[4] += t[X]; + _c[5] += t[Y]; + return *this; } -Translate pow(Translate const &t, int n) { - return Translate(t[0]*n, t[1]*n); +/** @brief Combine this transformation with scaling. */ +Affine &Affine::operator*=(Scale const &s) { + _c[0] *= s[X]; _c[1] *= s[Y]; + _c[2] *= s[X]; _c[3] *= s[Y]; + _c[4] *= s[X]; _c[5] *= s[Y]; + return *this; } -Coord pow(Coord x, long n) // shamelessly lifted from WP -{ - Coord result = 1; - while ( n ) { - if ( n & 1 ) { - result = result * x; - n = n-1; - } - x = x*x; - n = n/2; - } - return result; +/** @brief Combine this transformation a rotation. */ +Affine &Affine::operator*=(Rotate const &r) { + // TODO: we just convert the Rotate to an Affine and use the existing operator*=() + // is there a better way? + *this *= (Affine) r; + return *this; } -Scale pow(Scale const &s, int n) { - return Scale(pow(s[0],n), pow(s[1],n)); +/** @brief Combine this transformation with horizontal shearing (skew). */ +Affine &Affine::operator*=(HShear const &h) { + _c[0] += h.f * _c[1]; + _c[2] += h.f * _c[3]; + _c[4] += h.f * _c[5]; + return *this; } -Rotate pow(Rotate x, long n) -{ - Rotate result(0,1); // identity - while ( n ) { - if ( n & 1 ) { - result = result * x; - n = n-1; - } - x = x*x; - n = n/2; - } - return result; +/** @brief Combine this transformation with vertical shearing (skew). */ +Affine &Affine::operator*=(VShear const &v) { + _c[1] += v.f * _c[0]; + _c[3] += v.f * _c[2]; + _c[5] += v.f * _c[4]; + return *this; } -Matrix pow(Matrix x, long n) +// this checks whether the requirements of TransformConcept are satisfied for all transforms. +// if you add a new transform type, include it here! +void check_transforms() { - Matrix result; - result.setIdentity(); - while ( n ) { - if ( n & 1 ) { - result = result * x; - n = n-1; - } - x = x*x; - n = n/2; - } - return result; +#ifdef BOOST_CONCEPT_ASSERT + BOOST_CONCEPT_ASSERT((TransformConcept<Translate>)); + BOOST_CONCEPT_ASSERT((TransformConcept<Scale>)); + BOOST_CONCEPT_ASSERT((TransformConcept<Rotate>)); + BOOST_CONCEPT_ASSERT((TransformConcept<HShear>)); + BOOST_CONCEPT_ASSERT((TransformConcept<VShear>)); + BOOST_CONCEPT_ASSERT((TransformConcept<Affine>)); // Affine is also a transform +#endif + + // check inter-transform multiplication + Affine m; + Translate t(Translate::identity()); + Scale s(Scale::identity()); + Rotate r(Rotate::identity()); + HShear h(HShear::identity()); + VShear v(VShear::identity()); + + // notice that the first column is always the same and enumerates all transform types, + // while the second one changes to each transform type in turn. + m = t * t; m = t * s; m = t * r; m = t * h; m = t * v; + m = s * t; m = s * s; m = s * r; m = s * h; m = s * v; + m = r * t; m = r * s; m = r * r; m = r * h; m = r * v; + m = h * t; m = h * s; m = h * r; m = h * h; m = h * v; + m = v * t; m = v * s; m = v * r; m = v * h; m = v * v; } } diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index 1d8d87da3..1c965eb9f 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -1,11 +1,12 @@ /** - * \file - * \brief Transforms should be applied left to right. scale * translate means: first scale, then translate. - * + * @file + * @brief Affine transformation classes + *//* * Authors: - * ? <?@?.?> + * ? <?@?.?> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> * - * Copyright ?-? authors + * Copyright ?-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -29,132 +30,232 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. - * */ #ifndef SEEN_Geom_TRANSFORMS_H #define SEEN_Geom_TRANSFORMS_H -#include <2geom/matrix.h> +#include <2geom/forward.h> +#include <2geom/affine.h> #include <cmath> namespace Geom { +/** @brief Type requirements for transforms. + * @ingroup Concepts */ template <typename T> struct TransformConcept { T t; - Matrix m; + Affine m; Point p; + bool bool_; void constraints() { m = t; //implicit conversion - t = t.inverse(); + m *= t; + m = m * t; + m = t * m; + p *= t; p = p * t; + t *= t; t = t * t; + t = pow(t, 3); + bool_ = (t == t); + bool_ = (t != t); + t = T::identity(); + t = t.inverse(); } }; +/** @brief Base template for transforms. */ +template <typename T> +class TransformOperations + : boost::equality_comparable< T + , boost::multipliable< T + > > +{ +public: + template <typename T2> + Affine operator*(T2 const &t) const { + Affine ret(*static_cast<T const*>(this)); ret *= t; return ret; + } +}; -class Rotate; -class Translate { - private: - Translate(); +/** @brief Integer exponentiation for transforms. + * Negative exponents will yield the corresponding power of the inverse. This function + * can also be applied to matrices. + * @param t Affine or transform to exponantiate + * @param n Exponent + * @return \f$A^n\f$ if @a n is positive, \f$(A^{-1})^n\f$ if negative, identity if zero. + * @ingroup Transforms */ +template <typename T> +T pow(T const &t, int n) { + if (n == 0) return T::identity(); + T result(T::identity()); + T x(n < 0 ? t.inverse() : t); + if (n < 0) n = -n; + while ( n ) { // binary exponentiation - fast + if ( n & 1 ) { result *= x; --n; } + x *= x; n /= 2; + } + return result; +} + +/** @brief Translation by a vector. + * @ingroup Transforms */ +class Translate + : public TransformOperations< Translate > +{ + Translate() : vec(0, 0) {} Point vec; - public: +public: + /** @brief Construct a translation from its vector. */ explicit Translate(Point const &p) : vec(p) {} - explicit Translate(Coord const x, Coord const y) : vec(x, y) {} - inline operator Matrix() const { return Matrix(1, 0, 0, 1, vec[X], vec[Y]); } + /** @brief Construct a translation from its coordinates. */ + explicit Translate(Coord x, Coord y) : vec(x, y) {} - inline Coord operator[](Dim2 const dim) const { return vec[dim]; } - inline Coord operator[](unsigned const dim) const { return vec[dim]; } - inline bool operator==(Translate const &o) const { return vec == o.vec; } - inline bool operator!=(Translate const &o) const { return vec != o.vec; } + operator Affine() const { Affine ret(1, 0, 0, 1, vec[X], vec[Y]); return ret; } + Coord operator[](Dim2 dim) const { return vec[dim]; } + Coord operator[](unsigned dim) const { return vec[dim]; } + Translate &operator*=(Translate const &o) { vec += o.vec; return *this; } + bool operator==(Translate const &o) const { return vec == o.vec; } - inline Translate inverse() const { return Translate(-vec); } + /** @brief Get the inverse translation. */ + Translate inverse() const { return Translate(-vec); } + /** @brief Get a translation that doesn't do anything. */ + static Translate identity() { Translate ret; return ret; } - friend Point operator*(Point const &v, Translate const &t); - inline Translate operator*(Translate const &b) const { return Translate(vec + b.vec); } - - friend Matrix operator*(Translate const &t, Rotate const &r); + friend class Point; }; -inline Point operator*(Point const &v, Translate const &t) { return v + t.vec; } - -class Scale { - private: +/** @brief Scaling from the origin. + * During scaling, the point (0,0) will not move. To obtain a scale with a different + * invariant point, combine with translation to the origin and back. + * @ingroup Transforms */ +class Scale + : public TransformOperations< Scale > +{ Point vec; - Scale(); - public: + Scale() : vec(1, 1) {} +public: explicit Scale(Point const &p) : vec(p) {} - Scale(Coord const x, Coord const y) : vec(x, y) {} - explicit Scale(Coord const s) : vec(s, s) {} - inline operator Matrix() const { return Matrix(vec[X], 0, 0, vec[Y], 0, 0); } + Scale(Coord x, Coord y) : vec(x, y) {} + explicit Scale(Coord s) : vec(s, s) {} + inline operator Affine() const { Affine ret(vec[X], 0, 0, vec[Y], 0, 0); return ret; } - inline Coord operator[](Dim2 const d) const { return vec[d]; } - inline Coord operator[](unsigned const d) const { return vec[d]; } + Coord operator[](Dim2 d) const { return vec[d]; } + Coord operator[](unsigned d) const { return vec[d]; } //TODO: should we keep these mutators? add them to the other transforms? - inline Coord &operator[](Dim2 const d) { return vec[d]; } - inline Coord &operator[](unsigned const d) { return vec[d]; } - inline bool operator==(Scale const &o) const { return vec == o.vec; } - inline bool operator!=(Scale const &o) const { return vec != o.vec; } + Coord &operator[](Dim2 d) { return vec[d]; } + Coord &operator[](unsigned d) { return vec[d]; } + Scale &operator*=(Scale const &b) { vec[X] *= b[X]; vec[Y] *= b[Y]; return *this; } + bool operator==(Scale const &o) const { return vec == o.vec; } + Scale inverse() const { return Scale(1./vec[0], 1./vec[1]); } + static Scale identity() { Scale ret; return ret; } - inline Scale inverse() const { return Scale(1./vec[0], 1./vec[1]); } - - friend Point operator*(Point const &v, Translate const &t); - inline Scale operator*(Scale const &b) const { return Scale(vec[X]*b[X], vec[Y]*b[Y]); } + friend class Point; }; -inline Point operator*(Point const &p, Scale const &s) { return Point(p[X] * s[X], p[Y] * s[Y]); } - -/** Notionally an Geom::Matrix corresponding to rotation about the origin. - Behaves like Geom::Matrix for multiplication. -**/ -class Rotate { - private: - Rotate() {} +/** @brief Rotation around the origin. + * Combine with translations to the origin and back to get a rotation around a different point. + * @ingroup Transforms */ +class Rotate + : public TransformOperations< Rotate > +{ + Rotate() : vec(1, 0) {} Point vec; - public: - explicit Rotate(Coord theta) : vec(std::cos(theta), std::sin(theta)) {} - Rotate(Point const &p) {Point v = p; v.normalize(); vec = v;} //TODO: UGLY! +public: + /** @brief Construct a rotation from its angle in radians. + * Positive arguments correspond to counter-clockwise rotations (if Y grows upwards). */ + explicit Rotate(Coord theta) : vec(Point::polar(theta)) {} + /** @brief Construct a rotation from its characteristic vector. */ + explicit Rotate(Point const &p) : vec(unit_vector(p)) {} + /** @brief Construct a rotation from the coordinates of its characteristic vector. */ explicit Rotate(Coord x, Coord y) { Rotate(Point(x, y)); } - inline operator Matrix() const { return Matrix(vec[X], vec[Y], -vec[Y], vec[X], 0, 0); } + operator Affine() const { Affine ret(vec[X], vec[Y], -vec[Y], vec[X], 0, 0); return ret; } - inline Point vector() const { return vec; } - inline Coord operator[](Dim2 const dim) const { return vec[dim]; } - inline Coord operator[](unsigned const dim) const { return vec[dim]; } - inline bool operator==(Rotate const &o) const { return vec == o.vec; } - inline bool operator!=(Rotate const &o) const { return vec != o.vec; } - - inline Rotate inverse() const { + /** @brief Get the characteristic vector of the rotation. + * @return A vector that would be obtained by applying this transform to the X versor. */ + Point vector() const { return vec; } + Coord operator[](Dim2 dim) const { return vec[dim]; } + Coord operator[](unsigned dim) const { return vec[dim]; } + Rotate &operator*=(Rotate const &o) { vec *= o; return *this; } + bool operator==(Rotate const &o) const { return vec == o.vec; } + Rotate inverse() const { Rotate r; r.vec = Point(vec[X], -vec[Y]); return r; } + /** @brief Get a 0-degree rotation. */ + static Rotate identity() { Rotate ret; return ret; } + /** @brief Construct a rotation from its angle in degrees. + * Positive arguments correspond to counter-clockwise rotations (if Y grows upwards). */ static Rotate from_degrees(Coord deg) { Coord rad = (deg / 180.0) * M_PI; return Rotate(rad); } - friend Point operator*(Point const &v, Rotate const &r); - inline Rotate operator*(Rotate const &b) const { return Rotate(vec * b); } + friend class Point; }; -inline Point operator*(Point const &v, Rotate const &r) { return v ^ r.vec; } +/** @brief Common base for shearing transforms. + * @ingroup Transforms */ +template <typename S> +class ShearBase + : public TransformOperations< S > +{ +protected: + Coord f; + ShearBase(Coord _f) : f(_f) {} +public: + Coord factor() const { return f; } + void setFactor(Coord nf) { f = nf; } + S &operator*=(S const &s) { f += s.f; return *static_cast<S const*>(this); } + bool operator==(S const &s) const { return f == s.f; } + S inverse() const { return S(-f); } + static S identity() { return S(0); } -Matrix operator*(Translate const &t, Scale const &s); -Matrix operator*(Translate const &t, Rotate const &r); + friend class Point; + friend class Affine; +}; -Matrix operator*(Scale const &s, Translate const &t); -Matrix operator*(Scale const &s, Matrix const &m); +/** @brief Horizontal shearing. + * Points on the X axis will not move. Combine with translations to get a shear + * with a different invariant line. + * @ingroup Transforms */ +class HShear + : public ShearBase<HShear> +{ +public: + explicit HShear(Coord h) : ShearBase<HShear>(h) {} + operator Affine() const { Affine ret(1, 0, f, 1, 0, 0); return ret; } +}; -Matrix operator*(Matrix const &m, Translate const &t); -Matrix operator*(Matrix const &m, Scale const &s); -Matrix operator*(Matrix const &m, Rotate const &r); -Matrix operator*(Matrix const &m1, Matrix const &m2); +/** @brief Vertical shearing. + * Points on the Y axis will not move. Combine with translations to get a shear + * with a different invariant line. + * @ingroup Transforms */ +class VShear + : public ShearBase<VShear> +{ +public: + explicit VShear(Coord h) : ShearBase<VShear>(h) {} + operator Affine() const { Affine ret(1, f, 0, 1, 0, 0); return ret; } +}; -Translate pow(Translate const &t, int n); -Scale pow(Scale const &t, int n); -Rotate pow(Rotate t, int n); -Matrix pow(Matrix t, int n); +/** @brief Specialization of exponentiation for Scale. + * @relates Scale */ +template<> +inline Scale pow(Scale const &s, int n) { + Scale ret(::pow(s[X], n), ::pow(s[Y], n)); + return ret; +} +/** @brief Specialization of exponentiation for Translate. + * @relates Translate */ +template<> +inline Translate pow(Translate const &t, int n) { + Translate ret(t[X] * n, t[Y] * n); + return ret; +} //TODO: matrix to trans/scale/rotate diff --git a/src/2geom/utils.h b/src/2geom/utils.h index dcadc8431..ecd1b7283 100644 --- a/src/2geom/utils.h +++ b/src/2geom/utils.h @@ -33,7 +33,6 @@ * */ -#include <cmath> #include <vector> namespace Geom { @@ -41,46 +40,23 @@ namespace Geom { // proper logical xor inline bool logical_xor (bool a, bool b) { return (a || b) && !(a && b); } -/** Sign function - indicates the sign of a numeric type. -1 indicates negative, 1 indicates - * positive, and 0 indicates, well, 0. Mathsy people will know this is basically the derivative - * of abs, except for the fact that it is defined on 0. - */ -template <class T> inline int sgn(const T& x) {return (x < 0 ? -1 : (x > 0 ? 1 : 0) );} - -template <class T> inline T sqr(const T& x) {return x * x;} -template <class T> inline T cube(const T& x) {return x * x * x;} +void binomial_coefficients(std::vector<size_t>& bc, size_t n); -/** Between function - returns true if a number x is within a range. The values delimiting the - * range and the number must have the same type. - */ -template <class T> inline const T& between (const T& min, const T& max, const T& x) - { return min < x && max > x; } +struct EmptyClass {}; -/** Returns x rounded to the nearest integer. It is unspecified what happens - * if x is half way between two integers: we may in future use rint/round - * on platforms that have them. +/** + * @brief Noncommutative multiplication helper. + * Generates operator*(T, U) from operator*=(T, U). Does not generate operator*(U, T) + * like boost::multipliable does. This makes it suitable for noncommutative cases, + * such as transforms. */ -inline double round(double const x) { return std::floor(x + .5); } - -/** Returns x rounded to the nearest \a places decimal places. - - Implemented in terms of round, i.e. we make no guarantees as to what happens if x is - half way between two rounded numbers. - - Note: places is the number of decimal places without using scientific (e) notation, not the - number of significant figures. This function may not be suitable for values of x whose - magnitude is so far from 1 that one would want to use scientific (e) notation. - - places may be negative: e.g. places = -2 means rounding to a multiple of .01 -**/ -inline double decimal_round(double const x, int const places) { - //TODO: possibly implement with modulus instead? - double const multiplier = std::pow(10.0, places); - return round( x * multiplier ) / multiplier; -} - - -void binomial_coefficients(std::vector<size_t>& bc, size_t n); +template <class T, class U, class B = EmptyClass> +struct MultipliableNoncommutative : B +{ + friend T operator*(T const &lhs, U const &rhs) { + T nrv(lhs); nrv *= rhs; return nrv; + } +}; } diff --git a/src/Makefile.am b/src/Makefile.am index 6810d6d9d..c7381546b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -212,7 +212,11 @@ libinkscape_a_SOURCES = $(ink_common_sources) inkscape_SOURCES += main.cpp $(win32_sources) inkscape_LDADD = $(all_libs) +if EXPORT_DYNAMIC_DIRECT inkscape_LDFLAGS = --export-dynamic $(kdeldflags) $(mwindows) +else +inkscape_LDFLAGS = -Wl,--export-dynamic $(kdeldflags) $(mwindows) +endif inkview_SOURCES += inkview.cpp $(win32_sources) inkview_LDADD = $(all_libs) diff --git a/src/arc-context.cpp b/src/arc-context.cpp index 1c480ecbc..76b064f06 100644 --- a/src/arc-context.cpp +++ b/src/arc-context.cpp @@ -447,7 +447,7 @@ static void sp_arc_drag(SPArcContext *ac, Geom::Point pt, guint state) Geom::Point c = r.midpoint(); if (!ctrl_save) { if (fabs(dir[Geom::X]) > 1E-6 && fabs(dir[Geom::Y]) > 1E-6) { - Geom::Matrix const i2d ((ac->item)->i2d_affine ()); + Geom::Affine const i2d ((ac->item)->i2d_affine ()); Geom::Point new_dir = pt * i2d - c; new_dir[Geom::X] *= dir[Geom::Y] / dir[Geom::X]; double lambda = new_dir.length() / dir[Geom::Y]; diff --git a/src/arc-context.h b/src/arc-context.h index 1e182225a..3ed4478ba 100644 --- a/src/arc-context.h +++ b/src/arc-context.h @@ -15,6 +15,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <stddef.h> #include <sigc++/connection.h> #include <2geom/point.h> diff --git a/src/box3d-context.h b/src/box3d-context.h index 913e98263..4b8435d74 100644 --- a/src/box3d-context.h +++ b/src/box3d-context.h @@ -15,6 +15,7 @@ * Released under GNU GPL */ +#include <stddef.h> #include <sigc++/sigc++.h> #include "event-context.h" #include "proj_pt.h" diff --git a/src/box3d-side.cpp b/src/box3d-side.cpp index 72a479ca4..0c74a8f7e 100644 --- a/src/box3d-side.cpp +++ b/src/box3d-side.cpp @@ -209,21 +209,21 @@ void box3d_side_position_set (Box3DSide *side) { box3d_side_set_shape (SP_SHAPE (side)); - /* This call is responsible for live update of the sides during the initial drag */ - SP_OBJECT(side)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + // This call is responsible for live update of the sides during the initial drag + side->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } void box3d_side_set_shape (SPShape *shape) { Box3DSide *side = SP_BOX3D_SIDE (shape); - if (!SP_OBJECT_DOCUMENT(side)->root) { + if (!side->document->root) { // avoid a warning caused by sp_document_height() (which is called from sp_item_i2d_affine() below) // when reading a file containing 3D boxes return; } - SPObject *parent = SP_OBJECT(side)->parent; + SPObject *parent = side->parent; if (!SP_IS_BOX3D(parent)) { g_warning ("Parent of 3D box side is not a 3D box.\n"); return; @@ -306,12 +306,12 @@ box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]) { Persp3D * box3d_side_perspective(Box3DSide *side) { - return SP_BOX3D(SP_OBJECT(side)->parent)->persp_ref->getObject(); + return SP_BOX3D(side->parent)->persp_ref->getObject(); } Inkscape::XML::Node *box3d_side_convert_to_path(Box3DSide *side) { // TODO: Copy over all important attributes (see sp_selected_item_to_curved_repr() for an example) - SPDocument *doc = SP_OBJECT_DOCUMENT(side); + SPDocument *doc = side->document; Inkscape::XML::Document *xml_doc = doc->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); diff --git a/src/box3d.cpp b/src/box3d.cpp index b6bebc141..ac5814e4d 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -49,7 +49,7 @@ static void box3d_update(SPObject *object, SPCtx *ctx, guint flags); static Inkscape::XML::Node *box3d_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static gchar *box3d_description(SPItem *item); -static Geom::Matrix box3d_set_transform(SPItem *item, Geom::Matrix const &xform); +static Geom::Affine box3d_set_transform(SPItem *item, Geom::Affine const &xform); static void box3d_convert_to_guides(SPItem *item); static void box3d_ref_changed(SPObject *old_ref, SPObject *ref, SPBox3D *box); @@ -105,11 +105,10 @@ static void box3d_init(SPBox3D *box) { box->persp_href = NULL; - box->persp_ref = new Persp3DReference(SP_OBJECT(box)); + box->persp_ref = new Persp3DReference(box); } -static void -box3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) +static void box3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) { if (((SPObjectClass *) (parent_class))->build) { ((SPObjectClass *) (parent_class))->build(object, document, repr); @@ -125,15 +124,14 @@ box3d_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) // TODO: Create/link to the correct perspective - SPDocument *doc = SP_OBJECT_DOCUMENT(box); - if (!doc) - return; - - box->persp_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(box3d_ref_changed), box)); + SPDocument *doc = box->document; + if ( doc ) { + box->persp_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(box3d_ref_changed), box)); - object->readAttr( "inkscape:perspectiveID" ); - object->readAttr( "inkscape:corner0" ); - object->readAttr( "inkscape:corner7" ); + object->readAttr( "inkscape:perspectiveID" ); + object->readAttr( "inkscape:corner0" ); + object->readAttr( "inkscape:corner7" ); + } } /** @@ -168,7 +166,7 @@ box3d_release(SPObject *object) // by the following code and then again by the redo mechanism! Perhaps we should perform // deletion of the perspective from another location "outside" the undo/redo mechanism? if (persp->perspective_impl->boxes.empty()) { - SPDocument *doc = SP_OBJECT_DOCUMENT(box); + SPDocument *doc = box->document; persp->deleteObject(); doc->setCurrentPersp3D(persp3d_document_first_persp(doc)); } @@ -283,7 +281,7 @@ static Inkscape::XML::Node * box3d_write(SPObject *object, Inkscape::XML::Docume repr->setAttribute("inkscape:perspectiveID", box->persp_href); } else { /* box is not yet linked to a perspective; use the document's current perspective */ - SPDocument *doc = SP_OBJECT_DOCUMENT(object); + SPDocument *doc = object->document; if (box->persp_ref->getURI()) { gchar *uri_string = box->persp_ref->getURI()->toString(); repr->setAttribute("inkscape:perspectiveID", uri_string); @@ -335,15 +333,15 @@ void box3d_position_set(SPBox3D *box) } } -static Geom::Matrix -box3d_set_transform(SPItem *item, Geom::Matrix const &xform) +static Geom::Affine +box3d_set_transform(SPItem *item, Geom::Affine const &xform) { SPBox3D *box = SP_BOX3D(item); // We don't apply the transform to the box directly but instead to its perspective (which is // done in sp_selection_apply_affine). Here we only adjust strokes, patterns, etc. - Geom::Matrix ret(Geom::Matrix(xform).without_translation()); + Geom::Affine ret(Geom::Affine(xform).withoutTranslation()); gdouble const sw = hypot(ret[0], ret[1]); gdouble const sh = hypot(ret[2], ret[3]); @@ -390,7 +388,7 @@ box3d_get_corner_screen (SPBox3D const *box, guint id, bool item_coords) { if (!box3d_get_perspective(box)) { return Geom::Point (Geom::infinity(), Geom::infinity()); } - Geom::Matrix const i2d (SP_ITEM(box)->i2d_affine ()); + Geom::Affine const i2d (SP_ITEM(box)->i2d_affine ()); if (item_coords) { return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_corner).affine() * i2d.inverse(); } else { @@ -414,7 +412,7 @@ box3d_get_center_screen (SPBox3D *box) { if (!box3d_get_perspective(box)) { return Geom::Point (Geom::infinity(), Geom::infinity()); } - Geom::Matrix const i2d (SP_ITEM(box)->i2d_affine ()); + Geom::Affine const i2d (SP_ITEM(box)->i2d_affine ()); return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_center).affine() * i2d.inverse(); } @@ -1344,7 +1342,7 @@ box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp, the original box and deletes the latter */ SPGroup *box3d_convert_to_group(SPBox3D *box) { - SPDocument *doc = SP_OBJECT_DOCUMENT(box); + SPDocument *doc = box->document; Inkscape::XML::Document *xml_doc = doc->getReprDoc(); // remember position of the box @@ -1369,7 +1367,7 @@ SPGroup *box3d_convert_to_group(SPBox3D *box) } // add the new group to the box's parent and set remembered position - SPObject *parent = SP_OBJECT_PARENT(box); + SPObject *parent = box->parent; parent->appendChild(grepr); grepr->setPosition(pos); grepr->setAttribute("style", style); @@ -1378,7 +1376,7 @@ SPGroup *box3d_convert_to_group(SPBox3D *box) if (clip_path) grepr->setAttribute("clip-path", clip_path); - SP_OBJECT(box)->deleteObject(true); + box->deleteObject(true); grepr->setAttribute("id", id); diff --git a/src/color-profile.cpp b/src/color-profile.cpp index e08a416d3..f06ebab88 100644 --- a/src/color-profile.cpp +++ b/src/color-profile.cpp @@ -283,7 +283,7 @@ void ColorProfile::set( SPObject *object, unsigned key, gchar const *value ) //LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize); // Try to open relative - SPDocument *doc = SP_OBJECT_DOCUMENT(object); + SPDocument *doc = object->document; if (!doc) { doc = SP_ACTIVE_DOCUMENT; g_warning("object has no document. using active"); diff --git a/src/common-context.h b/src/common-context.h index 416307d58..74b6bbaef 100644 --- a/src/common-context.h +++ b/src/common-context.h @@ -21,7 +21,6 @@ #include "event-context.h" #include "display/curve.h" -#include "display/display-forward.h" #include <2geom/point.h> #define SP_TYPE_COMMON_CONTEXT (sp_common_context_get_type()) diff --git a/src/conditions.cpp b/src/conditions.cpp index d35f18cf1..21218831a 100644 --- a/src/conditions.cpp +++ b/src/conditions.cpp @@ -103,7 +103,7 @@ static bool evaluateSystemLanguage(SPItem const *item, gchar const *value) { if (language_codes.empty()) return false; - SPDocument *document = SP_OBJECT_DOCUMENT(item); + SPDocument *document = item->document; Glib::ustring document_language = document->getLanguage(); if (document_language.size() == 0) diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index 21ef2deab..4c6139672 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -75,13 +75,12 @@ SPAvoidRef::~SPAvoidRef() void SPAvoidRef::setAvoid(char const *value) { - if (SP_OBJECT_IS_CLONED(item)) { - // Don't keep avoidance information for cloned objects. - return; - } - new_setting = false; - if (value && (strcmp(value, "true") == 0)) { - new_setting = true; + // Don't keep avoidance information for cloned objects. + if ( !item->cloned ) { + new_setting = false; + if (value && (strcmp(value, "true") == 0)) { + new_setting = true; + } } } @@ -194,7 +193,7 @@ void SPAvoidRef::setConnectionPoints(gchar const *value) void SPAvoidRef::setConnectionPointsAttrUndoable(const gchar* value, const gchar* action) { - SPDocument* doc = SP_OBJECT_DOCUMENT(item); + SPDocument* doc = item->document; item->setAttribute( "inkscape:connection-points", value, 0 ); item->updateRepr(); @@ -390,7 +389,7 @@ Geom::Point SPAvoidRef::getConnectionPointPos(const int type, const int id) { g_assert(item); Geom::Point pos; - const Geom::Matrix& transform = item->i2doc_affine(); + const Geom::Affine& transform = item->i2doc_affine(); if ( type == ConnPointDefault ) { @@ -475,7 +474,7 @@ static std::vector<Geom::Point> approxCurveWithPoints(SPCurve *curve) return poly_points; } -static std::vector<Geom::Point> approxItemWithPoints(SPItem const *item, const Geom::Matrix& item_transform) +static std::vector<Geom::Point> approxItemWithPoints(SPItem const *item, const Geom::Affine& item_transform) { // The structure to hold the output std::vector<Geom::Point> poly_points; @@ -512,7 +511,7 @@ static Avoid::Polygon avoid_item_poly(SPItem const *item) g_assert(desktop != NULL); double spacing = desktop->namedview->connector_spacing; - Geom::Matrix itd_mat = item->i2doc_affine(); + Geom::Affine itd_mat = item->i2doc_affine(); std::vector<Geom::Point> hull_points; hull_points = approxItemWithPoints(item, itd_mat); @@ -525,15 +524,15 @@ static Avoid::Polygon avoid_item_poly(SPItem const *item) Geom::Line hull_edge(hull[-1], hull[0]); Geom::Line prev_parallel_hull_edge; - prev_parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing); - prev_parallel_hull_edge.versor(hull_edge.versor()); + prev_parallel_hull_edge.setOrigin(hull_edge.origin()+hull_edge.versor().ccw()*spacing); + prev_parallel_hull_edge.setVersor(hull_edge.versor()); int hull_size = hull.boundary.size(); for (int i = 0; i < hull_size; ++i) { - hull_edge.setBy2Points(hull[i], hull[i+1]); + hull_edge.setPoints(hull[i], hull[i+1]); Geom::Line parallel_hull_edge; - parallel_hull_edge.origin(hull_edge.origin()+hull_edge.versor().ccw()*spacing); - parallel_hull_edge.versor(hull_edge.versor()); + parallel_hull_edge.setOrigin(hull_edge.origin()+hull_edge.versor().ccw()*spacing); + parallel_hull_edge.setVersor(hull_edge.versor()); // determine the intersection point @@ -578,7 +577,7 @@ GSList *get_avoided_items(GSList *list, SPObject *from, SPDesktop *desktop, } -void avoid_item_move(Geom::Matrix const */*mp*/, SPItem *moved_item) +void avoid_item_move(Geom::Affine const */*mp*/, SPItem *moved_item) { Avoid::ShapeRef *shapeRef = moved_item->avoidRef->shapeRef; g_assert(shapeRef); diff --git a/src/conn-avoid-ref.h b/src/conn-avoid-ref.h index 5dff8dd38..9a028371a 100644 --- a/src/conn-avoid-ref.h +++ b/src/conn-avoid-ref.h @@ -14,6 +14,7 @@ */ #include <glib/gslist.h> +#include <stddef.h> #include <sigc++/connection.h> struct SPDesktop; @@ -65,7 +66,7 @@ private: extern GSList *get_avoided_items(GSList *list, SPObject *from, SPDesktop *desktop, bool initialised = true); -extern void avoid_item_move(Geom::Matrix const *mp, SPItem *moved_item); +extern void avoid_item_move(Geom::Affine const *mp, SPItem *moved_item); extern void init_avoided_shape_geometry(SPDesktop *desktop); static const double defaultConnSpacing = 3.0; diff --git a/src/connection-pool.h b/src/connection-pool.h index 67bcf0002..4aa44e30a 100644 --- a/src/connection-pool.h +++ b/src/connection-pool.h @@ -3,6 +3,7 @@ #include <glib-object.h> #include <gtkmm.h> +#include <stddef.h> #include <sigc++/sigc++.h> namespace Inkscape diff --git a/src/connector-context.cpp b/src/connector-context.cpp index b1061c124..27e052499 100644 --- a/src/connector-context.cpp +++ b/src/connector-context.cpp @@ -1,12 +1,14 @@ -/* +/** * Connector creation tool * * Authors: * Michael Wybrow <mjwybrow@users.sourceforge.net> * Abhishek Sharma + * Jon A. Cruz <jon@joncruz.org> * * Copyright (C) 2005-2008 Michael Wybrow * Copyright (C) 2009 Monash University + * Copyright (C) 2010 authors * * Released under GNU GPL, read the file 'COPYING' for more information * @@ -172,6 +174,7 @@ #include "inkscape.h" #include "preferences.h" #include "sp-path.h" +#include "display/sp-canvas.h" #include "display/canvas-bpath.h" #include "display/sodipodi-ctrl.h" #include <glibmm/i18n.h> @@ -486,7 +489,7 @@ void sp_connector_context_switch_mode(SPEventContext* ec, unsigned int newMode) cc->knot_tip = cc_knot_tips[1]; /* if (cc->active_shape) { - cc->selection->set( SP_OBJECT( cc->active_shape ) ); + cc->selection->set( cc->active_shape ); } else { @@ -494,7 +497,7 @@ void sp_connector_context_switch_mode(SPEventContext* ec, unsigned int newMode) if ( item ) { cc_set_active_shape(cc, item); - cc->selection->set( SP_OBJECT( item ) ); + cc->selection->set( item ); } }*/ } @@ -896,7 +899,7 @@ connector_handle_button_press(SPConnectorContext *const cc, GdkEventButton const if ( cc->selected_handle ) { cc->state = SP_CONNECTOR_CONTEXT_DRAGGING; - cc->selection->set( SP_OBJECT( cc->active_shape ) ); + cc->selection->set( cc->active_shape ); } ret = TRUE; @@ -974,8 +977,8 @@ connector_handle_motion_notify(SPConnectorContext *const cc, GdkEventMotion cons m.unSetup(); // Update the hidden path - Geom::Matrix i2d = (cc->clickeditem)->i2d_affine(); - Geom::Matrix d2i = i2d.inverse(); + Geom::Affine i2d = (cc->clickeditem)->i2d_affine(); + Geom::Affine d2i = i2d.inverse(); SPPath *path = SP_PATH(cc->clickeditem); SPCurve *curve = path->original_curve ? path->original_curve : path->curve; if (cc->clickedhandle == cc->endpt_handle[0]) { @@ -1200,7 +1203,7 @@ connector_handle_key_press(SPConnectorContext *const cc, guint const keyval) // Obtain original position ConnectionPoint const& cp = cc->connpthandles[cc->selected_handle]; SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(cc); - const Geom::Matrix& i2doc = (cc->active_shape)->i2doc_affine(); + const Geom::Affine& i2doc = (cc->active_shape)->i2doc_affine(); sp_knot_set_position(cc->selected_handle, cp.pos * i2doc * desktop->doc2dt(), 0); cc->state = SP_CONNECTOR_CONTEXT_IDLE; desktop->messageStack()->flash( Inkscape::NORMAL_MESSAGE, @@ -1604,7 +1607,7 @@ endpt_handler(SPKnot */*knot*/, GdkEvent *event, SPConnectorContext *cc) // Show the red path for dragging. cc->red_curve = SP_PATH(cc->clickeditem)->original_curve ? SP_PATH(cc->clickeditem)->original_curve->copy() : SP_PATH(cc->clickeditem)->curve->copy(); - Geom::Matrix i2d = (cc->clickeditem)->i2d_affine(); + Geom::Affine i2d = (cc->clickeditem)->i2d_affine(); cc->red_curve->transform(i2d); sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(cc->red_bpath), cc->red_curve); @@ -1665,7 +1668,7 @@ static void cc_set_active_shape(SPConnectorContext *cc, SPItem *item) } // Listen in case the active shape changes - cc->active_shape_repr = SP_OBJECT_REPR(item); + cc->active_shape_repr = item->getRepr(); if (cc->active_shape_repr) { Inkscape::GC::anchor(cc->active_shape_repr); sp_repr_add_listener(cc->active_shape_repr, &shape_repr_events, cc); @@ -1763,7 +1766,7 @@ cc_set_active_conn(SPConnectorContext *cc, SPItem *item) g_assert( SP_IS_PATH(item) ); SPCurve *curve = SP_PATH(item)->original_curve ? SP_PATH(item)->original_curve : SP_PATH(item)->curve; - Geom::Matrix i2d = item->i2d_affine(); + Geom::Affine i2d = item->i2d_affine(); if (cc->active_conn == item) { @@ -1797,7 +1800,7 @@ cc_set_active_conn(SPConnectorContext *cc, SPItem *item) } // Listen in case the active conn changes - cc->active_conn_repr = SP_OBJECT_REPR(item); + cc->active_conn_repr = item->getRepr(); if (cc->active_conn_repr) { Inkscape::GC::anchor(cc->active_conn_repr); sp_repr_add_listener(cc->active_conn_repr, &shape_repr_events, cc); diff --git a/src/connector-context.h b/src/connector-context.h index 036981f6f..97e21025d 100644 --- a/src/connector-context.h +++ b/src/connector-context.h @@ -12,11 +12,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <stddef.h> #include <sigc++/sigc++.h> #include <sigc++/connection.h> #include "event-context.h" #include <forward.h> -#include <display/display-forward.h> #include <2geom/point.h> #include "libavoid/connector.h" #include "connection-points.h" @@ -29,6 +29,8 @@ #define SP_IS_CONNECTOR_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_CONNECTOR_CONTEXT)) struct SPKnot; +struct SPCurve; + namespace Inkscape { class Selection; diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index 71c865879..b458827f0 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -453,7 +453,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) case GDK_KP_Delete: case GDK_BackSpace: { - SPDocument *doc = SP_OBJECT_DOCUMENT(guide); + SPDocument *doc = guide->document; sp_guide_remove(guide); DocumentUndo::done(doc, SP_VERB_NONE, _("Delete guide")); ret = TRUE; diff --git a/src/desktop-handles.cpp b/src/desktop-handles.cpp index 481bf35ea..d35df6454 100644 --- a/src/desktop-handles.cpp +++ b/src/desktop-handles.cpp @@ -1,5 +1,3 @@ -#define __SP_DESKTOP_HANDLES_C__ - /* * Frontends * @@ -13,6 +11,7 @@ */ #include "display/sp-canvas.h" +#include "display/sp-canvas-item.h" #include "desktop.h" SPEventContext * diff --git a/src/desktop-handles.h b/src/desktop-handles.h index 61ea43d1e..74001d890 100644 --- a/src/desktop-handles.h +++ b/src/desktop-handles.h @@ -13,9 +13,12 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/display-forward.h" #include "forward.h" +struct SPCanvas; +struct SPCanvasItem; +struct SPCanvasGroup; + namespace Inkscape { class MessageStack; class Selection; diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index d26752d33..88ad9ca57 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -108,9 +108,9 @@ sp_desktop_apply_css_recursive(SPObject *o, SPCSSAttr *css, bool skip_lines) !(SP_IS_FLOWREGION(o) || SP_IS_FLOWREGIONEXCLUDE(o) || (SP_IS_USE(o) && - SP_OBJECT_PARENT(o) && - (SP_IS_FLOWREGION(SP_OBJECT_PARENT(o)) || - SP_IS_FLOWREGIONEXCLUDE(SP_OBJECT_PARENT(o)) + o->parent && + (SP_IS_FLOWREGION(o->parent) || + SP_IS_FLOWREGIONEXCLUDE(o->parent) ) ) ) @@ -121,7 +121,7 @@ sp_desktop_apply_css_recursive(SPObject *o, SPCSSAttr *css, bool skip_lines) // Scale the style by the inverse of the accumulated parent transform in the paste context. { - Geom::Matrix const local(SP_ITEM(o)->i2doc_affine()); + Geom::Affine const local(SP_ITEM(o)->i2doc_affine()); double const ex(local.descrim()); if ( ( ex != 0. ) && ( ex != 1. ) ) { @@ -288,7 +288,7 @@ sp_desktop_get_master_opacity_tool(SPDesktop *desktop, Glib::ustring const &tool value = 1.0; // things failed. set back to the default } else { if (has_opacity) - *has_opacity = false; + *has_opacity = true; } } @@ -420,7 +420,7 @@ stroke_average_width (GSList const *objects) if (!SP_IS_ITEM (l->data)) continue; - Geom::Matrix i2d = SP_ITEM(l->data)->i2d_affine(); + Geom::Affine i2d = SP_ITEM(l->data)->i2d_affine(); SPObject *object = SP_OBJECT(l->data); @@ -431,7 +431,7 @@ stroke_average_width (GSList const *objects) notstroked = false; } - avgwidth += SP_OBJECT_STYLE (object)->stroke_width.computed * i2d.descrim(); + avgwidth += object->style->stroke_width.computed * i2d.descrim(); } if (notstroked) @@ -482,13 +482,15 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } SPIPaint *paint = isfill? &style->fill : &style->stroke; // We consider paint "effectively set" for anything within text hierarchy - SPObject *parent = SP_OBJECT_PARENT (obj); + SPObject *parent = obj->parent; bool paint_effectively_set = paint->set || (SP_IS_TEXT(parent) || SP_IS_TEXTPATH(parent) || SP_IS_TSPAN(parent) || SP_IS_FLOWTEXT(parent) || SP_IS_FLOWDIV(parent) || SP_IS_FLOWPARA(parent) @@ -649,18 +651,22 @@ objects_query_opacity (GSList *objects, SPStyle *style_res) for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } double opacity = SP_SCALE24_TO_FLOAT(style->opacity.value); opacity_sum += opacity; - if (opacity_prev != -1 && opacity != opacity_prev) + if (opacity_prev != -1 && opacity != opacity_prev) { same_opacity = false; + } opacity_prev = opacity; opacity_items ++; } - if (opacity_items > 1) + if (opacity_items > 1) { opacity_sum /= opacity_items; + } style_res->opacity.value = SP_SCALE24_FROM_FLOAT(opacity_sum); @@ -669,10 +675,11 @@ objects_query_opacity (GSList *objects, SPStyle *style_res) } else if (opacity_items == 1) { return QUERY_STYLE_SINGLE; } else { - if (same_opacity) + if (same_opacity) { return QUERY_STYLE_MULTIPLE_SAME; - else + } else { return QUERY_STYLE_MULTIPLE_AVERAGED; + } } } @@ -697,9 +704,13 @@ objects_query_strokewidth (GSList *objects, SPStyle *style_res) for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - if (!SP_IS_ITEM(obj)) continue; - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + if (!SP_IS_ITEM(obj)) { + continue; + } + SPStyle *style = obj->style; + if (!style) { + continue; + } if ( style->stroke.isNone() && !( style->marker[SP_MARKER_LOC].set || // stroke width affects markers, so if there's no stroke but only markers then we should @@ -714,7 +725,7 @@ objects_query_strokewidth (GSList *objects, SPStyle *style_res) noneSet &= style->stroke.isNone(); - Geom::Matrix i2d = SP_ITEM(obj)->i2d_affine(); + Geom::Affine i2d = SP_ITEM(obj)->i2d_affine(); double sw = style->stroke_width.computed * i2d.descrim(); if (prev_sw != -1 && fabs(sw - prev_sw) > 1e-3) @@ -762,9 +773,13 @@ objects_query_miterlimit (GSList *objects, SPStyle *style_res) for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - if (!SP_IS_ITEM(obj)) continue; - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + if (!SP_IS_ITEM(obj)) { + continue; + } + SPStyle *style = obj->style; + if (!style) { + continue; + } if ( style->stroke.isNone() ) { continue; @@ -772,15 +787,17 @@ objects_query_miterlimit (GSList *objects, SPStyle *style_res) n_stroked ++; - if (prev_ml != -1 && fabs(style->stroke_miterlimit.value - prev_ml) > 1e-3) + if (prev_ml != -1 && fabs(style->stroke_miterlimit.value - prev_ml) > 1e-3) { same_ml = false; + } prev_ml = style->stroke_miterlimit.value; avgml += style->stroke_miterlimit.value; } - if (n_stroked > 1) + if (n_stroked > 1) { avgml /= (n_stroked); + } style_res->stroke_miterlimit.value = avgml; style_res->stroke_miterlimit.set = true; @@ -815,9 +832,13 @@ objects_query_strokecap (GSList *objects, SPStyle *style_res) for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - if (!SP_IS_ITEM(obj)) continue; - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + if (!SP_IS_ITEM(obj)) { + continue; + } + SPStyle *style = obj->style; + if (!style) { + continue; + } if ( style->stroke.isNone() ) { continue; @@ -865,9 +886,13 @@ objects_query_strokejoin (GSList *objects, SPStyle *style_res) for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - if (!SP_IS_ITEM(obj)) continue; - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + if (!SP_IS_ITEM(obj)) { + continue; + } + SPStyle *style = obj->style; + if (!style) { + continue; + } if ( style->stroke.isNone() ) { continue; @@ -875,8 +900,9 @@ objects_query_strokejoin (GSList *objects, SPStyle *style_res) n_stroked ++; - if (prev_join != -1 && style->stroke_linejoin.value != prev_join) + if (prev_join != -1 && style->stroke_linejoin.value != prev_join) { same_join = false; + } prev_join = style->stroke_linejoin.value; join = style->stroke_linejoin.value; @@ -925,26 +951,31 @@ objects_query_fontnumbers (GSList *objects, SPStyle *style_res) if (!SP_IS_TEXT(obj) && !SP_IS_FLOWTEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_TREF(obj) && !SP_IS_TEXTPATH(obj) - && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj)) + && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj)) { continue; + } - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } texts ++; - size += style->font_size.computed * Geom::Matrix(SP_ITEM(obj)->i2d_affine()).descrim(); /// \todo FIXME: we assume non-% units here + size += style->font_size.computed * Geom::Affine(SP_ITEM(obj)->i2d_affine()).descrim(); /// \todo FIXME: we assume non-% units here if (style->letter_spacing.normal) { - if (!different && (letterspacing_prev == 0 || letterspacing_prev == letterspacing)) + if (!different && (letterspacing_prev == 0 || letterspacing_prev == letterspacing)) { letterspacing_normal = true; + } } else { letterspacing += style->letter_spacing.computed; /// \todo FIXME: we assume non-% units here letterspacing_normal = false; } if (style->word_spacing.normal) { - if (!different && (wordspacing_prev == 0 || wordspacing_prev == wordspacing)) + if (!different && (wordspacing_prev == 0 || wordspacing_prev == wordspacing)) { wordspacing_normal = true; + } } else { wordspacing += style->word_spacing.computed; /// \todo FIXME: we assume non-% units here wordspacing_normal = false; @@ -1035,8 +1066,10 @@ objects_query_fontstyle (GSList *objects, SPStyle *style_res) && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj)) continue; - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } texts ++; @@ -1095,11 +1128,14 @@ objects_query_baselines (GSList *objects, SPStyle *style_res) if (!SP_IS_TEXT(obj) && !SP_IS_FLOWTEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_TREF(obj) && !SP_IS_TEXTPATH(obj) - && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj)) + && !SP_IS_FLOWDIV(obj) && !SP_IS_FLOWPARA(obj) && !SP_IS_FLOWTSPAN(obj)) { continue; + } - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } texts ++; @@ -1187,8 +1223,10 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res) continue; } - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } texts ++; @@ -1206,8 +1244,9 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res) style_res->text->font_family.value = g_strdup(style->text->font_family.value); } - if (texts == 0 || !style_res->text->font_family.set) + if (texts == 0 || !style_res->text->font_family.set) { return QUERY_STYLE_NOTHING; + } if (texts > 1) { if (different) { @@ -1242,8 +1281,10 @@ objects_query_fontspecification (GSList *objects, SPStyle *style_res) continue; } - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } texts ++; @@ -1265,8 +1306,9 @@ objects_query_fontspecification (GSList *objects, SPStyle *style_res) } } - if (texts == 0) + if (texts == 0) { return QUERY_STYLE_NOTHING; + } if (texts > 1) { if (different) { @@ -1291,8 +1333,10 @@ objects_query_blend (GSList *objects, SPStyle *style_res) for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - SPStyle *style = SP_OBJECT_STYLE (obj); - if(!style || !SP_IS_ITEM(obj)) continue; + SPStyle *style = obj->style; + if (!style || !SP_IS_ITEM(obj)) { + continue; + } items++; @@ -1376,11 +1420,15 @@ objects_query_blur (GSList *objects, SPStyle *style_res) for (GSList const *i = objects; i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - SPStyle *style = SP_OBJECT_STYLE (obj); - if (!style) continue; - if (!SP_IS_ITEM(obj)) continue; + SPStyle *style = obj->style; + if (!style) { + continue; + } + if (!SP_IS_ITEM(obj)) { + continue; + } - Geom::Matrix i2d = SP_ITEM(obj)->i2d_affine(); + Geom::Affine i2d = SP_ITEM(obj)->i2d_affine(); items ++; diff --git a/src/desktop.cpp b/src/desktop.cpp index c52a33e9c..418809aca 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -80,6 +80,7 @@ #include "display/sp-canvas-util.h" #include "display/canvas-temporary-item-list.h" #include "display/snap-indicator.h" +#include "display/sp-canvas-group.h" #include "ui/dialog/dialog-manager.h" #include "xml/repr.h" #include "message-context.h" @@ -153,6 +154,7 @@ SPDesktop::SPDesktop() : _layer_hierarchy( 0 ), _reconstruction_old_layer_id( 0 ), _display_mode(Inkscape::RENDERMODE_NORMAL), + _display_color_mode(Inkscape::COLORRENDERMODE_NORMAL), _widget( 0 ), _inkscape( 0 ), _guides_message_context( 0 ), @@ -184,7 +186,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid namedview = nv; canvas = aCanvas; - SPDocument *document = SP_OBJECT_DOCUMENT (namedview); + SPDocument *document = namedview->document; /* Kill flicker */ document->ensureUpToDate(); @@ -453,6 +455,13 @@ void SPDesktop::_setDisplayMode(Inkscape::RenderMode mode) { sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw _widget->setTitle( sp_desktop_document(this)->getName() ); } +void SPDesktop::_setDisplayColorMode(Inkscape::ColorRenderMode mode) { + SP_CANVAS_ARENA (drawing)->arena->colorrendermode = mode; + canvas->colorrendermode = mode; + _display_color_mode = mode; + sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw + _widget->setTitle( sp_desktop_document(this)->getName() ); +} void SPDesktop::displayModeToggle() { switch (_display_mode) { @@ -465,11 +474,23 @@ void SPDesktop::displayModeToggle() { case Inkscape::RENDERMODE_OUTLINE: _setDisplayMode(Inkscape::RENDERMODE_NORMAL); break; -// case Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW: default: _setDisplayMode(Inkscape::RENDERMODE_NORMAL); } } +void SPDesktop::displayColorModeToggle() { + switch (_display_color_mode) { + case Inkscape::COLORRENDERMODE_NORMAL: + _setDisplayColorMode(Inkscape::COLORRENDERMODE_GRAYSCALE); + break; + case Inkscape::COLORRENDERMODE_GRAYSCALE: + _setDisplayColorMode(Inkscape::COLORRENDERMODE_NORMAL); + break; +// case Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW: + default: + _setDisplayColorMode(Inkscape::COLORRENDERMODE_NORMAL); + } +} /** * Returns current root (=bottom) layer. @@ -531,9 +552,9 @@ SPObject *SPDesktop::layerForObject(SPObject *object) { g_return_val_if_fail(object != NULL, NULL); SPObject *root=currentRoot(); - object = SP_OBJECT_PARENT(object); + object = object->parent; while ( object && object != root && !isLayer(object) ) { - object = SP_OBJECT_PARENT(object); + object = object->parent; } return object; } @@ -758,6 +779,9 @@ SPDesktop::push_current_zoom (GList **history) ( ((NRRect *) ((*history)->data))->y1 == old_zoom->y1 ) ) ) { *history = g_list_prepend (*history, old_zoom); + } else { + g_free(old_zoom); + old_zoom = 0; } } @@ -768,6 +792,7 @@ void SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double border, bool log) { g_assert(_widget); + bool zoomChanged = false; // save the zoom if (log) { @@ -801,7 +826,7 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double _w2d = Geom::Scale(1/newscale, 1/-newscale); sp_canvas_item_affine_absolute(SP_CANVAS_ITEM(main), _d2w); clear = TRUE; - signal_zoom_changed.emit(_d2w.descrim()); + zoomChanged = true; } /* Calculate top left corner (in document pixels) */ @@ -817,6 +842,11 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double _widget->updateRulers(); _widget->updateScrollbars(_d2w.descrim()); _widget->updateZoom(); + + + if ( zoomChanged ) { + signal_zoom_changed.emit(_d2w.descrim()); + } } void SPDesktop::set_display_area(Geom::Rect const &a, Geom::Coord b, bool log) @@ -1158,7 +1188,7 @@ SPDesktop::scroll_to_point (Geom::Point const &p, gdouble autoscrollspeed) if (!(p[X] > dbox.min()[X] && p[X] < dbox.max()[X]) || !(p[Y] > dbox.min()[Y] && p[Y] < dbox.max()[Y]) ) { - Geom::Point const s_w( p * (Geom::Matrix)_d2w ); + Geom::Point const s_w( p * (Geom::Affine)_d2w ); gdouble x_to; if (p[X] < dbox.min()[X]) @@ -1679,7 +1709,7 @@ _reconstruction_finish (SPDesktop * desktop) if (desktop->_reconstruction_old_layer_id == NULL) return; - SPObject * newLayer = SP_OBJECT_DOCUMENT(desktop->namedview)->getObjectById(desktop->_reconstruction_old_layer_id); + SPObject * newLayer = desktop->namedview->document->getObjectById(desktop->_reconstruction_old_layer_id); if (newLayer != NULL) desktop->setCurrentLayer(newLayer); @@ -1753,7 +1783,7 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop) } } -Geom::Matrix SPDesktop::w2d() const +Geom::Affine SPDesktop::w2d() const { return _w2d; } @@ -1768,12 +1798,12 @@ Geom::Point SPDesktop::d2w(Geom::Point const &p) const return p * _d2w; } -Geom::Matrix SPDesktop::doc2dt() const +Geom::Affine SPDesktop::doc2dt() const { return _doc2dt; } -Geom::Matrix SPDesktop::dt2doc() const +Geom::Affine SPDesktop::dt2doc() const { // doc2dt is its own inverse return _doc2dt; diff --git a/src/desktop.h b/src/desktop.h index 957c3b342..947e92fe7 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -29,9 +29,10 @@ #include <gdk/gdkevents.h> #include <gtk/gtktypeutils.h> +#include <stddef.h> #include <sigc++/sigc++.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/rect.h> #include "ui/view/view.h" @@ -206,13 +207,24 @@ public: void setDisplayModeOutline() { _setDisplayMode(Inkscape::RENDERMODE_OUTLINE); } -// void setDisplayModePrintColorsPreview() { -// _setDisplayMode(Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW); -// } void displayModeToggle(); Inkscape::RenderMode _display_mode; Inkscape::RenderMode getMode() const { return _display_mode; } + void _setDisplayColorMode(Inkscape::ColorRenderMode mode); + void setDisplayColorModeNormal() { + _setDisplayColorMode(Inkscape::COLORRENDERMODE_NORMAL); + } + void setDisplayColorModeGrayscale() { + _setDisplayColorMode(Inkscape::COLORRENDERMODE_GRAYSCALE); + } +// void setDisplayColorModePrintColorsPreview() { +// _setDisplayColorMode(Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW); +// } + void displayColorModeToggle(); + Inkscape::ColorRenderMode _display_color_mode; + Inkscape::ColorRenderMode getColorMode() const { return _display_color_mode; } + Inkscape::UI::Widget::Dock* getDock() { return _widget->getDock(); } void set_active (bool new_active); @@ -312,11 +324,11 @@ public: void fullscreen(); void focusMode(bool mode = true); - Geom::Matrix w2d() const; //transformation from window to desktop coordinates (used for zooming) + Geom::Affine w2d() const; //transformation from window to desktop coordinates (used for zooming) Geom::Point w2d(Geom::Point const &p) const; Geom::Point d2w(Geom::Point const &p) const; - Geom::Matrix doc2dt() const; - Geom::Matrix dt2doc() const; + Geom::Affine doc2dt() const; + Geom::Affine dt2doc() const; Geom::Point doc2dt(Geom::Point const &p) const; Geom::Point dt2doc(Geom::Point const &p) const; @@ -335,9 +347,9 @@ private: Inkscape::Application *_inkscape; Inkscape::MessageContext *_guides_message_context; bool _active; - Geom::Matrix _w2d; - Geom::Matrix _d2w; - Geom::Matrix _doc2dt; + Geom::Affine _w2d; + Geom::Affine _d2w; + Geom::Affine _doc2dt; bool grids_visible; /* don't set this variable directly, use the method below */ void set_grids_visible(bool visible); diff --git a/src/dialogs/clonetiler.cpp b/src/dialogs/clonetiler.cpp index 6e03f87e3..81204f27b 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -197,7 +197,7 @@ enum { }; -static Geom::Matrix +static Geom::Affine clonetiler_get_transform ( // symmetry group @@ -288,7 +288,7 @@ clonetiler_get_transform ( if ( shifty_exp != 1.0 ) shiftj = pow( shiftj, shifty_exp ); // Final shift - Geom::Matrix rect_translate (Geom::Translate (w * shifti, h * shiftj)); + Geom::Affine rect_translate (Geom::Translate (w * shifti, h * shiftj)); // Rotation (in degrees) ------------ double delta_rotationi = 0.0; @@ -371,25 +371,25 @@ clonetiler_get_transform ( // Calculate transformation matrices, translating back to "center of tile" (rotation center) before transforming - Geom::Matrix drot_c = Geom::Translate(-cx, -cy) * Geom::Rotate (M_PI*dr/180) * Geom::Translate(cx, cy); + Geom::Affine drot_c = Geom::Translate(-cx, -cy) * Geom::Rotate (M_PI*dr/180) * Geom::Translate(cx, cy); - Geom::Matrix dscale_c = Geom::Translate(-cx, -cy) * Geom::Scale (scalex, scaley) * Geom::Translate(cx, cy); + Geom::Affine dscale_c = Geom::Translate(-cx, -cy) * Geom::Scale (scalex, scaley) * Geom::Translate(cx, cy); - Geom::Matrix d_s_r = dscale_c * drot_c; + Geom::Affine d_s_r = dscale_c * drot_c; - Geom::Matrix rotate_180_c = Geom::Translate(-cx, -cy) * Geom::Rotate (M_PI) * Geom::Translate(cx, cy); + Geom::Affine rotate_180_c = Geom::Translate(-cx, -cy) * Geom::Rotate (M_PI) * Geom::Translate(cx, cy); - Geom::Matrix rotate_90_c = Geom::Translate(-cx, -cy) * Geom::Rotate (-M_PI/2) * Geom::Translate(cx, cy); - Geom::Matrix rotate_m90_c = Geom::Translate(-cx, -cy) * Geom::Rotate ( M_PI/2) * Geom::Translate(cx, cy); + Geom::Affine rotate_90_c = Geom::Translate(-cx, -cy) * Geom::Rotate (-M_PI/2) * Geom::Translate(cx, cy); + Geom::Affine rotate_m90_c = Geom::Translate(-cx, -cy) * Geom::Rotate ( M_PI/2) * Geom::Translate(cx, cy); - Geom::Matrix rotate_120_c = Geom::Translate(-cx, -cy) * Geom::Rotate (-2*M_PI/3) * Geom::Translate(cx, cy); - Geom::Matrix rotate_m120_c = Geom::Translate(-cx, -cy) * Geom::Rotate ( 2*M_PI/3) * Geom::Translate(cx, cy); + Geom::Affine rotate_120_c = Geom::Translate(-cx, -cy) * Geom::Rotate (-2*M_PI/3) * Geom::Translate(cx, cy); + Geom::Affine rotate_m120_c = Geom::Translate(-cx, -cy) * Geom::Rotate ( 2*M_PI/3) * Geom::Translate(cx, cy); - Geom::Matrix rotate_60_c = Geom::Translate(-cx, -cy) * Geom::Rotate (-M_PI/3) * Geom::Translate(cx, cy); - Geom::Matrix rotate_m60_c = Geom::Translate(-cx, -cy) * Geom::Rotate ( M_PI/3) * Geom::Translate(cx, cy); + Geom::Affine rotate_60_c = Geom::Translate(-cx, -cy) * Geom::Rotate (-M_PI/3) * Geom::Translate(cx, cy); + Geom::Affine rotate_m60_c = Geom::Translate(-cx, -cy) * Geom::Rotate ( M_PI/3) * Geom::Translate(cx, cy); - Geom::Matrix flip_x = Geom::Translate(-cx, -cy) * Geom::Scale (-1, 1) * Geom::Translate(cx, cy); - Geom::Matrix flip_y = Geom::Translate(-cx, -cy) * Geom::Scale (1, -1) * Geom::Translate(cx, cy); + Geom::Affine flip_x = Geom::Translate(-cx, -cy) * Geom::Scale (-1, 1) * Geom::Translate(cx, cy); + Geom::Affine flip_y = Geom::Translate(-cx, -cy) * Geom::Scale (1, -1) * Geom::Translate(cx, cy); // Create tile with required symmetry @@ -514,9 +514,9 @@ clonetiler_get_transform ( case TILE_P4: { - Geom::Matrix ori (Geom::Translate ((w + h) * pow((i/2), shiftx_exp) + dx, (h + w) * pow((j/2), shifty_exp) + dy)); - Geom::Matrix dia1 (Geom::Translate (w/2 + h/2, -h/2 + w/2)); - Geom::Matrix dia2 (Geom::Translate (-w/2 + h/2, h/2 + w/2)); + Geom::Affine ori (Geom::Translate ((w + h) * pow((i/2), shiftx_exp) + dx, (h + w) * pow((j/2), shifty_exp) + dy)); + Geom::Affine dia1 (Geom::Translate (w/2 + h/2, -h/2 + w/2)); + Geom::Affine dia2 (Geom::Translate (-w/2 + h/2, h/2 + w/2)); if (j % 2 == 0) { if (i % 2 == 0) { return d_s_r * ori; @@ -536,9 +536,9 @@ clonetiler_get_transform ( case TILE_P4M: { double max = MAX(w, h); - Geom::Matrix ori (Geom::Translate ((max + max) * pow((i/4), shiftx_exp) + dx, (max + max) * pow((j/2), shifty_exp) + dy)); - Geom::Matrix dia1 (Geom::Translate ( w/2 - h/2, h/2 - w/2)); - Geom::Matrix dia2 (Geom::Translate (-h/2 + w/2, w/2 - h/2)); + Geom::Affine ori (Geom::Translate ((max + max) * pow((i/4), shiftx_exp) + dx, (max + max) * pow((j/2), shifty_exp) + dy)); + Geom::Affine dia1 (Geom::Translate ( w/2 - h/2, h/2 - w/2)); + Geom::Affine dia2 (Geom::Translate (-h/2 + w/2, w/2 - h/2)); if (j % 2 == 0) { if (i % 4 == 0) { return d_s_r * ori; @@ -566,9 +566,9 @@ clonetiler_get_transform ( case TILE_P4G: { double max = MAX(w, h); - Geom::Matrix ori (Geom::Translate ((max + max) * pow((i/4), shiftx_exp) + dx, (max + max) * pow(j, shifty_exp) + dy)); - Geom::Matrix dia1 (Geom::Translate ( w/2 + h/2, h/2 - w/2)); - Geom::Matrix dia2 (Geom::Translate (-h/2 + w/2, w/2 + h/2)); + Geom::Affine ori (Geom::Translate ((max + max) * pow((i/4), shiftx_exp) + dx, (max + max) * pow(j, shifty_exp) + dy)); + Geom::Affine dia1 (Geom::Translate ( w/2 + h/2, h/2 - w/2)); + Geom::Affine dia2 (Geom::Translate (-h/2 + w/2, w/2 + h/2)); if (((i/4) + j) % 2 == 0) { if (i % 4 == 0) { return d_s_r * ori; @@ -597,20 +597,20 @@ clonetiler_get_transform ( { double width; double height; - Geom::Matrix dia1; - Geom::Matrix dia2; + Geom::Affine dia1; + Geom::Affine dia2; if (w > h) { width = w + w * cos60; height = 2 * w * sin60; - dia1 = Geom::Matrix (Geom::Translate (w/2 + w/2 * cos60, -(w/2 * sin60))); - dia2 = dia1 * Geom::Matrix (Geom::Translate (0, 2 * (w/2 * sin60))); + dia1 = Geom::Affine (Geom::Translate (w/2 + w/2 * cos60, -(w/2 * sin60))); + dia2 = dia1 * Geom::Affine (Geom::Translate (0, 2 * (w/2 * sin60))); } else { width = h * cos (M_PI/6); height = h; - dia1 = Geom::Matrix (Geom::Translate (h/2 * cos30, -(h/2 * sin30))); - dia2 = dia1 * Geom::Matrix (Geom::Translate (0, h/2)); + dia1 = Geom::Affine (Geom::Translate (h/2 * cos30, -(h/2 * sin30))); + dia2 = dia1 * Geom::Affine (Geom::Translate (0, h/2)); } - Geom::Matrix ori (Geom::Translate (width * pow((2*(i/3) + j%2), shiftx_exp) + dx, (height/2) * pow(j, shifty_exp) + dy)); + Geom::Affine ori (Geom::Translate (width * pow((2*(i/3) + j%2), shiftx_exp) + dx, (height/2) * pow(j, shifty_exp) + dy)); if (i % 3 == 0) { return d_s_r * ori; } else if (i % 3 == 1) { @@ -623,23 +623,23 @@ clonetiler_get_transform ( case TILE_P31M: { - Geom::Matrix ori; - Geom::Matrix dia1; - Geom::Matrix dia2; - Geom::Matrix dia3; - Geom::Matrix dia4; + Geom::Affine ori; + Geom::Affine dia1; + Geom::Affine dia2; + Geom::Affine dia3; + Geom::Affine dia4; if (w > h) { - ori = Geom::Matrix(Geom::Translate (w * pow((i/6) + 0.5*(j%2), shiftx_exp) + dx, (w * cos30) * pow(j, shifty_exp) + dy)); - dia1 = Geom::Matrix (Geom::Translate (0, h/2) * Geom::Translate (w/2, 0) * Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (-h/2 * cos30, -h/2 * sin30) ); - dia2 = dia1 * Geom::Matrix (Geom::Translate (h * cos30, h * sin30)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (0, 2 * (w/2 * sin60 - h/2 * sin30))); - dia4 = dia3 * Geom::Matrix (Geom::Translate (-h * cos30, h * sin30)); + ori = Geom::Affine(Geom::Translate (w * pow((i/6) + 0.5*(j%2), shiftx_exp) + dx, (w * cos30) * pow(j, shifty_exp) + dy)); + dia1 = Geom::Affine (Geom::Translate (0, h/2) * Geom::Translate (w/2, 0) * Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (-h/2 * cos30, -h/2 * sin30) ); + dia2 = dia1 * Geom::Affine (Geom::Translate (h * cos30, h * sin30)); + dia3 = dia2 * Geom::Affine (Geom::Translate (0, 2 * (w/2 * sin60 - h/2 * sin30))); + dia4 = dia3 * Geom::Affine (Geom::Translate (-h * cos30, h * sin30)); } else { - ori = Geom::Matrix (Geom::Translate (2*h * cos30 * pow((i/6 + 0.5*(j%2)), shiftx_exp) + dx, (2*h - h * sin30) * pow(j, shifty_exp) + dy)); - dia1 = Geom::Matrix (Geom::Translate (0, -h/2) * Geom::Translate (h/2 * cos30, h/2 * sin30)); - dia2 = dia1 * Geom::Matrix (Geom::Translate (h * cos30, h * sin30)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (0, h/2)); - dia4 = dia3 * Geom::Matrix (Geom::Translate (-h * cos30, h * sin30)); + ori = Geom::Affine (Geom::Translate (2*h * cos30 * pow((i/6 + 0.5*(j%2)), shiftx_exp) + dx, (2*h - h * sin30) * pow(j, shifty_exp) + dy)); + dia1 = Geom::Affine (Geom::Translate (0, -h/2) * Geom::Translate (h/2 * cos30, h/2 * sin30)); + dia2 = dia1 * Geom::Affine (Geom::Translate (h * cos30, h * sin30)); + dia3 = dia2 * Geom::Affine (Geom::Translate (0, h/2)); + dia4 = dia3 * Geom::Affine (Geom::Translate (-h * cos30, h * sin30)); } if (i % 6 == 0) { return d_s_r * ori; @@ -661,26 +661,26 @@ clonetiler_get_transform ( { double width; double height; - Geom::Matrix dia1; - Geom::Matrix dia2; - Geom::Matrix dia3; - Geom::Matrix dia4; + Geom::Affine dia1; + Geom::Affine dia2; + Geom::Affine dia3; + Geom::Affine dia4; if (w > h) { width = w + w * cos60; height = 2 * w * sin60; - dia1 = Geom::Matrix (Geom::Translate (0, h/2) * Geom::Translate (w/2, 0) * Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (-h/2 * cos30, -h/2 * sin30) ); - dia2 = dia1 * Geom::Matrix (Geom::Translate (h * cos30, h * sin30)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (0, 2 * (w/2 * sin60 - h/2 * sin30))); - dia4 = dia3 * Geom::Matrix (Geom::Translate (-h * cos30, h * sin30)); + dia1 = Geom::Affine (Geom::Translate (0, h/2) * Geom::Translate (w/2, 0) * Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (-h/2 * cos30, -h/2 * sin30) ); + dia2 = dia1 * Geom::Affine (Geom::Translate (h * cos30, h * sin30)); + dia3 = dia2 * Geom::Affine (Geom::Translate (0, 2 * (w/2 * sin60 - h/2 * sin30))); + dia4 = dia3 * Geom::Affine (Geom::Translate (-h * cos30, h * sin30)); } else { width = 2 * h * cos (M_PI/6); height = 2 * h; - dia1 = Geom::Matrix (Geom::Translate (0, -h/2) * Geom::Translate (h/2 * cos30, h/2 * sin30)); - dia2 = dia1 * Geom::Matrix (Geom::Translate (h * cos30, h * sin30)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (0, h/2)); - dia4 = dia3 * Geom::Matrix (Geom::Translate (-h * cos30, h * sin30)); + dia1 = Geom::Affine (Geom::Translate (0, -h/2) * Geom::Translate (h/2 * cos30, h/2 * sin30)); + dia2 = dia1 * Geom::Affine (Geom::Translate (h * cos30, h * sin30)); + dia3 = dia2 * Geom::Affine (Geom::Translate (0, h/2)); + dia4 = dia3 * Geom::Affine (Geom::Translate (-h * cos30, h * sin30)); } - Geom::Matrix ori (Geom::Translate (width * pow((2*(i/6) + j%2), shiftx_exp) + dx, (height/2) * pow(j, shifty_exp) + dy)); + Geom::Affine ori (Geom::Translate (width * pow((2*(i/6) + j%2), shiftx_exp) + dx, (height/2) * pow(j, shifty_exp) + dy)); if (i % 6 == 0) { return d_s_r * ori; } else if (i % 6 == 1) { @@ -699,24 +699,24 @@ clonetiler_get_transform ( case TILE_P6: { - Geom::Matrix ori; - Geom::Matrix dia1; - Geom::Matrix dia2; - Geom::Matrix dia3; - Geom::Matrix dia4; - Geom::Matrix dia5; + Geom::Affine ori; + Geom::Affine dia1; + Geom::Affine dia2; + Geom::Affine dia3; + Geom::Affine dia4; + Geom::Affine dia5; if (w > h) { - ori = Geom::Matrix(Geom::Translate (w * pow((2*(i/6) + (j%2)), shiftx_exp) + dx, (2*w * sin60) * pow(j, shifty_exp) + dy)); - dia1 = Geom::Matrix (Geom::Translate (w/2 * cos60, -w/2 * sin60)); - dia2 = dia1 * Geom::Matrix (Geom::Translate (w/2, 0)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (w/2 * cos60, w/2 * sin60)); - dia4 = dia3 * Geom::Matrix (Geom::Translate (-w/2 * cos60, w/2 * sin60)); - dia5 = dia4 * Geom::Matrix (Geom::Translate (-w/2, 0)); + ori = Geom::Affine(Geom::Translate (w * pow((2*(i/6) + (j%2)), shiftx_exp) + dx, (2*w * sin60) * pow(j, shifty_exp) + dy)); + dia1 = Geom::Affine (Geom::Translate (w/2 * cos60, -w/2 * sin60)); + dia2 = dia1 * Geom::Affine (Geom::Translate (w/2, 0)); + dia3 = dia2 * Geom::Affine (Geom::Translate (w/2 * cos60, w/2 * sin60)); + dia4 = dia3 * Geom::Affine (Geom::Translate (-w/2 * cos60, w/2 * sin60)); + dia5 = dia4 * Geom::Affine (Geom::Translate (-w/2, 0)); } else { - ori = Geom::Matrix(Geom::Translate (2*h * cos30 * pow((i/6 + 0.5*(j%2)), shiftx_exp) + dx, (h + h * sin30) * pow(j, shifty_exp) + dy)); - dia1 = Geom::Matrix (Geom::Translate (-w/2, -h/2) * Geom::Translate (h/2 * cos30, -h/2 * sin30) * Geom::Translate (w/2 * cos60, w/2 * sin60)); - dia2 = dia1 * Geom::Matrix (Geom::Translate (-w/2 * cos60, -w/2 * sin60) * Geom::Translate (h/2 * cos30, -h/2 * sin30) * Geom::Translate (h/2 * cos30, h/2 * sin30) * Geom::Translate (-w/2 * cos60, w/2 * sin60)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (h/2 * cos30, h/2 * sin30) * Geom::Translate (-w/2, h/2)); + ori = Geom::Affine(Geom::Translate (2*h * cos30 * pow((i/6 + 0.5*(j%2)), shiftx_exp) + dx, (h + h * sin30) * pow(j, shifty_exp) + dy)); + dia1 = Geom::Affine (Geom::Translate (-w/2, -h/2) * Geom::Translate (h/2 * cos30, -h/2 * sin30) * Geom::Translate (w/2 * cos60, w/2 * sin60)); + dia2 = dia1 * Geom::Affine (Geom::Translate (-w/2 * cos60, -w/2 * sin60) * Geom::Translate (h/2 * cos30, -h/2 * sin30) * Geom::Translate (h/2 * cos30, h/2 * sin30) * Geom::Translate (-w/2 * cos60, w/2 * sin60)); + dia3 = dia2 * Geom::Affine (Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (h/2 * cos30, h/2 * sin30) * Geom::Translate (-w/2, h/2)); dia4 = dia3 * dia1.inverse(); dia5 = dia3 * dia2.inverse(); } @@ -739,28 +739,28 @@ clonetiler_get_transform ( case TILE_P6M: { - Geom::Matrix ori; - Geom::Matrix dia1, dia2, dia3, dia4, dia5, dia6, dia7, dia8, dia9, dia10; + Geom::Affine ori; + Geom::Affine dia1, dia2, dia3, dia4, dia5, dia6, dia7, dia8, dia9, dia10; if (w > h) { - ori = Geom::Matrix(Geom::Translate (w * pow((2*(i/12) + (j%2)), shiftx_exp) + dx, (2*w * sin60) * pow(j, shifty_exp) + dy)); - dia1 = Geom::Matrix (Geom::Translate (w/2, h/2) * Geom::Translate (-w/2 * cos60, -w/2 * sin60) * Geom::Translate (-h/2 * cos30, h/2 * sin30)); - dia2 = dia1 * Geom::Matrix (Geom::Translate (h * cos30, -h * sin30)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (-h/2 * cos30, h/2 * sin30) * Geom::Translate (w * cos60, 0) * Geom::Translate (-h/2 * cos30, -h/2 * sin30)); - dia4 = dia3 * Geom::Matrix (Geom::Translate (h * cos30, h * sin30)); - dia5 = dia4 * Geom::Matrix (Geom::Translate (-h/2 * cos30, -h/2 * sin30) * Geom::Translate (-w/2 * cos60, w/2 * sin60) * Geom::Translate (w/2, -h/2)); - dia6 = dia5 * Geom::Matrix (Geom::Translate (0, h)); + ori = Geom::Affine(Geom::Translate (w * pow((2*(i/12) + (j%2)), shiftx_exp) + dx, (2*w * sin60) * pow(j, shifty_exp) + dy)); + dia1 = Geom::Affine (Geom::Translate (w/2, h/2) * Geom::Translate (-w/2 * cos60, -w/2 * sin60) * Geom::Translate (-h/2 * cos30, h/2 * sin30)); + dia2 = dia1 * Geom::Affine (Geom::Translate (h * cos30, -h * sin30)); + dia3 = dia2 * Geom::Affine (Geom::Translate (-h/2 * cos30, h/2 * sin30) * Geom::Translate (w * cos60, 0) * Geom::Translate (-h/2 * cos30, -h/2 * sin30)); + dia4 = dia3 * Geom::Affine (Geom::Translate (h * cos30, h * sin30)); + dia5 = dia4 * Geom::Affine (Geom::Translate (-h/2 * cos30, -h/2 * sin30) * Geom::Translate (-w/2 * cos60, w/2 * sin60) * Geom::Translate (w/2, -h/2)); + dia6 = dia5 * Geom::Affine (Geom::Translate (0, h)); dia7 = dia6 * dia1.inverse(); dia8 = dia6 * dia2.inverse(); dia9 = dia6 * dia3.inverse(); dia10 = dia6 * dia4.inverse(); } else { - ori = Geom::Matrix(Geom::Translate (4*h * cos30 * pow((i/12 + 0.5*(j%2)), shiftx_exp) + dx, (2*h + 2*h * sin30) * pow(j, shifty_exp) + dy)); - dia1 = Geom::Matrix (Geom::Translate (-w/2, -h/2) * Geom::Translate (h/2 * cos30, -h/2 * sin30) * Geom::Translate (w/2 * cos60, w/2 * sin60)); - dia2 = dia1 * Geom::Matrix (Geom::Translate (h * cos30, -h * sin30)); - dia3 = dia2 * Geom::Matrix (Geom::Translate (-w/2 * cos60, -w/2 * sin60) * Geom::Translate (h * cos30, 0) * Geom::Translate (-w/2 * cos60, w/2 * sin60)); - dia4 = dia3 * Geom::Matrix (Geom::Translate (h * cos30, h * sin30)); - dia5 = dia4 * Geom::Matrix (Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (h/2 * cos30, h/2 * sin30) * Geom::Translate (-w/2, h/2)); - dia6 = dia5 * Geom::Matrix (Geom::Translate (0, h)); + ori = Geom::Affine(Geom::Translate (4*h * cos30 * pow((i/12 + 0.5*(j%2)), shiftx_exp) + dx, (2*h + 2*h * sin30) * pow(j, shifty_exp) + dy)); + dia1 = Geom::Affine (Geom::Translate (-w/2, -h/2) * Geom::Translate (h/2 * cos30, -h/2 * sin30) * Geom::Translate (w/2 * cos60, w/2 * sin60)); + dia2 = dia1 * Geom::Affine (Geom::Translate (h * cos30, -h * sin30)); + dia3 = dia2 * Geom::Affine (Geom::Translate (-w/2 * cos60, -w/2 * sin60) * Geom::Translate (h * cos30, 0) * Geom::Translate (-w/2 * cos60, w/2 * sin60)); + dia4 = dia3 * Geom::Affine (Geom::Translate (h * cos30, h * sin30)); + dia5 = dia4 * Geom::Affine (Geom::Translate (w/2 * cos60, -w/2 * sin60) * Geom::Translate (h/2 * cos30, h/2 * sin30) * Geom::Translate (-w/2, h/2)); + dia6 = dia5 * Geom::Affine (Geom::Translate (0, h)); dia7 = dia6 * dia1.inverse(); dia8 = dia6 * dia2.inverse(); dia9 = dia6 * dia3.inverse(); @@ -804,27 +804,29 @@ clonetiler_get_transform ( static bool clonetiler_is_a_clone_of (SPObject *tile, SPObject *obj) { + bool result = false; char *id_href = NULL; if (obj) { - Inkscape::XML::Node *obj_repr = SP_OBJECT_REPR(obj); + Inkscape::XML::Node *obj_repr = obj->getRepr(); id_href = g_strdup_printf("#%s", obj_repr->attribute("id")); } if (SP_IS_USE(tile) && - SP_OBJECT_REPR(tile)->attribute("xlink:href") && - (!id_href || !strcmp(id_href, SP_OBJECT_REPR(tile)->attribute("xlink:href"))) && - SP_OBJECT_REPR(tile)->attribute("inkscape:tiled-clone-of") && - (!id_href || !strcmp(id_href, SP_OBJECT_REPR(tile)->attribute("inkscape:tiled-clone-of")))) + tile->getRepr()->attribute("xlink:href") && + (!id_href || !strcmp(id_href, tile->getRepr()->attribute("xlink:href"))) && + tile->getRepr()->attribute("inkscape:tiled-clone-of") && + (!id_href || !strcmp(id_href, tile->getRepr()->attribute("inkscape:tiled-clone-of")))) { - if (id_href) - g_free (id_href); - return true; + result = true; } else { - if (id_href) - g_free (id_href); - return false; + result = false; } + if (id_href) { + g_free(id_href); + id_href = 0; + } + return result; } static NRArena const *trace_arena = NULL; @@ -857,7 +859,7 @@ clonetiler_trace_setup (SPDocument *doc, gdouble zoom, SPItem *original) // hide the (current) original and any tiled clones, we only want to pick the background original->invoke_hide(trace_visionkey); - clonetiler_trace_hide_tiled_clones_recursively(SP_OBJECT(trace_doc->getRoot())); + clonetiler_trace_hide_tiled_clones_recursively(trace_doc->getRoot()); trace_doc->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); trace_doc->ensureUpToDate(); @@ -871,7 +873,7 @@ clonetiler_trace_pick (Geom::Rect box) if (!trace_arena) return 0; - Geom::Matrix t(Geom::Scale(trace_zoom, trace_zoom)); + Geom::Affine t(Geom::Scale(trace_zoom, trace_zoom)); nr_arena_item_set_transform(trace_root, &t); NRGC gc(NULL); gc.transform.setIdentity(); @@ -931,8 +933,8 @@ clonetiler_unclump( GtkWidget */*widget*/, void * ) return; } - SPObject *obj = SP_OBJECT(selection->singleItem()); - SPObject *parent = SP_OBJECT_PARENT (obj); + SPObject *obj = selection->singleItem(); + SPObject *parent = obj->parent; GSList *to_unclump = NULL; // not including the original @@ -955,7 +957,7 @@ clonetiler_unclump( GtkWidget */*widget*/, void * ) static guint clonetiler_number_of_clones (SPObject *obj) { - SPObject *parent = SP_OBJECT_PARENT (obj); + SPObject *parent = obj->parent; guint n = 0; @@ -983,8 +985,8 @@ clonetiler_remove( GtkWidget */*widget*/, void *, bool do_undo = true ) return; } - SPObject *obj = SP_OBJECT(selection->singleItem()); - SPObject *parent = SP_OBJECT_PARENT (obj); + SPObject *obj = selection->singleItem(); + SPObject *parent = obj->parent; // remove old tiling GSList *to_delete = NULL; @@ -1007,7 +1009,7 @@ clonetiler_remove( GtkWidget */*widget*/, void *, bool do_undo = true ) } static Geom::Rect -transform_rect( Geom::Rect const &r, Geom::Matrix const &m) +transform_rect( Geom::Rect const &r, Geom::Affine const &m) { using Geom::X; using Geom::Y; @@ -1068,10 +1070,10 @@ clonetiler_apply( GtkWidget */*widget*/, void * ) gtk_widget_queue_draw(GTK_WIDGET(status)); gdk_window_process_all_updates(); - SPObject *obj = SP_OBJECT(selection->singleItem()); - Inkscape::XML::Node *obj_repr = SP_OBJECT_REPR(obj); + SPObject *obj = selection->singleItem(); + Inkscape::XML::Node *obj_repr = obj->getRepr(); const char *id_href = g_strdup_printf("#%s", obj_repr->attribute("id")); - SPObject *parent = SP_OBJECT_PARENT (obj); + SPObject *parent = obj->parent; clonetiler_remove (NULL, NULL, false); @@ -1229,7 +1231,7 @@ clonetiler_apply( GtkWidget */*widget*/, void * ) // Note: We create a clone at 0,0 too, right over the original, in case our clones are colored // Get transform from symmetry, shift, scale, rotation - Geom::Matrix t = clonetiler_get_transform (type, i, j, center[Geom::X], center[Geom::Y], w, h, + Geom::Affine t = clonetiler_get_transform (type, i, j, center[Geom::X], center[Geom::Y], w, h, shiftx_per_i, shifty_per_i, shiftx_per_j, shifty_per_j, shiftx_rand, shifty_rand, @@ -1428,7 +1430,7 @@ clonetiler_apply( GtkWidget */*widget*/, void * ) } // add the new clone to the top of the original's parent - SP_OBJECT_REPR(parent)->appendChild(clone); + parent->getRepr()->appendChild(clone); if (blur > 0.0) { SPObject *clone_object = sp_desktop_document(desktop)->getObjectByRepr(clone); @@ -1441,7 +1443,7 @@ clonetiler_apply( GtkWidget */*widget*/, void * ) // that we can take bbox of; however here we only need a lower bound so that blur // margins are not too small, and the perimeter should work SPFilter *constructed = new_filter_gaussian_blur(sp_desktop_document(desktop), radius, t.descrim(), t.expansionX(), t.expansionY(), perimeter, perimeter); - sp_style_set_property_url (clone_object, "filter", SP_OBJECT(constructed), false); + sp_style_set_property_url (clone_object, "filter", constructed, false); } if (center_set) { @@ -2336,7 +2338,7 @@ clonetiler_dialog (void) // Dissolve { GtkWidget *l = gtk_label_new (""); - gtk_label_set_markup (GTK_LABEL(l), _("<b>Fade out:</b>")); + gtk_label_set_markup (GTK_LABEL(l), _("<b>Opacity:</b>")); gtk_size_group_add_widget(table_row_labels, l); clonetiler_table_attach (table, l, 1, 4, 1); } diff --git a/src/dialogs/export.cpp b/src/dialogs/export.cpp index 7e99c2496..b05f6589a 100644 --- a/src/dialogs/export.cpp +++ b/src/dialogs/export.cpp @@ -620,7 +620,7 @@ sp_export_dialog (void) { Gtk::HBox* batch_box = new Gtk::HBox(FALSE, 5); - GtkWidget *be = gtk_check_button_new_with_label(_("Batch export all selected objects")); + GtkWidget *be = gtk_check_button_new_with_mnemonic(_("B_atch export all selected objects")); gtk_widget_set_sensitive(GTK_WIDGET(be), TRUE); gtk_object_set_data(GTK_OBJECT(dlg), "batch_checkbox", be); batch_box->pack_start(*Glib::wrap(be), false, false); @@ -632,7 +632,7 @@ sp_export_dialog (void) { Gtk::HBox* hide_box = new Gtk::HBox(FALSE, 5); - GtkWidget *he = gtk_check_button_new_with_label(_("Hide all except selected")); + GtkWidget *he = gtk_check_button_new_with_mnemonic(_("Hide a_ll except selected")); gtk_widget_set_sensitive(GTK_WIDGET(he), TRUE); gtk_object_set_data(GTK_OBJECT(dlg), "hide_checkbox", he); hide_box->pack_start(*Glib::wrap(he), false, false); @@ -683,7 +683,7 @@ sp_export_update_checkbuttons (GtkObject *base) GtkWidget *he = (GtkWidget *)gtk_object_get_data(base, "hide_checkbox"); if (num >= 2) { gtk_widget_set_sensitive (be, true); - gtk_button_set_label (GTK_BUTTON(be), g_strdup_printf (ngettext("Batch export %d selected object","Batch export %d selected objects",num), num)); + gtk_button_set_label (GTK_BUTTON(be), g_strdup_printf (ngettext("B_atch export %d selected object","B_atch export %d selected objects",num), num)); } else { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(be), FALSE); gtk_widget_set_sensitive (be, FALSE); diff --git a/src/dialogs/find.cpp b/src/dialogs/find.cpp index fe264892a..c112b3531 100644 --- a/src/dialogs/find.cpp +++ b/src/dialogs/find.cpp @@ -110,15 +110,18 @@ sp_find_squeeze_window() bool item_id_match (SPItem *item, const gchar *id, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) + if (item->getRepr() == NULL) { return false; + } - if (SP_IS_STRING(item)) // SPStrings have "on demand" ids which are useless for searching + if (SP_IS_STRING(item)) { // SPStrings have "on demand" ids which are useless for searching return false; + } - const gchar *item_id = (SP_OBJECT_REPR (item))->attribute("id"); - if (item_id == NULL) + const gchar *item_id = item->getRepr()->attribute("id"); + if (item_id == NULL) { return false; + } if (exact) { return ((bool) !strcmp(item_id, id)); @@ -131,8 +134,9 @@ item_id_match (SPItem *item, const gchar *id, bool exact) bool item_text_match (SPItem *item, const gchar *text, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) + if (item->getRepr() == NULL) { return false; + } if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { const gchar *item_text = sp_te_get_string_multiline (item); @@ -154,12 +158,14 @@ item_text_match (SPItem *item, const gchar *text, bool exact) bool item_style_match (SPItem *item, const gchar *text, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) + if (item->getRepr() == NULL) { return false; + } - const gchar *item_text = (SP_OBJECT_REPR (item))->attribute("style"); - if (item_text == NULL) + const gchar *item_text = item->getRepr()->attribute("style"); + if (item_text == NULL) { return false; + } if (exact) { return ((bool) !strcmp(item_text, text)); @@ -168,18 +174,18 @@ item_style_match (SPItem *item, const gchar *text, bool exact) } } -bool -item_attr_match (SPItem *item, const gchar *name, bool exact) +bool item_attr_match(SPItem *item, const gchar *name, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) - return false; - - if (exact) { - const gchar *attr_value = (SP_OBJECT_REPR (item))->attribute(name); - return ((bool) (attr_value != NULL)); - } else { - return SP_OBJECT_REPR (item)->matchAttributeName(name); + bool result = false; + if (item->getRepr()) { + if (exact) { + const gchar *attr_value = item->getRepr()->attribute(name); + result = (attr_value != NULL); + } else { + result = item->getRepr()->matchAttributeName(name); + } } + return result; } @@ -288,17 +294,20 @@ all_items (SPObject *r, GSList *l, bool hidden, bool locked) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (SP_IS_DEFS(r)) + if (SP_IS_DEFS(r)) { return l; // we're not interested in items in defs + } - if (!strcmp (SP_OBJECT_REPR (r)->name(), "svg:metadata")) + if (!strcmp(r->getRepr()->name(), "svg:metadata")) { return l; // we're not interested in metadata + } for (SPObject *child = r->firstChild(); child; child = child->next) { - if (SP_IS_ITEM (child) && !SP_OBJECT_IS_CLONED (child) && !desktop->isLayer(SP_ITEM(child))) { - if ((hidden || !desktop->itemIsHidden(SP_ITEM(child))) && (locked || !SP_ITEM(child)->isLocked())) { - l = g_slist_prepend (l, child); - } + if ( SP_IS_ITEM(child) && !child->cloned && !desktop->isLayer(child) ) { + SPItem *item = SP_ITEM(child); + if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) { + l = g_slist_prepend (l, child); + } } l = all_items (child, l, hidden, locked); } @@ -311,9 +320,10 @@ all_selection_items (Inkscape::Selection *s, GSList *l, SPObject *ancestor, bool SPDesktop *desktop = SP_ACTIVE_DESKTOP; for (GSList *i = (GSList *) s->itemList(); i != NULL; i = i->next) { - if (SP_IS_ITEM (i->data) && !SP_OBJECT_IS_CLONED (i->data) && !desktop->isLayer(SP_ITEM(i->data))) { - if (!ancestor || ancestor->isAncestorOf(SP_OBJECT (i->data))) { - if ((hidden || !desktop->itemIsHidden(SP_ITEM(i->data))) && (locked || !SP_ITEM(i->data)->isLocked())) { + if ( SP_IS_ITEM(i->data) && !reinterpret_cast<SPObject*>(i->data)->cloned && !desktop->isLayer(SP_ITEM(i->data))) { + SPItem * item = SP_ITEM(i->data); + if (!ancestor || ancestor->isAncestorOf(item)) { + if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) { l = g_slist_prepend (l, i->data); } } diff --git a/src/dialogs/item-properties.cpp b/src/dialogs/item-properties.cpp index 8b5ac1784..94b8b1e98 100644 --- a/src/dialogs/item-properties.cpp +++ b/src/dialogs/item-properties.cpp @@ -310,7 +310,7 @@ sp_item_widget_setup ( SPWidget *spw, Inkscape::Selection *selection ) w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "hidden")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), item->isExplicitlyHidden()); - if (SP_OBJECT_IS_CLONED (item)) { + if (item->cloned) { /* ID */ w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id")); diff --git a/src/dialogs/object-attributes.cpp b/src/dialogs/object-attributes.cpp index d9a0545e1..57b295e4e 100644 --- a/src/dialogs/object-attributes.cpp +++ b/src/dialogs/object-attributes.cpp @@ -13,6 +13,7 @@ #include <glibmm/i18n.h> #include <string> #include <cstring> +#include <stddef.h> #include <sigc++/connection.h> #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> @@ -141,7 +142,7 @@ sp_object_attributes_dialog (SPObject *object, const gchar *tag) if (!strcmp (tag, "Link")) { sp_object_attr_show_dialog (object, anchor_desc, tag); } else if (!strcmp (tag, "Image")) { - Inkscape::XML::Node *ir = SP_OBJECT_REPR(object); + Inkscape::XML::Node *ir = object->getRepr(); const gchar *href = ir->attribute("xlink:href"); if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { sp_object_attr_show_dialog (object, image_nohref_desc, tag); diff --git a/src/dialogs/spellcheck.cpp b/src/dialogs/spellcheck.cpp index 4712d9926..f72612420 100644 --- a/src/dialogs/spellcheck.cpp +++ b/src/dialogs/spellcheck.cpp @@ -210,7 +210,7 @@ all_text_items (SPObject *r, GSList *l, bool hidden, bool locked) } for (SPObject *child = r->firstChild(); child; child = child->next) { - if (SP_IS_ITEM (child) && !SP_OBJECT_IS_CLONED (child) && !_desktop->isLayer(SP_ITEM(child))) { + if (SP_IS_ITEM (child) && !child->cloned && !_desktop->isLayer(SP_ITEM(child))) { if ((hidden || !_desktop->itemIsHidden(SP_ITEM(child))) && (locked || !SP_ITEM(child)->isLocked())) { if (SP_IS_TEXT(child) || SP_IS_FLOWTEXT(child)) l = g_slist_prepend (l, child); diff --git a/src/dialogs/text-edit.cpp b/src/dialogs/text-edit.cpp index 207b9b0d2..7cec16cd7 100644 --- a/src/dialogs/text-edit.cpp +++ b/src/dialogs/text-edit.cpp @@ -49,8 +49,10 @@ extern "C" { #include "svg/css-ostringstream.h" #include "widgets/icon.h" #include <xml/repr.h> +#include "util/ege-appear-time-tracker.h" using Inkscape::DocumentUndo; +using ege::AppearTimeTracker; #define VB_MARGIN 4 #define MIN_ONSCREEN_DISTANCE 50 @@ -139,6 +141,9 @@ text_view_focus_out (GtkWidget */*w*/, GdkEventKey */*event*/, gpointer data) void sp_text_edit_dialog (void) { + bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false); + GTimer *timer = wantTiming ? g_timer_new() : 0; + if (!dlg) { gchar title[500]; @@ -460,6 +465,13 @@ sp_text_edit_dialog (void) sp_text_edit_dialog_read_selection (dlg, TRUE, TRUE); } + if ( wantTiming ) { + // Time tracker takes ownership of the timer. + AppearTimeTracker *tracker = new AppearTimeTracker(timer, GTK_WIDGET(dlg), "DialogText"); + tracker->setAutodelete(true); + timer = 0; + } + gtk_window_present ((GtkWindow *) dlg); } // end of sp_text_edit_dialog() diff --git a/src/dialogs/xml-tree.cpp b/src/dialogs/xml-tree.cpp index c90cde490..ddb419dcd 100644 --- a/src/dialogs/xml-tree.cpp +++ b/src/dialogs/xml-tree.cpp @@ -41,8 +41,10 @@ #include "../widgets/sp-xmlview-attr-list.h" #include "../widgets/sp-xmlview-content.h" #include "../widgets/sp-xmlview-tree.h" +#include "util/ege-appear-time-tracker.h" using Inkscape::DocumentUndo; +using ege::AppearTimeTracker; #define MIN_ONSCREEN_DISTANCE 50 @@ -178,11 +180,13 @@ void attr_reset_context(gint attr) void sp_xml_tree_dialog() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (!desktop) { return; } + bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false); + GTimer *timer = wantTiming ? g_timer_new() : 0; + if (dlg == NULL) { // very long block @@ -604,6 +608,13 @@ void sp_xml_tree_dialog() tree_reset_context(); } // end of if (dlg == NULL) + if ( wantTiming ) { + // Time tracker takes ownership of the timer. + AppearTimeTracker *tracker = new AppearTimeTracker(timer, GTK_WIDGET(dlg), "DialogXMLEditor"); + tracker->setAutodelete(true); + timer = 0; + } + gtk_window_present((GtkWindow *) dlg); g_assert(desktop != NULL); @@ -1591,7 +1602,7 @@ bool in_dt_coordsys(SPObject const &item) if (!SP_IS_ITEM(child)) { return false; } - SPObject const * const parent = SP_OBJECT_PARENT(child); + SPObject const * const parent = child->parent; if (parent == NULL) { break; } diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert index 916dd6dc3..fc7c8e9ab 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -23,9 +23,10 @@ ink_common_sources += \ display/canvas-text.h \ display/curve.cpp \ display/curve.h \ - display/display-forward.h \ display/gnome-canvas-acetate.cpp \ display/gnome-canvas-acetate.h \ + display/grayscale.cpp \ + display/grayscale.h \ display/guideline.cpp \ display/guideline.h \ display/nr-3dutils.cpp \ diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index ed4de8afc..adf5dcb9a 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -18,7 +18,7 @@ #include <2geom/pathvector.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/point.h> #include <2geom/path.h> #include <2geom/transforms.h> @@ -73,7 +73,7 @@ CairoContext::CairoContext(cairo_t *obj, bool ref) : Cairo::Context(obj, ref) {} -void CairoContext::transform(Geom::Matrix const &m) +void CairoContext::transform(Geom::Affine const &m) { cairo_matrix_t cm; cm.xx = m[0]; @@ -113,7 +113,7 @@ Cairo::RefPtr<CairoContext> CairoContext::create(Cairo::RefPtr<Cairo::Surface> c * If optimize_stroke == false, the view Rect is not used. */ static void -feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Matrix const & trans, Geom::Rect view, bool optimize_stroke) +feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Affine const & trans, Geom::Rect view, bool optimize_stroke) { if( is_straight_curve(c) ) { @@ -203,7 +203,7 @@ feed_path_to_cairo (cairo_t *ct, Geom::Path const &path) /** Feeds path-creating calls to the cairo context translating them from the Path, with the given transform and shift */ static void -feed_path_to_cairo (cairo_t *ct, Geom::Path const &path, Geom::Matrix trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) +feed_path_to_cairo (cairo_t *ct, Geom::Path const &path, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) { if (!area) return; @@ -214,9 +214,9 @@ feed_path_to_cairo (cairo_t *ct, Geom::Path const &path, Geom::Matrix trans, Geo Geom::Point shift = area->min(); Geom::Rect view = *area; view.expandBy (stroke_width); - view = view * (Geom::Matrix)Geom::Translate(-shift); + view = view * (Geom::Affine)Geom::Translate(-shift); // Pass transformation to feed_curve, so that we don't need to create a whole new path. - Geom::Matrix transshift(trans * Geom::Translate(-shift)); + Geom::Affine transshift(trans * Geom::Translate(-shift)); Geom::Point initial = path.initialPoint() * transshift; cairo_move_to(ct, initial[0], initial[1] ); @@ -251,7 +251,7 @@ feed_path_to_cairo (cairo_t *ct, Geom::Path const &path, Geom::Matrix trans, Geo /** Feeds path-creating calls to the cairo context translating them from the PathVector, with the given transform and shift * One must have done cairo_new_path(ct); before calling this function. */ void -feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Matrix trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) +feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width) { if (!area) return; @@ -288,7 +288,7 @@ ink_cairo_set_source_color(cairo_t *ct, SPColor const &c, double opacity) cairo_set_source_rgba(ct, c.v.c[0], c.v.c[1], c.v.c[2], opacity); } -void ink_matrix_to_2geom(Geom::Matrix &m, cairo_matrix_t const &cm) +void ink_matrix_to_2geom(Geom::Affine &m, cairo_matrix_t const &cm) { m[0] = cm.xx; m[2] = cm.xy; @@ -298,7 +298,7 @@ void ink_matrix_to_2geom(Geom::Matrix &m, cairo_matrix_t const &cm) m[5] = cm.y0; } -void ink_matrix_to_cairo(cairo_matrix_t &cm, Geom::Matrix const &m) +void ink_matrix_to_cairo(cairo_matrix_t &cm, Geom::Affine const &m) { cm.xx = m[0]; cm.xy = m[2]; @@ -309,7 +309,7 @@ void ink_matrix_to_cairo(cairo_matrix_t &cm, Geom::Matrix const &m) } void -ink_cairo_transform(cairo_t *ct, Geom::Matrix const &m) +ink_cairo_transform(cairo_t *ct, Geom::Affine const &m) { cairo_matrix_t cm; ink_matrix_to_cairo(cm, m); @@ -317,7 +317,7 @@ ink_cairo_transform(cairo_t *ct, Geom::Matrix const &m) } void -ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Matrix const &m) +ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m) { cairo_matrix_t cm; ink_matrix_to_cairo(cm, m); diff --git a/src/display/cairo-utils.h b/src/display/cairo-utils.h index d563cfb75..d5c84810c 100644 --- a/src/display/cairo-utils.h +++ b/src/display/cairo-utils.h @@ -69,7 +69,7 @@ class CairoContext : public Cairo::Context { public: CairoContext(cairo_t *obj, bool ref = false); - void transform(Geom::Matrix const &m); + void transform(Geom::Affine const &m); void set_source_rgba32(guint32 color); void append_path(Geom::PathVector const &pv); @@ -80,12 +80,12 @@ public: void ink_cairo_set_source_color(cairo_t *ct, SPColor const &color, double opacity); void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba); -void ink_cairo_transform(cairo_t *ct, Geom::Matrix const &m); -void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Matrix const &m); +void ink_cairo_transform(cairo_t *ct, Geom::Affine const &m); +void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m); void ink_cairo_set_source_argb32_pixbuf(cairo_t *ct, GdkPixbuf *pb, double x, double y); -void ink_matrix_to_2geom(Geom::Matrix &, cairo_matrix_t const &); -void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Matrix const &); +void ink_matrix_to_2geom(Geom::Affine &, cairo_matrix_t const &); +void ink_matrix_to_cairo(cairo_matrix_t &, Geom::Affine const &); cairo_surface_t *ink_cairo_surface_copy(cairo_surface_t *s); cairo_surface_t *ink_cairo_surface_create_identical(cairo_surface_t *s); @@ -121,7 +121,7 @@ unpremul_alpha(guint32 color, guint32 alpha) } // TODO: move those to 2Geom -void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Matrix trans, Geom::OptRect area, bool optimize_stroke, double stroke_width); +void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv, Geom::Affine trans, Geom::OptRect area, bool optimize_stroke, double stroke_width); void feed_pathvector_to_cairo (cairo_t *ct, Geom::PathVector const &pathv); #define EXTRACT_ARGB32(px,a,r,g,b) \ diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index c681ea5a0..884e604be 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -1,5 +1,3 @@ -#define __SP_CANVAS_ARENA_C__ - /* * RGBA display list system for inkscape * @@ -31,7 +29,7 @@ static void sp_canvas_arena_class_init(SPCanvasArenaClass *klass); static void sp_canvas_arena_init(SPCanvasArena *group); static void sp_canvas_arena_destroy(GtkObject *object); -static void sp_canvas_arena_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf); static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event); @@ -136,7 +134,7 @@ sp_canvas_arena_destroy (GtkObject *object) } static void -sp_canvas_arena_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCanvasArena *arena = SP_CANVAS_ARENA (item); diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index df484197a..6db87b675 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -16,6 +16,7 @@ #include <cairo.h> #include <2geom/rect.h> #include "display/sp-canvas.h" +#include "display/sp-canvas-item.h" #include "display/nr-arena-item.h" G_BEGIN_DECLS diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index c4fdb2452..a9893f09d 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -1,5 +1,3 @@ -#define CANVAS_AXONOMGRID_C - /* * Copyright (C) 2006-2008 Johan Engelen <johan@shouraizou.nl> */ @@ -19,6 +17,7 @@ #include "2geom/line.h" #include "desktop.h" +#include "canvas-grid.h" #include "desktop-handles.h" #include "display/cairo-utils.h" #include "display/canvas-axonomgrid.h" @@ -475,7 +474,7 @@ CanvasAxonomGrid::updateWidgets() void -CanvasAxonomGrid::Update (Geom::Matrix const &affine, unsigned int /*flags*/) +CanvasAxonomGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/) { ow = origin * affine; sw = Geom::Point(fabs(affine[0]),fabs(affine[3])); diff --git a/src/display/canvas-axonomgrid.h b/src/display/canvas-axonomgrid.h index 58185e2e6..282524c74 100644 --- a/src/display/canvas-axonomgrid.h +++ b/src/display/canvas-axonomgrid.h @@ -34,7 +34,7 @@ public: CanvasAxonomGrid(SPNamedView * nv, Inkscape::XML::Node * in_repr, SPDocument * in_doc); virtual ~CanvasAxonomGrid(); - void Update (Geom::Matrix const &affine, unsigned int flags); + void Update (Geom::Affine const &affine, unsigned int flags); void Render (SPCanvasBuf *buf); void readRepr(); diff --git a/src/display/canvas-bpath.cpp b/src/display/canvas-bpath.cpp index 082e6d44e..f86743744 100644 --- a/src/display/canvas-bpath.cpp +++ b/src/display/canvas-bpath.cpp @@ -1,5 +1,3 @@ -#define __SP_CANVAS_BPATH_C__ - /* * Simple bezier bpath CanvasItem for inkscape * @@ -15,7 +13,12 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#include <sstream> +#include <string.h> +#include "desktop.h" + #include "color.h" +#include "display/sp-canvas-group.h" #include "display/sp-canvas-util.h" #include "display/canvas-bpath.h" #include "display/display-forward.h" @@ -23,17 +26,13 @@ #include "display/cairo-utils.h" #include "helper/geom.h" -#include <sstream> -#include <string.h> -#include <desktop.h> - void nr_pixblock_render_bpath_rgba (Shape* theS,uint32_t color,NRRectL &area,char* destBuf,int stride); static void sp_canvas_bpath_class_init (SPCanvasBPathClass *klass); static void sp_canvas_bpath_init (SPCanvasBPath *path); static void sp_canvas_bpath_destroy (GtkObject *object); -static void sp_canvas_bpath_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_canvas_bpath_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_canvas_bpath_render (SPCanvasItem *item, SPCanvasBuf *buf); static double sp_canvas_bpath_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); @@ -102,7 +101,7 @@ sp_canvas_bpath_destroy (GtkObject *object) } static void -sp_canvas_bpath_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_canvas_bpath_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCanvasBPath *cbp = SP_CANVAS_BPATH (item); diff --git a/src/display/canvas-bpath.h b/src/display/canvas-bpath.h index 65ad4aa00..7f8b75dfe 100644 --- a/src/display/canvas-bpath.h +++ b/src/display/canvas-bpath.h @@ -1,13 +1,15 @@ -#ifndef __SP_CANVAS_BPATH_H__ -#define __SP_CANVAS_BPATH_H__ +#ifndef SEEN_SP_CANVAS_BPATH_H +#define SEEN_SP_CANVAS_BPATH_H /* * Simple bezier bpath CanvasItem for inkscape * * Authors: * Lauris Kaplinski <lauris@ximian.com> + * Jon A. Cruz <jon@joncruz.org> * * Copyright (C) 2001 Lauris Kaplinski and Ximian, Inc. + * Copyright (C) 2010 authors * * Released under GNU GPL * @@ -15,10 +17,11 @@ #include <glib/gtypes.h> -#include <display/sp-canvas.h> +#include "sp-canvas-item.h" struct SPCanvasBPath; struct SPCanvasBPathClass; +struct SPCanvasGroup; struct SPCurve; #define SP_TYPE_CANVAS_BPATH (sp_canvas_bpath_get_type ()) @@ -64,7 +67,7 @@ struct SPCanvasBPath { /* Line def */ SPCurve *curve; - Geom::Matrix affine; + Geom::Affine affine; /* Fill attributes */ guint32 fill_rgba; diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 86897baaa..82ea036f6 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -22,6 +22,7 @@ #include "display/canvas-grid.h" #include "display/display-forward.h" #include "display/sp-canvas-util.h" +#include "display/sp-canvas-group.h" #include "document.h" #include "helper/units.h" #include "inkscape.h" @@ -52,7 +53,7 @@ static void grid_canvasitem_class_init (GridCanvasItemClass *klass); static void grid_canvasitem_init (GridCanvasItem *grid); static void grid_canvasitem_destroy (GtkObject *object); -static void grid_canvasitem_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void grid_canvasitem_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void grid_canvasitem_render (SPCanvasItem *item, SPCanvasBuf *buf); static SPCanvasItemClass * parent_class; @@ -124,7 +125,7 @@ grid_canvasitem_render (SPCanvasItem * item, SPCanvasBuf * buf) } static void -grid_canvasitem_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +grid_canvasitem_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { GridCanvasItem *gridcanvasitem = INKSCAPE_GRID_CANVASITEM (item); @@ -803,7 +804,7 @@ CanvasXYGrid::updateWidgets() void -CanvasXYGrid::Update (Geom::Matrix const &affine, unsigned int /*flags*/) +CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/) { ow = origin * affine; sw = spacing * affine; diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index a11d77d1d..f386fe05e 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -14,7 +14,7 @@ #include <gtkmm/box.h> #include <gtkmm.h> -#include "display/sp-canvas.h" +#include "sp-canvas-item.h" #include "xml/repr.h" #include "ui/widget/color-picker.h" #include "ui/widget/scalar-unit.h" @@ -26,6 +26,7 @@ struct SPDesktop; struct SPNamedView; +struct SPCanvasBuf; class SPDocument; namespace Inkscape { @@ -78,7 +79,7 @@ public: GridCanvasItem * createCanvasItem(SPDesktop * desktop); - virtual void Update (Geom::Matrix const &affine, unsigned int flags) = 0; + virtual void Update (Geom::Affine const &affine, unsigned int flags) = 0; virtual void Render (SPCanvasBuf *buf) = 0; virtual void readRepr() = 0; @@ -128,7 +129,7 @@ public: CanvasXYGrid(SPNamedView * nv, Inkscape::XML::Node * in_repr, SPDocument * in_doc); virtual ~CanvasXYGrid(); - void Update (Geom::Matrix const &affine, unsigned int flags); + void Update (Geom::Affine const &affine, unsigned int flags); void Render (SPCanvasBuf *buf); void readRepr(); diff --git a/src/display/canvas-temporary-item-list.h b/src/display/canvas-temporary-item-list.h index 4d712e216..47556b9f1 100644 --- a/src/display/canvas-temporary-item-list.h +++ b/src/display/canvas-temporary-item-list.h @@ -13,9 +13,10 @@ */ #include "forward.h" -#include "display/display-forward.h" #include <list> +struct SPCanvasItem; + namespace Inkscape { namespace Display { diff --git a/src/display/canvas-temporary-item.h b/src/display/canvas-temporary-item.h index 5077fb55b..b73907bad 100644 --- a/src/display/canvas-temporary-item.h +++ b/src/display/canvas-temporary-item.h @@ -12,9 +12,12 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/display-forward.h" +#include <stddef.h> #include <sigc++/sigc++.h> +#include <glib/gtypes.h> + +struct SPCanvasItem; namespace Inkscape { namespace Display { diff --git a/src/display/canvas-text.cpp b/src/display/canvas-text.cpp index 682b15eb8..54cbe5da8 100644 --- a/src/display/canvas-text.cpp +++ b/src/display/canvas-text.cpp @@ -31,7 +31,7 @@ static void sp_canvastext_class_init (SPCanvasTextClass *klass); static void sp_canvastext_init (SPCanvasText *canvastext); static void sp_canvastext_destroy (GtkObject *object); -static void sp_canvastext_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_canvastext_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_canvastext_render (SPCanvasItem *item, SPCanvasBuf *buf); static SPCanvasItemClass *parent_class_ct; @@ -131,7 +131,7 @@ sp_canvastext_render (SPCanvasItem *item, SPCanvasBuf *buf) } static void -sp_canvastext_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_canvastext_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCanvasText *cl = SP_CANVASTEXT (item); diff --git a/src/display/canvas-text.h b/src/display/canvas-text.h index e5d634985..9a6a93eb4 100644 --- a/src/display/canvas-text.h +++ b/src/display/canvas-text.h @@ -1,5 +1,5 @@ -#ifndef __SP_CANVASTEXT_H__ -#define __SP_CANVASTEXT_H__ +#ifndef SEEN_SP_CANVASTEXT_H +#define SEEN_SP_CANVASTEXT_H /* * Canvas text. @@ -14,10 +14,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -/* - * FIXME: The following code should actually be in a separate file called display/canvas-text.h. It - * temporarily had to be moved here because of linker errors. - */ +#include "sp-canvas-item.h" struct SPItem; struct SPDesktop; @@ -26,7 +23,7 @@ struct SPDesktop; #define SP_CANVASTEXT(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_CANVASTEXT, SPCanvasText)) #define SP_IS_CANVASTEXT(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_CANVASTEXT)) -struct SPCanvasText : public SPCanvasItem{ +struct SPCanvasText : public SPCanvasItem { SPItem *item; // the item to which this line belongs in some sense; may be NULL for some users guint32 rgba; guint32 rgba_stroke; @@ -34,7 +31,7 @@ struct SPCanvasText : public SPCanvasItem{ gchar* text; Geom::Point s; - Geom::Matrix affine; + Geom::Affine affine; double fontsize; double anchor_x; double anchor_y; @@ -53,7 +50,8 @@ void sp_canvastext_set_number_as_text (SPCanvasText *ct, int num); void sp_canvastext_set_fontsize (SPCanvasText *ct, double size); void sp_canvastext_set_anchor (SPCanvasText *ct, double anchor_x, double anchor_y); -#endif +#endif // SEEN_SP_CANVASTEXT_H + /* diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 303d1bb4d..5c18324eb 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -180,7 +180,7 @@ SPCurve::split() const * Transform all paths in curve using matrix. */ void -SPCurve::transform(Geom::Matrix const &m) +SPCurve::transform(Geom::Affine const &m) { _pathv *= m; } diff --git a/src/display/curve.h b/src/display/curve.h index e6387a9f0..ec828e674 100644 --- a/src/display/curve.h +++ b/src/display/curve.h @@ -67,7 +67,7 @@ public: void closepath_current(); void backspace(); - void transform(Geom::Matrix const &m); + void transform(Geom::Affine const &m); void stretch_endpoints(Geom::Point const &, Geom::Point const &); void move_endpoints(Geom::Point const &, Geom::Point const &); void last_point_additive_move(Geom::Point const & p); diff --git a/src/display/display-forward.h b/src/display/display-forward.h index 25c4a6e3d..bc7013214 100644 --- a/src/display/display-forward.h +++ b/src/display/display-forward.h @@ -18,26 +18,6 @@ namespace Display { } } -#define SP_TYPE_CANVAS_ITEM (sp_canvas_item_get_type()) -#define SP_CANVAS_ITEM(obj) (GTK_CHECK_CAST((obj), SP_TYPE_CANVAS_ITEM, SPCanvasItem)) -#define SP_IS_CANVAS_ITEM(obj) (GTK_CHECK_TYPE((obj), SP_TYPE_CANVAS_ITEM)) -#define SP_CANVAS_ITEM_GET_CLASS(o) (GTK_CHECK_GET_CLASS((o), SP_TYPE_CANVAS_ITEM, SPCanvasItemClass)) - -GType sp_canvas_item_get_type(); - -#define SP_TYPE_CANVAS_GROUP (sp_canvas_group_get_type()) -#define SP_CANVAS_GROUP(obj) (GTK_CHECK_CAST((obj), SP_TYPE_CANVAS_GROUP, SPCanvasGroup)) -#define SP_IS_CANVAS_GROUP(obj) (GTK_CHECK_TYPE((obj), SP_TYPE_CANVAS_GROUP)) - -GType sp_canvas_group_get_type(); - -#define SP_TYPE_CANVAS (sp_canvas_get_type()) -#define SP_CANVAS(obj) (GTK_CHECK_CAST((obj), SP_TYPE_CANVAS, SPCanvas)) -#define SP_IS_CANVAS(obj) (GTK_CHECK_TYPE((obj), SP_TYPE_CANVAS)) - -GType sp_canvas_get_type(); - - #endif /* !SEEN_DISPLAY_DISPLAY_FORWARD_H */ /* diff --git a/src/display/gnome-canvas-acetate.cpp b/src/display/gnome-canvas-acetate.cpp index fdb137e27..b86892e32 100644 --- a/src/display/gnome-canvas-acetate.cpp +++ b/src/display/gnome-canvas-acetate.cpp @@ -14,14 +14,13 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display-forward.h" #include "gnome-canvas-acetate.h" static void sp_canvas_acetate_class_init (SPCanvasAcetateClass *klass); static void sp_canvas_acetate_init (SPCanvasAcetate *acetate); static void sp_canvas_acetate_destroy (GtkObject *object); -static void sp_canvas_acetate_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_canvas_acetate_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static double sp_canvas_acetate_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); static SPCanvasItemClass *parent_class; @@ -82,7 +81,7 @@ sp_canvas_acetate_destroy (GtkObject *object) } static void -sp_canvas_acetate_update( SPCanvasItem *item, Geom::Matrix const &/*affine*/, unsigned int /*flags*/ ) +sp_canvas_acetate_update( SPCanvasItem *item, Geom::Affine const &/*affine*/, unsigned int /*flags*/ ) { item->x1 = -G_MAXINT; item->y1 = -G_MAXINT; diff --git a/src/display/gnome-canvas-acetate.h b/src/display/gnome-canvas-acetate.h index 40574e1bf..8c284291c 100644 --- a/src/display/gnome-canvas-acetate.h +++ b/src/display/gnome-canvas-acetate.h @@ -1,5 +1,5 @@ -#ifndef __SP_CANVAS_ACETATE_H__ -#define __SP_CANVAS_ACETATE_H__ +#ifndef SEEN_SP_CANVAS_ACETATE_H +#define SEEN_SP_CANVAS_ACETATE_H /* * Infinite invisible canvas item @@ -16,7 +16,7 @@ */ #include <glib/gtypes.h> -#include "display/sp-canvas.h" +#include "display/sp-canvas-item.h" #define GNOME_TYPE_CANVAS_ACETATE (sp_canvas_acetate_get_type ()) @@ -38,4 +38,15 @@ GtkType sp_canvas_acetate_get_type (void); -#endif +#endif // SEEN_SP_CANVAS_ACETATE_H + +/* + 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 : diff --git a/src/display/grayscale.cpp b/src/display/grayscale.cpp new file mode 100644 index 000000000..37f2b255c --- /dev/null +++ b/src/display/grayscale.cpp @@ -0,0 +1,95 @@ +/** \file + * Provide methods to calculate grayscale values (e.g. convert rgba value to grayscale rgba value) + */ + +/* + * Author: + * Johan Engelen <goejendaagh@zonnet.nl> + * + * Copyright (C) 2011 Author + * + * Released under GNU GPL + */ + +#include "display/grayscale.h" +#include "color.h" + +// for activeDesktopIsGrayscale: +#include "display/rendermode.h" +#include "inkscape.h" +#include "desktop.h" + +namespace Grayscale { + +guint32 process(guint32 rgba) { + return process(SP_RGBA32_R_U(rgba), SP_RGBA32_G_U(rgba), SP_RGBA32_B_U(rgba), SP_RGBA32_A_U(rgba)); +} + +guint32 process(guchar r, guchar g, guchar b, guchar a) { + float red_factor = 0.3; + float green_factor = 0.59; + float blue_factor = 0.11; + + /** To reduce banding in gradients, this calculation is tweaked a bit + * by outputing blue+1 or red+1 or both. The luminance is calculated + * times 4. Then last two bits are used to determine if red and/or blue + * can be increased by one. Then these two bits are discarded. + * So the output color it still looks gray, but has more than 256 steps. + * The assumption is that the eye is most sensitive to green, then red, then blue. + * (hope this trick works :-) Johan) + */ + + guint32 luminance = ( red_factor * (r << 3) + + green_factor * (g << 3) + + blue_factor * (b << 3) ); + unsigned blue_plus_one = (luminance & 0x01) ? 1 : 0; + unsigned red_plus_one = (luminance & 0x02) ? 1 : 0; + unsigned green_plus_one = (luminance & 0x04) ? 1 : 0; + luminance = luminance >> 3; + + if (luminance >= 0xff) { + return SP_RGBA32_U_COMPOSE(0xff, 0xff, 0xff, a); + } else { + return SP_RGBA32_U_COMPOSE(luminance + red_plus_one, luminance + green_plus_one, luminance + blue_plus_one, a); + } +} + +guchar luminance(guchar r, guchar g, guchar b) { + guint32 luminance = ( red_factor * r + + green_factor * g + + blue_factor * b ); + if (luminance > 0xff) { + luminance = 0xff; + } + + return luminance & 0xff; +} + +/** @brief Use this method if there is no other way to find out if grayscale view or not + * + * In some cases, the choice between normal or grayscale is so deep in the code hierarchy, + * that it is not possible to determine whether grayscale is desired or not, without using + * the global SP_ACTIVE_DESKTOP macro. Then use this method, so we know where the abuse is + * happening... + */ +bool activeDesktopIsGrayscale() { + if (SP_ACTIVE_DESKTOP) { + return (SP_ACTIVE_DESKTOP->getColorMode() == Inkscape::COLORRENDERMODE_GRAYSCALE); + } else { + return false; + } +} + + +}; + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/grayscale.h b/src/display/grayscale.h new file mode 100644 index 000000000..855c9e465 --- /dev/null +++ b/src/display/grayscale.h @@ -0,0 +1,40 @@ +#ifndef SEEN_DISPLAY_GRAYSCALE_H +#define SEEN_DISPLAY_GRAYSCALE_H + +/** \file + * Provide methods to calculate grayscale values (e.g. convert rgba value to grayscale rgba value) + * + * Author: + * Johan Engelen <goejendaagh@zonnet.nl> + * + * Copyright (C) 2011 Author + * + * Released under GNU GPL + */ + +#include <gdk/gdktypes.h> + +namespace Grayscale { + guint32 process(guint32 rgba); + guint32 process(guchar r, guchar g, guchar b, guchar a); + guchar luminance(guchar r, guchar g, guchar b); + + const float red_factor = 0.3; + const float green_factor = 0.59; + const float blue_factor = 0.11; + + bool activeDesktopIsGrayscale(); +}; + +#endif /* !SEEN_DISPLAY_GRAYSCALE_H */ + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp index 75c201d78..072ae69f1 100644 --- a/src/display/guideline.cpp +++ b/src/display/guideline.cpp @@ -1,5 +1,3 @@ -#define __SP_GUIDELINE_C__ - /* * Horizontal/vertical but can also be angled line * @@ -16,7 +14,6 @@ */ #include <2geom/transforms.h> -#include "display-forward.h" #include "sp-canvas-util.h" #include "sp-ctrlpoint.h" #include "guideline.h" @@ -26,7 +23,7 @@ static void sp_guideline_class_init(SPGuideLineClass *c); static void sp_guideline_init(SPGuideLine *guideline); static void sp_guideline_destroy(GtkObject *object); -static void sp_guideline_update(SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf); static double sp_guideline_point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); @@ -162,7 +159,7 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) cairo_restore(buf->ct); } -static void sp_guideline_update(SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPGuideLine *gl = SP_GUIDELINE(item); @@ -222,8 +219,8 @@ SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, Geom::Point point_on_line, void sp_guideline_set_position(SPGuideLine *gl, Geom::Point point_on_line) { - sp_canvas_item_affine_absolute(SP_CANVAS_ITEM (gl), Geom::Matrix(Geom::Translate(point_on_line))); - sp_canvas_item_affine_absolute(SP_CANVAS_ITEM (gl->origin), Geom::Matrix(Geom::Translate(point_on_line))); + sp_canvas_item_affine_absolute(SP_CANVAS_ITEM (gl), Geom::Affine(Geom::Translate(point_on_line))); + sp_canvas_item_affine_absolute(SP_CANVAS_ITEM (gl->origin), Geom::Affine(Geom::Translate(point_on_line))); } void sp_guideline_set_normal(SPGuideLine *gl, Geom::Point normal_to_line) diff --git a/src/display/guideline.h b/src/display/guideline.h index a6ce57113..9654d04a1 100644 --- a/src/display/guideline.h +++ b/src/display/guideline.h @@ -1,5 +1,5 @@ -#ifndef __SP_GUIDELINE_H__ -#define __SP_GUIDELINE_H__ +#ifndef SEEN_SP_GUIDELINE_H +#define SEEN_SP_GUIDELINE_H /* * The visual representation of SPGuide. @@ -14,8 +14,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "sp-canvas.h" #include <2geom/point.h> +#include "sp-canvas-item.h" #define SP_TYPE_GUIDELINE (sp_guideline_get_type()) #define SP_GUIDELINE(o) (GTK_CHECK_CAST((o), SP_TYPE_GUIDELINE, SPGuideLine)) @@ -53,7 +53,7 @@ void sp_guideline_set_color(SPGuideLine *gl, unsigned int rgba); void sp_guideline_set_sensitive(SPGuideLine *gl, int sensitive); void sp_guideline_delete(SPGuideLine *gl); -#endif +#endif // SEEN_SP_GUIDELINE_H /* Local Variables: diff --git a/src/display/nr-3dutils.cpp b/src/display/nr-3dutils.cpp index 4518269af..eb6858374 100644 --- a/src/display/nr-3dutils.cpp +++ b/src/display/nr-3dutils.cpp @@ -14,11 +14,11 @@ #include "display/nr-3dutils.h" #include <cmath> #include <2geom/point.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> namespace NR { -void convert_coord(gdouble &x, gdouble &y, gdouble &z, Geom::Matrix const &trans) { +void convert_coord(gdouble &x, gdouble &y, gdouble &z, Geom::Affine const &trans) { Geom::Point p = Geom::Point(x, y); p *= trans; x = p[Geom::X]; diff --git a/src/display/nr-3dutils.h b/src/display/nr-3dutils.h index 5651b2246..4e98c2374 100644 --- a/src/display/nr-3dutils.h +++ b/src/display/nr-3dutils.h @@ -90,7 +90,7 @@ void normalized_sum(Fvector &r, const Fvector &a, const Fvector &b); * \param z a reference to a z coordinate * \param z a reference to a transformation matrix */ -void convert_coord(gdouble &x, gdouble &y, gdouble &z, Geom::Matrix const &trans); +void convert_coord(gdouble &x, gdouble &y, gdouble &z, Geom::Affine const &trans); } /* namespace NR */ diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index 571f777fe..5f21ceaa9 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -17,7 +17,7 @@ # include <config.h> #endif #include "libnr/nr-convert2geom.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "style.h" #include "display/nr-arena.h" #include "display/nr-arena-glyphs.h" @@ -115,7 +115,7 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s return NR_ARENA_ITEM_STATE_ALL; Geom::OptRect b; - Geom::Matrix t = glyphs->g_transform * gc->transform; + Geom::Affine t = glyphs->g_transform * gc->transform; glyphs->x = t[4]; glyphs->y = t[5]; @@ -183,7 +183,7 @@ nr_arena_glyphs_pick(NRArenaItem *item, Geom::Point p, gdouble delta, unsigned i } void -nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int /*lieutenant*/, font_instance *font, gint glyph, Geom::Matrix const *transform) +nr_arena_glyphs_set_path(NRArenaGlyphs *glyphs, SPCurve */*curve*/, unsigned int /*lieutenant*/, font_instance *font, gint glyph, Geom::Affine const *transform) { nr_return_if_fail(glyphs != NULL); nr_return_if_fail(NR_IS_ARENA_GLYPHS(glyphs)); @@ -308,7 +308,7 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); Geom::PathVector const * pathv = g->font->PathVector(g->glyph); - Geom::Matrix transform = g->g_transform * group->ctm; + Geom::Affine transform = g->g_transform * group->ctm; cairo_new_path(ct); ink_cairo_transform(ct, transform); @@ -397,7 +397,7 @@ nr_arena_glyphs_group_clear(NRArenaGlyphsGroup *sg) } void -nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, Geom::Matrix const &transform) +nr_arena_glyphs_group_add_component(NRArenaGlyphsGroup *sg, font_instance *font, int glyph, Geom::Affine const &transform) { NRArenaGroup *group; diff --git a/src/display/nr-arena-glyphs.h b/src/display/nr-arena-glyphs.h index f0580282f..6f8a0bde5 100644 --- a/src/display/nr-arena-glyphs.h +++ b/src/display/nr-arena-glyphs.h @@ -1,5 +1,5 @@ -#ifndef __NR_ARENA_GLYPHS_H__ -#define __NR_ARENA_GLYPHS_H__ +#ifndef SEEN_NR_ARENA_GLYPHS_H +#define SEEN_NR_ARENA_GLYPHS_H /* * RGBA display list system for inkscape @@ -26,13 +26,15 @@ #define test_glyph_liv +struct SPCurve; class Shape; NRType nr_arena_glyphs_get_type (void); struct NRArenaGlyphs : public NRArenaItem { /* Glyphs data */ - Geom::Matrix g_transform; + Geom::Affine g_transform; + font_instance *font; gint glyph; float x, y; @@ -51,7 +53,7 @@ struct NRArenaGlyphsClass { void nr_arena_glyphs_set_path ( NRArenaGlyphs *glyphs, SPCurve *curve, unsigned int lieutenant, font_instance *font, int glyph, - Geom::Matrix const *transform ); + Geom::Affine const *transform ); void nr_arena_glyphs_set_style (NRArenaGlyphs *glyphs, SPStyle *style); /* Integrated group of component glyphss */ @@ -86,10 +88,21 @@ struct NRArenaGlyphsGroupClass { void nr_arena_glyphs_group_clear (NRArenaGlyphsGroup *group); -void nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *group, font_instance *font, int glyph, Geom::Matrix const &transform); +void nr_arena_glyphs_group_add_component (NRArenaGlyphsGroup *group, font_instance *font, int glyph, Geom::Affine const &transform); void nr_arena_glyphs_group_set_style (NRArenaGlyphsGroup *group, SPStyle *style); void nr_arena_glyphs_group_set_paintbox (NRArenaGlyphsGroup *group, const NRRect *pbox); -#endif +#endif // SEEN_NR_ARENA_GLYPHS_H + +/* + 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 : diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 7ad24bf70..97f92d02d 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -269,13 +269,13 @@ nr_arena_group_set_transparent (NRArenaGroup *group, unsigned int transparent) group->transparent = transparent; } -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Matrix const &t) +void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t) { - Geom::Matrix nt(t); + Geom::Affine nt(t); nr_arena_group_set_child_transform(group, &nt); } -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Matrix const *t) +void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t) { if (!t) t = &GEOM_MATRIX_IDENTITY; diff --git a/src/display/nr-arena-group.h b/src/display/nr-arena-group.h index 4579d068f..58394643c 100644 --- a/src/display/nr-arena-group.h +++ b/src/display/nr-arena-group.h @@ -26,7 +26,7 @@ struct NRArenaGroup : public NRArenaItem{ unsigned int transparent : 1; NRArenaItem *children; NRArenaItem *last; - Geom::Matrix child_transform; + Geom::Affine child_transform; SPStyle *style; static NRArenaGroup *create(NRArena *arena) { @@ -42,8 +42,8 @@ struct NRArenaGroupClass { void nr_arena_group_set_transparent(NRArenaGroup *group, unsigned int transparent); -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Matrix const &t); -void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Matrix const *t); +void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const &t); +void nr_arena_group_set_child_transform(NRArenaGroup *group, Geom::Affine const *t); void nr_arena_group_set_style(NRArenaGroup *group, SPStyle *style); #endif diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp index 9913fd08a..321d72ec1 100644 --- a/src/display/nr-arena-image.cpp +++ b/src/display/nr-arena-image.cpp @@ -163,7 +163,7 @@ nr_arena_image_render( cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock cairo_set_source_surface(ct, image->surface, 0, 0); cairo_matrix_t tt; - Geom::Matrix total; + Geom::Affine total; cairo_get_matrix(ct, &tt); ink_matrix_to_2geom(total, tt); diff --git a/src/display/nr-arena-image.h b/src/display/nr-arena-image.h index aaf7a5d59..6fa9223dd 100644 --- a/src/display/nr-arena-image.h +++ b/src/display/nr-arena-image.h @@ -28,7 +28,7 @@ struct NRArenaImage : public NRArenaItem { GdkPixbuf *pixbuf; cairo_surface_t *surface; - Geom::Matrix ctm; + Geom::Affine ctm; Geom::Rect clipbox; double ox, oy; double sx, sy; diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index a2a959415..8787c1033 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -329,7 +329,6 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); bool filter = (item->arena->rendermode != Inkscape::RENDERMODE_OUTLINE && item->arena->rendermode != Inkscape::RENDERMODE_NO_FILTERS); - //bool print_colors = (item->arena->rendermode == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW); nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), @@ -634,14 +633,14 @@ nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child) } void -nr_arena_item_set_transform (NRArenaItem *item, Geom::Matrix const &transform) +nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const &transform) { - Geom::Matrix const t (transform); + Geom::Affine const t (transform); nr_arena_item_set_transform (item, &t); } void -nr_arena_item_set_transform (NRArenaItem *item, Geom::Matrix const *transform) +nr_arena_item_set_transform (NRArenaItem *item, Geom::Affine const *transform) { nr_return_if_fail (item != NULL); nr_return_if_fail (NR_IS_ARENA_ITEM (item)); @@ -649,8 +648,8 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Matrix const *transform) if (!transform && !item->transform) return; - const Geom::Matrix *md = (item->transform) ? item->transform : &GEOM_MATRIX_IDENTITY; - const Geom::Matrix *ms = (transform) ? transform : &GEOM_MATRIX_IDENTITY; + const Geom::Affine *md = (item->transform) ? item->transform : &GEOM_MATRIX_IDENTITY; + const Geom::Affine *ms = (transform) ? transform : &GEOM_MATRIX_IDENTITY; if (!Geom::matrix_equalp(*md, *ms, NR_EPSILON)) { nr_arena_item_request_render (item); @@ -659,7 +658,7 @@ nr_arena_item_set_transform (NRArenaItem *item, Geom::Matrix const *transform) item->transform = NULL; } else { if (!item->transform) - item->transform = new (GC::ATOMIC) Geom::Matrix (); + item->transform = new (GC::ATOMIC) Geom::Affine (); *item->transform = *transform; } nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE); diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index 1497987ba..0fc4cbe48 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -14,7 +14,7 @@ #define SEEN_DISPLAY_NR_ARENA_ITEM_H #include <cairo.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "libnr/nr-rect-l.h" #include "libnr/nr-object.h" #include "gc-soft-ptr.h" @@ -67,7 +67,7 @@ class Filter; struct NRGC { NRGC(NRGC const *p) : parent(p) {} NRGC const *parent; - Geom::Matrix transform; + Geom::Affine transform; }; struct NRArenaItem : public NRObject { @@ -93,8 +93,8 @@ struct NRArenaItem : public NRObject { NRRectL bbox; ///< Bounding box in pixel grid coordinates; (0,0) is at page origin NRRectL drawbox; ///< Bounding box enlarged by filters, shrinked by clips and masks Geom::OptRect item_bbox; ///< Bounding box in item coordinates, required by filters - Geom::Matrix *transform; ///< Incremental transform of this item, as given by the transform= attribute - Geom::Matrix ctm; ///< Total transform from pixel grid to item coords + Geom::Affine *transform; ///< Incremental transform of this item, as given by the transform= attribute + Geom::Affine ctm; ///< Total transform from pixel grid to item coords NRArenaItem *clip; ///< Clipping path NRArenaItem *mask; ///< Mask Inkscape::Filters::Filter *filter; ///< Filter @@ -161,8 +161,8 @@ NRArenaItem *nr_arena_item_unparent (NRArenaItem *item); void nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child); -void nr_arena_item_set_transform(NRArenaItem *item, Geom::Matrix const &transform); -void nr_arena_item_set_transform(NRArenaItem *item, Geom::Matrix const *transform); +void nr_arena_item_set_transform(NRArenaItem *item, Geom::Affine const &transform); +void nr_arena_item_set_transform(NRArenaItem *item, Geom::Affine const *transform); void nr_arena_item_set_opacity (NRArenaItem *item, double opacity); void nr_arena_item_set_sensitive (NRArenaItem *item, unsigned int sensitive); void nr_arena_item_set_visible (NRArenaItem *item, unsigned int visible); diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index c687d3ca5..227b49526 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -1,5 +1,3 @@ -#define __NR_ARENA_SHAPE_C__ - /* * RGBA display list system for inkscape * @@ -13,8 +11,8 @@ */ #include <cairo.h> -#include <fenv.h> #include <glib.h> +#include <fenv.h> #include <typeinfo> #include <2geom/curves.h> @@ -348,7 +346,6 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock } bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - //bool print_colors_preview = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW); if (outline) { // cairo outline rendering diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index 1f7bd2591..43edb6918 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -57,6 +57,7 @@ nr_arena_init (NRArena *arena) arena->delta = 0; // to be set by desktop from prefs arena->renderoffscreen = false; // use render values from preferences otherwise render exact arena->rendermode = Inkscape::RENDERMODE_NORMAL; // default is normal render + arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; // default is normal color arena->blurquality = BLUR_QUALITY_NORMAL; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_NORMAL; arena->outlinecolor = 0xff; // black; to be set by desktop from bg color @@ -87,6 +88,7 @@ nr_arena_request_update (NRArena *arena, NRArenaItem *item) arena->blurquality = BLUR_QUALITY_BEST; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; arena->rendermode = Inkscape::RENDERMODE_NORMAL; + arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; } if (aobject->callbacks) { @@ -118,6 +120,7 @@ nr_arena_request_render_rect (NRArena *arena, NRRectL *area) arena->blurquality = BLUR_QUALITY_BEST; arena->filterquality = Inkscape::Filters::FILTER_QUALITY_BEST; arena->rendermode = Inkscape::RENDERMODE_NORMAL; + arena->colorrendermode = Inkscape::COLORRENDERMODE_NORMAL; } if (aobject->callbacks && area && !nr_rect_l_test_empty_ptr(area)) { for (unsigned int i = 0; i < aobject->callbacks->length; i++) { diff --git a/src/display/nr-arena.h b/src/display/nr-arena.h index f4d86a2e6..4d33aaa99 100644 --- a/src/display/nr-arena.h +++ b/src/display/nr-arena.h @@ -48,6 +48,7 @@ struct NRArena : public NRActiveObject { double delta; bool renderoffscreen; // if true then rendering must be exact Inkscape::RenderMode rendermode; + Inkscape::ColorRenderMode colorrendermode; int blurquality; // will be updated during update from preferences int filterquality; // will be updated during update from preferences diff --git a/src/display/nr-filter-blend.cpp b/src/display/nr-filter-blend.cpp index b5343d1d6..3cec479fa 100644 --- a/src/display/nr-filter-blend.cpp +++ b/src/display/nr-filter-blend.cpp @@ -190,7 +190,7 @@ void FilterBlend::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -bool FilterBlend::can_handle_affine(Geom::Matrix const &) +bool FilterBlend::can_handle_affine(Geom::Affine const &) { // blend is a per-pixel primitive and is immutable under transformations return true; diff --git a/src/display/nr-filter-blend.h b/src/display/nr-filter-blend.h index 0a2ba64d4..64b3c9284 100644 --- a/src/display/nr-filter-blend.h +++ b/src/display/nr-filter-blend.h @@ -38,7 +38,7 @@ public: virtual ~FilterBlend(); virtual void render_cairo(FilterSlot &slot); - virtual bool can_handle_affine(Geom::Matrix const &); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_input(int slot); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-colormatrix.cpp b/src/display/nr-filter-colormatrix.cpp index 1c2e3d85a..5f308da6a 100644 --- a/src/display/nr-filter-colormatrix.cpp +++ b/src/display/nr-filter-colormatrix.cpp @@ -182,12 +182,12 @@ void FilterColorMatrix::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -bool FilterColorMatrix::can_handle_affine(Geom::Matrix const &) +bool FilterColorMatrix::can_handle_affine(Geom::Affine const &) { return true; } -void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/) +void FilterColorMatrix::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) { } diff --git a/src/display/nr-filter-colormatrix.h b/src/display/nr-filter-colormatrix.h index 8e9b8a990..df851e0aa 100644 --- a/src/display/nr-filter-colormatrix.h +++ b/src/display/nr-filter-colormatrix.h @@ -36,9 +36,9 @@ public: virtual ~FilterColorMatrix(); virtual void render_cairo(FilterSlot &slot); - virtual bool can_handle_affine(Geom::Matrix const &); + virtual bool can_handle_affine(Geom::Affine const &); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); virtual void set_type(FilterColorMatrixType type); virtual void set_value(gdouble value); virtual void set_values(std::vector<gdouble> const &values); diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp index 83f240307..80bc07df8 100644 --- a/src/display/nr-filter-component-transfer.cpp +++ b/src/display/nr-filter-component-transfer.cpp @@ -299,12 +299,12 @@ void FilterComponentTransfer::render_cairo(FilterSlot &slot) //cairo_surface_destroy(outtemp); } -bool FilterComponentTransfer::can_handle_affine(Geom::Matrix const &) +bool FilterComponentTransfer::can_handle_affine(Geom::Affine const &) { return true; } -void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/) +void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) { } diff --git a/src/display/nr-filter-component-transfer.h b/src/display/nr-filter-component-transfer.h index b26aee917..89bc61403 100644 --- a/src/display/nr-filter-component-transfer.h +++ b/src/display/nr-filter-component-transfer.h @@ -36,8 +36,8 @@ public: virtual ~FilterComponentTransfer(); virtual void render_cairo(FilterSlot &slot); - virtual bool can_handle_affine(Geom::Matrix const &); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual bool can_handle_affine(Geom::Affine const &); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); FilterComponentTransferType type[4]; std::vector<gdouble> tableValues[4]; diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp index 68700f792..d4cf47af4 100644 --- a/src/display/nr-filter-composite.cpp +++ b/src/display/nr-filter-composite.cpp @@ -101,7 +101,7 @@ void FilterComposite::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -bool FilterComposite::can_handle_affine(Geom::Matrix const &) +bool FilterComposite::can_handle_affine(Geom::Affine const &) { return true; } diff --git a/src/display/nr-filter-composite.h b/src/display/nr-filter-composite.h index 828eb55b3..930898830 100644 --- a/src/display/nr-filter-composite.h +++ b/src/display/nr-filter-composite.h @@ -27,7 +27,7 @@ public: virtual ~FilterComposite(); virtual void render_cairo(FilterSlot &); - virtual bool can_handle_affine(Geom::Matrix const &); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp index 0a5ba16b0..06e28b074 100644 --- a/src/display/nr-filter-convolve-matrix.cpp +++ b/src/display/nr-filter-convolve-matrix.cpp @@ -202,7 +202,7 @@ void FilterConvolveMatrix::set_preserveAlpha(bool pa){ preserveAlpha = pa; } -void FilterConvolveMatrix::area_enlarge(NRRectL &area, Geom::Matrix const &/*trans*/) +void FilterConvolveMatrix::area_enlarge(NRRectL &area, Geom::Affine const &/*trans*/) { //Seems to me that since this filter's operation is resolution dependent, // some spurious pixels may still appear at the borders when low zooming or rotating. Needs a better fix. diff --git a/src/display/nr-filter-convolve-matrix.h b/src/display/nr-filter-convolve-matrix.h index 4f314e4c3..d13738260 100644 --- a/src/display/nr-filter-convolve-matrix.h +++ b/src/display/nr-filter-convolve-matrix.h @@ -35,7 +35,7 @@ public: virtual ~FilterConvolveMatrix(); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); void set_targetY(int coord); void set_targetX(int coord); diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index cc14bb165..e2954c3b1 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -83,7 +83,7 @@ private: struct DiffusePointLight : public DiffuseLight { DiffusePointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, - Geom::Matrix const &trans, double scale, double diffuse_constant, double x0, double y0) + Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) : DiffuseLight(bumpmap, scale, diffuse_constant) , _light(light, color, trans) , _x0(x0) @@ -105,7 +105,7 @@ private: struct DiffuseSpotLight : public DiffuseLight { DiffuseSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, - Geom::Matrix const &trans, double scale, double diffuse_constant, double x0, double y0) + Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) : DiffuseLight(bumpmap, scale, diffuse_constant) , _light(light, color, trans) , _x0(x0) @@ -129,7 +129,7 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot) cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); NRRectL const &slot_area = slot.get_slot_area(); - Geom::Matrix trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); double x0 = slot_area.x0, y0 = slot_area.y0; double scale = surfaceScale * trans.descrim(); @@ -159,7 +159,7 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Matrix const &trans) +void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Affine const &trans) { // TODO: support kernelUnitLength diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h index 1c17e8fe8..100673749 100644 --- a/src/display/nr-filter-diffuselighting.h +++ b/src/display/nr-filter-diffuselighting.h @@ -32,7 +32,7 @@ public: static FilterPrimitive *create(); virtual ~FilterDiffuseLighting(); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); union { SPFeDistantLight *distant; diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index 74b1b1dab..fdaf2c887 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -196,7 +196,7 @@ void FilterDisplacementMap::render_cairo(FilterSlot &slot) cairo_surface_t *map = slot.getcairo(_input2); cairo_surface_t *out = ink_cairo_surface_create_identical(texture); - Geom::Matrix trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); double scalex = scale * trans.expansionX(); double scaley = scale * trans.expansionY(); @@ -249,7 +249,7 @@ int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) { bool map_premultiplied = (map->mode == NR_PIXBLOCK_MODE_R8G8B8A8P); bool data_premultiplied = (out->mode == NR_PIXBLOCK_MODE_R8G8B8A8P); - Geom::Matrix trans = units.get_matrix_primitiveunits2pb(); + Geom::Affine trans = units.get_matrix_primitiveunits2pb(); double scalex = scale * trans.expansionX(); double scaley = scale * trans.expansionY(); @@ -314,7 +314,7 @@ void FilterDisplacementMap::set_channel_selector(int s, FilterDisplacementMapCha if (s == 1) Ychannel = ch; } -void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Matrix const &trans) +void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Affine const &trans) { //I assume scale is in user coordinates (?!?) //FIXME: trans should be multiplied by some primitiveunits2user, shouldn't it? diff --git a/src/display/nr-filter-displacement-map.h b/src/display/nr-filter-displacement-map.h index 534fac620..aec4b7eb6 100644 --- a/src/display/nr-filter-displacement-map.h +++ b/src/display/nr-filter-displacement-map.h @@ -32,7 +32,7 @@ public: virtual void set_scale(double s); virtual void set_channel_selector(int s, FilterDisplacementMapChannelSelector channel); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); private: double scale; diff --git a/src/display/nr-filter-flood.cpp b/src/display/nr-filter-flood.cpp index 4e3952f9a..a015d3f1f 100644 --- a/src/display/nr-filter-flood.cpp +++ b/src/display/nr-filter-flood.cpp @@ -3,8 +3,9 @@ * * Authors: * Felipe CorrĂȘa da Silva Sanches <juca@members.fsf.org> + * Tavmjong Bah <tavmjong@free.fr> (use primitive filter region) * - * Copyright (C) 2007 authors + * Copyright (C) 2007, 2011 authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -63,7 +64,7 @@ void FilterFlood::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -bool FilterFlood::can_handle_affine(Geom::Matrix const &) +bool FilterFlood::can_handle_affine(Geom::Affine const &) { // flood is a per-pixel primitive and is immutable under transformations return true; @@ -81,7 +82,7 @@ void FilterFlood::set_icc(SVGICCColor *icc_color) { icc = icc_color; } -void FilterFlood::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/) +void FilterFlood::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) { } diff --git a/src/display/nr-filter-flood.h b/src/display/nr-filter-flood.h index 78b48302f..6db90d439 100644 --- a/src/display/nr-filter-flood.h +++ b/src/display/nr-filter-flood.h @@ -26,11 +26,11 @@ public: virtual ~FilterFlood(); virtual void render_cairo(FilterSlot &slot); - virtual bool can_handle_affine(Geom::Matrix const &); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_opacity(double o); virtual void set_color(guint32 c); virtual void set_icc(SVGICCColor *icc_color); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); private: double opacity; guint32 color; diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 9bd9723cd..fdffabfeb 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -33,7 +33,7 @@ #include "display/nr-filter-types.h" #include "display/nr-filter-units.h" #include "display/nr-filter-slot.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "util/fixed_point.h" #include "preferences.h" @@ -78,15 +78,46 @@ template<typename T> static inline T clip(T const& v, T const& a, T const& b) { } template<typename Tt, typename Ts> -static inline Tt round_cast(Ts const& v) { +static inline Tt round_cast(Ts v) { static Ts const rndoffset(.5); return static_cast<Tt>(v+rndoffset); } +template<> +inline unsigned char round_cast(double v) { + // This (fast) rounding method is based on: + // http://stereopsis.com/sree/fpu2006.html +#if G_BYTE_ORDER==G_LITTLE_ENDIAN + double const dmr = 6755399441055744.0; + v = v + dmr; + return ((unsigned char*)&v)[0]; +#elif G_BYTE_ORDER==G_BIG_ENDIAN + double const dmr = 6755399441055744.0; + v = v + dmr; + return ((unsigned char*)&v)[7]; +#else + static double const rndoffset(.5); + return static_cast<unsigned char>(v+rndoffset); +#endif +} + +template<typename Tt, typename Ts> +static inline Tt clip_round_cast(Ts const v) { + Ts const minval = std::numeric_limits<Tt>::min(); + Ts const maxval = std::numeric_limits<Tt>::max(); + Tt const minval_rounded = std::numeric_limits<Tt>::min(); + Ts const maxval_rounded = std::numeric_limits<Tt>::max(); + if ( v < minval ) return minval_rounded; + if ( v > maxval ) return maxval_rounded; + return round_cast<Tt>(v); +} + template<typename Tt, typename Ts> -static inline Tt clip_round_cast(Ts const& v, Tt const minval=std::numeric_limits<Tt>::min(), Tt const maxval=std::numeric_limits<Tt>::max()) { - if ( v < minval ) return minval; - if ( v > maxval ) return maxval; +static inline Tt clip_round_cast_varmax(Ts const v, Ts const maxval, Tt const maxval_rounded) { + Ts const minval = std::numeric_limits<Tt>::min(); + Tt const minval_rounded = std::numeric_limits<Tt>::min(); + if ( v < minval ) return minval_rounded; + if ( v > maxval ) return maxval_rounded; return round_cast<Tt>(v); } @@ -313,7 +344,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2, dstimg -= dstr1; if ( PREMULTIPLIED_ALPHA ) { dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]); - PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast<PT>(v[0][c], std::numeric_limits<PT>::min(), dstimg[alpha_PC]); + PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][alpha_PC], dstimg[alpha_PC]); } else { for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]); } @@ -328,7 +359,7 @@ filter2D_IIR(PT *const dest, int const dstr1, int const dstr2, dstimg -= dstr1; if ( PREMULTIPLIED_ALPHA ) { dstimg[alpha_PC] = clip_round_cast<PT>(v[0][alpha_PC]); - PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast<PT>(v[0][c], std::numeric_limits<PT>::min(), dstimg[alpha_PC]); + PREMUL_ALPHA_LOOP dstimg[c] = clip_round_cast_varmax<PT>(v[0][c], v[0][alpha_PC], dstimg[alpha_PC]); } else { for(unsigned int c=0; c<PC; c++) dstimg[c] = clip_round_cast<PT>(v[0][c]); } @@ -534,7 +565,7 @@ void FilterGaussian::render_cairo(FilterSlot &slot) return; } - Geom::Matrix trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); int w_orig = ink_cairo_surface_get_width(in); int h_orig = ink_cairo_surface_get_height(in); @@ -635,7 +666,7 @@ void FilterGaussian::render_cairo(FilterSlot &slot) } } -void FilterGaussian::area_enlarge(NRRectL &area, Geom::Matrix const &trans) +void FilterGaussian::area_enlarge(NRRectL &area, Geom::Affine const &trans) { int area_x = _effect_area_scr(_deviation_x * trans.expansionX()); int area_y = _effect_area_scr(_deviation_y * trans.expansionY()); @@ -648,7 +679,7 @@ void FilterGaussian::area_enlarge(NRRectL &area, Geom::Matrix const &trans) area.y1 += area_max; } -bool FilterGaussian::can_handle_affine(Geom::Matrix const &) +bool FilterGaussian::can_handle_affine(Geom::Affine const &) { // Previously we tried to be smart and return true for rotations. // However, the transform passed here is NOT the total transform diff --git a/src/display/nr-filter-gaussian.h b/src/display/nr-filter-gaussian.h index cf3881ee3..811502016 100644 --- a/src/display/nr-filter-gaussian.h +++ b/src/display/nr-filter-gaussian.h @@ -35,8 +35,8 @@ public: virtual ~FilterGaussian(); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &m); - virtual bool can_handle_affine(Geom::Matrix const &m); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &m); + virtual bool can_handle_affine(Geom::Affine const &m); /** * Set the standard deviation value for gaussian blur. Deviation along diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index ca361e007..eea4f9781 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -6,7 +6,7 @@ * Tavmjong Bah <tavmjong@free.fr> * Abhishek Sharma * - * Copyright (C) 2007 authors + * Copyright (C) 2007-2011 authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -48,7 +48,7 @@ void FilterImage::render_cairo(FilterSlot &slot) //cairo_surface_t *input = slot.getcairo(_input); - Geom::Matrix m = slot.get_units().get_matrix_user2filterunits().inverse(); + Geom::Affine m = slot.get_units().get_matrix_user2filterunits().inverse(); Geom::Point bbox_00 = Geom::Point(0,0) * m; Geom::Point bbox_w0 = Geom::Point(1,0) * m; Geom::Point bbox_0h = Geom::Point(0,1) * m; @@ -86,7 +86,7 @@ void FilterImage::render_cairo(FilterSlot &slot) } Geom::Rect area = *optarea; - Geom::Matrix pu2pb = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Affine pu2pb = slot.get_units().get_matrix_primitiveunits2pb(); double scaleX = feImageWidth / area.width(); double scaleY = feImageHeight / area.height(); @@ -109,7 +109,7 @@ void FilterImage::render_cairo(FilterSlot &slot) // Update to renderable state NRGC gc(NULL); - Geom::Matrix t = Geom::identity(); + Geom::Affine t = Geom::identity(); nr_arena_item_set_transform(ai, &t); gc.transform.setIdentity(); nr_arena_item_invoke_update(ai, NULL, &gc, @@ -189,6 +189,8 @@ void FilterImage::render_cairo(FilterSlot &slot) ink_cairo_transform(ct, slot.get_units().get_matrix_primitiveunits2pb()); // now ct is in the coordinates of feImageX etc. + // TODO: add preserveAspectRatio support here + double scaleX = feImageWidth / image->get_width(); double scaleY = feImageHeight / image->get_height(); @@ -201,7 +203,7 @@ void FilterImage::render_cairo(FilterSlot &slot) slot.set(_output, out); } -bool FilterImage::can_handle_affine(Geom::Matrix const &) +bool FilterImage::can_handle_affine(Geom::Affine const &) { return true; } @@ -221,13 +223,21 @@ void FilterImage::set_document(SPDocument *doc){ document = doc; } -void FilterImage::set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height){ +void FilterImage::set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height) { feImageX=x.computed; feImageY=y.computed; feImageWidth=width.computed; feImageHeight=height.computed; } +void FilterImage::set_align( unsigned int align ) { + aspect_align = align; +} + +void FilterImage::set_clip( unsigned int clip ) { + aspect_clip = clip; +} + } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-image.h b/src/display/nr-filter-image.h index bd5cd525c..0651109ec 100644 --- a/src/display/nr-filter-image.h +++ b/src/display/nr-filter-image.h @@ -28,10 +28,12 @@ public: virtual ~FilterImage(); virtual void render_cairo(FilterSlot &slot); - virtual bool can_handle_affine(Geom::Matrix const &); + virtual bool can_handle_affine(Geom::Affine const &); void set_document( SPDocument *document ); void set_href(const gchar *href); void set_region(SVGLength x, SVGLength y, SVGLength width, SVGLength height); + void set_align( unsigned int align ); + void set_clip( unsigned int clip ); bool from_element; SPItem* SVGElem; @@ -40,7 +42,8 @@ private: gchar *feImageHref; Glib::RefPtr<Gdk::Pixbuf> image; cairo_surface_t *image_surface; - float feImageX,feImageY,feImageWidth,feImageHeight; + float feImageX, feImageY, feImageWidth, feImageHeight; + unsigned int aspect_align, aspect_clip; bool broken_ref; }; diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp index 2129d7894..51d3975cb 100644 --- a/src/display/nr-filter-merge.cpp +++ b/src/display/nr-filter-merge.cpp @@ -61,7 +61,7 @@ void FilterMerge::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -bool FilterMerge::can_handle_affine(Geom::Matrix const &) +bool FilterMerge::can_handle_affine(Geom::Affine const &) { // Merge is a per-pixel primitive and is immutable under transformations return true; diff --git a/src/display/nr-filter-merge.h b/src/display/nr-filter-merge.h index 9c4204f07..263fc8026 100644 --- a/src/display/nr-filter-merge.h +++ b/src/display/nr-filter-merge.h @@ -25,7 +25,7 @@ public: virtual ~FilterMerge(); virtual void render_cairo(FilterSlot &); - virtual bool can_handle_affine(Geom::Matrix const &); + virtual bool can_handle_affine(Geom::Affine const &); virtual void set_input(int input); virtual void set_input(int input, int slot); diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp index 9d3682fd6..c79667d3e 100644 --- a/src/display/nr-filter-morphology.cpp +++ b/src/display/nr-filter-morphology.cpp @@ -121,7 +121,7 @@ void FilterMorphology::render_cairo(FilterSlot &slot) return; } - Geom::Matrix p2pb = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Affine p2pb = slot.get_units().get_matrix_primitiveunits2pb(); double xr = xradius * p2pb.expansionX(); double yr = yradius * p2pb.expansionY(); @@ -147,7 +147,7 @@ void FilterMorphology::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -void FilterMorphology::area_enlarge(NRRectL &area, Geom::Matrix const &trans) +void FilterMorphology::area_enlarge(NRRectL &area, Geom::Affine const &trans) { int enlarge_x = ceil(xradius * trans.expansionX()); int enlarge_y = ceil(yradius * trans.expansionY()); diff --git a/src/display/nr-filter-morphology.h b/src/display/nr-filter-morphology.h index 48f43d61f..5924085d9 100644 --- a/src/display/nr-filter-morphology.h +++ b/src/display/nr-filter-morphology.h @@ -32,7 +32,7 @@ public: virtual ~FilterMorphology(); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); void set_operator(FilterMorphologyOperator &o); void set_xradius(double x); void set_yradius(double y); diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp index 7b70398db..3b0f83841 100644 --- a/src/display/nr-filter-offset.cpp +++ b/src/display/nr-filter-offset.cpp @@ -38,7 +38,7 @@ void FilterOffset::render_cairo(FilterSlot &slot) cairo_surface_t *out = ink_cairo_surface_create_identical(in); cairo_t *ct = cairo_create(out); - Geom::Matrix trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); Geom::Point offset(dx, dy); offset *= trans; offset[X] -= trans[4]; @@ -52,7 +52,7 @@ void FilterOffset::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -bool FilterOffset::can_handle_affine(Geom::Matrix const &) +bool FilterOffset::can_handle_affine(Geom::Affine const &) { return true; } @@ -65,7 +65,7 @@ void FilterOffset::set_dy(double amount) { dy = amount; } -void FilterOffset::area_enlarge(NRRectL &area, Geom::Matrix const &trans) +void FilterOffset::area_enlarge(NRRectL &area, Geom::Affine const &trans) { Geom::Point offset(dx, dy); offset *= trans; diff --git a/src/display/nr-filter-offset.h b/src/display/nr-filter-offset.h index 4a9e96789..09c57f803 100644 --- a/src/display/nr-filter-offset.h +++ b/src/display/nr-filter-offset.h @@ -27,8 +27,8 @@ public: virtual ~FilterOffset(); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); - virtual bool can_handle_affine(Geom::Matrix const &); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); + virtual bool can_handle_affine(Geom::Affine const &); void set_dx(double amount); void set_dy(double amount); diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index 2926b4960..b544d6df0 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -5,6 +5,7 @@ * * Author: * Niko Kiirala <niko@kiirala.com> + * Tavmjong Bah <tavmjong@free.fr> (primitive subregion) * * Copyright (C) 2006 Niko Kiirala * @@ -19,17 +20,27 @@ namespace Inkscape { namespace Filters { +using Geom::X; +using Geom::Y; + FilterPrimitive::FilterPrimitive() { _input = NR_FILTER_SLOT_NOT_SET; _output = NR_FILTER_SLOT_NOT_SET; - // These defaults are according to SVG standard. + // Primitive subregion, should default to the union of all subregions of referenced nodes + // (i.e. other filter primitives except feTile). If no referenced nodes, defaults to filter + // region expressed in percent. At the moment, we do not check referenced nodes. + + // We must keep track if a value is set or not, if not set then the region defaults to 0%, 0%, + // 100%, 100% ("x", "y", "width", "height") of the -> filter <- region. If set, then + // percentages are in terms of bounding box or viewbox, depending on value of "primitiveUnits". + // NB: SVGLength.set takes prescaled percent values: 1 means 100% - _region_x.set(SVGLength::PERCENT, 0, 0); - _region_y.set(SVGLength::PERCENT, 0, 0); - _region_width.set(SVGLength::PERCENT, 1, 0); - _region_height.set(SVGLength::PERCENT, 1, 0); + _subregion_x.unset(SVGLength::PERCENT, 0, 0); + _subregion_y.unset(SVGLength::PERCENT, 0, 0); + _subregion_width.unset(SVGLength::PERCENT, 1, 0); + _subregion_height.unset(SVGLength::PERCENT, 1, 0); } FilterPrimitive::~FilterPrimitive() @@ -44,7 +55,7 @@ void FilterPrimitive::render_cairo(FilterSlot &slot) slot.set(_output, in); } -void FilterPrimitive::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*m*/) +void FilterPrimitive::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*m*/) { // This doesn't need to do anything by default } @@ -61,6 +72,97 @@ void FilterPrimitive::set_output(int slot) { if (slot >= 0) _output = slot; } +// We need to copy reference even if unset as we need to know if +// someone has unset a value. +void FilterPrimitive::set_x(SVGLength const &length) +{ + _subregion_x = length; +} + +void FilterPrimitive::set_y(SVGLength const &length) +{ + _subregion_y = length; +} +void FilterPrimitive::set_width(SVGLength const &length) +{ + _subregion_width = length; +} +void FilterPrimitive::set_height(SVGLength const &length) +{ + _subregion_height = length; +} + +void FilterPrimitive::set_subregion(SVGLength const &x, SVGLength const &y, + SVGLength const &width, SVGLength const &height) { + _subregion_x = x; + _subregion_y = y; + _subregion_width = width; + _subregion_height = height; +} + +Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) +{ + Geom::OptRect bb = units.get_item_bbox(); + Geom::OptRect fa = units.get_filter_area(); + + /* Update computed values for ex, em, %. For %, assumes primitive unit is objectBoundingBox. */ + /* TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values. */ + double len_x = bb->width(); + double len_y = bb->height(); + _subregion_x.update(12, 6, len_x); + _subregion_y.update(12, 6, len_y); + _subregion_width.update(12, 6, len_x); + _subregion_height.update(12, 6, len_y); + + // x, y, width, and height are independently defined (i.e. one can be defined, by default, to + // the filter area while another is defined relative to the bounding box). It is better to keep + // track of them separately and then compose the Rect at the end. + double x = 0; + double y = 0; + double width = 0; + double height = 0; + + // If subregion not set, by special case use filter region. + if( !_subregion_x._set ) x = fa->min()[X]; + if( !_subregion_y._set ) y = fa->min()[Y]; + if( !_subregion_width._set ) width = fa->width(); + if( !_subregion_height._set ) height = fa->height(); + + if( units.get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) { + // Values are in terms of fraction of bounding box. + if( _subregion_x._set && _subregion_x.unit != SVGLength::PERCENT ) x = bb->min()[X] + bb->width() * _subregion_x.value; + if( _subregion_y._set && _subregion_y.unit != SVGLength::PERCENT ) y = bb->min()[Y] + bb->height() * _subregion_y.value; + if( _subregion_width._set && _subregion_width.unit != SVGLength::PERCENT ) width = bb->width() * _subregion_width.value; + if( _subregion_height._set && _subregion_height.unit != SVGLength::PERCENT ) height = bb->height() * _subregion_height.value; + // Values are in terms of percent + if( _subregion_x._set && _subregion_x.unit == SVGLength::PERCENT ) x = bb->min()[X] + _subregion_x.computed; + if( _subregion_y._set && _subregion_y.unit == SVGLength::PERCENT ) y = bb->min()[Y] + _subregion_y.computed; + if( _subregion_width._set && _subregion_width.unit == SVGLength::PERCENT ) width = _subregion_width.computed; + if( _subregion_height._set && _subregion_height.unit == SVGLength::PERCENT ) height = _subregion_height.computed; + } else { + // Values are in terms of user space coordinates or percent of viewbox (yuck!), + // which is usually the size of SVG drawing. Default. + if( _subregion_x._set && _subregion_x.unit != SVGLength::PERCENT ) x = _subregion_x.computed; + if( _subregion_y._set && _subregion_y.unit != SVGLength::PERCENT ) y = _subregion_y.computed; + if( _subregion_width._set && _subregion_width.unit != SVGLength::PERCENT ) width = _subregion_width.computed; + if( _subregion_height._set && _subregion_height.unit != SVGLength::PERCENT ) height = _subregion_height.computed; + // TODO: add percent of viewport TEMPORARY HACK FOR TESTING... + if( _subregion_x._set && _subregion_x.unit == SVGLength::PERCENT ) x = _subregion_x.value * 480; // viewport_x + if( _subregion_y._set && _subregion_y.unit == SVGLength::PERCENT ) y = _subregion_y.value * 360; + if( _subregion_width._set && _subregion_width.unit == SVGLength::PERCENT ) width = _subregion_width.value * 480; + if( _subregion_height._set && _subregion_height.unit == SVGLength::PERCENT ) height = _subregion_height.value * 360; + } + + Geom::Point minp, maxp; + minp[X] = x; + minp[Y] = y; + maxp[X] = x + width; + maxp[Y] = y + height; + + Geom::Rect area(minp, maxp); + return area; +} + FilterTraits FilterPrimitive::get_input_traits() { return TRAIT_ANYTHING; } diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h index 06badffa6..dd7363d76 100644 --- a/src/display/nr-filter-primitive.h +++ b/src/display/nr-filter-primitive.h @@ -47,7 +47,7 @@ public: virtual void render_cairo(FilterSlot &slot); virtual int render(FilterSlot &slot, FilterUnits const &units) { return 0; } - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &m); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &m); /** * Sets the input slot number 'slot' to be used as input in rendering @@ -81,27 +81,27 @@ public: */ virtual void set_output(int slot); - void set_x(SVGLength &length); - void set_y(SVGLength &length); - void set_width(SVGLength &length); - void set_height(SVGLength &length); - /** * Sets the filter primitive subregion. Passing an unset length - * (length._set == false) as any parameter results in that parameter - * not being changed. - * Filter primitive will not hold any references to the passed - * SVGLength object after function returns. - * If any of the parameters does not get set the default value, as - * defined in SVG standard, for that parameter is used instead. + * (length._set == false) WILL change the parameter as it is + * important to know if a parameter is unset. */ - void set_region(SVGLength &x, SVGLength &y, - SVGLength &width, SVGLength &height); + void set_x(SVGLength const &length); + void set_y(SVGLength const &length); + void set_width(SVGLength const &length); + void set_height(SVGLength const &length); + void set_subregion(SVGLength const &x, SVGLength const &y, + SVGLength const &width, SVGLength const &height); /** * Resets the filter primitive subregion to its default value */ - void reset_region(); + void reset_subregion(); // Not implemented + + /** + * Returns the filter primitive area in user coordinate system. + */ + Geom::Rect filter_primitive_area(FilterUnits const &units); /** * Queries the filter, which traits it needs from its input buffers. @@ -123,16 +123,17 @@ public: * the matrices from FilterUnits will contain at most a (possibly non-uniform) scale * and a translation. When all primitives of the filter return false, the rendering is * performed in display coordinate space and no intermediate surface is used. */ - virtual bool can_handle_affine(Geom::Matrix const &) { return false; } + virtual bool can_handle_affine(Geom::Affine const &) { return false; } protected: int _input; int _output; - SVGLength _region_x; - SVGLength _region_y; - SVGLength _region_width; - SVGLength _region_height; + /* Filter primitive subregion */ + SVGLength _subregion_x; + SVGLength _subregion_y; + SVGLength _subregion_width; + SVGLength _subregion_height; }; diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index dafab20c8..63f9dc1a6 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -45,7 +45,7 @@ FilterSlot::FilterSlot(NRArenaItem *item, cairo_t *bgct, NRRectL const *bgarea, Geom::Point(_source_graphic_area->x0, _source_graphic_area->y0), Geom::Point(_source_graphic_area->x1, _source_graphic_area->y1)); - Geom::Matrix trans = _units.get_matrix_display2pb(); + Geom::Affine trans = _units.get_matrix_display2pb(); Geom::Rect bbox_trans = bbox * trans; Geom::Point min = bbox_trans.min(); @@ -125,7 +125,7 @@ cairo_surface_t *FilterSlot::getcairo(int slot_nr) cairo_surface_t *FilterSlot::_get_transformed_source_graphic() { - Geom::Matrix trans = _units.get_matrix_display2pb(); + Geom::Affine trans = _units.get_matrix_display2pb(); if (trans.isIdentity()) { cairo_surface_reference(_source_graphic); @@ -150,7 +150,7 @@ cairo_surface_t *FilterSlot::_get_transformed_source_graphic() cairo_surface_t *FilterSlot::_get_transformed_background() { - Geom::Matrix trans = _units.get_matrix_display2pb(); + Geom::Affine trans = _units.get_matrix_display2pb(); cairo_surface_t *bg = cairo_get_target(_background_ct); cairo_surface_t *tbg = cairo_surface_create_similar( @@ -171,7 +171,7 @@ cairo_surface_t *FilterSlot::_get_transformed_background() cairo_surface_t *FilterSlot::get_result(int res) { - Geom::Matrix trans = _units.get_matrix_pb2display(); + Geom::Affine trans = _units.get_matrix_pb2display(); if (trans.isIdentity()) { cairo_surface_t *result = getcairo(res); cairo_surface_reference(result); diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp index 97936d86a..e9e3f2b28 100644 --- a/src/display/nr-filter-specularlighting.cpp +++ b/src/display/nr-filter-specularlighting.cpp @@ -91,7 +91,7 @@ private: struct SpecularPointLight : public SpecularLight { SpecularPointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, - Geom::Matrix const &trans, double scale, double specular_constant, + Geom::Affine const &trans, double scale, double specular_constant, double specular_exponent, double x0, double y0) : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) , _light(light, color, trans) @@ -115,7 +115,7 @@ private: struct SpecularSpotLight : public SpecularLight { SpecularSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, - Geom::Matrix const &trans, double scale, double specular_constant, + Geom::Affine const &trans, double scale, double specular_constant, double specular_exponent, double x0, double y0) : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) , _light(light, color, trans) @@ -141,7 +141,7 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot) cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); NRRectL const &slot_area = slot.get_slot_area(); - Geom::Matrix trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); double x0 = slot_area.x0, y0 = slot_area.y0; double scale = surfaceScale * trans.descrim(); double ks = specularConstant; @@ -195,7 +195,7 @@ int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) { int dx = 1; //TODO setup int dy = 1; //TODO setup //surface scale - Geom::Matrix trans = units.get_matrix_primitiveunits2pb(); + Geom::Affine trans = units.get_matrix_primitiveunits2pb(); gdouble ss = surfaceScale * trans[0]; gdouble ks = specularConstant; //diffuse lighting constant NR::Fvector L, N, LC, H; @@ -303,7 +303,7 @@ int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) { return 0; }*/ -void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Matrix const &trans) +void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Affine const &trans) { // TODO: support kernelUnitLength diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h index 8d6252c69..155496a41 100644 --- a/src/display/nr-filter-specularlighting.h +++ b/src/display/nr-filter-specularlighting.h @@ -32,7 +32,7 @@ public: static FilterPrimitive *create(); virtual ~FilterSpecularLighting(); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); union { SPFeDistantLight *distant; diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp index 739ee2c5e..b88386638 100644 --- a/src/display/nr-filter-tile.cpp +++ b/src/display/nr-filter-tile.cpp @@ -41,7 +41,7 @@ void FilterTile::render_cairo(FilterSlot &slot) slot.set(_output, in); } -void FilterTile::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/) +void FilterTile::area_enlarge(NRRectL &/*area*/, Geom::Affine const &/*trans*/) { } diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h index e0eacddcf..5c0a3e553 100644 --- a/src/display/nr-filter-tile.h +++ b/src/display/nr-filter-tile.h @@ -26,7 +26,7 @@ public: virtual ~FilterTile(); virtual void render_cairo(FilterSlot &slot); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + virtual void area_enlarge(NRRectL &area, Geom::Affine const &trans); }; } /* namespace Filters */ diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index 7beebab68..c1a3abd45 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -346,7 +346,7 @@ void FilterTurbulence::set_updated(bool u){ } struct Turbulence { - Turbulence(TurbulenceGenerator const &gen, Geom::Matrix const &trans, int x0, int y0) + Turbulence(TurbulenceGenerator const &gen, Geom::Affine const &trans, int x0, int y0) : _gen(gen) , _trans(trans) , _x0(x0), _y0(y0) @@ -358,7 +358,7 @@ struct Turbulence { } private: TurbulenceGenerator const &_gen; - Geom::Matrix _trans; + Geom::Affine _trans; int _x0, _y0; }; @@ -375,8 +375,7 @@ void FilterTurbulence::render_cairo(FilterSlot &slot) type == TURBULENCE_FRACTALNOISE, numOctaves); } - // TODO: convert this to ink_cairo_surface_synthesize - Geom::Matrix unit_trans = slot.get_units().get_matrix_primitiveunits2pb().inverse(); + Geom::Affine unit_trans = slot.get_units().get_matrix_primitiveunits2pb().inverse(); NRRectL const &slot_area = slot.get_slot_area(); ink_cairo_surface_synthesize(out, Turbulence(*gen, unit_trans, slot_area.x0, slot_area.y0)); diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp index 4cf165800..b1c475c41 100644 --- a/src/display/nr-filter-units.cpp +++ b/src/display/nr-filter-units.cpp @@ -35,7 +35,7 @@ FilterUnits::FilterUnits(SPFilterUnits const filterUnits, SPFilterUnits const pr paraller_axis(false), automatic_resolution(true) {} -void FilterUnits::set_ctm(Geom::Matrix const &ctm) { +void FilterUnits::set_ctm(Geom::Affine const &ctm) { this->ctm = ctm; } @@ -63,12 +63,12 @@ void FilterUnits::set_automatic_resolution(bool const automatic) { automatic_resolution = automatic; } -Geom::Matrix FilterUnits::get_matrix_user2pb() const { +Geom::Affine FilterUnits::get_matrix_user2pb() const { g_assert(resolution_x > 0); g_assert(resolution_y > 0); g_assert(filter_area); - Geom::Matrix u2pb = ctm; + Geom::Affine u2pb = ctm; if (paraller_axis || !automatic_resolution) { u2pb[0] = resolution_x / (filter_area->max()[X] - filter_area->min()[X]); @@ -82,9 +82,9 @@ Geom::Matrix FilterUnits::get_matrix_user2pb() const { return u2pb; } -Geom::Matrix FilterUnits::get_matrix_units2pb(SPFilterUnits units) const { +Geom::Affine FilterUnits::get_matrix_units2pb(SPFilterUnits units) const { if ( item_bbox && (units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) ) { - Geom::Matrix u2pb = get_matrix_user2pb(); + Geom::Affine u2pb = get_matrix_user2pb(); Geom::Point origo(item_bbox->min()); origo *= u2pb; Geom::Point i_end(item_bbox->max()[X], item_bbox->min()[Y]); @@ -106,31 +106,31 @@ Geom::Matrix FilterUnits::get_matrix_units2pb(SPFilterUnits units) const { return get_matrix_user2pb(); } else { g_warning("Error in Inkscape::Filters::FilterUnits::get_matrix_units2pb: unrecognized unit type (%d)", units); - return Geom::Matrix(); + return Geom::Affine(); } } -Geom::Matrix FilterUnits::get_matrix_filterunits2pb() const { +Geom::Affine FilterUnits::get_matrix_filterunits2pb() const { return get_matrix_units2pb(filterUnits); } -Geom::Matrix FilterUnits::get_matrix_primitiveunits2pb() const { +Geom::Affine FilterUnits::get_matrix_primitiveunits2pb() const { return get_matrix_units2pb(primitiveUnits); } -Geom::Matrix FilterUnits::get_matrix_display2pb() const { - Geom::Matrix d2pb = ctm.inverse(); +Geom::Affine FilterUnits::get_matrix_display2pb() const { + Geom::Affine d2pb = ctm.inverse(); d2pb *= get_matrix_user2pb(); return d2pb; } -Geom::Matrix FilterUnits::get_matrix_pb2display() const { - Geom::Matrix pb2d = get_matrix_user2pb().inverse(); +Geom::Affine FilterUnits::get_matrix_pb2display() const { + Geom::Affine pb2d = get_matrix_user2pb().inverse(); pb2d *= ctm; return pb2d; } -Geom::Matrix FilterUnits::get_matrix_user2units(SPFilterUnits units) const { +Geom::Affine FilterUnits::get_matrix_user2units(SPFilterUnits units) const { if (item_bbox && units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) { /* No need to worry about rotations: bounding box coordinates * always have base vectors paraller with userspace coordinates */ @@ -139,22 +139,22 @@ Geom::Matrix FilterUnits::get_matrix_user2units(SPFilterUnits units) const { double scale_x = 1.0 / (max[X] - min[X]); double scale_y = 1.0 / (max[Y] - min[Y]); //return Geom::Translate(min) * Geom::Scale(scale_x,scale_y); ? - return Geom::Matrix(scale_x, 0, + return Geom::Affine(scale_x, 0, 0, scale_y, min[X] * scale_x, min[Y] * scale_y); } else if (units == SP_FILTER_UNITS_USERSPACEONUSE) { return Geom::identity(); } else { g_warning("Error in Inkscape::Filters::FilterUnits::get_matrix_user2units: unrecognized unit type (%d)", units); - return Geom::Matrix(); + return Geom::Affine(); } } -Geom::Matrix FilterUnits::get_matrix_user2filterunits() const { +Geom::Affine FilterUnits::get_matrix_user2filterunits() const { return get_matrix_user2units(filterUnits); } -Geom::Matrix FilterUnits::get_matrix_user2primitiveunits() const { +Geom::Affine FilterUnits::get_matrix_user2primitiveunits() const { return get_matrix_user2units(primitiveUnits); } @@ -162,7 +162,7 @@ NR::IRect FilterUnits::get_pixblock_filterarea_paraller() const { g_assert(filter_area); int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN; - Geom::Matrix u2pb = get_matrix_user2pb(); + Geom::Affine u2pb = get_matrix_user2pb(); for (int i = 0 ; i < 4 ; i++) { Geom::Point p = filter_area->corner(i); diff --git a/src/display/nr-filter-units.h b/src/display/nr-filter-units.h index 7ef6190fc..2fc3e5533 100644 --- a/src/display/nr-filter-units.h +++ b/src/display/nr-filter-units.h @@ -14,7 +14,7 @@ #include "sp-filter-units.h" #include "libnr/nr-rect-l.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/rect.h> namespace Inkscape { @@ -41,7 +41,7 @@ public: * Sets the current transformation matrix, i.e. transformation matrix * from object's user coordinates to screen coordinates */ - void set_ctm(Geom::Matrix const &ctm); + void set_ctm(Geom::Affine const &ctm); /** * Sets the resolution, the filter should be rendered with. @@ -72,41 +72,61 @@ public: void set_automatic_resolution(bool const automatic); /** + * Gets the item bounding box in user coordinates + */ + Geom::OptRect get_item_bbox() const { return item_bbox; }; + + /** + * Gets the filter effects area in user coordinates + */ + Geom::OptRect get_filter_area() const { return filter_area; }; + + /** + * Gets Filter Units (userSpaceOnUse or objectBoundingBox) + */ + SPFilterUnits get_filter_units() const { return filterUnits; }; + + /** + * Gets Primitive Units (userSpaceOnUse or objectBoundingBox) + */ + SPFilterUnits get_primitive_units() const { return primitiveUnits; }; + + /** * Gets the user coordinates to pixblock coordinates transformation matrix. */ - Geom::Matrix get_matrix_user2pb() const; + Geom::Affine get_matrix_user2pb() const; /** * Gets the filterUnits to pixblock coordinates transformation matrix. */ - Geom::Matrix get_matrix_filterunits2pb() const; + Geom::Affine get_matrix_filterunits2pb() const; /** * Gets the primitiveUnits to pixblock coordinates transformation matrix. */ - Geom::Matrix get_matrix_primitiveunits2pb() const; + Geom::Affine get_matrix_primitiveunits2pb() const; /** * Gets the display coordinates to pixblock coordinates transformation * matrix. */ - Geom::Matrix get_matrix_display2pb() const; + Geom::Affine get_matrix_display2pb() const; /** * Gets the pixblock coordinates to display coordinates transformation * matrix */ - Geom::Matrix get_matrix_pb2display() const; + Geom::Affine get_matrix_pb2display() const; /** * Gets the user coordinates to filterUnits transformation matrix. */ - Geom::Matrix get_matrix_user2filterunits() const; + Geom::Affine get_matrix_user2filterunits() const; /** * Gets the user coordinates to primitiveUnits transformation matrix. */ - Geom::Matrix get_matrix_user2primitiveunits() const; + Geom::Affine get_matrix_user2primitiveunits() const; /** * Returns the filter area in pixblock coordinates. @@ -118,14 +138,14 @@ public: FilterUnits& operator=(FilterUnits const &other); private: - Geom::Matrix get_matrix_units2pb(SPFilterUnits units) const; - Geom::Matrix get_matrix_user2units(SPFilterUnits units) const; + Geom::Affine get_matrix_units2pb(SPFilterUnits units) const; + Geom::Affine get_matrix_user2units(SPFilterUnits units) const; SPFilterUnits filterUnits, primitiveUnits; double resolution_x, resolution_y; bool paraller_axis; bool automatic_resolution; - Geom::Matrix ctm; + Geom::Affine ctm; Geom::OptRect item_bbox; Geom::OptRect filter_area; diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 5e8419ef4..55190b00c 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -42,7 +42,7 @@ #include "display/nr-arena.h" #include "display/nr-arena-item.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/rect.h> #include "svg/svg-length.h" #include "sp-filter-units.h" @@ -112,7 +112,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea FilterQuality const filterquality = (FilterQuality)item->arena->filterquality; int const blurquality = item->arena->blurquality; - Geom::Matrix trans = item->ctm; + Geom::Affine trans = item->ctm; Geom::Rect item_bbox; { @@ -154,7 +154,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea } units.set_paraller(false); - Geom::Matrix pbtrans = units.get_matrix_display2pb(); + Geom::Affine pbtrans = units.get_matrix_display2pb(); for (unsigned i = 0 ; i < _primitive.size() ; i++) { if (!_primitive[i]->can_handle_affine(pbtrans)) { units.set_paraller(true); @@ -283,7 +283,7 @@ Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) minp[Y] = _region_y.computed; maxp[Y] = minp[Y] + _region_height.computed; } else { - g_warning("Error in Inkscape::Filters::Filter::bbox_enlarge: unrecognized value of _filter_units"); + g_warning("Error in Inkscape::Filters::Filter::filter_effect_area: unrecognized value of _filter_units"); } Geom::Rect area(minp, maxp); return area; @@ -432,7 +432,7 @@ int Filter::_resolution_limit(FilterQuality const quality) const { } std::pair<double,double> Filter::_filter_resolution( - Geom::Rect const &area, Geom::Matrix const &trans, + Geom::Rect const &area, Geom::Affine const &trans, FilterQuality const filterquality) const { std::pair<double,double> resolution; diff --git a/src/display/nr-filter.h b/src/display/nr-filter.h index ac434b402..e1d4c10e5 100644 --- a/src/display/nr-filter.h +++ b/src/display/nr-filter.h @@ -96,8 +96,8 @@ public: * If any of these parameters does not get set, the default value, as * defined in SVG standard, for that parameter is used instead. */ - void set_region(SVGLength &x, SVGLength &y, - SVGLength &width, SVGLength &height); + void set_region(SVGLength const &x, SVGLength const &y, + SVGLength const &width, SVGLength const &height); /** * Resets the filter effects region to its default value as defined @@ -135,7 +135,7 @@ public: void set_filter_units(SPFilterUnits unit); /** - * Set the primitiveUnits-properterty. If not set, the default value of + * Set the primitiveUnits-property. If not set, the default value of * userSpaceOnUse is used. If the parameter value is not a valid * enumeration value from SPFilterUnits, no changes to filter state * are made. @@ -201,7 +201,7 @@ private: void _common_init(); int _resolution_limit(FilterQuality const quality) const; std::pair<double,double> _filter_resolution(Geom::Rect const &area, - Geom::Matrix const &trans, + Geom::Affine const &trans, FilterQuality const q) const; }; diff --git a/src/display/nr-light.cpp b/src/display/nr-light.cpp index 0c801d736..65912470d 100644 --- a/src/display/nr-light.cpp +++ b/src/display/nr-light.cpp @@ -43,7 +43,7 @@ void DistantLight::light_components(NR::Fvector &lc) { lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } -PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Matrix &trans) { +PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans) { color = lighting_color; l_x = light->x; l_y = light->y; @@ -66,7 +66,7 @@ void PointLight::light_components(NR::Fvector &lc) { lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } -SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Matrix &trans) { +SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans) { gdouble p_x, p_y, p_z; color = lighting_color; l_x = light->x; diff --git a/src/display/nr-light.h b/src/display/nr-light.h index 65c341a7e..49130cc4e 100644 --- a/src/display/nr-light.h +++ b/src/display/nr-light.h @@ -68,7 +68,7 @@ class PointLight { * employed in the sp light object) and current coordinate (those * employed in the rendering) */ - PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Matrix &trans); + PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans); virtual ~PointLight(); /** * Computes the light vector of the distant light at point (x,y,z). @@ -108,7 +108,7 @@ class SpotLight { * employed in the sp light object) and current coordinate (those * employed in the rendering) */ - SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Matrix &trans); + SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans); virtual ~SpotLight(); /** diff --git a/src/display/nr-svgfonts.cpp b/src/display/nr-svgfonts.cpp index f3207cf18..b33835f64 100644 --- a/src/display/nr-svgfonts.cpp +++ b/src/display/nr-svgfonts.cpp @@ -253,7 +253,7 @@ SvgFont::scaled_font_render_glyph (cairo_scaled_font_t */*scaled_font*/, // Geom::Scale s(1.0/((SPFont*) node->parent)->horiz_adv_x); Geom::Scale s(1.0/1000);//TODO: use here the units-per-em attribute? //This matrix flips the glyph vertically - Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); + Geom::Affine m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); //then we offset it // pathv += Geom::Point(Geom::Coord(0),Geom::Coord(-((SPFont*) node->parent)->horiz_adv_x)); pathv += Geom::Point(Geom::Coord(0),Geom::Coord(-1000));//TODO: use here the units-per-em attribute? diff --git a/src/display/rendermode.h b/src/display/rendermode.h index abcdb3db4..8fc022bfb 100644 --- a/src/display/rendermode.h +++ b/src/display/rendermode.h @@ -12,8 +12,13 @@ namespace Inkscape { enum RenderMode { RENDERMODE_NORMAL, RENDERMODE_NO_FILTERS, - RENDERMODE_OUTLINE, - RENDERMODE_PRINT_COLORS_PREVIEW + RENDERMODE_OUTLINE +}; + +enum ColorRenderMode { + COLORRENDERMODE_NORMAL, + COLORRENDERMODE_GRAYSCALE, + COLORRENDERMODE_PRINT_COLORS_PREVIEW }; } diff --git a/src/display/snap-indicator.h b/src/display/snap-indicator.h index 5475f9f60..d60ff1481 100644 --- a/src/display/snap-indicator.h +++ b/src/display/snap-indicator.h @@ -15,12 +15,13 @@ */ #include "forward.h" -#include "display/display-forward.h" #include "snapped-point.h" namespace Inkscape { namespace Display { +class TemporaryItem; + class SnapIndicator { public: SnapIndicator(SPDesktop *desktop); diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index ce4df98c6..a165fd52e 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -10,7 +10,6 @@ #include <2geom/transforms.h> #include "sp-canvas-util.h" -#include "display-forward.h" #include "sodipodi-ctrl.h" #include "display/cairo-utils.h" @@ -33,7 +32,7 @@ static void sp_ctrl_init (SPCtrl *ctrl); static void sp_ctrl_destroy (GtkObject *object); static void sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); -static void sp_ctrl_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_ctrl_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf); static double sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); @@ -217,7 +216,7 @@ sp_ctrl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) } static void -sp_ctrl_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_ctrl_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCtrl *ctrl; gint x, y; @@ -544,7 +543,7 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) void SPCtrl::moveto (Geom::Point const p) { if (p != _point) { - sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (this), Geom::Matrix(Geom::Translate (p))); + sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (this), Geom::Affine(Geom::Translate (p))); _moved = true; } _point = p; diff --git a/src/display/sodipodi-ctrl.h b/src/display/sodipodi-ctrl.h index f9deffd56..27728296a 100644 --- a/src/display/sodipodi-ctrl.h +++ b/src/display/sodipodi-ctrl.h @@ -8,10 +8,9 @@ */ #include <gtk/gtkenums.h> -#include "sp-canvas.h" #include <gdk-pixbuf/gdk-pixbuf.h> #include <libnr/nr-rect-l.h> - +#include "sp-canvas-item.h" #define SP_TYPE_CTRL (sp_ctrl_get_type ()) @@ -35,7 +34,7 @@ typedef enum { SP_CTRL_MODE_XOR } SPCtrlModeType; -struct SPCtrl : public SPCanvasItem{ +struct SPCtrl : public SPCanvasItem { SPCtrlShapeType shape; SPCtrlModeType mode; GtkAnchorType anchor; diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp index 504a1bc92..592d45bc0 100644 --- a/src/display/sodipodi-ctrlrect.cpp +++ b/src/display/sodipodi-ctrlrect.cpp @@ -15,7 +15,6 @@ * */ -#include "display-forward.h" #include "sp-canvas-util.h" #include "sodipodi-ctrlrect.h" #include "display/cairo-utils.h" @@ -31,7 +30,7 @@ static void sp_ctrlrect_class_init(SPCtrlRectClass *c); static void sp_ctrlrect_init(CtrlRect *ctrlrect); static void sp_ctrlrect_destroy(GtkObject *object); -static void sp_ctrlrect_update(SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_ctrlrect_update(SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_ctrlrect_render(SPCanvasItem *item, SPCanvasBuf *buf); static SPCanvasItemClass *parent_class; @@ -162,7 +161,7 @@ static void sp_ctrlrect_render(SPCanvasItem *item, SPCanvasBuf *buf) } -static void sp_ctrlrect_update(SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +static void sp_ctrlrect_update(SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SP_CTRLRECT(item)->update(affine, flags); } @@ -248,7 +247,7 @@ void CtrlRect::render(SPCanvasBuf *buf) } -void CtrlRect::update(Geom::Matrix const &affine, unsigned int flags) +void CtrlRect::update(Geom::Affine const &affine, unsigned int flags) { if (((SPCanvasItemClass *) parent_class)->update) { ((SPCanvasItemClass *) parent_class)->update(this, affine, flags); diff --git a/src/display/sodipodi-ctrlrect.h b/src/display/sodipodi-ctrlrect.h index 70dcf1f30..2ba73a4c9 100644 --- a/src/display/sodipodi-ctrlrect.h +++ b/src/display/sodipodi-ctrlrect.h @@ -1,5 +1,5 @@ -#ifndef __INKSCAPE_CTRLRECT_H__ -#define __INKSCAPE_CTRLRECT_H__ +#ifndef SEEN_INKSCAPE_CTRLRECT_H +#define SEEN_INKSCAPE_CTRLRECT_H /** * \file sodipodi-ctrlrect.h @@ -17,7 +17,10 @@ */ #include <glib/gtypes.h> -#include "sp-canvas.h" +#include "sp-canvas-item.h" +#include "libnr/nr-rect-l.h" + +struct SPCanvasBuf; #define SP_TYPE_CTRLRECT (sp_ctrlrect_get_type ()) #define SP_CTRLRECT(obj) (GTK_CHECK_CAST((obj), SP_TYPE_CTRLRECT, CtrlRect)) @@ -36,7 +39,7 @@ public: void setDashed(bool d); void render(SPCanvasBuf *buf); - void update(Geom::Matrix const &affine, unsigned int flags); + void update(Geom::Affine const &affine, unsigned int flags); private: void _requestUpdate(); @@ -56,7 +59,7 @@ struct SPCtrlRectClass : public SPCanvasItemClass {}; GtkType sp_ctrlrect_get_type(); -#endif +#endif // SEEN_RUBBERBAND_H /* Local Variables: diff --git a/src/display/sp-canvas-group.h b/src/display/sp-canvas-group.h new file mode 100644 index 000000000..10bf0fa6c --- /dev/null +++ b/src/display/sp-canvas-group.h @@ -0,0 +1,45 @@ +#ifndef SEEN_SP_CANVAS_GROUP_H +#define SEEN_SP_CANVAS_GROUP_H + +/** \file + * SPCanvasGroup + * + * Authors: + * Federico Mena <federico@nuclecu.unam.mx> + * Raph Levien <raph@gimp.org> + * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 1998 The Free Software Foundation + * Copyright (C) 2002 Lauris Kaplinski + * Copyright (C) 2010 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glib-object.h> + +#define SP_TYPE_CANVAS_GROUP (sp_canvas_group_get_type()) +#define SP_CANVAS_GROUP(obj) (GTK_CHECK_CAST((obj), SP_TYPE_CANVAS_GROUP, SPCanvasGroup)) +#define SP_IS_CANVAS_GROUP(obj) (GTK_CHECK_TYPE((obj), SP_TYPE_CANVAS_GROUP)) + +GType sp_canvas_group_get_type(); + + + +#endif // SEEN_SP_CANVAS_GROUP_H + +/* + 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 : diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h new file mode 100644 index 000000000..cc0bdfc77 --- /dev/null +++ b/src/display/sp-canvas-item.h @@ -0,0 +1,110 @@ +#ifndef SEEN_SP_CANVAS_ITEM_H +#define SEEN_SP_CANVAS_ITEM_H + +/** \file + * SPCanvasItem. + * + * Authors: + * Federico Mena <federico@nuclecu.unam.mx> + * Raph Levien <raph@gimp.org> + * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 1998 The Free Software Foundation + * Copyright (C) 2002 Lauris Kaplinski + * Copyright (C) 2010 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glib-object.h> +#include <gtk/gtkobject.h> +#include <gdk/gdkevents.h> + +#include "2geom/rect.h" + +G_BEGIN_DECLS + +struct SPCanvas; +struct SPCanvasBuf; +struct SPCanvasGroup; + +typedef struct _SPCanvasItemClass SPCanvasItemClass; + +#define SP_TYPE_CANVAS_ITEM (sp_canvas_item_get_type()) +#define SP_CANVAS_ITEM(obj) (GTK_CHECK_CAST((obj), SP_TYPE_CANVAS_ITEM, SPCanvasItem)) +#define SP_IS_CANVAS_ITEM(obj) (GTK_CHECK_TYPE((obj), SP_TYPE_CANVAS_ITEM)) +#define SP_CANVAS_ITEM_GET_CLASS(o) (GTK_CHECK_GET_CLASS((o), SP_TYPE_CANVAS_ITEM, SPCanvasItemClass)) + +GType sp_canvas_item_get_type(); + +/** + * An SPCanvasItem refers to a SPCanvas and to its parent item; it has + * four coordinates, a bounding rectangle, and a transformation matrix. + */ +struct SPCanvasItem : public GtkObject { + SPCanvas *canvas; + SPCanvasItem *parent; + + double x1, y1, x2, y2; + Geom::Rect bounds; + Geom::Affine xform; +}; + +/** + * The vtable of an SPCanvasItem. + */ +struct _SPCanvasItemClass : public GtkObjectClass { + void (* update) (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); + + void (* render) (SPCanvasItem *item, SPCanvasBuf *buf); + double (* point) (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); + + int (* event) (SPCanvasItem *item, GdkEvent *event); +}; + +SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GtkType type, const gchar *first_arg_name, ...); + +G_END_DECLS + + +#define sp_canvas_item_set gtk_object_set + +void sp_canvas_item_affine_absolute(SPCanvasItem *item, Geom::Affine const &aff); + +void sp_canvas_item_raise(SPCanvasItem *item, int positions); +void sp_canvas_item_lower(SPCanvasItem *item, int positions); +bool sp_canvas_item_is_visible(SPCanvasItem *item); +void sp_canvas_item_show(SPCanvasItem *item); +void sp_canvas_item_hide(SPCanvasItem *item); +int sp_canvas_item_grab(SPCanvasItem *item, unsigned int event_mask, GdkCursor *cursor, guint32 etime); +void sp_canvas_item_ungrab(SPCanvasItem *item, guint32 etime); + +Geom::Affine sp_canvas_item_i2w_affine(SPCanvasItem const *item); + +void sp_canvas_item_grab_focus(SPCanvasItem *item); + +void sp_canvas_item_request_update(SPCanvasItem *item); + +/* get item z-order in parent group */ + +gint sp_canvas_item_order(SPCanvasItem * item); + + + +#endif // SEEN_SP_CANVAS_ITEM_H + +/* + 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 : diff --git a/src/display/sp-canvas-util.cpp b/src/display/sp-canvas-util.cpp index 23b92c35d..186609e49 100644 --- a/src/display/sp-canvas-util.cpp +++ b/src/display/sp-canvas-util.cpp @@ -13,10 +13,10 @@ */ -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "sp-canvas-util.h" -#include <string.h> /* for memset */ - +#include "sp-canvas-item.h" +#include "sp-canvas.h" void sp_canvas_update_bbox (SPCanvasItem *item, int x1, int y1, int x2, int y2) @@ -50,7 +50,7 @@ sp_canvas_prepare_buffer (SPCanvasBuf *buf) }*/ } -Geom::Matrix sp_canvas_item_i2p_affine (SPCanvasItem * item) +Geom::Affine sp_canvas_item_i2p_affine (SPCanvasItem * item) { g_assert (item != NULL); /* this may be overly zealous - it is * plausible that this gets called @@ -59,7 +59,7 @@ Geom::Matrix sp_canvas_item_i2p_affine (SPCanvasItem * item) return item->xform; } -Geom::Matrix sp_canvas_item_i2i_affine (SPCanvasItem * from, SPCanvasItem * to) +Geom::Affine sp_canvas_item_i2i_affine (SPCanvasItem * from, SPCanvasItem * to) { g_assert (from != NULL); g_assert (to != NULL); @@ -67,7 +67,7 @@ Geom::Matrix sp_canvas_item_i2i_affine (SPCanvasItem * from, SPCanvasItem * to) return sp_canvas_item_i2w_affine(from) * sp_canvas_item_i2w_affine(to).inverse(); } -void sp_canvas_item_set_i2w_affine (SPCanvasItem * item, Geom::Matrix const &i2w) +void sp_canvas_item_set_i2w_affine (SPCanvasItem * item, Geom::Affine const &i2w) { g_assert (item != NULL); diff --git a/src/display/sp-canvas-util.h b/src/display/sp-canvas-util.h index 82b85f1d8..41e085a5c 100644 --- a/src/display/sp-canvas-util.h +++ b/src/display/sp-canvas-util.h @@ -23,15 +23,15 @@ void sp_canvas_prepare_buffer (SPCanvasBuf *buf); /* get i2p (item to parent) affine transformation as general 6-element array */ -Geom::Matrix sp_canvas_item_i2p_affine (SPCanvasItem * item); +Geom::Affine sp_canvas_item_i2p_affine (SPCanvasItem * item); /* get i2i (item to item) affine transformation as general 6-element array */ -Geom::Matrix sp_canvas_item_i2i_affine (SPCanvasItem * from, SPCanvasItem * to); +Geom::Affine sp_canvas_item_i2i_affine (SPCanvasItem * from, SPCanvasItem * to); /* set item affine matrix to achieve given i2w matrix */ -void sp_canvas_item_set_i2w_affine (SPCanvasItem * item, Geom::Matrix const & aff); +void sp_canvas_item_set_i2w_affine (SPCanvasItem * item, Geom::Affine const & aff); void sp_canvas_item_move_to_z (SPCanvasItem * item, gint z); diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index d2fd2fa3d..43f33b74e 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1,5 +1,3 @@ -#define __SP_CANVAS_C__ - /** \file * Port of GnomeCanvas for Inkscape needs * @@ -28,9 +26,10 @@ #include "helper/sp-marshal.h" #include <helper/recthull.h> -#include <display/sp-canvas.h> #include "display-forward.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> +#include "display/sp-canvas.h" +#include "display/sp-canvas-group.h" #include "preferences.h" #include "inkscape.h" #include "sodipodi-ctrlrect.h" @@ -169,7 +168,7 @@ sp_canvas_item_init (SPCanvasItem *item) // that should be initially invisible; examples of such items: node handles, the CtrlRect // used for rubberbanding, path outline, etc. item->flags |= SP_CANVAS_ITEM_VISIBLE; - item->xform = Geom::Matrix(Geom::identity()); + item->xform = Geom::Affine(Geom::identity()); } /** @@ -282,10 +281,10 @@ sp_canvas_item_dispose (GObject *object) * NB! affine is parent2canvas. */ static void -sp_canvas_item_invoke_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_canvas_item_invoke_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { /* Apply the child item's transform */ - Geom::Matrix child_affine = item->xform * affine; + Geom::Affine child_affine = item->xform * affine; /* apply object flags to child flags */ int child_flags = flags & ~SP_CANVAS_UPDATE_REQUESTED; @@ -329,7 +328,7 @@ sp_canvas_item_invoke_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **a * @affine: An affine transformation matrix. */ void -sp_canvas_item_affine_absolute (SPCanvasItem *item, Geom::Matrix const &affine) +sp_canvas_item_affine_absolute (SPCanvasItem *item, Geom::Affine const &affine) { item->xform = affine; @@ -596,11 +595,11 @@ sp_canvas_item_ungrab (SPCanvasItem *item, guint32 etime) * Returns the product of all transformation matrices from the root item down * to the item. */ -Geom::Matrix sp_canvas_item_i2w_affine(SPCanvasItem const *item) +Geom::Affine sp_canvas_item_i2w_affine(SPCanvasItem const *item) { g_assert (SP_IS_CANVAS_ITEM (item)); // should we get this? - Geom::Matrix affine = Geom::identity(); + Geom::Affine affine = Geom::identity(); while (item) { affine *= item->xform; @@ -695,7 +694,7 @@ static void sp_canvas_group_class_init (SPCanvasGroupClass *klass); static void sp_canvas_group_init (SPCanvasGroup *group); static void sp_canvas_group_destroy (GtkObject *object); -static void sp_canvas_group_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_canvas_group_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static double sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); static void sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf); @@ -780,7 +779,7 @@ sp_canvas_group_destroy (GtkObject *object) * Update handler for canvas groups */ static void -sp_canvas_group_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_canvas_group_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCanvasGroup const *group = SP_CANVAS_GROUP (item); Geom::RectHull corners(Geom::Point(0, 0)); @@ -846,6 +845,12 @@ sp_canvas_group_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ } else has_point = FALSE; + // This metric should be improved, because in case of (partly) overlapping items we will now + // always select the last one that has been added to the group. We could instead select the one + // of which the center is the closest, for example. One can then move to the center + // of the item to be focused, and have that one selected. Of course this will only work if the + // centers are not coincident, but at least it's better than what we have now. + // See the extensive comment in Inkscape::SelTrans::_updateHandles() if (has_point && point_item && ((int) (dist + 0.5) <= item->canvas->close_enough)) { best = dist; *actual_item = point_item; diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 74476950f..53b8a61f1 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -2,7 +2,7 @@ #define SEEN_SP_CANVAS_H /** \file - * SPCanvas, SPCanvasBuf, and SPCanvasItem. + * SPCanvas, SPCanvasBuf. * * Authors: * Federico Mena <federico@nuclecu.unam.mx> @@ -35,16 +35,22 @@ #include <glibmm/ustring.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <libnr/nr-rect-l.h> #include <2geom/rect.h> G_BEGIN_DECLS +#define SP_TYPE_CANVAS sp_canvas_get_type() +#define SP_CANVAS(obj) (GTK_CHECK_CAST((obj), SP_TYPE_CANVAS, SPCanvas)) +#define SP_IS_CANVAS(obj) (GTK_CHECK_TYPE((obj), SP_TYPE_CANVAS)) + +GType sp_canvas_get_type(); + struct SPCanvas; +struct SPCanvasItem; struct SPCanvasGroup; -typedef struct _SPCanvasItemClass SPCanvasItemClass; enum { SP_CANVAS_UPDATE_REQUESTED = 1 << 0, @@ -64,58 +70,8 @@ struct SPCanvasBuf { bool is_empty; }; -/** - * An SPCanvasItem refers to a SPCanvas and to its parent item; it has - * four coordinates, a bounding rectangle, and a transformation matrix. - */ -struct SPCanvasItem : public GtkObject { - SPCanvas *canvas; - SPCanvasItem *parent; - - double x1, y1, x2, y2; - Geom::Rect bounds; - Geom::Matrix xform; -}; - -/** - * The vtable of an SPCanvasItem. - */ -struct _SPCanvasItemClass : public GtkObjectClass { - void (* update) (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); - - void (* render) (SPCanvasItem *item, SPCanvasBuf *buf); - double (* point) (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); - - int (* event) (SPCanvasItem *item, GdkEvent *event); -}; - -SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GtkType type, const gchar *first_arg_name, ...); - G_END_DECLS -#define sp_canvas_item_set gtk_object_set - -void sp_canvas_item_affine_absolute(SPCanvasItem *item, Geom::Matrix const &aff); - -void sp_canvas_item_raise(SPCanvasItem *item, int positions); -void sp_canvas_item_lower(SPCanvasItem *item, int positions); -bool sp_canvas_item_is_visible(SPCanvasItem *item); -void sp_canvas_item_show(SPCanvasItem *item); -void sp_canvas_item_hide(SPCanvasItem *item); -int sp_canvas_item_grab(SPCanvasItem *item, unsigned int event_mask, GdkCursor *cursor, guint32 etime); -void sp_canvas_item_ungrab(SPCanvasItem *item, guint32 etime); - -Geom::Matrix sp_canvas_item_i2w_affine(SPCanvasItem const *item); - -void sp_canvas_item_grab_focus(SPCanvasItem *item); - -void sp_canvas_item_request_update(SPCanvasItem *item); - -/* get item z-order in parent group */ - -gint sp_canvas_item_order(SPCanvasItem * item); - - // SPCanvas ------------------------------------------------- /** * Port of GnomeCanvas for inkscape needs. @@ -185,6 +141,7 @@ struct SPCanvas { bool drawing_disabled; int rendermode; + int colorrendermode; #if ENABLE_LCMS bool enable_cms_display_adj; diff --git a/src/display/sp-ctrlline.cpp b/src/display/sp-ctrlline.cpp index f5ea225cc..6c763abdf 100644 --- a/src/display/sp-ctrlline.cpp +++ b/src/display/sp-ctrlline.cpp @@ -34,7 +34,7 @@ static void sp_ctrlline_class_init (SPCtrlLineClass *klass); static void sp_ctrlline_init (SPCtrlLine *ctrlline); static void sp_ctrlline_destroy (GtkObject *object); -static void sp_ctrlline_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_ctrlline_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_ctrlline_render (SPCanvasItem *item, SPCanvasBuf *buf); static SPCanvasItemClass *parent_class; @@ -120,7 +120,7 @@ sp_ctrlline_render (SPCanvasItem *item, SPCanvasBuf *buf) } static void -sp_ctrlline_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_ctrlline_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCtrlLine *cl = SP_CTRLLINE (item); diff --git a/src/display/sp-ctrlline.h b/src/display/sp-ctrlline.h index 64497c464..e69c478fb 100644 --- a/src/display/sp-ctrlline.h +++ b/src/display/sp-ctrlline.h @@ -1,5 +1,5 @@ -#ifndef __INKSCAPE_CTRLLINE_H__ -#define __INKSCAPE_CTRLLINE_H__ +#ifndef SEEN_INKSCAPE_CTRLLINE_H +#define SEEN_INKSCAPE_CTRLLINE_H /* * Simple straight line @@ -14,7 +14,7 @@ * Released under GNU GPL */ -#include "sp-canvas.h" +#include "sp-canvas-item.h" struct SPItem; @@ -26,7 +26,7 @@ struct SPCtrlLine : public SPCanvasItem{ SPItem *item; // the item to which this line belongs in some sense; may be NULL for some users guint32 rgba; Geom::Point s, e; - Geom::Matrix affine; + Geom::Affine affine; }; struct SPCtrlLineClass : public SPCanvasItemClass{}; @@ -38,7 +38,7 @@ void sp_ctrlline_set_coords (SPCtrlLine *cl, const Geom::Point start, const Geom -#endif +#endif // SEEN_INKSCAPE_CTRLLINE_H /* Local Variables: diff --git a/src/display/sp-ctrlpoint.cpp b/src/display/sp-ctrlpoint.cpp index a5e93d07d..c33cdeeb9 100644 --- a/src/display/sp-ctrlpoint.cpp +++ b/src/display/sp-ctrlpoint.cpp @@ -11,7 +11,6 @@ * Released under GNU GPL */ -#include "display-forward.h" #include "sp-canvas-util.h" #include "sp-ctrlpoint.h" @@ -26,7 +25,7 @@ static void sp_ctrlpoint_class_init (SPCtrlPointClass *klass); static void sp_ctrlpoint_init (SPCtrlPoint *ctrlpoint); static void sp_ctrlpoint_destroy (GtkObject *object); -static void sp_ctrlpoint_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_ctrlpoint_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_ctrlpoint_render (SPCanvasItem *item, SPCanvasBuf *buf); static SPCanvasItemClass *parent_class; @@ -111,7 +110,7 @@ sp_ctrlpoint_render (SPCanvasItem *item, SPCanvasBuf *buf) } static void -sp_ctrlpoint_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_ctrlpoint_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCtrlPoint *cp = SP_CTRLPOINT (item); diff --git a/src/display/sp-ctrlpoint.h b/src/display/sp-ctrlpoint.h index d0e72f518..b98d48f67 100644 --- a/src/display/sp-ctrlpoint.h +++ b/src/display/sp-ctrlpoint.h @@ -1,5 +1,5 @@ -#ifndef __INKSCAPE_CTRLPOINT_H__ -#define __INKSCAPE_CTRLPOINT_H__ +#ifndef SEEN_INKSCAPE_CTRLPOINT_H +#define SEEN_INKSCAPE_CTRLPOINT_H /* * A simple point @@ -12,7 +12,7 @@ * Released under GNU GPL */ -#include "sp-canvas.h" +#include "sp-canvas-item.h" struct SPItem; @@ -20,11 +20,11 @@ struct SPItem; #define SP_CTRLPOINT(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_CTRLPOINT, SPCtrlPoint)) #define SP_IS_CTRLPOINT(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_CTRLPOINT)) -struct SPCtrlPoint : public SPCanvasItem{ +struct SPCtrlPoint : public SPCanvasItem { SPItem *item; // the item to which this line belongs in some sense; may be NULL for some users guint32 rgba; Geom::Point pt; - Geom::Matrix affine; + Geom::Affine affine; double radius; }; struct SPCtrlPointClass : public SPCanvasItemClass{}; @@ -38,7 +38,7 @@ void sp_ctrlpoint_set_radius (SPCtrlPoint *cp, const double r); -#endif +#endif // SEEN_INKSCAPE_CTRLPOINT_H /* Local Variables: diff --git a/src/display/sp-ctrlquadr.cpp b/src/display/sp-ctrlquadr.cpp index 7a577a088..0701d0b10 100644 --- a/src/display/sp-ctrlquadr.cpp +++ b/src/display/sp-ctrlquadr.cpp @@ -1,5 +1,3 @@ -#define __INKSCAPE_CTRLQUADR_C__ - /* * Quadrilateral * @@ -16,6 +14,8 @@ #endif #include "display-forward.h" +#include "sp-canvas-item.h" +#include "sp-canvas.h" #include "sp-canvas-util.h" #include "sp-ctrlquadr.h" #include "display/cairo-utils.h" @@ -24,7 +24,7 @@ struct SPCtrlQuadr : public SPCanvasItem{ guint32 rgba; Geom::Point p1, p2, p3, p4; - Geom::Matrix affine; + Geom::Affine affine; }; struct SPCtrlQuadrClass : public SPCanvasItemClass{}; @@ -33,7 +33,7 @@ static void sp_ctrlquadr_class_init (SPCtrlQuadrClass *klass); static void sp_ctrlquadr_init (SPCtrlQuadr *ctrlquadr); static void sp_ctrlquadr_destroy (GtkObject *object); -static void sp_ctrlquadr_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags); +static void sp_ctrlquadr_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static void sp_ctrlquadr_render (SPCanvasItem *item, SPCanvasBuf *buf); static SPCanvasItemClass *parent_class; @@ -139,7 +139,7 @@ sp_ctrlquadr_render (SPCanvasItem *item, SPCanvasBuf *buf) static void -sp_ctrlquadr_update (SPCanvasItem *item, Geom::Matrix const &affine, unsigned int flags) +sp_ctrlquadr_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) { SPCtrlQuadr *cq = SP_CTRLQUADR (item); diff --git a/src/document-private.h b/src/document-private.h index 61e6bad67..d641679ed 100644 --- a/src/document-private.h +++ b/src/document-private.h @@ -15,6 +15,7 @@ */ #include <map> +#include <stddef.h> #include <sigc++/sigc++.h> #include "xml/event-fns.h" #include "sp-defs.h" diff --git a/src/document-subset.h b/src/document-subset.h index ce7776da4..5f87e6429 100644 --- a/src/document-subset.h +++ b/src/document-subset.h @@ -10,6 +10,7 @@ #ifndef SEEN_INKSCAPE_DOCUMENT_SUBSET_H #define SEEN_INKSCAPE_DOCUMENT_SUBSET_H +#include <stddef.h> #include <sigc++/connection.h> #include <sigc++/functors/slot.h> diff --git a/src/document.cpp b/src/document.cpp index a473daa3c..c9b822ce6 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -267,7 +267,7 @@ unsigned long SPDocument::serial() const { void SPDocument::queueForOrphanCollection(SPObject *object) { g_return_if_fail(object != NULL); - g_return_if_fail(SP_OBJECT_DOCUMENT(object) == this); + g_return_if_fail(object->document == this); sp_object_ref(object, NULL); _collection_queue = g_slist_prepend(_collection_queue, object); @@ -550,7 +550,7 @@ void SPDocument::setWidth(gdouble width, const SPUnit *unit) root->viewBox.x1 = root->viewBox.x0 + (root->width.computed / old_computed) * (root->viewBox.x1 - root->viewBox.x0); } - SP_OBJECT (root)->updateRepr(); + root->updateRepr(); } void SPDocument::setHeight(gdouble height, const SPUnit *unit) @@ -576,7 +576,7 @@ void SPDocument::setHeight(gdouble height, const SPUnit *unit) root->viewBox.y1 = root->viewBox.y0 + (root->height.computed / old_computed) * (root->viewBox.y1 - root->viewBox.y0); } - SP_OBJECT (root)->updateRepr(); + root->updateRepr(); } gdouble SPDocument::getHeight() const @@ -632,9 +632,9 @@ void SPDocument::fitToRect(Geom::Rect const &rect, bool with_margins) margin_units = &px; } margin_top = nv->getMarginLength("fit-margin-top",margin_units, &px, w, h, false); - margin_top = nv->getMarginLength("fit-margin-left",margin_units, &px, w, h, true); - margin_top = nv->getMarginLength("fit-margin-right",margin_units, &px, w, h, true); - margin_top = nv->getMarginLength("fit-margin-bottom",margin_units, &px, w, h, false); + margin_left = nv->getMarginLength("fit-margin-left",margin_units, &px, w, h, true); + margin_right = nv->getMarginLength("fit-margin-right",margin_units, &px, w, h, true); + margin_bottom = nv->getMarginLength("fit-margin-bottom",margin_units, &px, w, h, false); } } @@ -848,7 +848,11 @@ SPObject *SPDocument::getObjectById(gchar const *id) const g_return_val_if_fail(id != NULL, NULL); GQuark idq = g_quark_from_string(id); - return (SPObject*)g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq)); + gpointer rv = g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq)); + if(rv != NULL) + return (SPObject*)rv; + else + return NULL; } sigc::connection SPDocument::connectIdChanged(gchar const *id, diff --git a/src/document.h b/src/document.h index 82c874cb7..2eb5e2e09 100644 --- a/src/document.h +++ b/src/document.h @@ -19,6 +19,7 @@ #include <glib-object.h> #include <gtk/gtksignal.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include <sigc++/class_slot.h> diff --git a/src/draw-context.cpp b/src/draw-context.cpp index 8ff056f96..4dd58afa7 100644 --- a/src/draw-context.cpp +++ b/src/draw-context.cpp @@ -301,7 +301,7 @@ spdc_check_for_and_apply_waiting_LPE(SPDrawContext *dc, SPItem *item) int shape = prefs->getInt(tool_name(dc) + "/shape", 0); bool shape_applied = false; - SPCSSAttr *css_item = sp_css_attr_from_object (SP_OBJECT(item), SP_STYLE_FLAG_ALWAYS); + SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS); const char *cstroke = sp_repr_css_property(css_item, "stroke", "none"); #define SHAPE_LENGTH 10 @@ -380,7 +380,7 @@ spdc_check_for_and_apply_waiting_LPE(SPDrawContext *dc, SPItem *item) sp_repr_css_set_property (css, "fill", cstroke); } sp_repr_css_set_property (css, "stroke", "none"); - sp_desktop_apply_css_recursive(SP_OBJECT(item), css, true); + sp_desktop_apply_css_recursive(item, css, true); sp_repr_css_attr_unref(css); return; } @@ -654,7 +654,7 @@ spdc_flush_white(SPDrawContext *dc, SPCurve *gc) bool has_lpe = false; Inkscape::XML::Node *repr; if (dc->white_item) { - repr = SP_OBJECT_REPR(dc->white_item); + repr = dc->white_item->getRepr(); has_lpe = sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(dc->white_item)); } else { repr = xml_doc->createElement("svg:path"); @@ -821,7 +821,7 @@ void spdc_create_single_dot(SPEventContext *ec, Geom::Point const &pt, char cons current stroke width, multiplied by the amount specified in the preferences */ Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); Geom::Point pp = pt; double rad = 0.5 * prefs->getDouble(tool_path + "/dot-size", 3.0); if (event_state & GDK_MOD1_MASK) { diff --git a/src/draw-context.h b/src/draw-context.h index 1364b5dad..3cad8da06 100644 --- a/src/draw-context.h +++ b/src/draw-context.h @@ -14,10 +14,10 @@ * Released under GNU GPL */ +#include <stddef.h> #include <sigc++/sigc++.h> #include "event-context.h" #include <forward.h> -#include <display/display-forward.h> #include <libnr/nr-point.h> #include "live_effects/effect.h" diff --git a/src/dropper-context.cpp b/src/dropper-context.cpp index 69bd8c971..e30d6b1e8 100644 --- a/src/dropper-context.cpp +++ b/src/dropper-context.cpp @@ -216,9 +216,9 @@ static gint sp_dropper_context_root_handler(SPEventContext *event_context, GdkEv } Geom::Point const cd = desktop->w2d(dc->centre); - Geom::Matrix const w2dt = desktop->w2d(); + Geom::Affine const w2dt = desktop->w2d(); const double scale = rw * w2dt.descrim(); - Geom::Matrix const sm( Geom::Scale(scale, scale) * Geom::Translate(cd) ); + Geom::Affine const sm( Geom::Scale(scale, scale) * Geom::Translate(cd) ); sp_canvas_item_affine_absolute(dc->area, sm); sp_canvas_item_show(dc->area); diff --git a/src/dropper-context.h b/src/dropper-context.h index 6f8b60b34..f2d18a507 100644 --- a/src/dropper-context.h +++ b/src/dropper-context.h @@ -12,7 +12,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/display-forward.h" #include "event-context.h" #define SP_TYPE_DROPPER_CONTEXT (sp_dropper_context_get_type ()) diff --git a/src/dyna-draw-context.cpp b/src/dyna-draw-context.cpp index c675cd8f7..aa7d840bc 100644 --- a/src/dyna-draw-context.cpp +++ b/src/dyna-draw-context.cpp @@ -59,6 +59,7 @@ #include "sp-shape.h" #include "sp-path.h" #include "sp-text.h" +#include "display/sp-canvas.h" #include "display/canvas-bpath.h" #include "display/canvas-arena.h" #include "livarot/Shape.h" @@ -583,7 +584,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, Geom::Point hatch_unit_vector(0,0); Geom::Point nearest(0,0); Geom::Point pointer(0,0); - Geom::Matrix motion_to_curve(Geom::identity()); + Geom::Affine motion_to_curve(Geom::identity()); if (event->motion.state & GDK_CONTROL_MASK) { // hatching - sense the item @@ -780,21 +781,21 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, if (dc->hatch_spacing == 0 && hatch_dist != 0) { // Haven't set spacing yet: gray, center free, update radius live Geom::Point c = desktop->w2d(motion_w); - Geom::Matrix const sm (Geom::Scale(hatch_dist, hatch_dist) * Geom::Translate(c)); + Geom::Affine const sm (Geom::Scale(hatch_dist, hatch_dist) * Geom::Translate(c)); sp_canvas_item_affine_absolute(dc->hatch_area, sm); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); sp_canvas_item_show(dc->hatch_area); } else if (dc->dragging && !dc->hatch_escaped) { // Tracking: green, center snapped, fixed radius Geom::Point c = motion_dt; - Geom::Matrix const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); + Geom::Affine const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); sp_canvas_item_affine_absolute(dc->hatch_area, sm); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x00FF00ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); sp_canvas_item_show(dc->hatch_area); } else if (dc->dragging && dc->hatch_escaped) { // Tracking escaped: red, center free, fixed radius Geom::Point c = motion_dt; - Geom::Matrix const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); + Geom::Affine const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); sp_canvas_item_affine_absolute(dc->hatch_area, sm); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0xFF0000ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); @@ -803,7 +804,7 @@ sp_dyna_draw_context_root_handler(SPEventContext *event_context, // Not drawing but spacing set: gray, center snapped, fixed radius Geom::Point c = (nearest + dc->hatch_spacing * hatch_unit_vector) * motion_to_curve.inverse(); if (!IS_NAN(c[Geom::X]) && !IS_NAN(c[Geom::Y])) { - Geom::Matrix const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); + Geom::Affine const sm (Geom::Scale(dc->hatch_spacing, dc->hatch_spacing) * Geom::Translate(c)); sp_canvas_item_affine_absolute(dc->hatch_area, sm); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); sp_canvas_item_show(dc->hatch_area); @@ -1086,32 +1087,20 @@ accumulate_calligraphic(SPDynaDrawContext *dc) return false; // failure } - Geom::CubicBezier const * dc_cal1_firstseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->first_segment() ); - Geom::CubicBezier const * rev_cal2_firstseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->first_segment() ); - Geom::CubicBezier const * dc_cal1_lastseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->last_segment() ); - Geom::CubicBezier const * rev_cal2_lastseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->last_segment() ); - - if ( - !dc_cal1_firstseg || - !rev_cal2_firstseg || - !dc_cal1_lastseg || - !rev_cal2_lastseg - ) { - rev_cal2->unref(); - dc->cal1->reset(); - dc->cal2->reset(); - return false; // failure - } + Geom::Curve const * dc_cal1_firstseg = dc->cal1->first_segment(); + Geom::Curve const * rev_cal2_firstseg = rev_cal2->first_segment(); + Geom::Curve const * dc_cal1_lastseg = dc->cal1->last_segment(); + Geom::Curve const * rev_cal2_lastseg = rev_cal2->last_segment(); dc->accumulated->reset(); /* Is this required ?? */ dc->accumulated->append(dc->cal1, false); - add_cap(dc->accumulated, (*dc_cal1_lastseg)[3], (*rev_cal2_firstseg)[0], dc->cap_rounding); + add_cap(dc->accumulated, dc_cal1_lastseg->finalPoint(), rev_cal2_firstseg->initialPoint(), dc->cap_rounding); dc->accumulated->append(rev_cal2, true); - add_cap(dc->accumulated, (*rev_cal2_lastseg)[3], (*dc_cal1_firstseg)[0], dc->cap_rounding); + add_cap(dc->accumulated, rev_cal2_lastseg->finalPoint(), dc_cal1_firstseg->initialPoint(), dc->cap_rounding); dc->accumulated->closepath(); diff --git a/src/ege-adjustment-action.cpp b/src/ege-adjustment-action.cpp index 17e11db2d..c075d67e7 100644 --- a/src/ege-adjustment-action.cpp +++ b/src/ege-adjustment-action.cpp @@ -770,20 +770,18 @@ static GtkWidget* create_menu_item( GtkAction* action ) if ( IS_EGE_ADJUSTMENT_ACTION(action) ) { EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action ); GValue value; - const gchar* sss = 0; GtkWidget* subby = 0; memset( &value, 0, sizeof(value) ); g_value_init( &value, G_TYPE_STRING ); g_object_get_property( G_OBJECT(action), "label", &value ); - sss = g_value_get_string( &value ); - - item = gtk_menu_item_new_with_label( sss ); + item = gtk_menu_item_new_with_label( g_value_get_string( &value ) ); subby = create_popup_number_menu( act ); gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby ); gtk_widget_show_all( subby ); + g_value_unset( &value ); } else { item = gParentClass->create_menu_item( action ); } @@ -816,8 +814,7 @@ static gboolean event_cb( EgeAdjustmentAction* act, GdkEvent* evt ) return handled; } -static gchar* -slider_format_falue (GtkScale* scale, gdouble value, gchar *label) +static gchar *slider_format_falue( GtkScale* scale, gdouble value, gchar *label ) { (void)scale; return g_strdup_printf("%s %d", label, (int) round(value)); @@ -831,19 +828,18 @@ static GtkWidget* create_tool_item( GtkAction* action ) EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action ); GtkWidget* spinbutton = 0; GtkWidget* hb = gtk_hbox_new( FALSE, 5 ); - GValue value; memset( &value, 0, sizeof(value) ); g_value_init( &value, G_TYPE_STRING ); g_object_get_property( G_OBJECT(action), "short_label", &value ); - const gchar* sss = g_value_get_string( &value ); if ( act->private_data->appearanceMode == APPEARANCE_FULL ) { - // Slider - spinbutton = gtk_hscale_new( act->private_data->adj); + // Slider + gchar *leakyForNow = g_value_dup_string( &value ); + spinbutton = gtk_hscale_new( act->private_data->adj); gtk_widget_set_size_request(spinbutton, 100, -1); - gtk_scale_set_digits (GTK_SCALE(spinbutton), 0); - gtk_signal_connect(GTK_OBJECT(spinbutton), "format-value", GTK_SIGNAL_FUNC(slider_format_falue), (void *) sss); + gtk_scale_set_digits( GTK_SCALE(spinbutton), 0 ); + g_signal_connect( G_OBJECT(spinbutton), "format-value", G_CALLBACK(slider_format_falue), leakyForNow ); #if GTK_CHECK_VERSION(2,12,0) } else if ( act->private_data->appearanceMode == APPEARANCE_MINIMAL ) { @@ -869,6 +865,7 @@ static GtkWidget* create_tool_item( GtkAction* action ) } gtk_tooltips_set_tip( act->private_data->toolTips, spinbutton, tipstr, 0 ); } + g_value_unset( &tooltip ); } if ( act->private_data->appearanceMode != APPEARANCE_FULL ) { @@ -880,7 +877,7 @@ static GtkWidget* create_tool_item( GtkAction* action ) GtkWidget* icon = sp_icon_new( act->private_data->iconSize, act->private_data->iconId ); gtk_box_pack_start( GTK_BOX(hb), icon, FALSE, FALSE, 0 ); } else { - GtkWidget* lbl = gtk_label_new( sss ? sss : "wwww" ); + GtkWidget* lbl = gtk_label_new( g_value_get_string( &value ) ? g_value_get_string( &value ) : "wwww" ); gtk_misc_set_alignment( GTK_MISC(lbl), 1.0, 0.5 ); gtk_box_pack_start( GTK_BOX(hb), lbl, FALSE, FALSE, 0 ); } @@ -921,6 +918,8 @@ static GtkWidget* create_tool_item( GtkAction* action ) if ( act->private_data->toolPost ) { act->private_data->toolPost( item ); } + + g_value_unset( &value ); } else { item = gParentClass->create_tool_item( action ); } diff --git a/src/ege-output-action.cpp b/src/ege-output-action.cpp index 62878eb16..72616ce18 100644 --- a/src/ege-output-action.cpp +++ b/src/ege-output-action.cpp @@ -222,6 +222,8 @@ GtkWidget* create_tool_item( GtkAction* action ) gtk_container_add( GTK_CONTAINER(item), hb ); gtk_widget_show_all( item ); + + g_value_unset( &value ); } else { item = gParentClass->create_tool_item( action ); } diff --git a/src/ege-select-one-action.cpp b/src/ege-select-one-action.cpp index 664ffd13d..83a083425 100644 --- a/src/ege-select-one-action.cpp +++ b/src/ege-select-one-action.cpp @@ -663,15 +663,18 @@ GtkWidget* create_tool_item( GtkAction* action ) gint index = 0; GtkTooltips* tooltips = gtk_tooltips_new(); - gchar* sss = 0; - g_object_get( G_OBJECT(action), "short_label", &sss, NULL ); - // If short_label not defined, g_object_get will return label. - // This hack allows a label to be used with a drop-down menu when - // no label is used with a set of icons that are self-explanatory. - if (sss && strcmp( sss, "NotUsed" ) != 0 ) { - GtkWidget* lbl; - lbl = gtk_label_new(sss); - gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 ); + { + gchar* sss = 0; + g_object_get( G_OBJECT(action), "short_label", &sss, NULL ); + // If short_label not defined, g_object_get will return label. + // This hack allows a label to be used with a drop-down menu when + // no label is used with a set of icons that are self-explanatory. + if (sss && strcmp( sss, "NotUsed" ) != 0 ) { + GtkWidget* lbl = gtk_label_new(sss); + gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 ); + } + g_free( sss ); + sss = 0; } valid = gtk_tree_model_get_iter_first( act->private_data->model, &iter ); @@ -813,9 +816,10 @@ GtkWidget* create_tool_item( GtkAction* action ) gchar* sss = 0; g_object_get( G_OBJECT(action), "short_label", &sss, NULL ); if (sss) { - GtkWidget* lbl; - lbl = gtk_label_new(sss); + GtkWidget* lbl = gtk_label_new(sss); gtk_box_pack_start( GTK_BOX(holder), lbl, FALSE, FALSE, 4 ); + g_free( sss ); + sss = 0; } } diff --git a/src/eraser-context.cpp b/src/eraser-context.cpp index 68c0989bc..8ac765b9e 100644 --- a/src/eraser-context.cpp +++ b/src/eraser-context.cpp @@ -34,6 +34,7 @@ #include <numeric> #include "svg/svg.h" +#include "display/sp-canvas.h" #include "display/canvas-bpath.h" #include <2geom/bezier-utils.h> diff --git a/src/extension/Makefile_insert b/src/extension/Makefile_insert index b9ce224ca..ffcee5f9a 100644 --- a/src/extension/Makefile_insert +++ b/src/extension/Makefile_insert @@ -24,8 +24,6 @@ ink_common_sources += \ extension/param/color.cpp \ extension/param/description.h \ extension/param/description.cpp \ - extension/param/groupheader.h \ - extension/param/groupheader.cpp \ extension/param/enum.h \ extension/param/enum.cpp \ extension/param/float.h \ diff --git a/src/extension/dbus/dbus-init.cpp b/src/extension/dbus/dbus-init.cpp index 253d6b938..3e453d048 100644 --- a/src/extension/dbus/dbus-init.cpp +++ b/src/extension/dbus/dbus-init.cpp @@ -14,6 +14,8 @@ */ #include <dbus/dbus-glib.h> +// this is reguired so that giomm headers won't barf +#undef DBUS_MESSAGE_TYPE_INVALID #include "dbus-init.h" #include "application-interface.h" @@ -84,7 +86,6 @@ init (void) GError *error = NULL; DBusGConnection *connection; DBusGProxy *proxy; - DocumentInterface *obj; connection = dbus_get_connection(); proxy = dbus_get_proxy(connection); org_freedesktop_DBus_request_name (proxy, @@ -100,16 +101,14 @@ init (void) gchar * init_document (void) { - guint result; - GError *error = NULL; DBusGConnection *connection; DBusGProxy *proxy; SPDocument *doc; - doc = sp_document_new(NULL, 1, TRUE); + doc = SPDocument::createNewDoc(NULL, 1, TRUE); std::string name("/org/inkscape/"); - name.append(doc->name); + name.append(doc->getName()); std::replace(name.begin(), name.end(), ' ', '_'); connection = dbus_get_connection(); diff --git a/src/extension/dbus/document-interface.cpp b/src/extension/dbus/document-interface.cpp index 836ad3397..8e22849b5 100644 --- a/src/extension/dbus/document-interface.cpp +++ b/src/extension/dbus/document-interface.cpp @@ -18,27 +18,23 @@ #include "document-interface.h" #include <string.h> -#include "verbs.h" -#include "helper/action.h" //sp_action_perform - -#include "inkscape.h" //inkscape_find_desktop_by_dkey, activate desktops - #include "desktop-handles.h" //sp_desktop_document() -#include "xml/repr.h" //sp_repr_document_new - -#include "sp-object.h" - -#include "document.h" // getReprDoc() - #include "desktop-style.h" //sp_desktop_get_style - -#include "selection.h" //selection struct +#include "display/canvas-text.h" //text +#include "display/sp-canvas.h" //text +#include "document.h" // getReprDoc() +#include "extension/output.h" //IO +#include "extension/system.h" //IO +#include "file.h" //IO +#include "helper/action.h" //sp_action_perform +#include "inkscape.h" //inkscape_find_desktop_by_dkey, activate desktops +#include "layer-fns.h" //LPOS_BELOW +#include "live_effects/parameter/text.h" //text +#include "print.h" //IO #include "selection-chemistry.h"// lots of selection functions - +#include "selection.h" //selection struct #include "sp-ellipse.h" - -#include "layer-fns.h" //LPOS_BELOW - +#include "sp-object.h" #include "style.h" //style_write #include "file.h" //IO @@ -52,6 +48,11 @@ #include "live_effects/parameter/text.h" //text #include "display/canvas-text.h" //text +#include "display/sp-canvas.h" //text +#include "text-editing.h" +#include "verbs.h" +#include "xml/repr.h" //sp_repr_document_new + //#include "2geom/svg-path-parser.h" //get_node_coordinates /**************************************************************************** @@ -74,13 +75,13 @@ get_repr_by_name (SPDesktop *desk, gchar *name, GError **error) /* ALTERNATIVE (is this faster if only repr is needed?) Inkscape::XML::Node *node = sp_repr_lookup_name((doc->root)->repr, name); */ - Inkscape::XML::Node * node = sp_desktop_document(desk)->getObjectById(name)->repr; - if (!node) + SPObject * obj = sp_desktop_document(desk)->getObjectById(name); + if (!obj) { g_set_error(error, INKSCAPE_ERROR, INKSCAPE_ERROR_OBJECT, "Object '%s' not found in document.", name); return NULL; } - return node; + return obj->getRepr(); } /* @@ -120,7 +121,7 @@ dbus_check_string (gchar *string, GError ** error, const gchar * errorstr) const gchar * get_name_from_object (SPObject * obj) { - return obj->repr->attribute("id"); + return obj->getRepr()->attribute("id"); } /* @@ -218,7 +219,8 @@ finish_create_shape (DocumentInterface *object, GError **error, Inkscape::XML::N object->desk->currentLayer()->updateRepr(); if (object->updates) - sp_document_done(sp_desktop_document(object->desk), 0, (gchar *)desc); + + Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), 0, (gchar *)desc); //else //document_interface_pause_updates(object, error); @@ -248,7 +250,7 @@ dbus_call_verb (DocumentInterface *object, int verbid, GError **error) //document_interface_pause_updates (object, error); sp_action_perform( action, NULL ); if (object->updates) - sp_document_done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip())); + Inkscape::DocumentUndo::done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip())); //if (!object->updates) //document_interface_pause_updates (object, error); return TRUE; @@ -356,8 +358,9 @@ document_interface_call_verb (DocumentInterface *object, gchar *verbid, GError * if ( action ) { sp_action_perform( action, NULL ); if (object->updates) { - sp_document_done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip())); + Inkscape::DocumentUndo::done(sp_desktop_document(desk2), verb->get_code(), g_strdup(verb->get_tip())); } + return TRUE; } } } @@ -482,17 +485,20 @@ document_interface_spiral (DocumentInterface *object, int cx, int cy, return retval; } -gboolean +gchar* document_interface_text (DocumentInterface *object, int x, int y, gchar *text, GError **error) { - //FIXME: Not selectable (aka broken). Needs to be rewritten completely. - SPDesktop *desktop = object->desk; - SPCanvasText * canvas_text = (SPCanvasText *) sp_canvastext_new(sp_desktop_tempgroup(desktop), desktop, Geom::Point(0,0), ""); - sp_canvastext_set_text (canvas_text, text); - sp_canvastext_set_coords (canvas_text, x, y); + Inkscape::XML::Node *text_node = dbus_create_node(object->desk, "svg:text"); + sp_repr_set_int(text_node, "x", x); + sp_repr_set_int(text_node, "y", y); + //just a workaround so i can get an spitem from the name + gchar *name = finish_create_shape (object, error, text_node, (gchar *)"create text"); + + SPItem* text_obj=(SPItem* )get_object_by_name(object->desk, name, error); + sp_te_set_repr_text_multiline(text_obj, text); - return TRUE; + return name; } gchar * @@ -511,7 +517,7 @@ document_interface_image (DocumentInterface *object, int x, int y, gchar *filena object->desk->currentLayer()->updateRepr(); if (object->updates) - sp_document_done(sp_desktop_document(object->desk), 0, "Imported bitmap."); + Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), 0, "Imported bitmap."); //g_free(uri); return strdup(newNode->attribute("id")); @@ -528,7 +534,7 @@ gchar *document_interface_node (DocumentInterface *object, gchar *type, GError * object->desk->currentLayer()->updateRepr(); if (object->updates) - sp_document_done(sp_desktop_document(object->desk), 0, (gchar *)"created empty node"); + Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), 0, (gchar *)"created empty node"); //else //document_interface_pause_updates(object, error); @@ -541,13 +547,13 @@ gchar *document_interface_node (DocumentInterface *object, gchar *type, GError * gdouble document_interface_document_get_width (DocumentInterface *object) { - return sp_document_width(sp_desktop_document(object->desk)); + return sp_desktop_document(object->desk)->getWidth(); } gdouble document_interface_document_get_height (DocumentInterface *object) { - return sp_document_height(sp_desktop_document(object->desk)); + return sp_desktop_document(object->desk)->getHeight(); } gchar * @@ -821,6 +827,20 @@ document_interface_get_node_coordinates (DocumentInterface *object, gchar *shape } +gboolean +document_interface_set_text (DocumentInterface *object, gchar *name, gchar *text, GError **error) +{ + + SPItem* text_obj=(SPItem* )get_object_by_name(object->desk, name, error); + //TODO verify object type + if (!text_obj) + return FALSE; + sp_te_set_repr_text_multiline(text_obj, text); + return TRUE; + +} + + /**************************************************************************** FILE I/O FUNCTIONS ****************************************************************************/ @@ -829,9 +849,9 @@ gboolean document_interface_save (DocumentInterface *object, GError **error) { SPDocument * doc = sp_desktop_document(object->desk); - printf("1: %s\n2: %s\n3: %s\n", doc->uri, doc->base, doc->name); - if (doc->uri) - return document_interface_save_as (object, doc->uri, error); + printf("1: %s\n2: %s\n3: %s\n", doc->getURI(), doc->getBase(), doc->getName()); + if (doc->getURI()) + return document_interface_save_as (object, doc->getURI(), error); return FALSE; } @@ -843,13 +863,13 @@ document_interface_load (DocumentInterface *object, const Glib::ustring file(filename); sp_file_open(file, NULL, TRUE, TRUE); if (object->updates) - sp_document_done(sp_desktop_document(object->desk), SP_VERB_FILE_OPEN, "Opened File"); + Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_FILE_OPEN, "Opened File"); return TRUE; } gboolean document_interface_save_as (DocumentInterface *object, - gchar *filename, GError **error) + const gchar *filename, GError **error) { SPDocument * doc = sp_desktop_document(object->desk); #ifdef WITH_GNOME_VFS @@ -950,7 +970,7 @@ document_interface_resume_updates (DocumentInterface *object, GError **error) //sp_desktop_document(object->desk)->root->mflags = TRUE; //sp_desktop_document(object->desk)->_updateDocument(); //FIXME: use better verb than rect. - sp_document_done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions"); + Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions"); } void @@ -963,7 +983,7 @@ document_interface_update (DocumentInterface *object, GError **error) object->desk->disableInteraction(); sp_desktop_document(object->desk)->root->uflags = FALSE; sp_desktop_document(object->desk)->root->mflags = FALSE; - //sp_document_done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions"); + //Inkscape::DocumentUndo::done(sp_desktop_document(object->desk), SP_VERB_CONTEXT_RECT, "Multiple actions"); } /**************************************************************************** @@ -982,7 +1002,7 @@ document_interface_selection_get (DocumentInterface *object, char ***out, GError int i = 0; for (GSList const *iter = oldsel; iter != NULL; iter = iter->next) { - (*out)[i] = g_strdup(SP_OBJECT(iter->data)->repr->attribute("id")); + (*out)[i] = g_strdup(SP_OBJECT(iter->data)->getRepr()->attribute("id")); i++; } (*out)[i] = NULL; @@ -1188,7 +1208,7 @@ document_interface_selection_move_to_layer (DocumentInterface *object, if (!next) return FALSE; - if (strcmp("layer", (next->repr)->attribute("inkscape:groupmode")) == 0) { + if (strcmp("layer", (next->getRepr())->attribute("inkscape:groupmode")) == 0) { sp_selection_cut(dt); diff --git a/src/extension/dbus/document-interface.h b/src/extension/dbus/document-interface.h index 8cf9b7ec1..0283d987e 100644 --- a/src/extension/dbus/document-interface.h +++ b/src/extension/dbus/document-interface.h @@ -22,6 +22,14 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-bindings.h> #include <dbus/dbus-glib-lowlevel.h> + +// this is reguired so that giomm headers won't barf +#undef DBUS_MESSAGE_TYPE_INVALID +#undef DBUS_MESSAGE_TYPE_METHOD_CALL +#undef DBUS_MESSAGE_TYPE_METHOD_RETURN +#undef DBUS_MESSAGE_TYPE_ERROR +#undef DBUS_MESSAGE_TYPE_SIGNAL + #include "desktop.h" #define DBUS_DOCUMENT_INTERFACE_PATH "/org/inkscape/document" @@ -107,10 +115,13 @@ gchar* document_interface_line (DocumentInterface *object, int x, int y, int x2, int y2, GError **error); -gboolean +gchar* document_interface_text (DocumentInterface *object, int x, int y, gchar *text, GError **error); - +gboolean +document_interface_set_text (DocumentInterface *object, gchar *name, + gchar *text, GError **error); + gchar * document_interface_image (DocumentInterface *object, int x, int y, gchar *filename, GError **error); @@ -224,7 +235,7 @@ document_interface_load (DocumentInterface *object, gboolean document_interface_save_as (DocumentInterface *object, - gchar *filename, GError **error); + const gchar *filename, GError **error); gboolean document_interface_mark_as_unmodified (DocumentInterface *object, GError **error); diff --git a/src/extension/dbus/document-interface.xml b/src/extension/dbus/document-interface.xml index 8b0252765..94f39ae7e 100644 --- a/src/extension/dbus/document-interface.xml +++ b/src/extension/dbus/document-interface.xml @@ -310,6 +310,12 @@ <doc:summary>The text you want.</doc:summary> </doc:doc> </arg> + <arg type="s" name="object_name" direction="out" > + <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/> + <doc:doc> + <doc:summary>The name of the new text.</doc:summary> + </doc:doc> + </arg> <doc:doc> <doc:description> <doc:para>This method creates some text in the current layer.</doc:para> @@ -472,6 +478,29 @@ </doc:doc> </method> + + <method name="set_text"> + <arg type="s" name="shape" direction="in" > + <doc:doc> + <doc:summary>The id of an object.</doc:summary> + </doc:doc> + </arg> + + <arg type="s" name="text" direction="in" > + <doc:doc> + <doc:summary>The text you want.</doc:summary> + </doc:doc> + </arg> + <doc:doc> + <doc:description> + <doc:para>set text of text object.</doc:para> + </doc:description> + </doc:doc> + </method> + + + + <method name="set_int_attribute"> <arg type="s" name="shape" direction="in" > <doc:doc> diff --git a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c index b59ee746b..7a33d4f38 100644 --- a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c +++ b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.c @@ -198,11 +198,13 @@ inkscape_line (DocumentInterface *doc, const gint IN_x, const gint IN_y, const g } //static -gboolean +char * inkscape_text (DocumentInterface *doc, const gint IN_x, const gint IN_y, const char * IN_text, GError **error) { + char * OUT_object_name; DBusGProxy *proxy = doc->proxy; - return org_inkscape_document_text (proxy, IN_x, IN_y, IN_text, error); + org_inkscape_document_text (proxy, IN_x, IN_y, IN_text, &OUT_object_name, error); + return OUT_object_name; } //static diff --git a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h index c314bf6f8..684f1b142 100644 --- a/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h +++ b/src/extension/dbus/wrapper/inkscape-dbus-wrapper.h @@ -72,7 +72,7 @@ char * inkscape_line (DocumentInterface *doc, const gint IN_x, const gint IN_y, const gint IN_x2, const gint IN_y2, GError **error); //static -gboolean +char * inkscape_text (DocumentInterface *doc, const gint IN_x, const gint IN_y, const char * IN_text, GError **error); //static diff --git a/src/extension/implementation/implementation.cpp b/src/extension/implementation/implementation.cpp index a8533a427..63181d0c4 100644 --- a/src/extension/implementation/implementation.cpp +++ b/src/extension/implementation/implementation.cpp @@ -96,23 +96,26 @@ Implementation::save(Inkscape::Extension::Output */*module*/, SPDocument */*doc* return; } /* Implementation::save */ -Gtk::Widget * -Implementation::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View * view, sigc::signal<void> * changeSignal, ImplementationDocumentCache * docCache) { - if (module->param_visible_count() == 0) return NULL; +Gtk::Widget *Implementation::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View * view, sigc::signal<void> * changeSignal, ImplementationDocumentCache * /*docCache*/) +{ + if (module->param_visible_count() == 0) { + return NULL; + } SPDocument * current_document = view->doc(); using Inkscape::Util::GSListConstIterator; GSListConstIterator<SPItem *> selected = sp_desktop_selection((SPDesktop *)view)->itemList(); - Inkscape::XML::Node * first_select = NULL; + Inkscape::XML::Node const* first_select = NULL; if (selected != NULL) { const SPItem * item = *selected; - first_select = SP_OBJECT_REPR(item); + first_select = item->getRepr(); } - return module->autogui(current_document, first_select, changeSignal); -} /* Implementation::prefs_effect */ + // TODO deal with this broken const correctness: + return module->autogui(current_document, const_cast<Inkscape::XML::Node *>(first_select), changeSignal); +} // Implementation::prefs_effect void Implementation::effect(Inkscape::Extension::Effect */*module*/, Inkscape::UI::View::View */*document*/, ImplementationDocumentCache * /*docCache*/) { @@ -148,7 +151,7 @@ Implementation::finish(Inkscape::Extension::Print */*module*/) /* Rendering methods */ unsigned int -Implementation::bind(Inkscape::Extension::Print */*module*/, Geom::Matrix const */*transform*/, float /*opacity*/) +Implementation::bind(Inkscape::Extension::Print */*module*/, Geom::Affine const */*transform*/, float /*opacity*/) { return 0; } @@ -166,14 +169,14 @@ Implementation::comment(Inkscape::Extension::Print */*module*/, char const */*co } unsigned int -Implementation::fill(Inkscape::Extension::Print */*module*/, Geom::PathVector const &/*pathv*/, Geom::Matrix const */*ctm*/, SPStyle const */*style*/, +Implementation::fill(Inkscape::Extension::Print */*module*/, Geom::PathVector const &/*pathv*/, Geom::Affine const */*ctm*/, SPStyle const */*style*/, NRRect const */*pbox*/, NRRect const */*dbox*/, NRRect const */*bbox*/) { return 0; } unsigned int -Implementation::stroke(Inkscape::Extension::Print */*module*/, Geom::PathVector const &/*pathv*/, Geom::Matrix const */*transform*/, SPStyle const */*style*/, +Implementation::stroke(Inkscape::Extension::Print */*module*/, Geom::PathVector const &/*pathv*/, Geom::Affine const */*transform*/, SPStyle const */*style*/, NRRect const */*pbox*/, NRRect const */*dbox*/, NRRect const */*bbox*/) { return 0; @@ -181,7 +184,7 @@ Implementation::stroke(Inkscape::Extension::Print */*module*/, Geom::PathVector unsigned int Implementation::image(Inkscape::Extension::Print */*module*/, unsigned char */*px*/, unsigned int /*w*/, unsigned int /*h*/, unsigned int /*rs*/, - Geom::Matrix const */*transform*/, SPStyle const */*style*/) + Geom::Affine const */*transform*/, SPStyle const */*style*/) { return 0; } diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h index 9de70dce7..bf584b401 100644 --- a/src/extension/implementation/implementation.h +++ b/src/extension/implementation/implementation.h @@ -100,20 +100,20 @@ public: /* ----- Rendering methods ----- */ virtual unsigned bind(Inkscape::Extension::Print *module, - Geom::Matrix const *transform, + Geom::Affine const *transform, float opacity); virtual unsigned release(Inkscape::Extension::Print *module); virtual unsigned comment(Inkscape::Extension::Print *module, const char * comment); virtual unsigned fill(Inkscape::Extension::Print *module, Geom::PathVector const &pathv, - Geom::Matrix const *ctm, + Geom::Affine const *ctm, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox); virtual unsigned stroke(Inkscape::Extension::Print *module, Geom::PathVector const &pathv, - Geom::Matrix const *transform, + Geom::Affine const *transform, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, @@ -123,7 +123,7 @@ public: unsigned int w, unsigned int h, unsigned int rs, - Geom::Matrix const *transform, + Geom::Affine const *transform, SPStyle const *style); virtual unsigned text(Inkscape::Extension::Print *module, char const *text, diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index bc143fd14..2f3e2cd65 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -45,7 +45,7 @@ #include "xml/attribute-record.h" #include "util/glib-list-iterators.h" - +#include "path-prefix.h" #ifdef WIN32 @@ -189,7 +189,6 @@ Script::solve_reldir(Inkscape::XML::Node *reprin) { } Glib::ustring reldir = s; - for (unsigned int i=0; i < Inkscape::Extension::Extension::search_path.size(); i++) { @@ -200,7 +199,7 @@ Script::solve_reldir(Inkscape::XML::Node *reprin) { NULL); Glib::ustring filename = fname; g_free(fname); - + //printf("Filename: %s\n", filename.c_str()); if ( Inkscape::IO::file_test(filename.c_str(), G_FILE_TEST_EXISTS) ) { return Glib::filename_from_utf8(filename); } @@ -229,14 +228,13 @@ Script::solve_reldir(Inkscape::XML::Node *reprin) { */ bool Script::check_existence(const std::string &command) { - // Check the simple case first if (command.empty()) { return false; } //Don't search when it is an absolute path. */ - if (!Glib::path_is_absolute(command)) { + if (Glib::path_is_absolute(command)) { if (Glib::file_test(command, Glib::FILE_TEST_EXISTS)) { return true; } else { @@ -244,12 +242,11 @@ bool Script::check_existence(const std::string &command) } } - std::string path = Glib::getenv("PATH"); - if (path.empty()) { - /* There is no `PATH' in the environment. - The default search path is the current directory */ - path = G_SEARCHPATH_SEPARATOR_S; - } + // First search in the current directory + std::string path = G_SEARCHPATH_SEPARATOR_S; + path.append(";"); + // And then in the PATH environment variable. + path.append(Glib::getenv("PATH")); std::string::size_type pos = 0; std::string::size_type pos2 = 0; @@ -379,8 +376,11 @@ Script::check(Inkscape::Extension::Extension *module) if (!command_text.empty()) { /* I've got the command */ bool existance = check_existence(command_text); - if (!existance) + if (!existance) { return false; + } + } else { + return false; } } @@ -603,7 +603,7 @@ void Script::save(Inkscape::Extension::Output *module, file_listener fileout; int data_read = execute(command, params, tempfilename_in, fileout); - + bool success = false; if (data_read > 0) { diff --git a/src/extension/implementation/xslt.cpp b/src/extension/implementation/xslt.cpp index c929ba19a..8b6e6c701 100644 --- a/src/extension/implementation/xslt.cpp +++ b/src/extension/implementation/xslt.cpp @@ -29,6 +29,7 @@ #include <libxml/parser.h> #include <libxslt/transform.h> +#include <libxslt/xsltutils.h> Inkscape::XML::Document * sp_repr_do_read (xmlDocPtr doc, const gchar * default_ns); @@ -217,11 +218,19 @@ XSLT::save(Inkscape::Extension::Output */*module*/, SPDocument *doc, gchar const params[0] = NULL; xmlDocPtr newdoc = xsltApplyStylesheet(_stylesheet, svgdoc, params); - xmlSaveFile(filename, newdoc); + //xmlSaveFile(filename, newdoc); + int success = xsltSaveResultToFilename(filename, newdoc, _stylesheet, 0); xmlFreeDoc(newdoc); xmlFreeDoc(svgdoc); + xsltCleanupGlobals(); + xmlCleanupParser(); + + if (success < 1) { + throw Inkscape::Extension::Output::save_failed(); + } + return; } diff --git a/src/extension/init.cpp b/src/extension/init.cpp index 8578e8c6c..230d4b50f 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -166,7 +166,7 @@ init() Internal::PdfInput::init(); #endif #ifdef HAVE_POPPLER_GLIB - if (0) { + if (1) { Internal::PdfInputCairo::init(); } #endif @@ -192,7 +192,7 @@ init() #ifdef WITH_DBUS Dbus::init(); #endif - + /* Raster Effects */ #ifdef WITH_IMAGE_MAGICK Internal::Bitmap::AdaptiveThreshold::init(); diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index e907612fd..65968bdc4 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -226,8 +226,9 @@ ImageMagick::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::Vie using Inkscape::Util::GSListConstIterator; GSListConstIterator<SPItem *> selected = sp_desktop_selection((SPDesktop *)view)->itemList(); Inkscape::XML::Node * first_select = NULL; - if (selected != NULL) - first_select = SP_OBJECT_REPR(*selected); + if (selected != NULL) { + first_select = (*selected)->getRepr(); + } return module->autogui(current_document, first_select, changeSignal); } diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp index ba6b8383c..8ec09d11e 100644 --- a/src/extension/internal/bluredge.cpp +++ b/src/extension/internal/bluredge.cpp @@ -74,9 +74,9 @@ BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View std::vector<Inkscape::XML::Node *> new_items(steps); Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node * new_group = xml_doc->createElement("svg:g"); - (SP_OBJECT_REPR(spitem)->parent())->appendChild(new_group); + spitem->getRepr()->parent()->appendChild(new_group); - double orig_opacity = sp_repr_css_double_property(sp_repr_css_attr(SP_OBJECT_REPR(spitem), "style"), "opacity", 1.0); + double orig_opacity = sp_repr_css_double_property(sp_repr_css_attr(spitem->getRepr(), "style"), "opacity", 1.0); char opacity_string[64]; g_ascii_formatd(opacity_string, sizeof(opacity_string), "%f", orig_opacity / (steps)); @@ -84,7 +84,7 @@ BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View for (int i = 0; i < steps; i++) { double offset = (width / (float)(steps - 1) * (float)i) - (width / 2.0); - new_items[i] = (SP_OBJECT_REPR(spitem))->duplicate(xml_doc); + new_items[i] = spitem->getRepr()->duplicate(xml_doc); SPCSSAttr * css = sp_repr_css_attr(new_items[i], "style"); sp_repr_css_set_property(css, "opacity", opacity_string); diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 07312aab1..a5b7b3237 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -142,7 +142,7 @@ CairoPsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar con int level = CAIRO_PS_LEVEL_2; try { new_level = mod->get_param_enum("PSlevel"); - if((new_level != NULL) && !(g_ascii_strcasecmp("PS3", new_level) == 0)) + if((new_level != NULL) && (g_ascii_strcasecmp("PS3", new_level) == 0)) level = CAIRO_PS_LEVEL_3; } catch(...) {} @@ -225,7 +225,7 @@ CairoEpsOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar co int level = CAIRO_PS_LEVEL_2; try { new_level = mod->get_param_enum("PSlevel"); - if((new_level != NULL) && !(g_ascii_strcasecmp("PS3", new_level) == 0)) + if((new_level != NULL) && (g_ascii_strcasecmp("PS3", new_level) == 0)) level = CAIRO_PS_LEVEL_3; } catch(...) {} diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 52e10f7a4..0e2194c17 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -58,6 +58,8 @@ #include "io/sys.h" +#include "svg/stringstream.h" + #include <cairo.h> // include support for only the compiled-in surface types @@ -516,7 +518,7 @@ CairoRenderContext::getClipMode(void) const CairoRenderState* CairoRenderContext::_createState(void) { - CairoRenderState *state = (CairoRenderState*)g_malloc(sizeof(CairoRenderState)); + CairoRenderState *state = (CairoRenderState*)g_try_malloc(sizeof(CairoRenderState)); g_assert( state != NULL ); state->has_filtereffect = FALSE; @@ -626,7 +628,7 @@ CairoRenderContext::popLayer(void) // copy over the correct CTM // It must be stored in item_transform of current state after pushState. - Geom::Matrix item_transform; + Geom::Affine item_transform; if (_state->parent_has_userspace) item_transform = getParentState()->transform * _state->item_transform; else @@ -785,6 +787,13 @@ CairoRenderContext::setupSurface(double width, double height) _width = width; _height = height; + Inkscape::SVGOStringStream os_bbox; + Inkscape::SVGOStringStream os_pagebbox; + os_bbox.setf(std::ios::fixed); // don't use scientific notation + os_pagebbox.setf(std::ios::fixed); // don't use scientific notation + os_bbox << "%%BoundingBox: 0 0 " << (int)ceil(width) << (int)ceil(height); // apparently, the numbers should be integers. (see bug 380501) + os_pagebbox << "%%PageBoundingBox: 0 0 " << (int)ceil(width) << (int)ceil(height); + cairo_surface_t *surface = NULL; cairo_matrix_t ctm; cairo_matrix_init_identity (&ctm); @@ -796,7 +805,7 @@ CairoRenderContext::setupSurface(double width, double height) case CAIRO_SURFACE_TYPE_PDF: surface = cairo_pdf_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, width, height); #if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)) - cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level); + cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level); #endif break; #endif @@ -812,10 +821,9 @@ CairoRenderContext::setupSurface(double width, double height) #endif // Cairo calculates the bounding box itself, however we want to override this. See Launchpad bug #380501 #if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)) - if (override_bbox) { - cairo_ps_dsc_comment(surface, "%%BoundingBox: 100 100 200 200"); - cairo_ps_dsc_comment(surface, "%%PageBoundingBox: 100 100 200 200"); - } +// cairo_ps_dsc_comment(surface, os_bbox.str().c_str()); +// cairo_ps_dsc_begin_page(surface); +// cairo_ps_dsc_comment(surface, os_pagebbox.str().c_str()); #endif break; #endif @@ -908,7 +916,7 @@ CairoRenderContext::finish(void) } void -CairoRenderContext::transform(Geom::Matrix const *transform) +CairoRenderContext::transform(Geom::Affine const *transform) { g_assert( _is_valid ); @@ -921,7 +929,7 @@ CairoRenderContext::transform(Geom::Matrix const *transform) } void -CairoRenderContext::setTransform(Geom::Matrix const *transform) +CairoRenderContext::setTransform(Geom::Affine const *transform) { g_assert( _is_valid ); @@ -932,7 +940,7 @@ CairoRenderContext::setTransform(Geom::Matrix const *transform) } void -CairoRenderContext::getTransform(Geom::Matrix *copy) const +CairoRenderContext::getTransform(Geom::Affine *copy) const { g_assert( _is_valid ); @@ -947,12 +955,12 @@ CairoRenderContext::getTransform(Geom::Matrix *copy) const } void -CairoRenderContext::getParentTransform(Geom::Matrix *copy) const +CairoRenderContext::getParentTransform(Geom::Affine *copy) const { g_assert( _is_valid ); CairoRenderState *parent_state = getParentState(); - memcpy(copy, &parent_state->transform, sizeof(Geom::Matrix)); + memcpy(copy, &parent_state->transform, sizeof(Geom::Affine)); } void @@ -1001,7 +1009,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver SPPattern *pat = SP_PATTERN (paintserver); - Geom::Matrix ps2user, pcs2dev; + Geom::Affine ps2user, pcs2dev; ps2user = Geom::identity(); pcs2dev = Geom::identity(); @@ -1015,7 +1023,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver TRACE(("%f x %f pattern\n", width, height)); if (pbox && pattern_patternUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { - //Geom::Matrix bbox2user (pbox->x1 - pbox->x0, 0.0, 0.0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0); + //Geom::Affine bbox2user (pbox->x1 - pbox->x0, 0.0, 0.0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0); bbox_width_scaler = pbox->x1 - pbox->x0; bbox_height_scaler = pbox->y1 - pbox->y0; ps2user[4] = x * bbox_width_scaler + pbox->x0; @@ -1028,7 +1036,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver } // apply pattern transformation - Geom::Matrix pattern_transform(pattern_patternTransform(pat)); + Geom::Affine pattern_transform(pattern_patternTransform(pat)); ps2user *= pattern_transform; Geom::Point ori (ps2user[4], ps2user[5]); @@ -1150,7 +1158,7 @@ CairoRenderContext::_createPatternForPaintServer(SPPaintServer const *const pain Geom::Point p2 (lg->x2.computed, lg->y2.computed); if (pbox && SP_GRADIENT(lg)->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { // convert to userspace - Geom::Matrix bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0); + Geom::Affine bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0); p1 *= bbox2user; p2 *= bbox2user; } @@ -1413,16 +1421,27 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con bool CairoRenderContext::renderImage(guchar *px, unsigned int w, unsigned int h, unsigned int rs, - Geom::Matrix const *image_transform, SPStyle const *style) + Geom::Affine const *image_transform, SPStyle const *style) { g_assert( _is_valid ); if (_render_mode == RENDER_MODE_CLIP) return true; - guchar* px_rgba = (guchar*)g_malloc(4 * w * h); - if (!px_rgba) + guchar* px_rgba = NULL; + guint64 size = 4L * (guint64)w * (guint64)h; + + if(size < (guint64)G_MAXSIZE) { + px_rgba = (guchar*)g_try_malloc(4 * w * h); + if (!px_rgba) { + g_warning ("Could not allocate %lu bytes for pixel buffer!", (long unsigned) size); + return false; + } + } else { + g_warning ("the requested memory exceeds the system limit"); return false; + } + float opacity; if (_state->merge_opacity) @@ -1432,15 +1451,16 @@ CairoRenderContext::renderImage(guchar *px, unsigned int w, unsigned int h, unsi // make a copy of the original pixbuf with premultiplied alpha // if we pass the original pixbuf it will get messed up + /// @todo optimize this code, it costs a lot of time for (unsigned i = 0; i < h; i++) { + guchar const *src = px + i * rs; + guint32 *dst = (guint32 *)(px_rgba + i * rs); for (unsigned j = 0; j < w; j++) { - guchar const *src = px + i * rs + j * 4; - guint32 *dst = (guint32 *)(px_rgba + i * rs + j * 4); guchar r, g, b, alpha_dst; // calculate opacity-modified alpha alpha_dst = src[3]; - if (opacity != 1.0 && _vector_based_target) + if ((opacity != 1.0) && _vector_based_target) alpha_dst = (guchar)ceil((float)alpha_dst * opacity); // premul alpha (needed because this will be undone by cairo-pdf) @@ -1449,6 +1469,9 @@ CairoRenderContext::renderImage(guchar *px, unsigned int w, unsigned int h, unsi b = src[2]*alpha_dst/255; *dst = (((alpha_dst) << 24) | (((r)) << 16) | (((g)) << 8) | (b)); + + dst++; // pointer to 4byte variables + src += 4; // pointer to 1byte variables } } @@ -1497,8 +1520,13 @@ CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoG cairo_glyph_t glyph_array[GLYPH_ARRAY_SIZE]; cairo_glyph_t *glyphs = glyph_array; unsigned int num_glyphs = glyphtext.size(); - if (num_glyphs > GLYPH_ARRAY_SIZE) - glyphs = (cairo_glyph_t*)g_malloc(sizeof(cairo_glyph_t) * num_glyphs); + if (num_glyphs > GLYPH_ARRAY_SIZE) { + glyphs = (cairo_glyph_t*)g_try_malloc(sizeof(cairo_glyph_t) * num_glyphs); + if(glyphs == NULL) { + g_warning("CairorenderContext::_showGlyphs: can not allocate memory for %d glyphs.", num_glyphs); + return 0; + } + } unsigned int num_invalid_glyphs = 0; unsigned int i = 0; // is a counter for indexing the glyphs array, only counts the valid glyphs @@ -1530,7 +1558,7 @@ CairoRenderContext::_showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoG } bool -CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Matrix const *font_matrix, +CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const *font_matrix, std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style) { // create a cairo_font_face from PangoFont @@ -1648,7 +1676,7 @@ CairoRenderContext::_concatTransform(cairo_t *cr, double xx, double yx, double x } void -CairoRenderContext::_initCairoMatrix(cairo_matrix_t *matrix, Geom::Matrix const *transform) +CairoRenderContext::_initCairoMatrix(cairo_matrix_t *matrix, Geom::Affine const *transform) { matrix->xx = (*transform)[0]; matrix->yx = (*transform)[1]; @@ -1659,7 +1687,7 @@ CairoRenderContext::_initCairoMatrix(cairo_matrix_t *matrix, Geom::Matrix const } void -CairoRenderContext::_concatTransform(cairo_t *cr, Geom::Matrix const *transform) +CairoRenderContext::_concatTransform(cairo_t *cr, Geom::Affine const *transform) { _concatTransform(cr, (*transform)[0], (*transform)[1], (*transform)[2], (*transform)[3], diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h index 4fb554de7..68a3c6537 100644 --- a/src/extension/internal/cairo-render-context.h +++ b/src/extension/internal/cairo-render-context.h @@ -22,7 +22,7 @@ #include <string> #include <2geom/forward.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "style.h" @@ -54,12 +54,12 @@ struct CairoRenderState { unsigned int parent_has_userspace : 1; // whether the parent's ctm should be applied float opacity; bool has_filtereffect; - Geom::Matrix item_transform; // this item's item->transform, for correct clipping + Geom::Affine item_transform; // this item's item->transform, for correct clipping SPClipPath *clip_path; SPMask* mask; - Geom::Matrix transform; // the CTM + Geom::Affine transform; // the CTM }; class CairoRenderContext { @@ -128,10 +128,10 @@ public: CairoRenderState *getParentState(void) const; void setStateForStyle(SPStyle const *style); - void transform(Geom::Matrix const *transform); - void setTransform(Geom::Matrix const *transform); - void getTransform(Geom::Matrix *copy) const; - void getParentTransform(Geom::Matrix *copy) const; + void transform(Geom::Affine const *transform); + void setTransform(Geom::Affine const *transform); + void getTransform(Geom::Affine *copy) const; + void getParentTransform(Geom::Affine *copy) const; /* Clipping methods */ void addClipPath(Geom::PathVector const &pv, SPIEnum const *fill_rule); @@ -140,8 +140,8 @@ public: /* Rendering methods */ bool renderPathVector(Geom::PathVector const & pathv, SPStyle const *style, NRRect const *pbox); bool renderImage(unsigned char *px, unsigned int w, unsigned int h, unsigned int rs, - Geom::Matrix const *image_transform, SPStyle const *style); - bool renderGlyphtext(PangoFont *font, Geom::Matrix const *font_matrix, + Geom::Affine const *image_transform, SPStyle const *style); + bool renderGlyphtext(PangoFont *font, Geom::Affine const *font_matrix, std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style); /* More general rendering methods will have to be added (like fill, stroke) */ @@ -192,9 +192,9 @@ protected: void _setFillStyle(SPStyle const *style, NRRect const *pbox); void _setStrokeStyle(SPStyle const *style, NRRect const *pbox); - void _initCairoMatrix(cairo_matrix_t *matrix, Geom::Matrix const *transform); + void _initCairoMatrix(cairo_matrix_t *matrix, Geom::Affine const *transform); void _concatTransform(cairo_t *cr, double xx, double yx, double xy, double yy, double x0, double y0); - void _concatTransform(cairo_t *cr, Geom::Matrix const *transform); + void _concatTransform(cairo_t *cr, Geom::Affine const *transform); GHashTable *font_table; static void font_data_free(gpointer data); diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index 8406e2a3b..6527a646b 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -37,7 +37,7 @@ #include "sp-item.h" #include "sp-root.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> namespace Inkscape { namespace Extension { diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 67f9354d8..dbda82c28 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -157,7 +157,7 @@ static void sp_image_render(SPItem *item, CairoRenderContext *ctx); static void sp_symbol_render(SPItem *item, CairoRenderContext *ctx); static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx); -static void sp_shape_render_invoke_marker_rendering(SPMarker* marker, Geom::Matrix tr, SPStyle* style, CairoRenderContext *ctx) +static void sp_shape_render_invoke_marker_rendering(SPMarker* marker, Geom::Affine tr, SPStyle* style, CairoRenderContext *ctx) { bool render = true; if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { @@ -169,9 +169,9 @@ static void sp_shape_render_invoke_marker_rendering(SPMarker* marker, Geom::Matr } if (render) { - SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker)); - tr = (Geom::Matrix)marker_item->transform * (Geom::Matrix)marker->c2p * tr; - Geom::Matrix old_tr = marker_item->transform; + SPItem* marker_item = sp_item_first_item_child(marker); + tr = (Geom::Affine)marker_item->transform * (Geom::Affine)marker->c2p * tr; + Geom::Affine old_tr = marker_item->transform; marker_item->transform = tr; ctx->getRenderer()->renderItem (ctx, marker_item); marker_item->transform = old_tr; @@ -184,14 +184,18 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) SPShape *shape = SP_SHAPE(item); - if (!shape->curve) return; + if (!shape->curve) { + return; + } item->invoke_bbox( &pbox, Geom::identity(), TRUE); - SPStyle* style = SP_OBJECT_STYLE (item); + SPStyle* style = item->style; Geom::PathVector const & pathv = shape->curve->get_pathvector(); - if (pathv.empty()) return; + if (pathv.empty()) { + return; + } ctx->renderPathVector(pathv, style, &pbox); @@ -199,7 +203,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( shape->marker[i] ) { SPMarker* marker = SP_MARKER (shape->marker[i]); - Geom::Matrix tr; + Geom::Affine tr; if (marker->orient_auto) { tr = sp_shape_marker_get_transform_at_start(pathv.begin()->front()); } else { @@ -217,7 +221,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) if ( path_it != pathv.begin() && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { - Geom::Matrix tr; + Geom::Affine tr; if (marker->orient_auto) { tr = sp_shape_marker_get_transform_at_start(path_it->front()); } else { @@ -234,7 +238,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) /* Put marker between curve_it1 and curve_it2. * Loop to end_default (so including closing segment), because when a path is closed, * there should be a midpoint marker between last segment and closing straight line segment */ - Geom::Matrix tr; + Geom::Affine tr; if (marker->orient_auto) { tr = sp_shape_marker_get_transform(*curve_it1, *curve_it2); } else { @@ -250,7 +254,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) // END position if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); - Geom::Matrix tr; + Geom::Affine tr; if (marker->orient_auto) { tr = sp_shape_marker_get_transform_at_end(lastcurve); } else { @@ -274,7 +278,7 @@ static void sp_shape_render (SPItem *item, CairoRenderContext *ctx) } Geom::Curve const &lastcurve = path_last[index]; - Geom::Matrix tr; + Geom::Affine tr; if (marker->orient_auto) { tr = sp_shape_marker_get_transform_at_end(lastcurve); } else { @@ -290,7 +294,7 @@ static void sp_group_render(SPItem *item, CairoRenderContext *ctx) { SPGroup *group = SP_GROUP(item); CairoRenderer *renderer = ctx->getRenderer(); - TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(SP_OBJECT_STYLE(item)->opacity.value))); + TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(item->style->opacity.value))); GSList *l = g_slist_reverse(group->childList(false)); while (l) { @@ -309,7 +313,7 @@ static void sp_use_render(SPItem *item, CairoRenderContext *ctx) CairoRenderer *renderer = ctx->getRenderer(); if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { - Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed)); + Geom::Affine tp(Geom::Translate(use->x.computed, use->y.computed)); ctx->pushState(); ctx->transform(&tp); translated = true; @@ -368,16 +372,17 @@ static void sp_image_render(SPItem *item, CairoRenderContext *ctx) Geom::Translate tp(x, y); Geom::Scale s(width / (double)w, height / (double)h); - Geom::Matrix t(s * tp); + Geom::Affine t(s * tp); - ctx->renderImage (px, w, h, rs, &t, SP_OBJECT_STYLE (item)); + ctx->renderImage (px, w, h, rs, &t, item->style); } static void sp_symbol_render(SPItem *item, CairoRenderContext *ctx) { SPSymbol *symbol = SP_SYMBOL(item); - if (!SP_OBJECT_IS_CLONED (symbol)) + if (!symbol->cloned) { return; + } /* Cloned <symbol> is actually renderable */ ctx->pushState(); @@ -385,7 +390,7 @@ static void sp_symbol_render(SPItem *item, CairoRenderContext *ctx) // apply viewbox if set if (0 /*symbol->viewBox_set*/) { - Geom::Matrix vb2user; + Geom::Affine vb2user; double x, y, width, height; double view_width, view_height; x = 0.0; @@ -418,12 +423,12 @@ static void sp_root_render(SPItem *item, CairoRenderContext *ctx) SPRoot *root = SP_ROOT(item); CairoRenderer *renderer = ctx->getRenderer(); - if (!ctx->getCurrentState()->has_overflow && SP_OBJECT(item)->parent) + if (!ctx->getCurrentState()->has_overflow && item->parent) ctx->addClippingRect(root->x.computed, root->y.computed, root->width.computed, root->height.computed); ctx->pushState(); renderer->setStateForItem(ctx, item); - Geom::Matrix tempmat (root->c2p); + Geom::Affine tempmat (root->c2p); ctx->transform(&tempmat); sp_group_render(item, ctx); ctx->popState(); @@ -452,8 +457,23 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx) Geom::OptRect bbox = item->getBounds(item->i2d_affine(), SPItem::RENDERING_BBOX); - if (!bbox) // no bbox, e.g. empty group + // no bbox, e.g. empty group + if (!bbox) { return; + } + + Geom::Rect docrect(Geom::Rect(Geom::Point(0, 0), item->document->getDimensions())); + Geom::Rect bboxrect(Geom::Rect(Geom::Point(bbox->min()[Geom::X], bbox->min()[Geom::Y]), Geom::Point(bbox->max()[Geom::X], bbox->max()[Geom::Y]))); + + Geom::OptRect _bbox = Geom::intersect(docrect, bboxrect); + + // assign the object dimension clipped on the document, no need to draw on area not on canvas + bbox = _bbox; + + // no bbox, e.g. empty group + if (!bbox) { + return; + } // The width and height of the bitmap in pixels unsigned width = (unsigned) floor ((bbox->max()[Geom::X] - bbox->min()[Geom::X]) * (res / PX_PER_IN)); @@ -477,15 +497,15 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx) // Calculate the matrix that will be applied to the image so that it exactly overlaps the source objects // Matix to put bitmap in correct place on document - Geom::Matrix t_on_document = (Geom::Matrix)(Geom::Scale (scale_x, -scale_y)) * - (Geom::Matrix)(Geom::Translate (shift_x, shift_y)); + Geom::Affine t_on_document = (Geom::Affine)(Geom::Scale (scale_x, -scale_y)) * + (Geom::Affine)(Geom::Translate (shift_x, shift_y)); // ctx matrix already includes item transformation. We must substract. - Geom::Matrix t_item = item->i2d_affine (); - Geom::Matrix t = t_on_document * t_item.inverse(); + Geom::Affine t_item = item->i2d_affine (); + Geom::Affine t = t_on_document * t_item.inverse(); // Do the export - SPDocument *document = SP_OBJECT(item)->document; + SPDocument *document = item->document; GSList *items = NULL; items = g_slist_append(items, item); @@ -499,8 +519,9 @@ static void sp_asbitmap_render(SPItem *item, CairoRenderContext *ctx) unsigned int w = gdk_pixbuf_get_width(pb); unsigned int h = gdk_pixbuf_get_height(pb); unsigned int rs = gdk_pixbuf_get_rowstride(pb); - ctx->renderImage (px, w, h, rs, &t, SP_OBJECT_STYLE (item)); - gdk_pixbuf_unref (pb); + ctx->renderImage(px, w, h, rs, &t, item->style); + gdk_pixbuf_unref(pb); + pb = 0; } g_slist_free (items); } @@ -513,7 +534,7 @@ static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx) return; } - SPStyle* style = SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if((ctx->getFilterToBitmap() == TRUE) && (style->filter.set != 0)) { return sp_asbitmap_render(item, ctx); } @@ -549,13 +570,13 @@ static void sp_item_invoke_render(SPItem *item, CairoRenderContext *ctx) void CairoRenderer::setStateForItem(CairoRenderContext *ctx, SPItem const *item) { - SPStyle const *style = SP_OBJECT_STYLE(item); + SPStyle const *style = item->style; ctx->setStateForStyle(style); CairoRenderState *state = ctx->getCurrentState(); state->clip_path = item->clip_ref->getObject(); state->mask = item->mask_ref->getObject(); - state->item_transform = Geom::Matrix (item->transform); + state->item_transform = Geom::Affine (item->transform); // If parent_has_userspace is true the parent state's transform // has to be used for the mask's/clippath's context. @@ -567,8 +588,8 @@ CairoRenderer::setStateForItem(CairoRenderContext *ctx, SPItem const *item) TRACE(("setStateForItem opacity: %f\n", state->opacity)); } -void -CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) +// TODO change this to accept a const SPItem: +void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) { if ( _omitText && (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) ) { // skip text if _omitText is true @@ -586,7 +607,7 @@ CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item) state->merge_opacity = FALSE; ctx->pushLayer(); } - Geom::Matrix tempmat (item->transform); + Geom::Affine tempmat (item->transform); ctx->transform(&tempmat); sp_item_invoke_render(item, ctx); @@ -637,7 +658,7 @@ CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool page if (ctx->_vector_based_target) high *= PT_PER_PX; - Geom::Matrix tp(Geom::Translate(-d.x0 * (ctx->_vector_based_target ? PX_PER_PT : 1.0), + Geom::Affine tp(Geom::Translate(-d.x0 * (ctx->_vector_based_target ? PX_PER_PT : 1.0), (d.y1 - high) * (ctx->_vector_based_target ? PX_PER_PT : 1.0))); ctx->transform(&tp); } @@ -659,11 +680,11 @@ CairoRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp) CairoRenderContext::CairoRenderMode saved_mode = ctx->getRenderMode(); ctx->setRenderMode(CairoRenderContext::RENDER_MODE_CLIP); - Geom::Matrix saved_ctm; + Geom::Affine saved_ctm; if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { //SP_PRINT_DRECT("clipd", cp->display->bbox); NRRect clip_bbox(cp->display->bbox); - Geom::Matrix t(Geom::Scale(clip_bbox.x1 - clip_bbox.x0, clip_bbox.y1 - clip_bbox.y0)); + Geom::Affine t(Geom::Scale(clip_bbox.x1 - clip_bbox.x0, clip_bbox.y1 - clip_bbox.y0)); t[4] = clip_bbox.x0; t[5] = clip_bbox.y0; t *= ctx->getCurrentState()->transform; @@ -672,20 +693,21 @@ CairoRenderer::applyClipPath(CairoRenderContext *ctx, SPClipPath const *cp) } TRACE(("BEGIN clip\n")); - SPObject *co = SP_OBJECT(cp); - for ( SPObject *child = co->firstChild() ; child; child = child->getNext() ) { + SPObject const *co = cp; + for ( SPObject const *child = co->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM(child)) { - SPItem *item = SP_ITEM(child); + SPItem const *item = SP_ITEM(child); // combine transform of the item in clippath and the item using clippath: - Geom::Matrix tempmat (item->transform); + Geom::Affine tempmat (item->transform); tempmat = tempmat * (ctx->getCurrentState()->item_transform); // render this item in clippath ctx->pushState(); ctx->transform(&tempmat); setStateForItem(ctx, item); - sp_item_invoke_render(item, ctx); + // TODO fix this call to accept const items + sp_item_invoke_render(const_cast<SPItem *>(item), ctx); ctx->popState(); } } @@ -715,7 +737,7 @@ CairoRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask) NRRect mask_bbox(mask->display->bbox); // TODO: should the bbox be transformed if maskUnits != userSpaceOnUse ? if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix t(Geom::Scale(mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0)); + Geom::Affine t(Geom::Scale(mask_bbox.x1 - mask_bbox.x0, mask_bbox.y1 - mask_bbox.y0)); t[4] = mask_bbox.x0; t[5] = mask_bbox.y0; t *= ctx->getCurrentState()->transform; @@ -730,11 +752,12 @@ CairoRenderer::applyMask(CairoRenderContext *ctx, SPMask const *mask) ctx->pushState(); TRACE(("BEGIN mask\n")); - SPObject *co = SP_OBJECT(mask); - for ( SPObject *child = co->firstChild() ; child; child = child->getNext() ) { + SPObject const *co = mask; + for ( SPObject const *child = co->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM(child)) { - SPItem *item = SP_ITEM(child); - renderItem(ctx, item); + SPItem const *item = SP_ITEM(child); + // TODO fix const correctness: + renderItem(ctx, const_cast<SPItem*>(item)); } } TRACE(("END mask\n")); diff --git a/src/extension/internal/emf-win32-inout.cpp b/src/extension/internal/emf-win32-inout.cpp index a1771de8d..979be1b63 100644 --- a/src/extension/internal/emf-win32-inout.cpp +++ b/src/extension/internal/emf-win32-inout.cpp @@ -53,11 +53,13 @@ #define PS_JOIN_MASK (PS_JOIN_BEVEL|PS_JOIN_MITER|PS_JOIN_ROUND) #endif +#define DPA 0x00A000C9 // TernaryRasterOperation namespace Inkscape { namespace Extension { namespace Internal { +static float device_scale = DEVICESCALE; EmfWin32::EmfWin32 (void) // The null constructor { @@ -102,7 +104,7 @@ emf_print_document_to_file(SPDocument *doc, gchar const *filename) /* Create new arena */ mod->base = SP_ITEM(doc->getRoot()); mod->arena = NRArena::create(); - mod->dkey = sp_item_display_key_new(1); + mod->dkey = SPItem::display_key_new(1); mod->root = mod->base->invoke_show(mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY); /* Print document */ ret = mod->begin(doc); @@ -205,7 +207,7 @@ typedef struct emf_callback_data { static void output_style(PEMF_CALLBACK_DATA d, int iType) { - SVGOStringStream tmp_id; +// SVGOStringStream tmp_id; SVGOStringStream tmp_style; char tmp[1024] = {0}; @@ -215,8 +217,8 @@ output_style(PEMF_CALLBACK_DATA d, int iType) float stroke_rgb[3]; sp_color_get_rgb_floatv(&(d->dc[d->level].style.stroke.value.color), stroke_rgb); - tmp_id << "\n\tid=\"" << (d->id++) << "\""; - *(d->outsvg) += tmp_id.str().c_str(); +// tmp_id << "\n\tid=\"" << (d->id++) << "\""; +// *(d->outsvg) += tmp_id.str().c_str(); *(d->outsvg) += "\n\tstyle=\""; if (iType == EMR_STROKEPATH || !d->dc[d->level].fill_set) { tmp_style << "fill:none;"; @@ -318,7 +320,7 @@ pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py) double ppy = _pix_y_to_point(d, py); double x = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21 + d->dc[d->level].worldTransform.eDx; - x *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : DEVICESCALE; + x *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : device_scale; return x; } @@ -330,7 +332,7 @@ pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py) double ppy = _pix_y_to_point(d, py); double y = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22 + d->dc[d->level].worldTransform.eDy; - y *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : DEVICESCALE; + y *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : device_scale; return y; } @@ -342,9 +344,9 @@ pix_to_size_point(PEMF_CALLBACK_DATA d, double px) double ppy = 0; double dx = ppx * d->dc[d->level].worldTransform.eM11 + ppy * d->dc[d->level].worldTransform.eM21; - dx *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : DEVICESCALE; + dx *= d->dc[d->level].ScaleOutX ? d->dc[d->level].ScaleOutX : device_scale; double dy = ppx * d->dc[d->level].worldTransform.eM12 + ppy * d->dc[d->level].worldTransform.eM22; - dy *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : DEVICESCALE; + dy *= d->dc[d->level].ScaleOutY ? d->dc[d->level].ScaleOutY : device_scale; double tmp = sqrt(dx * dx + dy * dy); return tmp; @@ -664,7 +666,7 @@ select_font(PEMF_CALLBACK_DATA d, int index) g_free(d->dc[d->level].tstyle.font_family.value); d->dc[d->level].tstyle.font_family.value = (gchar *) g_utf16_to_utf8( (gunichar2*) pEmr->elfw.elfLogFont.lfFaceName, -1, NULL, NULL, NULL ); - d->dc[d->level].style.text_transform.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10; + d->dc[d->level].style.baseline_shift.value = ((pEmr->elfw.elfLogFont.lfEscapement + 3600) % 3600) / 10; // use baseline_shift instead of text_transform to avoid overflow } static void @@ -763,24 +765,28 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * d->xDPI = 2540; d->yDPI = 2540; - d->dc[d->level].PixelsInX = pEmr->rclFrame.right - pEmr->rclFrame.left; - d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom - pEmr->rclFrame.top; + d->dc[d->level].PixelsInX = pEmr->rclFrame.right; // - pEmr->rclFrame.left; + d->dc[d->level].PixelsInY = pEmr->rclFrame.bottom; // - pEmr->rclFrame.top; d->MMX = d->dc[d->level].PixelsInX / 100.0; d->MMY = d->dc[d->level].PixelsInY / 100.0; d->dc[d->level].PixelsOutX = d->MMX * PX_PER_MM; d->dc[d->level].PixelsOutY = d->MMY * PX_PER_MM; + + // calculate ratio of Inkscape dpi/device dpi + if (pEmr->szlMillimeters.cx && pEmr->szlDevice.cx) + device_scale = PX_PER_MM*pEmr->szlMillimeters.cx/pEmr->szlDevice.cx; tmp_outsvg << " width=\"" << d->MMX << "mm\"\n" << - " height=\"" << d->MMY << "mm\"\n"; - tmp_outsvg << - " id=\"" << (d->id++) << "\">\n"; + " height=\"" << d->MMY << "mm\">\n"; +// tmp_outsvg << +// " id=\"" << (d->id++) << "\">\n"; - tmp_outsvg << - "<g\n" << - " id=\"" << (d->id++) << "\">\n"; + tmp_outsvg << "<g>\n"; +// "<g\n" << +// " id=\"" << (d->id++) << "\">\n"; if (pEmr->nHandles) { d->n_obj = pEmr->nHandles; @@ -1049,8 +1055,8 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * d->dc[d->level].ScaleOutY = (double) d->dc[d->level].PixelsOutY / (double) d->dc[d->level].sizeView.cy; } else { - d->dc[d->level].ScaleOutX = DEVICESCALE; - d->dc[d->level].ScaleOutY = DEVICESCALE; + d->dc[d->level].ScaleOutX = device_scale; + d->dc[d->level].ScaleOutY = device_scale; } break; @@ -1100,8 +1106,8 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * d->dc[d->level].ScaleOutY = (double) d->dc[d->level].PixelsOutY / (double) d->dc[d->level].sizeView.cy; } else { - d->dc[d->level].ScaleOutX = DEVICESCALE; - d->dc[d->level].ScaleOutY = DEVICESCALE; + d->dc[d->level].ScaleOutX = device_scale; + d->dc[d->level].ScaleOutY = device_scale; } break; @@ -1536,8 +1542,42 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * break; } case EMR_ROUNDRECT: + { dbg_str << "<!-- EMR_ROUNDRECT -->\n"; + + PEMRROUNDRECT pEmr = (PEMRROUNDRECT) lpEMFR; + RECTL rc = pEmr->rclBox; + SIZEL corner = pEmr->szlCorner; + double f = 4.*(sqrt(2) - 1)/3; + + double l = pix_to_x_point(d, rc.left, rc.top); + double t = pix_to_y_point(d, rc.left, rc.top); + double r = pix_to_x_point(d, rc.right, rc.bottom); + double b = pix_to_y_point(d, rc.right, rc.bottom); + double cnx = pix_to_size_point(d, corner.cx/2); + double cny = pix_to_size_point(d, corner.cy/2); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "d=\""; + tmp_rectangle << "\n\tM " << l << ", " << t + cny << " "; + tmp_rectangle << "\n\tC " << l << ", " << t + (1-f)*cny << " " << l + (1-f)*cnx << ", " << t << " " << l + cnx << ", " << t << " "; + tmp_rectangle << "\n\tL " << r - cnx << ", " << t << " "; + tmp_rectangle << "\n\tC " << r - (1-f)*cnx << ", " << t << " " << r << ", " << t + (1-f)*cny << " " << r << ", " << t + cny << " "; + tmp_rectangle << "\n\tL " << r << ", " << b - cny << " "; + tmp_rectangle << "\n\tC " << r << ", " << b - (1-f)*cny << " " << r - (1-f)*cnx << ", " << b << " " << r - cnx << ", " << b << " "; + tmp_rectangle << "\n\tL " << l + cnx << ", " << b << " "; + tmp_rectangle << "\n\tC " << l + (1-f)*cnx << ", " << b << " " << l << ", " << b - (1-f)*cny << " " << l << ", " << b - cny << " "; + tmp_rectangle << "\n\tz"; + assert_empty_path(d, "EMR_ROUNDRECT"); + + *(d->outsvg) += " <path "; + output_style(d, lpEMFR->iType); + *(d->outsvg) += "\n\t"; + *(d->outsvg) += tmp_rectangle.str().c_str(); + *(d->outsvg) += " \" /> \n"; + *(d->path) = ""; break; + } case EMR_ARC: dbg_str << "<!-- EMR_ARC -->\n"; break; @@ -1700,8 +1740,36 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * dbg_str << "<!-- EMR_EXTSELECTCLIPRGN -->\n"; break; case EMR_BITBLT: + { dbg_str << "<!-- EMR_BITBLT -->\n"; + + PEMRBITBLT pEmr = (PEMRBITBLT) lpEMFR; + if (pEmr->dwRop == DPA) { + // should be an application of a DIBPATTERNBRUSHPT, use a solid color instead + double l = pix_to_x_point( d, pEmr->xDest, pEmr->yDest); + double t = pix_to_y_point( d, pEmr->xDest, pEmr->yDest); + double r = pix_to_x_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest); + double b = pix_to_y_point( d, pEmr->xDest + pEmr->cxDest, pEmr->yDest + pEmr->cyDest); + + SVGOStringStream tmp_rectangle; + tmp_rectangle << "d=\""; + tmp_rectangle << "\n\tM " << l << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << t << " "; + tmp_rectangle << "\n\tL " << r << " " << b << " "; + tmp_rectangle << "\n\tL " << l << " " << b << " "; + tmp_rectangle << "\n\tz"; + + assert_empty_path(d, "EMR_BITBLT"); + + *(d->outsvg) += " <path "; + output_style(d, lpEMFR->iType); + *(d->outsvg) += "\n\t"; + *(d->outsvg) += tmp_rectangle.str().c_str(); + *(d->outsvg) += " \" /> \n"; + *(d->path) = ""; + } break; + } case EMR_STRETCHBLT: dbg_str << "<!-- EMR_STRETCHBLT -->\n"; break; @@ -1750,8 +1818,13 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * } if (!(d->dc[d->level].textAlign & TA_BOTTOM)) - y1 += fabs(d->dc[d->level].style.font_size.computed); - + if (d->dc[d->level].style.baseline_shift.value) { + x1 += std::sin(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); + y1 += std::cos(d->dc[d->level].style.baseline_shift.value*M_PI/180.0)*fabs(d->dc[d->level].style.font_size.computed); + } + else + y1 += fabs(d->dc[d->level].style.font_size.computed); + double x = pix_to_x_point(d, x1, y1); double y = pix_to_y_point(d, x1, y1); @@ -1761,28 +1834,28 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * (gchar *) g_utf16_to_utf8( (gunichar2 *) wide_text, pEmr->emrtext.nChars, NULL, NULL, NULL ); if (ansi_text) { - gchar *p = ansi_text; - while (*p) { - if (*p < 32 || *p >= 127) { - g_free(ansi_text); - ansi_text = g_strdup(""); - break; - } - p++; - } +// gchar *p = ansi_text; +// while (*p) { +// if (*p < 32 || *p >= 127) { +// g_free(ansi_text); +// ansi_text = g_strdup(""); +// break; +// } +// p++; +// } SVGOStringStream ts; gchar *escaped_text = g_markup_escape_text(ansi_text, -1); - float text_rgb[3]; - sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb ); +// float text_rgb[3]; +// sp_color_get_rgb_floatv( &(d->dc[d->level].style.fill.value.color), text_rgb ); - if (!d->dc[d->level].textColorSet) { - d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]), - SP_COLOR_F_TO_U(text_rgb[1]), - SP_COLOR_F_TO_U(text_rgb[2])); - } +// if (!d->dc[d->level].textColorSet) { +// d->dc[d->level].textColor = RGB(SP_COLOR_F_TO_U(text_rgb[0]), +// SP_COLOR_F_TO_U(text_rgb[1]), +// SP_COLOR_F_TO_U(text_rgb[2])); +// } char tmp[128]; snprintf(tmp, 127, @@ -1800,13 +1873,13 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * assert_empty_path(d, "EMR_EXTTEXTOUTW"); ts << " <text\n"; - ts << " id=\"" << (d->id++) << "\"\n"; +// ts << " id=\"" << (d->id++) << "\"\n"; ts << " xml:space=\"preserve\"\n"; ts << " x=\"" << x << "\"\n"; ts << " y=\"" << y << "\"\n"; - if (d->dc[d->level].style.text_transform.value) { + if (d->dc[d->level].style.baseline_shift.value) { ts << " transform=\"" - << "rotate(-" << d->dc[d->level].style.text_transform.value + << "rotate(-" << d->dc[d->level].style.baseline_shift.value << " " << x << " " << y << ")" << "\"\n"; } @@ -2053,8 +2126,17 @@ myEnhMetaFileProc(HDC /*hDC*/, HANDLETABLE * /*lpHTable*/, ENHMETARECORD const * dbg_str << "<!-- EMR_CREATEMONOBRUSH -->\n"; break; case EMR_CREATEDIBPATTERNBRUSHPT: + { dbg_str << "<!-- EMR_CREATEDIBPATTERNBRUSHPT -->\n"; + + PEMRCREATEDIBPATTERNBRUSHPT pEmr = (PEMRCREATEDIBPATTERNBRUSHPT) lpEMFR; + int index = pEmr->ihBrush; + + EMRCREATEDIBPATTERNBRUSHPT *pBrush = + (EMRCREATEDIBPATTERNBRUSHPT *) malloc( sizeof(EMRCREATEDIBPATTERNBRUSHPT) ); + insert_object(d, index, EMR_CREATEDIBPATTERNBRUSHPT, (ENHMETARECORD *) pBrush); break; + } case EMR_EXTCREATEPEN: { dbg_str << "<!-- EMR_EXTCREATEPEN -->\n"; @@ -2347,7 +2429,7 @@ EmfWin32::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) // std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl; - SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), d.outsvg->length(), TRUE); + SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE); delete d.outsvg; delete d.path; diff --git a/src/extension/internal/emf-win32-print.cpp b/src/extension/internal/emf-win32-print.cpp index 6be48e44c..503a13d09 100644 --- a/src/extension/internal/emf-win32-print.cpp +++ b/src/extension/internal/emf-win32-print.cpp @@ -310,7 +310,7 @@ PrintEmfWin32::destroy_brush() void -PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Matrix &transform) +PrintEmfWin32::create_pen(SPStyle const *style, const Geom::Affine &transform) { if (style) { float rgb[3]; @@ -459,12 +459,12 @@ PrintEmfWin32::flush_fill() } unsigned int -PrintEmfWin32::bind(Inkscape::Extension::Print * /*mod*/, Geom::Matrix const *transform, float /*opacity*/) +PrintEmfWin32::bind(Inkscape::Extension::Print * /*mod*/, Geom::Affine const *transform, float /*opacity*/) { - Geom::Matrix tr = *transform; + Geom::Affine tr = *transform; if (m_tr_stack.size()) { - Geom::Matrix tr_top = m_tr_stack.top(); + Geom::Affine tr_top = m_tr_stack.top(); m_tr_stack.push(tr * tr_top); } else { m_tr_stack.push(tr); @@ -482,12 +482,12 @@ PrintEmfWin32::release(Inkscape::Extension::Print * /*mod*/) unsigned int PrintEmfWin32::fill(Inkscape::Extension::Print * /*mod*/, - Geom::PathVector const &pathv, Geom::Matrix const * /*transform*/, SPStyle const *style, + Geom::PathVector const &pathv, Geom::Affine const * /*transform*/, SPStyle const *style, NRRect const * /*pbox*/, NRRect const * /*dbox*/, NRRect const * /*bbox*/) { if (!hdc) return 0; - Geom::Matrix tf = m_tr_stack.top(); + Geom::Affine tf = m_tr_stack.top(); flush_fill(); // flush any pending fills @@ -511,12 +511,12 @@ PrintEmfWin32::fill(Inkscape::Extension::Print * /*mod*/, unsigned int PrintEmfWin32::stroke (Inkscape::Extension::Print * /*mod*/, - Geom::PathVector const &pathv, const Geom::Matrix * /*transform*/, const SPStyle *style, + Geom::PathVector const &pathv, const Geom::Affine * /*transform*/, const SPStyle *style, const NRRect * /*pbox*/, const NRRect * /*dbox*/, const NRRect * /*bbox*/) { if (!hdc) return 0; - Geom::Matrix tf = m_tr_stack.top(); + Geom::Affine tf = m_tr_stack.top(); stroke_and_fill = ( pathv == fill_pathv ); @@ -550,7 +550,7 @@ PrintEmfWin32::stroke (Inkscape::Extension::Print * /*mod*/, bool -PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Matrix &transform) +PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Affine &transform) { Geom::PathVector pv = pathv_to_linear_and_cubic_beziers( pathv * transform ); @@ -681,24 +681,24 @@ PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Mat if (moves == 1 && moves+lines == nodes && closed) { polygon = true; - if (nodes==5) { - if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && - lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) - { - rectangle = true; - } - } +// if (nodes==5) { // disable due to LP Bug 407394 +// if (lpPoints[0].x == lpPoints[3].x && lpPoints[1].x == lpPoints[2].x && +// lpPoints[0].y == lpPoints[1].y && lpPoints[2].y == lpPoints[3].y) +// { +// rectangle = true; +// } +// } } else if (moves == 1 && nodes == 5 && moves+curves == nodes && closed) { - if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && - lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && - lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && - lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && - lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && - lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) - { - ellipse = true; - } +// if (lpPoints[0].x == lpPoints[1].x && lpPoints[1].x == lpPoints[11].x && +// lpPoints[5].x == lpPoints[6].x && lpPoints[6].x == lpPoints[7].x && +// lpPoints[2].x == lpPoints[10].x && lpPoints[3].x == lpPoints[9].x && lpPoints[4].x == lpPoints[8].x && +// lpPoints[2].y == lpPoints[3].y && lpPoints[3].y == lpPoints[4].y && +// lpPoints[8].y == lpPoints[9].y && lpPoints[9].y == lpPoints[10].y && +// lpPoints[5].y == lpPoints[1].y && lpPoints[6].y == lpPoints[0].y && lpPoints[7].y == lpPoints[11].y) +// { // disable due to LP Bug 407394 +// ellipse = true; +// } } if (polygon || ellipse) { @@ -746,7 +746,7 @@ PrintEmfWin32::print_simple_shape(Geom::PathVector const &pathv, const Geom::Mat } unsigned int -PrintEmfWin32::print_pathv(Geom::PathVector const &pathv, const Geom::Matrix &transform) +PrintEmfWin32::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) { simple_shape = print_simple_shape(pathv, transform); @@ -863,6 +863,8 @@ PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom if (!hdc) return 0; HFONT hfont = NULL; + Geom::Affine tf = m_tr_stack.top(); + double rot = 1800.0*std::atan2(tf[1], tf[0])/M_PI; // 0.1 degree rotation #ifdef USE_PANGO_WIN32 /* @@ -883,8 +885,8 @@ PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI; lf->lfWidth = 0; - lf->lfEscapement = 0; - lf->lfOrientation = 0; + lf->lfEscapement = rot; + lf->lfOrientation = rot; lf->lfWeight = style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN : style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT : @@ -919,8 +921,8 @@ PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom lf->lfHeight = style->font_size.computed * IN_PER_PX * dwDPI; lf->lfWidth = 0; - lf->lfEscapement = 0; - lf->lfOrientation = 0; + lf->lfEscapement = rot; + lf->lfOrientation = rot; lf->lfWeight = style->font_weight.computed == SP_CSS_FONT_WEIGHT_100 ? FW_THIN : style->font_weight.computed == SP_CSS_FONT_WEIGHT_200 ? FW_EXTRALIGHT : @@ -964,8 +966,6 @@ PrintEmfWin32::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom // Transparent text background SetBkMode(hdc, TRANSPARENT); - Geom::Matrix tf = m_tr_stack.top(); - p = p * tf; p[Geom::X] = (p[Geom::X] * IN_PER_PX * dwDPI); p[Geom::Y] = (p[Geom::Y] * IN_PER_PX * dwDPI); diff --git a/src/extension/internal/emf-win32-print.h b/src/extension/internal/emf-win32-print.h index a0f26abb5..a9f639bcd 100644 --- a/src/extension/internal/emf-win32-print.h +++ b/src/extension/internal/emf-win32-print.h @@ -38,15 +38,15 @@ class PrintEmfWin32 : public Inkscape::Extension::Implementation::Implementation HBRUSH hbrush, hbrushOld; HPEN hpen, hpenOld; - std::stack<Geom::Matrix> m_tr_stack; + std::stack<Geom::Affine> m_tr_stack; Geom::PathVector fill_pathv; - Geom::Matrix fill_transform; + Geom::Affine fill_transform; bool stroke_and_fill; bool fill_only; bool simple_shape; - unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Matrix &transform); - bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Matrix &transform); + unsigned int print_pathv (Geom::PathVector const &pathv, const Geom::Affine &transform); + bool print_simple_shape (Geom::PathVector const &pathv, const Geom::Affine &transform); public: PrintEmfWin32 (void); @@ -59,13 +59,13 @@ public: virtual unsigned int finish (Inkscape::Extension::Print * module); /* Rendering methods */ - virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Matrix const *transform, float opacity); + virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const *transform, float opacity); virtual unsigned int release(Inkscape::Extension::Print *module); virtual unsigned int fill (Inkscape::Extension::Print * module, - Geom::PathVector const &pathv, const Geom::Matrix *ctm, const SPStyle *style, + Geom::PathVector const &pathv, const Geom::Affine *ctm, const SPStyle *style, const NRRect *pbox, const NRRect *dbox, const NRRect *bbox); virtual unsigned int stroke (Inkscape::Extension::Print * module, - Geom::PathVector const &pathv, const Geom::Matrix *transform, const SPStyle *style, + Geom::PathVector const &pathv, const Geom::Affine *transform, const SPStyle *style, const NRRect *pbox, const NRRect *dbox, const NRRect *bbox); virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); virtual unsigned int text(Inkscape::Extension::Print *module, char const *text, @@ -79,7 +79,7 @@ protected: void destroy_brush(); - void create_pen(SPStyle const *style, const Geom::Matrix &transform); + void create_pen(SPStyle const *style, const Geom::Affine &transform); void destroy_pen(); diff --git a/src/extension/internal/filter/abc.h b/src/extension/internal/filter/abc.h new file mode 100755 index 000000000..8368d3f3b --- /dev/null +++ b/src/extension/internal/filter/abc.h @@ -0,0 +1,878 @@ +#ifndef __INKSCAPE_EXTENSION_INTERNAL_FILTER_ABC_H__ +#define __INKSCAPE_EXTENSION_INTERNAL_FILTER_ABC_H__ +/* Change the 'ABC' above to be your file name */ + +/* + * Copyright (C) 2011 Authors: + * Ivan Louette (filters) + * Nicolas Dufour (UI) <nicoduf@yahoo.fr> + * + * Basic filters + * Blur + * Clean edges + * Color shift + * Diffuse light + * Feather + * Matte jelly + * Noise fill + * Outline + * Roughen + * Silhouette + * Specular light + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +/* ^^^ Change the copyright to be you and your e-mail address ^^^ */ + +#include "filter.h" + +#include "extension/internal/clear-n_.h" +#include "extension/system.h" +#include "extension/extension.h" + +namespace Inkscape { +namespace Extension { +namespace Internal { +namespace Filter { + +/** + \brief Custom predefined Blur filter. + + Simple horizontal and vertical blur + + Filter's parameters: + * Horizontal blur (0.01->100., default 2) -> blur (stdDeviation) + * Vertical blur (0.01->100., default 2) -> blur (stdDeviation) +*/ + +class Blur : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Blur ( ) : Filter() { }; + virtual ~Blur ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Blur, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.Blur</id>\n" + "<param name=\"hblur\" gui-text=\"" N_("Horizontal blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">2</param>\n" + "<param name=\"vblur\" gui-text=\"" N_("Vertical blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">2</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Simple vertical and horizontal blur effect") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Blur()); + }; + +}; + +gchar const * +Blur::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream hblur; + std::ostringstream vblur; + + hblur << ext->get_param_float("hblur"); + vblur << ext->get_param_float("vblur"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Blur, custom\">\n" + "<feGaussianBlur stdDeviation=\"%s %s\" result=\"blur\" />\n" + "</filter>\n", hblur.str().c_str(), vblur.str().c_str()); + + return _filter; +}; /* Blur filter */ + +/** + \brief Custom predefined Clean edges filter. + + Removes or decreases glows and jaggeries around objects edges after applying some filters + + Filter's parameters: + * Strength (0.01->2., default 0.4) -> blur (stdDeviation) +*/ + +class CleanEdges : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + CleanEdges ( ) : Filter() { }; + virtual ~CleanEdges ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Clean edges, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.CleanEdges</id>\n" + "<param name=\"blur\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"2.00\">0.4</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Removes or decreases glows and jaggeries around objects edges after applying some filters") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new CleanEdges()); + }; + +}; + +gchar const * +CleanEdges::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream blur; + + blur << ext->get_param_float("blur"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Clean edges, custom\">\n" + "<feGaussianBlur stdDeviation=\"%s\" result=\"blur\" />\n" + "<feComposite in=\"SourceGraphic\" in2=\"blur\" operator=\"in\" result=\"composite1\" />\n" + "<feComposite in=\"composite1\" in2=\"composite1\" k2=\"1\" operator=\"in\" result=\"composite2\" />\n" + "</filter>\n", blur.str().c_str()); + + return _filter; +}; /* CleanEdges filter */ + + +/** + \brief Custom predefined Color shift filter. + + Rotate and desaturate hue + + Filter's parameters: + * Shift (0->360, default 330) -> color1 (values) + * Saturation (0.->1., default 0.6) -> color2 (values) +*/ + +class ColorShift : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + ColorShift ( ) : Filter() { }; + virtual ~ColorShift ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Color shift, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.ColorShift</id>\n" + "<param name=\"shift\" gui-text=\"" N_("Shift (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">330</param>\n" + "<param name=\"sat\" gui-text=\"" N_("Saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.\" max=\"1\">0.6</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Rotate and desaturate hue") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new ColorShift()); + }; + +}; + +gchar const * +ColorShift::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream shift; + std::ostringstream sat; + + shift << ext->get_param_int("shift"); + sat << ext->get_param_float("sat"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Color shift, custom\">\n" + "<feColorMatrix type=\"hueRotate\" values=\"%s\" result=\"color1\" />\n" + "<feColorMatrix type=\"saturate\" values=\"%s\" result=\"color2\" />\n" + "</filter>\n", shift.str().c_str(), sat.str().c_str()); + + return _filter; +}; /* ColorShift filter */ + +/** + \brief Custom predefined Diffuse light filter. + + Basic diffuse bevel to use for building textures + + Filter's parameters: + * Smoothness (0.->10., default 6.) -> blur (stdDeviation) + * Elevation (0->360, default 25) -> feDistantLight (elevation) + * Azimuth (0->360, default 235) -> feDistantLight (azimuth) + * Lightning color (guint, default -1 [white]) -> diffuse (lighting-color) +*/ + +class DiffuseLight : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + DiffuseLight ( ) : Filter() { }; + virtual ~DiffuseLight ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Diffuse light, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.DiffuseLight</id>\n" + "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"10\">6</param>\n" + "<param name=\"elevation\" gui-text=\"" N_("Elevation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">25</param>\n" + "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">235</param>\n" + "<param name=\"color\" gui-text=\"" N_("Lightning color") "\" type=\"color\">-1</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Basic diffuse bevel to use for building textures") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new DiffuseLight()); + }; + +}; + +gchar const * +DiffuseLight::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream smooth; + std::ostringstream elevation; + std::ostringstream azimuth; + std::ostringstream r; + std::ostringstream g; + std::ostringstream b; + std::ostringstream a; + + smooth << ext->get_param_float("smooth"); + elevation << ext->get_param_int("elevation"); + azimuth << ext->get_param_int("azimuth"); + guint32 color = ext->get_param_color("color"); + + r << ((color >> 24) & 0xff); + g << ((color >> 16) & 0xff); + b << ((color >> 8) & 0xff); + a << (color & 0xff) / 255.0F; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Diffuse light, custom\">\n" + "<feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"%s\" result=\"blur\" />\n" + "<feDiffuseLighting diffuseConstant=\"1\" surfaceScale=\"10\" lighting-color=\"rgb(%s,%s,%s)\" result=\"diffuse\">\n" + "<feDistantLight elevation=\"%s\" azimuth=\"%s\" />\n" + "</feDiffuseLighting>\n" + "<feComposite in=\"diffuse\" in2=\"diffuse\" operator=\"arithmetic\" k1=\"1\" result=\"composite1\" />\n" + "<feComposite in=\"composite1\" in2=\"SourceGraphic\" k1=\"%s\" operator=\"arithmetic\" k3=\"1\" result=\"composite2\" />\n" + "</filter>\n", smooth.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), elevation.str().c_str(), azimuth.str().c_str(), a.str().c_str()); + + return _filter; +}; /* DiffuseLight filter */ + +/** + \brief Custom predefined Feather filter. + + Blurred mask on the edge without altering the contents + + Filter's parameters: + * Strength (0.01->100., default 5) -> blur (stdDeviation) +*/ + +class Feather : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Feather ( ) : Filter() { }; + virtual ~Feather ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Feather, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.Feather</id>\n" + "<param name=\"blur\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">5</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Blurred mask on the edge without altering the contents") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Feather()); + }; + +}; + +gchar const * +Feather::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream blur; + + blur << ext->get_param_float("blur"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Black outline, custom\">\n" + "<feGaussianBlur stdDeviation=\"%s\" result=\"blur\" />\n" + "<feComposite in=\"SourceGraphic\" in2=\"blur\" operator=\"atop\" result=\"composite1\" />\n" + "<feComposite in2=\"composite1\" operator=\"in\" result=\"composite2\" />\n" + "<feComposite in2=\"composite2\" operator=\"in\" result=\"composite3\" />\n" + "</filter>\n", blur.str().c_str()); + + return _filter; +}; /* Feather filter */ + +/** + \brief Custom predefined Matte jelly filter. + + Bulging, matte jelly covering + + Filter's parameters: + * Smoothness (0.0->10., default 7.) -> blur (stdDeviation) + * Brightness (0.0->5., default .9) -> specular (specularConstant) + * Elevation (0->360, default 60) -> feDistantLight (elevation) + * Azimuth (0->360, default 225) -> feDistantLight (azimuth) + * Lightning color (guint, default -1 [white]) -> specular (lighting-color) +*/ + +class MatteJelly : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + MatteJelly ( ) : Filter() { }; + virtual ~MatteJelly ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Matte jelly, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.MatteJelly</id>\n" + "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"10.00\">7</param>\n" + "<param name=\"bright\" gui-text=\"" N_("Brightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"5.00\">0.9</param>\n" + "<param name=\"elevation\" gui-text=\"" N_("Elevation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">60</param>\n" + "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">225</param>\n" + "<param name=\"color\" gui-text=\"" N_("Lightning color") "\" type=\"color\">-1</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Bulging, matte jelly covering") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new MatteJelly()); + }; + +}; + +gchar const * +MatteJelly::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream smooth; + std::ostringstream bright; + std::ostringstream elevation; + std::ostringstream azimuth; + std::ostringstream r; + std::ostringstream g; + std::ostringstream b; + std::ostringstream a; + + smooth << ext->get_param_float("smooth"); + bright << ext->get_param_float("bright"); + elevation << ext->get_param_int("elevation"); + azimuth << ext->get_param_int("azimuth"); + guint32 color = ext->get_param_color("color"); + + r << ((color >> 24) & 0xff); + g << ((color >> 16) & 0xff); + b << ((color >> 8) & 0xff); + a << (color & 0xff) / 255.0F; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Matte jelly, custom\">\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.85 0\" result=\"color\" in=\"SourceGraphic\" />\n" + "<feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"%s\" result=\"blur\" />\n" + "<feSpecularLighting in=\"blur\" specularExponent=\"25\" specularConstant=\"%s\" surfaceScale=\"5\" lighting-color=\"rgb(%s,%s,%s)\" result=\"specular\">\n" + "<feDistantLight elevation=\"%s\" azimuth=\"%s\" />\n" + "</feSpecularLighting>\n" + "<feComposite in=\"specular\" in2=\"SourceGraphic\" k3=\"1\" k2=\"%s\" operator=\"arithmetic\" result=\"composite1\" />\n" + "<feComposite in=\"composite1\" in2=\"color\" operator=\"atop\" result=\"composite2\" />\n" + "</filter>\n", smooth.str().c_str(), bright.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), elevation.str().c_str(), azimuth.str().c_str(), a.str().c_str()); + + return _filter; +}; /* MatteJelly filter */ + +/** + \brief Custom predefined Noise fill filter. + + Basic noise fill and transparency texture + + Filter's parameters: + * Turbulence type (enum, default fractalNoise else turbulence) -> turbulence (type) + * Horizontal frequency (*1000) (0.01->10000., default 20) -> turbulence (baseFrequency [/1000]) + * Vertical frequency (*1000) (0.01->10000., default 40) -> turbulence (baseFrequency [/1000]) + * Complexity (1->5, default 5) -> turbulence (numOctaves) + * Variation (1->360, default 1) -> turbulence (seed) + * Dilatation (1.->50., default 3) -> color (n-1th value) + * Erosion (0.->50., default 1) -> color (nth value 0->-50) + * Color (guint, default 148,115,39,255) -> flood (flood-color, flood-opacity) + * Inverted (boolean, default false) -> composite1 (operator, true="in", false="out") +*/ + +class NoiseFill : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + NoiseFill ( ) : Filter() { }; + virtual ~NoiseFill ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Noise fill, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.NoiseFill</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<param name=\"type\" gui-text=\"" N_("Turbulence type:") "\" type=\"enum\">\n" + "<_item value=\"fractalNoise\">Fractal noise</_item>\n" + "<_item value=\"turbulence\">Turbulence</_item>\n" + "</param>\n" + "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10000.00\">20</param>\n" + "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10000.00\">40</param>\n" + "<param name=\"complexity\" gui-text=\"" N_("Complexity:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">5</param>\n" + "<param name=\"variation\" gui-text=\"" N_("Variation:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"360\">0</param>\n" + "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"50\">3</param>\n" + "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"50\">1</param>\n" + "<param name=\"inverted\" gui-text=\"" N_("Inverted") "\" type=\"boolean\" >false</param>\n" + "</page>\n" + "<page name=\"co11tab\" _gui-text=\"Noise color\">\n" + "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">354957823</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Basic noise fill and transparency texture") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new NoiseFill()); + }; + +}; + +gchar const * +NoiseFill::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream type; + std::ostringstream hfreq; + std::ostringstream vfreq; + std::ostringstream complexity; + std::ostringstream variation; + std::ostringstream dilat; + std::ostringstream erosion; + std::ostringstream r; + std::ostringstream g; + std::ostringstream b; + std::ostringstream a; + std::ostringstream inverted; + + type << ext->get_param_enum("type"); + hfreq << (ext->get_param_float("hfreq") / 1000); + vfreq << (ext->get_param_float("vfreq") / 1000); + complexity << ext->get_param_int("complexity"); + variation << ext->get_param_int("variation"); + dilat << ext->get_param_float("dilat"); + erosion << (- ext->get_param_float("erosion")); + guint32 color = ext->get_param_color("color"); + r << ((color >> 24) & 0xff); + g << ((color >> 16) & 0xff); + b << ((color >> 8) & 0xff); + a << (color & 0xff) / 255.0F; + if (ext->get_param_bool("inverted")) + inverted << "out"; + else + inverted << "in"; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Noise fill, custom\">\n" + "<feTurbulence type=\"%s\" baseFrequency=\"%s %s\" numOctaves=\"%s\" seed=\"%s\" result=\"turbulence\"/>\n" + "<feComposite in=\"SourceGraphic\" in2=\"turbulence\" operator=\"%s\" result=\"composite1\" />\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"color\" />\n" + "<feFlood in=\"color\" flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood\" />\n" + "<feMerge result=\"merge\">\n" + "<feMergeNode in=\"flood\" />\n" + "<feMergeNode in=\"color\" />\n" + "</feMerge>\n" + "<feComposite in2=\"SourceGraphic\" operator=\"in\" result=\"composite2\" />\n" + "</filter>\n", type.str().c_str(), hfreq.str().c_str(), vfreq.str().c_str(), complexity.str().c_str(), variation.str().c_str(), inverted.str().c_str(), dilat.str().c_str(), erosion.str().c_str(), a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str()); + + return _filter; +}; /* NoiseFill filter */ + +/** + \brief Custom predefined Outline filter. + + Adds a colorizable outline + + Filter's parameters: + * Width (0.01->50., default 5) -> blur1 (stdDeviation) + * Melt (0.01->50., default 2) -> blur2 (stdDeviation) + * Dilatation (1.->50., default 8) -> color2 (n-1th value) + * Erosion (0.->50., default 5) -> color2 (nth value 0->-50) + * Color (guint, default 156,102,102,255) -> flood (flood-color, flood-opacity) + * Blend (enum, default Normal) -> blend (mode) +*/ + +class Outline : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Outline ( ) : Filter() { }; + virtual ~Outline ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Outline, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.Outline</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<param name=\"width\" gui-text=\"" N_("Width:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">5</param>\n" + "<param name=\"melt\" gui-text=\"" N_("Melt:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">2</param>\n" + "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"50\">8</param>\n" + "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"50\">5</param>\n" + "</page>\n" + "<page name=\"co11tab\" _gui-text=\"Color\">\n" + "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">1029214207</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Adds a colorizable outline") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Outline()); + }; + +}; + +gchar const * +Outline::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream width; + std::ostringstream melt; + std::ostringstream dilat; + std::ostringstream erosion; + std::ostringstream r; + std::ostringstream g; + std::ostringstream b; + std::ostringstream a; + std::ostringstream blend; + + width << ext->get_param_float("width"); + melt << ext->get_param_float("melt"); + dilat << ext->get_param_float("dilat"); + erosion << (- ext->get_param_float("erosion")); + guint32 color = ext->get_param_color("color"); + r << ((color >> 24) & 0xff); + g << ((color >> 16) & 0xff); + b << ((color >> 8) & 0xff); + a << (color & 0xff) / 255.0F; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1.3\" width=\"1.3\" y=\"-0.15\" x=\"-0.15\" inkscape:label=\"Outline, custom\">\n" + "<feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"%s\" result=\"blur1\" />\n" + "<feColorMatrix result=\"color1\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 200 -1 \" />\n" + "<feGaussianBlur in=\"color1\" stdDeviation=\"%s\" result=\"blur2\" />\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"color2\" />\n" + "<feFlood in=\"color2\" result=\"flood\" flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" />\n" + "<feComposite in=\"flood\" in2=\"color2\" operator=\"in\" result=\"composite\" />\n" + "<feBlend in=\"SourceGraphic\" in2=\"composite\" mode=\"normal\" blend=\"normal\" />\n" + "</filter>\n", width.str().c_str(), melt.str().c_str(), dilat.str().c_str(), erosion.str().c_str(), a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str()); + + return _filter; +}; /* Outline filter */ + +/** + \brief Custom predefined Roughen filter. + + Small-scale roughening to edges and content + + Filter's parameters: + * Turbulence type (enum, default fractalNoise else turbulence) -> turbulence (type) + * Horizontal frequency (*1000) (0.01->10000., default 13) -> turbulence (baseFrequency [/1000]) + * Vertical frequency (*1000) (0.01->10000., default 13) -> turbulence (baseFrequency [/1000]) + * Complexity (1->5, default 5) -> turbulence (numOctaves) + * Variation (1->360, default 1) -> turbulence (seed) + * Intensity (0.0->50., default 6.6) -> displacement (scale) +*/ + +class Roughen : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Roughen ( ) : Filter() { }; + virtual ~Roughen ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Roughen, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.Roughen</id>\n" + "<param name=\"type\" gui-text=\"" N_("Turbulence type:") "\" type=\"enum\">\n" + "<_item value=\"fractalNoise\">Fractal noise</_item>\n" + "<_item value=\"turbulence\">Turbulence</_item>\n" + "</param>\n" + "<param name=\"hfreq\" gui-text=\"" N_("Horizontal frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10000.00\">13</param>\n" + "<param name=\"vfreq\" gui-text=\"" N_("Vertical frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10000.00\">13</param>\n" + "<param name=\"complexity\" gui-text=\"" N_("Complexity:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">5</param>\n" + "<param name=\"variation\" gui-text=\"" N_("Variation:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"360\">0</param>\n" + "<param name=\"intensity\" gui-text=\"" N_("Intensity:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"50\">6.6</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Small-scale roughening to edges and content") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Roughen()); + }; + +}; + +gchar const * +Roughen::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream type; + std::ostringstream hfreq; + std::ostringstream vfreq; + std::ostringstream complexity; + std::ostringstream variation; + std::ostringstream intensity; + + type << ext->get_param_enum("type"); + hfreq << (ext->get_param_float("hfreq") / 1000); + vfreq << (ext->get_param_float("vfreq") / 1000); + complexity << ext->get_param_int("complexity"); + variation << ext->get_param_int("variation"); + intensity << ext->get_param_float("intensity"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Roughen, custom\">\n" + "<feTurbulence type=\"%s\" numOctaves=\"%s\" seed=\"%s\" baseFrequency=\"%s %s\" result=\"turbulence\" />\n" + "<feDisplacementMap in=\"SourceGraphic\" in2=\"turbulence\" scale=\"%s\" yChannelSelector=\"G\" xChannelSelector=\"R\" />\n" + "</filter>\n", type.str().c_str(), complexity.str().c_str(), variation.str().c_str(), hfreq.str().c_str(), vfreq.str().c_str(), intensity.str().c_str()); + + return _filter; +}; /* Roughen filter */ + +/** + \brief Custom predefined Silhouette filter. + + Repaint anything visible monochrome + + Filter's parameters: + * Blur (0.01->50., default 0.01) -> blur (stdDeviation) + * Cutout (boolean, default False) -> composite (false=in, true=out) + * Color (guint, default 0,0,0,255) -> flood (flood-color, flood-opacity) +*/ + +class Silhouette : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Silhouette ( ) : Filter() { }; + virtual ~Silhouette ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Silhouette, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.Silhouette</id>\n" + "<param name=\"blur\" gui-text=\"" N_("Blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"50.00\">0.01</param>\n" + "<param name=\"cutout\" gui-text=\"" N_("Cutout") "\" type=\"boolean\">false</param>\n" + "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">255</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Repaint anything visible monochrome") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Silhouette()); + }; + +}; + +gchar const * +Silhouette::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream a; + std::ostringstream r; + std::ostringstream g; + std::ostringstream b; + std::ostringstream cutout; + std::ostringstream blur; + + guint32 color = ext->get_param_color("color"); + r << ((color >> 24) & 0xff); + g << ((color >> 16) & 0xff); + b << ((color >> 8) & 0xff); + a << (color & 0xff) / 255.0F; + if (ext->get_param_bool("cutout")) + cutout << "out"; + else + cutout << "in"; + blur << ext->get_param_float("blur"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Silhouette, custom\">\n" + "<feFlood in=\"SourceGraphic\" flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood\" />\n" + "<feComposite in=\"flood\" in2=\"SourceGraphic\" operator=\"%s\" result=\"composite\" />\n" + "<feGaussianBlur stdDeviation=\"%s\" />\n" + "</filter>\n", a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), cutout.str().c_str(), blur.str().c_str()); + + return _filter; +}; /* Silhouette filter */ + +/** + \brief Custom predefined Specular light filter. + + Basic specular bevel to use for building textures + + Filter's parameters: + * Smoothness (0.0->10., default 6.) -> blur (stdDeviation) + * Brightness (0.0->5., default 1.) -> specular (specularConstant) + * Elevation (0->360, default 45) -> feDistantLight (elevation) + * Azimuth (0->360, default 235) -> feDistantLight (azimuth) + * Lightning color (guint, default -1 [white]) -> specular (lighting-color) +*/ + +class SpecularLight : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + SpecularLight ( ) : Filter() { }; + virtual ~SpecularLight ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Specular light, custom (ABCs)") "</name>\n" + "<id>org.inkscape.effect.filter.SpecularLight</id>\n" + "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"10\">6</param>\n" + "<param name=\"bright\" gui-text=\"" N_("Brightness:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"5\">1</param>\n" + "<param name=\"elevation\" gui-text=\"" N_("Elevation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">45</param>\n" + "<param name=\"azimuth\" gui-text=\"" N_("Azimuth (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">235</param>\n" + "<param name=\"color\" gui-text=\"" N_("Lightning color") "\" type=\"color\">-1</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Basic specular bevel to use for building textures") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new SpecularLight()); + }; + +}; + +gchar const * +SpecularLight::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream smooth; + std::ostringstream bright; + std::ostringstream elevation; + std::ostringstream azimuth; + std::ostringstream r; + std::ostringstream g; + std::ostringstream b; + std::ostringstream a; + + smooth << ext->get_param_float("smooth"); + bright << ext->get_param_float("bright"); + elevation << ext->get_param_int("elevation"); + azimuth << ext->get_param_int("azimuth"); + guint32 color = ext->get_param_color("color"); + + r << ((color >> 24) & 0xff); + g << ((color >> 16) & 0xff); + b << ((color >> 8) & 0xff); + a << (color & 0xff) / 255.0F; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Specular light, custom\">\n" + "<feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"%s\" result=\"blur\" />\n" + "<feSpecularLighting in=\"blur\" specularExponent=\"25\" specularConstant=\"%s\" surfaceScale=\"10\" lighting-color=\"rgb(%s,%s,%s)\" result=\"specular\">\n" + "<feDistantLight elevation=\"%s\" azimuth=\"%s\" />\n" + "</feSpecularLighting>\n" + "<feComposite in=\"specular\" in2=\"SourceGraphic\" k3=\"1\" k2=\"%s\" operator=\"arithmetic\" result=\"composite1\" />\n" + "<feComposite in=\"composite1\" in2=\"SourceAlpha\" operator=\"in\" result=\"composite2\" />\n" + "</filter>\n", smooth.str().c_str(), bright.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), elevation.str().c_str(), azimuth.str().c_str(), a.str().c_str()); + + return _filter; +}; /* SpecularLight filter */ + + +}; /* namespace Filter */ +}; /* namespace Internal */ +}; /* namespace Extension */ +}; /* namespace Inkscape */ + +/* Change the 'ABC' below to be your file name */ +#endif /* __INKSCAPE_EXTENSION_INTERNAL_FILTER_ABC_H__ */ diff --git a/src/extension/internal/filter/color.h b/src/extension/internal/filter/color.h index 54312685c..27b1fdda9 100644..100755 --- a/src/extension/internal/filter/color.h +++ b/src/extension/internal/filter/color.h @@ -3,13 +3,17 @@ /* Change the 'COLOR' above to be your file name */ /* - * Copyright (C) 2010 Authors: + * Copyright (C) 2011 Authors: * Ivan Louette (filters) * Nicolas Dufour (UI) <nicoduf@yahoo.fr> * * Color filters + * Brightness * Colorize * Duochrome + * Electrize + * Greyscale + * Lightness * Quadritone * Solarize * Tritone @@ -30,6 +34,75 @@ namespace Internal { namespace Filter { /** + \brief Custom predefined Brightness filter. + + Brightness filter. + + Filter's parameters: + * Strength (-10.->10., default 1) -> colorMatrix (RVB entries) + * Vibration (-10.->10., default 0.) -> colorMatrix (6 other entries) + * Lightness (-10.->10., default 0.) -> colorMatrix (last column) + + Matrix: + St Vi Vi 0 Li + Vi St Vi 0 Li + Vi Vi St 0 Li + 0 0 0 1 0 +*/ +class Brightness : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Brightness ( ) : Filter() { }; + virtual ~Brightness ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Brightness, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Brightness</id>\n" + "<param name=\"strength\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">1</param>\n" + "<param name=\"vibration\" gui-text=\"" N_("Vibration:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0</param>\n" + "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Brightness filter") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Brightness()); + }; +}; + +gchar const * +Brightness::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream strength; + std::ostringstream vibration; + std::ostringstream lightness; + + strength << ext->get_param_float("strength"); + vibration << ext->get_param_float("vibration"); + lightness << ext->get_param_float("lightness"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Brightness, custom\">\n" + "<feColorMatrix values=\"%s %s %s 0 %s %s %s %s 0 %s %s %s %s 0 %s 0 0 0 1 0 \" />\n" + "</filter>\n", strength.str().c_str(), vibration.str().c_str(), vibration.str().c_str(), + lightness.str().c_str(), vibration.str().c_str(), strength.str().c_str(), + vibration.str().c_str(), lightness.str().c_str(), vibration.str().c_str(), + vibration.str().c_str(), strength.str().c_str(), lightness.str().c_str()); + + return _filter; +}; /* Brightness filter */ + +/** \brief Custom predefined Colorize filter. Blend image or object with a flood color. @@ -45,53 +118,59 @@ namespace Filter { class Colorize : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Colorize ( ) : Filter() { }; - virtual ~Colorize ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Colorize, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Colorize</id>\n" - "<param name=\"hlight\" gui-text=\"" N_("Harsh light:") "\" type=\"float\" min=\"0\" max=\"10\">0</param>\n" - "<param name=\"nlight\" gui-text=\"" N_("Normal light:") "\" type=\"float\" min=\"0\" max=\"10\">1</param>\n" - "<param name=\"duotone\" gui-text=\"" N_("Duotone") "\" type=\"boolean\" >false</param>\n" - "<param name=\"blend1\" gui-text=\"" N_("Blend1:") "\" type=\"enum\">\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"screen\">Screen</_item>\n" - "<_item value=\"lighten\">Lighten</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "<param name=\"blend2\" gui-text=\"" N_("Blend2:") "\" type=\"enum\">\n" - "<_item value=\"screen\">Screen</_item>\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"lighten\">Lighten</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "<param name=\"color\" gui-text=\"" N_("Color 1") "\" type=\"color\">-1639776001</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Blend image or object with a flood color") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Colorize()); - }; + Colorize ( ) : Filter() { }; + virtual ~Colorize ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Colorize, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Colorize</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<param name=\"hlight\" gui-text=\"" N_("Harsh light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">0</param>\n" + "<param name=\"nlight\" gui-text=\"" N_("Normal light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">1</param>\n" + "<param name=\"duotone\" gui-text=\"" N_("Duotone") "\" type=\"boolean\" >false</param>\n" + "<param name=\"blend1\" gui-text=\"" N_("Blend 1:") "\" type=\"enum\">\n" + "<_item value=\"multiply\">" N_("Multiply") "</_item>\n" + "<_item value=\"normal\">" N_("Normal") "</_item>\n" + "<_item value=\"screen\">" N_("Screen") "</_item>\n" + "<_item value=\"lighten\">" N_("Lighten") "</_item>\n" + "<_item value=\"darken\">" N_("Darken") "</_item>\n" + "</param>\n" + "<param name=\"blend2\" gui-text=\"" N_("Blend 2:") "\" type=\"enum\">\n" + "<_item value=\"screen\">" N_("Screen") "</_item>\n" + "<_item value=\"multiply\">" N_("Multiply") "</_item>\n" + "<_item value=\"normal\">" N_("Normal") "</_item>\n" + "<_item value=\"lighten\">" N_("Lighten") "</_item>\n" + "<_item value=\"darken\">" N_("Darken") "</_item>\n" + "</param>\n" + "</page>\n" + "<page name=\"colortab\" _gui-text=\"Color\">\n" + "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">-1639776001</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Blend image or object with a flood color") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Colorize()); + }; }; gchar const * Colorize::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream a; std::ostringstream r; @@ -118,18 +197,18 @@ Colorize::get_filter_text (Inkscape::Extension::Extension * ext) else duotone << "1"; - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Colorize, custom -EXP-\">\n" - "<feComposite in2=\"SourceGraphic\" operator=\"arithmetic\" k1=\"%s\" k2=\"%s\" result=\"composite1\" />\n" - "<feColorMatrix in=\"composite1\" values=\"%s\" type=\"saturate\" result=\"colormatrix1\" />\n" - "<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood1\" />\n" - "<feBlend in=\"flood1\" in2=\"colormatrix1\" mode=\"%s\" result=\"blend1\" />\n" - "<feBlend in2=\"blend1\" mode=\"%s\" result=\"blend2\" />\n" - "<feColorMatrix in=\"blend2\" values=\"1\" type=\"saturate\" result=\"colormatrix2\" />\n" - "<feComposite in=\"colormatrix2\" in2=\"SourceGraphic\" operator=\"in\" k2=\"1\" result=\"composite2\" />\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Colorize, custom\">\n" + "<feComposite in2=\"SourceGraphic\" operator=\"arithmetic\" k1=\"%s\" k2=\"%s\" result=\"composite1\" />\n" + "<feColorMatrix in=\"composite1\" values=\"%s\" type=\"saturate\" result=\"colormatrix1\" />\n" + "<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood1\" />\n" + "<feBlend in=\"flood1\" in2=\"colormatrix1\" mode=\"%s\" result=\"blend1\" />\n" + "<feBlend in2=\"blend1\" mode=\"%s\" result=\"blend2\" />\n" + "<feColorMatrix in=\"blend2\" values=\"1\" type=\"saturate\" result=\"colormatrix2\" />\n" + "<feComposite in=\"colormatrix2\" in2=\"SourceGraphic\" operator=\"in\" k2=\"1\" result=\"composite2\" />\n" "</filter>\n", hlight.str().c_str(), nlight.str().c_str(), duotone.str().c_str(), a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), blend1.str().c_str(), blend2.str().c_str()); - return _filter; + return _filter; }; /* Colorize filter */ @@ -147,52 +226,52 @@ Colorize::get_filter_text (Inkscape::Extension::Extension * ext) class Duochrome : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Duochrome ( ) : Filter() { }; - virtual ~Duochrome ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Duochrome, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Duochrome</id>\n" - "<param name=\"tab\" type=\"notebook\">\n" - "<page name=\"optionstab\" _gui-text=\"Options\">\n" - "<param name=\"fluo\" gui-text=\"" N_("Fluorescence level:") "\" type=\"float\" min=\"0\" max=\"2\">0</param>\n" - "<param name=\"swap\" gui-text=\"" N_("Swap:") "\" type=\"enum\">\n" - "<_item value=\"none\">No swap</_item>\n" - "<_item value=\"full\">Color and alpha</_item>\n" - "<_item value=\"color\">Color only</_item>\n" - "<_item value=\"alpha\">Alpha only</_item>\n" - "</param>\n" - "</page>\n" - "<page name=\"co11tab\" _gui-text=\"Color 1\">\n" - "<param name=\"color1\" gui-text=\"" N_("Color 1") "\" type=\"color\">1364325887</param>\n" - "</page>\n" - "<page name=\"co12tab\" _gui-text=\"Color 2\">\n" - "<param name=\"color2\" gui-text=\"" N_("Color 2") "\" type=\"color\">-65281</param>\n" - "</page>\n" - "</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Convert luminance values to a duochrome palette") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Duochrome()); - }; + Duochrome ( ) : Filter() { }; + virtual ~Duochrome ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Duochrome, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Duochrome</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<param name=\"fluo\" gui-text=\"" N_("Fluorescence level:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"2\">0</param>\n" + "<param name=\"swap\" gui-text=\"" N_("Swap:") "\" type=\"enum\">\n" + "<_item value=\"none\">" N_("No swap") "</_item>\n" + "<_item value=\"full\">" N_("Color and alpha") "</_item>\n" + "<_item value=\"color\">" N_("Color only") "</_item>\n" + "<_item value=\"alpha\">" N_("Alpha only") "</_item>\n" + "</param>\n" + "</page>\n" + "<page name=\"co11tab\" _gui-text=\"Color 1\">\n" + "<param name=\"color1\" gui-text=\"" N_("Color 1") "\" type=\"color\">1364325887</param>\n" + "</page>\n" + "<page name=\"co12tab\" _gui-text=\"Color 2\">\n" + "<param name=\"color2\" gui-text=\"" N_("Color 2") "\" type=\"color\">-65281</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Convert luminance values to a duochrome palette") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Duochrome()); + }; }; gchar const * Duochrome::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream a1; std::ostringstream r1; @@ -240,23 +319,264 @@ Duochrome::get_filter_text (Inkscape::Extension::Extension * ext) a2 << (color2 & 0xff) / 255.0F; } - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Duochrome, custom -EXP-\">\n" - "<feColorMatrix type=\"luminanceToAlpha\" result=\"colormatrix1\" />\n" - "<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood1\" />\n" - "<feComposite in2=\"colormatrix1\" operator=\"%s\" result=\"composite1\" />\n" - "<feFlood in=\"colormatrix1\" flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood2\" />\n" - "<feComposite in2=\"colormatrix1\" result=\"composite2\" operator=\"%s\" />\n" - "<feComposite in=\"composite2\" in2=\"composite1\" k2=\"1\" k3=\"1\" operator=\"arithmetic\" result=\"composite3\" />\n" - "<feColorMatrix in=\"composite3\" type=\"matrix\" values=\"2 -1 0 0 0 0 2 -1 0 0 -1 0 2 0 0 0 0 0 1 0 \" result=\"colormatrix2\" />\n" - "<feComposite in=\"colormatrix2\" in2=\"composite3\" operator=\"arithmetic\" k2=\"%s\" result=\"composite4\" />\n" - "<feBlend in=\"composite4\" in2=\"composite3\" blend=\"normal\" mode=\"normal\" result=\"blend\" />\n" - "<feComposite in2=\"SourceGraphic\" operator=\"in\" />\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Duochrome, custom\">\n" + "<feColorMatrix type=\"luminanceToAlpha\" result=\"colormatrix1\" />\n" + "<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood1\" />\n" + "<feComposite in2=\"colormatrix1\" operator=\"%s\" result=\"composite1\" />\n" + "<feFlood in=\"colormatrix1\" flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood2\" />\n" + "<feComposite in2=\"colormatrix1\" result=\"composite2\" operator=\"%s\" />\n" + "<feComposite in=\"composite2\" in2=\"composite1\" k2=\"1\" k3=\"1\" operator=\"arithmetic\" result=\"composite3\" />\n" + "<feColorMatrix in=\"composite3\" type=\"matrix\" values=\"2 -1 0 0 0 0 2 -1 0 0 -1 0 2 0 0 0 0 0 1 0 \" result=\"colormatrix2\" />\n" + "<feComposite in=\"colormatrix2\" in2=\"composite3\" operator=\"arithmetic\" k2=\"%s\" result=\"composite4\" />\n" + "<feBlend in=\"composite4\" in2=\"composite3\" blend=\"normal\" mode=\"normal\" result=\"blend\" />\n" + "<feComposite in2=\"SourceGraphic\" operator=\"in\" />\n" "</filter>\n", a1.str().c_str(), r1.str().c_str(), g1.str().c_str(), b1.str().c_str(), swap1.str().c_str(), a2.str().c_str(), r2.str().c_str(), g2.str().c_str(), b2.str().c_str(), swap2.str().c_str(), fluo.str().c_str()); - return _filter; + return _filter; }; /* Duochrome filter */ +/** + \brief Custom predefined Electrize filter. + + Electro solarization effects. + + Filter's parameters: + * Simplify (0.01->10., default 2.) -> blur (stdDeviation) + * Effect type (enum: table or discrete, default "table") -> component (type) + * Level (0->10, default 3) -> component (tableValues) + * Inverted (boolean, default false) -> component (tableValues) +*/ +class Electrize : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Electrize ( ) : Filter() { }; + virtual ~Electrize ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Electrize, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Electrize</id>\n" + "<param name=\"blur\" gui-text=\"" N_("Simplify:") "\" type=\"float\" appearance=\"full\" min=\"0.01\" max=\"10.0\">2.0</param>\n" + "<param name=\"type\" gui-text=\"" N_("Effect type:") "\" type=\"enum\">\n" + "<_item value=\"table\">" N_("Table") "</_item>\n" + "<_item value=\"discrete\">" N_("Discrete") "</_item>\n" + "</param>\n" + "<param name=\"levels\" gui-text=\"" N_("Levels:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"10\">3</param>\n" + "<param name=\"invert\" gui-text=\"" N_("Inverted") "\" type=\"boolean\">false</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Electro solarization effects") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Electrize()); + }; +}; + +gchar const * +Electrize::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream blur; + std::ostringstream type; + std::ostringstream values; + + blur << ext->get_param_float("blur"); + type << ext->get_param_enum("type"); + + // TransfertComponent table values are calculated based on the effect level and inverted parameters. + int val = 0; + int levels = ext->get_param_int("levels") + 1; + if (ext->get_param_bool("invert")) + val = 1; + values << val; + for ( int step = 1 ; step <= levels ; step++ ) { + if (val == 1) { + val = 0; + } + else { + val = 1; + } + values << " " << val; + } + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Electrize, custom\">\n" + "<feGaussianBlur stdDeviation=\"%s\" result=\"blur\" />\n" + "<feComponentTransfer in=\"blur\" stdDeviation=\"2\" result=\"component\" >\n" + "<feFuncR type=\"%s\" tableValues=\"%s\" />\n" + "<feFuncG type=\"%s\" tableValues=\"%s\" />\n" + "<feFuncB type=\"%s\" tableValues=\"%s\" />\n" + "</feComponentTransfer>\n" + "</filter>\n", blur.str().c_str(), type.str().c_str(), values.str().c_str(), type.str().c_str(), values.str().c_str(), type.str().c_str(), values.str().c_str()); + + return _filter; +}; /* Electrize filter */ + +/** + \brief Custom predefined Greyscale filter. + + Customize greyscale components. + + Filter's parameters: + * Red (-10.->10., default .21) -> colorMatrix (values) + * Green (-10.->10., default .72) -> colorMatrix (values) + * Blue (-10.->10., default .072) -> colorMatrix (values) + * Lightness (-10.->10., default 0.) -> colorMatrix (values) + * Transparent (boolean, default false) -> matrix structure + + Matrix: + normal transparency + R G B St 0 0 0 0 0 0 + R G B St 0 0 0 0 0 0 + R G B St 0 0 0 0 0 0 + 0 0 0 1 0 R G B 1-St 0 +*/ +class Greyscale : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Greyscale ( ) : Filter() { }; + virtual ~Greyscale ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Greyscale, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Greyscale</id>\n" + "<param name=\"red\" gui-text=\"" N_("Red:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.21</param>\n" + "<param name=\"green\" gui-text=\"" N_("Green:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.72</param>\n" + "<param name=\"blue\" gui-text=\"" N_("Blue:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0.072</param>\n" + "<param name=\"strength\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-10.00\" max=\"10.00\">0</param>\n" + "<param name=\"transparent\" gui-text=\"" N_("Transparent") "\" type=\"boolean\" >false</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Customize greyscale components") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Greyscale()); + }; +}; + +gchar const * +Greyscale::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream red; + std::ostringstream green; + std::ostringstream blue; + std::ostringstream strength; + std::ostringstream redt; + std::ostringstream greent; + std::ostringstream bluet; + std::ostringstream strengtht; + std::ostringstream transparency; + std::ostringstream line; + + red << ext->get_param_float("red"); + green << ext->get_param_float("green"); + blue << ext->get_param_float("blue"); + strength << ext->get_param_float("strength"); + + redt << - ext->get_param_float("red"); + greent << - ext->get_param_float("green"); + bluet << - ext->get_param_float("blue"); + strengtht << 1 - ext->get_param_float("strength"); + + if (ext->get_param_bool("transparent")) { + line << "0 0 0 0"; + transparency << redt.str().c_str() << " " << greent.str().c_str() << " " << bluet.str().c_str() << " " << strengtht.str().c_str(); + } else { + line << red.str().c_str() << " " << green.str().c_str() << " " << blue.str().c_str() << " " << strength.str().c_str(); + transparency << "0 0 0 1"; + } + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Greyscale, custom\">\n" + "<feColorMatrix values=\"%s 0 %s 0 %s 0 %s 0 \" />\n" + "</filter>\n", line.str().c_str(), line.str().c_str(), line.str().c_str(), transparency.str().c_str()); + return _filter; +}; /* Greyscale filter */ + +/** + \brief Custom predefined Lightness filter. + + Modify lights and shadows separately. + + Filter's parameters: + * Lightness (0.->20., default 1.) -> component (amplitude) + * Shadow (0.->20., default 1.) -> component (exponent) + * Offset (-1.->1., default 0.) -> component (offset) +*/ +class Lightness : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + Lightness ( ) : Filter() { }; + virtual ~Lightness ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Lightness, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Lightness</id>\n" + "<param name=\"amplitude\" gui-text=\"" N_("Lights:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"20.00\">1</param>\n" + "<param name=\"exponent\" gui-text=\"" N_("Shadows:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"20.00\">1</param>\n" + "<param name=\"offset\" gui-text=\"" N_("Offset:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"-1.00\" max=\"1.00\">0</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Modify lights and shadows separately") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Lightness()); + }; +}; + +gchar const * +Lightness::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream amplitude; + std::ostringstream exponent; + std::ostringstream offset; + + amplitude << ext->get_param_float("amplitude"); + exponent << ext->get_param_float("exponent"); + offset << ext->get_param_float("offset"); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Lightness, custom\">\n" + "<feComponentTransfer in=\"blur\" stdDeviation=\"2\" result=\"component\" >\n" + "<feFuncR type=\"gamma\" amplitude=\"%s\" exponent=\"%s\" offset=\"%s\" />\n" + "<feFuncG type=\"gamma\" amplitude=\"%s\" exponent=\"%s\" offset=\"%s\" />\n" + "<feFuncB type=\"gamma\" amplitude=\"%s\" exponent=\"%s\" offset=\"%s\" />\n" + "</feComponentTransfer>\n" + "</filter>\n", amplitude.str().c_str(), exponent.str().c_str(), offset.str().c_str(), + amplitude.str().c_str(), exponent.str().c_str(), offset.str().c_str(), + amplitude.str().c_str(), exponent.str().c_str(), offset.str().c_str()); + + return _filter; +}; /* Lightness filter */ /** \brief Custom predefined Quadritone filter. @@ -273,50 +593,50 @@ Duochrome::get_filter_text (Inkscape::Extension::Extension * ext) class Quadritone : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Quadritone ( ) : Filter() { }; - virtual ~Quadritone ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Quadritone fantasy, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Quadritone</id>\n" - "<param name=\"dist\" gui-text=\"" N_("Hue distribution:") "\" type=\"int\" min=\"0\" max=\"360\">280</param>\n" - "<param name=\"colors\" gui-text=\"" N_("Colors:") "\" type=\"int\" min=\"0\" max=\"360\">100</param>\n" - "<param name=\"blend1\" gui-text=\"" N_("Blend1:") "\" type=\"enum\">\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"screen\">Screen</_item>\n" - "</param>\n" - "<param name=\"sat\" gui-text=\"" N_("Over-saturation:") "\" type=\"float\" min=\"0\" max=\"1\">0</param>\n" - "<param name=\"blend2\" gui-text=\"" N_("Blend2:") "\" type=\"enum\">\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"screen\">Screen</_item>\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"lighten\">Lighten</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Replace hue by two colors") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Quadritone()); - }; + Quadritone ( ) : Filter() { }; + virtual ~Quadritone ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Quadritone fantasy, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Quadritone</id>\n" + "<param name=\"dist\" gui-text=\"" N_("Hue distribution (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">280</param>\n" + "<param name=\"colors\" gui-text=\"" N_("Colors:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">100</param>\n" + "<param name=\"blend1\" gui-text=\"" N_("Blend 1:") "\" type=\"enum\">\n" + "<_item value=\"normal\">" N_("Normal") "</_item>\n" + "<_item value=\"multiply\">" N_("Multiply") "</_item>\n" + "<_item value=\"screen\">" N_("Screen") "</_item>\n" + "</param>\n" + "<param name=\"sat\" gui-text=\"" N_("Over-saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">0</param>\n" + "<param name=\"blend2\" gui-text=\"" N_("Blend 2:") "\" type=\"enum\">\n" + "<_item value=\"normal\">" N_("Normal") "</_item>\n" + "<_item value=\"screen\">" N_("Screen") "</_item>\n" + "<_item value=\"multiply\">" N_("Multiply") "</_item>\n" + "<_item value=\"lighten\">" N_("Lighten") "</_item>\n" + "<_item value=\"darken\">" N_("Darken") "</_item>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Replace hue by two colors") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Quadritone()); + }; }; gchar const * Quadritone::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream dist; std::ostringstream colors; @@ -330,18 +650,18 @@ Quadritone::get_filter_text (Inkscape::Extension::Extension * ext) sat << ext->get_param_float("sat"); blend2 << ext->get_param_enum("blend2"); - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Quadritone fantasy, custom -EXP-\">\n" - "<feColorMatrix in=\"SourceGraphic\" type=\"hueRotate\" values=\"%s\" result=\"colormatrix1\" />\n" - "<feColorMatrix type=\"matrix\" values=\"0.5 0 0.5 0 0 0 1 0 0 0 0.5 0 0.5 0 0 0 0 0 1 0 \" result=\"colormatrix2\" />\n" - "<feColorMatrix type=\"hueRotate\" values=\"%s\" result=\"colormatrix3\" />\n" - "<feBlend in2=\"colormatrix3\" blend=\"normal\" mode=\"%s\" result=\"blend1\" />\n" - "<feColorMatrix type=\"matrix\" values=\"2.5 -0.75 -0.75 0 0 -0.75 2.5 -0.75 0 0 -0.75 -0.75 2.5 0 0 0 0 0 1 0 \" result=\"colormatrix4\" />\n" - "<feComposite in=\"colormatrix4\" in2=\"blend1\" operator=\"arithmetic\" k2=\"%s\" result=\"composite1\" />\n" - "<feBlend in2=\"blend1\" blend=\"normal\" mode=\"%s\" result=\"blend2\" />\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Quadritone fantasy, custom\">\n" + "<feColorMatrix in=\"SourceGraphic\" type=\"hueRotate\" values=\"%s\" result=\"colormatrix1\" />\n" + "<feColorMatrix type=\"matrix\" values=\"0.5 0 0.5 0 0 0 1 0 0 0 0.5 0 0.5 0 0 0 0 0 1 0 \" result=\"colormatrix2\" />\n" + "<feColorMatrix type=\"hueRotate\" values=\"%s\" result=\"colormatrix3\" />\n" + "<feBlend in2=\"colormatrix3\" blend=\"normal\" mode=\"%s\" result=\"blend1\" />\n" + "<feColorMatrix type=\"matrix\" values=\"2.5 -0.75 -0.75 0 0 -0.75 2.5 -0.75 0 0 -0.75 -0.75 2.5 0 0 0 0 0 1 0 \" result=\"colormatrix4\" />\n" + "<feComposite in=\"colormatrix4\" in2=\"blend1\" operator=\"arithmetic\" k2=\"%s\" result=\"composite1\" />\n" + "<feBlend in2=\"blend1\" blend=\"normal\" mode=\"%s\" result=\"blend2\" />\n" "</filter>\n", dist.str().c_str(), colors.str().c_str(), blend1.str().c_str(), sat.str().c_str(), blend2.str().c_str()); - return _filter; + return _filter; }; /* Quadritone filter */ @@ -360,40 +680,40 @@ Quadritone::get_filter_text (Inkscape::Extension::Extension * ext) class Solarize : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Solarize ( ) : Filter() { }; - virtual ~Solarize ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Solarize, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Solarize</id>\n" - "<param name=\"rotate\" gui-text=\"" N_("Hue rotation:") "\" type=\"int\" min=\"0\" max=\"360\">0</param>\n" - "<param name=\"type\" gui-text=\"" N_("Type:") "\" type=\"enum\">\n" - "<_item value=\"solarize\">Solarize</_item>\n" - "<_item value=\"moonarize\">Moonarize</_item>\n" - "</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Classic photographic solarization effect") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Solarize()); - }; + Solarize ( ) : Filter() { }; + virtual ~Solarize ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Solarize, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Solarize</id>\n" + "<param name=\"rotate\" gui-text=\"" N_("Hue rotation (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">0</param>\n" + "<param name=\"type\" gui-text=\"" N_("Type:") "\" type=\"enum\">\n" + "<_item value=\"solarize\">" N_("Solarize") "</_item>\n" + "<_item value=\"moonarize\">" N_("Moonarize") "</_item>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Classic photographic solarization effect") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Solarize()); + }; }; gchar const * Solarize::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream rotate; std::ostringstream blend1; @@ -411,17 +731,17 @@ Solarize::get_filter_text (Inkscape::Extension::Extension * ext) blend2 << "multiply"; } - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Solarize, custom -EXP-\">\n" - "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 \" />\n" - "<feColorMatrix type=\"hueRotate\" values=\"%s\" result=\"colormatrix2\" />\n" - "<feColorMatrix in=\"colormatrix2\" values=\"-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 \" result=\"colormatrix3\" />\n" - "<feBlend in=\"colormatrix3\" in2=\"colormatrix2\" mode=\"%s\" result=\"blend1\" />\n" - "<feBlend in2=\"blend1\" mode=\"%s\" result=\"blend2\" />\n" - "<feComposite in2=\"SourceGraphic\" operator=\"in\" />\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Solarize, custom\">\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 \" />\n" + "<feColorMatrix type=\"hueRotate\" values=\"%s\" result=\"colormatrix2\" />\n" + "<feColorMatrix in=\"colormatrix2\" values=\"-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0 \" result=\"colormatrix3\" />\n" + "<feBlend in=\"colormatrix3\" in2=\"colormatrix2\" mode=\"%s\" result=\"blend1\" />\n" + "<feBlend in2=\"blend1\" mode=\"%s\" result=\"blend2\" />\n" + "<feComposite in2=\"SourceGraphic\" operator=\"in\" />\n" "</filter>\n", rotate.str().c_str(), blend1.str().c_str(), blend2.str().c_str()); - return _filter; + return _filter; }; /* Solarize filter */ @@ -447,63 +767,63 @@ Solarize::get_filter_text (Inkscape::Extension::Extension * ext) class Tritone : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Tritone ( ) : Filter() { }; - virtual ~Tritone ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Tritone, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Tritone</id>\n" - "<param name=\"tab\" type=\"notebook\">\n" - "<page name=\"optionstab\" _gui-text=\"Options\">\n" - "<param name=\"type\" gui-text=\"" N_("Type:") "\" type=\"enum\">\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"enhue\">Enhance hue</_item>\n" - "<_item value=\"rad\">Radiation</_item>\n" - "<_item value=\"htb\">Hue to background</_item>\n" - "</param>\n" - "<param name=\"globalblend\" gui-text=\"" N_("Global blend:") "\" type=\"enum\">\n" - "<_item value=\"lighten\">Lighten</_item>\n" - "<_item value=\"screen\">Screen</_item>\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "<param name=\"glow\" gui-text=\"" N_("Glow:") "\" type=\"float\" min=\"0.01\" max=\"10\">0.01</param>\n" - "<param name=\"glowblend\" gui-text=\"" N_("Glow blend:") "\" type=\"enum\">\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "<param name=\"llight\" gui-text=\"" N_("Local light:") "\" type=\"float\" min=\"0\" max=\"10\">0</param>\n" - "<param name=\"glight\" gui-text=\"" N_("Global light:") "\" type=\"float\" min=\"0\" max=\"10\">1</param>\n" - "</page>\n" - "<page name=\"co1tab\" _gui-text=\"Color\">\n" - "<param name=\"dist\" gui-text=\"" N_("Hue distribution:") "\" type=\"int\" min=\"0\" max=\"360\">0</param>\n" - "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">-73203457</param>\n" - "</page>\n" - "</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Create a custom tritone palette with additional glow, blend modes and hue moving") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Tritone()); - }; + Tritone ( ) : Filter() { }; + virtual ~Tritone ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Tritone, custom (Color)") "</name>\n" + "<id>org.inkscape.effect.filter.Tritone</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<param name=\"type\" gui-text=\"" N_("Type:") "\" type=\"enum\">\n" + "<_item value=\"normal\">" N_("Normal") "</_item>\n" + "<_item value=\"enhue\">" N_("Enhance hue") "</_item>\n" + "<_item value=\"rad\">" N_("Radiation") "</_item>\n" + "<_item value=\"htb\">" N_("Hue to background") "</_item>\n" + "</param>\n" + "<param name=\"globalblend\" gui-text=\"" N_("Global blend:") "\" type=\"enum\">\n" + "<_item value=\"lighten\">" N_("Lighten") "</_item>\n" + "<_item value=\"screen\">" N_("Screen") "</_item>\n" + "<_item value=\"multiply\">" N_("Multiply") "</_item>\n" + "<_item value=\"darken\">" N_("Darken") "</_item>\n" + "</param>\n" + "<param name=\"glow\" gui-text=\"" N_("Glow:") "\" type=\"float\" appearance=\"full\" min=\"0.01\" max=\"10\">0.01</param>\n" + "<param name=\"glowblend\" gui-text=\"" N_("Glow blend:") "\" type=\"enum\">\n" + "<_item value=\"normal\">" N_("Normal") "</_item>\n" + "<_item value=\"multiply\">" N_("Multiply") "</_item>\n" + "<_item value=\"darken\">" N_("Darken") "</_item>\n" + "</param>\n" + "<param name=\"llight\" gui-text=\"" N_("Local light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">0</param>\n" + "<param name=\"glight\" gui-text=\"" N_("Global light:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"10\">1</param>\n" + "</page>\n" + "<page name=\"co1tab\" _gui-text=\"Color\">\n" + "<param name=\"dist\" gui-text=\"" N_("Hue distribution (°):") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"360\">0</param>\n" + "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">-73203457</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Create a custom tritone palette with additional glow, blend modes and hue moving") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Tritone()); + }; }; gchar const * Tritone::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream dist; std::ostringstream a; @@ -564,30 +884,30 @@ Tritone::get_filter_text (Inkscape::Extension::Extension * ext) b6in2 << "qminpc"; } - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Tritone, custom -EXP-\">\n" - "<feColorMatrix type=\"hueRotate\" result=\"colormatrix1\" values=\"%s\" />\n" - "<feColorMatrix in=\"colormatrix1\" result=\"r\" type=\"matrix\" values=\"1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 \" />\n" - "<feColorMatrix in=\"colormatrix1\" result=\"g\" type=\"matrix\" values=\"0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 \" />\n" - "<feColorMatrix in=\"colormatrix1\" result=\"b\" type=\"matrix\" values=\"0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 \" />\n" - "<feBlend in2=\"g\" mode=\"darken\" in=\"r\" result=\"minrg\" />\n" - "<feBlend in2=\"b\" mode=\"darken\" in=\"minrg\" result=\"p\" />\n" - "<feBlend in2=\"g\" mode=\"lighten\" in=\"r\" result=\"maxrg\" />\n" - "<feBlend in2=\"b\" mode=\"lighten\" in=\"maxrg\" result=\"q\" />\n" - "<feComponentTransfer in=\"q\" result=\"q2\">\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Tritone, custom\">\n" + "<feColorMatrix type=\"hueRotate\" result=\"colormatrix1\" values=\"%s\" />\n" + "<feColorMatrix in=\"colormatrix1\" result=\"r\" type=\"matrix\" values=\"1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 \" />\n" + "<feColorMatrix in=\"colormatrix1\" result=\"g\" type=\"matrix\" values=\"0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 \" />\n" + "<feColorMatrix in=\"colormatrix1\" result=\"b\" type=\"matrix\" values=\"0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 \" />\n" + "<feBlend in2=\"g\" mode=\"darken\" in=\"r\" result=\"minrg\" />\n" + "<feBlend in2=\"b\" mode=\"darken\" in=\"minrg\" result=\"p\" />\n" + "<feBlend in2=\"g\" mode=\"lighten\" in=\"r\" result=\"maxrg\" />\n" + "<feBlend in2=\"b\" mode=\"lighten\" in=\"maxrg\" result=\"q\" />\n" + "<feComponentTransfer in=\"q\" result=\"q2\">\n" "<feFuncR type=\"linear\" slope=\"0\" />\n" - "</feComponentTransfer>\n" - "<feBlend in2=\"q2\" mode=\"%s\" in=\"p\" result=\"pq\" />\n" - "<feColorMatrix in=\"pq\" result=\"qminp\" type=\"matrix\" values=\"-1 1 0 0 0 -1 1 0 0 0 -1 1 0 0 0 0 0 0 0 1 \" />\n" - "<feFlood in=\"qminp\" flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood\" />\n" - "<feComposite in=\"%s\" in2=\"%s\" result=\"qminpc\" operator=\"arithmetic\" k1=\"1\" />\n" - "<feGaussianBlur stdDeviation=\"%s\" />\n" - "<feBlend in2=\"%s\" blend=\"normal\" result=\"blend6\" mode=\"%s\" />\n" - "<feComposite in=\"%s\" in2=\"%s\" operator=\"arithmetic\" k1=\"%s\" k2=\"1\" k3=\"%s\" k4=\"0\" result=\"composite2\" />\n" - "<feComposite in2=\"SourceGraphic\" in=\"composite2\" operator=\"in\" />\n" + "</feComponentTransfer>\n" + "<feBlend in2=\"q2\" mode=\"%s\" in=\"p\" result=\"pq\" />\n" + "<feColorMatrix in=\"pq\" result=\"qminp\" type=\"matrix\" values=\"-1 1 0 0 0 -1 1 0 0 0 -1 1 0 0 0 0 0 0 0 1 \" />\n" + "<feFlood in=\"qminp\" flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood\" />\n" + "<feComposite in=\"%s\" in2=\"%s\" result=\"qminpc\" operator=\"arithmetic\" k1=\"1\" />\n" + "<feGaussianBlur stdDeviation=\"%s\" />\n" + "<feBlend in2=\"%s\" blend=\"normal\" result=\"blend6\" mode=\"%s\" />\n" + "<feComposite in=\"%s\" in2=\"%s\" operator=\"arithmetic\" k1=\"%s\" k2=\"1\" k3=\"%s\" k4=\"0\" result=\"composite2\" />\n" + "<feComposite in2=\"SourceGraphic\" in=\"composite2\" operator=\"in\" />\n" "</filter>\n", dist.str().c_str(), globalblend.str().c_str(), a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), c1in.str().c_str(), c1in2.str().c_str(), glow.str().c_str(), b6in2.str().c_str(), glowblend.str().c_str(), c2in.str().c_str(), c2in2.str().c_str(), llight.str().c_str(), glight.str().c_str()); - return _filter; + return _filter; }; /* Tritone filter */ }; /* namespace Filter */ diff --git a/src/extension/internal/filter/drop-shadow.h b/src/extension/internal/filter/drop-shadow.h index 0cd2a8eeb..c80571d67 100644 --- a/src/extension/internal/filter/drop-shadow.h +++ b/src/extension/internal/filter/drop-shadow.h @@ -34,10 +34,10 @@ public: "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" "<name>" N_("Drop Shadow") "</name>\n" "<id>org.inkscape.effect.filter.drop-shadow</id>\n" - "<param name=\"blur\" gui-text=\"" N_("Blur radius (px):") "\" type=\"float\" min=\"0.0\" max=\"200.0\">2.0</param>\n" - "<param name=\"opacity\" gui-text=\"" N_("Opacity (%):") "\" type=\"float\" min=\"0.0\" max=\"100.0\">50</param>\n" - "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px):") "\" type=\"float\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" - "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px):") "\" type=\"float\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" + "<param name=\"blur\" gui-text=\"" N_("Blur radius (px):") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"200.0\">2.0</param>\n" + "<param name=\"opacity\" gui-text=\"" N_("Opacity (%):") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"100.0\">50</param>\n" + "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" + "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" "<effect>\n" "<object-type>all</object-type>\n" "<effects-menu>\n" @@ -94,10 +94,10 @@ public: "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" "<name>" N_("Drop Glow") "</name>\n" "<id>org.inkscape.effect.filter.drop-glow</id>\n" - "<param name=\"blur\" gui-text=\"" N_("Blur radius (px):") "\" type=\"float\" min=\"0.0\" max=\"200.0\">2.0</param>\n" - "<param name=\"opacity\" gui-text=\"" N_("Opacity (%):") "\" type=\"float\" min=\"0.0\" max=\"100.0\">50</param>\n" - "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px):") "\" type=\"float\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" - "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px):") "\" type=\"float\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" + "<param name=\"blur\" gui-text=\"" N_("Blur radius (px):") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"200.0\">2.0</param>\n" + "<param name=\"opacity\" gui-text=\"" N_("Opacity (%):") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"100.0\">50</param>\n" + "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" + "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">4.0</param>\n" "<effect>\n" "<object-type>all</object-type>\n" "<effects-menu>\n" @@ -141,71 +141,6 @@ DropGlow::get_filter_text (Inkscape::Extension::Extension * ext) return _filter; }; -class ColorizableDropShadow : public Inkscape::Extension::Internal::Filter::Filter { -protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); - -public: - ColorizableDropShadow ( ) : Filter() { }; - virtual ~ColorizableDropShadow ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Drop shadow, color -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.colorizable-drop-shadow</id>\n" - "<param name=\"blur\" gui-text=\"" N_("Blur radius (px):") "\" type=\"float\" min=\"0.0\" max=\"200.0\">3.0</param>\n" - "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px):") "\" type=\"float\" min=\"-50.0\" max=\"50.0\">6.0</param>\n" - "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px):") "\" type=\"float\" min=\"-50.0\" max=\"50.0\">6.0</param>\n" - "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">127</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Colorizable Drop shadow") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new ColorizableDropShadow()); - }; - -}; - -gchar const * -ColorizableDropShadow::get_filter_text (Inkscape::Extension::Extension * ext) -{ - if (_filter != NULL) g_free((void *)_filter); - - std::ostringstream blur; - std::ostringstream a; - std::ostringstream r; - std::ostringstream g; - std::ostringstream b; - std::ostringstream x; - std::ostringstream y; - - guint32 color = ext->get_param_color("color"); - - blur << ext->get_param_float("blur"); - x << ext->get_param_float("xoffset"); - y << ext->get_param_float("yoffset"); - a << (color & 0xff) / 255.0F; - r << ((color >> 24) & 0xff); - g << ((color >> 16) & 0xff); - b << ((color >> 8) & 0xff); - - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1.2\" width=\"1.2\" y=\"-0.1\" x=\"-0.1\" inkscape:label=\"Drop shadow, color -EXP-\">\n" - "<feFlood flood-opacity=\"%s\" result=\"flood\" flood-color=\"rgb(%s,%s,%s)\" />\n" - "<feComposite in2=\"SourceGraphic\" in=\"flood\" result=\"composite\" operator=\"in\" />\n" - "<feGaussianBlur result=\"blur\" stdDeviation=\"%s\" in=\"composite\" />\n" - "<feOffset result=\"offsetBlur\" dx=\"%s\" dy=\"%s\" />\n" - "<feComposite in2=\"offsetBlur\" in=\"SourceGraphic\" operator=\"over\" result=\"compositeBlur\" />\n" - "</filter>\n", a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), blur.str().c_str(), x.str().c_str(), y.str().c_str()); - - return _filter; -}; }; /* namespace Filter */ }; /* namespace Internal */ }; /* namespace Extension */ diff --git a/src/extension/internal/filter/experimental.h b/src/extension/internal/filter/experimental.h index a8879720b..8d260f62e 100644..100755 --- a/src/extension/internal/filter/experimental.h +++ b/src/extension/internal/filter/experimental.h @@ -3,15 +3,17 @@ /* Change the 'EXPERIMENTAL' above to be your file name */ /* - * Copyright (C) 2010 Authors: + * Copyright (C) 2011 Authors: * Ivan Louette (filters) * Nicolas Dufour (UI) <nicoduf@yahoo.fr> * * Experimental filters (no assigned menu) * Chromolitho + * Cross engraving * Drawing + * Neon draw * Posterize - * Test filter (should no be used...) + * Posterize basic * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -38,15 +40,14 @@ namespace Filter { * Transparent (boolean, default unchecked) -> Checked = colormatrix5 (in="colormatrix4"), Unchecked = colormatrix5 (in="component1") * Invert (boolean, default false) -> component1 (tableValues) [adds a trailing 0] * Dented (boolean, default false) -> component1 (tableValues) [adds intermediate 0s] - * Expand white (0->5, default 1) -> component1 (tableValues) [0="0 1", 5="0 1 1 1 1 1 1"] - * Lightness (0->10, default 0) -> composite1 (k1) + * Lightness (0.->10., default 0.) -> composite1 (k1) * Saturation (0.->1., default 1.) -> colormatrix3 (values) * Noise reduction (1->1000, default 20) -> convolve (kernelMatrix, central value -1001->-2000, default -1020) * Drawing blend (enum, default Normal) -> blend1 (mode) * Smoothness (0.01->10, default 1) -> blur1 (stdDeviation) * Grain (boolean, default unchecked) -> Checked = blend2 (in="colormatrix2"), Unchecked = blend2 (in="blur1") - * Grain x frequency (0.->100, default 100) -> turbulence1 (baseFrequency, first value) - * Grain y frequency (0.->100, default 100) -> turbulence1 (baseFrequency, second value) + * Grain x frequency (0.->1000, default 1000) -> turbulence1 (baseFrequency, first value) + * Grain y frequency (0.->1000, default 1000) -> turbulence1 (baseFrequency, second value) * Grain complexity (1->5, default 1) -> turbulence1 (numOctaves) * Grain variation (0->1000, default 0) -> turbulence1 (seed) * Grain expansion (1.->50., default 1.) -> colormatrix1 (n-1 value) @@ -56,70 +57,70 @@ namespace Filter { */ class Chromolitho : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Chromolitho ( ) : Filter() { }; - virtual ~Chromolitho ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Chromolitho, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Chromolitho</id>\n" - "<param name=\"tab\" type=\"notebook\">\n" - "<page name=\"optionstab\" _gui-text=\"Options\">\n" - "<param name=\"drawing\" gui-text=\"" N_("Drawing mode") "\" type=\"boolean\" >true</param>\n" - "<param name=\"dblend\" gui-text=\"" N_("Drawing blend:") "\" type=\"enum\">\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"screen\">Screen</_item>\n" - "<_item value=\"lighten\">Lighten</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "<param name=\"transparent\" gui-text=\"" N_("Transparent") "\" type=\"boolean\" >false</param>\n" - "<param name=\"dented\" gui-text=\"" N_("Dented") "\" type=\"boolean\" >false</param>\n" - "<param name=\"inverted\" gui-text=\"" N_("Inverted") "\" type=\"boolean\" >false</param>\n" - "<param name=\"light\" gui-text=\"" N_("Lightness:") "\" type=\"int\" min=\"0\" max=\"10\">0</param>\n" - "<param name=\"saturation\" gui-text=\"" N_("Saturation:") "\" type=\"float\" min=\"0\" max=\"1\">1</param>\n" - "<param name=\"noise\" gui-text=\"" N_("Noise reduction:") "\" type=\"int\" min=\"1\" max=\"1000\">20</param>\n" - "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" min=\"0.01\" max=\"10\">1</param>\n" - "</page>\n" - "<page name=\"graintab\" _gui-text=\"Grain\">\n" - "<param name=\"grain\" gui-text=\"" N_("Grain mode") "\" type=\"boolean\" >true</param>\n" - "<param name=\"grainxf\" gui-text=\"" N_("X frequency:") "\" type=\"float\" min=\"0\" max=\"100\">100</param>\n" - "<param name=\"grainyf\" gui-text=\"" N_("Y frequency:") "\" type=\"float\" min=\"0\" max=\"100\">100</param>\n" - "<param name=\"grainc\" gui-text=\"" N_("Complexity:") "\" type=\"int\" min=\"1\" max=\"5\">1</param>\n" - "<param name=\"grainv\" gui-text=\"" N_("Variation:") "\" type=\"int\" min=\"0\" max=\"1000\">0</param>\n" - "<param name=\"grainexp\" gui-text=\"" N_("Expansion:") "\" type=\"float\" min=\"1\" max=\"50\">1</param>\n" - "<param name=\"grainero\" gui-text=\"" N_("Erosion:") "\" type=\"float\" min=\"0\" max=\"40\">0</param>\n" - "<param name=\"graincol\" gui-text=\"" N_("Color") "\" type=\"boolean\" >true</param>\n" - "<param name=\"gblend\" gui-text=\"" N_("Grain blend:") "\" type=\"enum\">\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"multiply\">Multiply</_item>\n" - "<_item value=\"screen\">Screen</_item>\n" - "<_item value=\"lighten\">Lighten</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "</page>\n" - "</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Chromo effect with customizable edge drawing and graininess") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Chromolitho()); - }; + Chromolitho ( ) : Filter() { }; + virtual ~Chromolitho ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Chromolitho, custom") "</name>\n" + "<id>org.inkscape.effect.filter.Chromolitho</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<param name=\"drawing\" gui-text=\"" N_("Drawing mode") "\" type=\"boolean\" >true</param>\n" + "<param name=\"dblend\" gui-text=\"" N_("Drawing blend:") "\" type=\"enum\">\n" + "<_item value=\"darken\">Darken</_item>\n" + "<_item value=\"normal\">Normal</_item>\n" + "<_item value=\"multiply\">Multiply</_item>\n" + "<_item value=\"screen\">Screen</_item>\n" + "<_item value=\"lighten\">Lighten</_item>\n" + "</param>\n" + "<param name=\"transparent\" gui-text=\"" N_("Transparent") "\" type=\"boolean\" >false</param>\n" + "<param name=\"dented\" gui-text=\"" N_("Dented") "\" type=\"boolean\" >false</param>\n" + "<param name=\"inverted\" gui-text=\"" N_("Inverted") "\" type=\"boolean\" >false</param>\n" + "<param name=\"light\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"10\">0</param>\n" + "<param name=\"saturation\" gui-text=\"" N_("Saturation:") "\" type=\"float\" precision=\"2\" appearance=\"full\" min=\"0\" max=\"1\">1</param>\n" + "<param name=\"noise\" gui-text=\"" N_("Noise reduction:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"1000\">10</param>\n" + "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">1</param>\n" + "</page>\n" + "<page name=\"graintab\" _gui-text=\"Grain\">\n" + "<param name=\"grain\" gui-text=\"" N_("Grain mode") "\" type=\"boolean\" >true</param>\n" + "<param name=\"grainxf\" gui-text=\"" N_("Horizontal frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1000\">1000</param>\n" + "<param name=\"grainyf\" gui-text=\"" N_("Vertical frequency:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"1000\">1000</param>\n" + "<param name=\"grainc\" gui-text=\"" N_("Complexity:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"5\">1</param>\n" + "<param name=\"grainv\" gui-text=\"" N_("Variation:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"1000\">0</param>\n" + "<param name=\"grainexp\" gui-text=\"" N_("Expansion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"1\" max=\"50\">1</param>\n" + "<param name=\"grainero\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0\" max=\"40\">0</param>\n" + "<param name=\"graincol\" gui-text=\"" N_("Color") "\" type=\"boolean\" >true</param>\n" + "<param name=\"gblend\" gui-text=\"" N_("Grain blend:") "\" type=\"enum\">\n" + "<_item value=\"normal\">Normal</_item>\n" + "<_item value=\"multiply\">Multiply</_item>\n" + "<_item value=\"screen\">Screen</_item>\n" + "<_item value=\"lighten\">Lighten</_item>\n" + "<_item value=\"darken\">Darken</_item>\n" + "</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Chromo effect with customizable edge drawing and graininess") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Chromolitho()); + }; }; gchar const * Chromolitho::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream b1in; std::ostringstream b2in; @@ -149,7 +150,7 @@ Chromolitho::get_filter_text (Inkscape::Extension::Extension * ext) col3in << "colormatrix4"; else col3in << "component1"; - light << ext->get_param_int("light"); + light << ext->get_param_float("light"); saturation << ext->get_param_float("saturation"); noise << (-1000 - ext->get_param_int("noise")); dblend << ext->get_param_enum("dblend"); @@ -167,8 +168,8 @@ Chromolitho::get_filter_text (Inkscape::Extension::Extension * ext) b2in << "colormatrix2"; else b2in << "blur1"; - grainxf << (ext->get_param_float("grainxf") / 100); - grainyf << (ext->get_param_float("grainyf") / 100); + grainxf << (ext->get_param_float("grainxf") / 1000); + grainyf << (ext->get_param_float("grainyf") / 1000); grainc << ext->get_param_int("grainc"); grainv << ext->get_param_int("grainv"); gblend << ext->get_param_enum("gblend"); @@ -179,135 +180,236 @@ Chromolitho::get_filter_text (Inkscape::Extension::Extension * ext) else graincol << "0"; - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Chromolitho, custom -EXP-\">\n" - - "<feComposite stdDeviation=\"1\" in=\"SourceGraphic\" in2=\"SourceGraphic\" operator=\"arithmetic\" k1=\"%s\" k2=\"1\" result=\"composite1\" />\n" - "<feConvolveMatrix in=\"composite1\" kernelMatrix=\"0 250 0 250 %s 250 0 250 0 \" order=\"3 3\" stdDeviation=\"1\" result=\"convolve1\" />\n" - "<feBlend in=\"%s\" in2=\"composite1\" mode=\"%s\" blend=\"normal\" stdDeviation=\"1\" result=\"blend1\" />\n" - "<feGaussianBlur in=\"blend1\" stdDeviation=\"%s\" result=\"blur1\" />\n" - "<feTurbulence baseFrequency=\"%s %s\" numOctaves=\"%s\" seed=\"%s\" type=\"fractalNoise\" result=\"turbulence1\" />\n" - "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"colormatrix1\" />\n" - "<feColorMatrix type=\"saturate\" stdDeviation=\"3\" values=\"%s\" result=\"colormatrix2\" />\n" - "<feBlend in=\"%s\" in2=\"blur1\" stdDeviation=\"1\" blend=\"normal\" mode=\"%s\" result=\"blend2\" />\n" - "<feColorMatrix in=\"blend2\" type=\"saturate\" values=\"%s\" result=\"colormatrix3\" />\n" - "<feComponentTransfer in=\"colormatrix3\" stdDeviation=\"2\" result=\"component1\">\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Chromolitho, custom\">\n" + "<feComposite stdDeviation=\"1\" in=\"SourceGraphic\" in2=\"SourceGraphic\" operator=\"arithmetic\" k1=\"%s\" k2=\"1\" result=\"composite1\" />\n" + "<feConvolveMatrix in=\"composite1\" kernelMatrix=\"0 250 0 250 %s 250 0 250 0 \" order=\"3 3\" stdDeviation=\"1\" result=\"convolve1\" />\n" + "<feBlend in=\"%s\" in2=\"composite1\" mode=\"%s\" blend=\"normal\" stdDeviation=\"1\" result=\"blend1\" />\n" + "<feGaussianBlur in=\"blend1\" stdDeviation=\"%s\" result=\"blur1\" />\n" + "<feTurbulence baseFrequency=\"%s %s\" numOctaves=\"%s\" seed=\"%s\" type=\"fractalNoise\" result=\"turbulence1\" />\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"colormatrix1\" />\n" + "<feColorMatrix type=\"saturate\" stdDeviation=\"3\" values=\"%s\" result=\"colormatrix2\" />\n" + "<feBlend in=\"%s\" in2=\"blur1\" stdDeviation=\"1\" blend=\"normal\" mode=\"%s\" result=\"blend2\" />\n" + "<feColorMatrix in=\"blend2\" type=\"saturate\" values=\"%s\" result=\"colormatrix3\" />\n" + "<feComponentTransfer in=\"colormatrix3\" stdDeviation=\"2\" result=\"component1\">\n" "<feFuncR type=\"discrete\" tableValues=\"%s\" />\n" "<feFuncG type=\"discrete\" tableValues=\"%s\" />\n" "<feFuncB type=\"discrete\" tableValues=\"%s\" />\n" - "</feComponentTransfer>\n" - "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 -0.2125 -0.7154 -0.0721 1 0 \" result=\"colormatrix4\" />\n" - "<feColorMatrix in=\"%s\" values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 15 0 \" result=\"colormatrix5\" />\n" - "<feComposite in2=\"SourceGraphic\" operator=\"in\" result=\"composite2\" />\n" + "</feComponentTransfer>\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 -0.2125 -0.7154 -0.0721 1 0 \" result=\"colormatrix4\" />\n" + "<feColorMatrix in=\"%s\" values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 15 0 \" result=\"colormatrix5\" />\n" + "<feComposite in2=\"SourceGraphic\" operator=\"in\" result=\"composite2\" />\n" "</filter>\n", light.str().c_str(), noise.str().c_str(), b1in.str().c_str(), dblend.str().c_str(), smooth.str().c_str(), grainxf.str().c_str(), grainyf.str().c_str(), grainc.str().c_str(), grainv.str().c_str(), grainexp.str().c_str(), grainero.str().c_str(), graincol.str().c_str(), b2in.str().c_str(), gblend.str().c_str(), saturation.str().c_str(), transf.str().c_str(), transf.str().c_str(), transf.str().c_str(), col3in.str().c_str()); - return _filter; + return _filter; }; /* Chromolitho filter */ /** + \brief Custom predefined Cross engraving filter. + + Convert image to an engraving made of vertical and horizontal lines + + Filter's parameters: + * Clean-up (1->500, default 30) -> convolve1 (kernelMatrix, central value -1001->-1500, default -1030) + * Dilatation (1.->50., default 1) -> color2 (n-1th value) + * Erosion (0.->50., default 0) -> color2 (nth value 0->-50) + * Strength (0.->10., default 0.5) -> composite2 (k2) + * Length (0.5->20, default 4) -> blur1 (stdDeviation x), blur2 (stdDeviation y) + * Transparent (boolean, default false) -> composite 4 (in, true->composite3, false->blend) +*/ +class CrossEngraving : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + CrossEngraving ( ) : Filter() { }; + virtual ~CrossEngraving ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Cross engraving, custom") "</name>\n" + "<id>org.inkscape.effect.filter.CrossEngraving</id>\n" + "<param name=\"clean\" gui-text=\"" N_("Clean-up:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"500\">30</param>\n" + "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"50\">1</param>\n" + "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"50\">0</param>\n" + "<param name=\"strength\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" min=\"0.1\" max=\"10\">0.5</param>\n" + "<param name=\"length\" gui-text=\"" N_("Length:") "\" type=\"float\" appearance=\"full\" min=\"0.5\" max=\"20\">4</param>\n" + "<param name=\"trans\" gui-text=\"" N_("Transparent") "\" type=\"boolean\" >false</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Convert image to an engraving made of vertical and horizontal lines") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new CrossEngraving()); + }; +}; + +gchar const * +CrossEngraving::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream clean; + std::ostringstream dilat; + std::ostringstream erosion; + std::ostringstream strength; + std::ostringstream length; + std::ostringstream trans; + + clean << (-1000 - ext->get_param_int("clean")); + dilat << ext->get_param_float("dilat"); + erosion << (- ext->get_param_float("erosion")); + strength << ext->get_param_float("strength"); + length << ext->get_param_float("length"); + if (ext->get_param_bool("trans")) + trans << "composite3"; + else + trans << "blend"; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Cross engraving, custom\">\n" + "<feConvolveMatrix in=\"SourceGraphic\" targetY=\"1\" targetX=\"1\" kernelMatrix=\"0 250 0 250 %s 250 0 250 0 \" order=\"3 3\" result=\"convolve\" />\n" + "<feComposite in=\"convolve\" in2=\"convolve\" k1=\"1\" k2=\"1\" operator=\"arithmetic\" result=\"composite1\" />\n" + "<feColorMatrix in=\"composite1\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2125 -0.7154 -0.0721 1 0 \" result=\"color1\" />\n" + "<feColorMatrix in=\"color1\" values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"color2\" />\n" + "<feComposite in=\"color2\" in2=\"color2\" operator=\"arithmetic\" k2=\"%s\" result=\"composite2\" />\n" + "<feGaussianBlur in=\"composite2\" stdDeviation=\"%s 0.01\" result=\"blur1\" />\n" + "<feGaussianBlur in=\"composite2\" stdDeviation=\"0.01 %s\" result=\"blur2\" />\n" + "<feComposite in=\"blur2\" in2=\"blur1\" k3=\"1\" k2=\"1\" operator=\"arithmetic\" result=\"composite3\" />\n" + "<feFlood flood-color=\"rgb(255,255,255)\" flood-opacity=\"1\" result=\"flood\" />\n" + "<feBlend in=\"flood\" in2=\"composite3\" blend=\"normal\" mode=\"multiply\" result=\"blend\" />\n" + "<feComposite in=\"%s\" in2=\"SourceGraphic\" operator=\"in\" result=\"composite4\" />\n" + "</filter>\n", clean.str().c_str(), dilat.str().c_str(), erosion.str().c_str(), strength.str().c_str(), length.str().c_str(), length.str().c_str(), trans.str().c_str()); + + return _filter; +}; /* CrossEngraving filter */ + +/** \brief Custom predefined Drawing filter. Convert images to duochrome drawings. Filter's parameters: - * Simplification (0.01->10, default 0.7) -> blur1 (stdDeviation) - * Lightness (0->50, default 5) -> convolve (kernelMatrix, central value -1000->-1050, default -1005) - * Smoothness (0.01->10, default 0.7) -> blur2 (stdDeviation) - * Dilatation (3->100, default 6) -> colormatrix3 (n-1th value) - - * Blur (0.01->10., default 1.) -> blur3 (stdDeviation) - * Blur spread (3->20, default 6) -> colormatrix5 (n-1th value) - * Blur erosion (-2->0, default -2) -> colormatrix5 (nth value) - - * Stroke color (guint, default 205,0,0) -> flood2 (flood-opacity, flood-color) - * Image on stroke (boolean, default false) -> composite1 (in="flood2" true-> in="SourceGraphic") - * Image on stroke opacity (0.->1., default 1) -> composite3 (k3) - * Fill color (guint, default 255,203,0) -> flood3 (flood-opacity, flood-color) - * Image on fill (boolean, default false) -> composite2 (in="flood3" true-> in="SourceGraphic") - * Image on fill opacity (0.->1., default 1) -> composite3 (k2) + * Simplification strength (0.01->20, default 0.6) -> blur1 (stdDeviation) + * Clean-up (1->500, default 10) -> convolve1 (kernelMatrix, central value -1001->-1500, default -1010) + * Erase (0.->6., default 0) -> composite1 (k4) + * Smoothness strength (0.01->20, default 0.6) -> blur2 (stdDeviation) + * Dilatation (1.->50., default 6) -> color2 (n-1th value) + * Erosion (0.->50., default 2) -> color2 (nth value 0->-50) + * Transluscent (boolean, default false) -> composite 8 (in, true->merge1, false->color5) + + * Blur strength (0.01->20., default 1.) -> blur3 (stdDeviation) + * Blur dilatation (1.->50., default 6) -> color4 (n-1th value) + * Blur erosion (0.->50., default 2) -> color4 (nth value 0->-50) + + * Stroke color (guint, default 64,64,64,255) -> flood2 (flood-color), composite3 (k2) + * Image on stroke (boolean, default false) -> composite2 (in="flood2" true-> in="SourceGraphic") + * Offset (-100->100, default 0) -> offset (val) + + * Fill color (guint, default 200,200,200,255) -> flood3 (flood-opacity), composite5 (k2) + * Image on fill (boolean, default false) -> composite4 (in="flood3" true-> in="SourceGraphic") + */ class Drawing : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Drawing ( ) : Filter() { }; - virtual ~Drawing ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Drawing, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Drawing</id>\n" - "<param name=\"tab\" type=\"notebook\">\n" - "<page name=\"optionstab\" _gui-text=\"Options\">\n" - "<param name=\"simply\" gui-text=\"" N_("Simplification:") "\" type=\"float\" min=\"0.01\" max=\"10\">0.7</param>\n" - "<param name=\"light\" gui-text=\"" N_("Lightness:") "\" type=\"int\" min=\"0\" max=\"50\">5</param>\n" - "<param name=\"smooth\" gui-text=\"" N_("Smoothness:") "\" type=\"float\" min=\"0.01\" max=\"10\">0.7</param>\n" - "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"int\" min=\"3\" max=\"100\">6</param>\n" - "<_param name=\"blurheader\" type=\"groupheader\">Blur</_param>\n" - "<param name=\"blur\" gui-text=\"" N_("Level:") "\" type=\"float\" min=\"0.01\" max=\"10\">1</param>\n" - "<param name=\"spread\" gui-text=\"" N_("Spread:") "\" type=\"int\" min=\"3\" max=\"20\">6</param>\n" - "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"int\" min=\"-2\" max=\"0\">-2</param>\n" - "</page>\n" - "<page name=\"co11tab\" _gui-text=\"Fill color\">\n" - "<param name=\"fcolor\" gui-text=\"" N_("Fill color") "\" type=\"color\">-3473153</param>\n" - "<param name=\"iof\" gui-text=\"" N_("Image on fill") "\" type=\"boolean\" >false</param>\n" - "<param name=\"iofo\" gui-text=\"" N_("Image on fill opacity:") "\" type=\"float\" min=\"0\" max=\"1\">1</param>\n" - "</page>\n" - "<page name=\"co12tab\" _gui-text=\"Stroke color\">\n" - "<param name=\"scolor\" gui-text=\"" N_("Stroke color") "\" type=\"color\">-855637761</param>\n" - "<param name=\"ios\" gui-text=\"" N_("Image on stroke") "\" type=\"boolean\" >false</param>\n" - "<param name=\"ioso\" gui-text=\"" N_("Image on stroke opacity:") "\" type=\"float\" min=\"0\" max=\"1\">1</param>\n" - "</page>\n" - "</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Convert images to duochrome drawings") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Drawing()); - }; + Drawing ( ) : Filter() { }; + virtual ~Drawing ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Drawing, custom") "</name>\n" + "<id>org.inkscape.effect.filter.Drawing</id>\n" + "<param name=\"tab\" type=\"notebook\">\n" + "<page name=\"optionstab\" _gui-text=\"Options\">\n" + "<_param name=\"simplifyheader\" type=\"description\" appearance=\"header\">Simplify</_param>\n" + "<param name=\"simply\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.6</param>\n" + "<param name=\"clean\" gui-text=\"" N_("Clean-up:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"500\">10</param>\n" + "<param name=\"erase\" gui-text=\"" N_("Erase:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"60\">0</param>\n" + "<param name=\"transluscent\" gui-text=\"" N_("Transluscent") "\" type=\"boolean\" >false</param>\n" + "<_param name=\"smoothheader\" type=\"description\" appearance=\"header\">Smoothness</_param>\n" + "<param name=\"smooth\" gui-text=\"" N_("Strength:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">0.6</param>\n" + "<param name=\"dilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"50\">6</param>\n" + "<param name=\"erosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"50\">2</param>\n" + "<_param name=\"meltheader\" type=\"description\" appearance=\"header\">Melt</_param>\n" + "<param name=\"blur\" gui-text=\"" N_("Level:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">1</param>\n" + "<param name=\"bdilat\" gui-text=\"" N_("Dilatation:") "\" type=\"float\" appearance=\"full\" min=\"1\" max=\"50\">6</param>\n" + "<param name=\"berosion\" gui-text=\"" N_("Erosion:") "\" type=\"float\" appearance=\"full\" min=\"0\" max=\"50\">2</param>\n" + "</page>\n" + "<page name=\"co11tab\" _gui-text=\"Fill color\">\n" + "<param name=\"fcolor\" gui-text=\"" N_("Fill color") "\" type=\"color\">-1515870721</param>\n" + "<param name=\"iof\" gui-text=\"" N_("Image on fill") "\" type=\"boolean\" >false</param>\n" + "</page>\n" + "<page name=\"co12tab\" _gui-text=\"Stroke color\">\n" + "<param name=\"scolor\" gui-text=\"" N_("Stroke color") "\" type=\"color\">589505535</param>\n" + "<param name=\"ios\" gui-text=\"" N_("Image on stroke") "\" type=\"boolean\" >false</param>\n" + "<param name=\"offset\" gui-text=\"" N_("Offset:") "\" type=\"int\" appearance=\"full\" min=\"-100\" max=\"100\">0</param>\n" + "</page>\n" + "</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Convert images to duochrome drawings") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Drawing()); + }; }; gchar const * Drawing::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream simply; - std::ostringstream light; + std::ostringstream clean; + std::ostringstream erase; std::ostringstream smooth; std::ostringstream dilat; - std::ostringstream blur; - std::ostringstream spread; std::ostringstream erosion; + std::ostringstream transluscent; + std::ostringstream offset; + std::ostringstream blur; + std::ostringstream bdilat; + std::ostringstream berosion; std::ostringstream strokea; std::ostringstream stroker; std::ostringstream strokeg; std::ostringstream strokeb; std::ostringstream ios; - std::ostringstream ioso; std::ostringstream filla; std::ostringstream fillr; std::ostringstream fillg; std::ostringstream fillb; std::ostringstream iof; - std::ostringstream iofo; simply << ext->get_param_float("simply"); - light << (-1000 - ext->get_param_int("light")); + clean << (-1000 - ext->get_param_int("clean")); + erase << (ext->get_param_float("erase") / 10); smooth << ext->get_param_float("smooth"); - dilat << ext->get_param_int("dilat"); - + dilat << ext->get_param_float("dilat"); + erosion << (- ext->get_param_float("erosion")); + if (ext->get_param_bool("transluscent")) + transluscent << "merge1"; + else + transluscent << "color5"; + offset << ext->get_param_int("offset"); + blur << ext->get_param_float("blur"); - spread << ext->get_param_int("spread"); - erosion << ext->get_param_int("erosion"); + bdilat << ext->get_param_float("bdilat"); + berosion << (- ext->get_param_float("berosion")); guint32 fcolor = ext->get_param_color("fcolor"); fillr << ((fcolor >> 24) & 0xff); @@ -318,7 +420,6 @@ Drawing::get_filter_text (Inkscape::Extension::Extension * ext) iof << "SourceGraphic"; else iof << "flood3"; - iofo << ext->get_param_float("iofo"); guint32 scolor = ext->get_param_color("scolor"); stroker << ((scolor >> 24) & 0xff); @@ -329,99 +430,213 @@ Drawing::get_filter_text (Inkscape::Extension::Extension * ext) ios << "SourceGraphic"; else ios << "flood2"; - ioso << ext->get_param_float("ioso"); - - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Drawing, custom -EXP-\">\n" + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Drawing, custom\">\n" "<feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"%s\" result=\"blur1\" />\n" - "<feConvolveMatrix in=\"blur1\" order=\"3 3\" kernelMatrix=\"0 250 0 250 %s 250 0 250 0 \" divisor=\"1\" targetX=\"1\" targetY=\"1\" preserveAlpha=\"true\" bias=\"0\" stdDeviation=\"1\" result=\"convolve\" />\n" - "<feColorMatrix values=\"0 -100 0 0 1 0 -100 0 0 1 0 -100 0 0 1 0 0 0 1 0 \" result=\"colormatrix1\" />\n" - "<feColorMatrix in=\"colormatrix1\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2125 -0.7154 -0.0721 1 0 \" result=\"colormatrix2\" />\n" + "<feConvolveMatrix in=\"blur1\" targetX=\"1\" targetY=\"1\" order=\"3 3\" kernelMatrix=\"0 250 0 250 %s 250 0 250 0 \" result=\"convolve1\" />\n" + "<feComposite in=\"convolve1\" in2=\"convolve1\" k1=\"1\" k2=\"1\" k4=\"%s\" operator=\"arithmetic\" stdDeviation=\"1\" result=\"composite1\" />\n" + "<feColorMatrix in=\"composite1\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2125 -0.7154 -0.0721 1 0 \" result=\"color1\" />\n" "<feGaussianBlur stdDeviation=\"%s\" result=\"blur2\" />\n" - "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s -2 \" result=\"colormatrix3\" />\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"color2\" />\n" "<feFlood flood-color=\"rgb(255,255,255)\" result=\"flood1\" />\n" - "<feBlend in2=\"colormatrix3\" blend=\"normal\" mode=\"multiply\" result=\"blend1\" />\n" - "<feComponentTransfer in=\"blend1\" result=\"component1\">\n" - "<feFuncR tableValues=\"0 1 1\" type=\"discrete\" />\n" - "<feFuncG tableValues=\"0 1 1\" type=\"discrete\" />\n" - "<feFuncB tableValues=\"0 1 1\" type=\"discrete\" />\n" + "<feBlend in2=\"color2\" mode=\"multiply\" blend=\"normal\" result=\"blend1\" />\n" + "<feComponentTransfer in=\"blend1\" stdDeviation=\"2\" result=\"component1\">\n" + "<feFuncR type=\"discrete\" tableValues=\"0 1 1 1\" />\n" + "<feFuncG type=\"discrete\" tableValues=\"0 1 1 1\" />\n" + "<feFuncB type=\"discrete\" tableValues=\"0 1 1 1\" />\n" "</feComponentTransfer>\n" "<feGaussianBlur stdDeviation=\"%s\" result=\"blur3\" />\n" - "<feColorMatrix in=\"blur3\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2125 -0.7154 -0.0721 1 0 \" result=\"colormatrix4\" />\n" - "<feColorMatrix stdDeviation=\"3\" values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"colormatrix5\" />\n" - "<feColorMatrix in=\"colormatrix5\" type=\"saturate\" values=\"1\" result=\"colormatrix6\" />\n" - "<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" stdDeviation=\"3\" result=\"flood2\" />\n" - "<feComposite in=\"%s\" in2=\"colormatrix6\" operator=\"in\" result=\"composite1\" />\n" - "<feFlood flood-opacity=\"%s\" in=\"colormatrix6\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood3\" />\n" - "<feComposite in=\"%s\" in2=\"colormatrix6\" operator=\"out\" result=\"composite2\" />\n" - "<feComposite in2=\"composite1\" operator=\"arithmetic\" k2=\"%s\" k3=\"%s\" result=\"composite3\" />\n" - "<feComposite in2=\"SourceGraphic\" operator=\"in\" />\n" - "</filter>\n", simply.str().c_str(), light.str().c_str(), smooth.str().c_str(), dilat.str().c_str(), blur.str().c_str(), spread.str().c_str(), erosion.str().c_str(), strokea.str().c_str(), stroker.str().c_str(), strokeg.str().c_str(), strokeb.str().c_str(), ios.str().c_str(), filla.str().c_str(), fillr.str().c_str(), fillg.str().c_str(), fillb.str().c_str(), iof.str().c_str(), iofo.str().c_str(), ioso.str().c_str()); - - return _filter; + "<feColorMatrix in=\"blur3\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2125 -0.7154 -0.0721 1 0 \" stdDeviation=\"1\" result=\"color3\" />\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 %s %s \" result=\"color4\" />\n" + "<feFlood flood-color=\"rgb(%s,%s,%s)\" result=\"flood2\" />\n" + "<feComposite in=\"%s\" in2=\"color4\" operator=\"in\" result=\"composite2\" />\n" + "<feComposite in=\"composite2\" in2=\"composite2\" operator=\"arithmetic\" k2=\"%s\" result=\"composite3\" />\n" + "<feOffset dx=\"%s\" dy=\"%s\" result=\"offset1\" />\n" + "<feFlood in=\"color4\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood3\" />\n" + "<feComposite in=\"%s\" in2=\"color4\" operator=\"out\" result=\"composite4\" />\n" + "<feComposite in=\"composite4\" in2=\"composite4\" operator=\"arithmetic\" k2=\"%s\" result=\"composite5\" />\n" + "<feMerge result=\"merge1\">\n" + "<feMergeNode in=\"composite5\" />\n" + "<feMergeNode in=\"offset1\" />\n" + "</feMerge>\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1.3 0 \" result=\"color5\" flood-opacity=\"0.56\" />\n" + "<feComposite in=\"%s\" in2=\"SourceGraphic\" operator=\"in\" result=\"composite8\" />\n" + "</filter>\n", simply.str().c_str(), clean.str().c_str(), erase.str().c_str(), smooth.str().c_str(), dilat.str().c_str(), erosion.str().c_str(), blur.str().c_str(), bdilat.str().c_str(), berosion.str().c_str(), stroker.str().c_str(), strokeg.str().c_str(), strokeb.str().c_str(), ios.str().c_str(), strokea.str().c_str(), offset.str().c_str(), offset.str().c_str(), fillr.str().c_str(), fillg.str().c_str(), fillb.str().c_str(), iof.str().c_str(), filla.str().c_str(), transluscent.str().c_str()); + + return _filter; }; /* Drawing filter */ + /** - \brief Custom predefined Posterize filter. + \brief Custom predefined Neon draw filter. + + Posterize and draw smooth lines around color shapes + + Filter's parameters: + * Lines type (enum, default smooth) -> + smooth = component1 (type="table"), component2 (type="table"), composite1 (in2="blur2") + hard = component1 (type="discrete"), component2 (type="discrete"), composite1 (in2="component1") + * Simplify (0.01->20., default 1.5) -> blur1 (stdDeviation) + * Line width (0.01->20., default 1.5) -> blur2 (stdDeviation) + * Lightness (0.->10., default 0.5) -> composite1 (k3) + * Blend (enum [normal, multiply, screen], default normal) -> blend (mode) + * Dark mode (boolean, default false) -> composite1 (true: in2="component2") +*/ +class NeonDraw : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + NeonDraw ( ) : Filter() { }; + virtual ~NeonDraw ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Neon draw, custom") "</name>\n" + "<id>org.inkscape.effect.filter.NeonDraw</id>\n" + "<param name=\"type\" gui-text=\"" N_("Line type:") "\" type=\"enum\">\n" + "<_item value=\"table\">Smoothed</_item>\n" + "<_item value=\"discrete\">Contrasted</_item>\n" + "</param>\n" + "<param name=\"simply\" gui-text=\"" N_("Simplify:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">1.5</param>\n" + "<param name=\"width\" gui-text=\"" N_("Line width:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">1.5</param>\n" + "<param name=\"lightness\" gui-text=\"" N_("Lightness:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"10.00\">0.5</param>\n" + "<param name=\"blend\" gui-text=\"" N_("Blend mode:") "\" type=\"enum\">\n" + "<_item value=\"normal\">Normal</_item>\n" + "<_item value=\"multiply\">Multiply</_item>\n" + "<_item value=\"screen\">Screen</_item>\n" + "</param>\n" + "<param name=\"dark\" gui-text=\"" N_("Dark mode") "\" type=\"boolean\" >false</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Posterize and draw smooth lines around color shapes") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new NeonDraw()); + }; +}; + +gchar const * +NeonDraw::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream blend; + std::ostringstream simply; + std::ostringstream width; + std::ostringstream lightness; + std::ostringstream type; + std::ostringstream dark; + + type << ext->get_param_enum("type"); + blend << ext->get_param_enum("blend"); + simply << ext->get_param_float("simply"); + width << ext->get_param_float("width"); + lightness << ext->get_param_float("lightness"); + + const gchar *typestr = ext->get_param_enum("type"); + if (ext->get_param_bool("dark")) + dark << "component2"; + else if ((g_ascii_strcasecmp("table", typestr) == 0)) + dark << "blur2"; + else + dark << "component1"; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Neon draw, custom\">\n" + "<feBlend blend=\"normal\" mode=\"%s\" result=\"blend\" />\n" + "<feGaussianBlur in=\"blend\" stdDeviation=\"%s\" result=\"blur1\" />\n" + "<feComponentTransfer result=\"component1\">\n" + "<feFuncR type=\"discrete\" tableValues=\"0 0.3 0.6 1 1\" />\n" + "<feFuncG type=\"discrete\" tableValues=\"0 0.3 0.6 1 1\" />\n" + "<feFuncB type=\"discrete\" tableValues=\"0 0.3 0.6 1 1\" />\n" + "</feComponentTransfer>\n" + "<feGaussianBlur in=\"component1\" stdDeviation=\"%s\" result=\"blur2\" />\n" + "<feComponentTransfer in=\"blur2\" result=\"component2\">\n" + "<feFuncR type=\"%s\" tableValues=\"0 1 0 1 0 1 0 1\" />\n" + "<feFuncG type=\"%s\" tableValues=\"0 1 0 1 0 1 0 1\" />\n" + "<feFuncB type=\"%s\" tableValues=\"0 1 0 1 0 1 0 1\" />\n" + "</feComponentTransfer>\n" + "<feComposite in=\"component2\" in2=\"%s\" k3=\"%s\" operator=\"arithmetic\" k2=\"1\" result=\"composite1\" />\n" + "<feComposite in=\"composite1\" in2=\"SourceGraphic\" operator=\"in\" result=\"composite2\" />\n" + "</filter>\n", blend.str().c_str(), simply.str().c_str(), width.str().c_str(), type.str().c_str(), type.str().c_str(), type.str().c_str(), dark.str().c_str(), lightness.str().c_str()); + + return _filter; +}; /* NeonDraw filter */ + +/** + \brief Custom predefined Poster paint filter. Poster and painting effects. - Filter's parameters (not finished yet): + Filter's parameters: * Effect type (enum, default "Normal") -> Normal = feComponentTransfer Dented = Normal + intermediate values - * Blur (0.01->10., default 5.) -> blur3 (stdDeviation) - + * Transfer type (enum, default "descrete") -> component (type) + * Levels (1->15, default 5) -> component (tableValues) + * Blend mode (enum, default "Lighten") -> blend (mode) + * Primary simplify (0.01->100., default 4.) -> blur1 (stdDeviation) + * Secondary simplify (0.01->100., default 0.5) -> blur2 (stdDeviation) + * Pre-saturation (0.->1., default 1.) -> color1 (values) + * Post-saturation (0.->1., default 1.) -> color2 (values) + * Simulate antialiasing (boolean, default false) -> blur3 (true->stdDeviation=0.5, false->stdDeviation=0.01) */ class Posterize : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Posterize ( ) : Filter() { }; - virtual ~Posterize ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Poster and painting, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Posterize</id>\n" - "<param name=\"type\" gui-text=\"" N_("Effect type:") "\" type=\"enum\">\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"dented\">Dented</_item>\n" - "</param>\n" - "<param name=\"table\" gui-text=\"" N_("Transfer type:") "\" type=\"enum\">\n" - "<_item value=\"discrete\">Poster</_item>\n" - "<_item value=\"table\">Painting</_item>\n" - "</param>\n" - "<param name=\"levels\" gui-text=\"" N_("Levels:") "\" type=\"int\" min=\"1\" max=\"15\">5</param>\n" - "<param name=\"blend\" gui-text=\"" N_("Blend mode:") "\" type=\"enum\">\n" - "<_item value=\"lighten\">Lighten</_item>\n" - "<_item value=\"normal\">Normal</_item>\n" - "<_item value=\"darken\">Darken</_item>\n" - "</param>\n" - "<param name=\"blur1\" gui-text=\"" N_("Primary blur:") "\" type=\"float\" min=\"0.0\" max=\"100.0\">4.0</param>\n" - "<param name=\"blur2\" gui-text=\"" N_("Secondary blur:") "\" type=\"float\" min=\"0.0\" max=\"100.0\">0.5</param>\n" - "<param name=\"presaturation\" gui-text=\"" N_("Pre-saturation:") "\" type=\"float\" min=\"0.00\" max=\"1.00\">1.00</param>\n" - "<param name=\"postsaturation\" gui-text=\"" N_("Post-saturation:") "\" type=\"float\" min=\"0.00\" max=\"1.00\">1.00</param>\n" - "<param name=\"antialiasing\" gui-text=\"" N_("Simulate antialiasing") "\" type=\"boolean\">false</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Poster and painting effects") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Posterize()); - }; + Posterize ( ) : Filter() { }; + virtual ~Posterize ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Poster paint, custom") "</name>\n" + "<id>org.inkscape.effect.filter.Posterize</id>\n" + "<param name=\"type\" gui-text=\"" N_("Effect type:") "\" type=\"enum\">\n" + "<_item value=\"normal\">Normal</_item>\n" + "<_item value=\"dented\">Dented</_item>\n" + "</param>\n" + "<param name=\"table\" gui-text=\"" N_("Transfer type:") "\" type=\"enum\">\n" + "<_item value=\"discrete\">Poster</_item>\n" + "<_item value=\"table\">Painting</_item>\n" + "</param>\n" + "<param name=\"levels\" gui-text=\"" N_("Levels:") "\" type=\"int\" appearance=\"full\" min=\"1\" max=\"15\">5</param>\n" + "<param name=\"blend\" gui-text=\"" N_("Blend mode:") "\" type=\"enum\">\n" + "<_item value=\"lighten\">Lighten</_item>\n" + "<_item value=\"normal\">Normal</_item>\n" + "<_item value=\"darken\">Darken</_item>\n" + "</param>\n" + "<param name=\"blur1\" gui-text=\"" N_("Simplify (primary):") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">4.0</param>\n" + "<param name=\"blur2\" gui-text=\"" N_("Simplify (secondary):") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"100.00\">0.5</param>\n" + "<param name=\"presaturation\" gui-text=\"" N_("Pre-saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">1.00</param>\n" + "<param name=\"postsaturation\" gui-text=\"" N_("Post-saturation:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.00\" max=\"1.00\">1.00</param>\n" + "<param name=\"antialiasing\" gui-text=\"" N_("Simulate antialiasing") "\" type=\"boolean\">false</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Poster and painting effects") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Posterize()); + }; }; gchar const * Posterize::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream table; std::ostringstream blendmode; @@ -434,8 +649,8 @@ Posterize::get_filter_text (Inkscape::Extension::Extension * ext) table << ext->get_param_enum("table"); blendmode << ext->get_param_enum("blend"); - blur1 << ext->get_param_float("blur1") + 0.01; - blur2 << ext->get_param_float("blur2") + 0.01; + blur1 << ext->get_param_float("blur1"); + blur2 << ext->get_param_float("blur2"); presat << ext->get_param_float("presaturation"); postsat << ext->get_param_float("postsaturation"); @@ -458,83 +673,100 @@ Posterize::get_filter_text (Inkscape::Extension::Extension * ext) else antialias << "0.01"; - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Poster and painting, custom -EXP-\">\n" - "<feComposite result=\"Composite1\" operator=\"arithmetic\" k2=\"1\" />\n" - "<feGaussianBlur stdDeviation=\"%s\" result=\"Gaussian1\" />\n" - "<feGaussianBlur stdDeviation=\"%s\" in=\"Composite1\" />\n" - "<feBlend in2=\"Gaussian1\" mode=\"%s\" />\n" - "<feColorMatrix type=\"saturate\" values=\"%s\" />\n" - "<feComponentTransfer>\n" - "<feFuncR type=\"%s\" tableValues=\"%s\" />\n" - "<feFuncG type=\"%s\" tableValues=\"%s\" />\n" - "<feFuncB type=\"%s\" tableValues=\"%s\" />\n" - "</feComponentTransfer>\n" - "<feColorMatrix type=\"saturate\" values=\"%s\" />\n" - "<feGaussianBlur stdDeviation=\"%s\" />\n" - "<feComposite in2=\"SourceGraphic\" operator=\"in\" />\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Poster paint, custom\">\n" + "<feComposite operator=\"arithmetic\" k2=\"1\" result=\"composite1\" />\n" + "<feGaussianBlur stdDeviation=\"%s\" result=\"blur1\" />\n" + "<feGaussianBlur in=\"composite1\" stdDeviation=\"%s\" result=\"blur2\" />\n" + "<feBlend in2=\"blur1\" mode=\"%s\" result=\"blend\"/>\n" + "<feColorMatrix type=\"saturate\" values=\"%s\" result=\"color1\" />\n" + "<feComponentTransfer result=\"component\">\n" + "<feFuncR type=\"%s\" tableValues=\"%s\" />\n" + "<feFuncG type=\"%s\" tableValues=\"%s\" />\n" + "<feFuncB type=\"%s\" tableValues=\"%s\" />\n" + "</feComponentTransfer>\n" + "<feColorMatrix type=\"saturate\" values=\"%s\" result=\"color2\" />\n" + "<feGaussianBlur stdDeviation=\"%s\" result=\"blur3\" />\n" + "<feComposite in2=\"SourceGraphic\" operator=\"in\" result=\"composite3\" />\n" "</filter>\n", blur1.str().c_str(), blur2.str().c_str(), blendmode.str().c_str(), presat.str().c_str(), table.str().c_str(), transf.str().c_str(), table.str().c_str(), transf.str().c_str(), table.str().c_str(), transf.str().c_str(), postsat.str().c_str(), antialias.str().c_str()); - return _filter; + return _filter; }; /* Posterize filter */ +/** + \brief Custom predefined Posterize basic filter. + + Simple posterizing effect -class TestFilter : public Inkscape::Extension::Internal::Filter::Filter { + Filter's parameters: + * Levels (0->20, default 5) -> component1 (tableValues) + * Blur (0.01->20., default 4.) -> blur1 (stdDeviation) +*/ +class PosterizeBasic : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - TestFilter ( ) : Filter() { }; - virtual ~TestFilter ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Test Filter -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.TestFilter</id>\n" - "<_param name=\"header1\" type=\"groupheader\">Test filter</_param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Change colors to a two colors palette") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new TestFilter()); - }; + PosterizeBasic ( ) : Filter() { }; + virtual ~PosterizeBasic ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Posterize basic, custom") "</name>\n" + "<id>org.inkscape.effect.filter.PosterizeBasic</id>\n" + "<param name=\"levels\" gui-text=\"" N_("Levels:") "\" type=\"int\" appearance=\"full\" min=\"0\" max=\"20\">5</param>\n" + "<param name=\"blur\" gui-text=\"" N_("Simplify:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"20.00\">4.0</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Simple posterizing effect") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new PosterizeBasic()); + }; }; gchar const * -TestFilter::get_filter_text (Inkscape::Extension::Extension * ext) +PosterizeBasic::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream blur; + std::ostringstream transf; - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Test Filter -EXP-\">\n" - "<feComposite result=\"Composite1\" operator=\"arithmetic\" k2=\"1\" />\n" - "<feGaussianBlur stdDeviation=\"4\" result=\"Gaussian1\" />\n" - "<feGaussianBlur stdDeviation=\"0.5\" in=\"Composite1\" />\n" - "<feBlend in2=\"Gaussian1\" mode=\"normal\" />\n" - "<feColorMatrix type=\"saturate\" values=\"1\" />\n" - "<feComponentTransfer>\n" - "<feFuncR type=\"discrete\" tableValues=\"0 0.25 0.5 0.75 1 1\" />\n" - "<feFuncG type=\"discrete\" tableValues=\"0 0.25 0.5 0.75 1 1\" />\n" - "<feFuncB type=\"discrete\" tableValues=\"0 0.25 0.5 0.75 1 1\" />\n" - "</feComponentTransfer>\n" - "<feColorMatrix type=\"saturate\" values=\"1\" />\n" - "<feGaussianBlur stdDeviation=\"0.05\" />\n" - "<feComposite in2=\"SourceGraphic\" operator=\"atop\" />\n" - "</filter>\n"); - - return _filter; -}; /* Test filter */ + blur << ext->get_param_float("blur"); + + transf << "0"; + int levels = ext->get_param_int("levels") + 1; + float val = 0.0; + for ( int step = 1 ; step <= levels ; step++ ) { + val = (float) step / levels; + transf << " " << val; + } + transf << " 1"; + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1\" width=\"1\" y=\"0\" x=\"0\" inkscape:label=\"Posterize basic, custom\">\n" + "<feGaussianBlur stdDeviation=\"%s\" result=\"blur1\" />\n" + "<feComponentTransfer stdDeviation=\"2\" in=\"blur1\" result=\"component1\">\n" + "<feFuncR type=\"discrete\" tableValues=\"%s\" />\n" + "<feFuncG type=\"discrete\" tableValues=\"%s\" />\n" + "<feFuncB type=\"discrete\" tableValues=\"%s\" />\n" + "</feComponentTransfer>\n" + "<feComposite in=\"component1\" in2=\"SourceGraphic\" operator=\"in\" />\n" + "</filter>\n", blur.str().c_str(), transf.str().c_str(), transf.str().c_str(), transf.str().c_str()); + + return _filter; +}; /* PosterizeBasic filter */ }; /* namespace Filter */ }; /* namespace Internal */ }; /* namespace Extension */ }; /* namespace Inkscape */ -/* Change the 'COLOR' below to be your file name */ +/* Change the 'EXPERIMENTAL' below to be your file name */ #endif /* __INKSCAPE_EXTENSION_INTERNAL_FILTER_EXPERIMENTAL_H__ */ diff --git a/src/extension/internal/filter/filter-all.cpp b/src/extension/internal/filter/filter-all.cpp index 06b942a1f..280dc9563 100644..100755 --- a/src/extension/internal/filter/filter-all.cpp +++ b/src/extension/internal/filter/filter-all.cpp @@ -8,9 +8,11 @@ #include "filter.h" /* Put your filter here */ +#include "abc.h" #include "color.h" #include "drop-shadow.h" #include "morphology.h" +#include "shadows.h" #include "snow.h" #include "experimental.h" @@ -30,24 +32,44 @@ Filter::filters_all (void ) Snow::init(); /* Experimental custom predefined filters */ - + + // ABCs + Blur::init(); + CleanEdges::init(); + ColorShift::init(); + DiffuseLight::init(); + Feather::init(); + MatteJelly::init(); + NoiseFill::init(); + Outline::init(); + Roughen::init(); + Silhouette::init(); + SpecularLight::init(); + // Color + Brightness::init(); Colorize::init(); Duochrome::init(); + Electrize::init(); + Greyscale::init(); + Lightness::init(); Quadritone::init(); Solarize::init(); Tritone::init(); // Morphology Crosssmooth::init(); - + // Shadows and glows ColorizableDropShadow::init(); // TDB Chromolitho::init(); + CrossEngraving::init(); Drawing::init(); + NeonDraw::init(); Posterize::init(); + PosterizeBasic::init(); // Here come the rest of the filters that are read from SVG files in share/filters and // .config/Inkscape/filters diff --git a/src/extension/internal/filter/filter-file.cpp b/src/extension/internal/filter/filter-file.cpp index 89afca133..d129f590c 100644 --- a/src/extension/internal/filter/filter-file.cpp +++ b/src/extension/internal/filter/filter-file.cpp @@ -26,13 +26,15 @@ namespace Extension { namespace Internal { namespace Filter { -void -Filter::filters_all_files (void) +void Filter::filters_all_files(void) { + gchar *filtersProfilePath = profile_path("filters"); + filters_load_dir(INKSCAPE_FILTERDIR, _("Bundled")); - filters_load_dir(profile_path("filters"), _("Personal")); + filters_load_dir(filtersProfilePath, _("Personal")); - return; + g_free(filtersProfilePath); + filtersProfilePath = 0; } #define INKSCAPE_FILTER_FILE ".svg" diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp index 90dc5dd6f..715278051 100644 --- a/src/extension/internal/filter/filter.cpp +++ b/src/extension/internal/filter/filter.cpp @@ -133,12 +133,12 @@ Filter::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *d items.insert<GSListConstIterator<SPItem *> >(items.end(), selection->itemList(), NULL); Inkscape::XML::Document * xmldoc = document->doc()->getReprDoc(); - Inkscape::XML::Node * defsrepr = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(document->doc())); + Inkscape::XML::Node * defsrepr = SP_DOCUMENT_DEFS(document->doc())->getRepr(); for(std::list<SPItem *>::iterator item = items.begin(); item != items.end(); item++) { SPItem * spitem = *item; - Inkscape::XML::Node * node = SP_OBJECT_REPR(spitem); + Inkscape::XML::Node * node = spitem->getRepr(); SPCSSAttr * css = sp_repr_css_attr(node, "style"); gchar const * filter = sp_repr_css_property(css, "filter", NULL); diff --git a/src/extension/internal/filter/morphology.h b/src/extension/internal/filter/morphology.h index 93d44d6fa..f52920158 100644 --- a/src/extension/internal/filter/morphology.h +++ b/src/extension/internal/filter/morphology.h @@ -3,7 +3,7 @@ /* Change the 'MORPHOLOGY' above to be your file name */ /* - * Copyright (C) 2010 Authors: + * Copyright (C) 2011 Authors: * Ivan Louette (filters) * Nicolas Dufour (UI) <nicoduf@yahoo.fr> * @@ -39,40 +39,40 @@ namespace Filter { class Crosssmooth : public Inkscape::Extension::Internal::Filter::Filter { protected: - virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); public: - Crosssmooth ( ) : Filter() { }; - virtual ~Crosssmooth ( ) { if (_filter != NULL) g_free((void *)_filter); return; } - - static void init (void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("Cross-smooth, custom -EXP-") "</name>\n" - "<id>org.inkscape.effect.filter.Crosssmooth</id>\n" - "<param name=\"type\" gui-text=\"" N_("Type:") "\" type=\"enum\">\n" - "<_item value=\"edges\">Smooth edges</_item>\n" - "<_item value=\"all\">Smooth all</_item>\n" - "</param>\n" - "<param name=\"blur\" gui-text=\"" N_("Blur:") "\" type=\"float\" min=\"0.01\" max=\"10\">5</param>\n" - "<effect>\n" - "<object-type>all</object-type>\n" - "<effects-menu>\n" - "<submenu name=\"" N_("Filters") "\">\n" - "<submenu name=\"" N_("Experimental") "\"/>\n" - "</submenu>\n" - "</effects-menu>\n" - "<menu-tip>" N_("Smooth edges and angles of shapes") "</menu-tip>\n" - "</effect>\n" - "</inkscape-extension>\n", new Crosssmooth()); - }; + Crosssmooth ( ) : Filter() { }; + virtual ~Crosssmooth ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Cross-smooth, custom (Morphology)") "</name>\n" + "<id>org.inkscape.effect.filter.crosssmooth</id>\n" + "<param name=\"type\" gui-text=\"" N_("Type:") "\" type=\"enum\">\n" + "<_item value=\"edges\">Smooth edges</_item>\n" + "<_item value=\"all\">Smooth all</_item>\n" + "</param>\n" + "<param name=\"blur\" gui-text=\"" N_("Blur:") "\" type=\"float\" appearance=\"full\" precision=\"2\" min=\"0.01\" max=\"10.00\">5</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Smooth edges and angles of shapes") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new Crosssmooth()); + }; }; gchar const * Crosssmooth::get_filter_text (Inkscape::Extension::Extension * ext) { - if (_filter != NULL) g_free((void *)_filter); + if (_filter != NULL) g_free((void *)_filter); std::ostringstream blur; std::ostringstream c1in; @@ -86,16 +86,16 @@ Crosssmooth::get_filter_text (Inkscape::Extension::Extension * ext) c1in << "SourceGraphic"; } - _filter = g_strdup_printf( - "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Cross-smooth, custom -EXP-\">\n" - "<feGaussianBlur stdDeviation=\"%s\" result=\"blur\" />\n" - "<feComposite in=\"%s\" in2=\"blur\" operator=\"atop\" result=\"composite1\" />\n" - "<feComposite in2=\"composite1\" operator=\"in\" result=\"composite2\" />\n" - "<feComposite in2=\"composite2\" operator=\"in\" result=\"composite3\" />\n" - "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10 \" result=\"colormatrix\" />\n" + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" inkscape:label=\"Cross-smooth, custom\">\n" + "<feGaussianBlur stdDeviation=\"%s\" result=\"blur\" />\n" + "<feComposite in=\"%s\" in2=\"blur\" operator=\"atop\" result=\"composite1\" />\n" + "<feComposite in2=\"composite1\" operator=\"in\" result=\"composite2\" />\n" + "<feComposite in2=\"composite2\" operator=\"in\" result=\"composite3\" />\n" + "<feColorMatrix values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10 \" result=\"colormatrix\" />\n" "</filter>\n", blur.str().c_str(), c1in.str().c_str()); - return _filter; + return _filter; }; /* Crosssmooth filter */ }; /* namespace Filter */ @@ -103,5 +103,5 @@ Crosssmooth::get_filter_text (Inkscape::Extension::Extension * ext) }; /* namespace Extension */ }; /* namespace Inkscape */ -/* Change the 'COLOR' below to be your file name */ +/* Change the 'MORPHOLOGY' below to be your file name */ #endif /* __INKSCAPE_EXTENSION_INTERNAL_FILTER_MORPHOLOGY_H__ */ diff --git a/src/extension/internal/filter/shadows.h b/src/extension/internal/filter/shadows.h new file mode 100644 index 000000000..e29092ae9 --- /dev/null +++ b/src/extension/internal/filter/shadows.h @@ -0,0 +1,111 @@ +#ifndef __INKSCAPE_EXTENSION_INTERNAL_FILTER_SHADOWS_H__ +#define __INKSCAPE_EXTENSION_INTERNAL_FILTER_SHADOWS_H__ +/* Change the 'SHADOWS' above to be your file name */ + +/* + * Copyright (C) 2011 Authors: + * Ivan Louette (filters) + * Nicolas Dufour (UI) <nicoduf@yahoo.fr> + * + * Color filters + * Drop shadow + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ +/* ^^^ Change the copyright to be you and your e-mail address ^^^ */ + +#include "filter.h" + +#include "extension/internal/clear-n_.h" +#include "extension/system.h" +#include "extension/extension.h" + +namespace Inkscape { +namespace Extension { +namespace Internal { +namespace Filter { + +/** + \brief Custom predefined Drop shadow filter. + + Colorizable Drop shadow. + + Filter's parameters: + * Blur radius (0.->200., default 3) -> blur (stdDeviation) + * Horizontal offset (-50.->50., default 6.0) -> offset (dx) + * Vertical offset (-50.->50., default 6.0) -> offset (dy) + * Color (guint, default 0,0,0,127) -> flood (flood-opacity, flood-color) +*/ +class ColorizableDropShadow : public Inkscape::Extension::Internal::Filter::Filter { +protected: + virtual gchar const * get_filter_text (Inkscape::Extension::Extension * ext); + +public: + ColorizableDropShadow ( ) : Filter() { }; + virtual ~ColorizableDropShadow ( ) { if (_filter != NULL) g_free((void *)_filter); return; } + + static void init (void) { + Inkscape::Extension::build_from_mem( + "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" + "<name>" N_("Drop shadow, custom (Shadows and Glows)") "</name>\n" + "<id>org.inkscape.effect.filter.ColorDropShadow</id>\n" + "<param name=\"blur\" gui-text=\"" N_("Blur radius (px):") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"200.0\">3.0</param>\n" + "<param name=\"xoffset\" gui-text=\"" N_("Horizontal offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">6.0</param>\n" + "<param name=\"yoffset\" gui-text=\"" N_("Vertical offset (px):") "\" type=\"float\" appearance=\"full\" min=\"-50.0\" max=\"50.0\">6.0</param>\n" + "<param name=\"color\" gui-text=\"" N_("Color") "\" type=\"color\">127</param>\n" + "<effect>\n" + "<object-type>all</object-type>\n" + "<effects-menu>\n" + "<submenu name=\"" N_("Filters") "\">\n" + "<submenu name=\"" N_("Experimental") "\"/>\n" + "</submenu>\n" + "</effects-menu>\n" + "<menu-tip>" N_("Colorizable Drop shadow") "</menu-tip>\n" + "</effect>\n" + "</inkscape-extension>\n", new ColorizableDropShadow()); + }; + +}; + +gchar const * +ColorizableDropShadow::get_filter_text (Inkscape::Extension::Extension * ext) +{ + if (_filter != NULL) g_free((void *)_filter); + + std::ostringstream blur; + std::ostringstream a; + std::ostringstream r; + std::ostringstream g; + std::ostringstream b; + std::ostringstream x; + std::ostringstream y; + + guint32 color = ext->get_param_color("color"); + + blur << ext->get_param_float("blur"); + x << ext->get_param_float("xoffset"); + y << ext->get_param_float("yoffset"); + a << (color & 0xff) / 255.0F; + r << ((color >> 24) & 0xff); + g << ((color >> 16) & 0xff); + b << ((color >> 8) & 0xff); + + _filter = g_strdup_printf( + "<filter xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" color-interpolation-filters=\"sRGB\" height=\"1.2\" width=\"1.2\" y=\"-0.1\" x=\"-0.1\" inkscape:label=\"Drop shadow, custom\">\n" + "<feFlood flood-opacity=\"%s\" flood-color=\"rgb(%s,%s,%s)\" result=\"flood\" />\n" + "<feComposite in=\"flood\" in2=\"SourceGraphic\" operator=\"in\" result=\"composite1\" />\n" + "<feGaussianBlur in=\"composite1\" stdDeviation=\"%s\" result=\"blur\" />\n" + "<feOffset dx=\"%s\" dy=\"%s\" result=\"offset\" />\n" + "<feComposite in=\"SourceGraphic\" in2=\"offset\" operator=\"over\" result=\"composite2\" />\n" + "</filter>\n", a.str().c_str(), r.str().c_str(), g.str().c_str(), b.str().c_str(), blur.str().c_str(), x.str().c_str(), y.str().c_str()); + + return _filter; +}; + +}; /* namespace Filter */ +}; /* namespace Internal */ +}; /* namespace Extension */ +}; /* namespace Inkscape */ + +/* Change the 'SHADOWS' below to be your file name */ +#endif /* __INKSCAPE_EXTENSION_INTERNAL_FILTER_SHADOWS_H__ */ diff --git a/src/extension/internal/filter/snow.h b/src/extension/internal/filter/snow.h index aac07fe62..9a88ab9d2 100644 --- a/src/extension/internal/filter/snow.h +++ b/src/extension/internal/filter/snow.h @@ -31,7 +31,7 @@ public: "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" "<name>" N_("Snow crest") "</name>\n" "<id>org.inkscape.effect.filter.snow</id>\n" - "<param name=\"drift\" gui-text=\"" N_("Drift Size:") "\" type=\"float\" min=\"0.0\" max=\"20.0\">3.5</param>\n" + "<param name=\"drift\" gui-text=\"" N_("Drift Size:") "\" type=\"float\" appearance=\"full\" min=\"0.0\" max=\"20.0\">3.5</param>\n" "<effect>\n" "<object-type>all</object-type>\n" "<effects-menu>\n" diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp index a19ab7538..6436624fd 100644 --- a/src/extension/internal/grid.cpp +++ b/src/extension/internal/grid.cpp @@ -183,8 +183,9 @@ Grid::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View using Inkscape::Util::GSListConstIterator; GSListConstIterator<SPItem *> selected = sp_desktop_selection((SPDesktop *)view)->itemList(); Inkscape::XML::Node * first_select = NULL; - if (selected != NULL) - first_select = SP_OBJECT_REPR(*selected); + if (selected != NULL) { + first_select = (*selected)->getRepr(); + } return module->autogui(current_document, first_select, changeSignal); } @@ -206,7 +207,9 @@ Grid::init (void) "<effect>\n" "<object-type>all</object-type>\n" "<effects-menu>\n" - "<submenu name=\"" N_("Render") "\" />\n" + "<submenu name=\"" N_("Render") "\">\n" + "<submenu name=\"" N_("Grids") "\" />\n" + "</submenu>\n" "</effects-menu>\n" "<menu-tip>" N_("Draw a path which is a grid") "</menu-tip>\n" "</effect>\n" diff --git a/src/extension/internal/javafx-out.cpp b/src/extension/internal/javafx-out.cpp index 7098027c7..750849eb1 100644 --- a/src/extension/internal/javafx-out.cpp +++ b/src/extension/internal/javafx-out.cpp @@ -86,12 +86,11 @@ static double effective_opacity(const SPStyle *style) { double val = 1.0; for (SPObject const *obj = style->object; obj ; obj = obj->parent) - { - style = SP_OBJECT_STYLE(obj); - if (style) { - val *= SP_SCALE24_TO_FLOAT(style->opacity.value); - } + { + if (obj->style) { + val *= SP_SCALE24_TO_FLOAT(obj->style->opacity.value); } + } return val; } @@ -488,13 +487,13 @@ bool JavaFXOutput::doCurve(SPItem *item, const String &id) /** * Output the style information */ - if (!doStyle(SP_OBJECT_STYLE(shape))) { + if (!doStyle(shape->style)) { return false; } // convert the path to only lineto's and cubic curveto's: Geom::Scale yflip(1.0, -1.0); - Geom::Matrix tf = item->i2d_affine() * yflip; + Geom::Affine tf = item->i2d_affine() * yflip; Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf ); //Count the NR_CURVETOs/LINETOs (including closing line segment) @@ -630,13 +629,13 @@ bool JavaFXOutput::doCurve(SPItem *item, const String &id) /** * Output the style information */ - if (!doStyle(SP_OBJECT_STYLE(shape))) { + if (!doStyle(shape->style)) { return false; } // convert the path to only lineto's and cubic curveto's: Geom::Scale yflip(1.0, -1.0); - Geom::Matrix tf = item->i2d_affine() * yflip; + Geom::Affine tf = item->i2d_affine() * yflip; Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf ); //Count the NR_CURVETOs/LINETOs (including closing line segment) diff --git a/src/extension/internal/latex-pstricks.cpp b/src/extension/internal/latex-pstricks.cpp index 44b64c5f8..e09e7c024 100644 --- a/src/extension/internal/latex-pstricks.cpp +++ b/src/extension/internal/latex-pstricks.cpp @@ -164,12 +164,12 @@ PrintLatex::finish (Inkscape::Extension::Print *mod) } unsigned int -PrintLatex::bind(Inkscape::Extension::Print *mod, Geom::Matrix const *transform, float opacity) +PrintLatex::bind(Inkscape::Extension::Print *mod, Geom::Affine const *transform, float opacity) { - Geom::Matrix tr = *transform; + Geom::Affine tr = *transform; if(m_tr_stack.size()){ - Geom::Matrix tr_top = m_tr_stack.top(); + Geom::Affine tr_top = m_tr_stack.top(); m_tr_stack.push(tr * tr_top); }else m_tr_stack.push(tr); @@ -194,7 +194,7 @@ unsigned int PrintLatex::comment (Inkscape::Extension::Print * module, unsigned int PrintLatex::fill(Inkscape::Extension::Print *mod, - Geom::PathVector const &pathv, Geom::Matrix const *transform, SPStyle const *style, + Geom::PathVector const &pathv, Geom::Affine const *transform, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox) { if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned. @@ -227,7 +227,7 @@ PrintLatex::fill(Inkscape::Extension::Print *mod, } unsigned int -PrintLatex::stroke (Inkscape::Extension::Print *mod, Geom::PathVector const &pathv, const Geom::Matrix *transform, const SPStyle *style, +PrintLatex::stroke (Inkscape::Extension::Print *mod, Geom::PathVector const &pathv, const Geom::Affine *transform, const SPStyle *style, const NRRect *pbox, const NRRect *dbox, const NRRect *bbox) { if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned. @@ -236,7 +236,7 @@ PrintLatex::stroke (Inkscape::Extension::Print *mod, Geom::PathVector const &pat Inkscape::SVGOStringStream os; float rgb[3]; float stroke_opacity; - Geom::Matrix tr_stack = m_tr_stack.top(); + Geom::Affine tr_stack = m_tr_stack.top(); double const scale = tr_stack.descrim(); os.setf(std::ios::fixed); @@ -277,13 +277,13 @@ PrintLatex::stroke (Inkscape::Extension::Print *mod, Geom::PathVector const &pat // FIXME: why is 'transform' argument not used? void -PrintLatex::print_pathvector(SVGOStringStream &os, Geom::PathVector const &pathv_in, const Geom::Matrix * /*transform*/) +PrintLatex::print_pathvector(SVGOStringStream &os, Geom::PathVector const &pathv_in, const Geom::Affine * /*transform*/) { if (pathv_in.empty()) return; -// Geom::Matrix tf=*transform; // why was this here? - Geom::Matrix tf_stack=m_tr_stack.top(); // and why is transform argument not used? +// Geom::Affine tf=*transform; // why was this here? + Geom::Affine tf_stack=m_tr_stack.top(); // and why is transform argument not used? Geom::PathVector pathv = pathv_in * tf_stack; // generates new path, which is a bit slow, but this doesn't have to be performance optimized os << "\\newpath\n"; diff --git a/src/extension/internal/latex-pstricks.h b/src/extension/internal/latex-pstricks.h index a33e169e8..64b0de474 100644 --- a/src/extension/internal/latex-pstricks.h +++ b/src/extension/internal/latex-pstricks.h @@ -31,9 +31,9 @@ class PrintLatex : public Inkscape::Extension::Implementation::Implementation { float _height; FILE * _stream; - std::stack<Geom::Matrix> m_tr_stack; + std::stack<Geom::Affine> m_tr_stack; - void print_pathvector(SVGOStringStream &os, Geom::PathVector const &pathv_in, const Geom::Matrix * /*transform*/); + void print_pathvector(SVGOStringStream &os, Geom::PathVector const &pathv_in, const Geom::Affine * /*transform*/); void print_2geomcurve(SVGOStringStream &os, Geom::Curve const & c ); public: @@ -47,12 +47,12 @@ public: virtual unsigned int finish (Inkscape::Extension::Print * module); /* Rendering methods */ - virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Matrix const *transform, float opacity); + virtual unsigned int bind(Inkscape::Extension::Print *module, Geom::Affine const *transform, float opacity); virtual unsigned int release(Inkscape::Extension::Print *module); - virtual unsigned int fill (Inkscape::Extension::Print * module, Geom::PathVector const &pathv, const Geom::Matrix *ctm, const SPStyle *style, + virtual unsigned int fill (Inkscape::Extension::Print * module, Geom::PathVector const &pathv, const Geom::Affine *ctm, const SPStyle *style, const NRRect *pbox, const NRRect *dbox, const NRRect *bbox); - virtual unsigned int stroke (Inkscape::Extension::Print * module, Geom::PathVector const &pathv, const Geom::Matrix *transform, const SPStyle *style, + virtual unsigned int stroke (Inkscape::Extension::Print * module, Geom::PathVector const &pathv, const Geom::Affine *transform, const SPStyle *style, const NRRect *pbox, const NRRect *dbox, const NRRect *bbox); virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment); bool textToPath (Inkscape::Extension::Print * ext); diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index fd99afe31..1f9bdfef1 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -246,7 +246,7 @@ LaTeXTextRenderer::sp_use_render(SPItem *item) SPUse *use = SP_USE(item); if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { - Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed)); + Geom::Affine tp(Geom::Translate(use->x.computed, use->y.computed)); push_transform(tp); translated = true; } @@ -264,7 +264,7 @@ void LaTeXTextRenderer::sp_text_render(SPItem *item) { SPText *textobj = SP_TEXT (item); - SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); + SPStyle *style = item->style; gchar *str = sp_te_get_string_multiline(item); if (!str) { @@ -311,8 +311,8 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) } // get rotation - Geom::Matrix i2doc = item->i2doc_affine(); - Geom::Matrix wotransl = i2doc.without_translation(); + Geom::Affine i2doc = item->i2doc_affine(); + Geom::Affine wotransl = i2doc.withoutTranslation(); double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis()); bool has_rotation = !Geom::are_near(degrees,0.); @@ -331,7 +331,44 @@ LaTeXTextRenderer::sp_text_render(SPItem *item) os << "\\rotatebox{" << degrees << "}{"; } os << "\\makebox(0,0)" << alignment << "{"; - os << "\\smash{" << str << "}"; // smash the text, to be able to put the makebox coordinates at the baseline + os << "\\smash{"; // smash the text, to be able to put the makebox coordinates at the baseline + + // Walk through all spans in the text object. + // Write span strings to LaTeX, associated with font weight and style. + Inkscape::Text::Layout const &layout = *(te_get_layout (item)); + for (Inkscape::Text::Layout::iterator li = layout.begin(), le = layout.end(); + li != le; li.nextStartOfSpan()) + { + SPStyle const &spanstyle = *(sp_te_style_at_position (item, li)); + bool is_bold = false, is_italic = false; + + if (spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_500 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_600 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_700 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_800 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_900 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_BOLD || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_BOLDER) + { + is_bold = true; + os << "{\\bfseries{}"; + } + if (spanstyle.font_style.computed == SP_CSS_FONT_STYLE_ITALIC) + { + is_italic = true; + os << "{\\itshape{}"; + } + + Inkscape::Text::Layout::iterator ln = li; + ln.nextStartOfSpan(); + Glib::ustring spanstr = sp_te_get_string_multiline (item, li, ln); + os << spanstr; + + if (is_italic) { os << "}"; } // italic end + if (is_bold) { os << "}"; } // bold end + } + + os << "}"; // smash end if (has_rotation) { os << "}"; // rotatebox end } @@ -350,7 +387,7 @@ Flowing in rectangle is possible, not in arb shape. */ SPFlowtext *flowtext = SP_FLOWTEXT(item); - SPStyle *style = SP_OBJECT_STYLE (SP_OBJECT(item)); + SPStyle *style = item->style; gchar *strtext = sp_te_get_string_multiline(item); if (!strtext) { @@ -412,8 +449,8 @@ Flowing in rectangle is possible, not in arb shape. } // get rotation - Geom::Matrix i2doc = item->i2doc_affine(); - Geom::Matrix wotransl = i2doc.without_translation(); + Geom::Affine i2doc = item->i2doc_affine(); + Geom::Affine wotransl = i2doc.withoutTranslation(); double degrees = -180/M_PI * Geom::atan2(wotransl.xAxis()); bool has_rotation = !Geom::are_near(degrees,0.); @@ -434,7 +471,42 @@ Flowing in rectangle is possible, not in arb shape. os << "\\makebox(0,0)" << alignment << "{"; os << "\\begin{minipage}{" << framebox.width() << "\\unitlength}"; os << justification; - os << str; + + // Walk through all spans in the text object. + // Write span strings to LaTeX, associated with font weight and style. + Inkscape::Text::Layout const &layout = *(te_get_layout (item)); + for (Inkscape::Text::Layout::iterator li = layout.begin(), le = layout.end(); + li != le; li.nextStartOfSpan()) + { + SPStyle const &spanstyle = *(sp_te_style_at_position (item, li)); + bool is_bold = false, is_italic = false; + + if (spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_500 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_600 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_700 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_800 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_900 || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_BOLD || + spanstyle.font_weight.computed == SP_CSS_FONT_WEIGHT_BOLDER) + { + is_bold = true; + os << "{\\bfseries{}"; + } + if (spanstyle.font_style.computed == SP_CSS_FONT_STYLE_ITALIC) + { + is_italic = true; + os << "{\\itshape{}"; + } + + Inkscape::Text::Layout::iterator ln = li; + ln.nextStartOfSpan(); + Glib::ustring spanstr = sp_te_get_string_multiline (item, li, ln); + os << spanstr; + + if (is_italic) { os << "}"; } // italic end + if (is_bold) { os << "}"; } // bold end + } + os << "\\end{minipage}"; if (has_rotation) { os << "}"; // rotatebox end @@ -528,10 +600,16 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * os << " \\ifx\\svgwidth\\undefined\n"; os << " \\setlength{\\unitlength}{" << d->width() * PT_PER_PX << "pt}\n"; + os << " \\ifx\\svgscale\\undefined\n"; + os << " \\relax\n"; + os << " \\else\n"; + os << " \\setlength{\\unitlength}{\\unitlength * \\real{\\svgscale}}\n"; + os << " \\fi\n"; os << " \\else\n"; os << " \\setlength{\\unitlength}{\\svgwidth}\n"; os << " \\fi\n"; os << " \\global\\let\\svgwidth\\undefined\n"; + os << " \\global\\let\\svgscale\\undefined\n"; os << " \\makeatother\n"; os << " \\begin{picture}(" << _width << "," << _height << ")%\n"; @@ -543,17 +621,17 @@ LaTeXTextRenderer::setupDocument(SPDocument *doc, bool pageBoundingBox, SPItem * return true; } -Geom::Matrix const & +Geom::Affine const & LaTeXTextRenderer::transform() { return _transform_stack.top(); } void -LaTeXTextRenderer::push_transform(Geom::Matrix const &tr) +LaTeXTextRenderer::push_transform(Geom::Affine const &tr) { if(_transform_stack.size()){ - Geom::Matrix tr_top = _transform_stack.top(); + Geom::Affine tr_top = _transform_stack.top(); _transform_stack.push(tr * tr_top); } else { _transform_stack.push(tr); diff --git a/src/extension/internal/latex-text-renderer.h b/src/extension/internal/latex-text-renderer.h index e4bbd94ed..2259427d6 100644 --- a/src/extension/internal/latex-text-renderer.h +++ b/src/extension/internal/latex-text-renderer.h @@ -18,7 +18,7 @@ #endif #include "extension/extension.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <stack> class SPItem; @@ -51,10 +51,10 @@ protected: bool _pdflatex; /** true if ouputting for pdfLaTeX*/ - void push_transform(Geom::Matrix const &transform); - Geom::Matrix const & transform(); + void push_transform(Geom::Affine const &transform); + Geom::Affine const & transform(); void pop_transform(); - std::stack<Geom::Matrix> _transform_stack; + std::stack<Geom::Affine> _transform_stack; void writePreamble(); void writePostamble(); diff --git a/src/extension/internal/odf.cpp b/src/extension/internal/odf.cpp index b5c842a40..6a350ab48 100644 --- a/src/extension/internal/odf.cpp +++ b/src/extension/internal/odf.cpp @@ -259,7 +259,7 @@ private: * NOTE: * This class is ported almost verbatim from the public domain * JAMA Matrix package. It is modified to handle only 3x3 matrices - * and our Geom::Matrix affine transform class. We give full + * and our Geom::Affine affine transform class. We give full * attribution to them, along with many thanks. JAMA can be found at: * http://math.nist.gov/javanumerics/jama * @@ -921,7 +921,7 @@ static Glib::ustring getExtension(const Glib::ustring &fname) } -static Glib::ustring formatTransform(Geom::Matrix &tf) +static Glib::ustring formatTransform(Geom::Affine &tf) { Glib::ustring str; if (!tf.isIdentity()) @@ -943,16 +943,16 @@ static Glib::ustring formatTransform(Geom::Matrix &tf) * Get the general transform from SVG pixels to * ODF cm */ -static Geom::Matrix getODFTransform(const SPItem *item) +static Geom::Affine getODFTransform(const SPItem *item) { //### Get SVG-to-ODF transform - Geom::Matrix tf (item->i2d_affine()); + Geom::Affine tf (item->i2d_affine()); //Flip Y into document coordinates double doc_height = SP_ACTIVE_DOCUMENT->getHeight(); - Geom::Matrix doc2dt_tf = Geom::Matrix(Geom::Scale(1.0, -1.0)); - doc2dt_tf = doc2dt_tf * Geom::Matrix(Geom::Translate(0, doc_height)); + Geom::Affine doc2dt_tf = Geom::Affine(Geom::Scale(1.0, -1.0)); + doc2dt_tf = doc2dt_tf * Geom::Affine(Geom::Translate(0, doc_height)); tf = tf * doc2dt_tf; - tf = tf * Geom::Matrix(Geom::Scale(pxToCm)); + tf = tf * Geom::Affine(Geom::Scale(pxToCm)); return tf; } @@ -970,10 +970,10 @@ static Geom::OptRect getODFBoundingBox(const SPItem *item) if (bbox_temp) { bbox = *bbox_temp; double doc_height = SP_ACTIVE_DOCUMENT->getHeight(); - Geom::Matrix doc2dt_tf = Geom::Matrix(Geom::Scale(1.0, -1.0)); - doc2dt_tf = doc2dt_tf * Geom::Matrix(Geom::Translate(0, doc_height)); + Geom::Affine doc2dt_tf = Geom::Affine(Geom::Scale(1.0, -1.0)); + doc2dt_tf = doc2dt_tf * Geom::Affine(Geom::Translate(0, doc_height)); bbox = *bbox * doc2dt_tf; - bbox = *bbox * Geom::Matrix(Geom::Scale(pxToCm)); + bbox = *bbox * Geom::Affine(Geom::Scale(pxToCm)); } return bbox; } @@ -984,10 +984,10 @@ static Geom::OptRect getODFBoundingBox(const SPItem *item) * Get the transform for an item, correcting for * handedness reversal */ -static Geom::Matrix getODFItemTransform(const SPItem *item) +static Geom::Affine getODFItemTransform(const SPItem *item) { - Geom::Matrix itemTransform (Geom::Scale(1, -1)); - itemTransform = itemTransform * (Geom::Matrix)item->transform; + Geom::Affine itemTransform (Geom::Scale(1, -1)); + itemTransform = itemTransform * (Geom::Affine)item->transform; itemTransform = itemTransform * Geom::Scale(1, -1); return itemTransform; } @@ -997,7 +997,7 @@ static Geom::Matrix getODFItemTransform(const SPItem *item) /** * Get some fun facts from the transform */ -static void analyzeTransform(Geom::Matrix &tf, +static void analyzeTransform(Geom::Affine &tf, double &rotate, double &/*xskew*/, double &/*yskew*/, double &xscale, double &yscale) { @@ -1087,7 +1087,7 @@ OdfOutput::preprocess(ZipFile &zf, Inkscape::XML::Node *node) } SPItem *item = SP_ITEM(reprobj); //### Get SVG-to-ODF transform - Geom::Matrix tf = getODFTransform(item); + Geom::Affine tf = getODFTransform(item); if (nodeName == "image" || nodeName == "svg:image") { @@ -1487,7 +1487,7 @@ bool OdfOutput::writeStyle(ZipFile &zf) */ static int writePath(Writer &outs, Geom::PathVector const &pathv, - Geom::Matrix const &tf, double xoff, double yoff) + Geom::Affine const &tf, double xoff, double yoff) { using Geom::X; using Geom::Y; @@ -1638,7 +1638,7 @@ bool OdfOutput::processStyle(Writer &outs, SPItem *item, bool OdfOutput::processGradient(Writer &outs, SPItem *item, - const Glib::ustring &id, Geom::Matrix &/*tf*/) + const Glib::ustring &id, Geom::Affine &/*tf*/) { if (!item) return false; @@ -1864,7 +1864,7 @@ bool OdfOutput::writeTree(Writer &couts, Writer &souts, Glib::ustring id = getAttribute(node, "id"); //### Get SVG-to-ODF transform - Geom::Matrix tf = getODFTransform(item); + Geom::Affine tf = getODFTransform(item); //### Get ODF bounding box params for item Geom::OptRect bbox = getODFBoundingBox(item); @@ -1960,7 +1960,7 @@ bool OdfOutput::writeTree(Writer &couts, Writer &souts, iwidth = xscale * iwidth; iheight = yscale * iheight; - Geom::Matrix itemTransform = getODFItemTransform(item); + Geom::Affine itemTransform = getODFItemTransform(item); Glib::ustring itemTransformString = formatTransform(itemTransform); diff --git a/src/extension/internal/odf.h b/src/extension/internal/odf.h index 9ad261098..2a6f7799f 100644 --- a/src/extension/internal/odf.h +++ b/src/extension/internal/odf.h @@ -317,7 +317,7 @@ private: bool processStyle(Writer &outs, SPItem *item, const Glib::ustring &id); bool processGradient(Writer &outs, SPItem *item, - const Glib::ustring &id, Geom::Matrix &tf); + const Glib::ustring &id, Geom::Affine &tf); bool writeStyleHeader(Writer &outs); diff --git a/src/extension/internal/pdf-input-cairo.cpp b/src/extension/internal/pdf-input-cairo.cpp index 2c7ea3b33..048b26bed 100644 --- a/src/extension/internal/pdf-input-cairo.cpp +++ b/src/extension/internal/pdf-input-cairo.cpp @@ -16,12 +16,16 @@ #endif #ifdef HAVE_POPPLER_GLIB +#ifdef HAVE_POPPLER_CAIRO #include "pdf-input-cairo.h" #include "extension/system.h" #include "extension/input.h" +#include "dialogs/dialog-events.h" #include "document.h" +#include "inkscape.h" + #include <cairo-svg.h> #include <poppler/glib/poppler.h> #include <poppler/glib/poppler-document.h> @@ -31,21 +35,581 @@ namespace Inkscape { namespace Extension { namespace Internal { + +/** + * \brief The PDF import dialog + * FIXME: Probably this should be placed into src/ui/dialog + */ + +static const gchar * crop_setting_choices[] = { + //TRANSLATORS: The following are document crop settings for PDF import + // more info: http://www.acrobatusers.com/tech_corners/javascript_corner/tips/2006/page_bounds/ + N_("media box"), + N_("crop box"), + N_("trim box"), + N_("bleed box"), + N_("art box") +}; + +PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc) +{ + if(doc == NULL) { + // if there is no document, throw exception here + throw; + } + + _poppler_doc = doc; + + cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); + okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); + _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); + + // Page number + int num_pages = poppler_document_get_n_pages(_poppler_doc); + Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage(new class Gtk::Adjustment(1, 1, num_pages, 1, 10, 0)); + _pageNumberSpin = Gtk::manage(new class Gtk::SpinButton(*_pageNumberSpin_adj, 1, 1)); + _labelTotalPages = Gtk::manage(new class Gtk::Label()); + hbox2 = Gtk::manage(new class Gtk::HBox(false, 0)); + // Disable the page selector when there's only one page + if ( num_pages == 1 ) { + _pageNumberSpin->set_sensitive(false); + } else { + // Display total number of pages + gchar *label_text = g_strdup_printf(_("out of %i"), num_pages); + _labelTotalPages->set_label(label_text); + g_free(label_text); + } + + // Crop settings + _cropCheck = Gtk::manage(new class Gtk::CheckButton(_("Clip to:"))); + _cropTypeCombo = Gtk::manage(new class Gtk::ComboBoxText()); + int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]); + for ( int i = 0 ; i < num_crop_choices ; i++ ) { + _cropTypeCombo->append_text(_(crop_setting_choices[i])); + } + _cropTypeCombo->set_active_text(_(crop_setting_choices[0])); + _cropTypeCombo->set_sensitive(false); + + hbox3 = Gtk::manage(new class Gtk::HBox(false, 4)); + vbox2 = Gtk::manage(new class Gtk::VBox(false, 4)); + alignment3 = Gtk::manage(new class Gtk::Alignment(0.5, 0.5, 1, 1)); + _labelPageSettings = Gtk::manage(new class Gtk::Label(_("Page settings"))); + _pageSettingsFrame = Gtk::manage(new class Gtk::Frame()); + _labelPrecision = Gtk::manage(new class Gtk::Label(_("Precision of approximating gradient meshes:"))); + _labelPrecisionWarning = Gtk::manage(new class Gtk::Label(_("<b>Note</b>: setting the precision too high may result in a large SVG file and slow performance."))); + + _fallbackPrecisionSlider_adj = Gtk::manage(new class Gtk::Adjustment(2, 1, 256, 1, 10, 10)); + _fallbackPrecisionSlider = Gtk::manage(new class Gtk::HScale(*_fallbackPrecisionSlider_adj)); + _fallbackPrecisionSlider->set_value(2.0); + _labelPrecisionComment = Gtk::manage(new class Gtk::Label(_("rough"))); + hbox6 = Gtk::manage(new class Gtk::HBox(false, 4)); + + // Text options + _labelText = Gtk::manage(new class Gtk::Label(_("Text handling:"))); + _textHandlingCombo = Gtk::manage(new class Gtk::ComboBoxText()); + _textHandlingCombo->append_text(_("Import text as text")); + _textHandlingCombo->set_active_text(_("Import text as text")); + _localFontsCheck = Gtk::manage(new class Gtk::CheckButton(_("Replace PDF fonts by closest-named installed fonts"))); + + hbox5 = Gtk::manage(new class Gtk::HBox(false, 4)); + _embedImagesCheck = Gtk::manage(new class Gtk::CheckButton(_("Embed images"))); + vbox3 = Gtk::manage(new class Gtk::VBox(false, 4)); + alignment4 = Gtk::manage(new class Gtk::Alignment(0.5, 0.5, 1, 1)); + _labelImportSettings = Gtk::manage(new class Gtk::Label(_("Import settings"))); + _importSettingsFrame = Gtk::manage(new class Gtk::Frame()); + vbox1 = Gtk::manage(new class Gtk::VBox(false, 4)); + _previewArea = Gtk::manage(new class Gtk::DrawingArea()); + hbox1 = Gtk::manage(new class Gtk::HBox(false, 4)); + cancelbutton->set_flags(Gtk::CAN_FOCUS); + cancelbutton->set_flags(Gtk::CAN_DEFAULT); + cancelbutton->set_relief(Gtk::RELIEF_NORMAL); + okbutton->set_flags(Gtk::CAN_FOCUS); + okbutton->set_flags(Gtk::CAN_DEFAULT); + okbutton->set_relief(Gtk::RELIEF_NORMAL); + this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END); + _labelSelect->set_alignment(0.5,0.5); + _labelSelect->set_padding(4,0); + _labelSelect->set_justify(Gtk::JUSTIFY_LEFT); + _labelSelect->set_line_wrap(false); + _labelSelect->set_use_markup(false); + _labelSelect->set_selectable(false); + _pageNumberSpin->set_flags(Gtk::CAN_FOCUS); + _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS); + _pageNumberSpin->set_numeric(true); + _pageNumberSpin->set_digits(0); + _pageNumberSpin->set_wrap(false); + _labelTotalPages->set_alignment(0.5,0.5); + _labelTotalPages->set_padding(4,0); + _labelTotalPages->set_justify(Gtk::JUSTIFY_LEFT); + _labelTotalPages->set_line_wrap(false); + _labelTotalPages->set_use_markup(false); + _labelTotalPages->set_selectable(false); + hbox2->pack_start(*_labelSelect, Gtk::PACK_SHRINK, 4); + hbox2->pack_start(*_pageNumberSpin, Gtk::PACK_SHRINK, 4); + hbox2->pack_start(*_labelTotalPages, Gtk::PACK_SHRINK, 4); + _cropCheck->set_flags(Gtk::CAN_FOCUS); + _cropCheck->set_relief(Gtk::RELIEF_NORMAL); + _cropCheck->set_mode(true); + _cropCheck->set_active(false); + _cropTypeCombo->set_border_width(1); + hbox3->pack_start(*_cropCheck, Gtk::PACK_SHRINK, 4); + hbox3->pack_start(*_cropTypeCombo, Gtk::PACK_SHRINK, 0); + vbox2->pack_start(*hbox2); + vbox2->pack_start(*hbox3); + alignment3->add(*vbox2); + _labelPageSettings->set_alignment(0.5,0.5); + _labelPageSettings->set_padding(4,0); + _labelPageSettings->set_justify(Gtk::JUSTIFY_LEFT); + _labelPageSettings->set_line_wrap(false); + _labelPageSettings->set_use_markup(true); + _labelPageSettings->set_selectable(false); + _pageSettingsFrame->set_border_width(4); + _pageSettingsFrame->set_shadow_type(Gtk::SHADOW_ETCHED_IN); + _pageSettingsFrame->set_label_align(0,0.5); + _pageSettingsFrame->add(*alignment3); + _pageSettingsFrame->set_label_widget(*_labelPageSettings); + _labelPrecision->set_alignment(0,0.5); + _labelPrecision->set_padding(4,0); + _labelPrecision->set_justify(Gtk::JUSTIFY_LEFT); + _labelPrecision->set_line_wrap(true); + _labelPrecision->set_use_markup(false); + _labelPrecision->set_selectable(false); + _labelPrecisionWarning->set_alignment(0,0.5); + _labelPrecisionWarning->set_padding(4,0); + _labelPrecisionWarning->set_justify(Gtk::JUSTIFY_LEFT); + _labelPrecisionWarning->set_line_wrap(true); + _labelPrecisionWarning->set_use_markup(true); + _labelPrecisionWarning->set_selectable(false); + _fallbackPrecisionSlider->set_size_request(180,-1); + _fallbackPrecisionSlider->set_flags(Gtk::CAN_FOCUS); + _fallbackPrecisionSlider->set_update_policy(Gtk::UPDATE_CONTINUOUS); + _fallbackPrecisionSlider->set_inverted(false); + _fallbackPrecisionSlider->set_digits(1); + _fallbackPrecisionSlider->set_draw_value(true); + _fallbackPrecisionSlider->set_value_pos(Gtk::POS_TOP); + _labelPrecisionComment->set_size_request(90,-1); + _labelPrecisionComment->set_alignment(0.5,0.5); + _labelPrecisionComment->set_padding(4,0); + _labelPrecisionComment->set_justify(Gtk::JUSTIFY_LEFT); + _labelPrecisionComment->set_line_wrap(false); + _labelPrecisionComment->set_use_markup(false); + _labelPrecisionComment->set_selectable(false); + hbox6->pack_start(*_fallbackPrecisionSlider, Gtk::PACK_SHRINK, 4); + hbox6->pack_start(*_labelPrecisionComment, Gtk::PACK_SHRINK, 0); + _labelText->set_alignment(0.5,0.5); + _labelText->set_padding(4,0); + _labelText->set_justify(Gtk::JUSTIFY_LEFT); + _labelText->set_line_wrap(false); + _labelText->set_use_markup(false); + _labelText->set_selectable(false); + hbox5->pack_start(*_labelText, Gtk::PACK_SHRINK, 0); + hbox5->pack_start(*_textHandlingCombo, Gtk::PACK_SHRINK, 0); + _localFontsCheck->set_flags(Gtk::CAN_FOCUS); + _localFontsCheck->set_relief(Gtk::RELIEF_NORMAL); + _localFontsCheck->set_mode(true); + _localFontsCheck->set_active(true); + _embedImagesCheck->set_flags(Gtk::CAN_FOCUS); + _embedImagesCheck->set_relief(Gtk::RELIEF_NORMAL); + _embedImagesCheck->set_mode(true); + _embedImagesCheck->set_active(true); + vbox3->pack_start(*_labelPrecision, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*hbox6, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*_labelPrecisionWarning, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*hbox5, Gtk::PACK_SHRINK, 4); + vbox3->pack_start(*_localFontsCheck, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*_embedImagesCheck, Gtk::PACK_SHRINK, 0); + alignment4->add(*vbox3); + _labelImportSettings->set_alignment(0.5,0.5); + _labelImportSettings->set_padding(4,0); + _labelImportSettings->set_justify(Gtk::JUSTIFY_LEFT); + _labelImportSettings->set_line_wrap(false); + _labelImportSettings->set_use_markup(true); + _labelImportSettings->set_selectable(false); + _importSettingsFrame->set_border_width(4); + _importSettingsFrame->set_shadow_type(Gtk::SHADOW_ETCHED_IN); + _importSettingsFrame->set_label_align(0,0.5); + _importSettingsFrame->add(*alignment4); + _importSettingsFrame->set_label_widget(*_labelImportSettings); + vbox1->pack_start(*_pageSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0); + vbox1->pack_start(*_importSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0); + hbox1->pack_start(*vbox1); + hbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 4); + this->get_vbox()->set_homogeneous(false); + this->get_vbox()->set_spacing(0); + this->get_vbox()->pack_start(*hbox1); + this->set_title(_("PDF Import Settings")); + this->set_modal(true); + sp_transientize((GtkWidget *)this->gobj()); //Make transient + this->property_window_position().set_value(Gtk::WIN_POS_NONE); + this->set_resizable(true); + this->property_destroy_with_parent().set_value(false); + this->set_has_separator(true); + this->add_action_widget(*cancelbutton, -6); + this->add_action_widget(*okbutton, -5); + cancelbutton->show(); + okbutton->show(); + _labelSelect->show(); + _pageNumberSpin->show(); + _labelTotalPages->show(); + hbox2->show(); + _cropCheck->show(); + _cropTypeCombo->show(); + hbox3->show(); + vbox2->show(); + alignment3->show(); + _labelPageSettings->show(); + _pageSettingsFrame->show(); + _labelPrecision->show(); + _labelPrecisionWarning->show(); + _fallbackPrecisionSlider->show(); + _labelPrecisionComment->show(); + hbox6->show(); + _labelText->show(); + _textHandlingCombo->show(); + hbox5->show(); + _localFontsCheck->show(); + _embedImagesCheck->show(); + vbox3->show(); + alignment4->show(); + _labelImportSettings->show(); + _importSettingsFrame->show(); + vbox1->show(); + _previewArea->show(); + hbox1->show(); + + // Connect signals + _previewArea->signal_expose_event().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onExposePreview)); + _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPageNumberChanged)); + _cropCheck->signal_toggled().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onToggleCropping)); + _fallbackPrecisionSlider_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPrecisionChanged)); + + _render_thumb = false; + _cairo_surface = NULL; + _render_thumb = true; + + // Set default preview size + _preview_width = 200; + _preview_height = 300; + + // Init preview + _thumb_data = NULL; + _pageNumberSpin_adj->set_value(1.0); + _current_page = 1; + _setPreviewPage(_current_page); + + set_default (*okbutton); + set_focus (*okbutton); +} + +PdfImportCairoDialog::~PdfImportCairoDialog() { + if (_cairo_surface) { + cairo_surface_destroy(_cairo_surface); + } + if (_thumb_data) { + if (_render_thumb) { + delete _thumb_data; + } else { + // -->gfree(_thumb_data); + delete _thumb_data; + } + } +} + +bool PdfImportCairoDialog::showDialog() { + show(); + gint b = run(); + hide(); + if ( b == Gtk::RESPONSE_OK ) { + return TRUE; + } else { + return FALSE; + } +} + +int PdfImportCairoDialog::getSelectedPage() { + return _current_page; +} + +/** + * \brief Retrieves the current settings into a repr which SvgBuilder will use + * for determining the behaviour desired by the user + */ +void PdfImportCairoDialog::getImportSettings(Inkscape::XML::Node *prefs) { + sp_repr_set_svg_double(prefs, "selectedPage", (double)_current_page); + if (_cropCheck->get_active()) { + Glib::ustring current_choice = _cropTypeCombo->get_active_text(); + int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]); + int i = 0; + for ( ; i < num_crop_choices ; i++ ) { + if ( current_choice == _(crop_setting_choices[i]) ) { + break; + } + } + sp_repr_set_svg_double(prefs, "cropTo", (double)i); + } else { + sp_repr_set_svg_double(prefs, "cropTo", -1.0); + } + sp_repr_set_svg_double(prefs, "approximationPrecision", + _fallbackPrecisionSlider->get_value()); + if (_localFontsCheck->get_active()) { + prefs->setAttribute("localFonts", "1"); + } else { + prefs->setAttribute("localFonts", "0"); + } + if (_embedImagesCheck->get_active()) { + prefs->setAttribute("embedImages", "1"); + } else { + prefs->setAttribute("embedImages", "0"); + } +} + +/** + * \brief Redisplay the comment on the current approximation precision setting + * Evenly divides the interval of possible values between the available labels. + */ +void PdfImportCairoDialog::_onPrecisionChanged() { + + static Glib::ustring precision_comments[] = { + Glib::ustring(C_("PDF input precision", "rough")), + Glib::ustring(C_("PDF input precision", "medium")), + Glib::ustring(C_("PDF input precision", "fine")), + Glib::ustring(C_("PDF input precision", "very fine")) + }; + + double min = _fallbackPrecisionSlider_adj->get_lower(); + double max = _fallbackPrecisionSlider_adj->get_upper(); + int num_intervals = sizeof(precision_comments) / sizeof(precision_comments[0]); + double interval_len = ( max - min ) / (double)num_intervals; + double value = _fallbackPrecisionSlider_adj->get_value(); + int comment_idx = (int)floor( ( value - min ) / interval_len ); + _labelPrecisionComment->set_label(precision_comments[comment_idx]); +} + +void PdfImportCairoDialog::_onToggleCropping() { + _cropTypeCombo->set_sensitive(_cropCheck->get_active()); +} + +void PdfImportCairoDialog::_onPageNumberChanged() { + int page = _pageNumberSpin->get_value_as_int(); + _current_page = CLAMP(page, 1, poppler_document_get_n_pages(_poppler_doc)); + _setPreviewPage(_current_page); +} + +/** + * \brief Copies image data from a Cairo surface to a pixbuf + * + * Borrowed from libpoppler, from the file poppler-page.cc + * Copyright (C) 2005, Red Hat, Inc. + * + */ +static void copy_cairo_surface_to_pixbuf (cairo_surface_t *surface, + unsigned char *data, + GdkPixbuf *pixbuf) +{ + int cairo_width, cairo_height, cairo_rowstride; + unsigned char *pixbuf_data, *dst, *cairo_data; + int pixbuf_rowstride, pixbuf_n_channels; + unsigned int *src; + int x, y; + + cairo_width = cairo_image_surface_get_width (surface); + cairo_height = cairo_image_surface_get_height (surface); + cairo_rowstride = cairo_width * 4; + cairo_data = data; + + pixbuf_data = gdk_pixbuf_get_pixels (pixbuf); + pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf); + pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf); + + if (cairo_width > gdk_pixbuf_get_width (pixbuf)) + cairo_width = gdk_pixbuf_get_width (pixbuf); + if (cairo_height > gdk_pixbuf_get_height (pixbuf)) + cairo_height = gdk_pixbuf_get_height (pixbuf); + for (y = 0; y < cairo_height; y++) + { + src = (unsigned int *) (cairo_data + y * cairo_rowstride); + dst = pixbuf_data + y * pixbuf_rowstride; + for (x = 0; x < cairo_width; x++) + { + dst[0] = (*src >> 16) & 0xff; + dst[1] = (*src >> 8) & 0xff; + dst[2] = (*src >> 0) & 0xff; + if (pixbuf_n_channels == 4) + dst[3] = (*src >> 24) & 0xff; + dst += pixbuf_n_channels; + src++; + } + } +} + +/** + * \brief Updates the preview area with the previously rendered thumbnail + */ +bool PdfImportCairoDialog::_onExposePreview(GdkEventExpose */*event*/) { + + // Check if we have a thumbnail at all + if (!_thumb_data) { + return true; + } + + // Create the pixbuf for the thumbnail + Glib::RefPtr<Gdk::Pixbuf> thumb; + if (_render_thumb) { + thumb = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, + 8, _thumb_width, _thumb_height); + } else { + thumb = Gdk::Pixbuf::create_from_data(_thumb_data, Gdk::COLORSPACE_RGB, + false, 8, _thumb_width, _thumb_height, _thumb_rowstride); + } + if (!thumb) { + return true; + } + + // Set background to white + if (_render_thumb) { + thumb->fill(0xffffffff); + Glib::RefPtr<Gdk::Pixmap> back_pixmap = Gdk::Pixmap::create( + _previewArea->get_window(), _thumb_width, _thumb_height, -1); + if (!back_pixmap) { + return true; + } + back_pixmap->draw_pixbuf(Glib::RefPtr<Gdk::GC>(), thumb, 0, 0, 0, 0, + _thumb_width, _thumb_height, + Gdk::RGB_DITHER_NONE, 0, 0); + _previewArea->get_window()->set_back_pixmap(back_pixmap, false); + _previewArea->get_window()->clear(); + } + + // Copy the thumbnail image from the Cairo surface + if (_render_thumb) { + copy_cairo_surface_to_pixbuf(_cairo_surface, _thumb_data, thumb->gobj()); + } + _previewArea->get_window()->draw_pixbuf(Glib::RefPtr<Gdk::GC>(), thumb, + 0, 0, 0, _render_thumb ? 0 : 20, + -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); + + return true; +} + +/** + * \brief Renders the given page's thumbnail using Cairo + */ +void PdfImportCairoDialog::_setPreviewPage(int page) { + + PopplerPage *_previewed_page = poppler_document_get_page(_poppler_doc, page); + + // Try to get a thumbnail from the PDF if possible + if (!_render_thumb) { + if (_thumb_data) { + // --> gfree(_thumb_data); + free(_thumb_data); + _thumb_data = NULL; + } + +/* +--> if (!_previewed_page->loadThumb(&_thumb_data, + &_thumb_width, &_thumb_height, &_thumb_rowstride)) { + return; + } +*/ + // Redraw preview area + _previewArea->set_size_request(_thumb_width, _thumb_height + 20); + _previewArea->queue_draw(); + return; + } + + // Get page size by accounting for rotation + double width, height; + // --> int rotate = _previewed_page->getRotate(); + int rotate = 0; + if ( rotate == 90 || rotate == 270 ) { +// --> height = _previewed_page->getCropWidth(); +// --> width = _previewed_page->getCropHeight(); + } else { + poppler_page_get_size (_previewed_page, &width, &height); +// --> width = _previewed_page->getCropWidth(); +// --> height = _previewed_page->getCropHeight(); + } + // Calculate the needed scaling for the page + double scale_x = (double)_preview_width / width; + double scale_y = (double)_preview_height / height; + double scale_factor = ( scale_x > scale_y ) ? scale_y : scale_x; + // Create new Cairo surface + _thumb_width = (int)ceil( width * scale_factor ); + _thumb_height = (int)ceil( height * scale_factor ); + _thumb_rowstride = _thumb_width * 4; + if (_thumb_data) { + delete _thumb_data; + } + _thumb_data = new unsigned char[ _thumb_rowstride * _thumb_height ]; + if (_cairo_surface) { + cairo_surface_destroy(_cairo_surface); + } + _cairo_surface = cairo_image_surface_create_for_data(_thumb_data, + CAIRO_FORMAT_ARGB32, _thumb_width, _thumb_height, _thumb_rowstride); + cairo_t *cr = cairo_create(_cairo_surface); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); // Set fill color to white + cairo_paint(cr); // Clear it + cairo_scale(cr, scale_factor, scale_factor); // Use Cairo for resizing the image + // Render page + if (_poppler_doc != NULL) { + PopplerPage *poppler_page = poppler_document_get_page(_poppler_doc, page - 1); + poppler_page_render(poppler_page, cr); + g_object_unref(G_OBJECT(poppler_page)); + } + // Clean up + cairo_destroy(cr); + // Redraw preview area + _previewArea->set_size_request(_preview_width, _preview_height); + _previewArea->queue_draw(); + +} + + static cairo_status_t _write_ustring_cb(void *closure, const unsigned char *data, unsigned int length); SPDocument * PdfInputCairo::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri) { - printf("Attempting to open using PdfInputCairo\n"); + g_message("Attempting to open using PdfInputCairo\n"); gchar* filename_uri = g_filename_to_uri(uri, NULL, NULL); - PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, NULL); - if (document == NULL) + GError *error = NULL; + /// @todo handle passwort + /// @todo check if win32 unicode needs special attention + PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, &error); + + if(error != NULL) { + g_message("Unable to read file: %s\n", error->message); + g_error_free (error); + } + + if (document == NULL) { return NULL; + } + + // create and show the import dialog + PdfImportCairoDialog *dlg = NULL; + if (inkscape_use_gui()) { + dlg = new PdfImportCairoDialog(document); + if (!dlg->showDialog()) { + delete dlg; + return NULL; + } + } + + // Get needed page + int page_num; + if (dlg) { + page_num = dlg->getSelectedPage(); + delete dlg; + } + else + page_num = 1; double width, height; - PopplerPage* page = poppler_document_get_page(document, 0); + PopplerPage* page = poppler_document_get_page(document, page_num - 1); poppler_page_get_size(page, &width, &height); Glib::ustring* output = new Glib::ustring(""); @@ -87,11 +651,11 @@ PdfInputCairo::init(void) { ext = Inkscape::Extension::build_from_mem( "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" "<name>PDF Input</name>\n" - "<id>org.inkscape.input.pdf</id>\n" + "<id>org.inkscape.input.cairo-pdf</id>\n" "<input>\n" "<extension>.pdf</extension>\n" "<mimetype>application/pdf</mimetype>\n" - "<filetypename>Adobe PDF (*.pdf)</filetypename>\n" + "<filetypename>Adobe PDF via poppler-cairo (*.pdf)</filetypename>\n" "<filetypetooltip>PDF Document</filetypetooltip>\n" "</input>\n" "</inkscape-extension>", new PdfInputCairo()); @@ -99,6 +663,7 @@ PdfInputCairo::init(void) { } } } /* namespace Inkscape, Extension, Implementation */ +#endif /* HAVE_POPPLER_CAIRO */ #endif /* HAVE_POPPLER_GLIB */ /* diff --git a/src/extension/internal/pdf-input-cairo.h b/src/extension/internal/pdf-input-cairo.h index 5715b57c9..ad7c884cb 100644 --- a/src/extension/internal/pdf-input-cairo.h +++ b/src/extension/internal/pdf-input-cairo.h @@ -16,7 +16,25 @@ # include <config.h> #endif +#include <gtkmm/dialog.h> +#include <gtkmm/button.h> +#include <gtkmm/buttonbox.h> +#include <gtkmm/label.h> +#include <gtkmm/spinbutton.h> +#include <gtkmm/box.h> +#include <gtkmm/checkbutton.h> +#include <gtkmm/comboboxtext.h> +#include <gtkmm/drawingarea.h> +#include <gtkmm/alignment.h> +#include <gtkmm/frame.h> +#include <gtkmm/scale.h> +#include <glibmm/i18n.h> +#include <gdk/gdk.h> + #ifdef HAVE_POPPLER_GLIB +#ifdef HAVE_POPPLER_CAIRO + +#include <poppler/glib/poppler.h> #include "../implementation/implementation.h" @@ -24,6 +42,69 @@ namespace Inkscape { namespace Extension { namespace Internal { +class PdfImportCairoDialog : public Gtk::Dialog +{ +public: + PdfImportCairoDialog(PopplerDocument* doc); + virtual ~PdfImportCairoDialog(); + + bool showDialog(); + int getSelectedPage(); + void getImportSettings(Inkscape::XML::Node *prefs); + +private: + void _setPreviewPage(int page); + + // Signal handlers + bool _onExposePreview(GdkEventExpose *event); + void _onPageNumberChanged(); + void _onToggleCropping(); + void _onPrecisionChanged(); + + class Gtk::Button * cancelbutton; + class Gtk::Button * okbutton; + class Gtk::Label * _labelSelect; + class Gtk::SpinButton * _pageNumberSpin; + class Gtk::Label * _labelTotalPages; + class Gtk::HBox * hbox2; + class Gtk::CheckButton * _cropCheck; + class Gtk::ComboBoxText * _cropTypeCombo; + class Gtk::HBox * hbox3; + class Gtk::VBox * vbox2; + class Gtk::Alignment * alignment3; + class Gtk::Label * _labelPageSettings; + class Gtk::Frame * _pageSettingsFrame; + class Gtk::Label * _labelPrecision; + class Gtk::Label * _labelPrecisionWarning; + class Gtk::HScale * _fallbackPrecisionSlider; + class Gtk::Adjustment *_fallbackPrecisionSlider_adj; + class Gtk::Label * _labelPrecisionComment; + class Gtk::HBox * hbox6; + class Gtk::Label * _labelText; + class Gtk::ComboBoxText * _textHandlingCombo; + class Gtk::HBox * hbox5; + class Gtk::CheckButton * _localFontsCheck; + class Gtk::CheckButton * _embedImagesCheck; + class Gtk::VBox * vbox3; + class Gtk::Alignment * alignment4; + class Gtk::Label * _labelImportSettings; + class Gtk::Frame * _importSettingsFrame; + class Gtk::VBox * vbox1; + class Gtk::DrawingArea * _previewArea; + class Gtk::HBox * hbox1; + + PopplerDocument *_poppler_doc; + // PopplerPage *_previewed_page; + int _current_page; // Current selected page + unsigned char *_thumb_data; // Thumbnail image data + int _thumb_width, _thumb_height; // Thumbnail size + int _thumb_rowstride; + int _preview_width, _preview_height; // Size of the preview area + bool _render_thumb; // Whether we can/shall render thumbnails + cairo_surface_t *_cairo_surface; // this cairo surface is used for preview +}; + + class PdfInputCairo: public Inkscape::Extension::Implementation::Implementation { PdfInputCairo () { }; public: @@ -35,6 +116,7 @@ public: } } } /* namespace Inkscape, Extension, Implementation */ +#endif /* HAVE_POPPLER_CAIRO */ #endif /* HAVE_POPPLER_GLIB */ #endif /* __EXTENSION_INTERNAL_PDFINPUTCAIRO_H__ */ diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 8b414239a..94edf826e 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -247,7 +247,7 @@ static gchar *svgConvertGfxRGB(GfxRGB *color) { static void svgSetTransform(Inkscape::XML::Node *node, double c0, double c1, double c2, double c3, double c4, double c5) { - Geom::Matrix matrix(c0, c1, c2, c3, c4, c5); + Geom::Affine matrix(c0, c1, c2, c3, c4, c5); gchar *transform_text = sp_svg_transform_write(matrix); node->setAttribute("transform", transform_text); g_free(transform_text); @@ -531,7 +531,7 @@ void SvgBuilder::setClipPath(GfxState *state, bool even_odd) { clip_path->appendChild(path); Inkscape::GC::release(path); // Append clipPath to defs and get id - SP_OBJECT_REPR (SP_DOCUMENT_DEFS (_doc))->appendChild(clip_path); + SP_DOCUMENT_DEFS(_doc)->getRepr()->appendChild(clip_path); gchar *urltext = g_strdup_printf ("url(#%s)", clip_path->attribute("id")); Inkscape::GC::release(clip_path); _container->setAttribute("clip-path", urltext); @@ -544,7 +544,7 @@ void SvgBuilder::setClipPath(GfxState *state, bool even_odd) { * \return true on success; false on invalid transformation */ bool SvgBuilder::getTransform(double *transform) { - Geom::Matrix svd; + Geom::Affine svd; gchar const *tr = _container->attribute("transform"); bool valid = sp_svg_transform_read(tr, &svd); if (valid) { @@ -634,7 +634,7 @@ gchar *SvgBuilder::_createTilingPattern(GfxTilingPattern *tiling_pattern, Inkscape::XML::Node *pattern_node = _xml_doc->createElement("svg:pattern"); // Set pattern transform matrix double *p2u = tiling_pattern->getMatrix(); - Geom::Matrix pat_matrix(p2u[0], p2u[1], p2u[2], p2u[3], p2u[4], p2u[5]); + Geom::Affine pat_matrix(p2u[0], p2u[1], p2u[2], p2u[3], p2u[4], p2u[5]); gchar *transform_text = sp_svg_transform_write(pat_matrix); pattern_node->setAttribute("patternTransform", transform_text); g_free(transform_text); @@ -678,7 +678,7 @@ gchar *SvgBuilder::_createTilingPattern(GfxTilingPattern *tiling_pattern, delete pattern_builder; // Append the pattern to defs - SP_OBJECT_REPR (SP_DOCUMENT_DEFS (_doc))->appendChild(pattern_node); + SP_DOCUMENT_DEFS(_doc)->getRepr()->appendChild(pattern_node); gchar *id = g_strdup(pattern_node->attribute("id")); Inkscape::GC::release(pattern_node); @@ -732,10 +732,10 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for gradient->setAttribute("gradientUnits", "userSpaceOnUse"); // If needed, flip the gradient transform around the y axis if (matrix) { - Geom::Matrix pat_matrix(matrix[0], matrix[1], matrix[2], matrix[3], + Geom::Affine pat_matrix(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); if ( !for_shading && _is_top_level ) { - Geom::Matrix flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * PT_PER_PX); + Geom::Affine flip(1.0, 0.0, 0.0, -1.0, 0.0, _height * PT_PER_PX); pat_matrix *= flip; } gchar *transform_text = sp_svg_transform_write(pat_matrix); @@ -752,7 +752,7 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for return NULL; } - Inkscape::XML::Node *defs = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (_doc)); + Inkscape::XML::Node *defs = SP_DOCUMENT_DEFS(_doc)->getRepr(); defs->appendChild(gradient); gchar *id = g_strdup(gradient->attribute("id")); Inkscape::GC::release(gradient); @@ -1149,7 +1149,7 @@ void SvgBuilder::updateTextMatrix(GfxState *state) { max_scale = h_scale; } // Calculate new text matrix - Geom::Matrix new_text_matrix(text_matrix[0] * state->getHorizScaling(), + Geom::Affine new_text_matrix(text_matrix[0] * state->getHorizScaling(), text_matrix[1] * state->getHorizScaling(), -text_matrix[2], -text_matrix[3], 0.0, 0.0); @@ -1184,7 +1184,7 @@ void SvgBuilder::_flushText() { Inkscape::XML::Node *text_node = _xml_doc->createElement("svg:text"); // Set text matrix - Geom::Matrix text_transform(_text_matrix); + Geom::Affine text_transform(_text_matrix); text_transform[4] = first_glyph.position[0]; text_transform[5] = first_glyph.position[1]; gchar *transform = sp_svg_transform_write(text_transform); @@ -1635,9 +1635,9 @@ Inkscape::XML::Node *SvgBuilder::_createMask(double width, double height) { sp_repr_set_svg_double(mask_node, "height", height); // Append mask to defs if (_is_top_level) { - SP_OBJECT_REPR (SP_DOCUMENT_DEFS (_doc))->appendChild(mask_node); + SP_DOCUMENT_DEFS(_doc)->getRepr()->appendChild(mask_node); Inkscape::GC::release(mask_node); - return SP_OBJECT_REPR (SP_DOCUMENT_DEFS (_doc))->lastChild(); + return SP_DOCUMENT_DEFS(_doc)->getRepr()->lastChild(); } else { // Work around for renderer bug when mask isn't defined in pattern static int mask_count = 0; Inkscape::XML::Node *defs = _root->firstChild(); @@ -1719,7 +1719,7 @@ void SvgBuilder::addMaskedImage(GfxState *state, Stream *str, int width, int hei mask_image_node->setAttribute("transform", NULL); mask_node->appendChild(mask_image_node); // Scale the mask to the size of the image - Geom::Matrix mask_transform((double)width, 0.0, 0.0, (double)height, 0.0, 0.0); + Geom::Affine mask_transform((double)width, 0.0, 0.0, (double)height, 0.0, 0.0); gchar *transform_text = sp_svg_transform_write(mask_transform); mask_node->setAttribute("maskTransform", transform_text); g_free(transform_text); diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index f0062bbe6..47e5d7735 100644 --- a/src/extension/internal/pdfinput/svg-builder.h +++ b/src/extension/internal/pdfinput/svg-builder.h @@ -27,7 +27,7 @@ namespace Inkscape { } #include <2geom/point.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <glibmm/ustring.h> #include "CharTypes.h" @@ -212,7 +212,7 @@ private: char *_font_specification; double _font_scaling; bool _need_font_update; - Geom::Matrix _text_matrix; + Geom::Affine _text_matrix; Geom::Point _text_position; std::vector<SvgGlyph> _glyphs; // Added characters bool _in_text_object; // Whether we are inside a text object diff --git a/src/extension/internal/pov-out.cpp b/src/extension/internal/pov-out.cpp index a130b6923..1563d04c1 100644 --- a/src/extension/internal/pov-out.cpp +++ b/src/extension/internal/pov-out.cpp @@ -72,16 +72,15 @@ static void err(const char *fmt, ...) -static double -effective_opacity(SPItem const *item) +static double effective_opacity(SPItem const *item) { + // TODO investigate this. The early return seems that it would abort early. + // Plus is will emit a warning, which may not be proper here. double ret = 1.0; - for (SPObject const *obj = item; obj; obj = obj->parent) - { - SPStyle const *const style = SP_OBJECT_STYLE(obj); - g_return_val_if_fail(style, ret); - ret *= SP_SCALE24_TO_FLOAT(style->opacity.value); - } + for (SPObject const *obj = item; obj; obj = obj->parent) { + g_return_val_if_fail(obj->style, ret); + ret *= SP_SCALE24_TO_FLOAT(obj->style->opacity.value); + } return ret; } @@ -275,7 +274,7 @@ bool PovOutput::doCurve(SPItem *item, const String &id) shapeInfo.color = ""; //Try to get the fill color of the shape - SPStyle *style = SP_OBJECT_STYLE(shape); + SPStyle *style = shape->style; /* fixme: Handle other fill types, even if this means translating gradients to a single flat colour. */ if (style) @@ -301,7 +300,7 @@ bool PovOutput::doCurve(SPItem *item, const String &id) povShapes.push_back(shapeInfo); //passed all tests. save the info // convert the path to only lineto's and cubic curveto's: - Geom::Matrix tf = item->i2d_affine(); + Geom::Affine tf = item->i2d_affine(); Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf ); /* diff --git a/src/extension/internal/win32.cpp b/src/extension/internal/win32.cpp index 8b4ff13c8..537c91a2c 100644 --- a/src/extension/internal/win32.cpp +++ b/src/extension/internal/win32.cpp @@ -293,7 +293,7 @@ PrintWin32::finish (Inkscape::Extension::Print *mod) scaley = dpiY / 72.0; // We simply map document 0,0 to physical page 0,0 - Geom::Matrix affine = Geom::Scale(scalex / 1.25, scaley / 1.25); + Geom::Affine affine = Geom::Scale(scalex / 1.25, scaley / 1.25); nr_arena_item_set_transform (mod->root, affine); diff --git a/src/extension/internal/win32.h b/src/extension/internal/win32.h index 02790a231..4a913bb05 100644 --- a/src/extension/internal/win32.h +++ b/src/extension/internal/win32.h @@ -70,11 +70,11 @@ public: /* Rendering methods */ /* - virtual unsigned int bind (Inkscape::Extension::Print * module, const Geom::Matrix *transform, float opacity); + virtual unsigned int bind (Inkscape::Extension::Print * module, const Geom::Affine *transform, float opacity); virtual unsigned int release (Inkscape::Extension::Print * module); virtual unsigned int comment (Inkscape::Extension::Print * module, const char * comment); virtual unsigned int image (Inkscape::Extension::Print * module, unsigned char *px, unsigned int w, unsigned int h, unsigned int rs, - const Geom::Matrix *transform, const SPStyle *style); + const Geom::Affine *transform, const SPStyle *style); */ }; diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index f17b45b4b..049b7d5a3 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -30,8 +30,16 @@ namespace Extension { /** \brief Initialize the object, to do that, copy the data. */ -ParamDescription::ParamDescription (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _value(NULL) +ParamDescription::ParamDescription (const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode) : + Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _value(NULL), _mode(mode) { // printf("Building Description\n"); const char * defaultval = NULL; @@ -60,13 +68,21 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node newguitext = _(_value); } - Gtk::Label * label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_LEFT)); - + Gtk::Label * label; + int padding = 12; + if (_mode == HEADER) { + label = Gtk::manage(new Gtk::Label(Glib::ustring("<b>") +newguitext + Glib::ustring("</b>"), Gtk::ALIGN_LEFT)); + label->set_padding(0,5); + label->set_use_markup(true); + padding = 0; + } else { + label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_LEFT)); + } label->set_line_wrap(); label->show(); Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); - hbox->pack_start(*label, true, true, 12); + hbox->pack_start(*label, true, true, padding); hbox->show(); return hbox; diff --git a/src/extension/param/description.h b/src/extension/param/description.h index c56b5c21d..c34e4ee38 100644 --- a/src/extension/param/description.h +++ b/src/extension/param/description.h @@ -18,13 +18,25 @@ namespace Extension { /** \brief A description parameter */ class ParamDescription : public Parameter { +public: + enum AppearanceMode { + DESC, HEADER + }; + ParamDescription(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal); private: /** \brief Internal value. */ gchar * _value; + AppearanceMode _mode; const gchar* _context; -public: - ParamDescription(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); - Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal); }; } /* namespace Extension */ diff --git a/src/extension/param/float.cpp b/src/extension/param/float.cpp index 62762b3bb..d94463a5b 100644 --- a/src/extension/param/float.cpp +++ b/src/extension/param/float.cpp @@ -11,6 +11,7 @@ #include <gtkmm/adjustment.h> #include <gtkmm/box.h> +#include <gtkmm/scale.h> #include <gtkmm/spinbutton.h> #include "xml/node.h" @@ -23,8 +24,17 @@ namespace Extension { /** \brief Use the superclass' allocator and set the \c _value */ -ParamFloat::ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _value(0.0), _min(0.0), _max(10.0) +ParamFloat::ParamFloat (const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode) : + Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), + _value(0.0), _mode(mode), _min(0.0), _max(10.0) { const gchar * defaultval = NULL; if (sp_repr_children(xml) != NULL) @@ -110,7 +120,7 @@ public: /** \brief Make the adjustment using an extension and the string describing the parameter. */ ParamFloatAdjustment (ParamFloat * param, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) : - Gtk::Adjustment(0.0, param->min(), param->max(), 0.1, 0), _pref(param), _doc(doc), _node(node), _changeSignal(changeSignal) { + Gtk::Adjustment(0.0, param->min(), param->max(), 0.1, 1.0, 0), _pref(param), _doc(doc), _node(node), _changeSignal(changeSignal) { this->set_value(_pref->get(NULL, NULL) /* \todo fix */); this->signal_value_changed().connect(sigc::mem_fun(this, &ParamFloatAdjustment::val_changed)); return; @@ -153,6 +163,15 @@ ParamFloat::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::sign hbox->pack_start(*label, true, true); ParamFloatAdjustment * fadjust = Gtk::manage(new ParamFloatAdjustment(this, doc, node, changeSignal)); + + if (_mode == FULL) { + Gtk::HScale * scale = Gtk::manage(new Gtk::HScale(*fadjust)); + scale->set_draw_value(false); + scale->set_size_request(200, -1); + scale->show(); + hbox->pack_start(*scale, false, false); + } + Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 0.1, _precision)); spin->show(); hbox->pack_start(*spin, false, false); diff --git a/src/extension/param/float.h b/src/extension/param/float.h index f105d8f0e..2e816d4dc 100644 --- a/src/extension/param/float.h +++ b/src/extension/param/float.h @@ -17,14 +17,19 @@ namespace Inkscape { namespace Extension { class ParamFloat : public Parameter { -private: - /** \brief Internal value. */ - float _value; - float _min; - float _max; - int _precision; public: - ParamFloat (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + enum AppearanceMode { + FULL, MINIMAL + }; + ParamFloat (const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode); /** \brief Returns \c _value */ float get (const SPDocument * /*doc*/, const Inkscape::XML::Node * /*node*/) { return _value; } float set (float in, SPDocument * doc, Inkscape::XML::Node * node); @@ -33,6 +38,13 @@ public: float precision (void) { return _precision; } Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal); void string (std::string &string); +private: + /** \brief Internal value. */ + float _value; + AppearanceMode _mode; + float _min; + float _max; + int _precision; }; } /* namespace Extension */ diff --git a/src/extension/param/groupheader.cpp b/src/extension/param/groupheader.cpp deleted file mode 100755 index abf5f8beb..000000000 --- a/src/extension/param/groupheader.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2005-2010 Authors: - * Ted Gould <ted@gould.cx> - * Johan Engelen <johan@shouraizou.nl> * - * Nicolas Dufour <nicoduf@yahoo.fr> - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef linux // does the dollar sign need escaping when passed as string parameter? -# define ESCAPE_DOLLAR_COMMANDLINE -#endif - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - - -#include "groupheader.h" - -#include <gtkmm/adjustment.h> -#include <gtkmm/box.h> -#include <gtkmm/spinbutton.h> -#include <sstream> -#include <glibmm/i18n.h> - -#include "xml/node.h" -#include "extension/extension.h" - -namespace Inkscape { -namespace Extension { - - -/** \brief Initialize the object, to do that, copy the data. */ -ParamGroupHeader::ParamGroupHeader (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _value(NULL) -{ - // printf("Building GroupHeader\n"); - const char * defaultval = NULL; - if (sp_repr_children(xml) != NULL) - defaultval = sp_repr_children(xml)->content(); - - if (defaultval != NULL) - _value = g_strdup(defaultval); - - _context = xml->attribute("msgctxt"); - - return; -} - -/** \brief Create a label for the GroupHeader */ -Gtk::Widget * -ParamGroupHeader::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal<void> * /*changeSignal*/) -{ - if (_gui_hidden) return NULL; - - Glib::ustring newguitext; - - if (_context != NULL) { - newguitext = g_dpgettext2(NULL, _context, _value); - } else { - newguitext = _(_value); - } - - Gtk::Label * label = Gtk::manage(new Gtk::Label(Glib::ustring("<b>") +newguitext + Glib::ustring("</b>"), Gtk::ALIGN_LEFT)); - label->set_line_wrap(); - label->set_padding(0,5); - label->set_use_markup(true); - label->show(); - - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); - hbox->pack_start(*label, true, true); - hbox->show(); - - return hbox; -} - -} /* namespace Extension */ -} /* namespace Inkscape */ diff --git a/src/extension/param/groupheader.h b/src/extension/param/groupheader.h deleted file mode 100755 index 94fe880f9..000000000 --- a/src/extension/param/groupheader.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __INK_EXTENSION_PARAMGROUPHEADER_H__ -#define __INK_EXTENSION_PARAMGROUPHEADER_H__ - -/* - * Copyright (C) 2005-2010 Authors: - * Ted Gould <ted@gould.cx> - * Johan Engelen <johan@shouraizou.nl> * - * Nicolas Dufour <nicoduf@yahoo.fr> - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include <gtkmm/widget.h> -#include <xml/node.h> -#include <document.h> -#include "parameter.h" - -namespace Inkscape { -namespace Extension { - -/** \brief A GroupLabel parameter */ -class ParamGroupHeader : public Parameter { -private: - /** \brief Internal value. */ - gchar * _value; - const gchar* _context; -public: - ParamGroupHeader(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); - Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal); -}; - -} /* namespace Extension */ -} /* namespace Inkscape */ - -#endif /* __INK_EXTENSION_PARAMGROUPHEADER_H__ */ - -/* - 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 : diff --git a/src/extension/param/int.cpp b/src/extension/param/int.cpp index ae69d0661..69849c656 100644 --- a/src/extension/param/int.cpp +++ b/src/extension/param/int.cpp @@ -11,6 +11,7 @@ #include <gtkmm/adjustment.h> #include <gtkmm/box.h> +#include <gtkmm/scale.h> #include <gtkmm/spinbutton.h> #include "xml/node.h" @@ -23,8 +24,17 @@ namespace Extension { /** \brief Use the superclass' allocator and set the \c _value */ -ParamInt::ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _value(0), _min(0), _max(10) +ParamInt::ParamInt (const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode) : + Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), + _value(0), _mode(mode), _min(0), _max(10) { const char * defaultval = NULL; if (sp_repr_children(xml) != NULL) @@ -95,7 +105,7 @@ public: /** \brief Make the adjustment using an extension and the string describing the parameter. */ ParamIntAdjustment (ParamInt * param, SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) : - Gtk::Adjustment(0.0, param->min(), param->max(), 1.0, 0), _pref(param), _doc(doc), _node(node), _changeSignal(changeSignal) { + Gtk::Adjustment(0.0, param->min(), param->max(), 1.0, 10.0, 0), _pref(param), _doc(doc), _node(node), _changeSignal(changeSignal) { this->set_value(_pref->get(NULL, NULL) /* \todo fix */); this->signal_value_changed().connect(sigc::mem_fun(this, &ParamIntAdjustment::val_changed)); return; @@ -138,6 +148,15 @@ ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal hbox->pack_start(*label, true, true); ParamIntAdjustment * fadjust = Gtk::manage(new ParamIntAdjustment(this, doc, node, changeSignal)); + + if (_mode == FULL) { + Gtk::HScale * scale = Gtk::manage(new Gtk::HScale(*fadjust)); + scale->set_draw_value(false); + scale->set_size_request(200, -1); + scale->show(); + hbox->pack_start(*scale, false, false); + } + Gtk::SpinButton * spin = Gtk::manage(new Gtk::SpinButton(*fadjust, 1.0, 0)); spin->show(); hbox->pack_start(*spin, false, false); diff --git a/src/extension/param/int.h b/src/extension/param/int.h index a4eb54c81..fce085378 100644 --- a/src/extension/param/int.h +++ b/src/extension/param/int.h @@ -17,13 +17,19 @@ namespace Inkscape { namespace Extension { class ParamInt : public Parameter { -private: - /** \brief Internal value. */ - int _value; - int _min; - int _max; public: - ParamInt (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + enum AppearanceMode { + FULL, MINIMAL + }; + ParamInt (const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode); /** \brief Returns \c _value */ int get (const SPDocument * /*doc*/, const Inkscape::XML::Node * /*node*/) { return _value; } int set (int in, SPDocument * doc, Inkscape::XML::Node * node); @@ -31,6 +37,12 @@ public: int min (void) { return _min; } Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal); void string (std::string &string); +private: + /** \brief Internal value. */ + int _value; + AppearanceMode _mode; + int _min; + int _max; }; } /* namespace Extension */ diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp index ac7c8b8dd..a9935cfe6 100644 --- a/src/extension/param/parameter.cpp +++ b/src/extension/param/parameter.cpp @@ -36,7 +36,6 @@ #include "bool.h" #include "color.h" #include "description.h" -#include "groupheader.h" #include "enum.h" #include "float.h" #include "int.h" @@ -124,9 +123,17 @@ Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * if (!strcmp(type, "boolean")) { param = new ParamBool(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); } else if (!strcmp(type, "int")) { - param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + if (appearance && !strcmp(appearance, "full")) { + param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamInt::FULL); + } else { + param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamInt::MINIMAL); + } } else if (!strcmp(type, "float")) { - param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + if (appearance && !strcmp(appearance, "full")) { + param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamFloat::FULL); + } else { + param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamFloat::MINIMAL); + } } else if (!strcmp(type, "string")) { param = new ParamString(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); const gchar * max_length = in_repr->attribute("max_length"); @@ -135,9 +142,11 @@ Parameter::make (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * ps->setMaxLength(atoi(max_length)); } } else if (!strcmp(type, "description")) { - param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); - } else if (!strcmp(type, "groupheader")) { - param = new ParamGroupHeader(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + if (appearance && !strcmp(appearance, "header")) { + param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamDescription::HEADER); + } else { + param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamDescription::DESC); + } } else if (!strcmp(type, "enum")) { param = new ParamComboBox(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); } else if (!strcmp(type, "notebook")) { @@ -349,7 +358,7 @@ Parameter::new_child (Inkscape::XML::Node * parent) Inkscape::XML::Node *Parameter::document_param_node(SPDocument * doc) { Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc)); + Inkscape::XML::Node * defs = SP_DOCUMENT_DEFS(doc)->getRepr(); Inkscape::XML::Node * params = NULL; GQuark const name_quark = g_quark_from_string("inkscape:extension-params"); diff --git a/src/extension/patheffect.cpp b/src/extension/patheffect.cpp index 8e3fc13f1..09ee9be0b 100644 --- a/src/extension/patheffect.cpp +++ b/src/extension/patheffect.cpp @@ -42,7 +42,7 @@ PathEffect::processPathEffects (SPDocument * doc, Inkscape::XML::Node * path) return; gchar ** patheffects = g_strsplit(patheffectlist, ";", 128); - Inkscape::XML::Node * defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc)); + Inkscape::XML::Node * defs = SP_DOCUMENT_DEFS(doc)->getRepr(); for (int i = 0; patheffects[i] != NULL && i < 128; i++) { gchar * patheffect = patheffects[i]; diff --git a/src/extension/print.cpp b/src/extension/print.cpp index 2d4177d60..ad8c4c38d 100644 --- a/src/extension/print.cpp +++ b/src/extension/print.cpp @@ -61,7 +61,7 @@ Print::finish (void) } unsigned int -Print::bind (const Geom::Matrix *transform, float opacity) +Print::bind (const Geom::Affine *transform, float opacity) { return imp->bind (this, transform, opacity); } @@ -79,14 +79,14 @@ Print::comment (const char * comment) } unsigned int -Print::fill (Geom::PathVector const &pathv, const Geom::Matrix *ctm, const SPStyle *style, +Print::fill (Geom::PathVector const &pathv, const Geom::Affine *ctm, const SPStyle *style, const NRRect *pbox, const NRRect *dbox, const NRRect *bbox) { return imp->fill (this, pathv, ctm, style, pbox, dbox, bbox); } unsigned int -Print::stroke (Geom::PathVector const &pathv, const Geom::Matrix *transform, const SPStyle *style, +Print::stroke (Geom::PathVector const &pathv, const Geom::Affine *transform, const SPStyle *style, const NRRect *pbox, const NRRect *dbox, const NRRect *bbox) { return imp->stroke (this, pathv, transform, style, pbox, dbox, bbox); @@ -94,7 +94,7 @@ Print::stroke (Geom::PathVector const &pathv, const Geom::Matrix *transform, con unsigned int Print::image (unsigned char *px, unsigned int w, unsigned int h, unsigned int rs, - const Geom::Matrix *transform, const SPStyle *style) + const Geom::Affine *transform, const SPStyle *style) { return imp->image (this, px, w, h, rs, transform, style); } diff --git a/src/extension/print.h b/src/extension/print.h index 0f0435c0f..d5218aed8 100644 --- a/src/extension/print.h +++ b/src/extension/print.h @@ -41,18 +41,18 @@ public: unsigned int finish (void); /* Rendering methods */ - unsigned int bind (Geom::Matrix const *transform, + unsigned int bind (Geom::Affine const *transform, float opacity); unsigned int release (void); unsigned int comment (const char * comment); unsigned int fill (Geom::PathVector const &pathv, - Geom::Matrix const *ctm, + Geom::Affine const *ctm, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox); unsigned int stroke (Geom::PathVector const &pathv, - Geom::Matrix const *transform, + Geom::Affine const *transform, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, @@ -61,7 +61,7 @@ public: unsigned int w, unsigned int h, unsigned int rs, - Geom::Matrix const *transform, + Geom::Affine const *transform, SPStyle const *style); unsigned int text (char const *text, Geom::Point p, diff --git a/src/extension/timer.h b/src/extension/timer.h index ebae62b24..33b9829e9 100644 --- a/src/extension/timer.h +++ b/src/extension/timer.h @@ -13,6 +13,7 @@ #ifndef INKSCAPE_EXTENSION_TIMER_H__ #define INKSCAPE_EXTENSION_TIMER_H__ +#include <stddef.h> #include <sigc++/sigc++.h> #include <glibmm/timeval.h> #include "extension-forward.h" diff --git a/src/file.cpp b/src/file.cpp index df668be55..ae774bb52 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -963,7 +963,7 @@ file_import(SPDocument *in_doc, const Glib::ustring &uri, prevent_id_clashes(doc, in_doc); SPObject *in_defs = SP_DOCUMENT_DEFS(in_doc); - Inkscape::XML::Node *last_def = SP_OBJECT_REPR(in_defs)->lastChild(); + Inkscape::XML::Node *last_def = in_defs->getRepr()->lastChild(); SPCSSAttr *style = sp_css_attr_from_object(doc->getRoot()); @@ -977,7 +977,7 @@ file_import(SPDocument *in_doc, const Glib::ustring &uri, // Create a new group if necessary. Inkscape::XML::Node *newgroup = NULL; - if ((style && style->firstChild()) || items_count > 1) { + if ((style && style->attributeList()) || items_count > 1) { newgroup = xml_in_doc->createElement("svg:g"); sp_repr_css_set(newgroup, style, "style"); } @@ -999,7 +999,7 @@ file_import(SPDocument *in_doc, const Glib::ustring &uri, SPObject *new_obj = NULL; for ( SPObject *child = doc->getRoot()->firstChild(); child; child = child->getNext() ) { if (SP_IS_ITEM(child)) { - Inkscape::XML::Node *newitem = SP_OBJECT_REPR(child)->duplicate(xml_in_doc); + Inkscape::XML::Node *newitem = child->getRepr()->duplicate(xml_in_doc); // convert layers to groups, and make sure they are unlocked // FIXME: add "preserve layers" mode where each layer from @@ -1012,15 +1012,15 @@ file_import(SPDocument *in_doc, const Glib::ustring &uri, } // don't lose top-level defs or style elements - else if (SP_OBJECT_REPR(child)->type() == Inkscape::XML::ELEMENT_NODE) { - const gchar *tag = SP_OBJECT_REPR(child)->name(); + else if (child->getRepr()->type() == Inkscape::XML::ELEMENT_NODE) { + const gchar *tag = child->getRepr()->name(); if (!strcmp(tag, "svg:defs")) { for ( SPObject *x = child->firstChild(); x; x = x->getNext() ) { - SP_OBJECT_REPR(in_defs)->addChild(SP_OBJECT_REPR(x)->duplicate(xml_in_doc), last_def); + in_defs->getRepr()->addChild(x->getRepr()->duplicate(xml_in_doc), last_def); } } else if (!strcmp(tag, "svg:style")) { - in_doc->getRoot()->appendChildRepr(SP_OBJECT_REPR(child)->duplicate(xml_in_doc)); + in_doc->getRoot()->appendChildRepr(child->getRepr()->duplicate(xml_in_doc)); } } } @@ -1038,7 +1038,7 @@ file_import(SPDocument *in_doc, const Glib::ustring &uri, // preserve parent and viewBox transformations // c2p is identity matrix at this point unless ensureUpToDate is called doc->ensureUpToDate(); - Geom::Matrix affine = SP_ROOT(doc->getRoot())->c2p * SP_ITEM(place_to_insert)->i2doc_affine().inverse(); + Geom::Affine affine = SP_ROOT(doc->getRoot())->c2p * SP_ITEM(place_to_insert)->i2doc_affine().inverse(); sp_selection_apply_affine(selection, desktop->dt2doc() * affine * desktop->doc2dt(), true, false); // move to mouse pointer diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index 4990404a4..16f5a6e85 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -40,7 +40,7 @@ static guint count_filter_hrefs(SPObject *o, SPFilter *filter) guint i = 0; - SPStyle *style = SP_OBJECT_STYLE(o); + SPStyle *style = o->style; if (style && style->filter.set && style->getFilter() == filter) @@ -328,7 +328,7 @@ new_filter_simple_from_item (SPDocument *document, SPItem *item, const char *mod width = height = 0; } - Geom::Matrix i2d (item->i2d_affine () ); + Geom::Affine i2d (item->i2d_affine () ); return (new_filter_blend_gaussian_blur (document, mode, radius, i2d.descrim(), i2d.expansionX(), i2d.expansionY(), width, height)); } @@ -354,8 +354,8 @@ SPFilter *modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *it // If there are more users for this filter, duplicate it if (filter->hrefcount > count_filter_hrefs(item, filter)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(item->style->getFilter())->duplicate(xml_doc); - SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document); + Inkscape::XML::Node *repr = item->style->getFilter()->getRepr()->duplicate(xml_doc); + SPDefs *defs = reinterpret_cast<SPDefs *>(SP_DOCUMENT_DEFS(document)); defs->appendChild(repr); filter = SP_FILTER( document->getObjectByRepr(repr) ); @@ -363,7 +363,7 @@ SPFilter *modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *it } // Determine the required standard deviation value - Geom::Matrix i2d (item->i2d_affine ()); + Geom::Affine i2d (item->i2d_affine ()); double expansion = i2d.descrim(); double stdDeviation = radius; if (expansion != 0) @@ -381,7 +381,7 @@ SPFilter *modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *it } // Set the filter effects area - Inkscape::XML::Node *repr = SP_OBJECT_REPR(item->style->getFilter()); + Inkscape::XML::Node *repr = item->style->getFilter()->getRepr(); set_filter_area(repr, radius, expansion, i2d.expansionX(), i2d.expansionY(), width, height); @@ -408,7 +408,7 @@ SPFilter *modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *it sp_repr_set_svg_double(b_repr, "stdDeviation", stdDeviation); //set feGaussianBlur as child of filter node - SP_OBJECT_REPR(filter)->appendChild(b_repr); + filter->getRepr()->appendChild(b_repr); Inkscape::GC::release(b_repr); return filter; @@ -416,13 +416,14 @@ SPFilter *modify_filter_gaussian_blur_from_item(SPDocument *document, SPItem *it void remove_filter (SPObject *item, bool recursive) { - SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_unset_property (css, "filter"); - if (recursive) - sp_repr_css_change_recursive(SP_OBJECT_REPR(item), css, "style"); - else - sp_repr_css_change (SP_OBJECT_REPR(item), css, "style"); - sp_repr_css_attr_unref (css); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_unset_property(css, "filter"); + if (recursive) { + sp_repr_css_change_recursive(item->getRepr(), css, "style"); + } else { + sp_repr_css_change(item->getRepr(), css, "style"); + } + sp_repr_css_attr_unref(css); } /** @@ -436,7 +437,7 @@ void remove_filter_gaussian_blur (SPObject *item) { if (item->style && item->style->filter.set && item->style->getFilter()) { // Search for the first blur primitive and remove it. (if found) - Inkscape::XML::Node *repr = SP_OBJECT_REPR(item->style->getFilter()); + Inkscape::XML::Node *repr = item->style->getFilter()->getRepr(); Inkscape::XML::Node *primitive = repr->firstChild(); while (primitive) { if (strcmp("svg:feGaussianBlur", primitive->name()) == 0) { @@ -455,18 +456,18 @@ void remove_filter_gaussian_blur (SPObject *item) bool filter_is_single_gaussian_blur(SPFilter *filter) { - return (SP_OBJECT(filter)->firstChild() && - SP_OBJECT(filter)->firstChild() == SP_OBJECT(filter)->lastChild() && - SP_IS_GAUSSIANBLUR(SP_OBJECT(filter)->firstChild())); + return (filter->firstChild() && + (filter->firstChild() == filter->lastChild()) && + SP_IS_GAUSSIANBLUR(filter->firstChild())); } double get_single_gaussian_blur_radius(SPFilter *filter) { - if (SP_OBJECT(filter)->firstChild() && - SP_OBJECT(filter)->firstChild() == SP_OBJECT(filter)->lastChild() && - SP_IS_GAUSSIANBLUR(SP_OBJECT(filter)->firstChild())) { + if (filter->firstChild() && + (filter->firstChild() == filter->lastChild()) && + SP_IS_GAUSSIANBLUR(filter->firstChild())) { - SPGaussianBlur *gb = SP_GAUSSIANBLUR(SP_OBJECT(filter)->firstChild()); + SPGaussianBlur *gb = SP_GAUSSIANBLUR(filter->firstChild()); double x = gb->stdDeviation.getNumber(); double y = gb->stdDeviation.getOptNumber(); if (x > 0 && y > 0) { diff --git a/src/filter-enums.cpp b/src/filter-enums.cpp index 2f6d2f64b..315b242bf 100644 --- a/src/filter-enums.cpp +++ b/src/filter-enums.cpp @@ -48,11 +48,11 @@ const EnumDataConverter<FilterPrimitiveInput> FPInputConverter(FPInputData, FPIN // feBlend const EnumData<Inkscape::Filters::FilterBlendMode> BlendModeData[Inkscape::Filters::BLEND_ENDMODE] = { - {Inkscape::Filters::BLEND_NORMAL, C_("Filter blend mode", "Normal"), "normal"}, - {Inkscape::Filters::BLEND_MULTIPLY, C_("Filter blend mode", "Multiply"), "multiply"}, - {Inkscape::Filters::BLEND_SCREEN, C_("Filter blend mode", "Screen"), "screen"}, - {Inkscape::Filters::BLEND_DARKEN, C_("Filter blend mode", "Darken"), "darken"}, - {Inkscape::Filters::BLEND_LIGHTEN, C_("Filter blend mode", "Lighten"), "lighten"} + {Inkscape::Filters::BLEND_NORMAL, _("Normal"), "normal"}, + {Inkscape::Filters::BLEND_MULTIPLY, _("Multiply"), "multiply"}, + {Inkscape::Filters::BLEND_SCREEN, _("Screen"), "screen"}, + {Inkscape::Filters::BLEND_DARKEN, _("Darken"), "darken"}, + {Inkscape::Filters::BLEND_LIGHTEN, _("Lighten"), "lighten"} }; const EnumDataConverter<Inkscape::Filters::FilterBlendMode> BlendModeConverter(BlendModeData, Inkscape::Filters::BLEND_ENDMODE); diff --git a/src/filters/colormatrix.cpp b/src/filters/colormatrix.cpp index 4d54aa579..b110e2766 100644 --- a/src/filters/colormatrix.cpp +++ b/src/filters/colormatrix.cpp @@ -191,7 +191,7 @@ sp_feColorMatrix_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape: /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feColorMatrix_parent_class)->write) { diff --git a/src/filters/componenttransfer-funcnode.cpp b/src/filters/componenttransfer-funcnode.cpp index a245e1c89..446009e1d 100644 --- a/src/filters/componenttransfer-funcnode.cpp +++ b/src/filters/componenttransfer-funcnode.cpp @@ -183,14 +183,13 @@ sp_fefuncnode_build(SPObject *object, SPDocument *document, Inkscape::XML::Node /** * Drops any allocated memory. */ -static void -sp_fefuncnode_release(SPObject *object) +static void sp_fefuncnode_release(SPObject *object) { //SPFeFuncNode *fefuncnode = SP_FEFUNCNODE(object); - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("fefuncnode", SP_OBJECT(object)); + if ( object->document ) { + // Unregister ourselves + object->document->removeResource("fefuncnode", object); } //TODO: release resources here @@ -313,7 +312,7 @@ sp_fefuncnode_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XM SPFeFuncNode *fefuncnode = SP_FEFUNCNODE(object); if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } (void)fefuncnode; diff --git a/src/filters/componenttransfer.cpp b/src/filters/componenttransfer.cpp index e2e4922c8..99d8616f4 100644 --- a/src/filters/componenttransfer.cpp +++ b/src/filters/componenttransfer.cpp @@ -222,7 +222,7 @@ sp_feComponentTransfer_write(SPObject *object, Inkscape::XML::Document *doc, Ink /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feComponentTransfer_parent_class)->write) { diff --git a/src/filters/convolvematrix.cpp b/src/filters/convolvematrix.cpp index 263e6edc4..20d652bee 100644 --- a/src/filters/convolvematrix.cpp +++ b/src/filters/convolvematrix.cpp @@ -299,7 +299,7 @@ sp_feConvolveMatrix_write(SPObject *object, Inkscape::XML::Document *doc, Inksca /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } diff --git a/src/filters/diffuselighting.cpp b/src/filters/diffuselighting.cpp index 7169bb285..0f2f29d67 100644 --- a/src/filters/diffuselighting.cpp +++ b/src/filters/diffuselighting.cpp @@ -249,7 +249,7 @@ sp_feDiffuseLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inksc /* TODO: Don't just clone, but create a new repr node and write all * relevant values _and children_ into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); //repr = doc->createElement("svg:feDiffuseLighting"); } diff --git a/src/filters/distantlight.cpp b/src/filters/distantlight.cpp index a646267be..891049415 100644 --- a/src/filters/distantlight.cpp +++ b/src/filters/distantlight.cpp @@ -115,9 +115,9 @@ sp_fedistantlight_release(SPObject *object) { //SPFeDistantLight *fedistantlight = SP_FEDISTANTLIGHT(object); - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("fedistantlight", SP_OBJECT(object)); + if ( object->document ) { + // Unregister ourselves + object->document->removeResource("fedistantlight", object); } //TODO: release resources here @@ -206,7 +206,7 @@ sp_fedistantlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape SPFeDistantLight *fedistantlight = SP_FEDISTANTLIGHT(object); if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (fedistantlight->azimuth_set) diff --git a/src/filters/flood.cpp b/src/filters/flood.cpp index e1c7ba214..3de1eb527 100644 --- a/src/filters/flood.cpp +++ b/src/filters/flood.cpp @@ -204,7 +204,7 @@ sp_feFlood_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML:: /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feFlood_parent_class)->write) { diff --git a/src/filters/gaussian-blur.cpp b/src/filters/gaussian-blur.cpp index 8919aece0..ee1af8904 100644 --- a/src/filters/gaussian-blur.cpp +++ b/src/filters/gaussian-blur.cpp @@ -159,7 +159,7 @@ sp_gaussianBlur_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape:: /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) gaussianBlur_parent_class)->write) { diff --git a/src/filters/image.cpp b/src/filters/image.cpp index bbe775c18..f6ef310f7 100644 --- a/src/filters/image.cpp +++ b/src/filters/image.cpp @@ -19,6 +19,7 @@ #endif #include "uri.h" #include "uri-references.h" +#include "enums.h" #include "attributes.h" #include "svg/svg.h" #include "image.h" @@ -78,8 +79,10 @@ static void sp_feImage_class_init(SPFeImageClass *klass) sp_primitive_class->build_renderer = sp_feImage_build_renderer; } -static void sp_feImage_init(SPFeImage */*feImage*/) +static void sp_feImage_init(SPFeImage *feImage) { + feImage->aspect_align = SP_ASPECT_XMID_YMID; // Default + feImage->aspect_clip = SP_ASPECT_MEET; // Default } /** @@ -99,10 +102,7 @@ static void sp_feImage_build(SPObject *object, SPDocument *document, Inkscape::X /*LOAD ATTRIBUTES FROM REPR HERE*/ - object->readAttr( "x" ); - object->readAttr( "y" ); - object->readAttr( "width" ); - object->readAttr( "height" ); + object->readAttr( "preserveAspectRatio" ); object->readAttr( "xlink:href" ); } @@ -185,22 +185,67 @@ static void sp_feImage_set(SPObject *object, unsigned int key, gchar const *valu } break; - case SP_ATTR_X: - feImage->x.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_Y: - feImage->y.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_WIDTH: - feImage->width.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - case SP_ATTR_HEIGHT: - feImage->height.readOrUnset(value); - object->requestModified(SP_OBJECT_MODIFIED_FLAG); + case SP_ATTR_PRESERVEASPECTRATIO: + /* Copied from sp-image.cpp */ + /* Do setup before, so we can use break to escape */ + feImage->aspect_align = SP_ASPECT_XMID_YMID; // Default + feImage->aspect_clip = SP_ASPECT_MEET; // Default + object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); + if (value) { + int len; + gchar c[256]; + const gchar *p, *e; + unsigned int align, clip; + p = value; + while (*p && *p == 32) p += 1; + if (!*p) break; + e = p; + while (*e && *e != 32) e += 1; + len = e - p; + if (len > 8) break; + memcpy (c, value, len); + c[len] = 0; + /* Now the actual part */ + if (!strcmp (c, "none")) { + align = SP_ASPECT_NONE; + } else if (!strcmp (c, "xMinYMin")) { + align = SP_ASPECT_XMIN_YMIN; + } else if (!strcmp (c, "xMidYMin")) { + align = SP_ASPECT_XMID_YMIN; + } else if (!strcmp (c, "xMaxYMin")) { + align = SP_ASPECT_XMAX_YMIN; + } else if (!strcmp (c, "xMinYMid")) { + align = SP_ASPECT_XMIN_YMID; + } else if (!strcmp (c, "xMidYMid")) { + align = SP_ASPECT_XMID_YMID; + } else if (!strcmp (c, "xMaxYMid")) { + align = SP_ASPECT_XMAX_YMID; + } else if (!strcmp (c, "xMinYMax")) { + align = SP_ASPECT_XMIN_YMAX; + } else if (!strcmp (c, "xMidYMax")) { + align = SP_ASPECT_XMID_YMAX; + } else if (!strcmp (c, "xMaxYMax")) { + align = SP_ASPECT_XMAX_YMAX; + } else { + g_warning("Illegal preserveAspectRatio: %s", c); + break; + } + clip = SP_ASPECT_MEET; + while (*e && *e == 32) e += 1; + if (*e) { + if (!strcmp (e, "meet")) { + clip = SP_ASPECT_MEET; + } else if (!strcmp (e, "slice")) { + clip = SP_ASPECT_SLICE; + } else { + break; + } + } + feImage->aspect_align = align; + feImage->aspect_clip = clip; + } break; + default: if (((SPObjectClass *) feImage_parent_class)->set) ((SPObjectClass *) feImage_parent_class)->set(object, key, value); @@ -234,7 +279,7 @@ static Inkscape::XML::Node * sp_feImage_write(SPObject *object, Inkscape::XML::D /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feImage_parent_class)->write) { @@ -259,7 +304,8 @@ static void sp_feImage_build_renderer(SPFilterPrimitive *primitive, Inkscape::Fi nr_image->from_element = sp_image->from_element; nr_image->SVGElem = sp_image->SVGElem; - nr_image->set_region(sp_image->x, sp_image->y, sp_image->width, sp_image->height); + nr_image->set_align( sp_image->aspect_align ); + nr_image->set_clip( sp_image->aspect_clip ); nr_image->set_href(sp_image->href); nr_image->set_document(sp_image->document); } diff --git a/src/filters/image.h b/src/filters/image.h index a66e6c4c5..b4081602a 100644 --- a/src/filters/image.h +++ b/src/filters/image.h @@ -28,7 +28,11 @@ class SPFeImageClass; struct SPFeImage : public SPFilterPrimitive { gchar *href; - SVGLength x, y, height, width; + + /* preserveAspectRatio */ + unsigned int aspect_align : 4; + unsigned int aspect_clip : 1; + SPDocument *document; bool from_element; SPItem* SVGElem; diff --git a/src/filters/merge.cpp b/src/filters/merge.cpp index dacfb7e91..47830c38b 100644 --- a/src/filters/merge.cpp +++ b/src/filters/merge.cpp @@ -151,7 +151,7 @@ sp_feMerge_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML:: /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it. And child nodes, too! */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } diff --git a/src/filters/mergenode.cpp b/src/filters/mergenode.cpp index f4c4c6089..639928305 100644 --- a/src/filters/mergenode.cpp +++ b/src/filters/mergenode.cpp @@ -151,9 +151,9 @@ sp_feMergeNode_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::X if (flags & SP_OBJECT_WRITE_EXT) { if (repr) { // is this sane? - //repr->mergeFrom(SP_OBJECT_REPR(object), "id"); + //repr->mergeFrom(object->getRepr(), "id"); } else { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } } diff --git a/src/filters/morphology.cpp b/src/filters/morphology.cpp index bbfa97728..42327d59f 100644 --- a/src/filters/morphology.cpp +++ b/src/filters/morphology.cpp @@ -185,7 +185,7 @@ sp_feMorphology_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape:: /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feMorphology_parent_class)->write) { diff --git a/src/filters/offset.cpp b/src/filters/offset.cpp index 360012d3b..f45169aba 100644 --- a/src/filters/offset.cpp +++ b/src/filters/offset.cpp @@ -169,7 +169,7 @@ sp_feOffset_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML: /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feOffset_parent_class)->write) { diff --git a/src/filters/pointlight.cpp b/src/filters/pointlight.cpp index f09449615..ee6824d00 100644 --- a/src/filters/pointlight.cpp +++ b/src/filters/pointlight.cpp @@ -119,9 +119,9 @@ sp_fepointlight_release(SPObject *object) { //SPFePointLight *fepointlight = SP_FEPOINTLIGHT(object); - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("fepointlight", SP_OBJECT(object)); + if ( object->document ) { + // Unregister ourselves + object->document->removeResource("fepointlight", object); } //TODO: release resources here @@ -229,7 +229,7 @@ sp_fepointlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape:: SPFePointLight *fepointlight = SP_FEPOINTLIGHT(object); if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (fepointlight->x_set) diff --git a/src/filters/specularlighting.cpp b/src/filters/specularlighting.cpp index acb986d74..71a705c94 100644 --- a/src/filters/specularlighting.cpp +++ b/src/filters/specularlighting.cpp @@ -276,7 +276,7 @@ sp_feSpecularLighting_write(SPObject *object, Inkscape::XML::Document *doc, Inks /* TODO: Don't just clone, but create a new repr node and write all * relevant values _and children_ into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); //repr = doc->createElement("svg:feSpecularLighting"); } diff --git a/src/filters/spotlight.cpp b/src/filters/spotlight.cpp index 060b3b04d..7be83ed00 100644 --- a/src/filters/spotlight.cpp +++ b/src/filters/spotlight.cpp @@ -134,9 +134,9 @@ sp_fespotlight_release(SPObject *object) { //SPFeSpotLight *fespotlight = SP_FESPOTLIGHT(object); - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("fespotlight", SP_OBJECT(object)); + if ( object->document ) { + // Unregister ourselves + object->document->removeResource("fespotlight", object); } //TODO: release resources here @@ -332,7 +332,7 @@ sp_fespotlight_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::X SPFeSpotLight *fespotlight = SP_FESPOTLIGHT(object); if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (fespotlight->x_set) diff --git a/src/filters/tile.cpp b/src/filters/tile.cpp index d4e4ac890..c3555ee7c 100644 --- a/src/filters/tile.cpp +++ b/src/filters/tile.cpp @@ -151,7 +151,7 @@ sp_feTile_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::N /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feTile_parent_class)->write) { diff --git a/src/filters/turbulence.cpp b/src/filters/turbulence.cpp index 739001311..9d1448c70 100644 --- a/src/filters/turbulence.cpp +++ b/src/filters/turbulence.cpp @@ -234,7 +234,7 @@ sp_feTurbulence_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape:: /* TODO: Don't just clone, but create a new repr node and write all * relevant values into it */ if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } if (((SPObjectClass *) feTurbulence_parent_class)->write) { diff --git a/src/flood-context.cpp b/src/flood-context.cpp index f8eec0a19..73e82607a 100644 --- a/src/flood-context.cpp +++ b/src/flood-context.cpp @@ -398,7 +398,7 @@ inline static bool check_if_pixel_is_paintable(guchar *px, unsigned char *trace_ * \param transform The transform to apply to the final SVG path. * \param union_with_selection If true, merge the final SVG path with the current selection. */ -static void do_trace(bitmap_coords_info bci, guchar *trace_px, SPDesktop *desktop, Geom::Matrix transform, unsigned int min_x, unsigned int max_x, unsigned int min_y, unsigned int max_y, bool union_with_selection) { +static void do_trace(bitmap_coords_info bci, guchar *trace_px, SPDesktop *desktop, Geom::Affine transform, unsigned int min_x, unsigned int max_x, unsigned int min_y, unsigned int max_y, bool union_with_selection) { SPDocument *document = sp_desktop_document(desktop); unsigned char *trace_t; @@ -493,10 +493,10 @@ static void do_trace(bitmap_coords_info bci, guchar *trace_px, SPDesktop *deskto SP_ITEM(reprobj)->doWriteTransform(pathRepr, transform, NULL); // premultiply the item transform by the accumulated parent transform in the paste layer - Geom::Matrix local (SP_GROUP(desktop->currentLayer())->i2doc_affine()); + Geom::Affine local (SP_GROUP(desktop->currentLayer())->i2doc_affine()); if (!local.isIdentity()) { gchar const *t_str = pathRepr->attribute("transform"); - Geom::Matrix item_t (Geom::identity()); + Geom::Affine item_t (Geom::identity()); if (t_str) sp_svg_transform_read(t_str, &item_t); item_t *= local.inverse(); @@ -809,7 +809,7 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even origin[Geom::Y] = origin[Geom::Y] + (screen.height() * ((1 - padding) / 2)); Geom::Scale scale(zoom_scale, zoom_scale); - Geom::Matrix affine = scale * Geom::Translate(-origin * scale); + Geom::Affine affine = scale * Geom::Translate(-origin * scale); /* Create ArenaItems and set transform */ NRArenaItem *root = SP_ITEM(document->getRoot())->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); @@ -1108,7 +1108,7 @@ static void sp_flood_do_flood_fill(SPEventContext *event_context, GdkEvent *even Geom::Point min_start = Geom::Point(min_x, min_y); affine = scale * Geom::Translate(-origin * scale - min_start); - Geom::Matrix inverted_affine = Geom::Matrix(affine).inverse(); + Geom::Affine inverted_affine = Geom::Affine(affine).inverse(); do_trace(bci, trace_px, desktop, inverted_affine, min_x, max_x, min_y, max_y, union_with_selection); diff --git a/src/flood-context.h b/src/flood-context.h index af537dea0..d9da96010 100644 --- a/src/flood-context.h +++ b/src/flood-context.h @@ -11,6 +11,7 @@ * Released under GNU GPL */ +#include <stddef.h> #include <sigc++/sigc++.h> #include <gtk/gtk.h> #include "event-context.h" diff --git a/src/gc-alloc.h b/src/gc-alloc.h index a552ff6d2..ba672ae2c 100644 --- a/src/gc-alloc.h +++ b/src/gc-alloc.h @@ -16,6 +16,7 @@ #define SEEN_INKSCAPE_GC_ALLOC_H #include <limits> +#include <cstddef> #include "gc-core.h" namespace Inkscape { diff --git a/src/gc-finalized.h b/src/gc-finalized.h index 4e09d6f8b..814a2af18 100644 --- a/src/gc-finalized.h +++ b/src/gc-finalized.h @@ -17,6 +17,7 @@ #define SEEN_INKSCAPE_GC_FINALIZED_H #include <new> +#include <cstddef> #include "gc-core.h" namespace Inkscape { diff --git a/src/gc.cpp b/src/gc.cpp index 97350daff..6b904c05f 100644 --- a/src/gc.cpp +++ b/src/gc.cpp @@ -16,6 +16,7 @@ #include <glib/gmessages.h> #include <sigc++/functors/ptr_fun.h> #include <glibmm/main.h> +#include <cstddef> namespace Inkscape { namespace GC { diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index 03c10768d..8cbd88eb6 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -78,9 +78,9 @@ SPGradient *sp_gradient_ensure_vector_normalized(SPGradient *gr) /* If gr hrefs some other gradient, remove the href */ if (gr->ref->getObject()) { - /* We are hrefing someone, so require flattening */ - SP_OBJECT(gr)->updateRepr(SP_OBJECT_WRITE_EXT | SP_OBJECT_WRITE_ALL); - sp_gradient_repr_set_link(SP_OBJECT_REPR(gr), NULL); + // We are hrefing someone, so require flattening + gr->updateRepr(SP_OBJECT_WRITE_EXT | SP_OBJECT_WRITE_ALL); + sp_gradient_repr_set_link(gr->getRepr(), NULL); } /* Everything is OK, set state flag */ @@ -121,7 +121,7 @@ static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGr sp_gradient_repr_set_link(repr, vector); /* Append the new private gradient to defs */ - SP_OBJECT_REPR(defs)->appendChild(repr); + defs->getRepr()->appendChild(repr); Inkscape::GC::release(repr); // get corresponding object @@ -142,7 +142,7 @@ guint count_gradient_hrefs(SPObject *o, SPGradient *gr) guint i = 0; - SPStyle *style = SP_OBJECT_STYLE(o); + SPStyle *style = o->style; if (style && style->fill.isPaintserver() && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) @@ -190,7 +190,7 @@ SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *ve // texts. SPObject *user = o; while (SP_IS_TSPAN(user)) { - user = SP_OBJECT_PARENT(user); + user = user->parent; } // Check the number of uses of the gradient within this object; @@ -199,17 +199,17 @@ SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *ve // check vector if ( gr != vector && gr->ref->getObject() != vector ) { /* our href is not the vector, and vector is different from gr; relink */ - sp_gradient_repr_set_link(SP_OBJECT_REPR(gr), vector); + sp_gradient_repr_set_link(gr->getRepr(), vector); } return gr; } - SPDocument *doc = SP_OBJECT_DOCUMENT(gr); + SPDocument *doc = gr->document; SPObject *defs = SP_DOCUMENT_DEFS(doc); if ((gr->hasStops()) || (gr->state != SP_GRADIENT_STATE_UNKNOWN) || - (SP_OBJECT_PARENT(gr) != SP_OBJECT(defs)) || + (gr->parent != SP_OBJECT(defs)) || (gr->hrefcount > 1)) { // we have to clone a fresh new private gradient for the given vector @@ -217,8 +217,8 @@ SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *ve SPGradient *gr_new = sp_gradient_get_private_normalized(doc, vector, type); // copy all the attributes to it - Inkscape::XML::Node *repr_new = SP_OBJECT_REPR(gr_new); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr); + Inkscape::XML::Node *repr_new = gr_new->getRepr(); + Inkscape::XML::Node *repr = gr->getRepr(); repr_new->setAttribute("gradientUnits", repr->attribute("gradientUnits")); repr_new->setAttribute("gradientTransform", repr->attribute("gradientTransform")); repr_new->setAttribute("spreadMethod", repr->attribute("spreadMethod")); @@ -252,11 +252,11 @@ SPGradient *sp_gradient_fork_vector_if_necessary(SPGradient *gr) return gr; if (gr->hrefcount > 1) { - SPDocument *doc = SP_OBJECT_DOCUMENT(gr); + SPDocument *doc = gr->document; Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *repr = SP_OBJECT_REPR (gr)->duplicate(xml_doc); - SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL); + Inkscape::XML::Node *repr = gr->getRepr()->duplicate(xml_doc); + SP_DOCUMENT_DEFS(doc)->getRepr()->addChild(repr, NULL); SPGradient *gr_new = (SPGradient *) doc->getObjectByRepr(repr); gr_new = sp_gradient_ensure_vector_normalized (gr_new); Inkscape::GC::release(repr); @@ -276,7 +276,7 @@ SPGradient *sp_gradient_get_forked_vector_if_necessary(SPGradient *gradient, boo SPGradient *vector = gradient->getVector(force_vector); vector = sp_gradient_fork_vector_if_necessary (vector); if ( gradient != vector && gradient->ref->getObject() != vector ) { - sp_gradient_repr_set_link(SP_OBJECT_REPR(gradient), vector); + sp_gradient_repr_set_link(gradient->getRepr(), vector); } return vector; } @@ -292,10 +292,10 @@ SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item) #ifdef SP_GR_VERBOSE g_message("sp_gradient_reset_to_userspace(%p, %p)", gr, item); #endif - Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr); + Inkscape::XML::Node *repr = gr->getRepr(); // calculate the bbox of the item - SP_OBJECT_DOCUMENT(item)->ensureUpToDate(); + item->document->ensureUpToDate(); Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine if (!bbox) @@ -314,14 +314,14 @@ SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item) sp_repr_set_svg_double(repr, "r", width/2); // we want it to be elliptic, not circular - Geom::Matrix squeeze = Geom::Translate (-center) * + Geom::Affine squeeze = Geom::Translate (-center) * Geom::Scale(1, height/width) * Geom::Translate (center); gr->gradientTransform = squeeze; { gchar *c=sp_svg_transform_write(gr->gradientTransform); - SP_OBJECT_REPR(gr)->setAttribute("gradientTransform", c); + gr->getRepr()->setAttribute("gradientTransform", c); g_free(c); } } else { @@ -354,18 +354,18 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar // First, fork it if it is shared gr = sp_gradient_fork_private_if_necessary(gr, gr->getVector(), - SP_IS_RADIALGRADIENT(gr) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, SP_OBJECT(item)); + SP_IS_RADIALGRADIENT(gr) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, item); if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr); + Inkscape::XML::Node *repr = gr->getRepr(); // calculate the bbox of the item - SP_OBJECT_DOCUMENT(item)->ensureUpToDate(); - Geom::Matrix bbox2user; + item->document->ensureUpToDate(); + Geom::Affine bbox2user; Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine if ( bbox ) { - bbox2user = Geom::Matrix(bbox->dimensions()[Geom::X], 0, + bbox2user = Geom::Affine(bbox->dimensions()[Geom::X], 0, 0, bbox->dimensions()[Geom::Y], bbox->min()[Geom::X], bbox->min()[Geom::Y]); } else { @@ -387,7 +387,7 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar * gradient vector in user space due to application of the non-uniform scaling * transformation from bounding box space to user space. */ - Geom::Matrix skew = bbox2user; + Geom::Affine skew = bbox2user; double exp = skew.descrim(); skew[0] /= exp; skew[1] /= exp; @@ -400,13 +400,13 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar gr->gradientTransform = skew; { gchar *c=sp_svg_transform_write(gr->gradientTransform); - SP_OBJECT_REPR(gr)->setAttribute("gradientTransform", c); + gr->getRepr()->setAttribute("gradientTransform", c); g_free(c); } // Matrix to convert points to userspace coords; postmultiply by inverse of skew so // as to cancel it out when it's applied to the gradient during rendering - Geom::Matrix point_convert = bbox2user * skew.inverse(); + Geom::Affine point_convert = bbox2user * skew.inverse(); if (SP_IS_RADIALGRADIENT(gr)) { SPRadialGradient *rg = SP_RADIALGRADIENT(gr); @@ -451,15 +451,16 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar // from sp_item_adjust_paint_recursive); however text and all its children should all // refer to one gradient, hence the recursive call for text (because we can't/don't // want to access tspans and set gradients on them separately) - if (SP_IS_TEXT(item)) - sp_style_set_property_url(SP_OBJECT(item), property, SP_OBJECT(gr), true); - else - sp_style_set_property_url(SP_OBJECT(item), property, SP_OBJECT(gr), false); + if (SP_IS_TEXT(item)) { + sp_style_set_property_url(item, property, gr, true); + } else { + sp_style_set_property_url(item, property, gr, false); + } return gr; } -void sp_gradient_transform_multiply(SPGradient *gradient, Geom::Matrix postmul, bool set) +void sp_gradient_transform_multiply(SPGradient *gradient, Geom::Affine postmul, bool set) { #ifdef SP_GR_VERBOSE g_message("sp_gradient_transform_multiply(%p, , %d)", gradient, set); @@ -472,7 +473,7 @@ void sp_gradient_transform_multiply(SPGradient *gradient, Geom::Matrix postmul, gradient->gradientTransform_set = TRUE; gchar *c=sp_svg_transform_write(gradient->gradientTransform); - SP_OBJECT_REPR(gradient)->setAttribute("gradientTransform", c); + gradient->getRepr()->setAttribute("gradientTransform", c); g_free(c); } @@ -546,12 +547,12 @@ SPStop *sp_vector_add_stop(SPGradient *vector, SPStop* prev_stop, SPStop* next_s #endif Inkscape::XML::Node *new_stop_repr = NULL; - new_stop_repr = SP_OBJECT_REPR(prev_stop)->duplicate(SP_OBJECT_REPR(vector)->document()); - SP_OBJECT_REPR(vector)->addChild(new_stop_repr, SP_OBJECT_REPR(prev_stop)); + new_stop_repr = prev_stop->getRepr()->duplicate(vector->getRepr()->document()); + vector->getRepr()->addChild(new_stop_repr, prev_stop->getRepr()); - SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(vector)->getObjectByRepr(new_stop_repr); + SPStop *newstop = reinterpret_cast<SPStop *>(vector->document->getObjectByRepr(new_stop_repr)); newstop->offset = offset; - sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)offset); + sp_repr_set_css_double( newstop->getRepr(), "offset", (double)offset); guint32 const c1 = sp_stop_get_rgba32(prev_stop); guint32 const c2 = sp_stop_get_rgba32(next_stop); guint32 cnew = average_color (c1, c2, (offset - prev_stop->offset) / (next_stop->offset - prev_stop->offset)); @@ -560,7 +561,7 @@ SPStop *sp_vector_add_stop(SPGradient *vector, SPStop* prev_stop, SPStop* next_s sp_svg_write_color (c, sizeof(c), cnew); gdouble opacity = (gdouble) SP_RGBA32_A_F (cnew); os << "stop-color:" << c << ";stop-opacity:" << opacity <<";"; - SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str()); + newstop->getRepr()->setAttribute("style", os.str().c_str()); Inkscape::GC::release(new_stop_repr); return newstop; @@ -675,7 +676,7 @@ void sp_item_gradient_stop_set_style(SPItem *item, guint point_type, guint point vector = sp_gradient_fork_vector_if_necessary (vector); if ( gradient != vector && gradient->ref->getObject() != vector ) { - sp_gradient_repr_set_link(SP_OBJECT_REPR(gradient), vector); + sp_gradient_repr_set_link(gradient->getRepr(), vector); } switch (point_type) { @@ -685,7 +686,7 @@ void sp_item_gradient_stop_set_style(SPItem *item, guint point_type, guint point { SPStop *first = vector->getFirstStop(); if (first) { - sp_repr_css_change (SP_OBJECT_REPR (first), stop, "style"); + sp_repr_css_change(first->getRepr(), stop, "style"); } } break; @@ -696,7 +697,7 @@ void sp_item_gradient_stop_set_style(SPItem *item, guint point_type, guint point { SPStop *last = sp_last_stop (vector); if (last) { - sp_repr_css_change (SP_OBJECT_REPR (last), stop, "style"); + sp_repr_css_change(last->getRepr(), stop, "style"); } } break; @@ -707,7 +708,7 @@ void sp_item_gradient_stop_set_style(SPItem *item, guint point_type, guint point { SPStop *stopi = sp_get_stop_i (vector, point_i); if (stopi) { - sp_repr_css_change (SP_OBJECT_REPR (stopi), stop, "style"); + sp_repr_css_change(stopi->getRepr(), stop, "style"); } } break; @@ -732,22 +733,22 @@ void sp_item_gradient_reverse_vector(SPItem *item, bool fill_or_stroke) vector = sp_gradient_fork_vector_if_necessary (vector); if ( gradient != vector && gradient->ref->getObject() != vector ) { - sp_gradient_repr_set_link(SP_OBJECT_REPR(gradient), vector); + sp_gradient_repr_set_link(gradient->getRepr(), vector); } GSList *child_reprs = NULL; GSList *child_objects = NULL; std::vector<double> offsets; for ( SPObject *child = vector->firstChild(); child; child = child->getNext()) { - child_reprs = g_slist_prepend (child_reprs, SP_OBJECT_REPR(child)); + child_reprs = g_slist_prepend (child_reprs, child->getRepr()); child_objects = g_slist_prepend (child_objects, child); - offsets.push_back(sp_repr_get_double_attribute(SP_OBJECT_REPR(child), "offset", 0)); + offsets.push_back(sp_repr_get_double_attribute(child->getRepr(), "offset", 0)); } GSList *child_copies = NULL; for (GSList *i = child_reprs; i != NULL; i = i->next) { Inkscape::XML::Node *repr = (Inkscape::XML::Node *) i->data; - Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(vector)->document(); + Inkscape::XML::Document *xml_doc = vector->getRepr()->document(); child_copies = g_slist_append (child_copies, repr->duplicate(xml_doc)); } @@ -788,12 +789,12 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, gradient = sp_gradient_convert_to_userspace (gradient, item, fill_or_stroke? "fill" : "stroke"); - Geom::Matrix i2d (item->i2d_affine ()); + Geom::Affine i2d (item->i2d_affine ()); Geom::Point p = p_w * i2d.inverse(); p *= (gradient->gradientTransform).inverse(); // now p is in gradient's original coordinates - Inkscape::XML::Node *repr = SP_OBJECT_REPR(gradient); + Inkscape::XML::Node *repr = gradient->getRepr(); if (SP_IS_LINEARGRADIENT(gradient)) { SPLinearGradient *lg = SP_LINEARGRADIENT(gradient); @@ -813,7 +814,7 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, sp_repr_set_svg_double(repr, "x1", lg->x1.computed); sp_repr_set_svg_double(repr, "y1", lg->y1.computed); } else { - SP_OBJECT (gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG); + gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case POINT_LG_END: @@ -831,7 +832,7 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, sp_repr_set_svg_double(repr, "x2", lg->x2.computed); sp_repr_set_svg_double(repr, "y2", lg->y2.computed); } else { - SP_OBJECT (gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG); + gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case POINT_LG_MID: @@ -844,9 +845,9 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, SPStop* stopi = sp_get_stop_i(vector, point_i); stopi->offset = offset; if (write_repr) { - sp_repr_set_css_double(SP_OBJECT_REPR(stopi), "offset", stopi->offset); + sp_repr_set_css_double(stopi->getRepr(), "offset", stopi->offset); } else { - SP_OBJECT (stopi)->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + stopi->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } } break; @@ -861,7 +862,7 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, // prevent setting a radius too close to the center return; } - Geom::Matrix new_transform; + Geom::Affine new_transform; bool transform_set = false; switch (point_type) { @@ -876,7 +877,7 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, sp_repr_set_svg_double(repr, "cx", rg->cx.computed); sp_repr_set_svg_double(repr, "cy", rg->cy.computed); } else { - SP_OBJECT (gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG); + gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case POINT_RG_FOCUS: @@ -886,7 +887,7 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, sp_repr_set_svg_double(repr, "fx", rg->fx.computed); sp_repr_set_svg_double(repr, "fy", rg->fy.computed); } else { - SP_OBJECT (gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG); + gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; case POINT_RG_R1: @@ -896,12 +897,12 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, double move_angle = Geom::atan2(p_w - c_w) - r1_angle; double move_stretch = Geom::L2(p_w - c_w) / Geom::L2(r1_w - c_w); - Geom::Matrix move = Geom::Matrix (Geom::Translate (-c_w)) * - Geom::Matrix (Geom::Rotate(-r1_angle)) * - Geom::Matrix (Geom::Scale(move_stretch, scale? move_stretch : 1)) * - Geom::Matrix (Geom::Rotate(r1_angle)) * - Geom::Matrix (Geom::Rotate(move_angle)) * - Geom::Matrix (Geom::Translate (c_w)); + Geom::Affine move = Geom::Affine (Geom::Translate (-c_w)) * + Geom::Affine (Geom::Rotate(-r1_angle)) * + Geom::Affine (Geom::Scale(move_stretch, scale? move_stretch : 1)) * + Geom::Affine (Geom::Rotate(r1_angle)) * + Geom::Affine (Geom::Rotate(move_angle)) * + Geom::Affine (Geom::Translate (c_w)); new_transform = gradient->gradientTransform * i2d * move * i2d.inverse(); transform_set = true; @@ -915,12 +916,12 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, double move_angle = Geom::atan2(p_w - c_w) - r2_angle; double move_stretch = Geom::L2(p_w - c_w) / Geom::L2(r2_w - c_w); - Geom::Matrix move = Geom::Matrix (Geom::Translate (-c_w)) * - Geom::Matrix (Geom::Rotate(-r2_angle)) * - Geom::Matrix (Geom::Scale(move_stretch, scale? move_stretch : 1)) * - Geom::Matrix (Geom::Rotate(r2_angle)) * - Geom::Matrix (Geom::Rotate(move_angle)) * - Geom::Matrix (Geom::Translate (c_w)); + Geom::Affine move = Geom::Affine (Geom::Translate (-c_w)) * + Geom::Affine (Geom::Rotate(-r2_angle)) * + Geom::Affine (Geom::Scale(move_stretch, scale? move_stretch : 1)) * + Geom::Affine (Geom::Rotate(r2_angle)) * + Geom::Affine (Geom::Rotate(move_angle)) * + Geom::Affine (Geom::Translate (c_w)); new_transform = gradient->gradientTransform * i2d * move * i2d.inverse(); transform_set = true; @@ -938,9 +939,9 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, SPStop* stopi = sp_get_stop_i(vector, point_i); stopi->offset = offset; if (write_repr) { - sp_repr_set_css_double(SP_OBJECT_REPR(stopi), "offset", stopi->offset); + sp_repr_set_css_double(stopi->getRepr(), "offset", stopi->offset); } else { - SP_OBJECT (stopi)->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + stopi->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } break; } @@ -954,9 +955,9 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, SPStop* stopi = sp_get_stop_i(vector, point_i); stopi->offset = offset; if (write_repr) { - sp_repr_set_css_double(SP_OBJECT_REPR(stopi), "offset", stopi->offset); + sp_repr_set_css_double(stopi->getRepr(), "offset", stopi->offset); } else { - SP_OBJECT (stopi)->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + stopi->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); } break; } @@ -966,10 +967,10 @@ void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, gradient->gradientTransform_set = TRUE; if (write_repr) { gchar *s=sp_svg_transform_write(gradient->gradientTransform); - SP_OBJECT_REPR(gradient)->setAttribute("gradientTransform", s); + gradient->getRepr()->setAttribute("gradientTransform", s); g_free(s); } else { - SP_OBJECT (gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG); + gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); } } } @@ -1061,15 +1062,15 @@ Geom::Point sp_item_gradient_get_coords(SPItem *item, guint point_type, guint po } if (SP_GRADIENT(gradient)->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { - SP_OBJECT_DOCUMENT(item)->ensureUpToDate(); + item->document->ensureUpToDate(); Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine if (bbox) { - p *= Geom::Matrix(bbox->dimensions()[Geom::X], 0, + p *= Geom::Affine(bbox->dimensions()[Geom::X], 0, 0, bbox->dimensions()[Geom::Y], bbox->min()[Geom::X], bbox->min()[Geom::Y]); } } - p *= Geom::Matrix(gradient->gradientTransform) * (Geom::Matrix)item->i2d_affine(); + p *= Geom::Affine(gradient->gradientTransform) * (Geom::Affine)item->i2d_affine(); return from_2geom(p); } @@ -1091,7 +1092,7 @@ SPGradient *sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType ty g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL); g_return_val_if_fail(gr->state == SP_GRADIENT_STATE_VECTOR, NULL); - SPStyle *style = SP_OBJECT_STYLE(item); + SPStyle *style = item->style; g_assert(style != NULL); SPPaintServer *ps = NULL; @@ -1106,20 +1107,20 @@ SPGradient *sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType ty /* Current fill style is the gradient of the required type */ SPGradient *current = SP_GRADIENT(ps); - //g_message("hrefcount %d count %d\n", current->hrefcount, count_gradient_hrefs(SP_OBJECT(item), current)); + //g_message("hrefcount %d count %d\n", current->hrefcount, count_gradient_hrefs(item, current)); if (!current->isSwatch() && (current->hrefcount == 1 || - current->hrefcount == count_gradient_hrefs(SP_OBJECT(item), current))) { + current->hrefcount == count_gradient_hrefs(item, current))) { // current is private and it's either used once, or all its uses are by children of item; // so just change its href to vector if ( current != gr && current->getVector() != gr ) { - /* href is not the vector */ - sp_gradient_repr_set_link(SP_OBJECT_REPR(current), gr); + // href is not the vector + sp_gradient_repr_set_link(current->getRepr(), gr); } - SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); return current; } else { @@ -1134,19 +1135,19 @@ SPGradient *sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType ty /* We have to change object style here; recursive because this is used from * fill&stroke and must work for groups etc. */ - sp_style_set_property_url(SP_OBJECT(item), is_fill? "fill" : "stroke", SP_OBJECT(normalized), true); + sp_style_set_property_url(item, is_fill? "fill" : "stroke", normalized, true); } - SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); return normalized; } } else { /* Current fill style is not a gradient or wrong type, so construct everything */ - SPGradient *constructed = sp_gradient_get_private_normalized(SP_OBJECT_DOCUMENT(item), gr, type); + SPGradient *constructed = sp_gradient_get_private_normalized(item->document, gr, type); constructed = sp_gradient_reset_to_userspace(constructed, item); - sp_style_set_property_url(SP_OBJECT(item), ( is_fill ? "fill" : "stroke" ), SP_OBJECT(constructed), true); - SP_OBJECT(item)->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG | - SP_OBJECT_STYLE_MODIFIED_FLAG )); + sp_style_set_property_url(item, ( is_fill ? "fill" : "stroke" ), constructed, true); + item->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG | + SP_OBJECT_STYLE_MODIFIED_FLAG )); return constructed; } } @@ -1213,7 +1214,7 @@ SPGradient *sp_document_default_gradient_vector( SPDocument *document, SPColor c addStop( repr, colorStr, 0, "1" ); } - SP_OBJECT_REPR(defs)->addChild(repr, NULL); + defs->getRepr()->addChild(repr, NULL); Inkscape::GC::release(repr); /* fixme: This does not look like nice */ @@ -1234,11 +1235,11 @@ SPGradient *sp_gradient_vector_for_object( SPDocument *const doc, SPDesktop *con SPObject *const o, bool const is_fill, bool singleStop ) { SPColor color; - if (o == NULL || SP_OBJECT_STYLE(o) == NULL) { + if ( (o == NULL) || (o->style == NULL) ) { color = sp_desktop_get_color(desktop, is_fill); } else { // take the color of the object - SPStyle const &style = *SP_OBJECT_STYLE(o); + SPStyle const &style = *(o->style); SPIPaint const &paint = ( is_fill ? style.fill : style.stroke ); diff --git a/src/gradient-chemistry.h b/src/gradient-chemistry.h index 5e4a7b337..e0d9a1f46 100644 --- a/src/gradient-chemistry.h +++ b/src/gradient-chemistry.h @@ -64,7 +64,7 @@ guint32 average_color (guint32 c1, guint32 c2, gdouble p = 0.5); SPStop *sp_vector_add_stop (SPGradient *vector, SPStop* prev_stop, SPStop* next_stop, gfloat offset); -void sp_gradient_transform_multiply (SPGradient *gradient, Geom::Matrix postmul, bool set); +void sp_gradient_transform_multiply (SPGradient *gradient, Geom::Affine postmul, bool set); SPGradient * sp_item_gradient (SPItem *item, bool fill_or_stroke); void sp_item_gradient_set_coords (SPItem *item, guint point_type, guint point_i, Geom::Point p_desk, bool fill_or_stroke, bool write_repr, bool scale); diff --git a/src/gradient-context.cpp b/src/gradient-context.cpp index 768370509..bfd1047f1 100644 --- a/src/gradient-context.cpp +++ b/src/gradient-context.cpp @@ -378,9 +378,9 @@ sp_gradient_context_add_stops_between_selected_stops (SPGradientContext *rc) SPStop *this_stop = (SPStop *) i->data; SPStop *next_stop = (SPStop *) j->data; gfloat offset = 0.5*(this_stop->offset + next_stop->offset); - SPObject *parent = SP_OBJECT_PARENT(this_stop); + SPObject *parent = this_stop->parent; if (SP_IS_GRADIENT (parent)) { - doc = SP_OBJECT_DOCUMENT (parent); + doc = parent->document; sp_vector_add_stop (SP_GRADIENT (parent), this_stop, next_stop, offset); SP_GRADIENT(parent)->ensureVector(); } @@ -449,9 +449,9 @@ sp_gradient_simplify(SPGradientContext *rc, double tolerance) for (i = todel; i != NULL; i = i->next) { SPStop *stop = (SPStop*) i->data; - doc = SP_OBJECT_DOCUMENT (stop); - Inkscape::XML::Node * parent = SP_OBJECT_REPR(stop)->parent(); - parent->removeChild(SP_OBJECT_REPR(stop)); + doc = stop->document; + Inkscape::XML::Node * parent = stop->getRepr()->parent(); + parent->removeChild( stop->getRepr() ); } if (g_slist_length(todel) > 0) { @@ -525,7 +525,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) SPGradientType new_type = (SPGradientType) prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR); guint new_fill = prefs->getInt("/tools/gradient/newfillorstroke", 1); - SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop, SP_OBJECT (item), new_fill); + SPGradient *vector = sp_gradient_vector_for_object(sp_desktop_document(desktop), desktop, item, new_fill); SPGradient *priv = sp_item_set_gradient(item, vector, new_type, new_fill); sp_gradient_reset_to_userspace(priv, item); @@ -903,7 +903,7 @@ static void sp_gradient_drag(SPGradientContext &rc, Geom::Point const pt, guint for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { //FIXME: see above - sp_repr_css_change_recursive(SP_OBJECT_REPR(i->data), css, "style"); + sp_repr_css_change_recursive(SP_OBJECT(i->data)->getRepr(), css, "style"); sp_item_set_gradient(SP_ITEM(i->data), vector, (SPGradientType) type, fill_or_stroke); @@ -914,7 +914,7 @@ static void sp_gradient_drag(SPGradientContext &rc, Geom::Point const pt, guint sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false); sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_R1, 0, pt, fill_or_stroke, true, false); } - SP_OBJECT (i->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); + SP_OBJECT(i->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); } if (ec->_grdrag) { ec->_grdrag->updateDraggers(); diff --git a/src/gradient-context.h b/src/gradient-context.h index 0e1059ee9..3bb9efa15 100644 --- a/src/gradient-context.h +++ b/src/gradient-context.h @@ -15,6 +15,7 @@ * Released under GNU GPL */ +#include <stddef.h> #include <sigc++/sigc++.h> #include "event-context.h" diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 2e9a21acf..8f7effe43 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -25,6 +25,7 @@ #include "selection.h" #include "desktop.h" #include "desktop-style.h" +#include "desktop-handles.h" #include "document.h" #include "display/sp-ctrlline.h" #include "display/sp-canvas-util.h" @@ -449,7 +450,7 @@ GrDrag::dropColor(SPItem */*item*/, gchar const *c, Geom::Point p) SPCSSAttr *css = sp_repr_css_attr_new (); sp_repr_css_set_property( css, "stop-color", stopIsNull ? 0 : toUse.c_str() ); sp_repr_css_set_property( css, "stop-opacity", "1" ); - sp_repr_css_change (SP_OBJECT_REPR (stop), css, "style"); + sp_repr_css_change(stop->getRepr(), css, "style"); return true; } } @@ -959,7 +960,7 @@ gr_knot_clicked_handler(SPKnot */*knot*/, guint state, gpointer data) SPStop *next = stop->getNextStop(); if (next) { next->offset = 0; - sp_repr_set_css_double (SP_OBJECT_REPR (next), "offset", 0); + sp_repr_set_css_double(next->getRepr(), "offset", 0); } } break; @@ -971,7 +972,7 @@ gr_knot_clicked_handler(SPKnot */*knot*/, guint state, gpointer data) SPStop *prev = stop->getPrevStop(); if (prev) { prev->offset = 1; - sp_repr_set_css_double (SP_OBJECT_REPR (prev), "offset", 1); + sp_repr_set_css_double(prev->getRepr(), "offset", 1); } } break; @@ -982,8 +983,8 @@ gr_knot_clicked_handler(SPKnot */*knot*/, guint state, gpointer data) break; } - SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop)); - DocumentUndo::done(SP_OBJECT_DOCUMENT (gradient), SP_VERB_CONTEXT_GRADIENT, + gradient->getRepr()->removeChild(stop->getRepr()); + DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT, _("Delete gradient stop")); } } else { @@ -1744,7 +1745,7 @@ GrDrag::updateLines () SPItem *item = SP_ITEM(i->data); - SPStyle *style = SP_OBJECT_STYLE (item); + SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { SPPaintServer *server = item->style->getFillPaintServer(); @@ -2037,14 +2038,14 @@ GrDrag::deleteSelected (bool just_one) } while (midstoplist) { SPStop *stop = (SPStop*) midstoplist->data; - document = SP_OBJECT_DOCUMENT (stop); - Inkscape::XML::Node * parent = SP_OBJECT_REPR(stop)->parent(); - parent->removeChild(SP_OBJECT_REPR(stop)); + document = stop->document; + Inkscape::XML::Node * parent = stop->getRepr()->parent(); + parent->removeChild(stop->getRepr()); midstoplist = g_slist_remove(midstoplist, stop); } while (endstoplist) { StructStopInfo *stopinfo = (StructStopInfo*) endstoplist->data; - document = SP_OBJECT_DOCUMENT (stopinfo->spstop); + document = stopinfo->spstop->document; // 2 is the minimum, cannot delete more than that without deleting the whole vector // cannot use vector->vector.stops.size() because the vector might be invalidated by deletion of a midstop @@ -2061,7 +2062,7 @@ GrDrag::deleteSelected (bool just_one) switch (stopinfo->draggable->point_type) { case POINT_LG_BEGIN: { - SP_OBJECT_REPR(stopinfo->vector)->removeChild(SP_OBJECT_REPR(stopinfo->spstop)); + stopinfo->vector->getRepr()->removeChild(stopinfo->spstop->getRepr()); SPLinearGradient *lg = SP_LINEARGRADIENT(stopinfo->gradient); Geom::Point oldbegin = Geom::Point (lg->x1.computed, lg->y1.computed); @@ -2072,25 +2073,25 @@ GrDrag::deleteSelected (bool just_one) lg->x1.computed = newbegin[Geom::X]; lg->y1.computed = newbegin[Geom::Y]; - Inkscape::XML::Node *repr = SP_OBJECT_REPR(stopinfo->gradient); + Inkscape::XML::Node *repr = stopinfo->gradient->getRepr(); sp_repr_set_svg_double(repr, "x1", lg->x1.computed); sp_repr_set_svg_double(repr, "y1", lg->y1.computed); stop->offset = 0; - sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", 0); + sp_repr_set_css_double(stop->getRepr(), "offset", 0); // iterate through midstops to set new offset values such that they won't move on canvas. SPStop *laststop = sp_last_stop(stopinfo->vector); stop = stop->getNextStop(); while ( stop != laststop ) { stop->offset = (stop->offset - offset)/(1 - offset); - sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", stop->offset); + sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); stop = stop->getNextStop(); } } break; case POINT_LG_END: { - SP_OBJECT_REPR(stopinfo->vector)->removeChild(SP_OBJECT_REPR(stopinfo->spstop)); + stopinfo->vector->getRepr()->removeChild(stopinfo->spstop->getRepr()); SPLinearGradient *lg = SP_LINEARGRADIENT(stopinfo->gradient); Geom::Point begin = Geom::Point (lg->x1.computed, lg->y1.computed); @@ -2101,18 +2102,18 @@ GrDrag::deleteSelected (bool just_one) lg->x2.computed = newend[Geom::X]; lg->y2.computed = newend[Geom::Y]; - Inkscape::XML::Node *repr = SP_OBJECT_REPR(stopinfo->gradient); + Inkscape::XML::Node *repr = stopinfo->gradient->getRepr(); sp_repr_set_svg_double(repr, "x2", lg->x2.computed); sp_repr_set_svg_double(repr, "y2", lg->y2.computed); laststop->offset = 1; - sp_repr_set_css_double (SP_OBJECT_REPR (laststop), "offset", 1); + sp_repr_set_css_double(laststop->getRepr(), "offset", 1); // iterate through midstops to set new offset values such that they won't move on canvas. SPStop *stop = stopinfo->vector->getFirstStop(); stop = stop->getNextStop(); while ( stop != laststop ) { stop->offset = stop->offset / offset; - sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", stop->offset); + sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); stop = stop->getNextStop(); } } @@ -2122,14 +2123,14 @@ GrDrag::deleteSelected (bool just_one) SPStop *newfirst = stopinfo->spstop->getNextStop(); if (newfirst) { newfirst->offset = 0; - sp_repr_set_css_double (SP_OBJECT_REPR (newfirst), "offset", 0); + sp_repr_set_css_double(newfirst->getRepr(), "offset", 0); } - SP_OBJECT_REPR(stopinfo->vector)->removeChild(SP_OBJECT_REPR(stopinfo->spstop)); + stopinfo->vector->getRepr()->removeChild(stopinfo->spstop->getRepr()); } break; case POINT_RG_R1: case POINT_RG_R2: - SP_OBJECT_REPR(stopinfo->vector)->removeChild(SP_OBJECT_REPR(stopinfo->spstop)); + stopinfo->vector->getRepr()->removeChild(stopinfo->spstop->getRepr()); SPRadialGradient *rg = SP_RADIALGRADIENT(stopinfo->gradient); double oldradius = rg->r.computed; @@ -2138,17 +2139,17 @@ GrDrag::deleteSelected (bool just_one) double newradius = offset * oldradius; rg->r.computed = newradius; - Inkscape::XML::Node *repr = SP_OBJECT_REPR(rg); + Inkscape::XML::Node *repr = rg->getRepr(); sp_repr_set_svg_double(repr, "r", rg->r.computed); laststop->offset = 1; - sp_repr_set_css_double (SP_OBJECT_REPR (laststop), "offset", 1); + sp_repr_set_css_double(laststop->getRepr(), "offset", 1); // iterate through midstops to set new offset values such that they won't move on canvas. SPStop *stop = stopinfo->vector->getFirstStop(); stop = stop->getNextStop(); while ( stop != laststop ) { stop->offset = stop->offset / offset; - sp_repr_set_css_double (SP_OBJECT_REPR (stop), "offset", stop->offset); + sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); stop = stop->getNextStop(); } break; @@ -2159,8 +2160,8 @@ GrDrag::deleteSelected (bool just_one) SPCSSAttr *css = sp_repr_css_attr_new (); // stopinfo->spstop is the selected stop - Inkscape::XML::Node *unselectedrepr = SP_OBJECT_REPR(stopinfo->vector)->firstChild(); - if (unselectedrepr == SP_OBJECT_REPR(stopinfo->spstop) ) { + Inkscape::XML::Node *unselectedrepr = stopinfo->vector->getRepr()->firstChild(); + if (unselectedrepr == stopinfo->spstop->getRepr() ) { unselectedrepr = unselectedrepr->next(); } @@ -2182,7 +2183,7 @@ GrDrag::deleteSelected (bool just_one) sp_repr_css_attr_unref (stopcss); } - sp_repr_css_change (SP_OBJECT_REPR (stopinfo->draggable->item), css, "style"); + sp_repr_css_change(stopinfo->draggable->item->getRepr(), css, "style"); sp_repr_css_attr_unref (css); } diff --git a/src/gradient-drag.h b/src/gradient-drag.h index 8cbe9f305..40ab065ca 100644 --- a/src/gradient-drag.h +++ b/src/gradient-drag.h @@ -15,6 +15,7 @@ */ #include <glib/gslist.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include <vector> diff --git a/src/helper/geom-curves.h b/src/helper/geom-curves.h index f927634d8..5b921e572 100644 --- a/src/helper/geom-curves.h +++ b/src/helper/geom-curves.h @@ -26,17 +26,15 @@ inline bool is_straight_curve(Geom::Curve const & c) { } // the curve can be a quad/cubic bezier, but could still be a perfect straight line // if the control points are exactly on the line connecting the initial and final points. - else if ( Geom::QuadraticBezier const *quad = dynamic_cast<Geom::QuadraticBezier const*>(&c) ) { - Geom::Line line( quad->initialPoint(), quad->finalPoint() ); - if ( are_near((*quad)[1], line) ) { - return true; - } - } - else if ( Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&c) ) { - Geom::Line line( cubic->initialPoint(), cubic->finalPoint() ); - if ( are_near((*cubic)[1], line) && are_near((*cubic)[2], line) ) { - return true; + Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&c); + if (curve) { + Geom::Line line(curve->initialPoint(), curve->finalPoint()); + std::vector<Geom::Point> pts = curve->points(); + for (unsigned i = 1; i < pts.size() - 1; ++i) { + if (!are_near(pts[i], line)) + return false; } + return true; } return false; diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 7b8c5d57f..64aa8bc48 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -38,8 +38,8 @@ cubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y0 { Geom::Coord a, b, c, D; - bbox[0].extendTo(x111); - bbox[1].extendTo(y111); + bbox[0].expandTo(x111); + bbox[1].expandTo(y111); // It already contains (x000,y000) and (x111,y111) // All points of the Bezier lie in the convex hull of (x000,y000), (x001,y001), (x011,y011) and (x111,y111) @@ -81,7 +81,7 @@ cubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y0 if ((s > 0.0) && (s < 1.0)) { t = 1.0 - s; xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111; - bbox[0].extendTo(xttt); + bbox[0].expandTo(xttt); } } } else { @@ -95,13 +95,13 @@ cubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y0 if ((s > 0.0) && (s < 1.0)) { t = 1.0 - s; xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111; - bbox[0].extendTo(xttt); + bbox[0].expandTo(xttt); } s = (-b - d) / (2 * a); if ((s > 0.0) && (s < 1.0)) { t = 1.0 - s; xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111; - bbox[0].extendTo(xttt); + bbox[0].expandTo(xttt); } } } @@ -120,7 +120,7 @@ cubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y0 if ((s > 0.0) && (s < 1.0)) { t = 1.0 - s; yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111; - bbox[1].extendTo(yttt); + bbox[1].expandTo(yttt); } } } else { @@ -134,13 +134,13 @@ cubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y0 if ((s > 0.0) && (s < 1.0)) { t = 1.0 - s; yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111; - bbox[1].extendTo(yttt); + bbox[1].expandTo(yttt); } s = (-b - d) / (2 * a); if ((s > 0.0) && (s < 1.0)) { t = 1.0 - s; yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111; - bbox[1].extendTo(yttt); + bbox[1].expandTo(yttt); } } } @@ -148,14 +148,14 @@ cubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y0 } Geom::OptRect -bounds_fast_transformed(Geom::PathVector const & pv, Geom::Matrix const & t) +bounds_fast_transformed(Geom::PathVector const & pv, Geom::Affine const & t) { return bounds_exact_transformed(pv, t); //use this as it is faster for now! :) // return Geom::bounds_fast(pv * t); } Geom::OptRect -bounds_exact_transformed(Geom::PathVector const & pv, Geom::Matrix const & t) +bounds_exact_transformed(Geom::PathVector const & pv, Geom::Affine const & t) { if (pv.empty()) return Geom::OptRect(); @@ -352,7 +352,7 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000, } static void -geom_curve_bbox_wind_distance(Geom::Curve const & c, Geom::Matrix const &m, +geom_curve_bbox_wind_distance(Geom::Curve const & c, Geom::Affine const &m, Geom::Point const &pt, Geom::Rect *bbox, int *wind, Geom::Coord *dist, Geom::Coord tolerance, Geom::Rect const *viewbox, @@ -415,7 +415,7 @@ geom_curve_bbox_wind_distance(Geom::Curve const & c, Geom::Matrix const &m, Returns bounding box in *bbox if bbox!=NULL. */ void -pathv_matrix_point_bbox_wind_distance (Geom::PathVector const & pathv, Geom::Matrix const &m, Geom::Point const &pt, +pathv_matrix_point_bbox_wind_distance (Geom::PathVector const & pathv, Geom::Affine const &m, Geom::Point const &pt, Geom::Rect *bbox, int *wind, Geom::Coord *dist, Geom::Coord tolerance, Geom::Rect const *viewbox) { @@ -474,15 +474,19 @@ pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ) output.back().close( pit->closed() ); for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { - if( dynamic_cast<Geom::CubicBezier const*>(&*cit) || - is_straight_curve(*cit) ) - { - output.back().append(*cit); - } - else { - // convert all other curve types to cubicbeziers - Geom::Path cubicbezier_path = Geom::cubicbezierpath_from_sbasis(cit->toSBasis(), 0.1); - output.back().append(cubicbezier_path); + if (is_straight_curve(*cit)) { + Geom::LineSegment l(cit->initialPoint(), cit->finalPoint()); + output.back().append(l); + } else { + Geom::BezierCurve const *curve = dynamic_cast<Geom::BezierCurve const *>(&*cit); + if (curve && curve->order() == 3) { + Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); + output.back().append(b); + } else { + // convert all other curve types to cubicbeziers + Geom::Path cubicbezier_path = Geom::cubicbezierpath_from_sbasis(cit->toSBasis(), 0.1); + output.back().append(cubicbezier_path); + } } } } @@ -505,7 +509,7 @@ void round_rectangle_outwards(Geom::Rect & rect) { namespace Geom { -bool transform_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coord const epsilon) { +bool transform_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon) { return NR_DF_TEST_CLOSE(m0[0], m1[0], epsilon) && NR_DF_TEST_CLOSE(m0[1], m1[1], epsilon) && @@ -514,12 +518,12 @@ bool transform_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coor } -bool translate_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coord const epsilon) { +bool translate_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon) { return NR_DF_TEST_CLOSE(m0[4], m1[4], epsilon) && NR_DF_TEST_CLOSE(m0[5], m1[5], epsilon); } -bool matrix_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coord const epsilon) { +bool matrix_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon) { return transform_equalp(m0, m1, epsilon) && translate_equalp(m0, m1, epsilon); } @@ -528,7 +532,7 @@ bool matrix_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coord c The following predefined objects are for reference and comparison. */ -Geom::Matrix GEOM_MATRIX_IDENTITY = Geom::identity(); +Geom::Affine GEOM_MATRIX_IDENTITY = Geom::identity(); /* Local Variables: diff --git a/src/helper/geom.h b/src/helper/geom.h index 73f95794f..b1015b185 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -16,10 +16,10 @@ #include <libnr/nr-forward.h> #include <libnr/nr-coord.h> -Geom::OptRect bounds_fast_transformed(Geom::PathVector const & pv, Geom::Matrix const & t); -Geom::OptRect bounds_exact_transformed(Geom::PathVector const & pv, Geom::Matrix const & t); +Geom::OptRect bounds_fast_transformed(Geom::PathVector const & pv, Geom::Affine const & t); +Geom::OptRect bounds_exact_transformed(Geom::PathVector const & pv, Geom::Affine const & t); -void pathv_matrix_point_bbox_wind_distance ( Geom::PathVector const & pathv, Geom::Matrix const &m, Geom::Point const &pt, +void pathv_matrix_point_bbox_wind_distance ( Geom::PathVector const & pathv, Geom::Affine const &m, Geom::Point const &pt, Geom::Rect *bbox, int *wind, Geom::Coord *dist, Geom::Coord tolerance, Geom::Rect const *viewbox); @@ -31,12 +31,12 @@ void round_rectangle_outwards(Geom::Rect & rect); The following predefined objects are for reference and comparison. They are defined in helper/geom.cpp */ -extern Geom::Matrix GEOM_MATRIX_IDENTITY; +extern Geom::Affine GEOM_MATRIX_IDENTITY; namespace Geom{ -bool transform_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coord const epsilon); -bool translate_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coord const epsilon); -bool matrix_equalp(Geom::Matrix const &m0, Geom::Matrix const &m1, Geom::Coord const epsilon); +bool transform_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); +bool translate_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); +bool matrix_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); } #endif // INKSCAPE_HELPER_GEOM_H diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index b2daa152e..f6796f2ad 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -86,6 +86,19 @@ sp_export_jpg_file(SPDocument *doc, gchar const *filename, else return false; } +/** + generates a bitmap from given items + the bitmap is stored in RAM and not written to file + @param x0 + @param y0 + @param x1 + @param y1 + @param width + @param height + @param xdpi + @param ydpi + @return the created GdkPixbuf structure or NULL if no memory is allocable +*/ GdkPixbuf* sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, double x0, double y0, double x1, double y1, @@ -114,7 +127,7 @@ sp_generate_internal_bitmap(SPDocument *doc, gchar const */*filename*/, origin[Geom::Y] = origin[Geom::Y] + (screen[Geom::Y].extent() * ((1 - padding) / 2)); Geom::Scale scale( (xdpi / PX_PER_IN), (ydpi / PX_PER_IN)); - Geom::Matrix affine = scale * Geom::Translate(-origin * scale); + Geom::Affine affine = scale * Geom::Translate(-origin * scale); /* Create ArenaItems and set transform */ NRArenaItem *root = SP_ITEM(doc->getRoot())->invoke_show( arena, dkey, SP_ITEM_SHOW_DISPLAY); diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 53cc168d2..4667f631b 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -448,7 +448,7 @@ sp_export_png_file(SPDocument *doc, gchar const *filename, * (2) a[5] = -a[3] * y1 */ - Geom::Matrix const affine(Geom::Translate(translation) + Geom::Affine const affine(Geom::Translate(translation) * Geom::Scale(width / area.width(), height / area.height())); diff --git a/src/helper/stock-items.cpp b/src/helper/stock-items.cpp index 4ec61c54a..9f3f172ac 100644 --- a/src/helper/stock-items.cpp +++ b/src/helper/stock-items.cpp @@ -71,8 +71,8 @@ static SPObject * sp_marker_load_from_svg(gchar const *name, SPDocument *current if (object && SP_IS_MARKER(object)) { SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS(current_doc); Inkscape::XML::Document *xml_doc = current_doc->getReprDoc(); - Inkscape::XML::Node *mark_repr = SP_OBJECT_REPR(object)->duplicate(xml_doc); - SP_OBJECT_REPR(defs)->addChild(mark_repr, NULL); + Inkscape::XML::Node *mark_repr = object->getRepr()->duplicate(xml_doc); + defs->getRepr()->addChild(mark_repr, NULL); SPObject *cloned_item = current_doc->getObjectByRepr(mark_repr); Inkscape::GC::release(mark_repr); return cloned_item; @@ -115,8 +115,8 @@ sp_pattern_load_from_svg(gchar const *name, SPDocument *current_doc) if (object && SP_IS_PATTERN(object)) { SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS(current_doc); Inkscape::XML::Document *xml_doc = current_doc->getReprDoc(); - Inkscape::XML::Node *pat_repr = SP_OBJECT_REPR(object)->duplicate(xml_doc); - SP_OBJECT_REPR(defs)->addChild(pat_repr, NULL); + Inkscape::XML::Node *pat_repr = object->getRepr()->duplicate(xml_doc); + defs->getRepr()->addChild(pat_repr, NULL); Inkscape::GC::release(pat_repr); return object; } @@ -158,8 +158,8 @@ sp_gradient_load_from_svg(gchar const *name, SPDocument *current_doc) if (object && SP_IS_GRADIENT(object)) { SPDefs *defs= (SPDefs *) SP_DOCUMENT_DEFS(current_doc); Inkscape::XML::Document *xml_doc = current_doc->getReprDoc(); - Inkscape::XML::Node *pat_repr = SP_OBJECT_REPR(object)->duplicate(xml_doc); - SP_OBJECT_REPR(defs)->addChild(pat_repr, NULL); + Inkscape::XML::Node *pat_repr = object->getRepr()->duplicate(xml_doc); + defs->getRepr()->addChild(pat_repr, NULL); Inkscape::GC::release(pat_repr); return object; } @@ -201,8 +201,8 @@ SPObject *get_stock_item(gchar const *urn) if (!strcmp(base, "marker")) { for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { - if (SP_OBJECT_REPR(child)->attribute("inkscape:stockid") && - !strcmp(name_p, SP_OBJECT_REPR(child)->attribute("inkscape:stockid")) && + if (child->getRepr()->attribute("inkscape:stockid") && + !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_MARKER(child)) { object = child; @@ -214,7 +214,7 @@ SPObject *get_stock_item(gchar const *urn) for ( SPObject *child = defs->firstChild() ; child; child = child->getNext() ) { if (child->getRepr()->attribute("inkscape:stockid") && - !strcmp(name_p, SP_OBJECT_REPR(child)->attribute("inkscape:stockid")) && + !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_PATTERN(child)) { object = child; @@ -225,8 +225,8 @@ SPObject *get_stock_item(gchar const *urn) else if (!strcmp(base,"gradient")) { for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { - if (SP_OBJECT_REPR(child)->attribute("inkscape:stockid") && - !strcmp(name_p, SP_OBJECT_REPR(child)->attribute("inkscape:stockid")) && + if (child->getRepr()->attribute("inkscape:stockid") && + !strcmp(name_p, child->getRepr()->attribute("inkscape:stockid")) && SP_IS_GRADIENT(child)) { object = child; diff --git a/src/id-clash.cpp b/src/id-clash.cpp index 0594fe8e6..67e27e2f0 100644 --- a/src/id-clash.cpp +++ b/src/id-clash.cpp @@ -88,8 +88,8 @@ const char* clipboard_properties[] = { static void find_references(SPObject *elem, refmap_type *refmap) { - if (SP_OBJECT_IS_CLONED(elem)) return; - Inkscape::XML::Node *repr_elem = SP_OBJECT_REPR(elem); + if (elem->cloned) return; + Inkscape::XML::Node *repr_elem = elem->getRepr(); if (!repr_elem) return; if (repr_elem->type() != Inkscape::XML::ELEMENT_NODE) return; @@ -124,7 +124,7 @@ find_references(SPObject *elem, refmap_type *refmap) } } - SPStyle *style = SP_OBJECT_STYLE(elem); + SPStyle *style = elem->style; /* check for url(#...) references in 'fill' or 'stroke' */ for (unsigned i = 0; i < NUM_SPIPAINT_PROPERTIES; ++i) { @@ -197,7 +197,7 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, imported_doc->getObjectById(str) == NULL) break; } // Change to the new ID - SP_OBJECT_REPR(elem)->setAttribute("id", new_id.c_str()); + elem->getRepr()->setAttribute("id", new_id.c_str()); // Make a note of this change, if we need to fix up refs to it if (refmap->find(old_id) != refmap->end()) id_changes->push_back(id_changeitem_type(elem, old_id)); @@ -226,27 +226,25 @@ fix_up_refs(const refmap_type *refmap, const id_changelist_type &id_changes) for (it = pos->second.begin(); it != it_end; ++it) { if (it->type == REF_HREF) { gchar *new_uri = g_strdup_printf("#%s", obj->getId()); - SP_OBJECT_REPR(it->elem)->setAttribute(it->attr, new_uri); + it->elem->getRepr()->setAttribute(it->attr, new_uri); g_free(new_uri); - } - else if (it->type == REF_STYLE) { + } else if (it->type == REF_STYLE) { sp_style_set_property_url(it->elem, it->attr, obj, false); - } - else if (it->type == REF_URL) { + } else if (it->type == REF_URL) { gchar *url = g_strdup_printf("url(#%s)", obj->getId()); - SP_OBJECT_REPR(it->elem)->setAttribute(it->attr, url); + it->elem->getRepr()->setAttribute(it->attr, url); g_free(url); - } - else if (it->type == REF_CLIPBOARD) { - SPCSSAttr *style = sp_repr_css_attr(SP_OBJECT_REPR(it->elem), "style"); + } else if (it->type == REF_CLIPBOARD) { + SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); gchar *url = g_strdup_printf("url(#%s)", obj->getId()); sp_repr_css_set_property(style, it->attr, url); g_free(url); gchar *style_string = sp_repr_css_write_string(style); - SP_OBJECT_REPR(it->elem)->setAttribute("style", style_string); + it->elem->getRepr()->setAttribute("style", style_string); g_free(style_string); + } else { + g_assert(0); // shouldn't happen } - else g_assert(0); // shouldn't happen } } } diff --git a/src/ink-action.cpp b/src/ink-action.cpp index d8673a3ab..587efdff0 100644 --- a/src/ink-action.cpp +++ b/src/ink-action.cpp @@ -441,9 +441,11 @@ static GtkWidget* ink_toggle_action_create_tool_item( GtkAction* action ) gtk_container_add( GTK_CONTAINER(align), child ); gtk_tool_button_set_icon_widget( button, align ); } else { - gchar *label; - g_object_get (G_OBJECT(action), "short_label", &label, NULL); + gchar *label = 0; + g_object_get( G_OBJECT(action), "short_label", &label, NULL ); gtk_tool_button_set_label( button, label ); + g_free( label ); + label = 0; } } else { // For now trigger a warning but don't do anything else diff --git a/src/inkscape.cpp b/src/inkscape.cpp index 430977567..1007c315a 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -875,23 +875,31 @@ gboolean inkscape_use_gui() * Menus management * */ -bool inkscape_load_menus (Inkscape::Application */*inkscape*/) +bool inkscape_load_menus( Inkscape::Application * inkscape ) { - // TODO fix that fn is being leaked gchar *fn = profile_path(MENUS_FILE); - gchar *menus_xml = NULL; + gchar *menus_xml = 0; gsize len = 0; - if (g_file_get_contents(fn, &menus_xml, &len, NULL)) { + if ( inkscape != inkscape_get_instance() ) { + g_warning("BAD BAD BAD THINGS"); + } + + if ( g_file_get_contents(fn, &menus_xml, &len, NULL) ) { // load the menus_xml file - INKSCAPE->menus = sp_repr_read_mem(menus_xml, len, NULL); + inkscape->menus = sp_repr_read_mem(menus_xml, len, NULL); + g_free(menus_xml); - if (INKSCAPE->menus) { - return true; - } + menus_xml = 0; } - INKSCAPE->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL); - return (INKSCAPE->menus != 0); + g_free(fn); + fn = 0; + + if ( !inkscape->menus ) { + inkscape->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL); + } + + return (inkscape->menus != 0); } diff --git a/src/inkscape.rc b/src/inkscape.rc index 08746aa77..e3e79ffe5 100644 --- a/src/inkscape.rc +++ b/src/inkscape.rc @@ -15,7 +15,7 @@ BEGIN VALUE "FileDescription", "Inkscape" VALUE "FileVersion", "0.48+devel" VALUE "InternalName", "Inkscape" - VALUE "LegalCopyright", "© 2010 Inkscape" + VALUE "LegalCopyright", "© 2011 Inkscape" VALUE "ProductName", "Inkscape" VALUE "ProductVersion", "0.48+devel" END diff --git a/src/inkview.cpp b/src/inkview.cpp index 09adb8c2d..448aa77f1 100644 --- a/src/inkview.cpp +++ b/src/inkview.cpp @@ -325,8 +325,7 @@ main (int argc, const char **argv) (ss.doc)->ensureUpToDate(); ss.view = sp_svg_view_widget_new (ss.doc); (ss.doc)->doUnref (); - sp_svg_view_widget_set_resize (SP_SVG_VIEW_WIDGET (ss.view), FALSE, - (ss.doc)->getWidth (), (ss.doc)->getHeight ()); + SP_SVG_VIEW_WIDGET(ss.view)->setResize( false, ss.doc->getWidth(), ss.doc->getHeight() ); gtk_widget_show (ss.view); gtk_container_add (GTK_CONTAINER (w), ss.view); diff --git a/src/interface.cpp b/src/interface.cpp index 62af21a99..7dcb050ee 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -8,6 +8,7 @@ * Jon A. Cruz <jon@joncruz.org> * Abhishek Sharma * + * Copyright (C) 2010 authors * Copyright (C) 1999-2005 authors * Copyright (C) 2001-2002 Ximian, Inc. * Copyright (C) 2004 David Turner @@ -272,7 +273,9 @@ sp_create_window(SPViewWidget *vw, gboolean editable) win->show(); // needed because the first ACTIVATE_DESKTOP was sent when there was no window yet - inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop); + if ( SP_IS_DESKTOP_WIDGET(vw) ) { + inkscape_reactivate_desktop(SP_DESKTOP_WIDGET(vw)->desktop); + } } void @@ -294,20 +297,16 @@ sp_ui_new_view() /* TODO: not yet working */ /* To be re-enabled (by adding to menu) once it works. */ -void -sp_ui_new_view_preview() +void sp_ui_new_view_preview() { - SPDocument *document; - SPViewWidget *dtw; - - document = SP_ACTIVE_DOCUMENT; - if (!document) return; - - dtw = (SPViewWidget *) sp_svg_view_widget_new(document); - g_return_if_fail(dtw != NULL); - sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(dtw), TRUE, 400.0, 400.0); + SPDocument *document = SP_ACTIVE_DOCUMENT; + if ( document ) { + SPViewWidget *dtw = reinterpret_cast<SPViewWidget *>(sp_svg_view_widget_new(document)); + g_return_if_fail(dtw != NULL); + SP_SVG_VIEW_WIDGET(dtw)->setResize(true, 400.0, 400.0); - sp_create_window(dtw, FALSE); + sp_create_window(dtw, FALSE); + } } /** @@ -641,44 +640,49 @@ static void taskToggled(GtkCheckMenuItem *menuitem, gpointer userData) /** - * \brief Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline) + * \brief Callback function to update the status of the radio buttons in the View -> Display mode menu (Normal, No Filters, Outline) and Color display mode */ static gboolean update_view_menu(GtkWidget *widget, GdkEventExpose */*event*/, gpointer user_data) { - SPAction *action = (SPAction *) user_data; - g_assert(action->id != NULL); + SPAction *action = (SPAction *) user_data; + g_assert(action->id != NULL); - Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view"); + Inkscape::UI::View::View *view = (Inkscape::UI::View::View *) g_object_get_data(G_OBJECT(widget), "view"); SPDesktop *dt = static_cast<SPDesktop*>(view); - Inkscape::RenderMode mode = dt->getMode(); - - bool new_state = false; - if (!strcmp(action->id, "ViewModeNormal")) { - new_state = mode == Inkscape::RENDERMODE_NORMAL; - } else if (!strcmp(action->id, "ViewModeNoFilters")) { - new_state = mode == Inkscape::RENDERMODE_NO_FILTERS; + Inkscape::RenderMode mode = dt->getMode(); + Inkscape::ColorRenderMode colormode = dt->getColorMode(); + + bool new_state = false; + if (!strcmp(action->id, "ViewModeNormal")) { + new_state = mode == Inkscape::RENDERMODE_NORMAL; + } else if (!strcmp(action->id, "ViewModeNoFilters")) { + new_state = mode == Inkscape::RENDERMODE_NO_FILTERS; } else if (!strcmp(action->id, "ViewModeOutline")) { - new_state = mode == Inkscape::RENDERMODE_OUTLINE; - } else if (!strcmp(action->id, "ViewModePrintColorsPreview")) { - new_state = mode == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW; + new_state = mode == Inkscape::RENDERMODE_OUTLINE; + } else if (!strcmp(action->id, "ViewColorModeNormal")) { + new_state = colormode == Inkscape::COLORRENDERMODE_NORMAL; + } else if (!strcmp(action->id, "ViewColorModeGrayscale")) { + new_state = colormode == Inkscape::COLORRENDERMODE_GRAYSCALE; + } else if (!strcmp(action->id, "ViewColorModePrintColorsPreview")) { + new_state = colormode == Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW; } else { - g_warning("update_view_menu does not handle this verb"); + g_warning("update_view_menu does not handle this verb"); + } + + if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated + if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) { + // When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second + // emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled. + // This emission however should not invoke any actions, hence we block it here: + temporarily_block_actions = true; + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), TRUE); + temporarily_block_actions = false; + } } - if (new_state) { //only one of the radio buttons has to be activated; the others will automatically be deactivated - if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) { - // When the GtkMenuItem version of the "activate" signal has been emitted by a GtkRadioMenuItem, there is a second - // emission as the most recently active item is toggled to inactive. This is dealt with before the original signal is handled. - // This emission however should not invoke any actions, hence we block it here: - temporarily_block_actions = true; - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), TRUE); - temporarily_block_actions = false; - } - } - - return FALSE; + return FALSE; } void @@ -772,12 +776,20 @@ sp_menu_append_new_templates(GtkWidget *menu, Inkscape::UI::View::View *view) if (dir) { for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) { - if (!g_str_has_suffix(file, ".svg") && !g_str_has_suffix(file, ".svgz")) + if (!g_str_has_suffix(file, ".svg") && !g_str_has_suffix(file, ".svgz")) { continue; // skip non-svg files + } - gchar *basename = g_path_get_basename(file); - if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default.")) - continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already + { + gchar *basename = g_path_get_basename(file); + if (g_str_has_suffix(basename, ".svg") && g_str_has_prefix(basename, "default.")) { + g_free(basename); + basename = 0; + continue; // skip default.*.svg (i.e. default.svg and translations) - it's in the menu already + } + g_free(basename); + basename = 0; + } gchar const *filepath = g_build_filename(dirname, file, NULL); gchar *dupfile = g_strndup(file, strlen(file) - 4); @@ -1026,7 +1038,7 @@ sp_ui_main_menubar(Inkscape::UI::View::View *view) } static void leave_group(GtkMenuItem *, SPDesktop *desktop) { - desktop->setCurrentLayer(SP_OBJECT_PARENT(desktop->currentLayer())); + desktop->setCurrentLayer(desktop->currentLayer()->parent); } static void enter_group(GtkMenuItem *mi, SPDesktop *desktop) { @@ -1072,13 +1084,13 @@ sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item) if (item) { if (SP_IS_GROUP(item)) { group = SP_GROUP(item); - } else if ( item != dt->currentRoot() && SP_IS_GROUP(SP_OBJECT_PARENT(item)) ) { - group = SP_GROUP(SP_OBJECT_PARENT(item)); + } else if ( item != dt->currentRoot() && SP_IS_GROUP(item->parent) ) { + group = SP_GROUP(item->parent); } } if (( group && group != dt->currentLayer() ) || - ( dt->currentLayer() != dt->currentRoot() && SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) ) { + ( dt->currentLayer() != dt->currentRoot() && dt->currentLayer()->parent != dt->currentRoot() ) ) { /* Separator */ sp_ui_menu_append_item(GTK_MENU(m), NULL, NULL, NULL, NULL, NULL, NULL); } @@ -1095,7 +1107,7 @@ sp_ui_context_menu(Inkscape::UI::View::View *view, SPItem *item) } if ( dt->currentLayer() != dt->currentRoot() ) { - if ( SP_OBJECT_PARENT(dt->currentLayer()) != dt->currentRoot() ) { + if ( dt->currentLayer()->parent != dt->currentRoot() ) { GtkWidget *w = gtk_menu_item_new_with_label(_("Go to parent")); g_signal_connect(G_OBJECT(w), "activate", GCallback(leave_group), dt); gtk_widget_show(w); @@ -1168,10 +1180,10 @@ sp_ui_drag_data_received(GtkWidget *widget, g_free(str); str = 0; - SP_OBJECT(item)->setAttribute( - fillnotstroke ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag", - palName.c_str(), - false ); + item->setAttribute( + fillnotstroke ? "inkscape:x-fill-tag":"inkscape:x-stroke-tag", + palName.c_str(), + false ); item->updateRepr(); sp_repr_css_set_property( css, fillnotstroke ? "fill":"stroke", c ); @@ -1252,9 +1264,9 @@ sp_ui_drag_data_received(GtkWidget *widget, Inkscape::Preferences *prefs = Inkscape::Preferences::get(); delta = desktop->d2w(delta); double stroke_tolerance = - ( !SP_OBJECT_STYLE(item)->stroke.isNone() ? + ( !item->style->stroke.isNone() ? desktop->current_zoom() * - SP_OBJECT_STYLE (item)->stroke_width.computed * + item->style->stroke_width.computed * item->i2d_affine().descrim() * 0.5 : 0.0) + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); @@ -1355,9 +1367,9 @@ sp_ui_drag_data_received(GtkWidget *widget, Inkscape::Preferences *prefs = Inkscape::Preferences::get(); delta = desktop->d2w(delta); double stroke_tolerance = - ( !SP_OBJECT_STYLE(item)->stroke.isNone() ? + ( !item->style->stroke.isNone() ? desktop->current_zoom() * - SP_OBJECT_STYLE (item)->stroke_width.computed * + item->style->stroke_width.computed * item->i2d_affine().descrim() * 0.5 : 0.0) + prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); diff --git a/src/jabber_whiteboard/node-tracker.cpp b/src/jabber_whiteboard/node-tracker.cpp index 9f40a7dc6..286ab8216 100644 --- a/src/jabber_whiteboard/node-tracker.cpp +++ b/src/jabber_whiteboard/node-tracker.cpp @@ -288,7 +288,7 @@ void XMLNodeTracker::reset() if (!namedview) { g_warning("namedview node does not exist; it will be created during synchronization"); } else { - put(_namedviewKey, *(SP_OBJECT_REPR(namedview))); + put(_namedviewKey, *(namedview->getRepr())); } } diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp index 767a660be..7da3d0c0e 100644 --- a/src/knot-holder-entity.cpp +++ b/src/knot-holder-entity.cpp @@ -24,7 +24,7 @@ #include "snap.h" #include "desktop.h" #include "sp-namedview.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/transforms.h> int KnotHolderEntity::counter = 0; @@ -75,7 +75,7 @@ KnotHolderEntity::~KnotHolderEntity() void KnotHolderEntity::update_knot() { - Geom::Matrix const i2d(item->i2d_affine()); + Geom::Affine const i2d(item->i2d_affine()); Geom::Point dp(knot_get() * i2d); @@ -87,7 +87,7 @@ KnotHolderEntity::update_knot() Geom::Point KnotHolderEntity::snap_knot_position(Geom::Point const &p) { - Geom::Matrix const i2d (item->i2d_affine()); + Geom::Affine const i2d (item->i2d_affine()); Geom::Point s = p * i2d; SnapManager &m = desktop->namedview->snap_manager; @@ -101,7 +101,7 @@ KnotHolderEntity::snap_knot_position(Geom::Point const &p) Geom::Point KnotHolderEntity::snap_knot_position_constrained(Geom::Point const &p, Inkscape::Snapper::SnapConstraint const &constraint) { - Geom::Matrix const i2d (item->i2d_affine()); + Geom::Affine const i2d (item->i2d_affine()); Geom::Point s = p * i2d; SnapManager &m = desktop->namedview->snap_manager; @@ -124,13 +124,13 @@ KnotHolderEntity::snap_knot_position_constrained(Geom::Point const &p, Inkscape: static gdouble sp_pattern_extract_theta(SPPattern *pat) { - Geom::Matrix transf = pat->patternTransform; + Geom::Affine transf = pat->patternTransform; return Geom::atan2(transf.xAxis()); } static Geom::Point sp_pattern_extract_scale(SPPattern *pat) { - Geom::Matrix transf = pat->patternTransform; + Geom::Affine transf = pat->patternTransform; return Geom::Point( transf.expansionX(), transf.expansionY() ); } @@ -157,7 +157,7 @@ PatternKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &ori if (state) { Geom::Point const q = p_snapped - sp_pattern_extract_trans(pat); - item->adjust_pattern(Geom::Matrix(Geom::Translate(q))); + item->adjust_pattern(Geom::Affine(Geom::Translate(q))); } item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); @@ -180,7 +180,7 @@ PatternKnotHolderEntityAngle::knot_get() Geom::Point delta = Geom::Point(x,y); Geom::Point scale = sp_pattern_extract_scale(pat); gdouble theta = sp_pattern_extract_theta(pat); - delta = delta * Geom::Matrix(Geom::Scale(scale))*Geom::Matrix(Geom::Rotate(theta)); + delta = delta * Geom::Affine(Geom::Scale(scale))*Geom::Affine(Geom::Rotate(theta)); delta = delta + sp_pattern_extract_trans(pat); return delta; } @@ -203,7 +203,7 @@ PatternKnotHolderEntityAngle::knot_set(Geom::Point const &p, Geom::Point const & // get the scale from the current transform so we can keep it. Geom::Point scl = sp_pattern_extract_scale(pat); - Geom::Matrix rot = Geom::Matrix(Geom::Scale(scl)) * Geom::Matrix(Geom::Rotate(theta)); + Geom::Affine rot = Geom::Affine(Geom::Scale(scl)) * Geom::Affine(Geom::Rotate(theta)); Geom::Point const t = sp_pattern_extract_trans(pat); rot[4] = t[Geom::X]; rot[5] = t[Geom::Y]; @@ -236,7 +236,7 @@ PatternKnotHolderEntityScale::knot_set(Geom::Point const &p, Geom::Point const & scl = Geom::Scale(d[Geom::X] / pat_x, d[Geom::Y] / pat_y); } - Geom::Matrix rot = (Geom::Matrix)scl * Geom::Rotate(theta); + Geom::Affine rot = (Geom::Affine)scl * Geom::Rotate(theta); Geom::Point const t = sp_pattern_extract_trans(pat); rot[4] = t[Geom::X]; @@ -254,7 +254,7 @@ PatternKnotHolderEntityScale::knot_get() gdouble x = pattern_width(pat); gdouble y = pattern_height(pat); Geom::Point delta = Geom::Point(x,y); - Geom::Matrix a = pat->patternTransform; + Geom::Affine a = pat->patternTransform; a[4] = 0; a[5] = 0; delta = delta * a; diff --git a/src/knot.h b/src/knot.h index 32035d603..1af2548e1 100644 --- a/src/knot.h +++ b/src/knot.h @@ -16,14 +16,15 @@ #include <gdk/gdk.h> #include <gtk/gtkenums.h> -#include "display/display-forward.h" #include "forward.h" #include <2geom/point.h> #include "knot-enums.h" +#include <stddef.h> #include <sigc++/sigc++.h> class SPKnot; class SPKnotClass; +struct SPCanvasItem; #define SP_TYPE_KNOT (sp_knot_get_type()) #define SP_KNOT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_KNOT, SPKnot)) diff --git a/src/knotholder.cpp b/src/knotholder.cpp index f5e28618e..59059c2a8 100644 --- a/src/knotholder.cpp +++ b/src/knotholder.cpp @@ -44,7 +44,7 @@ class SPDesktop; KnotHolder::KnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) { //XML Tree being used directly here while it shouldn't be... - Inkscape::XML::Node *repr = SP_OBJECT(item)->getRepr(); + Inkscape::XML::Node *repr = item->getRepr(); if (!desktop || !item || !SP_IS_ITEM(item)) { g_print ("Error! Throw an exception, please!\n"); @@ -85,7 +85,7 @@ KnotHolder::~KnotHolder() { void KnotHolder::update_knots() { - Geom::Matrix const i2d(item->i2d_affine()); + Geom::Affine const i2d(item->i2d_affine()); for(std::list<KnotHolderEntity *>::iterator i = entity.begin(); i != entity.end(); ++i) { KnotHolderEntity *e = *i; @@ -148,7 +148,7 @@ KnotHolder::knot_clicked_handler(SPKnot *knot, guint state) } // for drag, this is done by ungrabbed_handler, but for click we must do it here - DocumentUndo::done(SP_OBJECT_DOCUMENT(item), object_verb, + DocumentUndo::done(item->document, object_verb, _("Change handle")); } @@ -204,7 +204,7 @@ KnotHolder::knot_ungrabbed_handler(SPKnot */*knot*/) Inkscape::LivePathEffect::Effect *lpe = sp_lpe_item_get_current_lpe(SP_LPE_ITEM(object)); if (lpe) { LivePathEffectObject *lpeobj = lpe->getLPEObj(); - SP_OBJECT(lpeobj)->updateRepr(); + lpeobj->updateRepr(); } } @@ -227,7 +227,7 @@ KnotHolder::knot_ungrabbed_handler(SPKnot */*knot*/) object_verb = SP_VERB_SELECTION_DYNAMIC_OFFSET; } - DocumentUndo::done(SP_OBJECT_DOCUMENT (object), object_verb, + DocumentUndo::done(object->document, object_verb, _("Move handle")); } } @@ -241,8 +241,8 @@ KnotHolder::add(KnotHolderEntity *e) void KnotHolder::add_pattern_knotholder() { - if ((SP_OBJECT(item)->style->fill.isPaintserver()) - && SP_IS_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style))) + if ((item->style->fill.isPaintserver()) + && SP_IS_PATTERN(item->style->getFillPaintServer())) { PatternKnotHolderEntityXY *entity_xy = new PatternKnotHolderEntityXY(); PatternKnotHolderEntityAngle *entity_angle = new PatternKnotHolderEntityAngle(); diff --git a/src/layer-fns.cpp b/src/layer-fns.cpp index 84f21cd97..3637c11f1 100644 --- a/src/layer-fns.cpp +++ b/src/layer-fns.cpp @@ -51,7 +51,7 @@ SPObject *previous_sibling_layer(SPObject *layer) { using Inkscape::Algorithms::find_last_if; SPObject *sibling(find_last_if<SPObject::SiblingIterator>( - SP_OBJECT_PARENT(layer)->firstChild(), layer, &is_layer + layer->parent->firstChild(), layer, &is_layer )); return ( sibling != layer ) ? sibling : NULL; @@ -91,16 +91,18 @@ SPObject *last_child_layer(SPObject *layer) { SPObject *last_elder_layer(SPObject *root, SPObject *layer) { using Inkscape::Algorithms::find_last_if; + SPObject *result = 0; while ( layer != root ) { SPObject *sibling(previous_sibling_layer(layer)); if (sibling) { - return sibling; + result = sibling; + break; } - layer = SP_OBJECT_PARENT(layer); + layer = layer->parent; } - return NULL; + return result; } } @@ -114,23 +116,21 @@ SPObject *next_layer(SPObject *root, SPObject *layer) { using std::find_if; g_return_val_if_fail(layer != NULL, NULL); + SPObject *result = 0; - SPObject *sibling(next_sibling_layer(layer)); + SPObject *sibling = next_sibling_layer(layer); if (sibling) { SPObject *descendant(first_descendant_layer(sibling)); if (descendant) { - return descendant; + result = descendant; } else { - return sibling; - } - } else { - SPObject *parent=SP_OBJECT_PARENT(layer); - if ( parent != root ) { - return parent; - } else { - return NULL; + result = sibling; } + } else if ( layer->parent != root ) { + result = layer->parent; } + + return result; } @@ -143,20 +143,21 @@ SPObject *previous_layer(SPObject *root, SPObject *layer) { using Inkscape::Algorithms::find_last_if; g_return_val_if_fail(layer != NULL, NULL); + SPObject *result = 0; - SPObject *child(last_child_layer(layer)); + SPObject *child = last_child_layer(layer); if (child) { - return child; + result = child; } else if ( layer != root ) { - SPObject *sibling(previous_sibling_layer(layer)); + SPObject *sibling = previous_sibling_layer(layer); if (sibling) { - return sibling; + result = sibling; } else { - return last_elder_layer(root, SP_OBJECT_PARENT(layer)); + result = last_elder_layer(root, layer->parent); } } - return NULL; + return result; } /** @@ -168,7 +169,7 @@ SPObject *previous_layer(SPObject *root, SPObject *layer) { * \pre \a root should be either \a layer or an ancestor of it */ SPObject *create_layer(SPObject *root, SPObject *layer, LayerRelativePosition position) { - SPDocument *document=SP_OBJECT_DOCUMENT(root); + SPDocument *document = root->document; static int layer_suffix=1; gchar *id=NULL; @@ -192,9 +193,9 @@ SPObject *create_layer(SPObject *root, SPObject *layer, LayerRelativePosition po } if ( root == layer ) { - SP_OBJECT_REPR(root)->appendChild(repr); + root->getRepr()->appendChild(repr); } else { - Inkscape::XML::Node *layer_repr=SP_OBJECT_REPR(layer); + Inkscape::XML::Node *layer_repr = layer->getRepr(); sp_repr_parent(layer_repr)->addChild(repr, layer_repr); if ( LPOS_BELOW == position ) { diff --git a/src/layer-manager.cpp b/src/layer-manager.cpp index 95cefc229..e07d7b945 100644 --- a/src/layer-manager.cpp +++ b/src/layer-manager.cpp @@ -236,7 +236,7 @@ void LayerManager::_rebuild() { LayerWatcher* one = _watchers.back(); _watchers.pop_back(); if ( one->_obj ) { - Node* node = SP_OBJECT_REPR(one->_obj); + Node* node = one->_obj->getRepr(); if ( node ) { node->removeObserver(*one); } @@ -264,7 +264,7 @@ void LayerManager::_rebuild() { if ( root->isAncestorOf(layer) ) { needsAdd = true; - for ( SPObject* curr = layer; curr && (curr != root) && needsAdd; curr = SP_OBJECT_PARENT(curr) ) { + for ( SPObject* curr = layer; curr && (curr != root) && needsAdd; curr = curr->parent ) { if ( SP_IS_GROUP(curr) ) { SPGroup* group = SP_GROUP(curr); if ( group->layerMode() == SPGroup::LAYER ) { @@ -307,10 +307,10 @@ void LayerManager::_rebuild() { // See http://sourceforge.net/tracker/index.php?func=detail&aid=1339397&group_id=93438&atid=604306 SPObject const *higher = layer; - while ( higher && (SP_OBJECT_PARENT(higher) != root) ) { - higher = SP_OBJECT_PARENT(higher); + while ( higher && (higher->parent != root) ) { + higher = higher->parent; } - Node* node = higher ? SP_OBJECT_REPR(higher) : 0; + Node const* node = higher ? higher->getRepr() : 0; if ( node && node->parent() ) { // Debug::EventTracker<DebugAddLayer> tracker(*layer); @@ -318,7 +318,7 @@ void LayerManager::_rebuild() { LayerWatcher *eye = new LayerWatcher(this, layer, connection); _watchers.push_back( eye ); - SP_OBJECT_REPR(layer)->addObserver(*eye); + layer->getRepr()->addObserver(*eye); _addOne(layer); } diff --git a/src/libavoid/geomtypes.h b/src/libavoid/geomtypes.h index ced53e6b0..61963c46f 100644 --- a/src/libavoid/geomtypes.h +++ b/src/libavoid/geomtypes.h @@ -29,6 +29,7 @@ #ifndef AVOID_GEOMTYPES_H #define AVOID_GEOMTYPES_H +#include <cstddef> #include <vector> #include <utility> diff --git a/src/libnr/nr-convert2geom.h b/src/libnr/nr-convert2geom.h index 49871c1f6..75098ce2b 100644 --- a/src/libnr/nr-convert2geom.h +++ b/src/libnr/nr-convert2geom.h @@ -11,7 +11,7 @@ #include <libnr/nr-rect.h> #include <libnr/nr-point.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/d2.h> #include <2geom/transforms.h> #include <2geom/point.h> diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 41533e0ab..7fc0a9715 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -371,7 +371,10 @@ Glib::ustring font_factory::ConstructFontSpecification(PangoFontDescription *fon PangoFontDescription *copy = pango_font_description_copy(font); pango_font_description_unset_fields (copy, PANGO_FONT_MASK_SIZE); - pangoString = Glib::ustring(pango_font_description_to_string(copy)); + char * copyAsString = pango_font_description_to_string(copy); + pangoString = copyAsString; + g_free(copyAsString); + copyAsString = 0; pango_font_description_free(copy); @@ -420,8 +423,11 @@ Glib::ustring font_factory::GetUIStyleString(PangoFontDescription const *fontDes pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_SIZE); // For now, keep it as style name taken from pango - style = pango_font_description_to_string(fontDescrCopy); + char *fontDescrAsString = pango_font_description_to_string(fontDescrCopy); + style = fontDescrAsString; + g_free(fontDescrAsString); + fontDescrAsString = 0; pango_font_description_free(fontDescrCopy); } @@ -745,7 +751,11 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) } } } + g_free(faces); + faces = 0; } + g_free(families); + families = 0; // Sort the style lists for (FamilyToStylesMap::iterator iter = map->begin() ; iter != map->end(); iter++) { diff --git a/src/libnrtype/Layout-TNG-OutIter.cpp b/src/libnrtype/Layout-TNG-OutIter.cpp index 0682e3570..4d461a486 100644 --- a/src/libnrtype/Layout-TNG-OutIter.cpp +++ b/src/libnrtype/Layout-TNG-OutIter.cpp @@ -343,7 +343,7 @@ Geom::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) co return Geom::Rect(top_left, bottom_right); } -std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Matrix const &transform) const +std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Affine const &transform) const { std::vector<Geom::Point> quads; unsigned char_index; @@ -398,7 +398,7 @@ std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start, continue; Geom::Point center_of_rotation((top_left[Geom::X] + bottom_right[Geom::X]) * 0.5, top_left[Geom::Y] + _spans[span_index].line_height.ascent); - Geom::Matrix total_transform = Geom::Translate(-center_of_rotation) * Geom::Rotate(char_rotation) * Geom::Translate(center_of_rotation) * transform; + Geom::Affine total_transform = Geom::Translate(-center_of_rotation) * Geom::Rotate(char_rotation) * Geom::Translate(center_of_rotation) * transform; for(int i = 0; i < 4; i ++) quads.push_back(char_box.corner(i) * total_transform); } diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp index 7c941522d..610f92582 100644 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -63,7 +63,7 @@ void Layout::LineHeight::max(LineHeight const &other) if (other.leading > leading) leading = other.leading; } -void Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Matrix *matrix) const +void Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const { Span const &span = _glyphs[glyph_index].span(this); double sin_rotation = sin(_glyphs[glyph_index].rotation); @@ -94,7 +94,7 @@ void Layout::show(NRArenaGroup *in_arena, NRRect const *paintbox) const nr_arena_glyphs_group_set_style(nr_group, text_source->style); while (glyph_index < (int)_glyphs.size() && _characters[_glyphs[glyph_index].in_character].in_span == span_index) { if (_characters[_glyphs[glyph_index].in_character].in_glyph != -1) { - Geom::Matrix glyph_matrix; + Geom::Affine glyph_matrix; _getGlyphTransformMatrix(glyph_index, &glyph_matrix); nr_arena_glyphs_group_add_component(nr_group, _spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix); } @@ -105,7 +105,7 @@ void Layout::show(NRArenaGroup *in_arena, NRRect const *paintbox) const nr_arena_item_request_update(NR_ARENA_ITEM(in_arena), NR_ARENA_ITEM_STATE_ALL, FALSE); } -void Layout::getBoundingBox(NRRect *bounding_box, Geom::Matrix const &transform, int start, int length) const +void Layout::getBoundingBox(NRRect *bounding_box, Geom::Affine const &transform, int start, int length) const { for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; glyph_index++) { if (_characters[_glyphs[glyph_index].in_character].in_glyph == -1) continue; @@ -116,9 +116,9 @@ void Layout::getBoundingBox(NRRect *bounding_box, Geom::Matrix const &transform, if ((int) _glyphs[glyph_index].in_character > start + length) continue; } // this could be faster - Geom::Matrix glyph_matrix; + Geom::Affine glyph_matrix; _getGlyphTransformMatrix(glyph_index, &glyph_matrix); - Geom::Matrix total_transform = glyph_matrix; + Geom::Affine total_transform = glyph_matrix; total_transform *= transform; if(_glyphs[glyph_index].span(this).font) { Geom::OptRect glyph_rect = _glyphs[glyph_index].span(this).font->BBox(_glyphs[glyph_index].glyph); @@ -143,11 +143,11 @@ void Layout::getBoundingBox(NRRect *bounding_box, Geom::Matrix const &transform, void Layout::print(SPPrintContext *ctx, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox, - Geom::Matrix const &ctm) const + Geom::Affine const &ctm) const { if (_input_stream.empty()) return; - Geom::Matrix ctm_2geom(ctm); + Geom::Affine ctm_2geom(ctm); Direction block_progression = _blockProgression(); bool text_to_path = ctx->module->textToPath(); for (unsigned glyph_index = 0 ; glyph_index < _glyphs.size() ; ) { @@ -158,7 +158,7 @@ void Layout::print(SPPrintContext *ctx, glyph_index++; continue; } - Geom::Matrix glyph_matrix; + Geom::Affine glyph_matrix; Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span]; InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]); if (text_to_path || _path_fitted) { @@ -174,7 +174,7 @@ void Layout::print(SPPrintContext *ctx, glyph_index++; } else { Geom::Point g_pos(0,0); // all strings are output at (0,0) because we do the translation using the matrix - glyph_matrix = Geom::Scale(1.0, -1.0) * (Geom::Matrix)Geom::Rotate(_glyphs[glyph_index].rotation); + glyph_matrix = Geom::Scale(1.0, -1.0) * (Geom::Affine)Geom::Rotate(_glyphs[glyph_index].rotation); if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) { glyph_matrix[4] = span.line(this).baseline_y + span.baseline_shift; // since we're outputting character codes, not glyphs, we want the character x @@ -234,7 +234,7 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const Span const &span = _spans[_characters[_glyphs[glyph_index].in_character].in_span]; InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[span.in_input_stream_item]); - Geom::Matrix glyph_matrix; + Geom::Affine glyph_matrix; _getGlyphTransformMatrix(glyph_index, &glyph_matrix); if (clip_mode) { Geom::PathVector const *pathv = span.font->PathVector(_glyphs[glyph_index].glyph); @@ -247,7 +247,7 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const continue; } - Geom::Matrix font_matrix = glyph_matrix; + Geom::Affine font_matrix = glyph_matrix; font_matrix[4] = 0; font_matrix[5] = 0; @@ -289,7 +289,7 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const && _characters[_glyphs[glyph_index].in_character].in_span == this_span_index); // remove vertical flip - Geom::Matrix flip_matrix; + Geom::Affine flip_matrix; flip_matrix.setIdentity(); flip_matrix[3] = -1.0; font_matrix = flip_matrix * font_matrix; @@ -544,7 +544,7 @@ SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_ GSList *cc = NULL; for (int glyph_index = from_glyph._glyph_index ; glyph_index < to_glyph._glyph_index ; glyph_index++) { - Geom::Matrix glyph_matrix; + Geom::Affine glyph_matrix; Span const &span = _glyphs[glyph_index].span(this); _getGlyphTransformMatrix(glyph_index, &glyph_matrix); @@ -573,7 +573,7 @@ SPCurve *Layout::convertToCurves(iterator const &from_glyph, iterator const &to_ return curve; } -void Layout::transform(Geom::Matrix const &transform) +void Layout::transform(Geom::Affine const &transform) { // this is all massively oversimplified // I can't actually think of anybody who'll want to use it at the moment, so it'll stay simple diff --git a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp index 1bfde1f2d..7144f3876 100644 --- a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp +++ b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp @@ -85,9 +85,9 @@ Layout::ShapeScanlineMaker::ShapeScanlineMaker(Shape const *shape, Layout::Direc _shape_needs_freeing = true; temp_rotated_shape->Copy(const_cast<Shape*>(shape)); switch (block_progression) { - case BOTTOM_TO_TOP: temp_rotated_shape->Transform(Geom::Matrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)); break; // reflect about x axis - case LEFT_TO_RIGHT: temp_rotated_shape->Transform(Geom::Matrix(0.0, 1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=x - case RIGHT_TO_LEFT: temp_rotated_shape->Transform(Geom::Matrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=-x + case BOTTOM_TO_TOP: temp_rotated_shape->Transform(Geom::Affine(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)); break; // reflect about x axis + case LEFT_TO_RIGHT: temp_rotated_shape->Transform(Geom::Affine(0.0, 1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=x + case RIGHT_TO_LEFT: temp_rotated_shape->Transform(Geom::Affine(0.0, -1.0, 1.0, 0.0, 0.0, 0.0)); break; // reflect about y=-x default: break; } _rotated_shape = new Shape; diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h index 833ddc6fd..7d0c58c3e 100644 --- a/src/libnrtype/Layout-TNG.h +++ b/src/libnrtype/Layout-TNG.h @@ -16,7 +16,7 @@ #endif #include <libnr/nr-rect.h> #include <2geom/d2.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <glibmm/ustring.h> #include <pango/pango-break.h> #include <algorithm> @@ -335,7 +335,7 @@ public: \param transform The transform to be applied to the entire object prior to calculating its bounds. */ - void getBoundingBox(NRRect *bounding_box, Geom::Matrix const &transform, int start = -1, int length = -1) const; + void getBoundingBox(NRRect *bounding_box, Geom::Affine const &transform, int start = -1, int length = -1) const; /** Sends all the glyphs to the given print context. \param ctx I have @@ -344,7 +344,7 @@ public: \param bbox parameters \param ctm do yet */ - void print(SPPrintContext *ctx, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox, Geom::Matrix const &ctm) const; + void print(SPPrintContext *ctx, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox, Geom::Affine const &ctm) const; #ifdef HAVE_CAIRO_PDF /** Renders all the glyphs to the given Cairo rendering context. @@ -378,7 +378,7 @@ public: /** Apply the given transform to all the output presently stored in this object. This only transforms the glyph positions, The glyphs themselves will not be transformed. */ - void transform(Geom::Matrix const &transform); + void transform(Geom::Affine const &transform); //@} @@ -499,7 +499,7 @@ public: \a start to \a end and returns the union of these boxes. The return value is a list of zero or more quadrilaterals specified by a group of four points for each, thus size() is always a multiple of four. */ - std::vector<Geom::Point> createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Matrix const &transform) const; + std::vector<Geom::Point> createSelectionShape(iterator const &it_start, iterator const &it_end, Geom::Affine const &transform) const; /** Returns true if \a it points to a character which is a valid cursor position, as defined by Pango. */ @@ -744,7 +744,7 @@ private: /** gets the overall matrix that transforms the given glyph from local space to world space. */ - void _getGlyphTransformMatrix(int glyph_index, Geom::Matrix *matrix) const; + void _getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const; // loads of functions to drill down the object tree, all of them // annoyingly similar and all of them requiring predicate functors. diff --git a/src/libnrtype/font-style.h b/src/libnrtype/font-style.h index 20f03df86..abfac2737 100644 --- a/src/libnrtype/font-style.h +++ b/src/libnrtype/font-style.h @@ -1,7 +1,7 @@ #ifndef SEEN_LIBNRTYPE_FONT_STYLE_H #define SEEN_LIBNRTYPE_FONT_STYLE_H -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <livarot/LivarotDefs.h> #include <livarot/livarot-forward.h> @@ -9,7 +9,7 @@ // Different raster styles. struct font_style { - Geom::Matrix transform; // the ctm. contains the font-size + Geom::Affine transform; // the ctm. contains the font-size bool vertical; // should be rendered vertically or not? // good font support would take the glyph alternates for vertical mode, when present double stroke_width; // if 0, the glyph is filled; otherwise stroked diff --git a/src/livarot/Path.cpp b/src/livarot/Path.cpp index 2a1851cfe..88d397864 100644 --- a/src/livarot/Path.cpp +++ b/src/livarot/Path.cpp @@ -699,7 +699,7 @@ void Path::PointAndTangentAt(int piece, double at, Geom::Point &pos, Geom::Point } } -void Path::Transform(const Geom::Matrix &trans) +void Path::Transform(const Geom::Affine &trans) { for (std::vector<PathDescr*>::iterator i = descr_cmd.begin(); i != descr_cmd.end(); i++) { (*i)->transform(trans); diff --git a/src/livarot/Path.h b/src/livarot/Path.h index 19b1ab48c..b8041c63a 100644 --- a/src/livarot/Path.h +++ b/src/livarot/Path.h @@ -178,12 +178,12 @@ public: void DashPolylineFromStyle(SPStyle *style, float scale, float min_len); //utilitaire pour inkscape - void LoadPath(Geom::Path const &path, Geom::Matrix const &tr, bool doTransformation, bool append = false); - void LoadPathVector(Geom::PathVector const &pv, Geom::Matrix const &tr, bool doTransformation); + void LoadPath(Geom::Path const &path, Geom::Affine const &tr, bool doTransformation, bool append = false); + void LoadPathVector(Geom::PathVector const &pv, Geom::Affine const &tr, bool doTransformation); void LoadPathVector(Geom::PathVector const &pv); Geom::PathVector* MakePathVector(); - void Transform(const Geom::Matrix &trans); + void Transform(const Geom::Affine &trans); // decompose le chemin en ses sous-chemin // killNoSurf=true -> oublie les chemins de surface nulle diff --git a/src/livarot/PathCutting.cpp b/src/livarot/PathCutting.cpp index 112aabed7..708d20f3f 100644 --- a/src/livarot/PathCutting.cpp +++ b/src/livarot/PathCutting.cpp @@ -23,7 +23,7 @@ #include "libnr/nr-convert2geom.h" #include <2geom/pathvector.h> #include <2geom/point.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/curves.h> #include "../display/canvas-bpath.h" @@ -399,9 +399,9 @@ void Path::AddCurve(Geom::Curve const &c) } else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc const *>(&c)) { ArcTo( svg_elliptical_arc->finalPoint(), - svg_elliptical_arc->ray(0), svg_elliptical_arc->ray(1), - svg_elliptical_arc->rotation_angle(), /// \todo check that this parameter is in radians (rotation_angle returns the angle in radians!) - svg_elliptical_arc->large_arc_flag(), !svg_elliptical_arc->sweep_flag() ); + svg_elliptical_arc->ray(Geom::X), svg_elliptical_arc->ray(Geom::Y), + svg_elliptical_arc->rotationAngle(), /// \todo check that this parameter is in radians (rotation_angle returns the angle in radians!) + svg_elliptical_arc->largeArc(), !svg_elliptical_arc->sweep() ); } else { //this case handles sbasis as well as all other curve types Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c.toSBasis(), 0.1); @@ -415,7 +415,7 @@ void Path::AddCurve(Geom::Curve const &c) /** append is false by default: it means that the path should be resetted. If it is true, the path is not resetted and Geom::Path will be appended as a new path */ -void Path::LoadPath(Geom::Path const &path, Geom::Matrix const &tr, bool doTransformation, bool append) +void Path::LoadPath(Geom::Path const &path, Geom::Affine const &tr, bool doTransformation, bool append) { if (!append) { SetBackData (false); @@ -448,10 +448,10 @@ void Path::LoadPath(Geom::Path const &path, Geom::Matrix const &tr, bool doTran void Path::LoadPathVector(Geom::PathVector const &pv) { - LoadPathVector(pv, Geom::Matrix(), false); + LoadPathVector(pv, Geom::Affine(), false); } -void Path::LoadPathVector(Geom::PathVector const &pv, Geom::Matrix const &tr, bool doTransformation) +void Path::LoadPathVector(Geom::PathVector const &pv, Geom::Affine const &tr, bool doTransformation) { SetBackData (false); Reset(); diff --git a/src/livarot/PathSimplify.cpp b/src/livarot/PathSimplify.cpp index 4ebed0efd..fb2aa55e2 100644 --- a/src/livarot/PathSimplify.cpp +++ b/src/livarot/PathSimplify.cpp @@ -251,7 +251,7 @@ bool Path::FitCubic(Geom::Point const &start, PathDescrCubicTo &res, Geom::Point const end = res.p; // la matrice tNN - Geom::Matrix M(0, 0, 0, 0, 0, 0); + Geom::Affine M(0, 0, 0, 0, 0, 0); for (int i = 1; i < nbPt - 1; i++) { M[0] += N13(tk[i]) * N13(tk[i]); M[1] += N23(tk[i]) * N13(tk[i]); @@ -266,7 +266,7 @@ bool Path::FitCubic(Geom::Point const &start, PathDescrCubicTo &res, return false; } - Geom::Matrix const iM = M.inverse(); + Geom::Affine const iM = M.inverse(); M = iM; // phase 1: abcisses diff --git a/src/livarot/Shape.h b/src/livarot/Shape.h index 44dd43a4a..5649ff9e4 100644 --- a/src/livarot/Shape.h +++ b/src/livarot/Shape.h @@ -288,9 +288,9 @@ public: // create a graph that is an offseted version of the graph "of" // the offset is dec, with joins between edges of type "join" (see LivarotDefs.h) // the result is NOT a polygon; you need a subsequent call to ConvertToShape to get a real polygon - int MakeOffset(Shape *of, double dec, JoinType join, double miter, bool do_profile=false, double cx = 0, double cy = 0, double radius = 0, Geom::Matrix *i2doc = NULL); + int MakeOffset(Shape *of, double dec, JoinType join, double miter, bool do_profile=false, double cx = 0, double cy = 0, double radius = 0, Geom::Affine *i2doc = NULL); - int MakeTweak (int mode, Shape *a, double dec, JoinType join, double miter, bool do_profile, Geom::Point c, Geom::Point vector, double radius, Geom::Matrix *i2doc); + int MakeTweak (int mode, Shape *a, double dec, JoinType join, double miter, bool do_profile, Geom::Point c, Geom::Point vector, double radius, Geom::Affine *i2doc); int PtWinding(const Geom::Point px) const; // plus rapide int Winding(const Geom::Point px) const; @@ -314,7 +314,7 @@ public: void QuickScan(float &pos, int &curP, float to, FillRule directed, BitLigne* line, float step); void QuickScan(float &pos, int &curP, float to, AlphaLigne* line, float step); - void Transform(Geom::Matrix const &tr) + void Transform(Geom::Affine const &tr) {for(std::vector<dg_point>::iterator it=_pts.begin();it!=_pts.end();it++) it->x*=tr;} std::vector<back_data> ebData; diff --git a/src/livarot/ShapeMisc.cpp b/src/livarot/ShapeMisc.cpp index a82da4c8a..da268910f 100644 --- a/src/livarot/ShapeMisc.cpp +++ b/src/livarot/ShapeMisc.cpp @@ -14,7 +14,7 @@ #include <cstdlib> #include <cstring> #include <2geom/point.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> /* * polygon offset and polyline to path reassembling (when using back data) @@ -528,7 +528,7 @@ Shape::ConvertToFormeNested (Path * dest, int nbP, Path * *orig, int wildPath,in int -Shape::MakeTweak (int mode, Shape *a, double power, JoinType join, double miter, bool do_profile, Geom::Point c, Geom::Point vector, double radius, Geom::Matrix *i2doc) +Shape::MakeTweak (int mode, Shape *a, double power, JoinType join, double miter, bool do_profile, Geom::Point c, Geom::Point vector, double radius, Geom::Affine *i2doc) { Reset (0, 0); MakeBackData(a->_has_back_data); @@ -639,7 +639,7 @@ Shape::MakeTweak (int mode, Shape *a, double power, JoinType join, double miter, Geom::Point this_vec(0,0); if (mode == tweak_mode_push) { - Geom::Matrix tovec (*i2doc); + Geom::Affine tovec (*i2doc); tovec[4] = tovec[5] = 0; tovec = tovec.inverse(); this_vec = this_power * (vector * tovec) ; @@ -718,7 +718,7 @@ Shape::MakeTweak (int mode, Shape *a, double power, JoinType join, double miter, // you gotta be very careful with the join, as anything but the right one will fuck everything up // see PathStroke.cpp for the "right" joins int -Shape::MakeOffset (Shape * a, double dec, JoinType join, double miter, bool do_profile, double cx, double cy, double radius, Geom::Matrix *i2doc) +Shape::MakeOffset (Shape * a, double dec, JoinType join, double miter, bool do_profile, double cx, double cy, double radius, Geom::Affine *i2doc) { Reset (0, 0); MakeBackData(a->_has_back_data); diff --git a/src/livarot/ShapeSweep.cpp b/src/livarot/ShapeSweep.cpp index 9ff633f1d..e3fb0296d 100644 --- a/src/livarot/ShapeSweep.cpp +++ b/src/livarot/ShapeSweep.cpp @@ -11,7 +11,7 @@ #include <cstring> #include <glib.h> #include <glib/gmem.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "Shape.h" #include "livarot/sweep-event-queue.h" #include "livarot/sweep-tree-list.h" @@ -2605,7 +2605,7 @@ Shape::TesteIntersection (Shape * ils, Shape * irs, int ilb, int irb, usvs = irs->pData[rSt].rx - ils->pData[lSt].rx; // pas sur de l'ordre des coefs de m - Geom::Matrix m(ldir[0], ldir[1], + Geom::Affine m(ldir[0], ldir[1], rdir[0], rdir[1], 0, 0); double det = m.det(); diff --git a/src/livarot/path-description.cpp b/src/livarot/path-description.cpp index fd91cb447..c34965a5c 100644 --- a/src/livarot/path-description.cpp +++ b/src/livarot/path-description.cpp @@ -1,5 +1,5 @@ #include "livarot/path-description.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> PathDescr *PathDescrMoveTo::clone() const { @@ -11,7 +11,7 @@ void PathDescrMoveTo::dumpSVG(Inkscape::SVGOStringStream& s, Geom::Point const & s << "M " << p[Geom::X] << " " << p[Geom::Y] << " "; } -void PathDescrMoveTo::transform(Geom::Matrix const& t) +void PathDescrMoveTo::transform(Geom::Affine const& t) { p = p * t; } @@ -32,7 +32,7 @@ PathDescr *PathDescrLineTo::clone() const return new PathDescrLineTo(*this); } -void PathDescrLineTo::transform(Geom::Matrix const& t) +void PathDescrLineTo::transform(Geom::Affine const& t) { p = p * t; } @@ -48,7 +48,7 @@ PathDescr *PathDescrBezierTo::clone() const return new PathDescrBezierTo(*this); } -void PathDescrBezierTo::transform(Geom::Matrix const& t) +void PathDescrBezierTo::transform(Geom::Affine const& t) { p = p * t; } @@ -64,7 +64,7 @@ PathDescr *PathDescrIntermBezierTo::clone() const return new PathDescrIntermBezierTo(*this); } -void PathDescrIntermBezierTo::transform(Geom::Matrix const& t) +void PathDescrIntermBezierTo::transform(Geom::Affine const& t) { p = p * t; } @@ -100,9 +100,9 @@ void PathDescrCubicTo::dump(std::ostream &s) const << end[Geom::X] << " " << end[Geom::Y] << " "; } -void PathDescrCubicTo::transform(Geom::Matrix const& t) +void PathDescrCubicTo::transform(Geom::Affine const& t) { - Geom::Matrix tr = t; + Geom::Affine tr = t; tr[4] = tr[5] = 0; start = start * tr; end = end * tr; @@ -127,7 +127,7 @@ PathDescr *PathDescrArcTo::clone() const return new PathDescrArcTo(*this); } -void PathDescrArcTo::transform(Geom::Matrix const& t) +void PathDescrArcTo::transform(Geom::Affine const& t) { p = p * t; } diff --git a/src/livarot/path-description.h b/src/livarot/path-description.h index 68088c27c..1d0dfb57e 100644 --- a/src/livarot/path-description.h +++ b/src/livarot/path-description.h @@ -37,7 +37,7 @@ struct PathDescr virtual void dumpSVG(Inkscape::SVGOStringStream &/*s*/, Geom::Point const &/*last*/) const {} virtual PathDescr *clone() const = 0; - virtual void transform(Geom::Matrix const &/*t*/) {} + virtual void transform(Geom::Affine const &/*t*/) {} virtual void dump(std::ostream &/*s*/) const {} int flags; // most notably contains the path command no @@ -53,7 +53,7 @@ struct PathDescrMoveTo : public PathDescr void dumpSVG(Inkscape::SVGOStringStream &s, Geom::Point const &last) const; PathDescr *clone() const; - void transform(Geom::Matrix const &t); + void transform(Geom::Affine const &t); void dump(std::ostream &s) const; Geom::Point p; @@ -66,7 +66,7 @@ struct PathDescrLineTo : public PathDescr void dumpSVG(Inkscape::SVGOStringStream &s, Geom::Point const &last) const; PathDescr *clone() const; - void transform(Geom::Matrix const &t); + void transform(Geom::Affine const &t); void dump(std::ostream &s) const; Geom::Point p; @@ -79,7 +79,7 @@ struct PathDescrBezierTo : public PathDescr : PathDescr(descr_bezierto), p(pp), nb(n) {} PathDescr *clone() const; - void transform(Geom::Matrix const &t); + void transform(Geom::Affine const &t); void dump(std::ostream &s) const; Geom::Point p; // the endpoint's coordinates @@ -95,7 +95,7 @@ struct PathDescrIntermBezierTo : public PathDescr : PathDescr(descr_interm_bezier), p(pp) {} PathDescr *clone() const; - void transform(Geom::Matrix const &t); + void transform(Geom::Affine const &t); void dump(std::ostream &s) const; Geom::Point p; // control point coordinates @@ -109,7 +109,7 @@ struct PathDescrCubicTo : public PathDescr void dumpSVG(Inkscape::SVGOStringStream &s, Geom::Point const &last) const; PathDescr *clone() const; - void transform(Geom::Matrix const &t); + void transform(Geom::Affine const &t); void dump(std::ostream &s) const; Geom::Point p; @@ -125,7 +125,7 @@ struct PathDescrArcTo : public PathDescr void dumpSVG(Inkscape::SVGOStringStream &s, Geom::Point const &last) const; PathDescr *clone() const; - void transform(Geom::Matrix const &t); + void transform(Geom::Affine const &t); void dump(std::ostream &s) const; Geom::Point p; diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 3ea57de23..ed0d162ac 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -38,7 +38,7 @@ #include <exception> #include <2geom/sbasis-to-bezier.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/pathvector.h> // include effects: @@ -249,7 +249,7 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) } if (neweffect) { - neweffect->readallParameters(SP_OBJECT_REPR(lpeobj)); + neweffect->readallParameters(lpeobj->getRepr()); } return neweffect; @@ -262,7 +262,7 @@ void Effect::createAndApply(const char* name, SPDocument *doc, SPItem *item) Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect"); repr->setAttribute("effect", name); - SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute + SP_DOCUMENT_DEFS(doc)->getRepr()->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute const gchar * repr_id = repr->attribute("id"); Inkscape::GC::release(repr); @@ -579,17 +579,17 @@ Effect::newWidget(Gtk::Tooltips * tooltips) } -Inkscape::XML::Node * -Effect::getRepr() +Inkscape::XML::Node *Effect::getRepr() { - return SP_OBJECT_REPR(lpeobj); + return lpeobj->getRepr(); } -SPDocument * -Effect::getSPDoc() +SPDocument *Effect::getSPDoc() { - if (SP_OBJECT_DOCUMENT(lpeobj) == NULL) g_message("Effect::getSPDoc() returns NULL"); - return SP_OBJECT_DOCUMENT(lpeobj); + if (lpeobj->document == NULL) { + g_message("Effect::getSPDoc() returns NULL"); + } + return lpeobj->document; } Parameter * @@ -668,7 +668,7 @@ Effect::resetDefaults(SPItem * /*item*/) } void -Effect::transform_multiply(Geom::Matrix const& postmul, bool set) +Effect::transform_multiply(Geom::Affine const& postmul, bool set) { // cycle through all parameters. Most parameters will not need transformation, but path and point params do. for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); it++) { diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 681bae387..7fe4e9348 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -10,7 +10,6 @@ */ -#include "display/display-forward.h" #include <map> #include <glibmm/ustring.h> #include <2geom/forward.h> @@ -29,6 +28,7 @@ class SPLPEItem; class KnotHolder; class KnotHolderEntity; class SPPath; +struct SPCurve; namespace Gtk { class Widget; @@ -92,7 +92,7 @@ public: virtual void resetDefaults(SPItem * item); /// /todo: is this method really necessary? it causes UI inconsistensies... (johan) - virtual void transform_multiply(Geom::Matrix const& postmul, bool set); + virtual void transform_multiply(Geom::Affine const& postmul, bool set); // /TODO: providesKnotholder() is currently used as an indicator of whether a nodepath is // created for an item or not. When we allow both at the same time, this needs rethinking! diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp index 254500908..2d6bbeb22 100644 --- a/src/live_effects/lpe-bendpath.cpp +++ b/src/live_effects/lpe-bendpath.cpp @@ -53,9 +53,9 @@ namespace LivePathEffect { LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) : Effect(lpeobject), bend_path(_("Bend path:"), _("Path along which to bend the original path"), "bendpath", &wr, this, "M0,0 L1,0"), - prop_scale(_("Width:"), _("Width of the path"), "prop_scale", &wr, this, 1), - scale_y_rel(_("Width in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false), - vertical_pattern(_("Original path is vertical"), _("Rotates the original 90 degrees, before bending it along the bend path"), "vertical", &wr, this, false) + prop_scale(_("_Width:"), _("Width of the path"), "prop_scale", &wr, this, 1), + scale_y_rel(_("W_idth in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false), + vertical_pattern(_("_Original path is vertical"), _("Rotates the original 90 degrees, before bending it along the bend path"), "vertical", &wr, this, false) { registerParameter( dynamic_cast<Parameter *>(&bend_path) ); registerParameter( dynamic_cast<Parameter *>(&prop_scale) ); diff --git a/src/live_effects/lpe-constructgrid.cpp b/src/live_effects/lpe-constructgrid.cpp index aee4c127a..cb9c031aa 100644 --- a/src/live_effects/lpe-constructgrid.cpp +++ b/src/live_effects/lpe-constructgrid.cpp @@ -23,8 +23,8 @@ using namespace Geom; LPEConstructGrid::LPEConstructGrid(LivePathEffectObject *lpeobject) : Effect(lpeobject), - nr_x(_("Size X:"), _("The size of the grid in X direction."), "nr_x", &wr, this, 5), - nr_y(_("Size Y:"), _("The size of the grid in Y direction."), "nr_y", &wr, this, 5) + nr_x(_("Size _X:"), _("The size of the grid in X direction."), "nr_x", &wr, this, 5), + nr_y(_("Size _Y:"), _("The size of the grid in Y direction."), "nr_y", &wr, this, 5) { registerParameter( dynamic_cast<Parameter *>(&nr_x) ); registerParameter( dynamic_cast<Parameter *>(&nr_y) ); diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index dac34c5d4..38869cb97 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -101,12 +101,12 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p Piecewise<D2<SBasis> > output; - Matrix pre = Translate(-origin) * Rotate(-deg_to_rad(starting_angle)); + Affine pre = Translate(-origin) * Rotate(-deg_to_rad(starting_angle)); for (int i = 0; i < num_copies; ++i) { // I first suspected the minus sign to be a bug in 2geom but it is // likely due to SVG's choice of coordinate system orientation (max) Rotate rot(-deg_to_rad(rotation_angle * i)); - Matrix t = pre * rot * Translate(origin); + Affine t = pre * rot * Translate(origin); output.concat(pwd2_in * t); } diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index 9e9488ce5..a002901b2 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -27,7 +27,7 @@ #include <2geom/bezier-to-sbasis.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/d2.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "ui/widget/scalar.h" #include "libnr/nr-values.h" @@ -40,13 +40,13 @@ using namespace Geom; LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : Effect(lpeobject), strokepath(_("Stitch path:"), _("The path that will be used as stitch."), "strokepath", &wr, this, "M0,0 L1,0"), - nrofpaths(_("Number of paths:"), _("The number of paths that will be generated."), "count", &wr, this, 5), - startpoint_edge_variation(_("Start edge variance:"), _("The amount of random jitter to move the start points of the stitches inside & outside the guide path"), "startpoint_edge_variation", &wr, this, 0), - startpoint_spacing_variation(_("Start spacing variance:"), _("The amount of random shifting to move the start points of the stitches back & forth along the guide path"), "startpoint_spacing_variation", &wr, this, 0), - endpoint_edge_variation(_("End edge variance:"), _("The amount of randomness that moves the end points of the stitches inside & outside the guide path"), "endpoint_edge_variation", &wr, this, 0), - endpoint_spacing_variation(_("End spacing variance:"), _("The amount of random shifting to move the end points of the stitches back & forth along the guide path"), "endpoint_spacing_variation", &wr, this, 0), - prop_scale(_("Scale width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1), - scale_y_rel(_("Scale width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false) + nrofpaths(_("N_umber of paths:"), _("The number of paths that will be generated."), "count", &wr, this, 5), + startpoint_edge_variation(_("Sta_rt edge variance:"), _("The amount of random jitter to move the start points of the stitches inside & outside the guide path"), "startpoint_edge_variation", &wr, this, 0), + startpoint_spacing_variation(_("Sta_rt spacing variance:"), _("The amount of random shifting to move the start points of the stitches back & forth along the guide path"), "startpoint_spacing_variation", &wr, this, 0), + endpoint_edge_variation(_("End ed_ge variance:"), _("The amount of randomness that moves the end points of the stitches inside & outside the guide path"), "endpoint_edge_variation", &wr, this, 0), + endpoint_spacing_variation(_("End spa_cing variance:"), _("The amount of random shifting to move the end points of the stitches back & forth along the guide path"), "endpoint_spacing_variation", &wr, this, 0), + prop_scale(_("Scale _width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1), + scale_y_rel(_("Scale _width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false) { registerParameter( dynamic_cast<Parameter *>(&nrofpaths) ); registerParameter( dynamic_cast<Parameter *>(&startpoint_edge_variation) ); @@ -120,7 +120,7 @@ LPECurveStitch::doEffect_path (std::vector<Geom::Path> const & path_in) scaling_y = prop_scale; } - Matrix transform; + Affine transform; transform.setXAxis( (end-start) / scaling ); transform.setYAxis( rot90(unit_vector(end-start)) * scaling_y); transform.setTranslation( start ); @@ -163,7 +163,7 @@ LPECurveStitch::resetDefaults(SPItem * item) // calculate bounding box: (isn't there a simpler way?) Piecewise<D2<SBasis> > pwd2; - std::vector<Geom::Path> temppath = sp_svg_read_pathv( SP_OBJECT_REPR(item)->attribute("inkscape:original-d")); + std::vector<Geom::Path> temppath = sp_svg_read_pathv( item->getRepr()->attribute("inkscape:original-d")); for (unsigned int i=0; i < temppath.size(); i++) { pwd2.concat( temppath[i].toPwSb() ); } @@ -195,7 +195,7 @@ LPECurveStitch::resetDefaults(SPItem * item) * special casing is probably needed, because rotation should not be propagated to the strokepath. */ void -LPECurveStitch::transform_multiply(Geom::Matrix const& postmul, bool set) +LPECurveStitch::transform_multiply(Geom::Affine const& postmul, bool set) { // only take translations into account if (postmul.isTranslation()) { @@ -203,7 +203,7 @@ LPECurveStitch::transform_multiply(Geom::Matrix const& postmul, bool set) } else if (!scale_y_rel.get_value()) { // this basically means that for this transformation, the result should be the same as normal scaling the result path // don't know how to do this yet. -// Geom::Matrix new_postmul; +// Geom::Affine new_postmul; //new_postmul.setIdentity(); // new_postmul.setTranslation(postmul.translation()); // Effect::transform_multiply(new_postmul, set); diff --git a/src/live_effects/lpe-curvestitch.h b/src/live_effects/lpe-curvestitch.h index 8a8e43f2c..f46f2a5d2 100644 --- a/src/live_effects/lpe-curvestitch.h +++ b/src/live_effects/lpe-curvestitch.h @@ -32,7 +32,7 @@ public: virtual void resetDefaults(SPItem * item); - virtual void transform_multiply(Geom::Matrix const& postmul, bool set); + virtual void transform_multiply(Geom::Affine const& postmul, bool set); private: PathParam strokepath; diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp index a9f9202e9..0fd31dccf 100644 --- a/src/live_effects/lpe-dynastroke.cpp +++ b/src/live_effects/lpe-dynastroke.cpp @@ -166,12 +166,12 @@ LPEDynastroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p std::cout<<"ellptic pen\n"; //FIXME: roundness=0??? double c = cos(angle_rad), s = sin(angle_rad); - Matrix rot,slant; - rot = Matrix(c, -s, s, c, 0, 0 ); - slant = Matrix(double(width)*roundness, 0, 0, double(width), 0, 0 ); + Affine rot,slant; + rot = Affine(c, -s, s, c, 0, 0 ); + slant = Affine(double(width)*roundness, 0, 0, double(width), 0, 0 ); Piecewise<D2<SBasis> > nn = unitVector(v * ( rot * slant ) ); - slant = Matrix( 0,-roundness, 1, 0, 0, 0 ); - rot = Matrix(-s, -c, c, -s, 0, 0 ); + slant = Affine( 0,-roundness, 1, 0, 0, 0 ); + rot = Affine(-s, -c, c, -s, 0, 0 ); nn = nn * (slant * rot ); n1 = nn*double(width); diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp index bd1cc5861..49f294498 100644 --- a/src/live_effects/lpe-envelope.cpp +++ b/src/live_effects/lpe-envelope.cpp @@ -34,8 +34,8 @@ LPEEnvelope::LPEEnvelope(LivePathEffectObject *lpeobject) : bend_path2(_("Right bend path:"), _("Right path along which to bend the original path"), "bendpath2", &wr, this, "M0,0 L1,0"), bend_path3(_("Bottom bend path:"), _("Bottom path along which to bend the original path"), "bendpath3", &wr, this, "M0,0 L1,0"), bend_path4(_("Left bend path:"), _("Left path along which to bend the original path"), "bendpath4", &wr, this, "M0,0 L1,0"), - xx(_("Enable left & right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true), - yy(_("Enable top & bottom paths"), _("Enable the top and bottom deformation paths"), "yy", &wr, this, true) + xx(_("E_nable left & right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true), + yy(_("_Enable top & bottom paths"), _("Enable the top and bottom deformation paths"), "yy", &wr, this, true) { registerParameter( dynamic_cast<Parameter *>(&yy) ); registerParameter( dynamic_cast<Parameter *>(&xx) ); diff --git a/src/live_effects/lpe-gears.cpp b/src/live_effects/lpe-gears.cpp index c9bbde8f2..337beb516 100644 --- a/src/live_effects/lpe-gears.cpp +++ b/src/live_effects/lpe-gears.cpp @@ -209,8 +209,8 @@ namespace LivePathEffect { LPEGears::LPEGears(LivePathEffectObject *lpeobject) : Effect(lpeobject), - teeth(_("Teeth:"), _("The number of teeth"), "teeth", &wr, this, 10), - phi(_("Phi:"), _("Tooth pressure angle (typically 20-25 deg). The ratio of teeth not in contact."), "phi", &wr, this, 5) + teeth(_("_Teeth:"), _("The number of teeth"), "teeth", &wr, this, 10), + phi(_("_Phi:"), _("Tooth pressure angle (typically 20-25 deg). The ratio of teeth not in contact."), "phi", &wr, this, 5) { /* Tooth pressure angle: The angle between the tooth profile and a perpendicular to the pitch * circle, usually at the point where the pitch circle meets the tooth profile. Standard angles diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp index a4546726f..621823546 100644 --- a/src/live_effects/lpe-interpolate.cpp +++ b/src/live_effects/lpe-interpolate.cpp @@ -28,8 +28,8 @@ namespace LivePathEffect { LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) : Effect(lpeobject), trajectory_path(_("Trajectory:"), _("Path along which intermediate steps are created."), "trajectory", &wr, this, "M0,0 L0,0"), - number_of_steps(_("Steps:"), _("Determines the number of steps from start to end path."), "steps", &wr, this, 5), - equidistant_spacing(_("Equidistant spacing"), _("If true, the spacing between intermediates is constant along the length of the path. If false, the distance depends on the location of the nodes of the trajectory path."), "equidistant_spacing", &wr, this, true) + number_of_steps(_("Steps_:"), _("Determines the number of steps from start to end path."), "steps", &wr, this, 5), + equidistant_spacing(_("E_quidistant spacing"), _("If true, the spacing between intermediates is constant along the length of the path. If false, the distance depends on the location of the nodes of the trajectory path."), "equidistant_spacing", &wr, this, true) { show_orig_path = true; diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index fef4e1f87..522b3cdc6 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -95,7 +95,7 @@ findShadowedTime(Geom::Path const &patha, std::vector<Geom::Point> const &pt_and Point N = T.cw(); Point A = pt_and_dir[0]-3*width*T, B = A+6*width*T; - Matrix mat = from_basis( T, N, pt_and_dir[0] ); + Affine mat = from_basis( T, N, pt_and_dir[0] ); mat = mat.inverse(); Path p = patha * mat; @@ -340,11 +340,11 @@ CrossingPoints::inherit_signs(CrossingPoints const &other, int default_value) LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: - interruption_width(_("Fixed width:"), _("Size of hidden region of lower string"), "interruption_width", &wr, this, 3), - prop_to_stroke_width(_("In units of stroke width"), _("Consider 'Interruption width' as a ratio of stroke width"), "prop_to_stroke_width", &wr, this, true), - add_stroke_width(_("Stroke width"), _("Add the stroke width to the interruption size"), "add_stroke_width", &wr, this, true), - add_other_stroke_width(_("Crossing path stroke width"), _("Add crossed stroke width to the interruption size"), "add_other_stroke_width", &wr, this, true), - switcher_size(_("Switcher size:"), _("Orientation indicator/switcher size"), "switcher_size", &wr, this, 15), + interruption_width(_("Fi_xed width:"), _("Size of hidden region of lower string"), "interruption_width", &wr, this, 3), + prop_to_stroke_width(_("_In units of stroke width"), _("Consider 'Interruption width' as a ratio of stroke width"), "prop_to_stroke_width", &wr, this, true), + add_stroke_width(_("St_roke width"), _("Add the stroke width to the interruption size"), "add_stroke_width", &wr, this, true), + add_other_stroke_width(_("_Crossing path stroke width"), _("Add crossed stroke width to the interruption size"), "add_other_stroke_width", &wr, this, true), + switcher_size(_("S_witcher size:"), _("Orientation indicator/switcher size"), "switcher_size", &wr, this, 15), crossing_points_vector(_("Crossing Signs"), _("Crossings signs"), "crossing_points_vector", &wr, this), gpaths(),gstroke_widths() { @@ -611,7 +611,7 @@ LPEKnot::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVecto svgd = "M 10,0 C 10,5.52 5.52,10 0,10 -5.52,10 -10,5.52 -10,0 c 0,-5.52 4.48,-10 10,-10 5.52,0 10,4.48 10,10 z"; } PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Matrix(r,0,0,r,0,0); + pathv *= Affine(r,0,0,r,0,0); pathv+=switcher; hp_vec.push_back(pathv); } diff --git a/src/live_effects/lpe-line_segment.cpp b/src/live_effects/lpe-line_segment.cpp index df5619002..da30cd32c 100644 --- a/src/live_effects/lpe-line_segment.cpp +++ b/src/live_effects/lpe-line_segment.cpp @@ -47,7 +47,7 @@ LPELineSegment::~LPELineSegment() void LPELineSegment::doBeforeEffect (SPLPEItem *lpeitem) { - lpetool_get_limiting_bbox_corners(SP_OBJECT_DOCUMENT(lpeitem), bboxA, bboxB); + lpetool_get_limiting_bbox_corners(lpeitem->document, bboxA, bboxB); } std::vector<Geom::Path> diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 1af2ed6ca..dec8c9216 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -20,7 +20,7 @@ #include <2geom/path.h> #include <2geom/transforms.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> namespace Inkscape { namespace LivePathEffect { @@ -46,7 +46,7 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem *lpeitem) using namespace Geom; SPItem *item = SP_ITEM(lpeitem); - Geom::Matrix t = item->i2d_affine(); + Geom::Affine t = item->i2d_affine(); Geom::Rect bbox = *item->getBounds(t); // fixme: what happens if getBounds does not return a valid rect? Point A(bbox.left(), bbox.bottom()); @@ -74,15 +74,15 @@ LPEMirrorSymmetry::doEffect_path (std::vector<Geom::Path> const & path_in) Geom::Point A(mline.front().initialPoint()); Geom::Point B(mline.back().finalPoint()); - Geom::Matrix m1(1.0, 0.0, 0.0, 1.0, A[0], A[1]); + Geom::Affine m1(1.0, 0.0, 0.0, 1.0, A[0], A[1]); double hyp = Geom::distance(A, B); double c = (B[0] - A[0]) / hyp; // cos(alpha) double s = (B[1] - A[1]) / hyp; // sin(alpha) - Geom::Matrix m2(c, -s, s, c, 0.0, 0.0); - Geom::Matrix sca(1.0, 0.0, 0.0, -1.0, 0.0, 0.0); + Geom::Affine m2(c, -s, s, c, 0.0, 0.0); + Geom::Affine sca(1.0, 0.0, 0.0, -1.0, 0.0, 0.0); - Geom::Matrix m = m1.inverse() * m2; + Geom::Affine m = m1.inverse() * m2; m = m * sca; m = m * m2.inverse(); m = m * m1; diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp index d00dc11db..0a05228d2 100644 --- a/src/live_effects/lpe-patternalongpath.cpp +++ b/src/live_effects/lpe-patternalongpath.cpp @@ -61,22 +61,22 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) : pattern(_("Pattern source:"), _("Path to put along the skeleton path"), "pattern", &wr, this, "M0,0 L1,0"), copytype(_("Pattern copies:"), _("How many pattern copies to place along the skeleton path"), "copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED), - prop_scale(_("Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1), - scale_y_rel(_("Width in units of length"), + prop_scale(_("_Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1), + scale_y_rel(_("Wid_th in units of length"), _("Scale the width of the pattern in units of its length"), "scale_y_rel", &wr, this, false), - spacing(_("Spacing:"), + spacing(_("Spa_cing:"), // xgettext:no-c-format _("Space between copies of the pattern. Negative values allowed, but are limited to -90% of pattern width."), "spacing", &wr, this, 0), - normal_offset(_("Normal offset:"), "", "normal_offset", &wr, this, 0), - tang_offset(_("Tangential offset:"), "", "tang_offset", &wr, this, 0), - prop_units(_("Offsets in unit of pattern size"), + normal_offset(_("No_rmal offset:"), "", "normal_offset", &wr, this, 0), + tang_offset(_("Tan_gential offset:"), "", "tang_offset", &wr, this, 0), + prop_units(_("Offsets in _unit of pattern size"), _("Spacing, tangential and normal offset are expressed as a ratio of width/height"), "prop_units", &wr, this, false), - vertical_pattern(_("Pattern is vertical"), _("Rotate pattern 90 deg before applying"), + vertical_pattern(_("Pattern is _vertical"), _("Rotate pattern 90 deg before applying"), "vertical_pattern", &wr, this, false), - fuse_tolerance(_("Fuse nearby ends:"), _("Fuse ends closer than this number. 0 means don't fuse."), + fuse_tolerance(_("_Fuse nearby ends:"), _("Fuse ends closer than this number. 0 means don't fuse."), "fuse_tolerance", &wr, this, 0) { registerParameter( dynamic_cast<Parameter *>(&pattern) ); @@ -230,7 +230,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con } void -LPEPatternAlongPath::transform_multiply(Geom::Matrix const& postmul, bool set) +LPEPatternAlongPath::transform_multiply(Geom::Affine const& postmul, bool set) { // overriding the Effect class default method, disabling transform forwarding to the parameters. diff --git a/src/live_effects/lpe-patternalongpath.h b/src/live_effects/lpe-patternalongpath.h index 1c02f2c08..f48281090 100644 --- a/src/live_effects/lpe-patternalongpath.h +++ b/src/live_effects/lpe-patternalongpath.h @@ -32,7 +32,7 @@ public: virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); - virtual void transform_multiply(Geom::Matrix const& postmul, bool set); + virtual void transform_multiply(Geom::Affine const& postmul, bool set); PathParam pattern; private: diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 5dc170e84..82f4ccdea 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -21,18 +21,31 @@ #include <2geom/transforms.h> #include <2geom/bezier-utils.h> +#include "live_effects/bezctx.h" +#include "live_effects/bezctx_intf.h" +#include "live_effects/spiro.h" + /// @TODO Move this to 2geom namespace Geom { namespace Interpolate { +enum InterpolatorType { + INTERP_LINEAR, + INTERP_CUBICBEZIER, + INTERP_CUBICBEZIER_JOHAN, + INTERP_SPIRO +}; + class Interpolator { public: Interpolator() {}; virtual ~Interpolator() {}; + static Interpolator* create(InterpolatorType type); + // virtual Piecewise<D2<SBasis> > interpolateToPwD2Sb(std::vector<Point> points) = 0; - virtual Path interpolateToPath(std::vector<Point> points) = 0; + virtual Geom::Path interpolateToPath(std::vector<Point> points) = 0; private: Interpolator(const Interpolator&); @@ -120,16 +133,153 @@ private: CubicBezierJohan& operator=(const CubicBezierJohan&); }; + +#define SPIRO_SHOW_INFINITE_COORDINATE_CALLS +class SpiroInterpolator : public Interpolator { +public: + SpiroInterpolator() {}; + virtual ~SpiroInterpolator() {}; + + virtual Path interpolateToPath(std::vector<Point> points) { + Path fit; + + Coord scale_y = 100.; + + guint len = points.size(); + bezctx *bc = new_bezctx_ink(&fit); + spiro_cp *controlpoints = g_new (spiro_cp, len); + for (unsigned int i = 0; i < len; ++i) { + controlpoints[i].x = points[i][X]; + controlpoints[i].y = points[i][Y] / scale_y; + controlpoints[i].ty = 'c'; + } + controlpoints[0].ty = '{'; + controlpoints[1].ty = 'v'; + controlpoints[len-2].ty = 'v'; + controlpoints[len-1].ty = '}'; + + spiro_seg *s = run_spiro(controlpoints, len); + spiro_to_bpath(s, len, bc); + free(s); + free(bc); + + fit *= Scale(1,scale_y); + return fit; + }; + +private: + typedef struct { + bezctx base; + Path *path; + int is_open; + } bezctx_ink; + + static void bezctx_ink_moveto(bezctx *bc, double x, double y, int /*is_open*/) + { + bezctx_ink *bi = (bezctx_ink *) bc; + if ( IS_FINITE(x) && IS_FINITE(y) ) { + bi->path->start(Point(x, y)); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro moveto not finite"); + } + #endif + } + + static void bezctx_ink_lineto(bezctx *bc, double x, double y) + { + bezctx_ink *bi = (bezctx_ink *) bc; + if ( IS_FINITE(x) && IS_FINITE(y) ) { + bi->path->appendNew<LineSegment>( Point(x, y) ); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro lineto not finite"); + } + #endif + } + + static void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3) + { + bezctx_ink *bi = (bezctx_ink *) bc; + + if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) { + bi->path->appendNew<QuadraticBezier>(Point(xm, ym), Point(x3, y3)); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro quadto not finite"); + } + #endif + } + + static void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2, + double x3, double y3) + { + bezctx_ink *bi = (bezctx_ink *) bc; + if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) { + bi->path->appendNew<CubicBezier>(Point(x1, y1), Point(x2, y2), Point(x3, y3)); + } + #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS + else { + g_message("spiro curveto not finite"); + } + #endif + } + + bezctx * + new_bezctx_ink(Geom::Path *path) { + bezctx_ink *result = g_new(bezctx_ink, 1); + result->base.moveto = bezctx_ink_moveto; + result->base.lineto = bezctx_ink_lineto; + result->base.quadto = bezctx_ink_quadto; + result->base.curveto = bezctx_ink_curveto; + result->base.mark_knot = NULL; + result->path = path; + return &result->base; + } + + SpiroInterpolator(const SpiroInterpolator&); + SpiroInterpolator& operator=(const SpiroInterpolator&); +}; + + +Interpolator* +Interpolator::create(InterpolatorType type) { + switch (type) { + case INTERP_LINEAR: + return new Geom::Interpolate::Linear(); + case INTERP_CUBICBEZIER: + return new Geom::Interpolate::CubicBezierFit(); + case INTERP_CUBICBEZIER_JOHAN: + return new Geom::Interpolate::CubicBezierJohan(); + case INTERP_SPIRO: + return new Geom::Interpolate::SpiroInterpolator(); + default: + return new Geom::Interpolate::Linear(); + } +} + } //namespace Interpolate } //namespace Geom namespace Inkscape { namespace LivePathEffect { +static const Util::EnumData<unsigned> InterpolatorTypeData[] = { + {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, + {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, + {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, + {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"} +}; +static const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); + LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : Effect(lpeobject), offset_points(_("Offset points"), _("Offset points"), "offset_points", &wr, this), - sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve."), "sort_points", &wr, this, true) + sort_points(_("Sort points"), _("Sort offset points according to their time value along the curve."), "sort_points", &wr, this, true), + interpolator_type(_("Interpolator type"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path."), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN) { show_orig_path = true; @@ -137,6 +287,7 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : registerParameter( dynamic_cast<Parameter *>(&offset_points) ); registerParameter( dynamic_cast<Parameter *>(&sort_points) ); + registerParameter( dynamic_cast<Parameter *>(&interpolator_type) ); } LPEPowerStroke::~LPEPowerStroke() @@ -195,9 +346,10 @@ LPEPowerStroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & } // create stroke path where points (x,y) := (t, offset) - Geom::Interpolate::CubicBezierJohan interpolator; - Path strokepath = interpolator.interpolateToPath(ts); - Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1); + Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())); + Geom::Path strokepath = interpolator->interpolateToPath(ts); + Geom::Path mirroredpath = strokepath.reverse() * Geom::Scale(1,-1); + delete interpolator; strokepath.append(mirroredpath, Geom::Path::STITCH_DISCONTINUOUS); strokepath.close(); @@ -221,8 +373,9 @@ LPEPowerStroke::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & ts.insert(ts.begin(), last_point - Point(pwd2_in.domain().extent() ,0)); ts.push_back( first_point + Point(pwd2_in.domain().extent() ,0) ); // create stroke path where points (x,y) := (t, offset) - Geom::Interpolate::CubicBezierJohan interpolator; - Path strokepath = interpolator.interpolateToPath(ts); + Geom::Interpolate::Interpolator *interpolator = Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())); + Geom::Path strokepath = interpolator->interpolateToPath(ts); + delete interpolator; // output 2 separate paths D2<Piecewise<SBasis> > patternd2 = make_cuts_independent(strokepath.toPwSb()); diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h index 667c94f53..7a1f3829a 100644 --- a/src/live_effects/lpe-powerstroke.h +++ b/src/live_effects/lpe-powerstroke.h @@ -15,6 +15,7 @@ #include "live_effects/effect.h" #include "live_effects/parameter/bool.h" #include "live_effects/parameter/powerstrokepointarray.h" +#include "live_effects/parameter/enum.h" namespace Inkscape { namespace LivePathEffect { @@ -31,6 +32,7 @@ public: private: PowerStrokePointArrayParam offset_points; BoolParam sort_points; + EnumParam<unsigned> interpolator_type; LPEPowerStroke(const LPEPowerStroke&); LPEPowerStroke& operator=(const LPEPowerStroke&); diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp index 7d5b6c238..671d88a8b 100644 --- a/src/live_effects/lpe-rough-hatches.cpp +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -28,7 +28,7 @@ #include <2geom/bezier-to-sbasis.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/d2.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "ui/widget/scalar.h" #include "libnr/nr-values.h" @@ -309,12 +309,12 @@ LPERoughHatches::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & } Point transformed_org = direction.getOrigin(); Piecewise<SBasis> tilter;//used to bend the hatches - Matrix bend_mat;//used to bend the hatches + Affine bend_mat;//used to bend the hatches if (do_bend.get_value()){ Point bend_dir = -rot90(unit_vector(bender.getVector())); double bend_amount = L2(bender.getVector()); - bend_mat = Matrix(-bend_dir[Y], bend_dir[X], bend_dir[X], bend_dir[Y],0,0); + bend_mat = Affine(-bend_dir[Y], bend_dir[X], bend_dir[X], bend_dir[Y],0,0); transformed_pwd2_in = transformed_pwd2_in * bend_mat; tilter = Piecewise<SBasis>(shift(Linear(-bend_amount),1)); OptRect bbox = bounds_exact( transformed_pwd2_in ); @@ -325,7 +325,7 @@ LPERoughHatches::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & } hatch_dist = Geom::L2(direction.getVector())/5; Point hatches_dir = rot90(unit_vector(direction.getVector())); - Matrix mat(-hatches_dir[Y], hatches_dir[X], hatches_dir[X], hatches_dir[Y],0,0); + Affine mat(-hatches_dir[Y], hatches_dir[X], hatches_dir[X], hatches_dir[Y],0,0); transformed_pwd2_in = transformed_pwd2_in * mat; transformed_org *= mat; diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp index e51b03d15..d7a393197 100644 --- a/src/live_effects/lpe-ruler.cpp +++ b/src/live_effects/lpe-ruler.cpp @@ -40,14 +40,14 @@ static const Util::EnumDataConverter<BorderMarkType> BorderMarkTypeConverter(Bor LPERuler::LPERuler(LivePathEffectObject *lpeobject) : Effect(lpeobject), - mark_distance(_("Mark distance:"), _("Distance between successive ruler marks"), "mark_distance", &wr, this, 20.0), + mark_distance(_("_Mark distance:"), _("Distance between successive ruler marks"), "mark_distance", &wr, this, 20.0), unit(_("Unit:"), _("Unit"), "unit", &wr, this), - mark_length(_("Major length:"), _("Length of major ruler marks"), "mark_length", &wr, this, 14.0), - minor_mark_length(_("Minor length:"), _("Length of minor ruler marks"), "minor_mark_length", &wr, this, 7.0), - major_mark_steps(_("Major steps:"), _("Draw a major mark every ... steps"), "major_mark_steps", &wr, this, 5), - shift(_("Shift marks by:"), _("Shift marks by this many steps"), "shift", &wr, this, 0), + mark_length(_("Ma_jor length:"), _("Length of major ruler marks"), "mark_length", &wr, this, 14.0), + minor_mark_length(_("Mino_r length:"), _("Length of minor ruler marks"), "minor_mark_length", &wr, this, 7.0), + major_mark_steps(_("Major steps_:"), _("Draw a major mark every ... steps"), "major_mark_steps", &wr, this, 5), + shift(_("Shift marks _by:"), _("Shift marks by this many steps"), "shift", &wr, this, 0), mark_dir(_("Mark direction:"), _("Direction of marks (when viewing along the path from start to end)"), "mark_dir", MarkDirTypeConverter, &wr, this, MARKDIR_LEFT), - offset(_("Offset:"), _("Offset of first mark"), "offset", &wr, this, 0.0), + offset(_("_Offset:"), _("Offset of first mark"), "offset", &wr, this, 0.0), border_marks(_("Border marks:"), _("Choose whether to draw marks at the beginning and end of the path"), "border_marks", BorderMarkTypeConverter, &wr, this, BORDERMARK_BOTH) { registerParameter(dynamic_cast<Parameter *>(&unit)); diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index bcdf9df3c..b621f6eca 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -343,7 +343,7 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_ //TODO: put this 4 as a parameter in the UI... //TODO: what if with v=0? double l = tgtlength*(1-tgtlength_rdm)/v_t.length(); - double r = pow(v_t.length(),3)/cross(a_t,v_t); + double r = std::pow(v_t.length(),3)/cross(a_t,v_t); r = sqrt((2*fabs(r)-tgtscale)*tgtscale)/v_t.length(); l=(r<l)?r:l; //collect the tgt segment into output. diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp index 7c8262af6..54554ebb2 100644 --- a/src/live_effects/lpe-spiro.cpp +++ b/src/live_effects/lpe-spiro.cpp @@ -9,7 +9,7 @@ #include "display/curve.h" #include <typeinfo> #include <2geom/pathvector.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> #include <2geom/isnan.h> diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index b94d03c1f..56e73e3a3 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -43,16 +43,16 @@ VonKochRefPathParam::param_readSVGValue(const gchar * strvalue) LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) : Effect(lpeobject), - nbgenerations(_("Nb of generations:"), _("Depth of the recursion --- keep low!!"), "nbgenerations", &wr, this, 1), + nbgenerations(_("N_r of generations:"), _("Depth of the recursion --- keep low!!"), "nbgenerations", &wr, this, 1), generator(_("Generating path:"), _("Path whose segments define the iterated transforms"), "generator", &wr, this, "M0,0 L30,0 M0,10 L10,10 M 20,10 L30,10"), - similar_only(_("Use uniform transforms only"), _("2 consecutive segments are used to reverse/preserve orientation only (otherwise, they define a general transform)."), "similar_only", &wr, this, false), - drawall(_("Draw all generations"), _("If unchecked, draw only the last generation"), "drawall", &wr, this, true), + similar_only(_("_Use uniform transforms only"), _("2 consecutive segments are used to reverse/preserve orientation only (otherwise, they define a general transform)."), "similar_only", &wr, this, false), + drawall(_("Dra_w all generations"), _("If unchecked, draw only the last generation"), "drawall", &wr, this, true), //,draw_boxes(_("Display boxes"), _("Display boxes instead of paths only"), "draw_boxes", &wr, this, true) ref_path(_("Reference segment:"), _("The reference segment. Defaults to the horizontal midline of the bbox."), "ref_path", &wr, this, "M0,0 L10,0"), //refA(_("Ref Start"), _("Left side middle of the reference box"), "refA", &wr, this), //refB(_("Ref End"), _("Right side middle of the reference box"), "refB", &wr, this), //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug. - maxComplexity(_("Max complexity:"), _("Disable effect if the output is too complex"), "maxComplexity", &wr, this, 1000) + maxComplexity(_("_Max complexity:"), _("Disable effect if the output is too complex"), "maxComplexity", &wr, this, 1000) { //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug. registerParameter( dynamic_cast<Parameter *>(&ref_path) ); @@ -88,25 +88,25 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in) } //Collect transform matrices. - Matrix m0; + Affine m0; Geom::Path refpath = ref_path.get_pathvector().front(); Point A = refpath.pointAt(0); Point B = refpath.pointAt(refpath.size()); Point u = B-A; - m0 = Matrix(u[X], u[Y],-u[Y], u[X], A[X], A[Y]); + m0 = Affine(u[X], u[Y],-u[Y], u[X], A[X], A[Y]); //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug. //Point u = refB-refA; - //m0 = Matrix(u[X], u[Y],-u[Y], u[X], refA[X], refA[Y]); + //m0 = Affine(u[X], u[Y],-u[Y], u[X], refA[X], refA[Y]); m0 = m0.inverse(); - std::vector<Matrix> transforms; + std::vector<Affine> transforms; for (unsigned i=0; i<generating_path.size(); i++){ - Matrix m; + Affine m; if(generating_path[i].size()==1){ Point p = generating_path[i].pointAt(0); Point u = generating_path[i].pointAt(1)-p; - m = Matrix(u[X], u[Y],-u[Y], u[X], p[X], p[Y]); + m = Affine(u[X], u[Y],-u[Y], u[X], p[X], p[Y]); m = m0*m; transforms.push_back(m); }else if(generating_path[i].size()>=2){ @@ -118,7 +118,7 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in) v[X] = -u[Y]*sign; v[Y] = u[X]*sign; } - m = Matrix(u[X], u[Y],v[X], v[Y], p[X], p[Y]); + m = Affine(u[X], u[Y],v[X], v[Y], p[X], p[Y]); m = m0*m; transforms.push_back(m); } @@ -133,16 +133,16 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in) for (unsigned k = 0; k < path_in.size(); k++){ path_in_complexity+=path_in[k].size(); } - double complexity = pow(transforms.size(),nbgenerations)*path_in_complexity; + double complexity = std::pow(transforms.size(),nbgenerations)*path_in_complexity; if (drawall.get_value()){ int k = transforms.size(); if(k>1){ - complexity = (pow(k,nbgenerations+1)-1)/(k-1)*path_in_complexity; + complexity = (std::pow(k,nbgenerations+1)-1)/(k-1)*path_in_complexity; }else{ complexity = nbgenerations*k*path_in_complexity; } }else{ - complexity = pow(transforms.size(),nbgenerations)*path_in_complexity; + complexity = std::pow(transforms.size(),nbgenerations)*path_in_complexity; } if (complexity > double(maxComplexity)){ g_warning("VonKoch lpe's output too complex. Effect bypassed."); @@ -288,8 +288,8 @@ LPEVonKoch::resetDefaults(SPItem * item) refpaths.push_back(path); ref_path.set_new_value(refpaths, true); - paths.push_back(path * Matrix(1./3,0,0,1./3, A[X]*2./3, A[Y]*2./3 + boundingbox_Y.extent()/2)); - paths.push_back(path * Matrix(1./3,0,0,1./3, B[X]*2./3, B[Y]*2./3 + boundingbox_Y.extent()/2)); + paths.push_back(path * Affine(1./3,0,0,1./3, A[X]*2./3, A[Y]*2./3 + boundingbox_Y.extent()/2)); + paths.push_back(path * Affine(1./3,0,0,1./3, B[X]*2./3, B[Y]*2./3 + boundingbox_Y.extent()/2)); generator.set_new_value(paths, true); //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug. @@ -300,8 +300,8 @@ LPEVonKoch::resetDefaults(SPItem * item) //std::vector<Geom::Path> paths; //Geom::Path path = Geom::Path( (Point) refA); //path.appendNew<Geom::LineSegment>( (Point) refB ); - //paths.push_back(path * Matrix(1./3,0,0,1./3, refA[X]*2./3, refA[Y]*2./3 + boundingbox_Y.extent()/2)); - //paths.push_back(path * Matrix(1./3,0,0,1./3, refB[X]*2./3, refB[Y]*2./3 + boundingbox_Y.extent()/2)); + //paths.push_back(path * Affine(1./3,0,0,1./3, refA[X]*2./3, refA[Y]*2./3 + boundingbox_Y.extent()/2)); + //paths.push_back(path * Affine(1./3,0,0,1./3, refB[X]*2./3, refB[Y]*2./3 + boundingbox_Y.extent()/2)); //paths.push_back(path); //generator.set_new_value(paths, true); } diff --git a/src/live_effects/lpegroupbbox.cpp b/src/live_effects/lpegroupbbox.cpp index e6fc95f86..2678509a4 100644 --- a/src/live_effects/lpegroupbbox.cpp +++ b/src/live_effects/lpegroupbbox.cpp @@ -28,7 +28,7 @@ GroupBBoxEffect::original_bbox(SPLPEItem *lpeitem, bool absolute) // Get item bounding box SPItem* item = SP_ITEM(lpeitem); - Geom::Matrix transform; + Geom::Affine transform; if (absolute) { transform = item->i2doc_affine(); } diff --git a/src/live_effects/lpeobject-reference.cpp b/src/live_effects/lpeobject-reference.cpp index 9163d1c91..573c8a2fd 100644 --- a/src/live_effects/lpeobject-reference.cpp +++ b/src/live_effects/lpeobject-reference.cpp @@ -45,7 +45,7 @@ bool LPEObjectReference::_acceptObject(SPObject * const obj) const if (IS_LIVEPATHEFFECT(obj)) { SPObject * const owner = getOwner(); /* Refuse references to us or to an ancestor. */ - for ( SPObject *iter = owner ; iter ; iter = SP_OBJECT_PARENT(iter) ) { + for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { if ( iter == obj ) { return false; } @@ -94,7 +94,7 @@ LPEObjectReference::start_listening(LivePathEffectObject* to) return; } lpeobject = to; - lpeobject_repr = SP_OBJECT_REPR(to); + lpeobject_repr = to->getRepr(); _delete_connection = to->connectDelete(sigc::bind(sigc::ptr_fun(&lpeobjectreference_delete_self), this)); _modified_connection = to->connectModified(sigc::bind<2>(sigc::ptr_fun(&lpeobjectreference_source_modified), this)); } diff --git a/src/live_effects/lpeobject-reference.h b/src/live_effects/lpeobject-reference.h index 48d7eb3a5..8d2b406eb 100644 --- a/src/live_effects/lpeobject-reference.h +++ b/src/live_effects/lpeobject-reference.h @@ -11,6 +11,7 @@ #include <forward.h> #include <uri-references.h> +#include <stddef.h> #include <sigc++/sigc++.h> namespace Inkscape { diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp index 389e18d20..1b5ed1d49 100644 --- a/src/live_effects/lpeobject.cpp +++ b/src/live_effects/lpeobject.cpp @@ -125,13 +125,13 @@ LivePathEffectObject::livepatheffect_release(SPObject *object) LivePathEffectObject *lpeobj = LIVEPATHEFFECT(object); - SP_OBJECT_REPR(object)->removeListenerByData(object); + object->getRepr()->removeListenerByData(object); /* - if (SP_OBJECT_DOCUMENT(object)) { + if (object->document) { // Unregister ourselves - sp_document_removeResource(SP_OBJECT_DOCUMENT(object), "livepatheffect", SP_OBJECT(object)); + sp_document_removeResource(object->document, "livepatheffect", object); } if (gradient->ref) { @@ -249,11 +249,11 @@ livepatheffect_on_repr_attr_changed ( Inkscape::XML::Node * /*repr*/, LivePathEffectObject *LivePathEffectObject::fork_private_if_necessary(unsigned int nr_of_allowed_users) { if (hrefcount > nr_of_allowed_users) { - SPDocument *doc = SP_OBJECT_DOCUMENT(this); + SPDocument *doc = this->document; Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *dup_repr = SP_OBJECT_REPR (this)->duplicate(xml_doc); + Inkscape::XML::Node *dup_repr = this->getRepr()->duplicate(xml_doc); - SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(dup_repr, NULL); + SP_DOCUMENT_DEFS(doc)->getRepr()->addChild(dup_repr, NULL); LivePathEffectObject *lpeobj_new = LIVEPATHEFFECT( doc->getObjectByRepr(dup_repr) ); Inkscape::GC::release(dup_repr); diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index ff878e717..cee10bc70 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -67,7 +67,7 @@ public: virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {}; virtual void param_setup_nodepath(Inkscape::NodePath::Path */*np*/) {}; - virtual void param_transform_multiply(Geom::Matrix const& /*postmul*/, bool /*set*/) {}; + virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/) {}; Glib::ustring param_key; Inkscape::UI::Widget::Registry * param_wr; diff --git a/src/live_effects/parameter/path-reference.h b/src/live_effects/parameter/path-reference.h index 3bedecccb..26fce952a 100644 --- a/src/live_effects/parameter/path-reference.h +++ b/src/live_effects/parameter/path-reference.h @@ -13,6 +13,7 @@ #include <forward.h> #include "sp-item.h" #include <uri-references.h> +#include <stddef.h> #include <sigc++/sigc++.h> class Path; diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 8d9b2376f..d652dfd0c 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -235,7 +235,7 @@ PathParam::addCanvasIndicators(SPLPEItem */*lpeitem*/, std::vector<Geom::PathVec * Only applies transform when not referring to other path! */ void -PathParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/) +PathParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) { // only apply transform when not referring to other path if (!href) { diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h index 23ad51417..8c4de7cff 100644 --- a/src/live_effects/parameter/path.h +++ b/src/live_effects/parameter/path.h @@ -16,6 +16,7 @@ #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/path-reference.h" +#include <stddef.h> #include <sigc++/sigc++.h> namespace Inkscape { @@ -49,7 +50,7 @@ public: virtual void param_setup_nodepath(Inkscape::NodePath::Path *np); virtual void addCanvasIndicators(SPLPEItem *lpeitem, std::vector<Geom::PathVector> &hp_vec); - virtual void param_transform_multiply(Geom::Matrix const& /*postmul*/, bool /*set*/); + virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); sigc::signal <void> signal_path_pasted; sigc::signal <void> signal_path_changed; diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index e7abb70ea..550a8517c 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -84,7 +84,7 @@ PointParam::param_newWidget(Gtk::Tooltips * /*tooltips*/) param_effect->getSPDoc() ) ); // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Geom::Matrix transf = desktop->doc2dt(); + Geom::Affine transf = desktop->doc2dt(); pointwdg->setTransform(transf); pointwdg->setValue( *this ); pointwdg->clearProgrammatically(); @@ -114,7 +114,7 @@ PointParam::param_set_and_write_new_value (Geom::Point newpoint) } void -PointParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/) +PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) { param_set_and_write_new_value( (*this) * postmul ); } diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index ec61fcd88..2d4e942c0 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -45,7 +45,7 @@ public: void param_set_and_write_new_value(Geom::Point newpoint); - virtual void param_transform_multiply(Geom::Matrix const& /*postmul*/, bool /*set*/); + virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index c20980193..9d43e8447 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -55,7 +55,7 @@ PowerStrokePointArrayParam::param_newWidget(Gtk::Tooltips * /*tooltips*/) param_effect->getSPDoc() ) ); // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Geom::Matrix transf = desktop->doc2dt(); + Geom::Affine transf = desktop->doc2dt(); pointwdg->setTransform(transf); pointwdg->setValue( *this ); pointwdg->clearProgrammatically(); @@ -71,7 +71,7 @@ PowerStrokePointArrayParam::param_newWidget(Gtk::Tooltips * /*tooltips*/) void -PowerStrokePointArrayParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/) +PowerStrokePointArrayParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) { // param_set_and_write_new_value( (*this) * postmul ); } diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index 06d406dfe..d984a7de5 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -36,7 +36,7 @@ public: virtual Gtk::Widget * param_newWidget(Gtk::Tooltips * tooltips); - virtual void param_transform_multiply(Geom::Matrix const& /*postmul*/, bool /*set*/); + virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); diff --git a/src/live_effects/parameter/vector.cpp b/src/live_effects/parameter/vector.cpp index 5496b52f2..9086ab376 100644 --- a/src/live_effects/parameter/vector.cpp +++ b/src/live_effects/parameter/vector.cpp @@ -112,9 +112,9 @@ VectorParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point } void -VectorParam::param_transform_multiply(Geom::Matrix const& postmul, bool /*set*/) +VectorParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) { - set_and_write_new_values( origin * postmul, vector * postmul.without_translation() ); + set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() ); } diff --git a/src/live_effects/parameter/vector.h b/src/live_effects/parameter/vector.h index a4c29d317..cb7094b7f 100644 --- a/src/live_effects/parameter/vector.h +++ b/src/live_effects/parameter/vector.h @@ -48,7 +48,7 @@ public: void set_and_write_new_values(Geom::Point const &new_origin, Geom::Point const &new_vector); - virtual void param_transform_multiply(Geom::Matrix const &postmul, bool set); + virtual void param_transform_multiply(Geom::Affine const &postmul, bool set); void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); diff --git a/src/lpe-tool-context.cpp b/src/lpe-tool-context.cpp index f25949296..d4c795656 100644 --- a/src/lpe-tool-context.cpp +++ b/src/lpe-tool-context.cpp @@ -426,7 +426,7 @@ lpetool_context_reset_limiting_bbox(SPLPEToolContext *lc) Geom::Point A, B; lpetool_get_limiting_bbox_corners(document, A, B); - Geom::Matrix doc2dt(lc->desktop->doc2dt()); + Geom::Affine doc2dt(lc->desktop->doc2dt()); A *= doc2dt; B *= doc2dt; diff --git a/src/main.cpp b/src/main.cpp index a1b21cc4d..ac0994be6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1298,7 +1298,7 @@ sp_do_export_png(SPDocument *doc) if (sp_export_use_hints) { // retrieve export filename hint - const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename"); + const gchar *fn_hint = o->getRepr()->attribute("inkscape:export-filename"); if (fn_hint) { if (sp_export_png) { g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint); @@ -1313,7 +1313,7 @@ sp_do_export_png(SPDocument *doc) } // retrieve export dpi hints - const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now + const gchar *dpi_hint = o->getRepr()->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now if (dpi_hint) { if (sp_export_dpi || sp_export_width || sp_export_height) { g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint); diff --git a/src/marker.cpp b/src/marker.cpp index e403bd71f..2bd5884b7 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -18,7 +18,7 @@ #include "config.h" #include "libnr/nr-convert2geom.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "svg/svg.h" #include "display/nr-arena-group.h" #include "xml/repr.h" @@ -44,7 +44,7 @@ static Inkscape::XML::Node *sp_marker_write (SPObject *object, Inkscape::XML::Do static NRArenaItem *sp_marker_private_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_marker_private_hide (SPItem *item, unsigned int key); -static void sp_marker_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_marker_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_marker_print (SPItem *item, SPPrintContext *ctx); static void sp_marker_view_remove (SPMarker *marker, SPMarkerView *view, unsigned int destroyitems); @@ -457,7 +457,7 @@ sp_marker_update (SPObject *object, SPCtx *ctx, guint flags) for (v = marker->views; v != NULL; v = v->next) { for (unsigned i = 0 ; i < v->items.size() ; i++) { if (v->items[i]) { - Geom::Matrix tmp = marker->c2p; + Geom::Affine tmp = marker->c2p; nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->items[i]), &tmp); } } @@ -551,7 +551,7 @@ sp_marker_private_hide (SPItem */*item*/, unsigned int /*key*/) * This routine is disabled to break propagation. */ static void -sp_marker_bbox(SPItem const *, NRRect *, Geom::Matrix const &, unsigned const) +sp_marker_bbox(SPItem const *, NRRect *, Geom::Affine const &, unsigned const) { /* Break propagation */ } @@ -613,7 +613,7 @@ sp_marker_show_dimension (SPMarker *marker, unsigned int key, unsigned int size) NRArenaItem * sp_marker_show_instance ( SPMarker *marker, NRArenaItem *parent, unsigned int key, unsigned int pos, - Geom::Matrix const &base, float linewidth) + Geom::Affine const &base, float linewidth) { // do not show marker if linewidth == 0 and markerUnits == strokeWidth // otherwise Cairo will fail to render anything on the tile @@ -636,12 +636,12 @@ sp_marker_show_instance ( SPMarker *marker, NRArenaItem *parent, /* fixme: Position (Lauris) */ nr_arena_item_add_child (parent, v->items[pos], NULL); /* nr_arena_item_unref (v->items[pos]); */ - Geom::Matrix tmp = marker->c2p; + Geom::Affine tmp = marker->c2p; nr_arena_group_set_child_transform((NRArenaGroup *) v->items[pos], &tmp); } } if (v->items[pos]) { - Geom::Matrix m; + Geom::Affine m; if (marker->orient_auto) { m = base; } else { @@ -711,7 +711,7 @@ sp_marker_view_remove (SPMarker *marker, SPMarkerView *view, unsigned int destro delete view; } -const gchar *generate_marker(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Matrix /*transform*/, Geom::Matrix move) +const gchar *generate_marker(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine /*transform*/, Geom::Affine move) { Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = SP_DOCUMENT_DEFS(document)->getRepr(); @@ -736,12 +736,12 @@ const gchar *generate_marker(GSList *reprs, Geom::Rect bounds, SPDocument *docum Inkscape::XML::Node *node = (Inkscape::XML::Node *)(i->data); SPItem *copy = SP_ITEM(mark_object->appendChildRepr(node)); - Geom::Matrix dup_transform; + Geom::Affine dup_transform; if (!sp_svg_transform_read (node->attribute("transform"), &dup_transform)) dup_transform = Geom::identity(); dup_transform *= move; - copy->doWriteTransform(SP_OBJECT_REPR(copy), dup_transform); + copy->doWriteTransform(copy->getRepr(), dup_transform); } Inkscape::GC::release(repr); diff --git a/src/marker.h b/src/marker.h index f2d74a3a6..09461b3a1 100644 --- a/src/marker.h +++ b/src/marker.h @@ -27,7 +27,7 @@ class SPMarkerClass; class SPMarkerView; #include <2geom/rect.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "svg/svg-length.h" #include "enums.h" #include "sp-item-group.h" @@ -61,7 +61,7 @@ struct SPMarker : public SPGroup { unsigned int aspect_clip : 1; /* Child to parent additional transform */ - Geom::Matrix c2p; + Geom::Affine c2p; /* Private views */ SPMarkerView *views; @@ -87,9 +87,9 @@ protected: void sp_marker_show_dimension (SPMarker *marker, unsigned int key, unsigned int size); NRArenaItem *sp_marker_show_instance (SPMarker *marker, NRArenaItem *parent, unsigned int key, unsigned int pos, - Geom::Matrix const &base, float linewidth); + Geom::Affine const &base, float linewidth); void sp_marker_hide (SPMarker *marker, unsigned int key); -const gchar *generate_marker (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Matrix transform, Geom::Matrix move); +const gchar *generate_marker (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); #endif diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index 924cc1989..f1b633865 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -112,6 +112,14 @@ static char const menus_skeleton[] = //" <verb verb-id=\"ViewModePrintColorsPreview\" radio=\"yes\"/>\n" //" <verb verb-id=\"DialogPrintColorsPreview\" />\n" " </submenu>\n" +" <submenu name=\"" N_("_Color display mode") "\">\n" +" <verb verb-id=\"ViewColorModeToggle\"/>\n" +" <verb verb-id=\"ViewColorModeNormal\" radio=\"yes\" default=\"yes\"/>\n" +" <verb verb-id=\"ViewColorModeGrayscale\" radio=\"yes\"/>\n" +// Better location in menu needs to be found +//" <verb verb-id=\"ViewColorModePrintColorsPreview\" radio=\"yes\"/>\n" +//" <verb verb-id=\"DialogPrintColorsPreview\" />\n" +" </submenu>\n" " <separator/>\n" " <verb verb-id=\"ToggleGrid\" />\n" " <verb verb-id=\"ToggleGuides\" />\n" diff --git a/src/message-stack.h b/src/message-stack.h index b5f1dd345..ae8860965 100644 --- a/src/message-stack.h +++ b/src/message-stack.h @@ -14,6 +14,7 @@ #ifndef SEEN_INKSCAPE_MESSAGE_STACK_H #define SEEN_INKSCAPE_MESSAGE_STACK_H +#include <stddef.h> #include <sigc++/sigc++.h> #include <glib.h> #include <stdarg.h> diff --git a/src/object-edit.cpp b/src/object-edit.cpp index f9947b619..553c125a3 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -73,8 +73,8 @@ sp_item_knot_holder(SPItem *item, SPDesktop *desktop) knotholder = new OffsetKnotHolder(desktop, item, NULL); } else if (SP_IS_FLOWTEXT(item) && SP_FLOWTEXT(item)->has_internal_frame()) { knotholder = new FlowtextKnotHolder(desktop, SP_FLOWTEXT(item)->get_frame(NULL), NULL); - } else if ((SP_OBJECT(item)->style->fill.isPaintserver()) - && SP_IS_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style))) { + } else if ((item->style->fill.isPaintserver()) + && SP_IS_PATTERN(item->style->getFillPaintServer())) { knotholder = new KnotHolder(desktop, item, NULL); knotholder->add_pattern_knotholder(); } @@ -157,11 +157,11 @@ RectKnotHolderEntityRX::knot_click(guint state) if (state & GDK_SHIFT_MASK) { /* remove rounding from rectangle */ - SP_OBJECT_REPR(rect)->setAttribute("rx", NULL); - SP_OBJECT_REPR(rect)->setAttribute("ry", NULL); + rect->getRepr()->setAttribute("rx", NULL); + rect->getRepr()->setAttribute("ry", NULL); } else if (state & GDK_CONTROL_MASK) { /* Ctrl-click sets the vertical rounding to be the same as the horizontal */ - SP_OBJECT_REPR(rect)->setAttribute("ry", SP_OBJECT_REPR(rect)->attribute("rx")); + rect->getRepr()->setAttribute("ry", rect->getRepr()->attribute("rx")); } } @@ -215,11 +215,11 @@ RectKnotHolderEntityRY::knot_click(guint state) if (state & GDK_SHIFT_MASK) { /* remove rounding */ - SP_OBJECT_REPR(rect)->setAttribute("rx", NULL); - SP_OBJECT_REPR(rect)->setAttribute("ry", NULL); + rect->getRepr()->setAttribute("rx", NULL); + rect->getRepr()->setAttribute("ry", NULL); } else if (state & GDK_CONTROL_MASK) { /* Ctrl-click sets the vertical rounding to be the same as the horizontal */ - SP_OBJECT_REPR(rect)->setAttribute("rx", SP_OBJECT_REPR(rect)->attribute("ry")); + rect->getRepr()->setAttribute("rx", rect->getRepr()->attribute("ry")); } } @@ -474,7 +474,7 @@ Box3DKnotHolderEntity::knot_set_generic(SPItem *item, unsigned int knot_id, Geom g_assert(item != NULL); SPBox3D *box = SP_BOX3D(item); - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); Box3D::Axis movement; if ((knot_id < 4) != (state & GDK_SHIFT_MASK)) { @@ -650,7 +650,7 @@ Box3DKnotHolderEntityCenter::knot_set(Geom::Point const &new_pos, Geom::Point co Geom::Point const s = snap_knot_position(new_pos); SPBox3D *box = SP_BOX3D(item); - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); box3d_set_center (SP_BOX3D(item), s * i2d, origin * i2d, !(state & GDK_SHIFT_MASK) ? Box3D::XY : Box3D::Z, state & GDK_CONTROL_MASK); diff --git a/src/object-hierarchy.cpp b/src/object-hierarchy.cpp index 55af55f28..e6a1618a7 100644 --- a/src/object-hierarchy.cpp +++ b/src/object-hierarchy.cpp @@ -70,10 +70,10 @@ void ObjectHierarchy::_addTop(SPObject *senior, SPObject *junior) { g_assert(junior != NULL); g_assert(senior != NULL); - SPObject *object=SP_OBJECT_PARENT(junior); + SPObject *object = junior->parent; do { _addTop(object); - object = SP_OBJECT_PARENT(object); + object = object->parent; } while ( object != senior ); } @@ -160,7 +160,7 @@ void ObjectHierarchy::_addBottom(SPObject *senior, SPObject *junior) { g_assert(senior != NULL); if ( junior != senior ) { - _addBottom(senior, SP_OBJECT_PARENT(junior)); + _addBottom(senior, junior->parent); _addBottom(junior); } } diff --git a/src/object-hierarchy.h b/src/object-hierarchy.h index 8a6d4aedc..f6ae4f15d 100644 --- a/src/object-hierarchy.h +++ b/src/object-hierarchy.h @@ -14,6 +14,7 @@ #include <exception> #include <list> +#include <stddef.h> #include <sigc++/connection.h> #include <sigc++/signal.h> #include <glib/gmessages.h> diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 43651f002..1e2f71c95 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -84,7 +84,7 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent, bool const &first_point, Geom::Rect const &bbox_to_snap, bool const clip_or_mask, - Geom::Matrix const additional_affine) const // transformation of the item being clipped / masked + Geom::Affine const additional_affine) const // transformation of the item being clipped / masked { if (!ThisSnapperMightSnap()) { return; @@ -198,7 +198,7 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapSourceType const &t, } for (std::vector<SnapCandidateItem>::const_iterator i = _candidates->begin(); i != _candidates->end(); i++) { - //Geom::Matrix i2doc(Geom::identity()); + //Geom::Affine i2doc(Geom::identity()); SPItem *root_item = (*i).item; if (SP_IS_USE((*i).item)) { root_item = sp_use_root(SP_USE((*i).item)); @@ -378,7 +378,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Geom::Point /*p*/, for (std::vector<SnapCandidateItem>::const_iterator i = _candidates->begin(); i != _candidates->end(); i++) { /* Transform the requested snap point to this item's coordinates */ - Geom::Matrix i2doc(Geom::identity()); + Geom::Affine i2doc(Geom::identity()); SPItem *root_item = NULL; /* We might have a clone at hand, so make sure we get the root item */ if (SP_IS_USE((*i).item)) { @@ -414,8 +414,13 @@ void Inkscape::ObjectSnapper::_collectPaths(Geom::Point /*p*/, very_complex_path = sp_nodes_in_path(SP_PATH(root_item)) > 500; } - if (!very_lenghty_prose && !very_complex_path) { - SPCurve *curve = curve_for_item(root_item); + if (!very_lenghty_prose && !very_complex_path && root_item) { + SPCurve *curve = NULL; + if (SP_IS_SHAPE(root_item)) { + curve = SP_SHAPE(root_item)->getCurve(); + } else if (SP_IS_TEXT(root_item) || SP_IS_FLOWTEXT(root_item)) { + curve = te_get_layout(root_item)->convertToCurves(); + } if (curve) { // We will get our own copy of the pathvector, which must be freed at some point diff --git a/src/object-snapper.h b/src/object-snapper.h index 6bde3dd39..6e3cc620f 100644 --- a/src/object-snapper.h +++ b/src/object-snapper.h @@ -71,7 +71,7 @@ private: bool const &first_point, Geom::Rect const &bbox_to_snap, bool const _clip_or_mask, - Geom::Matrix const additional_affine) const; + Geom::Affine const additional_affine) const; void _snapNodes(SnappedConstraints &sc, Inkscape::SnapCandidatePoint const &p, // in desktop coordinates diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index bec3c5cbf..607d0ab6a 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -95,8 +95,9 @@ sp_selected_path_combine(SPDesktop *desktop) for (GSList *i = items; i != NULL; i = i->next) { // going from top to bottom SPItem *item = (SPItem *) i->data; - if (!SP_IS_PATH(item)) + if (!SP_IS_PATH(item)) { continue; + } if (!did) { selection->clear(); @@ -106,17 +107,17 @@ sp_selected_path_combine(SPDesktop *desktop) SPCurve *c = sp_path_get_curve_for_edit(SP_PATH(item)); if (first == NULL) { // this is the topmost path first = item; - parent = SP_OBJECT_REPR(first)->parent(); - position = SP_OBJECT_REPR(first)->position(); - id = SP_OBJECT_REPR(first)->attribute("id"); - transform = SP_OBJECT_REPR(first)->attribute("transform"); + parent = first->getRepr()->parent(); + position = first->getRepr()->position(); + id = first->getRepr()->attribute("id"); + transform = first->getRepr()->attribute("transform"); // FIXME: merge styles of combined objects instead of using the first one's style - style = g_strdup(SP_OBJECT_REPR(first)->attribute("style")); - path_effect = g_strdup(SP_OBJECT_REPR(first)->attribute("inkscape:path-effect")); + style = g_strdup(first->getRepr()->attribute("style")); + path_effect = g_strdup(first->getRepr()->attribute("inkscape:path-effect")); //c->transform(item->transform); curve = c; } else { - c->transform(item->getRelativeTransform(SP_OBJECT(first))); + c->transform(item->getRelativeTransform(first)); curve->append(c, false); c->unref(); } @@ -124,17 +125,18 @@ sp_selected_path_combine(SPDesktop *desktop) // unless this is the topmost object, if (item != first) { // reduce position only if the same parent - if (SP_OBJECT_REPR(item)->parent() == parent) + if (item->getRepr()->parent() == parent) { position--; + } // delete the object for real, so that its clones can take appropriate action - SP_OBJECT(item)->deleteObject(); + item->deleteObject(); } } g_slist_free(items); if (did) { - SP_OBJECT(first)->deleteObject(false); + first->deleteObject(false); // delete the topmost. Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); @@ -214,21 +216,21 @@ sp_selected_path_break_apart(SPDesktop *desktop) did = true; - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); - gint pos = SP_OBJECT_REPR(item)->position(); - char const *id = SP_OBJECT_REPR(item)->attribute("id"); + Inkscape::XML::Node *parent = item->getRepr()->parent(); + gint pos = item->getRepr()->position(); + char const *id = item->getRepr()->attribute("id"); // XML Tree being used directly here while it shouldn't be... - gchar *style = g_strdup(SP_OBJECT(item)->getRepr()->attribute("style")); + gchar *style = g_strdup(item->getRepr()->attribute("style")); // XML Tree being used directly here while it shouldn't be... - gchar *path_effect = g_strdup(SP_OBJECT(item)->getRepr()->attribute("inkscape:path-effect")); + gchar *path_effect = g_strdup(item->getRepr()->attribute("inkscape:path-effect")); Geom::PathVector apv = curve->get_pathvector() * SP_ITEM(path)->transform; curve->unref(); // it's going to resurrect as one of the pieces, so we delete without advertisement - SP_OBJECT(item)->deleteObject(false); + item->deleteObject(false); curve = new SPCurve(apv); g_assert(curve != NULL); @@ -380,7 +382,7 @@ sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_selec if (SP_IS_BOX3D(item)) { // convert 3D box to ordinary group of paths; replace the old element in 'selected' with the new group - Inkscape::XML::Node *repr = SP_OBJECT_REPR(box3d_convert_to_group(SP_BOX3D(item))); + Inkscape::XML::Node *repr = box3d_convert_to_group(SP_BOX3D(item))->getRepr(); if (repr) { *to_select = g_slist_prepend (*to_select, repr); @@ -416,18 +418,18 @@ sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_selec *selected = g_slist_remove (*selected, item); // remember the position of the item - gint pos = SP_OBJECT_REPR(item)->position(); + gint pos = item->getRepr()->position(); // remember parent - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); + Inkscape::XML::Node *parent = item->getRepr()->parent(); // remember id - char const *id = SP_OBJECT_REPR(item)->attribute("id"); + char const *id = item->getRepr()->attribute("id"); // remember title gchar *title = item->title(); // remember description gchar *desc = item->desc(); // It's going to resurrect, so we delete without notifying listeners. - SP_OBJECT(item)->deleteObject(false); + item->deleteObject(false); // restore id repr->setAttribute("id", id); @@ -461,26 +463,26 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) if (!item) return NULL; - Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(item)->document(); + Inkscape::XML::Document *xml_doc = item->getRepr()->document(); if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { // Special treatment for text: convert each glyph to separate path, then group the paths Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g"); - g_repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform")); + g_repr->setAttribute("transform", item->getRepr()->attribute("transform")); /* Mask */ - gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); + gchar *mask_str = (gchar *) item->getRepr()->attribute("mask"); if ( mask_str ) g_repr->setAttribute("mask", mask_str); /* Clip path */ - gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); + gchar *clip_path_str = (gchar *) item->getRepr()->attribute("clip-path"); if ( clip_path_str ) g_repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ - g_repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); - g_repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); + g_repr->setAttribute("inkscape:transform-center-x", item->getRepr()->attribute("inkscape:transform-center-x"), false); + g_repr->setAttribute("inkscape:transform-center-y", item->getRepr()->attribute("inkscape:transform-center-y"), false); /* Whole text's style */ - gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(item), - SP_OBJECT_STYLE(SP_OBJECT_PARENT(item))); + gchar *style_str = sp_style_write_difference(item->style, + item->parent->style); g_repr->setAttribute("style", style_str); g_free(style_str); Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); @@ -497,11 +499,11 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) if (!rawptr || !SP_IS_OBJECT(rawptr)) // no source for glyph, abort break; pos_obj = SP_OBJECT(rawptr); - while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) { - pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style + while (SP_IS_STRING(pos_obj) && pos_obj->parent) { + pos_obj = pos_obj->parent; // SPStrings don't have style } - gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(pos_obj), - SP_OBJECT_STYLE(SP_OBJECT_PARENT(pos_obj))); + gchar *style_str = sp_style_write_difference(pos_obj->style, + pos_obj->parent->style); // get path from iter to iter_next: SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next); @@ -555,26 +557,26 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); /* Transformation */ - repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform")); + repr->setAttribute("transform", item->getRepr()->attribute("transform")); /* Style */ - gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(item), - SP_OBJECT_STYLE(SP_OBJECT_PARENT(item))); + gchar *style_str = sp_style_write_difference(item->style, + item->parent->style); repr->setAttribute("style", style_str); g_free(style_str); /* Mask */ - gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); + gchar *mask_str = (gchar *) item->getRepr()->attribute("mask"); if ( mask_str ) repr->setAttribute("mask", mask_str); /* Clip path */ - gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); + gchar *clip_path_str = (gchar *) item->getRepr()->attribute("clip-path"); if ( clip_path_str ) repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ - repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); - repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); + repr->setAttribute("inkscape:transform-center-x", item->getRepr()->attribute("inkscape:transform-center-x"), false); + repr->setAttribute("inkscape:transform-center-y", item->getRepr()->attribute("inkscape:transform-center-y"), false); /* Definition */ gchar *def_str = sp_svg_write_path(curve->get_pathvector()); @@ -605,8 +607,9 @@ sp_selected_path_reverse(SPDesktop *desktop) for (GSList *i = items; i != NULL; i = i->next) { - if (!SP_IS_PATH(i->data)) + if (!SP_IS_PATH(i->data)) { continue; + } did = true; SPPath *path = SP_PATH(i->data); @@ -615,18 +618,18 @@ sp_selected_path_reverse(SPDesktop *desktop) gchar *str = sp_svg_write_path(rcurve->get_pathvector()); if ( sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(path)) ) { - SP_OBJECT_REPR(path)->setAttribute("inkscape:original-d", str); + path->getRepr()->setAttribute("inkscape:original-d", str); } else { - SP_OBJECT_REPR(path)->setAttribute("d", str); + path->getRepr()->setAttribute("d", str); } g_free(str); rcurve->unref(); // reverse nodetypes order (Bug #179866) - gchar *nodetypes = g_strdup(SP_OBJECT_REPR(path)->attribute("sodipodi:nodetypes")); + gchar *nodetypes = g_strdup(path->getRepr()->attribute("sodipodi:nodetypes")); if ( nodetypes ) { - SP_OBJECT_REPR(path)->setAttribute("sodipodi:nodetypes", g_strreverse(nodetypes)); + path->getRepr()->setAttribute("sodipodi:nodetypes", g_strreverse(nodetypes)); g_free(nodetypes); } } diff --git a/src/pen-context.cpp b/src/pen-context.cpp index 6778d4bcc..607bdaedc 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -31,6 +31,7 @@ #include "message-context.h" #include "preferences.h" #include "sp-path.h" +#include "display/sp-canvas.h" #include "display/curve.h" #include "pixmaps/cursor-pen.xpm" #include "display/canvas-bpath.h" diff --git a/src/pencil-context.cpp b/src/pencil-context.cpp index 0717724de..a873eb6fc 100644 --- a/src/pencil-context.cpp +++ b/src/pencil-context.cpp @@ -41,6 +41,7 @@ #include "document.h" #include "desktop-style.h" #include "macros.h" +#include "display/sp-canvas.h" #include "display/curve.h" #include "livarot/Path.h" diff --git a/src/persp3d-reference.cpp b/src/persp3d-reference.cpp index 509332b52..895eac6f2 100644 --- a/src/persp3d-reference.cpp +++ b/src/persp3d-reference.cpp @@ -55,7 +55,7 @@ Persp3DReference::start_listening(Persp3D* to) return; } persp = to; - persp_repr = SP_OBJECT_REPR(to); + persp_repr = to->getRepr(); _delete_connection = to->connectDelete(sigc::bind(sigc::ptr_fun(&persp3dreference_delete_self), this)); _modified_connection = to->connectModified(sigc::bind<2>(sigc::ptr_fun(&persp3dreference_source_modified), this)); } diff --git a/src/persp3d-reference.h b/src/persp3d-reference.h index 992d34f60..28744b2fa 100644 --- a/src/persp3d-reference.h +++ b/src/persp3d-reference.h @@ -11,6 +11,7 @@ */ #include "uri-references.h" +#include <stddef.h> #include <sigc++/sigc++.h> #include "persp3d.h" diff --git a/src/persp3d.cpp b/src/persp3d.cpp index 74208444b..d43e6b2c5 100644 --- a/src/persp3d.cpp +++ b/src/persp3d.cpp @@ -134,7 +134,7 @@ static void persp3d_build(SPObject *object, SPDocument *document, Inkscape::XML: static void persp3d_release(SPObject *object) { Persp3D *persp = SP_PERSP3D(object); delete persp->perspective_impl; - SP_OBJECT_REPR(object)->removeListenerByData(object); + object->getRepr()->removeListenerByData(object); } @@ -244,10 +244,10 @@ Persp3D *persp3d_create_xml_element(SPDocument *document, Persp3DImpl *dup) {// g_free (str); /* Append the new persp3d to defs */ - SP_OBJECT_REPR(defs)->addChild(repr, NULL); + defs->getRepr()->addChild(repr, NULL); Inkscape::GC::release(repr); - return (Persp3D *) SP_OBJECT(defs)->get_child_by_repr (repr); + return reinterpret_cast<Persp3D *>( defs->get_child_by_repr(repr) ); } Persp3D *persp3d_document_first_persp(SPDocument *document) @@ -338,7 +338,7 @@ persp3d_toggle_VP (Persp3D *persp, Proj::Axis axis, bool set_undo) { // On the other hand, vp_drag_sel_modified() would update all boxes; // here we can confine ourselves to the boxes of this particular perspective. persp3d_update_box_reprs (persp); - SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT); + persp->updateRepr(SP_OBJECT_WRITE_EXT); if (set_undo) { DocumentUndo::done(sp_desktop_document(inkscape_active_desktop()), SP_VERB_CONTEXT_3DBOX, _("Toggle vanishing point")); @@ -376,7 +376,7 @@ persp3d_rotate_VP (Persp3D *persp, Proj::Axis axis, double angle, bool alt_press persp->perspective_impl->tmat.set_infinite_direction (axis, a); persp3d_update_box_reprs (persp); - SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT); + persp->updateRepr(SP_OBJECT_WRITE_EXT); } void @@ -385,10 +385,10 @@ persp3d_update_with_point (Persp3DImpl *persp_impl, Proj::Axis const axis, Proj: } void -persp3d_apply_affine_transformation (Persp3D *persp, Geom::Matrix const &xform) { +persp3d_apply_affine_transformation (Persp3D *persp, Geom::Affine const &xform) { persp->perspective_impl->tmat *= xform; persp3d_update_box_reprs(persp); - SP_OBJECT(persp)->updateRepr(SP_OBJECT_WRITE_EXT); + persp->updateRepr(SP_OBJECT_WRITE_EXT); } gchar * @@ -455,7 +455,7 @@ persp3d_update_box_reprs (Persp3D *persp) { if (persp_impl->boxes.empty()) return; for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) { - SP_OBJECT(*i)->updateRepr(SP_OBJECT_WRITE_EXT); + (*i)->updateRepr(SP_OBJECT_WRITE_EXT); box3d_set_z_orders(*i); } } @@ -504,7 +504,7 @@ persp3d_absorb(Persp3D *persp1, Persp3D *persp2) { for (std::list<SPBox3D *>::iterator i = boxes_of_persp2.begin(); i != boxes_of_persp2.end(); ++i) { box3d_switch_perspectives((*i), persp2, persp1, true); - SP_OBJECT(*i)->updateRepr(SP_OBJECT_WRITE_EXT); // so that undo/redo can do its job properly + (*i)->updateRepr(SP_OBJECT_WRITE_EXT); // so that undo/redo can do its job properly } } @@ -583,7 +583,7 @@ persp3d_print_all_selected() { for (std::list<Persp3D *>::iterator j = sel_persps.begin(); j != sel_persps.end(); ++j) { Persp3D *persp = SP_PERSP3D(*j); Persp3DImpl *persp_impl = persp->perspective_impl; - g_print (" %s (%d): ", SP_OBJECT_REPR(persp)->attribute("id"), persp->perspective_impl->my_counter); + g_print (" %s (%d): ", persp->getRepr()->attribute("id"), persp->perspective_impl->my_counter); for (std::vector<SPBox3D *>::iterator i = persp_impl->boxes.begin(); i != persp_impl->boxes.end(); ++i) { g_print ("%d ", (*i)->my_counter); @@ -596,7 +596,7 @@ persp3d_print_all_selected() { void print_current_persp3d(gchar *func_name, Persp3D *persp) { g_print ("%s: current_persp3d is now %s\n", func_name, - persp ? SP_OBJECT_REPR(persp)->attribute("id") : "NULL"); + persp ? persp->getRepr()->attribute("id") : "NULL"); } /* diff --git a/src/persp3d.h b/src/persp3d.h index 44b6d2435..db4971635 100644 --- a/src/persp3d.h +++ b/src/persp3d.h @@ -74,7 +74,7 @@ void persp3d_toggle_VP (Persp3D *persp, Proj::Axis axis, bool set_undo = true); void persp3d_toggle_VPs (std::list<Persp3D *>, Proj::Axis axis); void persp3d_set_VP_state (Persp3D *persp, Proj::Axis axis, Proj::VPState state); void persp3d_rotate_VP (Persp3D *persp, Proj::Axis axis, double angle, bool alt_pressed); // angle is in degrees -void persp3d_apply_affine_transformation (Persp3D *persp, Geom::Matrix const &xform); +void persp3d_apply_affine_transformation (Persp3D *persp, Geom::Affine const &xform); void persp3d_add_box (Persp3D *persp, SPBox3D *box); void persp3d_remove_box (Persp3D *persp, SPBox3D *box); diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 671f76e57..5becb2770 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -106,8 +106,8 @@ static char const preferences_skeleton[] = " <group id=\"cp5\" name=\"" N_("Tracing") "\" width=\"50\" mass=\"0\" wiggle=\"0.0\" angle=\"0.0\" thinning=\"0.0\" tremor=\"0.0\" flatness=\"0\" cap_rounding=\"0.0\" tracebackground=\"1\" usepressure=\"1\" usetilt=\"1\"/>\n" " </group>\n" " </eventcontext>\n" -" <eventcontext id=\"eraser\" mode=\"0\" style=\"fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;\"\n" -" mass=\"0.02\" drag=\"1\" angle=\"30\" width=\"0.15\" thinning=\"0.1\" flatness=\"0.0\" cap_rounding=\"1.4\" usecurrent=\"0\"\n" +" <eventcontext id=\"eraser\" mode=\"1\" style=\"fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;\"\n" +" mass=\"0.02\" drag=\"1\" angle=\"30\" width=\"10\" thinning=\"0.1\" flatness=\"0.0\" cap_rounding=\"1.4\" usecurrent=\"0\"\n" " tracebackground=\"0\" usepressure=\"1\" usetilt=\"0\" selcue=\"1\">\n" " </eventcontext>\n" " <eventcontext id=\"lpetool\" mode=\"drag\" style=\"fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;\">\n" @@ -118,7 +118,7 @@ static char const preferences_skeleton[] = " style=\"fill:black;fill-opacity:1;stroke:none;font-family:Sans;font-style:normal;font-weight:normal;font-size:40px;\" selcue=\"1\"/>\n" " <eventcontext id=\"nodes\" selcue=\"1\" gradientdrag=\"1\" highlight_color=\"4278190335\" pathflash_enabled=\"1\" pathflash_unselected=\"0\" pathflash_timeout=\"500\" show_handles=\"1\" show_outline=\"0\" sculpting_profile=\"1\" single_node_transform_handles=\"0\" show_transform_handles=\"0\" live_outline=\"1\" live_objects=\"1\" show_helperpath=\"0\" x=\"0\" y=\"0\" edit_clipping_paths=\"0\" edit_masks=\"0\" />\n" " <eventcontext id=\"tweak\" selcue=\"0\" gradientdrag=\"0\" show_handles=\"0\" width=\"0.2\" force=\"0.2\" fidelity=\"0.5\" usepressure=\"1\" style=\"fill:red;stroke:none;\" usecurrent=\"0\"/>\n" -" <eventcontext id=\"spray\" usepressure=\"1\" width=\"15\" population=\"70\" mode=\"1\" rotation_variation=\"0\" scale_variation=\"0\" standard_deviation=\"70\" mean=\"0\"/>\n" +" <eventcontext id=\"spray\" selcue=\"1\" gradientdrag=\"0\" usepressure=\"1\" width=\"15\" population=\"70\" mode=\"1\" rotation_variation=\"0\" scale_variation=\"0\" standard_deviation=\"70\" mean=\"0\"/>\n" " <eventcontext id=\"gradient\" selcue=\"1\"/>\n" " <eventcontext id=\"zoom\" selcue=\"1\" gradientdrag=\"0\"/>\n" " <eventcontext id=\"dropper\" selcue=\"1\" gradientdrag=\"1\" pick=\"1\" setalpha=\"1\"/>\n" @@ -277,7 +277,7 @@ static char const preferences_skeleton[] = " <group id=\"autoscrolldistance\" value=\"-10\"/>\n" " <group id=\"simplifythreshold\" value=\"0.002\"/>\n" " <group id=\"bitmapoversample\" value=\"1\"/>\n" -" <group id=\"bitmapeditor\" value=\"0\" choices=\"gimp,krita,gpaint,kolourpaint,mtpaint,cinepaint\"/>\n" +" <group id=\"bitmapeditor\" value=\"gimp\"/>\n" " <group id=\"bitmapautoreload\" value=\"1\"/>\n" " <group id=\"dialogtype\" value=\"1\"/>\n" " <group id=\"dock\" " diff --git a/src/preferences.cpp b/src/preferences.cpp index 3815d44c5..94fbc7257 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -1,5 +1,5 @@ /** @file - * @brief Singleton class to access the preferences file - implementation + * Singleton class to access the preferences file - implementation. */ /* Authors: * Krzysztof KosiĆski <tweenk.pl@gmail.com> @@ -59,7 +59,7 @@ static void file_add_recent(gchar const *uri) // private inner class definition /** - * @brief XML - prefs observer bridge + * XML - prefs observer bridge. * * This is an XML node observer that watches for changes in the XML document storing the preferences. * It is used to implement preference observers. @@ -110,7 +110,7 @@ Preferences::~Preferences() } /** - * @brief Load internal defaults + * Load internal defaults. * * In the future this will try to load the system-wide file before falling * back to the internal defaults. @@ -121,7 +121,7 @@ void Preferences::_loadDefaults() } /** - * @brief Load the user's customized preferences + * Load the user's customized preferences. * * Tries to load the user's preferences.xml file. If there is none, creates it. */ @@ -255,7 +255,7 @@ static void migrateDetails( Inkscape::XML::Document *from, Inkscape::XML::Docume } /** - * @brief Flush all pref changes to the XML file + * Flush all pref changes to the XML file. */ void Preferences::save() { @@ -364,9 +364,10 @@ void Preferences::migrate( std::string const& legacyDir, std::string const& pref // Now for the meat. /** - * @brief Get names of all entries in the specified path - * @param path Preference path to query - * @return A vector containing all entries in the given directory + * Get names of all entries in the specified path. + * + * @param path Preference path to query. + * @return A vector containing all entries in the given directory. */ std::vector<Preferences::Entry> Preferences::getAllEntries(Glib::ustring const &path) { @@ -383,9 +384,10 @@ std::vector<Preferences::Entry> Preferences::getAllEntries(Glib::ustring const & } /** - * @brief Get the paths to all subdirectories of the specified path - * @param path Preference path to query - * @return A vector containing absolute paths to all subdirectories in the given path + * Get the paths to all subdirectories of the specified path. + * + * @param path Preference path to query. + * @return A vector containing absolute paths to all subdirectories in the given path. */ std::vector<Glib::ustring> Preferences::getAllDirs(Glib::ustring const &path) { @@ -411,9 +413,10 @@ Preferences::Entry const Preferences::getEntry(Glib::ustring const &pref_path) // setter methods /** - * @brief Set a boolean attribute of a preference - * @param pref_path Path of the preference to modify - * @param value The new value of the pref attribute + * Set a boolean attribute of a preference. + * + * @param pref_path Path of the preference to modify. + * @param value The new value of the pref attribute. */ void Preferences::setBool(Glib::ustring const &pref_path, bool value) { @@ -424,9 +427,10 @@ void Preferences::setBool(Glib::ustring const &pref_path, bool value) } /** - * @brief Set an integer attribute of a preference - * @param pref_path Path of the preference to modify - * @param value The new value of the pref attribute + * Set an integer attribute of a preference. + * + * @param pref_path Path of the preference to modify. + * @param value The new value of the pref attribute. */ void Preferences::setInt(Glib::ustring const &pref_path, int value) { @@ -436,9 +440,10 @@ void Preferences::setInt(Glib::ustring const &pref_path, int value) } /** - * @brief Set a floating point attribute of a preference - * @param pref_path Path of the preference to modify - * @param value The new value of the pref attribute + * Set a floating point attribute of a preference. + * + * @param pref_path Path of the preference to modify. + * @param value The new value of the pref attribute. */ void Preferences::setDouble(Glib::ustring const &pref_path, double value) { @@ -455,9 +460,10 @@ void Preferences::setColor(Glib::ustring const &pref_path, guint32 value) } /** - * @brief Set a string attribute of a preference - * @param pref_path Path of the preference to modify - * @param value The new value of the pref attribute + * Set a string attribute of a preference. + * + * @param pref_path Path of the preference to modify. + * @param value The new value of the pref attribute. */ void Preferences::setString(Glib::ustring const &pref_path, Glib::ustring const &value) { @@ -486,7 +492,7 @@ void Preferences::mergeStyle(Glib::ustring const &pref_path, SPCSSAttr *style) namespace { /** - * @brief Structure that holds additional information for registered Observers + * Structure that holds additional information for registered Observers. */ struct _ObserverData { Inkscape::XML::Node *_node; ///< Node at which the wrapping PrefNodeObserver is registered @@ -542,7 +548,7 @@ void Preferences::PrefNodeObserver::notifyAttributeChanged(XML::Node &node, GQua } /** - * @brief Find the XML node to observe + * Find the XML node to observe. */ XML::Node *Preferences::_findObserverNode(Glib::ustring const &pref_path, Glib::ustring &node_key, Glib::ustring &attr_key, bool create) { @@ -613,11 +619,12 @@ void Preferences::removeObserver(Observer &o) /** - * @brief Get the XML node corresponding to the given pref key - * @param pref_key Preference key (path) to get - * @param create Whether to create the corresponding node if it doesn't exist - * @param separator The character used to separate parts of the pref key - * @return XML node corresponding to the specified key + * Get the XML node corresponding to the given pref key. + * + * @param pref_key Preference key (path) to get. + * @param create Whether to create the corresponding node if it doesn't exist. + * @param separator The character used to separate parts of the pref key. + * @return XML node corresponding to the specified key. * * Derived from former inkscape_get_repr(). Private because it assumes that the backend is * a flat XML file, which may not be the case e.g. if we are using GConf (in future). @@ -660,8 +667,11 @@ Inkscape::XML::Node *Preferences::_getNode(Glib::ustring const &pref_key, bool c node = child; } g_strfreev(splits); + splits = 0; return node; } else { + g_strfreev(splits); + splits = 0; return NULL; } } diff --git a/src/preferences.h b/src/preferences.h index 5e1ccf9d6..c79a7377d 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -1,5 +1,5 @@ /** @file - * @brief Singleton class to access the preferences file in a convenient way. + * Singleton class to access the preferences file in a convenient way. */ /* Authors: * Krzysztof Kosi_ski <tweenk.pl@gmail.com> @@ -33,7 +33,7 @@ public: }; /** - * @brief Preference storage class. + * Preference storage class. * * This is a singleton that allows one to access the user preferences stored in * the preferences.xml file. The preferences are stored in a file system-like @@ -63,7 +63,7 @@ public: class Observer; /** - * @brief Base class for preference observers + * Base class for preference observers. * * If you want to watch for changes in the preferences, you'll have to * derive a class from this one and override the notify() method. @@ -73,7 +73,7 @@ public: public: /** - * @brief Constructor. + * Constructor. * * Since each Observer is assigned to a single path, the base * constructor takes this path as an argument. This prevents one from @@ -88,15 +88,16 @@ public: * Watching the preference "/options/some_group/some_option" will only * generate notifications when this single preference changes. * - * @param path Preference path the observer should watch + * @param path Preference path the observer should watch. */ Observer(Glib::ustring const &path); virtual ~Observer(); /** - * @brief Notification about a preference change + * Notification about a preference change. + * * @param new_val Entry object containing information about - * the modified preference + * the modified preference. */ virtual void notify(Preferences::Entry const &new_val) = 0; @@ -107,7 +108,7 @@ public: /** - * @brief Data type representing a typeless value of a preference + * Data type representing a typeless value of a preference. * * This is passed to the observer in the notify() method. * To retrieve useful data from it, use its member functions. Setting @@ -122,75 +123,80 @@ public: Entry(Entry const &other) : _pref_path(other._pref_path), _value(other._value) {} /** - * @brief Check whether the received entry is valid. + * Check whether the received entry is valid. + * * @return If false, the default value will be returned by the getters. */ bool isValid() const { return _value != NULL; } /** - * @brief Interpret the preference as a Boolean value. - * @param def Default value if the preference is not set + * Interpret the preference as a Boolean value. + * + * @param def Default value if the preference is not set. */ inline bool getBool(bool def=false) const; /** - * @brief Interpret the preference as an integer. - * @param def Default value if the preference is not set + * Interpret the preference as an integer. + * + * @param def Default value if the preference is not set. */ inline int getInt(int def=0) const; /** - * @brief Interpret the preference as a limited integer. + * Interpret the preference as a limited integer. * * This method will return the default value if the interpreted value is * larger than @c max or smaller than @c min. Do not use to store * Boolean values as integers. * - * @param def Default value if the preference is not set - * @param min Minimum value allowed to return - * @param max Maximum value allowed to return + * @param def Default value if the preference is not set. + * @param min Minimum value allowed to return. + * @param max Maximum value allowed to return. */ inline int getIntLimited(int def=0, int min=INT_MIN, int max=INT_MAX) const; /** - * @brief Interpret the preference as a floating point value. - * @param def Default value if the preference is not set + * Interpret the preference as a floating point value. + * + * @param def Default value if the preference is not set. */ inline double getDouble(double def=0.0) const; /** - * @brief Interpret the preference as a limited floating point value. + * Interpret the preference as a limited floating point value. * * This method will return the default value if the interpreted value is * larger than @c max or smaller than @c min. * - * @param def Default value if the preference is not set - * @param min Minimum value allowed to return - * @param max Maximum value allowed to return + * @param def Default value if the preference is not set. + * @param min Minimum value allowed to return. + * @param max Maximum value allowed to return. */ inline double getDoubleLimited(double def=0.0, double min=DBL_MIN, double max=DBL_MAX) const; /** - * @brief Interpret the preference as an UTF-8 string. + * Interpret the preference as an UTF-8 string. * * To store a filename, convert it using Glib::filename_to_utf8(). */ inline Glib::ustring getString() const; /** - * @brief Interpret the preference as an RGBA color value. + * Interpret the preference as an RGBA color value. */ inline guint32 getColor(guint32 def) const; /** - * @brief Interpret the preference as a CSS style. + * Interpret the preference as a CSS style. + * * @return A CSS style that has to be unrefed when no longer necessary. Never NULL. */ inline SPCSSAttr *getStyle() const; /** - * @brief Interpret the preference as a CSS style with directory-based - * inheritance + * Interpret the preference as a CSS style with directory-based + * inheritance. * * This function will look up the preferences with the same entry name * in ancestor directories and return the inherited CSS style. @@ -200,12 +206,12 @@ public: inline SPCSSAttr *getInheritedStyle() const; /** - * @brief Get the full path of the preference described by this Entry. + * Get the full path of the preference described by this Entry. */ Glib::ustring const &getPath() const { return _pref_path; } /** - * @brief Get the last component of the preference's path + * Get the last component of the preference's path. * * E.g. For "/options/some_group/some_option" it will return "some_option". */ @@ -220,7 +226,7 @@ public: // utility methods /** - * @brief Save all preferences to the hard disk. + * Save all preferences to the hard disk. * * For some backends, the preferences may be saved as they are modified. * Not calling this method doesn't guarantee the preferences are unmodified @@ -229,13 +235,13 @@ public: void save(); /** - * @brief Check whether saving the preferences will have any effect. + * Check whether saving the preferences will have any effect. */ bool isWritable() { return _writable; } /*@}*/ /** - * @brief Return details of the last encountered error, if any. + * Return details of the last encountered error, if any. * * This method will return true if an error has been encountered, and fill * in the primary and secondary error strings of the last error. If an error @@ -254,7 +260,7 @@ public: */ /** - * @brief Get all entries from the specified directory + * Get all entries from the specified directory. * * This method will return a vector populated with preference entries * from the specified directory. Subdirectories will not be represented. @@ -262,7 +268,7 @@ public: std::vector<Entry> getAllEntries(Glib::ustring const &path); /** - * @brief Get all subdirectories of the specified directory + * Get all subdirectories of the specified directory. * * This will return a vector populated with full paths to the subdirectories * present in the specified @c path. @@ -276,59 +282,63 @@ public: */ /** - * @brief Retrieve a Boolean value - * @param pref_path Path to the retrieved preference - * @param def The default value to return if the preference is not set + * Retrieve a Boolean value. + * + * @param pref_path Path to the retrieved preference. + * @param def The default value to return if the preference is not set. */ bool getBool(Glib::ustring const &pref_path, bool def=false) { return getEntry(pref_path).getBool(def); } /** - * @brief Retrieve an integer - * @param pref_path Path to the retrieved preference - * @param def The default value to return if the preference is not set + * Retrieve an integer. + * + * @param pref_path Path to the retrieved preference. + * @param def The default value to return if the preference is not set. */ int getInt(Glib::ustring const &pref_path, int def=0) { return getEntry(pref_path).getInt(def); } /** - * @brief Retrieve a limited integer + * Retrieve a limited integer. * * The default value is returned if the actual value is larger than @c max * or smaller than @c min. Do not use to store Boolean values. * - * @param pref_path Path to the retrieved preference - * @param def The default value to return if the preference is not set - * @param min Minimum value to return - * @param max Maximum value to return + * @param pref_path Path to the retrieved preference. + * @param def The default value to return if the preference is not set. + * @param min Minimum value to return. + * @param max Maximum value to return. */ int getIntLimited(Glib::ustring const &pref_path, int def=0, int min=INT_MIN, int max=INT_MAX) { return getEntry(pref_path).getIntLimited(def, min, max); } + double getDouble(Glib::ustring const &pref_path, double def=0.0) { return getEntry(pref_path).getDouble(def); } /** - * @brief Retrieve a limited floating point value + * Retrieve a limited floating point value. * * The default value is returned if the actual value is larger than @c max * or smaller than @c min. * - * @param pref_path Path to the retrieved preference - * @param def The default value to return if the preference is not set - * @param min Minimum value to return - * @param max Maximum value to return + * @param pref_path Path to the retrieved preference. + * @param def The default value to return if the preference is not set. + * @param min Minimum value to return. + * @param max Maximum value to return. */ double getDoubleLimited(Glib::ustring const &pref_path, double def=0.0, double min=DBL_MIN, double max=DBL_MAX) { return getEntry(pref_path).getDoubleLimited(def, min, max); } /** - * @brief Retrieve an UTF-8 string - * @param pref_path Path to the retrieved preference + * Retrieve an UTF-8 string. + * + * @param pref_path Path to the retrieved preference. */ Glib::ustring getString(Glib::ustring const &pref_path) { return getEntry(pref_path).getString(); @@ -339,8 +349,9 @@ public: } /** - * @brief Retrieve a CSS style - * @param pref_path Path to the retrieved preference + * Retrieve a CSS style. + * + * @param pref_path Path to the retrieved preference. * @return A CSS style that has to be unrefed after use. */ SPCSSAttr *getStyle(Glib::ustring const &pref_path) { @@ -348,13 +359,13 @@ public: } /** - * @brief Retrieve an inherited CSS style + * Retrieve an inherited CSS style. * * This method will look up preferences with the same entry name in ancestor * directories and return a style obtained by inheriting properties from * ancestor styles. * - * @param pref_path Path to the retrieved preference + * @param pref_path Path to the retrieved preference. * @return An inherited CSS style that has to be unrefed after use. */ SPCSSAttr *getInheritedStyle(Glib::ustring const &pref_path) { @@ -362,7 +373,7 @@ public: } /** - * @brief Retrieve a preference entry without specifying its type + * Retrieve a preference entry without specifying its type. */ Entry const getEntry(Glib::ustring const &pref_path); /*@}*/ @@ -373,37 +384,37 @@ public: */ /** - * @brief Set a Boolean value + * Set a Boolean value. */ void setBool(Glib::ustring const &pref_path, bool value); /** - * @brief Set an integer value + * Set an integer value. */ void setInt(Glib::ustring const &pref_path, int value); /** - * @brief Set a floating point value + * Set a floating point value. */ void setDouble(Glib::ustring const &pref_path, double value); /** - * @brief Set an UTF-8 string value + * Set an UTF-8 string value. */ void setString(Glib::ustring const &pref_path, Glib::ustring const &value); /** - * @brief Set an RGBA color value + * Set an RGBA color value. */ void setColor(Glib::ustring const &pref_path, guint32 value); /** - * @brief Set a CSS style + * Set a CSS style. */ void setStyle(Glib::ustring const &pref_path, SPCSSAttr *style); /** - * @brief Merge a CSS style with the current preference value + * Merge a CSS style with the current preference value. * * This method is similar to setStyle(), except that it merges the style * rather than replacing it. This means that if @c style doesn't have @@ -419,12 +430,12 @@ public: */ /** - * @brief Register a preference observer + * Register a preference observer. */ void addObserver(Observer &); /** - * @brief Remove an observer an prevent further notifications to it. + * Remove an observer an prevent further notifications to it. */ void removeObserver(Observer &); /*@}*/ @@ -441,7 +452,7 @@ public: static void migrate( std::string const& legacyDir, std::string const& prefdir ); /** - * @brief Access the singleton Preferences object. + * Access the singleton Preferences object. */ static Preferences *get() { if (!_instance) { @@ -453,8 +464,9 @@ public: void setErrorHandler(ErrorReporter* handler); /** - * @brief Unload all preferences - * @param save Whether to save the preferences; defaults to true + * Unload all preferences. + * + * @param save Whether to save the preferences; defaults to true. * * This deletes the singleton object. Calling get() after this function * will reinstate it, so you shouldn't. Pass false as the parameter diff --git a/src/print.cpp b/src/print.cpp index e0601aa33..fe52ea6dd 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -27,14 +27,14 @@ /* Identity typedef */ -unsigned int sp_print_bind(SPPrintContext *ctx, Geom::Matrix const &transform, float opacity) +unsigned int sp_print_bind(SPPrintContext *ctx, Geom::Affine const &transform, float opacity) { - Geom::Matrix const ntransform(transform); + Geom::Affine const ntransform(transform); return sp_print_bind(ctx, &ntransform, opacity); } unsigned int -sp_print_bind(SPPrintContext *ctx, Geom::Matrix const *transform, float opacity) +sp_print_bind(SPPrintContext *ctx, Geom::Affine const *transform, float opacity) { return ctx->module->bind(transform, opacity); } @@ -52,14 +52,14 @@ sp_print_comment(SPPrintContext *ctx, char const *comment) } unsigned int -sp_print_fill(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Matrix const *ctm, SPStyle const *style, +sp_print_fill(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Affine const *ctm, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox) { return ctx->module->fill(pathv, ctm, style, pbox, dbox, bbox); } unsigned int -sp_print_stroke(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Matrix const *ctm, SPStyle const *style, +sp_print_stroke(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Affine const *ctm, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox) { return ctx->module->stroke(pathv, ctm, style, pbox, dbox, bbox); @@ -68,7 +68,7 @@ sp_print_stroke(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Matrix unsigned int sp_print_image_R8G8B8A8_N(SPPrintContext *ctx, guchar *px, unsigned int w, unsigned int h, unsigned int rs, - Geom::Matrix const *transform, SPStyle const *style) + Geom::Affine const *transform, SPStyle const *style) { return ctx->module->image(px, w, h, rs, transform, style); } diff --git a/src/print.h b/src/print.h index f566d4e31..70361fb14 100644 --- a/src/print.h +++ b/src/print.h @@ -21,18 +21,18 @@ struct SPPrintContext { Inkscape::Extension::Print *module; }; -unsigned int sp_print_bind(SPPrintContext *ctx, Geom::Matrix const &transform, float opacity); -unsigned int sp_print_bind(SPPrintContext *ctx, Geom::Matrix const *transform, float opacity); +unsigned int sp_print_bind(SPPrintContext *ctx, Geom::Affine const &transform, float opacity); +unsigned int sp_print_bind(SPPrintContext *ctx, Geom::Affine const *transform, float opacity); unsigned int sp_print_release(SPPrintContext *ctx); unsigned int sp_print_comment(SPPrintContext *ctx, char const *comment); -unsigned int sp_print_fill(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Matrix const *ctm, SPStyle const *style, +unsigned int sp_print_fill(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Affine const *ctm, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox); -unsigned int sp_print_stroke(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Matrix const *transform, SPStyle const *style, +unsigned int sp_print_stroke(SPPrintContext *ctx, Geom::PathVector const &pathv, Geom::Affine const *transform, SPStyle const *style, NRRect const *pbox, NRRect const *dbox, NRRect const *bbox); unsigned int sp_print_image_R8G8B8A8_N(SPPrintContext *ctx, guchar *px, unsigned int w, unsigned int h, unsigned int rs, - Geom::Matrix const *transform, SPStyle const *style); + Geom::Affine const *transform, SPStyle const *style); unsigned int sp_print_text(SPPrintContext *ctx, char const *text, Geom::Point p, SPStyle const *style); diff --git a/src/rect-context.h b/src/rect-context.h index 0445338bf..54f790c68 100644 --- a/src/rect-context.h +++ b/src/rect-context.h @@ -14,6 +14,7 @@ * Released under GNU GPL */ +#include <stddef.h> #include <sigc++/sigc++.h> #include "event-context.h" #include "libnr/nr-point.h" diff --git a/src/rubberband.cpp b/src/rubberband.cpp index 17e7102f8..398f01d3e 100644 --- a/src/rubberband.cpp +++ b/src/rubberband.cpp @@ -1,5 +1,3 @@ -#define __RUBBERBAND_C__ - /** * \file src/rubberband.cpp * \brief Rubberbanding selector @@ -16,6 +14,8 @@ #include "desktop.h" #include "desktop-handles.h" #include "rubberband.h" +#include "display/sp-canvas.h" +#include "display/sp-canvas-item.h" #include "display/canvas-bpath.h" #include "display/curve.h" diff --git a/src/rubberband.h b/src/rubberband.h index 57e4ea2a3..6c857fb63 100644 --- a/src/rubberband.h +++ b/src/rubberband.h @@ -1,5 +1,5 @@ -#ifndef __RUBBERBAND_H__ -#define __RUBBERBAND_H__ +#ifndef SEEN_RUBBERBAND_H +#define SEEN_RUBBERBAND_H /** * \file src/rubberband.h @@ -74,7 +74,7 @@ private: } -#endif +#endif // SEEN_RUBBERBAND_H /* Local Variables: diff --git a/src/selcue.h b/src/selcue.h index c9266ac9a..0869a597d 100644 --- a/src/selcue.h +++ b/src/selcue.h @@ -14,6 +14,7 @@ */ #include <list> +#include <stddef.h> #include <sigc++/sigc++.h> class SPDesktop; diff --git a/src/select-context.cpp b/src/select-context.cpp index febcc282d..e6d78975b 100644 --- a/src/select-context.cpp +++ b/src/select-context.cpp @@ -5,7 +5,9 @@ * Lauris Kaplinski <lauris@kaplinski.com> * bulia byak <buliabyak@users.sf.net> * Abhishek Sharma + * Jon A. Cruz <jon@joncruz.org> * + * Copyright (C) 2010 authors * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl> * Copyright (C) 1999-2005 Authors * @@ -40,6 +42,8 @@ #include "selection-describer.h" #include "seltrans.h" #include "box3d.h" +#include "display/sp-canvas.h" +#include "display/nr-arena-item.h" using Inkscape::DocumentUndo; @@ -109,6 +113,10 @@ sp_select_context_init(SPSelectContext *sc) sc->button_press_shift = false; sc->button_press_ctrl = false; sc->button_press_alt = false; + sc->cycling_items = NULL; + sc->cycling_items_cmp = NULL; + sc->cycling_items_selected_before = NULL; + sc->cycling_cur_item = NULL; sc->_seltrans = NULL; sc->_describer = NULL; @@ -176,7 +184,7 @@ sp_select_context_setup(SPEventContext *ec) desktop->selection, desktop->messageStack(), _("Click selection to toggle scale/rotation handles"), - _("No objects selected. Click, Shift+click, or drag around objects to select.") + _("No objects selected. Click, Shift+click, Alt+scroll mouse on top of objects, or drag around objects to select.") ); select_context->_seltrans = new Inkscape::SelTrans(desktop); @@ -222,11 +230,11 @@ sp_select_context_abort(SPEventContext *event_context) if (sc->item) { // only undo if the item is still valid - if (SP_OBJECT_DOCUMENT( SP_OBJECT(sc->item))) { + if (sc->item->document) { DocumentUndo::undo(sp_desktop_document(desktop)); } - sp_object_unref( SP_OBJECT(sc->item), NULL); + sp_object_unref( sc->item, NULL); } else if (sc->button_press_ctrl) { // NOTE: This is a workaround to a bug. // When the ctrl key is held, sc->item is not defined @@ -278,9 +286,9 @@ sp_select_context_up_one_layer(SPDesktop *desktop) */ SPObject *const current_layer = desktop->currentLayer(); if (current_layer) { - SPObject *const parent = SP_OBJECT_PARENT(current_layer); + SPObject *const parent = current_layer->parent; if ( parent - && ( SP_OBJECT_PARENT(parent) + && ( parent->parent || !( SP_IS_GROUP(current_layer) && ( SPGroup::LAYER == SP_GROUP(current_layer)->layerMode() ) ) ) ) @@ -305,7 +313,7 @@ sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkE tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); // make sure we still have valid objects to move around - if (sc->item && SP_OBJECT_DOCUMENT( SP_OBJECT(sc->item))==NULL) { + if (sc->item && sc->item->document == NULL) { sp_select_context_abort(event_context); } @@ -401,6 +409,43 @@ sp_select_context_item_handler(SPEventContext *event_context, SPItem *item, GdkE return ret; } +static void +sp_select_context_cycle_through_items(SPSelectContext *sc, Inkscape::Selection *selection, GdkEventScroll *scroll_event, bool shift_pressed) { + if (!sc->cycling_cur_item) + return; + + NRArenaItem *arenaitem; + SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; + SPItem *item = SP_ITEM(sc->cycling_cur_item->data); + + // Deactivate current item + if (!g_list_find(sc->cycling_items_selected_before, item) && selection->includes(item)) + selection->remove(item); + arenaitem = item->get_arenaitem(desktop->dkey); + nr_arena_item_set_opacity (arenaitem, 0.3); + + // Find next item and activate it + GList *next; + if (scroll_event->direction == GDK_SCROLL_UP) { + next = sc->cycling_cur_item->next; + if (next == NULL) + next = sc->cycling_items; + } else { + next = sc->cycling_cur_item->prev; + if (next == NULL) + next = g_list_last(sc->cycling_items); + } + sc->cycling_cur_item = next; + item = SP_ITEM(sc->cycling_cur_item->data); + arenaitem = item->get_arenaitem(desktop->dkey); + nr_arena_item_set_opacity (arenaitem, 1.0); + + if (shift_pressed) + selection->add(item); + else + selection->set(item); +} + static gint sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) { @@ -415,7 +460,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // make sure we still have valid objects to move around - if (sc->item && SP_OBJECT_DOCUMENT( SP_OBJECT(sc->item))==NULL) { + if (sc->item && sc->item->document == NULL) { sp_select_context_abort(event_context); } @@ -481,6 +526,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) break; case GDK_MOTION_NOTIFY: + { tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); if (event->motion.state & GDK_BUTTON1_MASK && !event_context->space_panning) { Geom::Point const motion_pt(event->motion.x, event->motion.y); @@ -567,6 +613,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) } } break; + } case GDK_BUTTON_RELEASE: xp = yp = 0; if ((event->button.button == 1) && (sc->grabbed) && !event_context->space_panning) { @@ -605,7 +652,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) sp_canvas_end_forced_full_redraws(desktop->canvas); if (sc->item) { - sp_object_unref( SP_OBJECT(sc->item), NULL); + sp_object_unref( sc->item, NULL); } sc->item = NULL; } else { @@ -699,6 +746,89 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) sc->button_press_alt = false; break; + case GDK_SCROLL: + { + SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); + GdkEventScroll *scroll_event = (GdkEventScroll*) event; + + if (scroll_event->state & GDK_MOD1_MASK) { // alt modified pressed + bool shift_pressed = scroll_event->state & GDK_SHIFT_MASK; + + /* Rebuild list of items underneath the mouse pointer */ + Geom::Point p = desktop->d2w(desktop->point()); + SPItem *item = desktop->getItemAtPoint(p, true, NULL); + + // Save pointer to current cycle-item so that we can find it again later, in the freshly built list + SPItem *tmp_cur_item = sc->cycling_cur_item ? SP_ITEM(sc->cycling_cur_item->data) : NULL; + g_list_free(sc->cycling_items); + sc->cycling_items = NULL; + sc->cycling_cur_item = NULL; + + while(item != NULL) { + sc->cycling_items = g_list_append(sc->cycling_items, item); + item = desktop->getItemAtPoint(p, true, item); + } + + /* Compare current item list with item list during previous scroll ... */ + GList *l1, *l2; + bool item_lists_differ = false; + // Note that we can do an 'or' comparison in the loop because it is safe to call g_list_next with a NULL pointer. + for (l1 = sc->cycling_items, l2 = sc->cycling_items_cmp; l1 != NULL || l2 != NULL; l1 = g_list_next(l1), l2 = g_list_next(l2)) { + if ((l1 !=NULL && l2 == NULL) || (l1 == NULL && l2 != NULL) || (l1->data != l2->data)) { + item_lists_differ = true; + break; + } + } + + /* If list of items under mouse pointer hasn't changed ... */ + if (!item_lists_differ) { + // ... find current item in the freshly built list and continue cycling ... + // TODO: This wouldn't be necessary if cycling_cur_item pointed to an element of cycling_items_cmp instead + sc->cycling_cur_item = g_list_find(sc->cycling_items, tmp_cur_item); + g_assert(sc->cycling_cur_item != NULL || sc->cycling_items == NULL); + } else { + // ... otherwise reset opacities for outdated items ... + NRArenaItem *arenaitem; + for(GList *l = sc->cycling_items_cmp; l != NULL; l = l->next) { + arenaitem = SP_ITEM(l->data)->get_arenaitem(desktop->dkey); + nr_arena_item_set_opacity (arenaitem, 1.0); + //if (!shift_pressed && !g_list_find(sc->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) + if (!g_list_find(sc->cycling_items_selected_before, SP_ITEM(l->data)) && selection->includes(SP_ITEM(l->data))) + selection->remove(SP_ITEM(l->data)); + } + + // ... clear the lists ... + g_list_free(sc->cycling_items_cmp); + g_list_free(sc->cycling_items_selected_before); + sc->cycling_items_cmp = NULL; + sc->cycling_items_selected_before = NULL; + sc->cycling_cur_item = NULL; + + // ... and rebuild them with the new items. + sc->cycling_items_cmp = g_list_copy(sc->cycling_items); + SPItem *item; + for(GList *l = sc->cycling_items; l != NULL; l = l->next) { + item = SP_ITEM(l->data); + arenaitem = item->get_arenaitem(desktop->dkey); + nr_arena_item_set_opacity (arenaitem, 0.3); + if (selection->includes(item)) { + // already selected items are stored separately, too + sc->cycling_items_selected_before = g_list_append(sc->cycling_items_selected_before, item); + } + } + + // set the current item to the bottommost one so that the cycling step below re-starts at the top + sc->cycling_cur_item = g_list_last(sc->cycling_items); + } + + // Cycle through the items underneath the mouse pointer, one-by-one + sp_select_context_cycle_through_items(sc, selection, scroll_event, shift_pressed); + + ret = TRUE; + } + break; + } + case GDK_KEY_PRESS: // keybindings for select context { @@ -727,7 +857,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) sp_event_show_modifier_tip (event_context->defaultMessageContext(), event, _("<b>Ctrl</b>: click to select in groups; drag to move hor/vert"), _("<b>Shift</b>: click to toggle select; drag for rubberband selection"), - _("<b>Alt</b>: click to select under; drag to move selected or select by touch")); + _("<b>Alt</b>: click to select under; scroll mouse-wheel to cycle-select; drag to move selected or select by touch")); // if Alt and nonempty selection, show moving cursor ("move selected"): if (alt && !selection->isEmpty() && !desktop->isWaitingCursor()) { gdk_window_set_cursor(GTK_WIDGET(sp_desktop_canvas(desktop))->window, CursorSelectDragging); @@ -815,6 +945,7 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) selection->clear(); ret = TRUE; break; + case GDK_a: case GDK_A: if (MOD__CTRL_ONLY) { @@ -950,7 +1081,25 @@ sp_select_context_root_handler(SPEventContext *event_context, GdkEvent *event) if (alt) { Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_RECT); } + } else { + if (alt) { // TODO: Should we have a variable like is_cycling or is it harmless to run this piece of code each time? + // quit cycle-selection and reset opacities + SPSelectContext *sc = SP_SELECT_CONTEXT(event_context); + NRArenaItem *arenaitem; + for (GList *l = sc->cycling_items; l != NULL; l = g_list_next(l)) { + arenaitem = SP_ITEM(l->data)->get_arenaitem(desktop->dkey); + nr_arena_item_set_opacity (arenaitem, 1.0); + } + g_list_free(sc->cycling_items); + g_list_free(sc->cycling_items_selected_before); + g_list_free(sc->cycling_items_cmp); + sc->cycling_items = NULL; + sc->cycling_items_selected_before = NULL; + sc->cycling_cur_item = NULL; + sc->cycling_items_cmp = NULL; + } } + } // set cursor to default. if (!desktop->isWaitingCursor()) { diff --git a/src/select-context.h b/src/select-context.h index 3f3f8bfb6..377e07275 100644 --- a/src/select-context.h +++ b/src/select-context.h @@ -37,6 +37,12 @@ struct SPSelectContext : public SPEventContext { bool button_press_shift; bool button_press_ctrl; bool button_press_alt; + + GList *cycling_items; + GList *cycling_items_cmp; + GList *cycling_items_selected_before; + GList *cycling_cur_item; + SPItem *item; SPCanvasItem *grabbed; Inkscape::SelTrans *_seltrans; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 91c902a46..7dbffba1a 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -212,7 +212,7 @@ void SelectionHelper::selectPrev(SPDesktop *dt) * Copies repr and its inherited css style elements, along with the accumulated transform 'full_t', * then prepends the copy to 'clip'. */ -void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Matrix full_t, GSList **clip, Inkscape::XML::Document* xml_doc) +void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, GSList **clip, Inkscape::XML::Document* xml_doc) { Inkscape::XML::Node *copy = repr->duplicate(xml_doc); @@ -239,7 +239,7 @@ void sp_selection_copy_impl(GSList const *items, GSList **clip, Inkscape::XML::D // Copy item reprs: for (GSList *i = (GSList *) sorted_items; i != NULL; i = i->next) { - sp_selection_copy_one(SP_OBJECT_REPR(i->data), SP_ITEM(i->data)->i2doc_affine(), clip, xml_doc); + sp_selection_copy_one(SP_OBJECT(i->data)->getRepr(), SP_ITEM(i->data)->i2doc_affine(), clip, xml_doc); } *clip = g_slist_reverse(*clip); @@ -257,10 +257,10 @@ GSList *sp_selection_paste_impl(SPDocument *doc, SPObject *parent, GSList **clip Inkscape::XML::Node *copy = repr->duplicate(xml_doc); // premultiply the item transform by the accumulated parent transform in the paste layer - Geom::Matrix local(SP_ITEM(parent)->i2doc_affine()); + Geom::Affine local(SP_ITEM(parent)->i2doc_affine()); if (!local.isIdentity()) { gchar const *t_str = copy->attribute("transform"); - Geom::Matrix item_t(Geom::identity()); + Geom::Affine item_t(Geom::identity()); if (t_str) sp_svg_transform_read(t_str, &item_t); item_t *= local.inverse(); @@ -408,7 +408,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) // std::cout << id << " old, its ori: " << orig->getId() << "; will relink:" << new_ids[i] << " to " << new_ids[j] << "\n"; gchar *newref = g_strdup_printf("#%s", new_ids[j]); SPObject *new_clone = doc->getObjectById(new_ids[i]); - SP_OBJECT_REPR(new_clone)->setAttribute("xlink:href", newref); + new_clone->getRepr()->setAttribute("xlink:href", newref); new_clone->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); g_free(newref); } @@ -587,7 +587,7 @@ void sp_selection_group_impl(GSList *p, Inkscape::XML::Node *group, Inkscape::XM // At this point, current may already have no item, due to its being a clone whose original is already moved away // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform gchar const *t_str = current->attribute("transform"); - Geom::Matrix item_t(Geom::identity()); + Geom::Affine item_t(Geom::identity()); if (t_str) sp_svg_transform_read(t_str, &item_t); item_t *= SP_ITEM(doc->getObjectByRepr(current->parent()))->i2doc_affine(); @@ -691,7 +691,7 @@ void sp_selection_ungroup(SPDesktop *desktop) } /* We do not allow ungrouping <svg> etc. (lauris) */ - if (strcmp(SP_OBJECT_REPR(group)->name(), "svg:g") && strcmp(SP_OBJECT_REPR(group)->name(), "svg:switch")) { + if (strcmp(group->getRepr()->name(), "svg:g") && strcmp(group->getRepr()->name(), "svg:switch")) { // keep the non-group item in the new selection new_select = g_slist_append(new_select, group); continue; @@ -755,13 +755,13 @@ sp_item_list_common_parent_group(GSList const *items) if (!items) { return NULL; } - SPObject *parent = SP_OBJECT_PARENT(items->data); - /* Strictly speaking this CAN happen, if user selects <svg> from Inkscape::XML editor */ + SPObject *parent = SP_OBJECT(items->data)->parent; + // Strictly speaking this CAN happen, if user selects <svg> from Inkscape::XML editor if (!SP_IS_GROUP(parent)) { return NULL; } for (items = items->next; items; items = items->next) { - if (SP_OBJECT_PARENT(items->data) != parent) { + if (SP_OBJECT(items->data)->parent != parent) { return NULL; } } @@ -812,7 +812,7 @@ sp_selection_raise(SPDesktop *desktop) return; } - Inkscape::XML::Node *grepr = SP_OBJECT_REPR(group); + Inkscape::XML::Node *grepr = const_cast<Inkscape::XML::Node *>(group->getRepr()); /* Construct reverse-ordered list of selected children. */ GSList *rev = g_slist_copy((GSList *) items); @@ -834,7 +834,7 @@ sp_selection_raise(SPDesktop *desktop) // AND if it's not one of our selected objects, if (!g_slist_find((GSList *) items, newref)) { // move the selected object after that sibling - grepr->changeOrder(SP_OBJECT_REPR(child), SP_OBJECT_REPR(newref)); + grepr->changeOrder(child->getRepr(), newref->getRepr()); } break; } @@ -906,7 +906,7 @@ sp_selection_lower(SPDesktop *desktop) return; } - Inkscape::XML::Node *grepr = SP_OBJECT_REPR(group); + Inkscape::XML::Node *grepr = const_cast<Inkscape::XML::Node *>(group->getRepr()); // Determine the common bbox of the selected items. Geom::OptRect selected = enclose_items(items); @@ -931,9 +931,9 @@ sp_selection_lower(SPDesktop *desktop) // move the selected object before that sibling SPObject *put_after = prev_sibling(newref); if (put_after) - grepr->changeOrder(SP_OBJECT_REPR(child), SP_OBJECT_REPR(put_after)); + grepr->changeOrder(child->getRepr(), put_after->getRepr()); else - SP_OBJECT_REPR(child)->setPosition(0); + child->getRepr()->setPosition(0); } break; } @@ -1299,7 +1299,7 @@ value of set_i2d==false is only used by seltrans when it's dragging objects live that case, items are already in the new position, but the repr is in the old, and this function then simply updates the repr from item->transform. */ -void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix const &affine, bool set_i2d, bool compensate) +void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine const &affine, bool set_i2d, bool compensate) { if (selection->isEmpty()) return; @@ -1316,7 +1316,7 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix cons std::list<SPBox3D *> selboxes = selection->box3DList(persp); // create a new perspective as a copy of the current one and link the selected boxes to it - transf_persp = persp3d_create_xml_element (SP_OBJECT_DOCUMENT(persp), persp->perspective_impl); + transf_persp = persp3d_create_xml_element (persp->document, persp->perspective_impl); for (std::list<SPBox3D *>::iterator b = selboxes.begin(); b != selboxes.end(); ++b) box3d_switch_perspectives(*b, persp, transf_persp); @@ -1375,9 +1375,9 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix cons * Same for textpath if we are also doing ANY transform to its path: do not touch textpath, * letters cannot be squeezed or rotated anyway, they only refill the changed path. * Same for linked offset if we are also moving its source: do not move it. */ - if (transform_textpath_with_path || transform_offset_with_source) { + if (transform_textpath_with_path) { // Restore item->transform field from the repr, in case it was changed by seltrans. - SP_OBJECT(item)->readAttr( "transform" ); + item->readAttr( "transform" ); } else if (transform_flowtext_with_frame) { // apply the inverse of the region's transform to the <use> so that the flow remains // the same (even though the output itself gets transformed) @@ -1390,48 +1390,61 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix cons } } } - } else if (transform_clone_with_original) { + } else if (transform_clone_with_original || transform_offset_with_source) { // We are transforming a clone along with its original. The below matrix juggling is // necessary to ensure that they transform as a whole, i.e. the clone's induced // transform and its move compensation are both cancelled out. // restore item->transform field from the repr, in case it was changed by seltrans - SP_OBJECT(item)->readAttr( "transform" ); + item->readAttr( "transform" ); // calculate the matrix we need to apply to the clone to cancel its induced transform from its original - Geom::Matrix parent2dt = SP_ITEM(SP_OBJECT_PARENT(item))->i2d_affine(); - Geom::Matrix t = parent2dt * affine * parent2dt.inverse(); - Geom::Matrix t_inv = t.inverse(); - Geom::Matrix result = t_inv * item->transform * t; + Geom::Affine parent2dt = SP_ITEM(item->parent)->i2d_affine(); + Geom::Affine t = parent2dt * affine * parent2dt.inverse(); + Geom::Affine t_inv = t.inverse(); + Geom::Affine result = t_inv * item->transform * t; - if ((prefs_parallel || prefs_unmoved) && affine.isTranslation()) { + if (transform_clone_with_original && (prefs_parallel || prefs_unmoved) && affine.isTranslation()) { // we need to cancel out the move compensation, too // find out the clone move, same as in sp_use_move_compensate - Geom::Matrix parent = sp_use_get_parent_transform(SP_USE(item)); - Geom::Matrix clone_move = parent.inverse() * t * parent; + Geom::Affine parent = sp_use_get_parent_transform(SP_USE(item)); + Geom::Affine clone_move = parent.inverse() * t * parent; if (prefs_parallel) { - Geom::Matrix move = result * clone_move * t_inv; - item->doWriteTransform(SP_OBJECT_REPR(item), move, &move, compensate); + Geom::Affine move = result * clone_move * t_inv; + item->doWriteTransform(item->getRepr(), move, &move, compensate); } else if (prefs_unmoved) { //if (SP_IS_USE(sp_use_get_original(SP_USE(item)))) // clone_move = Geom::identity(); - Geom::Matrix move = result * clone_move; - item->doWriteTransform(SP_OBJECT_REPR(item), move, &t, compensate); + Geom::Affine move = result * clone_move; + item->doWriteTransform(item->getRepr(), move, &t, compensate); + } + + } else if (transform_offset_with_source && (prefs_parallel || prefs_unmoved) && affine.isTranslation()){ + Geom::Affine parent = item->transform; + Geom::Affine offset_move = parent.inverse() * t * parent; + + if (prefs_parallel) { + Geom::Affine move = result * offset_move * t_inv; + item->doWriteTransform(item->getRepr(), move, &move, compensate); + + } else if (prefs_unmoved) { + Geom::Affine move = result * offset_move; + item->doWriteTransform(item->getRepr(), move, &t, compensate); } } else { // just apply the result - item->doWriteTransform(SP_OBJECT_REPR(item), result, &t, compensate); + item->doWriteTransform(item->getRepr(), result, &t, compensate); } } else { if (set_i2d) { - item->set_i2d_affine(item->i2d_affine() * (Geom::Matrix)affine); + item->set_i2d_affine(item->i2d_affine() * (Geom::Affine)affine); } - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform, NULL, compensate); + item->doWriteTransform(item->getRepr(), item->transform, NULL, compensate); } // if we're moving the actual object, not just updating the repr, we can transform the @@ -1479,7 +1492,7 @@ sp_selection_scale_absolute(Inkscape::Selection *selection, y1 - y0); Geom::Scale const scale( newSize * Geom::Scale(bbox->dimensions()).inverse() ); Geom::Translate const o2n(x0, y0); - Geom::Matrix const final( p2o * scale * o2n ); + Geom::Affine const final( p2o * scale * o2n ); sp_selection_apply_affine(selection, final); } @@ -1505,7 +1518,7 @@ void sp_selection_scale_relative(Inkscape::Selection *selection, Geom::Point con Geom::Translate const n2d(-align); Geom::Translate const d2n(align); - Geom::Matrix const final( n2d * scale * d2n ); + Geom::Affine const final( n2d * scale * d2n ); sp_selection_apply_affine(selection, final); } @@ -1515,7 +1528,7 @@ sp_selection_rotate_relative(Inkscape::Selection *selection, Geom::Point const & Geom::Translate const d2n(center); Geom::Translate const n2d(-center); Geom::Rotate const rotate(Geom::Rotate::from_degrees(angle_degrees)); - Geom::Matrix const final( Geom::Matrix(n2d) * rotate * d2n ); + Geom::Affine const final( Geom::Affine(n2d) * rotate * d2n ); sp_selection_apply_affine(selection, final); } @@ -1524,21 +1537,21 @@ sp_selection_skew_relative(Inkscape::Selection *selection, Geom::Point const &al { Geom::Translate const d2n(align); Geom::Translate const n2d(-align); - Geom::Matrix const skew(1, dy, + Geom::Affine const skew(1, dy, dx, 1, 0, 0); - Geom::Matrix const final( n2d * skew * d2n ); + Geom::Affine const final( n2d * skew * d2n ); sp_selection_apply_affine(selection, final); } void sp_selection_move_relative(Inkscape::Selection *selection, Geom::Point const &move, bool compensate) { - sp_selection_apply_affine(selection, Geom::Matrix(Geom::Translate(move)), true, compensate); + sp_selection_apply_affine(selection, Geom::Affine(Geom::Translate(move)), true, compensate); } void sp_selection_move_relative(Inkscape::Selection *selection, double dx, double dy) { - sp_selection_apply_affine(selection, Geom::Matrix(Geom::Translate(dx, dy))); + sp_selection_apply_affine(selection, Geom::Affine(Geom::Translate(dx, dy))); } /** @@ -1762,7 +1775,7 @@ struct ListReverse { return make_list(o->firstChild(), NULL); } static Iterator siblings_after(SPObject *o) { - return make_list(SP_OBJECT_PARENT(o)->firstChild(), o); + return make_list(o->parent->firstChild(), o); } static void dispose(Iterator i) { g_slist_free(i); @@ -1893,8 +1906,8 @@ void sp_selection_edit_clip_or_mask(SPDesktop * /*dt*/, bool /*clip*/) for (GSList *i = const_cast<GSList*>(items); i; i= i->next) { SPItem *item = SP_ITEM(i->data); SPObject *search = clip - ? SP_OBJECT(item->clip_ref ? item->clip_ref->getObject() : NULL) - : SP_OBJECT(item->mask_ref ? item->mask_ref->getObject() : NULL); + ? (item->clip_ref ? item->clip_ref->getObject() : NULL) + : item->mask_ref ? item->mask_ref->getObject() : NULL; has_path |= has_path_recursive(search); if (has_path) break; } @@ -1935,7 +1948,7 @@ SPItem *next_item_from_list(SPDesktop *desktop, GSList const *items, GSList *path=NULL; while ( current != root ) { path = g_slist_prepend(path, current); - current = SP_OBJECT_PARENT(current); + current = current->parent; } SPItem *next; @@ -1961,7 +1974,7 @@ SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, if (path) { SPObject *object=reinterpret_cast<SPObject *>(path->data); - g_assert(SP_OBJECT_PARENT(object) == root); + g_assert(object->parent == root); if (desktop->isLayer(object)) { found = next_item<D>(desktop, path->next, object, only_in_viewport, inlayer, onlyvisible, onlysensitive); } @@ -2101,7 +2114,7 @@ sp_selection_relink(SPDesktop *desktop) if (!SP_IS_USE(item)) continue; - SP_OBJECT_REPR(item)->setAttribute("xlink:href", newref); + item->getRepr()->setAttribute("xlink:href", newref); item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); relinked = true; } @@ -2211,7 +2224,7 @@ sp_select_clone_original(SPDesktop *desktop) } else if (SP_IS_OFFSET(item) && SP_OFFSET(item)->sourceHref) { original = sp_offset_get_source(SP_OFFSET(item)); } else if (SP_IS_TEXT_TEXTPATH(item)) { - original = sp_textpath_get_path_item(SP_TEXTPATH(SP_OBJECT(item)->firstChild())); + original = sp_textpath_get_path_item(SP_TEXTPATH(item->firstChild())); } else if (SP_IS_FLOWTEXT(item)) { original = SP_FLOWTEXT(item)->get_frame(NULL); // first frame only } else { // it's an object that we don't know what to do with @@ -2224,7 +2237,7 @@ sp_select_clone_original(SPDesktop *desktop) return; } - for (SPObject *o = original; o && !SP_IS_ROOT(o); o = SP_OBJECT_PARENT(o)) { + for (SPObject *o = original; o && !SP_IS_ROOT(o); o = o->parent) { if (SP_IS_DEFS(o)) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The object you're trying to select is <b>not visible</b> (it is in <defs>)")); return; @@ -2287,25 +2300,25 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) // calculate the transform to be applied to objects to move them to 0,0 Geom::Point move_p = Geom::Point(0, doc->getHeight()) - *c; move_p[Geom::Y] = -move_p[Geom::Y]; - Geom::Matrix move = Geom::Matrix(Geom::Translate(move_p)); + Geom::Affine move = Geom::Affine(Geom::Translate(move_p)); GSList *items = g_slist_copy((GSList *) selection->itemList()); items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // bottommost object, after sorting - SPObject *parent = SP_OBJECT_PARENT(items->data); + SPObject *parent = SP_OBJECT(items->data)->parent; - Geom::Matrix parent_transform(SP_ITEM(parent)->i2doc_affine()); + Geom::Affine parent_transform(SP_ITEM(parent)->i2doc_affine()); // remember the position of the first item - gint pos = SP_OBJECT_REPR(items->data)->position(); + gint pos = SP_OBJECT(items->data)->getRepr()->position(); (void)pos; // TODO check why this was remembered // create a list of duplicates GSList *repr_copies = NULL; for (GSList *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *dup = (SP_OBJECT_REPR(i->data))->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); repr_copies = g_slist_prepend(repr_copies, dup); } @@ -2327,7 +2340,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); gchar const *mark_id = generate_marker(repr_copies, bounds, doc, - ( Geom::Matrix(Geom::Translate(desktop->dt2doc( + ( Geom::Affine(Geom::Translate(desktop->dt2doc( Geom::Point(r->min()[Geom::X], r->max()[Geom::Y])))) * parent_transform.inverse() ), @@ -2411,24 +2424,24 @@ sp_selection_tile(SPDesktop *desktop, bool apply) // calculate the transform to be applied to objects to move them to 0,0 Geom::Point move_p = Geom::Point(0, doc->getHeight()) - (r->min() + Geom::Point(0, r->dimensions()[Geom::Y])); move_p[Geom::Y] = -move_p[Geom::Y]; - Geom::Matrix move = Geom::Matrix(Geom::Translate(move_p)); + Geom::Affine move = Geom::Affine(Geom::Translate(move_p)); GSList *items = g_slist_copy((GSList *) selection->itemList()); items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // bottommost object, after sorting - SPObject *parent = SP_OBJECT_PARENT(items->data); + SPObject *parent = SP_OBJECT(items->data)->parent; - Geom::Matrix parent_transform(SP_ITEM(parent)->i2doc_affine()); + Geom::Affine parent_transform(SP_ITEM(parent)->i2doc_affine()); // remember the position of the first item - gint pos = SP_OBJECT_REPR(items->data)->position(); + gint pos = SP_OBJECT(items->data)->getRepr()->position(); // create a list of duplicates GSList *repr_copies = NULL; for (GSList *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *dup = (SP_OBJECT_REPR(i->data))->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); repr_copies = g_slist_prepend(repr_copies, dup); } // restore the z-order after prepends @@ -2452,7 +2465,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); gchar const *pat_id = pattern_tile(repr_copies, bounds, doc, - ( Geom::Matrix(Geom::Translate(desktop->dt2doc(Geom::Point(r->min()[Geom::X], + ( Geom::Affine(Geom::Translate(desktop->dt2doc(Geom::Point(r->min()[Geom::X], r->max()[Geom::Y])))) * parent_transform.inverse() ), parent_transform * move); @@ -2473,7 +2486,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) sp_repr_set_svg_double(rect, "y", min[Geom::Y]); // restore parent and position - SP_OBJECT_REPR(parent)->appendChild(rect); + parent->getRepr()->appendChild(rect); rect->setPosition(pos > 0 ? pos : 0); SPItem *rectangle = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(rect); @@ -2530,11 +2543,11 @@ void sp_selection_untile(SPDesktop *desktop) SPPattern *pattern = pattern_getroot(SP_PATTERN(server)); - Geom::Matrix pat_transform = pattern_patternTransform(SP_PATTERN(server)); + Geom::Affine pat_transform = pattern_patternTransform(SP_PATTERN(server)); pat_transform *= item->transform; for (SPObject *child = pattern->firstChild() ; child != NULL; child = child->next ) { - Inkscape::XML::Node *copy = SP_OBJECT_REPR(child)->duplicate(xml_doc); + Inkscape::XML::Node *copy = child->getRepr()->duplicate(xml_doc); SPItem *i = SP_ITEM(desktop->currentLayer()->appendChildRepr(copy)); // FIXME: relink clones to the new canvas objects @@ -2543,15 +2556,15 @@ void sp_selection_untile(SPDesktop *desktop) // this is needed to make sure the new item has curve (simply requestDisplayUpdate does not work) doc->ensureUpToDate(); - Geom::Matrix transform( i->transform * pat_transform ); - i->doWriteTransform(SP_OBJECT_REPR(i), transform); + Geom::Affine transform( i->transform * pat_transform ); + i->doWriteTransform(i->getRepr(), transform); new_select = g_slist_prepend(new_select, i); } SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "fill", "none"); - sp_repr_css_change(SP_OBJECT_REPR(item), css, "style"); + sp_repr_css_change(item->getRepr(), css, "style"); } if (!did) { @@ -2671,7 +2684,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) // Create the filename. gchar *const basename = g_strdup_printf("%s-%s-%u.png", document->getName(), - SP_OBJECT_REPR(items->data)->attribute("id"), + SP_OBJECT(items->data)->getRepr()->attribute("id"), current); // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters, // digits, and a few other chars, with "_" @@ -2690,9 +2703,9 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) //g_print("%s\n", filepath); // Remember parent and z-order of the topmost one - gint pos = SP_OBJECT_REPR(g_slist_last(items)->data)->position(); - SPObject *parent_object = SP_OBJECT_PARENT(g_slist_last(items)->data); - Inkscape::XML::Node *parent = SP_OBJECT_REPR(parent_object); + gint pos = SP_OBJECT(g_slist_last(items)->data)->getRepr()->position(); + SPObject *parent_object = SP_OBJECT(g_slist_last(items)->data)->parent; + Inkscape::XML::Node *parent = parent_object->getRepr(); // Calculate resolution Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -2753,8 +2766,8 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) } // Calculate the matrix that will be applied to the image so that it exactly overlaps the source objects - Geom::Matrix eek(SP_ITEM(parent_object)->i2d_affine()); - Geom::Matrix t; + Geom::Affine eek(SP_ITEM(parent_object)->i2d_affine()); + Geom::Affine t; double shift_x = bbox->min()[Geom::X]; double shift_y = bbox->max()[Geom::Y]; @@ -2890,7 +2903,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ apply_to_items = g_slist_prepend(apply_to_items, desktop->currentLayer()); for (GSList *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *dup = (SP_OBJECT_REPR(i->data))->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); SPObject *item = reinterpret_cast<SPObject*>(i->data); @@ -2904,7 +2917,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ } else if (!topmost) { // topmost item is used as a mask, which is applied to other items in a selection GSList *i = items; - Inkscape::XML::Node *dup = (SP_OBJECT_REPR(i->data))->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { @@ -2923,7 +2936,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ items_to_select = g_slist_prepend(items_to_select, i->data); } - Inkscape::XML::Node *dup = (SP_OBJECT_REPR(i->data))->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { @@ -2946,8 +2959,8 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ GSList *reprs_to_group = NULL; for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { - reprs_to_group = g_slist_prepend(reprs_to_group, SP_OBJECT_REPR(i->data)); - items_to_select = g_slist_remove(items_to_select, i->data); + reprs_to_group = g_slist_prepend(reprs_to_group, SP_OBJECT(i->data)->getRepr()); + items_to_select = g_slist_remove(items_to_select, i->data); } reprs_to_group = g_slist_reverse(reprs_to_group); @@ -2970,7 +2983,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ SPItem *item = reinterpret_cast<SPItem *>(i->data); // inverted object transform should be applied to a mask object, // as mask is calculated in user space (after applying transform) - Geom::Matrix maskTransform(item->transform.inverse()); + Geom::Affine maskTransform(item->transform.inverse()); GSList *mask_items_dup = NULL; for (GSList *mask_item = mask_items; NULL != mask_item; mask_item = mask_item->next) { @@ -2988,7 +3001,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ g_slist_free(mask_items_dup); mask_items_dup = NULL; - Inkscape::XML::Node *current = SP_OBJECT_REPR(i->data); + Inkscape::XML::Node *current = SP_OBJECT(i->data)->getRepr(); // Node to apply mask to Inkscape::XML::Node *apply_mask_to = current; @@ -3091,7 +3104,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { } } - SP_OBJECT_REPR(i->data)->setAttribute(attributeName, "none"); + SP_OBJECT(i->data)->getRepr()->setAttribute(attributeName, "none"); if (ungroup_masked && SP_IS_GROUP(i->data)) { // if we had previously enclosed masked object in group, @@ -3113,7 +3126,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { GSList *items_to_move = NULL; for ( SPObject *child = obj->firstChild() ; child; child = child->getNext() ) { // Collect all clipped paths and masks within a single group - Inkscape::XML::Node *copy = SP_OBJECT_REPR(child)->duplicate(xml_doc); + Inkscape::XML::Node *copy = SP_OBJECT(child)->getRepr()->duplicate(xml_doc); items_to_move = g_slist_prepend(items_to_move, copy); } @@ -3123,8 +3136,8 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { } // remember parent and position of the item to which the clippath/mask was applied - Inkscape::XML::Node *parent = SP_OBJECT_REPR((*it).second)->parent(); - gint pos = SP_OBJECT_REPR((*it).second)->position(); + Inkscape::XML::Node *parent = ((*it).second)->getRepr()->parent(); + gint pos = ((*it).second)->getRepr()->position(); // Iterate through all clipped paths / masks for (GSList *i = items_to_move; NULL != i; i = i->next) { @@ -3138,9 +3151,9 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { items_to_select = g_slist_prepend(items_to_select, mask_item); // transform mask, so it is moved the same spot where mask was applied - Geom::Matrix transform(mask_item->transform); + Geom::Affine transform(mask_item->transform); transform *= (*it).second->transform; - mask_item->doWriteTransform(SP_OBJECT_REPR(mask_item), transform); + mask_item->doWriteTransform(mask_item->getRepr(), transform); } g_slist_free(items_to_move); @@ -3218,7 +3231,7 @@ fit_canvas_to_drawing(SPDocument *doc, bool with_margins) doc->ensureUpToDate(); SPItem const *const root = SP_ITEM(doc->root); - Geom::OptRect const bbox(root->getBounds(root->i2d_affine())); + Geom::OptRect const bbox(root->getBounds(root->i2d_affine(), SPItem::RENDERING_BBOX)); if (bbox) { doc->fitToRect(*bbox, with_margins); return true; diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index 65d1ba296..b3d64ae8e 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -93,7 +93,7 @@ void sp_selection_paste_size_separately(SPDesktop *desktop, bool apply_x, bool a void sp_selection_to_next_layer( SPDesktop *desktop, bool suppressDone = false ); void sp_selection_to_prev_layer( SPDesktop *desktop, bool suppressDone = false ); -void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Matrix const &affine, bool set_i2d = true, bool compensate = true); +void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine const &affine, bool set_i2d = true, bool compensate = true); void sp_selection_remove_transform (SPDesktop *desktop); void sp_selection_scale_absolute (Inkscape::Selection *selection, double x0, double x1, double y0, double y1); void sp_selection_scale_relative(Inkscape::Selection *selection, Geom::Point const &align, Geom::Scale const &scale); diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index 7bc6adf38..5693ce351 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -128,7 +128,7 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select _context.set(Inkscape::NORMAL_MESSAGE, _when_nothing); } else { SPItem *item = SP_ITEM(items->data); - SPObject *layer = selection->desktop()->layerForObject (SP_OBJECT (item)); + SPObject *layer = selection->desktop()->layerForObject(item); SPObject *root = selection->desktop()->currentRoot(); // Layer name @@ -154,7 +154,7 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select } // Parent name - SPObject *parent = SP_OBJECT_PARENT (item); + SPObject *parent = item->parent; gchar const *parent_label = parent->getId(); char *quoted_parent_label = xml_quote_strdup(parent_label); gchar *parent_name = g_strdup_printf(_("<i>%s</i>"), quoted_parent_label); diff --git a/src/selection-describer.h b/src/selection-describer.h index cca6a3033..b4174edd8 100644 --- a/src/selection-describer.h +++ b/src/selection-describer.h @@ -12,6 +12,7 @@ #ifndef SEEN_INKSCAPE_SELECTION_DESCRIPTION_HANDLER_H #define SEEN_INKSCAPE_SELECTION_DESCRIPTION_HANDLER_H +#include <stddef.h> #include <sigc++/sigc++.h> #include "message-context.h" diff --git a/src/selection.cpp b/src/selection.cpp index 9cef87076..7564fad3a 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -308,7 +308,7 @@ GSList const *Selection::reprList() { for ( GSList const *iter=itemList() ; iter != NULL ; iter = iter->next ) { SPObject *obj=reinterpret_cast<SPObject *>(iter->data); - _reprs = g_slist_prepend(_reprs, SP_OBJECT_REPR(obj)); + _reprs = g_slist_prepend(_reprs, obj->getRepr()); } _reprs = g_slist_reverse(_reprs); @@ -359,7 +359,7 @@ SPItem *Selection::singleItem() { Inkscape::XML::Node *Selection::singleRepr() { SPObject *obj=single(); - return obj ? SP_OBJECT_REPR(obj) : NULL; + return obj ? obj->getRepr() : NULL; } NRRect *Selection::bounds(NRRect *bbox, SPItem::BBoxType type) const @@ -394,7 +394,7 @@ NRRect *Selection::boundsInDocument(NRRect *bbox, SPItem::BBoxType type) const { for ( GSList const *iter=items ; iter != NULL ; iter = iter->next ) { SPItem *item=SP_ITEM(iter->data); - Geom::Matrix i2doc(item->i2doc_affine()); + Geom::Affine i2doc(item->i2doc_affine()); item->invoke_bbox( bbox, i2doc, FALSE, type); } @@ -489,24 +489,24 @@ void Selection::_removeObjectDescendants(SPObject *obj) { for ( iter = _objs ; iter ; iter = next ) { next = iter->next; SPObject *sel_obj=reinterpret_cast<SPObject *>(iter->data); - SPObject *parent=SP_OBJECT_PARENT(sel_obj); + SPObject *parent = sel_obj->parent; while (parent) { if ( parent == obj ) { _remove(sel_obj); break; } - parent = SP_OBJECT_PARENT(parent); + parent = parent->parent; } } } void Selection::_removeObjectAncestors(SPObject *obj) { - SPObject *parent=SP_OBJECT_PARENT(obj); + SPObject *parent = obj->parent; while (parent) { if (includes(parent)) { _remove(parent); } - parent = SP_OBJECT_PARENT(parent); + parent = parent->parent; } } @@ -537,7 +537,7 @@ guint Selection::numberOfParents() { GSList const *items = const_cast<Selection *>(this)->itemList(); GSList *parents = NULL; for (GSList const *iter = items; iter != NULL; iter = iter->next) { - SPObject *parent = SP_OBJECT_PARENT(iter->data); + SPObject *parent = SP_OBJECT(iter->data)->parent; if (g_slist_find (parents, parent) == NULL) { parents = g_slist_prepend (parents, parent); } diff --git a/src/selection.h b/src/selection.h index a3a6e87e8..00572a1c5 100644 --- a/src/selection.h +++ b/src/selection.h @@ -19,6 +19,7 @@ #include <vector> #include <map> #include <list> +#include <stddef.h> #include <sigc++/sigc++.h> #include "forward.h" diff --git a/src/seltrans-handles.cpp b/src/seltrans-handles.cpp index d3197a062..10b87aaff 100644 --- a/src/seltrans-handles.cpp +++ b/src/seltrans-handles.cpp @@ -1,5 +1,3 @@ -#define SP_SELTRANS_HANDLES_C - #include "seltrans-handles.h" diff --git a/src/seltrans-handles.h b/src/seltrans-handles.h index 4a0dd0bf7..f796a1007 100644 --- a/src/seltrans-handles.h +++ b/src/seltrans-handles.h @@ -1,5 +1,5 @@ -#ifndef __SP_SELTRANS_HANDLES_H__ -#define __SP_SELTRANS_HANDLES_H__ +#ifndef SEEN_SP_SELTRANS_HANDLES_H +#define SEEN_SP_SELTRANS_HANDLES_H /* * Seltrans knots @@ -14,6 +14,7 @@ #include "display/sodipodi-ctrl.h" #include <2geom/forward.h> +#include <gdk/gdkcursor.h> namespace Inkscape { @@ -50,9 +51,22 @@ struct SPSelTransHandle { gdouble x, y; }; +// TODO these must be purged: extern SPSelTransHandle const handles_scale[8]; extern SPSelTransHandle const handles_rotate[8]; extern SPSelTransHandle const handle_center; -#endif +#endif // SEEN_SP_SELTRANS_HANDLES_H + +/* + 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 : + diff --git a/src/seltrans.cpp b/src/seltrans.cpp index c92f67348..bb333caca 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -201,7 +201,7 @@ Inkscape::SelTrans::~SelTrans() } for (unsigned i = 0; i < _items.size(); i++) { - sp_object_unref(SP_OBJECT(_items[i]), NULL); + sp_object_unref(_items[i], NULL); } _items.clear(); @@ -235,7 +235,7 @@ void Inkscape::SelTrans::setCenter(Geom::Point const &p) // Write the new center position into all selected items for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { - SPItem *it = (SPItem*)SP_OBJECT(l->data); + SPItem *it = SP_ITEM(l->data); it->setCenter(p); // only set the value; updating repr and document_done will be done once, on ungrab } @@ -264,7 +264,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s } for (GSList const *l = selection->itemList(); l; l = l->next) { - SPItem *it = (SPItem *)sp_object_ref(SP_OBJECT(l->data), NULL); + SPItem *it = reinterpret_cast<SPItem*>(sp_object_ref(SP_ITEM(l->data), NULL)); _items.push_back(it); _items_const.push_back(it); _items_affines.push_back(it->i2d_affine()); @@ -299,7 +299,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s An average user would rarely ever try to snap such a large number of nodes anyway, because (s)he could hardly discern which node would be snapping */ if (prefs->getBool("/options/snapclosestonly/value", false)) { - _keepClosestPointOnly(_snap_points, p); + m.keepClosestPointOnly(_snap_points, p); } else { _snap_points = snap_points_hull; } @@ -360,14 +360,14 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s if (prefs->getBool("/options/snapclosestonly/value", false)) { if (m.snapprefs.getSnapModeNode()) { - _keepClosestPointOnly(_snap_points, p); + m.keepClosestPointOnly(_snap_points, p); } else { _snap_points.clear(); // don't keep any point } if (m.snapprefs.getSnapModeBBox()) { - _keepClosestPointOnly(_bbox_points, p); - _keepClosestPointOnly(_bbox_points_for_translating, p); + m.keepClosestPointOnly(_bbox_points, p); + m.keepClosestPointOnly(_bbox_points_for_translating, p); } else { _bbox_points.clear(); // don't keep any point _bbox_points_for_translating.clear(); @@ -419,18 +419,18 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s g_return_if_fail(_stamp_cache == NULL); } -void Inkscape::SelTrans::transform(Geom::Matrix const &rel_affine, Geom::Point const &norm) +void Inkscape::SelTrans::transform(Geom::Affine const &rel_affine, Geom::Point const &norm) { g_return_if_fail(_grabbed); g_return_if_fail(!_empty); - Geom::Matrix const affine( Geom::Translate(-norm) * rel_affine * Geom::Translate(norm) ); + Geom::Affine const affine( Geom::Translate(-norm) * rel_affine * Geom::Translate(norm) ); if (_show == SHOW_CONTENT) { // update the content for (unsigned i = 0; i < _items.size(); i++) { SPItem &item = *_items[i]; - Geom::Matrix const &prev_transform = _items_affines[i]; + Geom::Affine const &prev_transform = _items_affines[i]; item.set_i2d_affine(prev_transform * affine); } } else { @@ -463,7 +463,7 @@ void Inkscape::SelTrans::ungrab() _updateVolatileState(); for (unsigned i = 0; i < _items.size(); i++) { - sp_object_unref(SP_OBJECT(_items[i]), NULL); + sp_object_unref(_items[i], NULL); } sp_canvas_item_hide(_norm); @@ -496,7 +496,7 @@ void Inkscape::SelTrans::ungrab() SPItem *currentItem = _items[i]; if (currentItem->isCenterSet()) { // only if it's already set currentItem->setCenter (_items_centers[i] * _current_relative_affine); - SP_OBJECT(currentItem)->updateRepr(); + currentItem->updateRepr(); } } } @@ -509,10 +509,10 @@ void Inkscape::SelTrans::ungrab() if (_current_relative_affine.isTranslation()) { DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, _("Move")); - } else if (_current_relative_affine.without_translation().isScale()) { + } else if (_current_relative_affine.withoutTranslation().isScale()) { DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, _("Scale")); - } else if (_current_relative_affine.without_translation().isRotation()) { + } else if (_current_relative_affine.withoutTranslation().isRotation()) { DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, _("Rotate")); } else { @@ -525,8 +525,8 @@ void Inkscape::SelTrans::ungrab() if (_center_is_set) { // we were dragging center; update reprs and commit undoable action for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { - SPItem *it = (SPItem*)SP_OBJECT(l->data); - SP_OBJECT(it)->updateRepr(); + SPItem *it = SP_ITEM(l->data); + it->updateRepr(); } DocumentUndo::done(sp_desktop_document(_desktop), SP_VERB_CONTEXT_SELECT, _("Set center")); @@ -568,7 +568,7 @@ void Inkscape::SelTrans::stamp() while (l) { SPItem *original_item = SP_ITEM(l->data); - Inkscape::XML::Node *original_repr = SP_OBJECT_REPR(original_item); + Inkscape::XML::Node *original_repr = original_item->getRepr(); // remember the position of the item gint pos = original_repr->position(); @@ -584,10 +584,10 @@ void Inkscape::SelTrans::stamp() SPItem *copy_item = (SPItem *) sp_desktop_document(_desktop)->getObjectByRepr(copy_repr); - Geom::Matrix const *new_affine; + Geom::Affine const *new_affine; if (_show == SHOW_OUTLINE) { - Geom::Matrix const i2d(original_item->i2d_affine()); - Geom::Matrix const i2dnew( i2d * _current_relative_affine ); + Geom::Affine const i2d(original_item->i2d_affine()); + Geom::Affine const i2dnew( i2d * _current_relative_affine ); copy_item->set_i2d_affine(i2dnew); new_affine = ©_item->transform; } else { @@ -624,34 +624,14 @@ void Inkscape::SelTrans::_updateHandles() return; } - // center handle - if ( _chandle == NULL ) { - _chandle = sp_knot_new(_desktop, _("<b>Center</b> of rotation and skewing: drag to reposition; scaling with Shift also uses this center")); - - _chandle->setShape (SP_CTRL_SHAPE_BITMAP); - _chandle->setSize (13); - _chandle->setAnchor (handle_center.anchor); - _chandle->setMode (SP_CTRL_MODE_XOR); - _chandle->setFill(0x00000000, 0x00000000, 0x00000000); - _chandle->setStroke(0x000000ff, 0xff0000b0, 0xff0000b0); - _chandle->setPixbuf(handles[handle_center.control]); - sp_knot_update_ctrl(_chandle); - - g_signal_connect(G_OBJECT(_chandle), "request", - G_CALLBACK(sp_sel_trans_handle_request), (gpointer) &handle_center); - g_signal_connect(G_OBJECT(_chandle), "moved", - G_CALLBACK(sp_sel_trans_handle_new_event), (gpointer) &handle_center); - g_signal_connect(G_OBJECT(_chandle), "grabbed", - G_CALLBACK(sp_sel_trans_handle_grab), (gpointer) &handle_center); - g_signal_connect(G_OBJECT(_chandle), "ungrabbed", - G_CALLBACK(sp_sel_trans_handle_ungrab), (gpointer) &handle_center); - g_signal_connect(G_OBJECT(_chandle), "clicked", - G_CALLBACK(sp_sel_trans_handle_click), (gpointer) &handle_center); + if (!_center_is_set) { + _center = _desktop->selection->center(); + _center_is_set = true; } - sp_remove_handles(&_chandle, 1); if ( _state == STATE_SCALE ) { sp_remove_handles(_rhandle, 8); + sp_remove_handles(&_chandle, 1); _showHandles(_shandle, handles_scale, 8, _("<b>Squeeze or stretch</b> selection; with <b>Ctrl</b> to scale uniformly; with <b>Shift</b> to scale around rotation center"), _("<b>Scale</b> selection; with <b>Ctrl</b> to scale uniformly; with <b>Shift</b> to scale around rotation center")); @@ -660,18 +640,47 @@ void Inkscape::SelTrans::_updateHandles() _showHandles(_rhandle, handles_rotate, 8, _("<b>Skew</b> selection; with <b>Ctrl</b> to snap angle; with <b>Shift</b> to skew around the opposite side"), _("<b>Rotate</b> selection; with <b>Ctrl</b> to snap angle; with <b>Shift</b> to rotate around the opposite corner")); - } - - if (!_center_is_set) { - _center = _desktop->selection->center(); - _center_is_set = true; - } + // center handle + /* Assuming that the center handle is in its default position, ie. in the center: + * Multiple handles will be shown, for rotating, skewing and the center handle. For straight lines, the bounding box of the center handle will be + * fully overlapped by bounding boxes of two of the skew handles. Due to the internals of sp_canvas_group_point, the center handle must be the + * last handle in the SPCanvasGroup if it is to be selectable in such a case. So we have made sure here that the center handle is added to the + * group after the rotation handles (determined by the chronological order of sp_knot_new() calls) + * Now when the center handle is in still in the center, the skew handles can be selected because because the bounding box of the + * center handle does not fully overlap the bounding box of either of the skew handles. However, if the center handle has been moved such that it + * covers one of the other eight handles, then either the opposite handle has to be used (in case of rotating), or the center handle has to be moved. + * Although this is annoying, this is still better than not being able to select the center handle at all + */ + if ( _chandle == NULL ) { + _chandle = sp_knot_new(_desktop, _("<b>Center</b> of rotation and skewing: drag to reposition; scaling with Shift also uses this center")); + + _chandle->setShape (SP_CTRL_SHAPE_BITMAP); + _chandle->setSize (13); + _chandle->setAnchor (handle_center.anchor); + _chandle->setMode (SP_CTRL_MODE_XOR); + _chandle->setFill(0x00000000, 0x00000000, 0x00000000); + _chandle->setStroke(0x000000ff, 0xff0000b0, 0xff0000b0); + _chandle->setPixbuf(handles[handle_center.control]); + sp_knot_update_ctrl(_chandle); + + g_signal_connect(G_OBJECT(_chandle), "request", + G_CALLBACK(sp_sel_trans_handle_request), (gpointer) &handle_center); + g_signal_connect(G_OBJECT(_chandle), "moved", + G_CALLBACK(sp_sel_trans_handle_new_event), (gpointer) &handle_center); + g_signal_connect(G_OBJECT(_chandle), "grabbed", + G_CALLBACK(sp_sel_trans_handle_grab), (gpointer) &handle_center); + g_signal_connect(G_OBJECT(_chandle), "ungrabbed", + G_CALLBACK(sp_sel_trans_handle_ungrab), (gpointer) &handle_center); + g_signal_connect(G_OBJECT(_chandle), "clicked", + G_CALLBACK(sp_sel_trans_handle_click), (gpointer) &handle_center); + } - if ( _state == STATE_SCALE || !_center ) { - sp_knot_hide(_chandle); - } else { - sp_knot_show(_chandle); - sp_knot_moveto(_chandle, *_center); + if ( _center ) { + sp_knot_show(_chandle); + sp_knot_moveto(_chandle, *_center); + } else { + sp_remove_handles(&_chandle, 1); + } } } @@ -786,9 +795,9 @@ void Inkscape::SelTrans::handleClick(SPKnot */*knot*/, guint state, SPSelTransHa if (state & GDK_SHIFT_MASK) { // Unset the center position for all selected items for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { - SPItem *it = (SPItem*)(SP_OBJECT(l->data)); + SPItem *it = SP_ITEM(l->data); it->unsetCenter(); - SP_OBJECT(it)->updateRepr(); + it->updateRepr(); _center_is_set = false; // center has changed _updateHandles(); } @@ -835,7 +844,7 @@ void Inkscape::SelTrans::handleNewEvent(SPKnot *knot, Geom::Point *position, gui // in case items have been unhooked from the document, don't // try to continue processing events for them. for (unsigned int i = 0; i < _items.size(); i++) { - if (!SP_OBJECT_DOCUMENT(SP_OBJECT(_items[i])) ) { + if ( !_items[i]->document ) { return; } } @@ -1520,7 +1529,7 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) } } - Geom::Matrix const move((Geom::Translate(dxy))); + Geom::Affine const move((Geom::Translate(dxy))); Geom::Point const norm(0, 0); transform(move, norm); @@ -1557,7 +1566,7 @@ Geom::Point Inkscape::SelTrans::_getGeomHandlePos(Geom::Point const &visual_hand // Calculate the absolute affine while taking into account the scaling of the stroke width Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool transform_stroke = prefs->getBool("/options/transform/stroke", true); - Geom::Matrix abs_affine = get_scale_transform_with_stroke (*_bbox, _strokewidth, transform_stroke, + Geom::Affine abs_affine = get_scale_transform_with_stroke (*_bbox, _strokewidth, transform_stroke, new_bbox.min()[Geom::X], new_bbox.min()[Geom::Y], new_bbox.max()[Geom::X], new_bbox.max()[Geom::Y]); // Calculate the scaled geometrical bbox @@ -1591,7 +1600,7 @@ Geom::Scale Inkscape::calcScaleFactors(Geom::Point const &initial_point, Geom::P // Only for scaling/stretching Geom::Point Inkscape::SelTrans::_calcAbsAffineDefault(Geom::Scale const default_scale) { - Geom::Matrix abs_affine = Geom::Translate(-_origin) * Geom::Matrix(default_scale) * Geom::Translate(_origin); + Geom::Affine abs_affine = Geom::Translate(-_origin) * Geom::Affine(default_scale) * Geom::Translate(_origin); Geom::Point new_bbox_min = _approximate_bbox->min() * abs_affine; Geom::Point new_bbox_max = _approximate_bbox->max() * abs_affine; @@ -1614,7 +1623,7 @@ Geom::Point Inkscape::SelTrans::_calcAbsAffineDefault(Geom::Scale const default_ // Only for scaling/stretching Geom::Point Inkscape::SelTrans::_calcAbsAffineGeom(Geom::Scale const geom_scale) { - _relative_affine = Geom::Matrix(geom_scale); + _relative_affine = Geom::Affine(geom_scale); _absolute_affine = Geom::Translate(-_origin_for_specpoints) * _relative_affine * Geom::Translate(_origin_for_specpoints); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -1632,26 +1641,6 @@ Geom::Point Inkscape::SelTrans::_calcAbsAffineGeom(Geom::Scale const geom_scale) return _calcAbsAffineDefault(geom_scale); // this is bogus, but we must return _something_ } -void Inkscape::SelTrans::_keepClosestPointOnly(std::vector<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference) -{ - if (points.size() < 2) return; - - Inkscape::SnapCandidatePoint closest_point = Inkscape::SnapCandidatePoint(Geom::Point(Geom::infinity(), Geom::infinity()), SNAPSOURCE_UNDEFINED, SNAPTARGET_UNDEFINED); - Geom::Coord closest_dist = Geom::infinity(); - - for(std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); i++) { - Geom::Coord dist = Geom::L2((*i).getPoint() - reference); - if (i == points.begin() || dist < closest_dist) { - closest_point = *i; - closest_dist = dist; - } - } - - closest_point.setSourceNum(-1); - points.clear(); - points.push_back(closest_point); -} - /* Local Variables: mode:c++ diff --git a/src/seltrans.h b/src/seltrans.h index 0183683ff..dd890ee9b 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -15,9 +15,10 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <stddef.h> #include <sigc++/sigc++.h> #include <2geom/point.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/rect.h> #include "knot.h" #include "forward.h" @@ -55,7 +56,7 @@ public: void resetState(); void setCenter(Geom::Point const &p); void grab(Geom::Point const &p, gdouble x, gdouble y, bool show_handles, bool translating); - void transform(Geom::Matrix const &rel_affine, Geom::Point const &norm); + void transform(Geom::Affine const &rel_affine, Geom::Point const &norm); void ungrab(); void stamp(); void moveTo(Geom::Point const &xy, guint state); @@ -103,7 +104,6 @@ private: Geom::Point _getGeomHandlePos(Geom::Point const &visual_handle_pos); Geom::Point _calcAbsAffineDefault(Geom::Scale const default_scale); Geom::Point _calcAbsAffineGeom(Geom::Scale const geom_scale); - void _keepClosestPointOnly(std::vector<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference); void _display_snapsource(); enum State { @@ -115,7 +115,7 @@ private: std::vector<SPItem *> _items; std::vector<SPItem const *> _items_const; - std::vector<Geom::Matrix> _items_affines; + std::vector<Geom::Affine> _items_affines; std::vector<Geom::Point> _items_centers; std::vector<Inkscape::SnapCandidatePoint> _snap_points; @@ -140,9 +140,9 @@ private: Geom::OptRect _geometric_bbox; gdouble _strokewidth; - Geom::Matrix _current_relative_affine; - Geom::Matrix _absolute_affine; - Geom::Matrix _relative_affine; + Geom::Affine _current_relative_affine; + Geom::Affine _absolute_affine; + Geom::Affine _relative_affine; /* According to Merriam - Webster's online dictionary * Affine: a transformation (as a translation, a rotation, or a uniform stretching) that carries straight * lines into straight lines and parallel lines into parallel lines but may alter distance between points diff --git a/src/snap-candidate.h b/src/snap-candidate.h index 772800be5..236f2497d 100644 --- a/src/snap-candidate.h +++ b/src/snap-candidate.h @@ -82,7 +82,7 @@ private: class SnapCandidateItem { public: - SnapCandidateItem(SPItem* item, bool clip_or_mask, Geom::Matrix additional_affine) + SnapCandidateItem(SPItem* item, bool clip_or_mask, Geom::Affine additional_affine) : item(item), clip_or_mask(clip_or_mask), additional_affine(additional_affine) {} ~SnapCandidateItem() {}; @@ -93,7 +93,7 @@ public: * the transformation of the clipping path or mask itself, but also the transformation of * the object to which the clip or mask is being applied; that transformation is stored here */ - Geom::Matrix additional_affine; + Geom::Affine additional_affine; } ; diff --git a/src/snap.cpp b/src/snap.cpp index 7b0b4ce48..f8fe8e3fa 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -22,6 +22,7 @@ #include "sp-namedview.h" #include "snap.h" +#include "snap-enums.h" #include "snapped-line.h" #include "snapped-curve.h" @@ -682,7 +683,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( Geom::Point const &transformation, Geom::Point const &origin, Geom::Dim2 dim, - bool uniform) const + bool uniform) { /* We have a list of points, which we are proposing to transform in some way. We need to see ** if any of these points, when transformed, snap to anything. If they do, we return the @@ -734,6 +735,12 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( g_warning("Unconstrained rotation is not supported!"); } + // We will try to snap a set of points, but we don't want to have a snap indicator displayed + // for each of them. That's why it's temporarily disabled here, and re-enabled again after we + // have finished calling the freeSnap() and constrainedSnap() methods + bool _orig_snapindicator_status = _snapindicator; + _snapindicator = false; + std::vector<Inkscape::SnapCandidatePoint>::iterator j = transformed_points.begin(); // std::cout << std::endl; @@ -753,16 +760,6 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, b); } else if (transformation_type == ROTATE) { Geom::Coord r = Geom::L2(b); // the radius of the circular constraint - if (r < 1e-9) { // points too close to the rotation center will not move. Don't try to snap these - // as they will always yield a perfect snap result if they're already snapped beforehand (e.g. - // when the transformation center has been snapped to a grid intersection in the selector tool) - continue; // skip this SnapCandidate and continue with the next one - // PS1: Apparently we don't have to do this for skewing, but why? - // PS2: We cannot easily filter these points upstream, e.g. in the grab() method (seltrans.cpp) - // because the rotation center will change when pressing shift, and grab() won't be recalled. - // Filtering could be done in handleRequest() (again in seltrans.cpp), by iterating through - // the snap candidates. But hey, we're iterating here anyway. - } dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, b, r); } else if (transformation_type == STRETCH) { // when non-uniform stretching { dedicated_constraint = Inkscape::Snapper::SnapConstraint((*i).getPoint(), component_vectors[dim]); @@ -802,6 +799,9 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl; snapped_point.setPointerDistance(Geom::L2(pointer - (*i).getPoint())); + // Allow the snapindicator to be displayed again + _snapindicator = _orig_snapindicator_status; + Geom::Point result; /*Find the transformation that describes where the snapped point has @@ -816,11 +816,11 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( /* Consider the case in which a box is almost aligned with a grid in both * horizontal and vertical directions. The distance to the intersection of * the grid lines will always be larger then the distance to a single grid - * line. If we prefer snapping to an intersection instead of to a single + * line. If we prefer snapping to an intersection over to a single * grid line, then we cannot use "metric = Geom::L2(result)". Therefore the * snapped distance will be used as a metric. Please note that the snapped - * distance is defined as the distance to the nearest line of the intersection, - * and not to the intersection itself! + * distance to an intersection is defined as the distance to the nearest line + * of the intersection, and not to the intersection itself! */ // Only for translations, the relevant metric will be the real snapped distance, // so we don't have to do anything special here @@ -838,7 +838,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( if (fabs(fabs(a[index]/b[index]) - fabs(transformation[index])) > 1e-12) { // if SNAPPING DID occur in this direction result[index] = a[index] / b[index]; // then calculate it! } - // we might leave result[1-index] = NR_HUGE + // we might have left result[1-index] = NR_HUGE // if scaling didn't occur in the other direction } } @@ -851,8 +851,12 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( } // Compare the resulting scaling with the desired scaling Geom::Point scale_metric = Geom::abs(result - transformation); // One or both of its components might be NR_HUGE - snapped_point.setSnapDistance(std::min(scale_metric[0], scale_metric[1])); - snapped_point.setSecondSnapDistance(std::max(scale_metric[0], scale_metric[1])); + if (scale_metric[0] == NR_HUGE || scale_metric[1] == NR_HUGE) { + snapped_point.setSnapDistance(std::min(scale_metric[0], scale_metric[1])); + } else { + snapped_point.setSnapDistance(Geom::L2(scale_metric)); + } + snapped_point.setSecondSnapDistance(NR_HUGE); break; } case STRETCH: @@ -881,8 +885,18 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( // a is vector to snapped point; b is vector to original point; now lets calculate angle between a and b result[0] = atan2(Geom::dot(Geom::rot90(b), a), Geom::dot(b, a)); result[1] = result[1]; // how else should we store an angle in a point ;-) - // Store the metric for this transformation as a virtual distance (we're storing an angle) - snapped_point.setSnapDistance(std::abs(result[0] - transformation[0])); + if (Geom::L2(b) < 1e-9) { // points too close to the rotation center will not move. Don't try to snap these + // as they will always yield a perfect snap result if they're already snapped beforehand (e.g. + // when the transformation center has been snapped to a grid intersection in the selector tool) + snapped_point.setSnapDistance(NR_HUGE); + // PS1: Apparently we don't have to do this for skewing, but why? + // PS2: We cannot easily filter these points upstream, e.g. in the grab() method (seltrans.cpp) + // because the rotation center will change when pressing shift, and grab() won't be recalled. + // Filtering could be done in handleRequest() (again in seltrans.cpp), by iterating through + // the snap candidates. But hey, we're iterating here anyway. + } else { + snapped_point.setSnapDistance(std::abs(result[0] - transformation[0])); + } snapped_point.setSecondSnapDistance(NR_HUGE); break; default: @@ -932,6 +946,14 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( // Using " < 1e6" instead of " < Geom::infinity()" for catching some rounding errors // These rounding errors might be caused by NRRects, see bug #1584301 best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : Geom::infinity()); + + if (_snapindicator) { + if (best_snapped_point.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(best_snapped_point); + } else { + _desktop->snapindicator->remove_snaptarget(); + } + } return best_snapped_point; } @@ -947,7 +969,7 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( Inkscape::SnappedPoint SnapManager::freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, - Geom::Point const &tr) const + Geom::Point const &tr) { Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), TRANSLATE, tr, Geom::Point(0,0), Geom::X, false); @@ -971,7 +993,7 @@ Inkscape::SnappedPoint SnapManager::freeSnapTranslate(std::vector<Inkscape::Snap Inkscape::SnappedPoint SnapManager::constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Inkscape::Snapper::SnapConstraint const &constraint, - Geom::Point const &tr) const + Geom::Point const &tr) { Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, constraint, TRANSLATE, tr, Geom::Point(0,0), Geom::X, false); @@ -996,7 +1018,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapTranslate(std::vector<Inkscap Inkscape::SnappedPoint SnapManager::freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Geom::Scale const &s, - Geom::Point const &o) const + Geom::Point const &o) { Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false); @@ -1021,7 +1043,7 @@ Inkscape::SnappedPoint SnapManager::freeSnapScale(std::vector<Inkscape::SnapCand Inkscape::SnappedPoint SnapManager::constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Geom::Scale const &s, - Geom::Point const &o) const + Geom::Point const &o) { // When constrained scaling, only uniform scaling is supported. Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true); @@ -1050,7 +1072,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapStretch(std::vector<Inkscape: Geom::Coord const &s, Geom::Point const &o, Geom::Dim2 d, - bool u) const + bool u) { Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u); @@ -1078,7 +1100,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(std::vector<Inkscape::Sn Inkscape::Snapper::SnapConstraint const &constraint, Geom::Point const &s, Geom::Point const &o, - Geom::Dim2 d) const + Geom::Dim2 d) { // "s" contains skew factor in s[0], and scale factor in s[1] @@ -1113,7 +1135,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(std::vector<Inkscape::Sn Inkscape::SnappedPoint SnapManager::constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Geom::Coord const &angle, - Geom::Point const &o) const + Geom::Point const &o) { // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if // the transformation of the bounding box is equal to the transformation of the individual nodes. This is @@ -1429,6 +1451,26 @@ void SnapManager::_displaySnapsource(Inkscape::SnapCandidatePoint const &p) cons } } +void SnapManager::keepClosestPointOnly(std::vector<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference) const +{ + if (points.size() < 2) return; + + Inkscape::SnapCandidatePoint closest_point = Inkscape::SnapCandidatePoint(Geom::Point(NR_HUGE, NR_HUGE), Inkscape::SNAPSOURCE_UNDEFINED, Inkscape::SNAPTARGET_UNDEFINED); + Geom::Coord closest_dist = NR_HUGE; + + for(std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); i++) { + Geom::Coord dist = Geom::L2((*i).getPoint() - reference); + if (i == points.begin() || dist < closest_dist) { + closest_point = *i; + closest_dist = dist; + } + } + + closest_point.setSourceNum(-1); + points.clear(); + points.push_back(closest_point); +} + /* Local Variables: mode:c++ diff --git a/src/snap.h b/src/snap.h index c79bd308a..8f8416ee5 100644 --- a/src/snap.h +++ b/src/snap.h @@ -149,41 +149,41 @@ public: Inkscape::SnappedPoint freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, - Geom::Point const &tr) const; + Geom::Point const &tr); Inkscape::SnappedPoint constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Inkscape::Snapper::SnapConstraint const &constraint, - Geom::Point const &tr) const; + Geom::Point const &tr); Inkscape::SnappedPoint freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Geom::Scale const &s, - Geom::Point const &o) const; + Geom::Point const &o); Inkscape::SnappedPoint constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Geom::Scale const &s, - Geom::Point const &o) const; + Geom::Point const &o); Inkscape::SnappedPoint constrainedSnapStretch(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Geom::Coord const &s, Geom::Point const &o, Geom::Dim2 d, - bool uniform) const; + bool uniform); Inkscape::SnappedPoint constrainedSnapSkew(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Inkscape::Snapper::SnapConstraint const &constraint, Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor Geom::Point const &o, - Geom::Dim2 d) const; + Geom::Dim2 d); Inkscape::SnappedPoint constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p, Geom::Point const &pointer, Geom::Coord const &angle, - Geom::Point const &o) const; + Geom::Point const &o); Inkscape::GuideSnapper guide; ///< guide snapper Inkscape::ObjectSnapper object; ///< snapper to other objects @@ -200,6 +200,7 @@ public: bool getSnapIndicator() const {return _snapindicator;} Inkscape::SnappedPoint findBestSnap(Inkscape::SnapCandidatePoint const &p, SnappedConstraints const &sc, bool constrained, bool noCurves = false, bool allowOffScreen = false) const; + void keepClosestPointOnly(std::vector<Inkscape::SnapCandidatePoint> &points, const Geom::Point &reference) const; protected: SPNamedView const *_named_view; @@ -220,7 +221,7 @@ private: Geom::Point const &transformation, Geom::Point const &origin, Geom::Dim2 dim, - bool uniform) const; + bool uniform); Geom::Point _transformPoint(Inkscape::SnapCandidatePoint const &p, Transformation const transformation_type, diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp index 3d563a3ec..4876b896d 100644 --- a/src/snapped-curve.cpp +++ b/src/snapped-curve.cpp @@ -56,7 +56,7 @@ Inkscape::SnappedCurve::~SnappedCurve() { } -Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, Geom::Point const &p, Geom::Matrix dt2doc) const +Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, Geom::Point const &p, Geom::Affine dt2doc) const { // Calculate the intersections of two curves, which are both within snapping range, and // return only the closest intersection @@ -125,7 +125,7 @@ bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::Sn } // search for the closest intersection of two snapped curves, which are both member of the same collection -bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geom::Point const &p, Inkscape::SnappedPoint &result, Geom::Matrix dt2doc) +bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geom::Point const &p, Inkscape::SnappedPoint &result, Geom::Affine dt2doc) { bool success = false; diff --git a/src/snapped-curve.h b/src/snapped-curve.h index 595f84411..ed04576df 100644 --- a/src/snapped-curve.h +++ b/src/snapped-curve.h @@ -26,7 +26,7 @@ public: SnappedCurve(); SnappedCurve(Geom::Point const &snapped_point, int num_path, int num_segm, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve, SnapSourceType source, long source_num, SnapTargetType target, Geom::OptRect target_bbox); ~SnappedCurve(); - Inkscape::SnappedPoint intersect(SnappedCurve const &curve, Geom::Point const &p, Geom::Matrix dt2doc) const; //intersect with another SnappedCurve + Inkscape::SnappedPoint intersect(SnappedCurve const &curve, Geom::Point const &p, Geom::Affine dt2doc) const; //intersect with another SnappedCurve private: Geom::Curve const *_curve; @@ -37,7 +37,7 @@ private: } bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::SnappedCurve &result); -bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geom::Point const &p, Inkscape::SnappedPoint &result, Geom::Matrix dt2doc); +bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geom::Point const &p, Inkscape::SnappedPoint &result, Geom::Affine dt2doc); #endif /* !SEEN_SNAPPEDCURVE_H */ diff --git a/src/sp-anchor.cpp b/src/sp-anchor.cpp index e57ac8a58..517512eb2 100644 --- a/src/sp-anchor.cpp +++ b/src/sp-anchor.cpp @@ -152,7 +152,7 @@ static Inkscape::XML::Node *sp_anchor_write(SPObject *object, Inkscape::XML::Doc repr->setAttribute("xlink:href", anchor->href); - if (repr != SP_OBJECT_REPR(object)) { + if (repr != object->getRepr()) { // XML Tree being directly used while it shouldn't be in the // below COPY_ATTR lines COPY_ATTR(repr, object->getRepr(), "xlink:type"); diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 310008713..4e9f37ee3 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -97,9 +97,9 @@ void SPClipPath::build(SPObject *object, SPDocument *document, Inkscape::XML::No void SPClipPath::release(SPObject * object) { - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("clipPath", object); + if (object->document) { + // Unregister ourselves + object->document->removeResource("clipPath", object); } SPClipPath *cp = SP_CLIPPATH(object); @@ -145,7 +145,7 @@ void SPClipPath::childAdded(SPObject *object, Inkscape::XML::Node *child, Inksca ((SPObjectClass *) (SPClipPathClass::static_parent_class))->child_added(object, child, ref); /* Show new object */ - SPObject *ochild = SP_OBJECT_DOCUMENT(object)->getObjectByRepr(child); + SPObject *ochild = object->document->getObjectByRepr(child); if (SP_IS_ITEM(ochild)) { SPClipPath *cp = SP_CLIPPATH(object); for (SPClipPathView *v = cp->display; v != NULL; v = v->next) { @@ -186,7 +186,7 @@ void SPClipPath::update(SPObject *object, SPCtx *ctx, guint flags) SPClipPath *cp = SP_CLIPPATH(object); for (SPClipPathView *v = cp->display; v != NULL; v = v->next) { if (cp->clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix t(Geom::Scale(v->bbox.x1 - v->bbox.x0, v->bbox.y1 - v->bbox.y0)); + Geom::Affine t(Geom::Scale(v->bbox.x1 - v->bbox.x0, v->bbox.y1 - v->bbox.y0)); t[4] = v->bbox.x0; t[5] = v->bbox.y0; nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), &t); @@ -253,7 +253,7 @@ NRArenaItem *SPClipPath::show(NRArena *arena, unsigned int key) } if (clipPathUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix t(Geom::Scale(display->bbox.x1 - display->bbox.x0, display->bbox.y1 - display->bbox.y0)); + Geom::Affine t(Geom::Scale(display->bbox.x1 - display->bbox.x0, display->bbox.y1 - display->bbox.y0)); t[4] = display->bbox.x0; t[5] = display->bbox.y0; nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), &t); @@ -296,7 +296,7 @@ void SPClipPath::setBBox(unsigned int key, NRRect *bbox) } } -void SPClipPath::getBBox(NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) +void SPClipPath::getBBox(NRRect *bbox, Geom::Affine const &transform, unsigned const /*flags*/) { SPObject *i = 0; for (i = firstChild(); i && !SP_IS_ITEM(i); i = i->getNext()) { @@ -305,13 +305,13 @@ void SPClipPath::getBBox(NRRect *bbox, Geom::Matrix const &transform, unsigned c return; } - SP_ITEM(i)->invoke_bbox_full( bbox, Geom::Matrix(SP_ITEM(i)->transform) * transform, SPItem::GEOMETRIC_BBOX, FALSE); + SP_ITEM(i)->invoke_bbox_full( bbox, Geom::Affine(SP_ITEM(i)->transform) * transform, SPItem::GEOMETRIC_BBOX, FALSE); SPObject *i_start = i; while (i != NULL) { if (i != i_start) { NRRect i_box; - SP_ITEM(i)->invoke_bbox_full( &i_box, Geom::Matrix(SP_ITEM(i)->transform) * transform, SPItem::GEOMETRIC_BBOX, FALSE); + SP_ITEM(i)->invoke_bbox_full( &i_box, Geom::Affine(SP_ITEM(i)->transform) * transform, SPItem::GEOMETRIC_BBOX, FALSE); nr_rect_d_union (bbox, bbox, &i_box); } i = i->getNext(); @@ -354,9 +354,9 @@ sp_clippath_view_list_remove(SPClipPathView *list, SPClipPathView *view) } // Create a mask element (using passed elements), add it to <defs> -const gchar *SPClipPath::create (GSList *reprs, SPDocument *document, Geom::Matrix const* applyTransform) +const gchar *SPClipPath::create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform) { - Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); + Inkscape::XML::Node *defsrepr = SP_DOCUMENT_DEFS(document)->getRepr(); Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:clipPath"); @@ -371,9 +371,9 @@ const gchar *SPClipPath::create (GSList *reprs, SPDocument *document, Geom::Matr SPItem *item = SP_ITEM(clip_path_object->appendChildRepr(node)); if (NULL != applyTransform) { - Geom::Matrix transform (item->transform); + Geom::Affine transform (item->transform); transform *= (*applyTransform); - item->doWriteTransform(SP_OBJECT_REPR(item), transform); + item->doWriteTransform(item->getRepr(), transform); } } diff --git a/src/sp-clippath.h b/src/sp-clippath.h index a622df1f6..d3c650ca6 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -37,14 +37,14 @@ public: unsigned int clipPathUnits : 1; SPClipPathView *display; - static const gchar *create(GSList *reprs, SPDocument *document, Geom::Matrix const* applyTransform); + static const gchar *create(GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform); static GType sp_clippath_get_type(void); NRArenaItem *show(NRArena *arena, unsigned int key); void hide(unsigned int key); void setBBox(unsigned int key, NRRect *bbox); - void getBBox(NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); + void getBBox(NRRect *bbox, Geom::Affine const &transform, unsigned const flags); private: static void init(SPClipPath *clippath); diff --git a/src/sp-conn-end-pair.cpp b/src/sp-conn-end-pair.cpp index 0a5a6d7bd..3cc022c39 100644 --- a/src/sp-conn-end-pair.cpp +++ b/src/sp-conn-end-pair.cpp @@ -90,7 +90,7 @@ sp_conn_end_pair_build(SPObject *object) static void -avoid_conn_transformed(Geom::Matrix const */*mp*/, SPItem *moved_item) +avoid_conn_transformed(Geom::Affine const */*mp*/, SPItem *moved_item) { SPPath *path = SP_PATH(moved_item); if (path->connEndPair.isAutoRoutingConn()) { @@ -217,6 +217,7 @@ SPConnEndPair::getEndpoints(Geom::Point endPts[]) const { SPCurve *curve = _path->original_curve ? _path->original_curve : _path->curve; SPItem *h2attItem[2]; getAttachedItems(h2attItem); + Geom::Affine i2d = SP_ITEM(_path)->i2doc_affine(); for (unsigned h = 0; h < 2; ++h) { if ( h2attItem[h] ) { @@ -226,10 +227,10 @@ SPConnEndPair::getEndpoints(Geom::Point endPts[]) const { else { if (h == 0) { - endPts[h] = *(curve->first_point()); + endPts[h] = *(curve->first_point())*i2d; } else { - endPts[h] = *(curve->last_point()); + endPts[h] = *(curve->last_point())*i2d; } } } @@ -406,7 +407,7 @@ SPConnEndPair::reroutePathFromLibavoid(void) recreateCurve( curve, _connRef, _connCurvature ); - Geom::Matrix doc2item = SP_ITEM(_path)->i2doc_affine().inverse(); + Geom::Affine doc2item = SP_ITEM(_path)->i2doc_affine().inverse(); curve->transform(doc2item); return true; diff --git a/src/sp-conn-end-pair.h b/src/sp-conn-end-pair.h index 3b011ed17..6e62b9839 100644 --- a/src/sp-conn-end-pair.h +++ b/src/sp-conn-end-pair.h @@ -15,6 +15,7 @@ #include "forward.h" #include "libnr/nr-point.h" +#include <stddef.h> #include <sigc++/connection.h> #include <sigc++/functors/slot.h> #include <sigc++/signal.h> @@ -22,6 +23,8 @@ class SPConnEnd; +struct SPCurve; + namespace Inkscape { namespace XML { class Node; diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index e97b6f4ec..538638d7a 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -42,7 +42,7 @@ get_nearest_common_ancestor(SPObject const *const obj, SPItem const *const objs[ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_pv, SPItem* item, - const Geom::Matrix& item_transform, double& intersect_pos) { + const Geom::Affine& item_transform, double& intersect_pos) { double initial_pos = intersect_pos; // if this is a group... @@ -95,7 +95,7 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p // The transforms given should be to a common ancestor of both the path and item. // static bool try_get_intersect_point_with_item(SPPath* conn, SPItem* item, - const Geom::Matrix& item_transform, const Geom::Matrix& conn_transform, + const Geom::Affine& item_transform, const Geom::Affine& conn_transform, const bool at_start, double& intersect_pos) { // Copy the curve and apply transformations up to common ancestor. @@ -146,7 +146,7 @@ sp_conn_get_route_and_redraw(SPPath *const path, SPItem const *const path_item = SP_ITEM(path); SPObject const *const ancestor = get_nearest_common_ancestor(path_item, h2attItem); - Geom::Matrix const path2anc(i2anc_affine(path_item, ancestor)); + Geom::Affine const path2anc(i2anc_affine(path_item, ancestor)); // Set sensible values incase there the connector ends are not // attached to any shapes. @@ -156,7 +156,7 @@ sp_conn_get_route_and_redraw(SPPath *const path, SPConnEnd** _connEnd = path->connEndPair.getConnEnds(); for (unsigned h = 0; h < 2; ++h) { if (h2attItem[h] && _connEnd[h]->type == ConnPointDefault && _connEnd[h]->id == ConnPointPosCC) { - Geom::Matrix h2i2anc = i2anc_affine(h2attItem[h], ancestor); + Geom::Affine h2i2anc = i2anc_affine(h2attItem[h], ancestor); try_get_intersect_point_with_item(path, h2attItem[h], h2i2anc, path2anc, (h == 0), endPos[h]); } @@ -170,7 +170,7 @@ sp_conn_get_route_and_redraw(SPPath *const path, static void -sp_conn_end_shape_move(Geom::Matrix const */*mp*/, SPItem */*moved_item*/, +sp_conn_end_shape_move(Geom::Affine const */*mp*/, SPItem */*moved_item*/, SPPath *const path) { if (path->connEndPair.isAutoRoutingConn()) { @@ -232,8 +232,8 @@ sp_conn_end_deleted(SPObject *, SPObject *const owner, unsigned const handle_ix) g_return_if_fail(handle_ix < 2); char const * const attr_strs[] = {"inkscape:connection-start", "inkscape:connection-start-point", "inkscape:connection-end", "inkscape:connection-end-point"}; - SP_OBJECT_REPR(owner)->setAttribute(attr_strs[2*handle_ix], NULL); - SP_OBJECT_REPR(owner)->setAttribute(attr_strs[2*handle_ix+1], NULL); + owner->getRepr()->setAttribute(attr_strs[2*handle_ix], NULL); + owner->getRepr()->setAttribute(attr_strs[2*handle_ix+1], NULL); /* I believe this will trigger sp_conn_end_href_changed. */ } @@ -374,8 +374,8 @@ sp_conn_end_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPObject *refobj = connEnd.ref.getObject(); if (refobj) { connEnd._delete_connection - = SP_OBJECT(refobj)->connectDelete(sigc::bind(sigc::ptr_fun(&sp_conn_end_deleted), - SP_OBJECT(path), handle_ix)); + = refobj->connectDelete(sigc::bind(sigc::ptr_fun(&sp_conn_end_deleted), + path, handle_ix)); connEnd._transformed_connection = SP_ITEM(refobj)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_conn_end_shape_move), path)); diff --git a/src/sp-conn-end.h b/src/sp-conn-end.h index 16a611ec4..052e8ddcb 100644 --- a/src/sp-conn-end.h +++ b/src/sp-conn-end.h @@ -2,6 +2,7 @@ #define SEEN_SP_CONN_END #include <glib/gtypes.h> +#include <stddef.h> #include <sigc++/connection.h> #include "sp-use-reference.h" diff --git a/src/sp-desc.cpp b/src/sp-desc.cpp index 1c8229847..18b1a1cad 100644 --- a/src/sp-desc.cpp +++ b/src/sp-desc.cpp @@ -66,11 +66,12 @@ static Inkscape::XML::Node * sp_desc_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { if (!repr) { - repr = SP_OBJECT_REPR (object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } - if (((SPObjectClass *) desc_parent_class)->write) + if (((SPObjectClass *) desc_parent_class)->write) { ((SPObjectClass *) desc_parent_class)->write(object, doc, repr, flags); + } return repr; } diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index 5d17b0206..cf5927fc8 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -166,7 +166,7 @@ sp_genericellipse_update_patheffect(SPLPEItem *lpeitem, bool write) sp_genericellipse_set_shape(shape); if (write) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); + Inkscape::XML::Node *repr = shape->getRepr(); if ( shape->curve != NULL ) { gchar *str = sp_svg_write_path(shape->curve->get_pathvector()); repr->setAttribute("d", str); @@ -185,9 +185,9 @@ static void sp_genericellipse_set_shape(SPShape *shape) { if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) { g_warning ("The ellipse shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as ellipse will remove the bad LPE"); - if (SP_OBJECT_REPR(shape)->attribute("d")) { + if (shape->getRepr()->attribute("d")) { // unconditionally read the curve from d, if any, to preserve appearance - Geom::PathVector pv = sp_svg_read_pathv(SP_OBJECT_REPR(shape)->attribute("d")); + Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); SPCurve *cold = new SPCurve(pv); shape->setCurveInsync( cold, TRUE); cold->unref(); @@ -251,12 +251,14 @@ static void sp_genericellipse_set_shape(SPShape *shape) curve->closepath(); } - Geom::Matrix aff = Geom::Scale(rx, ry) * Geom::Translate(ellipse->cx.computed, ellipse->cy.computed); + Geom::Affine aff = Geom::Scale(rx, ry) * Geom::Translate(ellipse->cx.computed, ellipse->cy.computed); curve->transform(aff); - /* Reset the shape'scurve to the "original_curve" + /* Reset the shape's curve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ shape->setCurveInsync( curve, TRUE); + shape->setCurveBeforeLPE(curve); + if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { SPCurve *c_lpe = curve->copy(); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); @@ -280,7 +282,7 @@ static void sp_genericellipse_snappoints(SPItem const *item, std::vector<Inkscap SPGenericEllipse *ellipse = SP_GENERICELLIPSE(item); sp_genericellipse_normalize(ellipse); - Geom::Matrix const i2d = item->i2d_affine(); + Geom::Affine const i2d = item->i2d_affine(); // figure out if we have a slice, while guarding against rounding errors bool slice = false; @@ -362,12 +364,14 @@ static Inkscape::XML::Node *sp_genericellipse_write(SPObject *object, Inkscape:: sp_repr_set_svg_double(repr, "sodipodi:rx", ellipse->rx.computed); sp_repr_set_svg_double(repr, "sodipodi:ry", ellipse->ry.computed); - if (SP_IS_ARC(ellipse)) - sp_arc_set_elliptical_path_attribute(SP_ARC(object), SP_OBJECT_REPR(object)); + if (SP_IS_ARC(ellipse)) { + sp_arc_set_elliptical_path_attribute(SP_ARC(object), object->getRepr()); + } } - if (((SPObjectClass *) ge_parent_class)->write) + if (((SPObjectClass *) ge_parent_class)->write) { ((SPObjectClass *) ge_parent_class)->write(object, xml_doc, repr, flags); + } return repr; } diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp index 30eda7159..c186c7fd9 100644 --- a/src/sp-filter-primitive.cpp +++ b/src/sp-filter-primitive.cpp @@ -84,6 +84,16 @@ sp_filter_primitive_init(SPFilterPrimitive *filter_primitive) { filter_primitive->image_in = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; filter_primitive->image_out = Inkscape::Filters::NR_FILTER_SLOT_NOT_SET; + + // We must keep track if a value is set or not, if not set then the region defaults to 0%, 0%, + // 100%, 100% ("x", "y", "width", "height") of the -> filter <- region. If set then + // percentages are in terms of bounding box or viewbox, depending on value of "primitiveUnits" + + // NB: SVGLength.set takes prescaled percent values: 1 means 100% + filter_primitive->x.unset(SVGLength::PERCENT, 0, 0); + filter_primitive->y.unset(SVGLength::PERCENT, 0, 0); + filter_primitive->width.unset(SVGLength::PERCENT, 1, 0); + filter_primitive->height.unset(SVGLength::PERCENT, 1, 0); } /** @@ -100,6 +110,10 @@ sp_filter_primitive_build(SPObject *object, SPDocument *document, Inkscape::XML: object->readAttr( "in" ); object->readAttr( "result" ); + object->readAttr( "x" ); + object->readAttr( "y" ); + object->readAttr( "width" ); + object->readAttr( "height" ); } /** @@ -121,7 +135,6 @@ sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value) { SPFilterPrimitive *filter_primitive = SP_FILTER_PRIMITIVE(object); (void)filter_primitive; - int image_nr; switch (key) { case SP_ATTR_IN: @@ -146,6 +159,24 @@ sp_filter_primitive_set(SPObject *object, unsigned int key, gchar const *value) object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } break; + + /* Filter primitive sub-region */ + case SP_ATTR_X: + filter_primitive->x.readOrUnset(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + case SP_ATTR_Y: + filter_primitive->y.readOrUnset(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + case SP_ATTR_WIDTH: + filter_primitive->width.readOrUnset(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + case SP_ATTR_HEIGHT: + filter_primitive->height.readOrUnset(value); + object->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; } /* See if any parents need this value. */ @@ -165,6 +196,10 @@ sp_filter_primitive_update(SPObject *object, SPCtx *ctx, guint flags) if (flags & SP_OBJECT_MODIFIED_FLAG) { object->readAttr( "in" ); object->readAttr( "result" ); + object->readAttr( "x" ); + object->readAttr( "y" ); + object->readAttr( "width" ); + object->readAttr( "height" ); } if (((SPObjectClass *) filter_primitive_parent_class)->update) { @@ -182,7 +217,7 @@ sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inksca SPFilter *parent = SP_FILTER(object->parent); if (!repr) { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } gchar const *in_name = sp_filter_name_for_image(parent, prim->image_in); @@ -191,6 +226,7 @@ sp_filter_primitive_write(SPObject *object, Inkscape::XML::Document *doc, Inksca gchar const *out_name = sp_filter_name_for_image(parent, prim->image_out); repr->setAttribute("result", out_name); + /* Do we need to add x,y,width,height? */ if (((SPObjectClass *) filter_primitive_parent_class)->write) { ((SPObjectClass *) filter_primitive_parent_class)->write(object, doc, repr, flags); } @@ -279,6 +315,7 @@ void sp_filter_primitive_renderer_common(SPFilterPrimitive *sp_prim, Inkscape::F nr_prim->set_output(sp_prim->image_out); /* TODO: place here code to handle input images, filter area etc. */ + nr_prim->set_subregion( sp_prim->x, sp_prim->y, sp_prim->width, sp_prim->height ); } diff --git a/src/sp-filter-primitive.h b/src/sp-filter-primitive.h index 4ebe5df1a..60104047e 100644 --- a/src/sp-filter-primitive.h +++ b/src/sp-filter-primitive.h @@ -15,6 +15,7 @@ */ #include "sp-object.h" +#include "svg/svg-length.h" #define SP_TYPE_FILTER_PRIMITIVE (sp_filter_primitive_get_type ()) #define SP_FILTER_PRIMITIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_FILTER_PRIMITIVE, SPFilterPrimitive)) @@ -33,6 +34,9 @@ class FilterPrimitive; struct SPFilterPrimitive : public SPObject { int image_in, image_out; + + /* filter primitive subregion */ + SVGLength x, y, height, width; }; struct SPFilterPrimitiveClass { diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index ce752f603..a7c1aa1fb 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -100,7 +100,7 @@ sp_filter_class_init(SPFilterClass *klass) static void sp_filter_init(SPFilter *filter) { - filter->href = new SPFilterReference(SP_OBJECT(filter)); + filter->href = new SPFilterReference(filter); filter->href->changedSignal().connect(sigc::bind(sigc::ptr_fun(filter_ref_changed), filter)); filter->x = 0; @@ -153,14 +153,13 @@ sp_filter_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep /** * Drops any allocated memory. */ -static void -sp_filter_release(SPObject *object) +static void sp_filter_release(SPObject *object) { SPFilter *filter = SP_FILTER(object); - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("filter", SP_OBJECT(object)); + if (object->document) { + // Unregister ourselves + object->document->removeResource("filter", object); } //TODO: release resources here @@ -405,10 +404,9 @@ filter_ref_changed(SPObject *old_ref, SPObject *ref, SPFilter *filter) filter_ref_modified(ref, 0, filter); } -static void -filter_ref_modified(SPObject */*href*/, guint /*flags*/, SPFilter *filter) +static void filter_ref_modified(SPObject */*href*/, guint /*flags*/, SPFilter *filter) { - SP_OBJECT(filter)->requestModified(SP_OBJECT_MODIFIED_FLAG); + filter->requestModified(SP_OBJECT_MODIFIED_FLAG); } /** @@ -553,7 +551,7 @@ Glib::ustring sp_filter_get_new_result_name(SPFilter *filter) { SPObject *primitive_obj = filter->children; while (primitive_obj) { if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(primitive_obj); + Inkscape::XML::Node *repr = primitive_obj->getRepr(); char const *result = repr->attribute("result"); int index; if (result && sscanf(result, "result%d", &index) == 1) { diff --git a/src/sp-flowdiv.cpp b/src/sp-flowdiv.cpp index c3ff96a7d..5cb258735 100644 --- a/src/sp-flowdiv.cpp +++ b/src/sp-flowdiv.cpp @@ -404,7 +404,7 @@ static Inkscape::XML::Node *sp_flowtspan_write(SPObject *object, Inkscape::XML:: } else if ( SP_IS_FLOWPARA(child) ) { child->updateRepr(flags); } else if ( SP_IS_STRING(child) ) { - SP_OBJECT_REPR(child)->setContent(SP_STRING(child)->string.c_str()); + child->getRepr()->setContent(SP_STRING(child)->string.c_str()); } } } diff --git a/src/sp-flowregion.cpp b/src/sp-flowregion.cpp index 680589b55..46690167f 100644 --- a/src/sp-flowregion.cpp +++ b/src/sp-flowregion.cpp @@ -502,12 +502,12 @@ static void GetDest(SPObject* child,Shape **computed) if ( child == NULL ) return; SPCurve *curve=NULL; - Geom::Matrix tr_mat; + Geom::Affine tr_mat; SPObject* u_child=child; if ( SP_IS_USE(u_child) ) { u_child=SP_USE(u_child)->child; - tr_mat = SP_ITEM(u_child)->getRelativeTransform(SP_OBJECT_PARENT(child)); + tr_mat = SP_ITEM(u_child)->getRelativeTransform(child->parent); } else { tr_mat = SP_ITEM(u_child)->transform; } @@ -524,7 +524,7 @@ static void GetDest(SPObject* child,Shape **computed) temp->Convert(0.25); temp->Fill(n_shp,0); Shape* uncross=new Shape; - SPStyle* style=SP_OBJECT_STYLE(u_child); + SPStyle* style = u_child->style; if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) { uncross->ConvertToShape(n_shp,fill_oddEven); } else { diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index 3af12064f..d7bc0053f 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -46,7 +46,7 @@ static Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::D static void sp_flowtext_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); static void sp_flowtext_set(SPObject *object, unsigned key, gchar const *value); -static void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_flowtext_print(SPItem *item, SPPrintContext *ctx); static gchar *sp_flowtext_description(SPItem *item); static void sp_flowtext_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); @@ -180,7 +180,7 @@ static void sp_flowtext_update(SPObject *object, SPCtx *ctx, unsigned flags) group->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView *v = group->display; v != NULL; v = v->next) { group->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); // pass the bbox of the flowtext object as paintbox (used for paintserver fills) group->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); } @@ -201,7 +201,7 @@ static void sp_flowtext_modified(SPObject *object, guint flags) text->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView* v = text->display; v != NULL; v = v->next) { text->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); } } @@ -241,7 +241,7 @@ sp_flowtext_set(SPObject *object, unsigned key, gchar const *value) case SP_ATTR_LAYOUT_OPTIONS: { // deprecated attribute, read for backward compatibility only //XML Tree being directly used while it shouldn't be. - SPCSSAttr *opts = sp_repr_css_attr((SP_OBJECT(group))->getRepr(), "inkscape:layoutOptions"); + SPCSSAttr *opts = sp_repr_css_attr(group->getRepr(), "inkscape:layoutOptions"); { gchar const *val = sp_repr_css_property(opts, "justification", NULL); if (val != NULL && !object->style->text_align.set) { @@ -328,13 +328,13 @@ static Inkscape::XML::Node *sp_flowtext_write(SPObject *object, Inkscape::XML::D } static void -sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) +sp_flowtext_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const /*flags*/) { SPFlowtext *group = SP_FLOWTEXT(item); group->layout.getBoundingBox(bbox, transform); // Add stroke width - SPStyle* style=SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if ( !style->stroke.isNone() ) { double const scale = transform.descrim(); if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord @@ -366,9 +366,9 @@ sp_flowtext_print(SPItem *item, SPPrintContext *ctx) NRRect dbox; dbox.x0 = 0.0; dbox.y0 = 0.0; - dbox.x1 = SP_OBJECT_DOCUMENT(item)->getWidth(); - dbox.y1 = SP_OBJECT_DOCUMENT(item)->getHeight(); - Geom::Matrix const ctm (item->i2d_affine()); + dbox.x1 = item->document->getWidth(); + dbox.y1 = item->document->getHeight(); + Geom::Affine const ctm (item->i2d_affine()); group->layout.print(ctx, &pbox, &dbox, &bbox, ctm); } @@ -438,7 +438,7 @@ void SPFlowtext::_buildLayoutInput(SPObject *root, Shape const *exclusion_shape, if (SP_IS_FLOWPARA(root)) { // emulate par-indent with the first char's kern SPObject *t = root; - for ( ; t != NULL && !SP_IS_FLOWTEXT(t); t = SP_OBJECT_PARENT(t)){}; + for ( ; t != NULL && !SP_IS_FLOWTEXT(t); t = t->parent){}; if (SP_IS_FLOWTEXT(t)) { double indent = SP_FLOWTEXT(t)->par_indent; if (indent != 0) { @@ -556,10 +556,10 @@ SPFlowtext::getAsText() SPItem *item = SP_ITEM(this); - Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(this)->getReprDoc(); + Inkscape::XML::Document *xml_doc = this->document->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:text"); repr->setAttribute("xml:space", "preserve"); - repr->setAttribute("style", SP_OBJECT_REPR(this)->attribute("style")); + repr->setAttribute("style", this->getRepr()->attribute("style")); Geom::Point anchor_point = this->layout.characterAnchorPoint(this->layout.begin()); sp_repr_set_svg_double(repr, "x", anchor_point[Geom::X]); sp_repr_set_svg_double(repr, "y", anchor_point[Geom::Y]); @@ -695,7 +695,7 @@ bool SPFlowtext::has_internal_frame() { SPItem *frame = get_frame(NULL); - return (frame && SP_OBJECT(this)->isAncestorOf(SP_OBJECT(frame)) && SP_IS_RECT(frame)); + return (frame && this->isAncestorOf(frame) && SP_IS_RECT(frame)); } @@ -718,7 +718,7 @@ SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, Geom::Point p0, Inkscape::XML::Node *rect_repr = xml_doc->createElement("svg:rect"); // FIXME: use path!!! after rects are converted to use path region_repr->appendChild(rect_repr); - SPObject *rect = doc->getObjectByRepr(rect_repr); + SPRect *rect = SP_RECT(doc->getObjectByRepr(rect_repr)); p0 *= desktop->dt2doc(); p1 *= desktop->dt2doc(); @@ -731,8 +731,8 @@ SPItem *create_flowtext_with_internal_frame (SPDesktop *desktop, Geom::Point p0, Geom::Coord const w = x1 - x0; Geom::Coord const h = y1 - y0; - sp_rect_position_set(SP_RECT(rect), x0, y0, w, h); - SP_OBJECT(rect)->updateRepr(); + sp_rect_position_set(rect, x0, y0, w, h); + rect->updateRepr(); Inkscape::XML::Node *para_repr = xml_doc->createElement("svg:flowPara"); root_repr->appendChild(para_repr); diff --git a/src/sp-font-face.cpp b/src/sp-font-face.cpp index 93e2eeac8..520eee855 100644 --- a/src/sp-font-face.cpp +++ b/src/sp-font-face.cpp @@ -865,7 +865,7 @@ static Inkscape::XML::Node *sp_fontface_write(SPObject *object, Inkscape::XML::D sp_repr_set_svg_double(repr, "overline-position", face->overline_position); sp_repr_set_svg_double(repr, "overline-thickness", face->overline_thickness); - if (repr != SP_OBJECT_REPR(object)) { + if (repr != object->getRepr()) { // In all COPY_ATTR given below the XML tree is // being used directly while it shouldn't be. COPY_ATTR(repr, object->getRepr(), "font-family"); diff --git a/src/sp-font.cpp b/src/sp-font.cpp index 64f7bd481..852e6ba5d 100644 --- a/src/sp-font.cpp +++ b/src/sp-font.cpp @@ -151,7 +151,7 @@ sp_font_remove_child(SPObject *object, Inkscape::XML::Node *child) static void sp_font_release(SPObject *object) { //SPFont *font = SP_FONT(object); - SP_OBJECT_DOCUMENT(object)->removeResource("font", object); + object->document->removeResource("font", object); if (((SPObjectClass *) parent_class)->release) { ((SPObjectClass *) parent_class)->release(object); @@ -263,7 +263,7 @@ static Inkscape::XML::Node *sp_font_write(SPObject *object, Inkscape::XML::Docum sp_repr_set_svg_double(repr, "vert-origin-y", font->vert_origin_y); sp_repr_set_svg_double(repr, "vert-adv-y", font->vert_adv_y); - if (repr != SP_OBJECT_REPR(object)) { + if (repr != object->getRepr()) { // All the below COPY_ATTR funtions are directly using // the XML Tree while they shouldn't COPY_ATTR(repr, object->getRepr(), "horiz-origin-x"); diff --git a/src/sp-glyph-kerning.cpp b/src/sp-glyph-kerning.cpp index 7a9f9b2ff..61a2ac531 100644 --- a/src/sp-glyph-kerning.cpp +++ b/src/sp-glyph-kerning.cpp @@ -250,7 +250,7 @@ static Inkscape::XML::Node *sp_glyph_kerning_write(SPObject *object, Inkscape::X sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); */ - if (repr != SP_OBJECT_REPR(object)) { + if (repr != object->getRepr()) { // All the COPY_ATTR functions below use // XML Tree directly, while they shouldn't. COPY_ATTR(repr, object->getRepr(), "u1"); diff --git a/src/sp-glyph.cpp b/src/sp-glyph.cpp index 6f7238133..709a33be2 100644 --- a/src/sp-glyph.cpp +++ b/src/sp-glyph.cpp @@ -290,7 +290,7 @@ static Inkscape::XML::Node *sp_glyph_write(SPObject *object, Inkscape::XML::Docu sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); */ - if (repr != SP_OBJECT_REPR(object)) { + if (repr != object->getRepr()) { // All the COPY_ATTR functions below use // XML Tree directly while they shouldn't. COPY_ATTR(repr, object->getRepr(), "unicode"); diff --git a/src/sp-gradient-fns.h b/src/sp-gradient-fns.h index a5b654822..5fb939905 100644 --- a/src/sp-gradient-fns.h +++ b/src/sp-gradient-fns.h @@ -22,12 +22,12 @@ void sp_gradient_repr_clear_vector(SPGradient *gr); cairo_pattern_t *sp_gradient_create_preview_pattern(SPGradient *gradient, double width); /** Transforms to/from gradient position space in given environment */ -Geom::Matrix sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, +Geom::Affine sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox); -Geom::Matrix sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, +Geom::Affine sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox); -void sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Matrix const &ctm, Geom::Rect const &bbox, - Geom::Matrix const &gs2d); +void sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm, Geom::Rect const &bbox, + Geom::Affine const &gs2d); #endif /* !SEEN_SP_GRADIENT_FNS_H */ diff --git a/src/sp-gradient-test.h b/src/sp-gradient-test.h index 5ab08467d..696072929 100644 --- a/src/sp-gradient-test.h +++ b/src/sp-gradient-test.h @@ -56,13 +56,13 @@ public: SP_OBJECT(gr)->document = _doc; SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTTRANSFORM, "translate(5, 8)"); - TS_ASSERT_EQUALS( gr->gradientTransform, Geom::Matrix(Geom::Translate(5, 8)) ); + TS_ASSERT_EQUALS( gr->gradientTransform, Geom::Affine(Geom::Translate(5, 8)) ); SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTTRANSFORM, ""); TS_ASSERT_EQUALS( gr->gradientTransform, Geom::identity() ); SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTTRANSFORM, "rotate(90)"); - TS_ASSERT_EQUALS( gr->gradientTransform, Geom::Matrix(rotate_degrees(90)) ); + TS_ASSERT_EQUALS( gr->gradientTransform, Geom::Affine(rotate_degrees(90)) ); g_object_unref(gr); } @@ -79,10 +79,10 @@ public: SP_OBJECT(gr)->updateRepr(repr, SP_OBJECT_WRITE_ALL); { gchar const *tr = repr->attribute("gradientTransform"); - Geom::Matrix svd; + Geom::Affine svd; bool const valid = sp_svg_transform_read(tr, &svd); TS_ASSERT( valid ); - TS_ASSERT_EQUALS( svd, Geom::Matrix(rotate_degrees(90)) ); + TS_ASSERT_EQUALS( svd, Geom::Affine(rotate_degrees(90)) ); } g_object_unref(gr); @@ -93,14 +93,14 @@ public: { SPGradient *gr = static_cast<SPGradient *>(g_object_new(SP_TYPE_GRADIENT, NULL)); SP_OBJECT(gr)->document = _doc; - Geom::Matrix const grXform(2, 1, + Geom::Affine const grXform(2, 1, 1, 3, 4, 6); gr->gradientTransform = grXform; Geom::Rect const unit_rect(Geom::Point(0, 0), Geom::Point(1, 1)); { - Geom::Matrix const g2d(sp_gradient_get_g2d_matrix(gr, Geom::identity(), unit_rect)); - Geom::Matrix const gs2d(sp_gradient_get_gs2d_matrix(gr, Geom::identity(), unit_rect)); + Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, Geom::identity(), unit_rect)); + Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, Geom::identity(), unit_rect)); TS_ASSERT_EQUALS( g2d, Geom::identity() ); TS_ASSERT( Geom::matrix_equalp(gs2d, gr->gradientTransform * g2d, 1e-12) ); @@ -109,12 +109,12 @@ public: } gr->gradientTransform = grXform; - Geom::Matrix const funny(2, 3, + Geom::Affine const funny(2, 3, 4, 5, 6, 7); { - Geom::Matrix const g2d(sp_gradient_get_g2d_matrix(gr, funny, unit_rect)); - Geom::Matrix const gs2d(sp_gradient_get_gs2d_matrix(gr, funny, unit_rect)); + Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, funny, unit_rect)); + Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, funny, unit_rect)); TS_ASSERT_EQUALS( g2d, funny ); TS_ASSERT( Geom::matrix_equalp(gs2d, gr->gradientTransform * g2d, 1e-12) ); @@ -125,9 +125,9 @@ public: gr->gradientTransform = grXform; Geom::Rect const larger_rect(Geom::Point(5, 6), Geom::Point(8, 10)); { - Geom::Matrix const g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect)); - Geom::Matrix const gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect)); - TS_ASSERT_EQUALS( g2d, Geom::Matrix(3, 0, + Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect)); + Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect)); + TS_ASSERT_EQUALS( g2d, Geom::Affine(3, 0, 0, 4, 5, 6) * funny ); TS_ASSERT( Geom::matrix_equalp(gs2d, gr->gradientTransform * g2d, 1e-12) ); @@ -136,8 +136,8 @@ public: TS_ASSERT( Geom::matrix_equalp(gr->gradientTransform, grXform, 1e-12) ); SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTUNITS, "userSpaceOnUse"); - Geom::Matrix const user_g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect)); - Geom::Matrix const user_gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect)); + Geom::Affine const user_g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect)); + Geom::Affine const user_gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect)); TS_ASSERT_EQUALS( user_g2d, funny ); TS_ASSERT( Geom::matrix_equalp(user_gs2d, gr->gradientTransform * user_g2d, 1e-12) ); } diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp index c211e4891..3aa14dc45 100644 --- a/src/sp-gradient.cpp +++ b/src/sp-gradient.cpp @@ -44,6 +44,7 @@ #include "uri.h" #include "xml/repr.h" #include "style.h" +#include "display/grayscale.h" #define SP_MACROS_SILENT #include "macros.h" @@ -371,7 +372,7 @@ void SPGradientImpl::classInit(SPGradientClass *klass) */ void SPGradientImpl::init(SPGradient *gr) { - gr->ref = new SPGradientReference(SP_OBJECT(gr)); + gr->ref = new SPGradientReference(gr); gr->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(SPGradientImpl::gradientRefChanged), gr)); /** \todo @@ -441,9 +442,9 @@ void SPGradientImpl::release(SPObject *object) g_print("Releasing gradient %s\n", object->getId()); #endif - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("gradient", SP_OBJECT(object)); + if (object->document) { + // Unregister ourselves + object->document->removeResource("gradient", object); } if (gradient->ref) { @@ -482,7 +483,7 @@ void SPGradientImpl::setGradientAttr(SPObject *object, unsigned key, gchar const object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_GRADIENTTRANSFORM: { - Geom::Matrix t; + Geom::Affine t; if (value && sp_svg_transform_read(value, &t)) { gr->gradientTransform = t; gr->gradientTransform_set = TRUE; @@ -921,7 +922,7 @@ SPGradientUnits SPGradient::fetchUnits() void sp_gradient_repr_clear_vector(SPGradient *gr) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr); + Inkscape::XML::Node *repr = gr->getRepr(); /* Collect stops from original repr */ GSList *sl = NULL; @@ -951,8 +952,8 @@ sp_gradient_repr_write_vector(SPGradient *gr) g_return_if_fail(gr != NULL); g_return_if_fail(SP_IS_GRADIENT(gr)); - Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(gr)->getReprDoc(); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr); + Inkscape::XML::Document *xml_doc = gr->document->getReprDoc(); + Inkscape::XML::Node *repr = gr->getRepr(); /* We have to be careful, as vector may be our own, so construct repr list at first */ GSList *cl = NULL; @@ -984,7 +985,7 @@ sp_gradient_repr_write_vector(SPGradient *gr) void SPGradientImpl::gradientRefModified(SPObject */*href*/, guint /*flags*/, SPGradient *gradient) { if ( gradient->invalidateVector() ) { - SP_OBJECT(gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG); + gradient->requestModified(SP_OBJECT_MODIFIED_FLAG); // Conditional to avoid causing infinite loop if there's a cycle in the href chain. } } @@ -1101,34 +1102,34 @@ void SPGradient::rebuildVector() vector.built = true; } -Geom::Matrix -sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, Geom::Rect const &bbox) +Geom::Affine +sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox) { if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { return ( Geom::Scale(bbox.dimensions()) * Geom::Translate(bbox.min()) - * Geom::Matrix(ctm) ); + * Geom::Affine(ctm) ); } else { return ctm; } } -Geom::Matrix -sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, Geom::Rect const &bbox) +Geom::Affine +sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox) { if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { return ( gr->gradientTransform * Geom::Scale(bbox.dimensions()) * Geom::Translate(bbox.min()) - * Geom::Matrix(ctm) ); + * Geom::Affine(ctm) ); } else { return gr->gradientTransform * ctm; } } void -sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Matrix const &ctm, - Geom::Rect const &bbox, Geom::Matrix const &gs2d) +sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm, + Geom::Rect const &bbox, Geom::Affine const &gs2d) { gr->gradientTransform = gs2d * ctm.inverse(); if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) { @@ -1138,7 +1139,7 @@ sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Matrix const &ctm, } gr->gradientTransform_set = TRUE; - SP_OBJECT(gr)->requestModified(SP_OBJECT_MODIFIED_FLAG); + gr->requestModified(SP_OBJECT_MODIFIED_FLAG); } /* @@ -1301,7 +1302,7 @@ sp_lineargradient_set_position(SPLinearGradient *lg, lg->x2.set(SVGLength::NONE, x2, x2); lg->y2.set(SVGLength::NONE, y2, y2); - SP_OBJECT(lg)->requestModified(SP_OBJECT_MODIFIED_FLAG); + lg->requestModified(SP_OBJECT_MODIFIED_FLAG); } /* @@ -1485,7 +1486,7 @@ sp_radialgradient_set_position(SPRadialGradient *rg, rg->fy.set(SVGLength::NONE, fy, fy); rg->r.set(SVGLength::NONE, r, r); - SP_OBJECT(rg)->requestModified(SP_OBJECT_MODIFIED_FLAG); + rg->requestModified(SP_OBJECT_MODIFIED_FLAG); } /* CAIRO RENDERING STUFF */ @@ -1520,9 +1521,9 @@ sp_gradient_pattern_common_setup(cairo_pattern_t *cp, } // set pattern matrix - Geom::Matrix gs2user = gr->gradientTransform; + Geom::Affine gs2user = gr->gradientTransform; if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + Geom::Affine bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); gs2user *= bbox2user; } ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); diff --git a/src/sp-gradient.h b/src/sp-gradient.h index bc0fe8691..f7afd969a 100644 --- a/src/sp-gradient.h +++ b/src/sp-gradient.h @@ -18,13 +18,14 @@ */ #include <gdk/gdktypes.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <glibmm/ustring.h> #include "sp-paint-server.h" #include "sp-gradient-spread.h" #include "sp-gradient-units.h" #include "sp-gradient-vector.h" +#include <stddef.h> #include <sigc++/connection.h> struct SPGradientReference; @@ -84,7 +85,7 @@ private: public: /** gradientTransform attribute */ - Geom::Matrix gradientTransform; + Geom::Affine gradientTransform; guint gradientTransform_set : 1; private: diff --git a/src/sp-guide.cpp b/src/sp-guide.cpp index f92d79116..7d36df4a3 100644 --- a/src/sp-guide.cpp +++ b/src/sp-guide.cpp @@ -23,6 +23,7 @@ #include <cstring> #include <string> #include "desktop-handles.h" +#include "display/sp-canvas.h" #include "display/guideline.h" #include "svg/svg.h" #include "svg/stringstream.h" @@ -221,7 +222,7 @@ static void sp_guide_set(SPObject *object, unsigned int key, const gchar *value) guide->point_on_line = Geom::Point(newx, newy); } else if (success == 1) { // before 0.46 style guideline definition. - const gchar *attr = SP_OBJECT_REPR(object)->attribute("orientation"); + const gchar *attr = object->getRepr()->attribute("orientation"); if (attr && !strcmp(attr, "horizontal")) { guide->point_on_line = Geom::Point(0, newx); } else { @@ -344,7 +345,7 @@ double SPGuide::getDistanceFrom(Geom::Point const &pt) const * true indicates a "committing" version: in response to button release event after * dragging a guideline, or clicking OK in guide editing dialog. */ -void sp_guide_moveto(SPGuide const &guide, Geom::Point const point_on_line, bool const commit) +void sp_guide_moveto(SPGuide &guide, Geom::Point const point_on_line, bool const commit) { g_assert(SP_IS_GUIDE(&guide)); @@ -356,7 +357,7 @@ void sp_guide_moveto(SPGuide const &guide, Geom::Point const point_on_line, bool case, so that the guide's new position is available for sp_item_rm_unsatisfied_cns. */ if (commit) { //XML Tree being used here directly while it shouldn't be. - sp_repr_set_point(SP_OBJECT(&guide)->getRepr(), "position", point_on_line); + sp_repr_set_point(guide.getRepr(), "position", point_on_line); } /* DISABLED CODE BECAUSE SPGuideAttachment IS NOT USE AT THE MOMENT (johan) @@ -375,7 +376,7 @@ void sp_guide_moveto(SPGuide const &guide, Geom::Point const point_on_line, bool * true indicates a "committing" version: in response to button release event after * dragging a guideline, or clicking OK in guide editing dialog. */ -void sp_guide_set_normal(SPGuide const &guide, Geom::Point const normal_to_line, bool const commit) +void sp_guide_set_normal(SPGuide &guide, Geom::Point const normal_to_line, bool const commit) { g_assert(SP_IS_GUIDE(&guide)); @@ -387,7 +388,7 @@ void sp_guide_set_normal(SPGuide const &guide, Geom::Point const normal_to_line, case, so that the guide's new position is available for sp_item_rm_unsatisfied_cns. */ if (commit) { //XML Tree being used directly while it shouldn't be - sp_repr_set_point(SP_OBJECT(&guide)->getRepr(), "orientation", normal_to_line); + sp_repr_set_point(guide.getRepr(), "orientation", normal_to_line); } /* DISABLED CODE BECAUSE SPGuideAttachment IS NOT USE AT THE MOMENT (johan) @@ -458,7 +459,7 @@ void sp_guide_remove(SPGuide *guide) guide->attached_items.clear(); //XML Tree being used directly while it shouldn't be. - sp_repr_unparent(SP_OBJECT(guide)->getRepr()); + sp_repr_unparent(guide->getRepr()); } /* diff --git a/src/sp-guide.h b/src/sp-guide.h index 4fc4032db..c53042da5 100644 --- a/src/sp-guide.h +++ b/src/sp-guide.h @@ -15,11 +15,13 @@ #include <vector> -#include "display/display-forward.h" #include <2geom/point.h> #include "sp-object.h" #include "sp-guide-attachment.h" +struct SPCanvas; +struct SPCanvasGroup; + #define SP_TYPE_GUIDE (sp_guide_get_type()) #define SP_GUIDE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SP_TYPE_GUIDE, SPGuide)) #define SP_GUIDE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SP_TYPE_GUIDE, SPGuideClass)) @@ -58,8 +60,8 @@ GType sp_guide_get_type(); void sp_guide_pt_pairs_to_guides(SPDesktop *dt, std::list<std::pair<Geom::Point, Geom::Point> > &pts); void sp_guide_create_guides_around_page(SPDesktop *dt); -void sp_guide_moveto(SPGuide const &guide, Geom::Point const point_on_line, bool const commit); -void sp_guide_set_normal(SPGuide const &guide, Geom::Point const normal_to_line, bool const commit); +void sp_guide_moveto(SPGuide &guide, Geom::Point const point_on_line, bool const commit); +void sp_guide_set_normal(SPGuide &guide, Geom::Point const normal_to_line, bool const commit); void sp_guide_remove(SPGuide *guide); char *sp_guide_description(SPGuide const *guide, const bool verbose = true); diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 6507d8948..8c4f7b0ca 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -77,12 +77,12 @@ static void sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags); static void sp_image_modified (SPObject *object, unsigned int flags); static Inkscape::XML::Node *sp_image_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_image_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_image_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_image_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_image_description (SPItem * item); static void sp_image_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); static NRArenaItem *sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); -static Geom::Matrix sp_image_set_transform (SPItem *item, Geom::Matrix const &xform); +static Geom::Affine sp_image_set_transform (SPItem *item, Geom::Affine const &xform); static void sp_image_set_curve(SPImage *image); @@ -381,9 +381,13 @@ static bool readPngAndHeaders( PushPull &youme, gint & dpiX, gint & dpiY ) #if defined(PNG_iCCP_SUPPORTED) { - char* name = 0; + png_charp name = 0; int compression_type = 0; - char* profile = 0; +#if (PNG_LIBPNG_VER < 10500) + png_charp profile = 0; +#else + png_bytep profile = 0; +#endif png_uint_32 proflen = 0; if ( png_get_iCCP(pngPtr, infoPtr, &name, &compression_type, &profile, &proflen) ) { // g_message("Found an iCCP chunk named [%s] with %d bytes and comp %d", name, proflen, compression_type); @@ -643,9 +647,9 @@ sp_image_release (SPObject *object) { SPImage *image = SP_IMAGE(object); - if (SP_OBJECT_DOCUMENT (object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("image", SP_OBJECT(object)); + if (object->document) { + // Unregister ourselves + object->document->removeResource("image", object); } if (image->href) { @@ -806,7 +810,7 @@ static void sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags) { SPImage *image = SP_IMAGE(object); - SPDocument *doc = SP_OBJECT_DOCUMENT(object); + SPDocument *doc = object->document; if (((SPObjectClass *) (parent_class))->update) { ((SPObjectClass *) (parent_class))->update (object, ctx, flags); @@ -850,7 +854,7 @@ sp_image_update (SPObject *object, SPCtx *ctx, unsigned int flags) DEBUG_MESSAGE( lcmsFive, "in <image>'s sp_image_update. About to call colorprofile_get_handle()" ); #endif // DEBUG_LCMS guint profIntent = Inkscape::RENDERING_INTENT_UNKNOWN; - cmsHPROFILE prof = Inkscape::colorprofile_get_handle( SP_OBJECT_DOCUMENT( object ), + cmsHPROFILE prof = Inkscape::colorprofile_get_handle( object->document, &profIntent, image->color_profile ); if ( prof ) { @@ -1064,7 +1068,7 @@ sp_image_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XM } static void -sp_image_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) +sp_image_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const /*flags*/) { SPImage const &image = *SP_IMAGE(item); @@ -1097,13 +1101,13 @@ sp_image_print (SPItem *item, SPPrintContext *ctx) int pixskip = gdk_pixbuf_get_n_channels(pb) * gdk_pixbuf_get_bits_per_sample(pb) / 8; if (image->aspect_align == SP_ASPECT_NONE) { - Geom::Matrix t; + Geom::Affine t; Geom::Translate tp(image->x.computed, image->y.computed); Geom::Scale s(image->width.computed, -image->height.computed); Geom::Translate ti(0.0, -1.0); t = s * tp; t = ti * t; - sp_print_image_R8G8B8A8_N(ctx, px, w, h, rs, &t, SP_OBJECT_STYLE (item)); + sp_print_image_R8G8B8A8_N(ctx, px, w, h, rs, &t, item->style); } else { // preserveAspectRatio double vw = image->width.computed / image->sx; double vh = image->height.computed / image->sy; @@ -1118,13 +1122,13 @@ sp_image_print (SPItem *item, SPPrintContext *ctx) double vcw = std::min<double>(image->width.computed, vw); double vch = std::min<double>(image->height.computed, vh); - Geom::Matrix t; + Geom::Affine t; Geom::Translate tp(vx, vy); Geom::Scale s(vcw, -vch); Geom::Translate ti(0.0, -1.0); t = s * tp; t = ti * t; - sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, &t, SP_OBJECT_STYLE(item)); + sp_print_image_R8G8B8A8_N(ctx, px + trimx*pixskip + trimy*rs, trimwidth, trimheight, rs, &t, item->style); } } } @@ -1274,7 +1278,7 @@ sp_image_pixbuf_force_rgba (GdkPixbuf * pixbuf) static void sp_image_update_arenaitem (SPImage *image, NRArenaImage *ai) { - nr_arena_image_set_style(ai, SP_OBJECT_STYLE(SP_OBJECT(image))); + nr_arena_image_set_style(ai, SP_OBJECT(image)->style); nr_arena_image_set_argb32_pixbuf(ai, image->pixbuf); nr_arena_image_set_origin(ai, Geom::Point(image->ox, image->oy)); nr_arena_image_set_scale(ai, image->sx, image->sy); @@ -1312,7 +1316,7 @@ static void sp_image_snappoints(SPItem const *item, std::vector<Inkscape::SnapCa double const y0 = image.y.computed; double const x1 = x0 + image.width.computed; double const y1 = y0 + image.height.computed; - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(x0, y0) * i2d, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER)); p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(x0, y1) * i2d, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER)); p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(x1, y1) * i2d, Inkscape::SNAPSOURCE_CORNER, Inkscape::SNAPTARGET_CORNER)); @@ -1325,8 +1329,8 @@ static void sp_image_snappoints(SPItem const *item, std::vector<Inkscape::SnapCa * Transform x, y, set x, y, clear translation */ -static Geom::Matrix -sp_image_set_transform(SPItem *item, Geom::Matrix const &xform) +static Geom::Affine +sp_image_set_transform(SPItem *item, Geom::Affine const &xform) { SPImage *image = SP_IMAGE(item); @@ -1335,7 +1339,7 @@ sp_image_set_transform(SPItem *item, Geom::Matrix const &xform) /* This function takes care of translation and scaling, we return whatever parts we can't handle. */ - Geom::Matrix ret(Geom::Matrix(xform).without_translation()); + Geom::Affine ret(Geom::Affine(xform).withoutTranslation()); Geom::Point const scale(hypot(ret[0], ret[1]), hypot(ret[2], ret[3])); if ( scale[Geom::X] > MAGIC_EPSILON ) { diff --git a/src/sp-image.h b/src/sp-image.h index 2d744fb12..2b3940412 100644 --- a/src/sp-image.h +++ b/src/sp-image.h @@ -29,7 +29,6 @@ class SPImageClass; #include <glibmm/ustring.h> #include "svg/svg-length.h" #include "sp-item.h" -#include "display/display-forward.h" #define SP_IMAGE_HREF_MODIFIED_FLAG SP_OBJECT_USER_MODIFIED_FLAG_A diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 05ffc16ec..2ee57dbe5 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -64,7 +64,7 @@ static void sp_group_modified (SPObject *object, guint flags); static Inkscape::XML::Node *sp_group_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static void sp_group_set(SPObject *object, unsigned key, char const *value); -static void sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_group_print (SPItem * item, SPPrintContext *ctx); static gchar * sp_group_description (SPItem * item); static NRArenaItem *sp_group_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); @@ -154,7 +154,7 @@ static void sp_group_build(SPObject *object, SPDocument *document, Inkscape::XML static void sp_group_release(SPObject *object) { if ( SP_GROUP(object)->_layer_mode == SPGroup::LAYER ) { - SP_OBJECT_DOCUMENT(object)->removeResource("layer", object); + object->document->removeResource("layer", object); } if (((SPObjectClass *)parent_class)->release) { ((SPObjectClass *)parent_class)->release(object); @@ -276,7 +276,7 @@ static Inkscape::XML::Node * sp_group_write(SPObject *object, Inkscape::XML::Doc } static void -sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags) +sp_group_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags) { SP_GROUP(item)->group->calculateBBox(bbox, transform, flags); } @@ -342,20 +342,20 @@ sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done) g_return_if_fail (group != NULL); g_return_if_fail (SP_IS_GROUP (group)); - SPDocument *doc = SP_OBJECT_DOCUMENT (group); + SPDocument *doc = group->document; SPObject *root = doc->getRoot(); - SPObject *defs = SP_OBJECT (SP_ROOT (root)->defs); + SPObject *defs = SP_OBJECT(SP_ROOT(root)->defs); SPItem *gitem = SP_ITEM (group); - Inkscape::XML::Node *grepr = SP_OBJECT_REPR (gitem); + Inkscape::XML::Node *grepr = gitem->getRepr(); g_return_if_fail (!strcmp (grepr->name(), "svg:g") || !strcmp (grepr->name(), "svg:a") || !strcmp (grepr->name(), "svg:switch")); // this converts the gradient/pattern fill/stroke on the group, if any, to userSpaceOnUse gitem->adjust_paint_recursive (Geom::identity(), Geom::identity(), false); - SPItem *pitem = SP_ITEM (SP_OBJECT_PARENT (gitem)); - Inkscape::XML::Node *prepr = SP_OBJECT_REPR (pitem); + SPItem *pitem = SP_ITEM(gitem->parent); + Inkscape::XML::Node *prepr = pitem->getRepr(); if (SP_IS_BOX3D(gitem)) { group = box3d_convert_to_group(SP_BOX3D(gitem)); @@ -378,7 +378,7 @@ sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done) // it here _before_ the new transform is set, so as to use the pre-transform bbox citem->adjust_paint_recursive (Geom::identity(), Geom::identity(), false); - sp_style_merge_from_dying_parent(SP_OBJECT_STYLE(child), SP_OBJECT_STYLE(gitem)); + sp_style_merge_from_dying_parent(child->style, gitem->style); /* * fixme: We currently make no allowance for the case where child is cloned * and the group has any style settings. @@ -403,33 +403,33 @@ sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done) child->updateRepr(); - Inkscape::XML::Node *nrepr = SP_OBJECT_REPR (child)->duplicate(prepr->document()); + Inkscape::XML::Node *nrepr = child->getRepr()->duplicate(prepr->document()); // Merging transform - Geom::Matrix ctrans; - Geom::Matrix const g(gitem->transform); + Geom::Affine ctrans; + Geom::Affine const g(gitem->transform); if (SP_IS_USE(citem) && sp_use_get_original (SP_USE(citem)) && - SP_OBJECT_PARENT (sp_use_get_original (SP_USE(citem))) == SP_OBJECT(group)) { + sp_use_get_original( SP_USE(citem) )->parent == SP_OBJECT(group)) { // make sure a clone's effective transform is the same as was under group ctrans = g.inverse() * citem->transform * g; } else { - // We should not apply the group's transformation to both a linked offset AND to its source - if (SP_IS_OFFSET(citem)) { // Do we have an offset at hand (whether it's dynamic or linked)? - SPItem *source = sp_offset_get_source(SP_OFFSET(citem)); - // When dealing with a chain of linked offsets, the transformation of an offset will be - // tied to the transformation of the top-most source, not to any of the intermediate - // offsets. So let's find the top-most source - while (source != NULL && SP_IS_OFFSET(source)) { - source = sp_offset_get_source(SP_OFFSET(source)); - } - if (source != NULL && // If true then we must be dealing with a linked offset ... - SP_OBJECT(group)->isAncestorOf(SP_OBJECT(source)) == false) { // ... of which the source is not in the same group - ctrans = citem->transform * g; // then we should apply the transformation of the group to the offset - } else { - ctrans = citem->transform; - } + // We should not apply the group's transformation to both a linked offset AND to its source + if (SP_IS_OFFSET(citem)) { // Do we have an offset at hand (whether it's dynamic or linked)? + SPItem *source = sp_offset_get_source(SP_OFFSET(citem)); + // When dealing with a chain of linked offsets, the transformation of an offset will be + // tied to the transformation of the top-most source, not to any of the intermediate + // offsets. So let's find the top-most source + while (source != NULL && SP_IS_OFFSET(source)) { + source = sp_offset_get_source(SP_OFFSET(source)); + } + if (source != NULL && // If true then we must be dealing with a linked offset ... + group->isAncestorOf(source) == false) { // ... of which the source is not in the same group + ctrans = citem->transform * g; // then we should apply the transformation of the group to the offset + } else { + ctrans = citem->transform; + } } else { - ctrans = citem->transform * g; + ctrans = citem->transform * g; } } @@ -450,27 +450,28 @@ sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done) items = g_slist_prepend (items, nrepr); } else { - Inkscape::XML::Node *nrepr = SP_OBJECT_REPR (child)->duplicate(prepr->document()); + Inkscape::XML::Node *nrepr = child->getRepr()->duplicate(prepr->document()); objects = g_slist_prepend (objects, nrepr); } } /* Step 2 - clear group */ // remember the position of the group - gint pos = SP_OBJECT_REPR(group)->position(); + gint pos = group->getRepr()->position(); // the group is leaving forever, no heir, clones should take note; its children however are going to reemerge - SP_OBJECT (group)->deleteObject(true, false); + group->deleteObject(true, false); /* Step 3 - add nonitems */ if (objects) { - Inkscape::XML::Node *last_def = SP_OBJECT_REPR(defs)->lastChild(); + Inkscape::XML::Node *last_def = defs->getRepr()->lastChild(); while (objects) { - Inkscape::XML::Node *repr = (Inkscape::XML::Node *) objects->data; - if (!sp_repr_is_meta_element(repr)) - SP_OBJECT_REPR(defs)->addChild(repr, last_def); - Inkscape::GC::release(repr); - objects = g_slist_remove (objects, objects->data); + Inkscape::XML::Node *repr = (Inkscape::XML::Node *) objects->data; + if (!sp_repr_is_meta_element(repr)) { + defs->getRepr()->addChild(repr, last_def); + } + Inkscape::GC::release(repr); + objects = g_slist_remove (objects, objects->data); } } @@ -532,9 +533,9 @@ SPObject *sp_item_group_get_child_by_name(SPGroup *group, SPObject *ref, const g void SPGroup::setLayerMode(LayerMode mode) { if ( _layer_mode != mode ) { if ( mode == LAYER ) { - SP_OBJECT_DOCUMENT(this)->addResource("layer", this); + this->document->addResource("layer", this); } else if ( _layer_mode == LAYER ) { - SP_OBJECT_DOCUMENT(this)->removeResource("layer", this); + this->document->removeResource("layer", this); } _layer_mode = mode; _updateLayerMode(); @@ -590,7 +591,7 @@ CGroup::~CGroup() { void CGroup::onChildAdded(Inkscape::XML::Node *child) { SPObject *last_child = _group->lastChild(); - if (last_child && SP_OBJECT_REPR(last_child) == child) { + if (last_child && last_child->getRepr() == child) { // optimization for the common special case where the child is being added at the end SPObject *ochild = last_child; if ( SP_IS_ITEM(ochild) ) { @@ -646,9 +647,9 @@ void CGroup::onUpdate(SPCtx *ctx, unsigned int flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - SPObject *object = SP_OBJECT(_group); - for (SPItemView *v = SP_ITEM(_group)->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + SPObject *object = _group; + for (SPItemView *v = _group->display; v != NULL; v = v->next) { + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); } } @@ -677,9 +678,9 @@ void CGroup::onModified(guint flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { - SPObject *object = SP_OBJECT(_group); - for (SPItemView *v = SP_ITEM(_group)->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + SPObject *object = _group; + for (SPItemView *v = _group->display; v != NULL; v = v->next) { + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); } } @@ -694,7 +695,7 @@ void CGroup::onModified(guint flags) { } } -void CGroup::calculateBBox(NRRect *bbox, Geom::Matrix const &transform, unsigned const flags) { +void CGroup::calculateBBox(NRRect *bbox, Geom::Affine const &transform, unsigned const flags) { Geom::OptRect dummy_bbox; @@ -703,7 +704,7 @@ void CGroup::calculateBBox(NRRect *bbox, Geom::Matrix const &transform, unsigned SPObject *o = SP_OBJECT (l->data); if (SP_IS_ITEM(o) && !SP_ITEM(o)->isHidden()) { SPItem *child = SP_ITEM(o); - Geom::Matrix const ct(child->transform * transform); + Geom::Affine const ct(child->transform * transform); child->invoke_bbox_full( dummy_bbox, ct, flags, FALSE); } l = g_slist_remove (l, o); @@ -744,14 +745,14 @@ gchar *CGroup::getDescription() { NRArenaItem *CGroup::show (NRArena *arena, unsigned int key, unsigned int flags) { NRArenaItem *ai; - SPObject *object = SP_OBJECT(_group); + SPObject *object = _group; ai = NRArenaGroup::create(arena); nr_arena_group_set_transparent(NR_ARENA_GROUP (ai), _group->effectiveLayerMode(key) == SPGroup::LAYER); - nr_arena_group_set_style(NR_ARENA_GROUP(ai), SP_OBJECT_STYLE(object)); + nr_arena_group_set_style(NR_ARENA_GROUP(ai), object->style); _showChildren(arena, ai, key, flags); return ai; @@ -861,7 +862,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) SP_SHAPE(subitem)->setCurve(c, TRUE); if (write) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(subitem); + Inkscape::XML::Node *repr = subitem->getRepr(); gchar *str = sp_svg_write_path(c->get_pathvector()); repr->setAttribute("d", str); #ifdef GROUP_VERBOSE diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 932241a42..e2aeb8bc5 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -69,7 +69,7 @@ public: virtual void onChildRemoved(Inkscape::XML::Node *child); virtual void onUpdate(SPCtx *ctx, unsigned int flags); virtual void onModified(guint flags); - virtual void calculateBBox(NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); + virtual void calculateBBox(NRRect *bbox, Geom::Affine const &transform, unsigned const flags); virtual void onPrint(SPPrintContext *ctx); virtual void onOrderChanged(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref); virtual gchar *getDescription(); diff --git a/src/sp-item-notify-moveto.cpp b/src/sp-item-notify-moveto.cpp index 928d6f82f..2005356bd 100644 --- a/src/sp-item-notify-moveto.cpp +++ b/src/sp-item-notify-moveto.cpp @@ -49,7 +49,7 @@ void sp_item_notify_moveto(SPItem &item, SPGuide const &mv_g, int const snappoin /* Commit repr. */ { - item.doWriteTransform(SP_OBJECT_REPR(&item), item.transform); + item.doWriteTransform(item.getRepr(), item.transform); } sp_item_rm_unsatisfied_cns(item); diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 5b983b64b..ae55a5c50 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -21,12 +21,12 @@ sp_item_rotate_rel(SPItem *item, Geom::Rotate const &rotation) { Geom::Point center = item->getCenter(); Geom::Translate const s(item->getCenter()); - Geom::Matrix affine = Geom::Matrix(s).inverse() * Geom::Matrix(rotation) * Geom::Matrix(s); + Geom::Affine affine = Geom::Affine(s).inverse() * Geom::Affine(rotation) * Geom::Affine(s); // Rotate item. - item->set_i2d_affine(item->i2d_affine() * (Geom::Matrix)affine); + item->set_i2d_affine(item->i2d_affine() * (Geom::Affine)affine); // Use each item's own transform writer, consistent with sp_selection_apply_affine() - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform); + item->doWriteTransform(item->getRepr(), item->transform); // Restore the center position (it's changed because the bbox center changed) if (item->isCenterSet()) { @@ -42,7 +42,7 @@ sp_item_scale_rel (SPItem *item, Geom::Scale const &scale) if (bbox) { Geom::Translate const s(bbox->midpoint()); // use getCenter? item->set_i2d_affine(item->i2d_affine() * s.inverse() * scale * s); - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform); + item->doWriteTransform(item->getRepr(), item->transform); } } @@ -52,11 +52,11 @@ sp_item_skew_rel (SPItem *item, double skewX, double skewY) Geom::Point center = item->getCenter(); Geom::Translate const s(item->getCenter()); - Geom::Matrix const skew(1, skewY, skewX, 1, 0, 0); - Geom::Matrix affine = Geom::Matrix(s).inverse() * skew * Geom::Matrix(s); + Geom::Affine const skew(1, skewY, skewX, 1, 0, 0); + Geom::Affine affine = Geom::Affine(s).inverse() * skew * Geom::Affine(s); item->set_i2d_affine(item->i2d_affine() * affine); - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform); + item->doWriteTransform(item->getRepr(), item->transform); // Restore the center position (it's changed because the bbox center changed) if (item->isCenterSet()) { @@ -69,7 +69,7 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) { item->set_i2d_affine(item->i2d_affine() * tr); - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform); + item->doWriteTransform(item->getRepr(), item->transform); } /* @@ -79,16 +79,16 @@ preference value passed to it. Has to solve a quadratic equation to make sure the goal is met exactly and the stroke scaling is obeyed. */ -Geom::Matrix +Geom::Affine get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewidth, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) { Geom::Rect bbox (bbox_param); - Geom::Matrix p2o = Geom::Translate (-bbox.min()); - Geom::Matrix o2n = Geom::Translate (x0, y0); + Geom::Affine p2o = Geom::Translate (-bbox.min()); + Geom::Affine o2n = Geom::Translate (x0, y0); - Geom::Matrix scale = Geom::Scale (1, 1); // scale component - Geom::Matrix unbudge = Geom::Translate (0, 0); // move component to compensate for the drift caused by stroke width change + Geom::Affine scale = Geom::Scale (1, 1); // scale component + Geom::Affine unbudge = Geom::Translate (0, 0); // move component to compensate for the drift caused by stroke width change gdouble w0 = bbox[Geom::X].extent(); // will return a value >= 0, as required further down the road gdouble h0 = bbox[Geom::Y].extent(); @@ -97,11 +97,11 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid gdouble r0 = strokewidth; if (bbox.hasZeroArea()) { - Geom::Matrix move = Geom::Translate(x0 - bbox.min()[Geom::X], y0 - bbox.min()[Geom::Y]); + Geom::Affine move = Geom::Translate(x0 - bbox.min()[Geom::X], y0 - bbox.min()[Geom::Y]); return (move); // cannot scale from empty boxes at all, so only translate } - Geom::Matrix direct = Geom::Scale(w1 / w0, h1 / h0); + Geom::Affine direct = Geom::Scale(w1 / w0, h1 / h0); if (fabs(w0 - r0) < 1e-6 || fabs(h0 - r0) < 1e-6 || (!transform_stroke && (fabs(w1 - r0) < 1e-6 || fabs(h1 - r0) < 1e-6))) { return (p2o * direct * o2n); // can't solve the equation: one of the dimensions is equal to stroke width, so return the straightforward scaler @@ -120,7 +120,7 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid gdouble ratio_x = (w1 - r0) / (w0 - r0); gdouble ratio_y = (h1 - r0) / (h0 - r0); - Geom::Matrix direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); + Geom::Affine direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); if (transform_stroke && r0 != 0 && r0 != Geom::infinity()) { // there's stroke, and we need to scale it // These coefficients are obtained from the assumption that scaling applies to the @@ -159,7 +159,7 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid } Geom::Rect -get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Matrix const &abs_affine, gdouble const initial_strokewidth, bool const transform_stroke) +get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Affine const &abs_affine, gdouble const initial_strokewidth, bool const transform_stroke) { g_assert(initial_geom_bbox); diff --git a/src/sp-item-transform.h b/src/sp-item-transform.h index 893ab5822..552b23e2f 100644 --- a/src/sp-item-transform.h +++ b/src/sp-item-transform.h @@ -9,8 +9,8 @@ void sp_item_scale_rel (SPItem *item, Geom::Scale const &scale); void sp_item_skew_rel (SPItem *item, double skewX, double skewY); void sp_item_move_rel(SPItem *item, Geom::Translate const &tr); -Geom::Matrix get_scale_transform_with_stroke (Geom::Rect const &bbox, gdouble strokewidth, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1); -Geom::Rect get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Matrix const &abs_affine, gdouble const initial_strokewidth, bool const transform_stroke); +Geom::Affine get_scale_transform_with_stroke (Geom::Rect const &bbox, gdouble strokewidth, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1); +Geom::Rect get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Affine const &abs_affine, gdouble const initial_strokewidth, bool const transform_stroke); #endif /* !SP_ITEM_TRANSFORM_H */ diff --git a/src/sp-item.cpp b/src/sp-item.cpp index d2d940644..7e5f5f96a 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -65,7 +65,7 @@ #include "util/find-last-if.h" #include "util/reverse-list.h" #include <2geom/rect.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/transforms.h> #include "xml/repr.h" @@ -158,7 +158,7 @@ void SPItem::init() { new (&constraints) std::vector<SPGuideConstraint>(); - new (&_transformed_signal) sigc::signal<void, Geom::Matrix const *, SPItem *>(); + new (&_transformed_signal) sigc::signal<void, Geom::Affine const *, SPItem *>(); } bool SPItem::isVisibleAndUnlocked() const { @@ -435,7 +435,7 @@ void SPItem::sp_item_set(SPObject *object, unsigned key, gchar const *value) switch (key) { case SP_ATTR_TRANSFORM: { - Geom::Matrix t; + Geom::Affine t; if (value && sp_svg_transform_read(value, &t)) { item->set_item_transform(t); } else { @@ -702,7 +702,7 @@ Inkscape::XML::Node *SPItem::sp_item_write(SPObject *const object, Inkscape::XML * \return There is no guarantee that the return value will contain a rectangle. If this item does not have a boundingbox, it might well be empty. */ -Geom::OptRect SPItem::getBounds(Geom::Matrix const &transform, +Geom::OptRect SPItem::getBounds(Geom::Affine const &transform, SPItem::BBoxType type, unsigned int /*dkey*/) const { @@ -711,13 +711,13 @@ Geom::OptRect SPItem::getBounds(Geom::Matrix const &transform, return r; } -void SPItem::invoke_bbox( Geom::OptRect &bbox, Geom::Matrix const &transform, unsigned const clear, SPItem::BBoxType type) +void SPItem::invoke_bbox( Geom::OptRect &bbox, Geom::Affine const &transform, unsigned const clear, SPItem::BBoxType type) { invoke_bbox_full( bbox, transform, type, clear); } // DEPRECATED to phase out the use of NRRect in favor of Geom::OptRect -void SPItem::invoke_bbox( NRRect *bbox, Geom::Matrix const &transform, unsigned const clear, SPItem::BBoxType type) +void SPItem::invoke_bbox( NRRect *bbox, Geom::Affine const &transform, unsigned const clear, SPItem::BBoxType type) { invoke_bbox_full( bbox, transform, type, clear); } @@ -729,7 +729,7 @@ void SPItem::invoke_bbox( NRRect *bbox, Geom::Matrix const &transform, unsigned * \retval bbox Note that there is no guarantee that bbox will contain a rectangle when the * function returns. If this item does not have a boundingbox, this might well be empty. */ -void SPItem::invoke_bbox_full( Geom::OptRect &bbox, Geom::Matrix const &transform, unsigned const flags, unsigned const clear) const +void SPItem::invoke_bbox_full( Geom::OptRect &bbox, Geom::Affine const &transform, unsigned const flags, unsigned const clear) const { if (clear) { bbox = Geom::OptRect(); @@ -789,7 +789,7 @@ void SPItem::invoke_bbox_full( Geom::OptRect &bbox, Geom::Matrix const &transfor } // transform the expansions by the item's transform: - Geom::Matrix i2d(i2d_affine ()); + Geom::Affine i2d(i2d_affine ()); dx0 *= i2d.expansionX(); dx1 *= i2d.expansionX(); dy0 *= i2d.expansionY(); @@ -833,7 +833,7 @@ void SPItem::invoke_bbox_full( Geom::OptRect &bbox, Geom::Matrix const &transfor * unions the resulting bbox with \a bbox. If \a clear is true, empties \a bbox first. Passes the * transform and the flags to the actual bbox methods. Note that many of subclasses (e.g. groups, * clones), in turn, call this function in their bbox methods. */ -void SPItem::invoke_bbox_full( NRRect *bbox, Geom::Matrix const &transform, unsigned const flags, unsigned const clear) +void SPItem::invoke_bbox_full( NRRect *bbox, Geom::Affine const &transform, unsigned const flags, unsigned const clear) { g_assert(bbox != NULL); @@ -1134,7 +1134,7 @@ void SPItem::invoke_hide(unsigned key) // Adjusters -void SPItem::adjust_pattern (Geom::Matrix const &postmul, bool set) +void SPItem::adjust_pattern (Geom::Affine const &postmul, bool set) { if (style && (style->fill.isPaintserver())) { SPObject *server = style->getFillPaintServer(); @@ -1153,7 +1153,7 @@ void SPItem::adjust_pattern (Geom::Matrix const &postmul, bool set) } } -void SPItem::adjust_gradient( Geom::Matrix const &postmul, bool set ) +void SPItem::adjust_gradient( Geom::Affine const &postmul, bool set ) { if ( style && style->fill.isPaintserver() ) { SPPaintServer *server = style->getFillPaintServer(); @@ -1205,12 +1205,12 @@ void SPItem::adjust_stroke( gdouble ex ) /** * Find out the inverse of previous transform of an item (from its repr) */ -Geom::Matrix sp_item_transform_repr (SPItem *item) +Geom::Affine sp_item_transform_repr (SPItem *item) { - Geom::Matrix t_old(Geom::identity()); + Geom::Affine t_old(Geom::identity()); gchar const *t_attr = item->getRepr()->attribute("transform"); if (t_attr) { - Geom::Matrix t; + Geom::Affine t; if (sp_svg_transform_read(t_attr, &t)) { t_old = t; } @@ -1241,7 +1241,7 @@ void SPItem::adjust_stroke_width_recursive(double expansion) * Recursively adjust rx and ry of rects. */ void -sp_item_adjust_rects_recursive(SPItem *item, Geom::Matrix advertized_transform) +sp_item_adjust_rects_recursive(SPItem *item, Geom::Affine advertized_transform) { if (SP_IS_RECT (item)) { sp_rect_compensate_rxry (SP_RECT(item), advertized_transform); @@ -1256,13 +1256,13 @@ sp_item_adjust_rects_recursive(SPItem *item, Geom::Matrix advertized_transform) /** * Recursively compensate pattern or gradient transform. */ -void SPItem::adjust_paint_recursive (Geom::Matrix advertized_transform, Geom::Matrix t_ancestors, bool is_pattern) +void SPItem::adjust_paint_recursive (Geom::Affine advertized_transform, Geom::Affine t_ancestors, bool is_pattern) { // _Before_ full pattern/gradient transform: t_paint * t_item * t_ancestors // _After_ full pattern/gradient transform: t_paint_new * t_item * t_ancestors * advertised_transform // By equating these two expressions we get t_paint_new = t_paint * paint_delta, where: - Geom::Matrix t_item = sp_item_transform_repr (this); - Geom::Matrix paint_delta = t_item * t_ancestors * advertized_transform * t_ancestors.inverse() * t_item.inverse(); + Geom::Affine t_item = sp_item_transform_repr (this); + Geom::Affine paint_delta = t_item * t_ancestors * advertized_transform * t_ancestors.inverse() * t_item.inverse(); // Within text, we do not fork gradients, and so must not recurse to avoid double compensation; // also we do not recurse into clones, because a clone's child is the ghost of its original - @@ -1289,7 +1289,7 @@ void SPItem::adjust_paint_recursive (Geom::Matrix advertized_transform, Geom::Ma } } -void SPItem::adjust_livepatheffect (Geom::Matrix const &postmul, bool set) +void SPItem::adjust_livepatheffect (Geom::Affine const &postmul, bool set) { if ( SP_IS_LPE_ITEM(this) ) { SPLPEItem *lpeitem = SP_LPE_ITEM (this); @@ -1318,12 +1318,12 @@ void SPItem::adjust_livepatheffect (Geom::Matrix const &postmul, bool set) * stored optimized. Send _transformed_signal. Invoke _write method so that * the repr is updated with the new transform. */ -void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Matrix const &transform, Geom::Matrix const *adv, bool compensate) +void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Affine const &transform, Geom::Affine const *adv, bool compensate) { g_return_if_fail(repr != NULL); // calculate the relative transform, if not given by the adv attribute - Geom::Matrix advertized_transform; + Geom::Affine advertized_transform; if (adv != NULL) { advertized_transform = *adv; } else { @@ -1361,7 +1361,7 @@ void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Matrix const &tra } // endif(compensate) gint preserve = prefs->getBool("/options/preservetransform/value", 0); - Geom::Matrix transform_attr (transform); + Geom::Affine transform_attr (transform); if ( // run the object's set_transform (i.e. embed transform) only if: ((SPItemClass *) G_OBJECT_GET_CLASS(this))->set_transform && // it does have a set_transform method !preserve && // user did not chose to preserve all transforms @@ -1397,7 +1397,7 @@ gint SPItem::emitEvent(SPEvent &event) * Sets item private transform (not propagated to repr), without compensating stroke widths, * gradients, patterns as sp_item_write_transform does. */ -void SPItem::set_item_transform(Geom::Matrix const &transform_matrix) +void SPItem::set_item_transform(Geom::Affine const &transform_matrix) { if (!matrix_equalp(transform_matrix, transform, NR_EPSILON)) { transform = transform_matrix; @@ -1424,9 +1424,9 @@ void SPItem::convert_item_to_guides() { * \pre \a ancestor really is an ancestor (\>=) of \a object, or NULL. * ("Ancestor (\>=)" here includes as far as \a object itself.) */ -Geom::Matrix +Geom::Affine i2anc_affine(SPObject const *object, SPObject const *const ancestor) { - Geom::Matrix ret(Geom::identity()); + Geom::Affine ret(Geom::identity()); g_return_val_if_fail(object != NULL, ret); /* stop at first non-renderable ancestor */ @@ -1441,14 +1441,14 @@ i2anc_affine(SPObject const *object, SPObject const *const ancestor) { return ret; } -Geom::Matrix +Geom::Affine i2i_affine(SPObject const *src, SPObject const *dest) { g_return_val_if_fail(src != NULL && dest != NULL, Geom::identity()); SPObject const *ancestor = src->nearestCommonAncestor(dest); return i2anc_affine(src, ancestor) * i2anc_affine(dest, ancestor).inverse(); } -Geom::Matrix SPItem::getRelativeTransform(SPObject const *dest) const { +Geom::Affine SPItem::getRelativeTransform(SPObject const *dest) const { return i2i_affine(this, dest); } @@ -1456,7 +1456,7 @@ Geom::Matrix SPItem::getRelativeTransform(SPObject const *dest) const { * Returns the accumulated transformation of the item and all its ancestors, including root's viewport. * \pre (item != NULL) and SP_IS_ITEM(item). */ -Geom::Matrix SPItem::i2doc_affine() const +Geom::Affine SPItem::i2doc_affine() const { return i2anc_affine(this, NULL); } @@ -1464,17 +1464,17 @@ Geom::Matrix SPItem::i2doc_affine() const /** * Returns the transformation from item to desktop coords */ -Geom::Matrix SPItem::i2d_affine() const +Geom::Affine SPItem::i2d_affine() const { - Geom::Matrix const ret( i2doc_affine() + Geom::Affine const ret( i2doc_affine() * Geom::Scale(1, -1) * Geom::Translate(0, document->getHeight()) ); return ret; } -void SPItem::set_i2d_affine(Geom::Matrix const &i2dt) +void SPItem::set_i2d_affine(Geom::Affine const &i2dt) { - Geom::Matrix dt2p; /* desktop to item parent transform */ + Geom::Affine dt2p; /* desktop to item parent transform */ if (parent) { dt2p = static_cast<SPItem *>(parent)->i2d_affine().inverse(); } else { @@ -1482,7 +1482,7 @@ void SPItem::set_i2d_affine(Geom::Matrix const &i2dt) * Geom::Scale(1, -1) ); } - Geom::Matrix const i2p( i2dt * dt2p ); + Geom::Affine const i2p( i2dt * dt2p ); set_item_transform(i2p); } @@ -1490,7 +1490,7 @@ void SPItem::set_i2d_affine(Geom::Matrix const &i2dt) /** * should rather be named "sp_item_d2i_affine" to match "sp_item_i2d_affine" (or vice versa) */ -Geom::Matrix SPItem::dt2i_affine() const +Geom::Affine SPItem::dt2i_affine() const { /* fixme: Implement the right way (Lauris) */ return i2d_affine().inverse(); @@ -1547,12 +1547,17 @@ NRArenaItem *SPItem::get_arenaitem(unsigned key) return NULL; } -int sp_item_repr_compare_position(SPItem *first, SPItem *second) +int sp_item_repr_compare_position(SPItem const *first, SPItem const *second) { return sp_repr_compare_position(first->getRepr(), second->getRepr()); } +SPItem const *sp_item_first_item_child(SPObject const *obj) +{ + return sp_item_first_item_child( const_cast<SPObject *>(obj) ); +} + SPItem *sp_item_first_item_child(SPObject *obj) { SPItem *child = 0; diff --git a/src/sp-item.h b/src/sp-item.h index 4ba3dc7a4..7c3eb87d9 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -22,7 +22,7 @@ #include "display/nr-arena-forward.h" #include "sp-object.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <libnr/nr-rect.h> #include <2geom/forward.h> #include <libnr/nr-convert2geom.h> @@ -86,11 +86,11 @@ class SPItemCtx { public: SPCtx ctx; /** Item to document transformation */ - Geom::Matrix i2doc; + Geom::Affine i2doc; /** Viewport size */ NRRect vp; /** Item to viewport transformation */ - Geom::Matrix i2vp; + Geom::Affine i2vp; }; class SPItem; @@ -120,7 +120,7 @@ public: double transform_center_x; double transform_center_y; - Geom::Matrix transform; + Geom::Affine transform; SPClipPathReference *clip_ref; SPMaskReference *mask_ref; @@ -132,7 +132,7 @@ public: std::vector<SPGuideConstraint> constraints; - sigc::signal<void, Geom::Matrix const *, SPItem *> _transformed_signal; + sigc::signal<void, Geom::Affine const *, SPItem *> _transformed_signal; void init(); bool isLocked() const; @@ -160,25 +160,25 @@ public: bool isVisibleAndUnlocked(unsigned display_key) const; - Geom::Matrix getRelativeTransform(SPObject const *obj) const; + Geom::Affine getRelativeTransform(SPObject const *obj) const; void raiseOne(); void lowerOne(); void raiseToTop(); void lowerToBottom(); - Geom::OptRect getBounds(Geom::Matrix const &transform, BBoxType type=APPROXIMATE_BBOX, unsigned int dkey=0) const; + Geom::OptRect getBounds(Geom::Affine const &transform, BBoxType type=APPROXIMATE_BBOX, unsigned int dkey=0) const; sigc::connection _clip_ref_connection; sigc::connection _mask_ref_connection; - sigc::connection connectTransformed(sigc::slot<void, Geom::Matrix const *, SPItem *> slot) { + sigc::connection connectTransformed(sigc::slot<void, Geom::Affine const *, SPItem *> slot) { return _transformed_signal.connect(slot); } - void invoke_bbox( Geom::OptRect &bbox, Geom::Matrix const &transform, unsigned const clear, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX); - void invoke_bbox( NRRect *bbox, Geom::Matrix const &transform, unsigned const clear, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) __attribute__ ((deprecated)); - void invoke_bbox_full( Geom::OptRect &bbox, Geom::Matrix const &transform, unsigned const flags, unsigned const clear) const; - void invoke_bbox_full( NRRect *bbox, Geom::Matrix const &transform, unsigned const flags, unsigned const clear) __attribute__ ((deprecated)); + void invoke_bbox( Geom::OptRect &bbox, Geom::Affine const &transform, unsigned const clear, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX); + void invoke_bbox( NRRect *bbox, Geom::Affine const &transform, unsigned const clear, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) __attribute__ ((deprecated)); + void invoke_bbox_full( Geom::OptRect &bbox, Geom::Affine const &transform, unsigned const flags, unsigned const clear) const; + void invoke_bbox_full( NRRect *bbox, Geom::Affine const &transform, unsigned const flags, unsigned const clear) __attribute__ ((deprecated)); unsigned pos_in_parent(); gchar *description(); @@ -187,23 +187,23 @@ public: NRArenaItem *invoke_show(NRArena *arena, unsigned int key, unsigned int flags); void invoke_hide(unsigned int key); void getSnappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs=0) const; - void adjust_pattern(/* Geom::Matrix const &premul, */ Geom::Matrix const &postmul, bool set = false); - void adjust_gradient(/* Geom::Matrix const &premul, */ Geom::Matrix const &postmul, bool set = false); + void adjust_pattern(/* Geom::Affine const &premul, */ Geom::Affine const &postmul, bool set = false); + void adjust_gradient(/* Geom::Affine const &premul, */ Geom::Affine const &postmul, bool set = false); void adjust_stroke(gdouble ex); void adjust_stroke_width_recursive(gdouble ex); - void adjust_paint_recursive(Geom::Matrix advertized_transform, Geom::Matrix t_ancestors, bool is_pattern); - void adjust_livepatheffect(Geom::Matrix const &postmul, bool set = false); - void doWriteTransform(Inkscape::XML::Node *repr, Geom::Matrix const &transform, Geom::Matrix const *adv = NULL, bool compensate = true); - void set_item_transform(Geom::Matrix const &transform_matrix); + void adjust_paint_recursive(Geom::Affine advertized_transform, Geom::Affine t_ancestors, bool is_pattern); + void adjust_livepatheffect(Geom::Affine const &postmul, bool set = false); + void doWriteTransform(Inkscape::XML::Node *repr, Geom::Affine const &transform, Geom::Affine const *adv = NULL, bool compensate = true); + void set_item_transform(Geom::Affine const &transform_matrix); void convert_item_to_guides(); gint emitEvent (SPEvent &event); NRArenaItem *get_arenaitem(unsigned int key); void getBboxDesktop(NRRect *bbox, SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX) __attribute__ ((deprecated)); Geom::OptRect getBboxDesktop(SPItem::BBoxType type = SPItem::APPROXIMATE_BBOX); - Geom::Matrix i2doc_affine() const; - Geom::Matrix i2d_affine() const; - void set_i2d_affine(Geom::Matrix const &transform); - Geom::Matrix dt2i_affine() const; + Geom::Affine i2doc_affine() const; + Geom::Affine i2d_affine() const; + void set_i2d_affine(Geom::Affine const &transform); + Geom::Affine dt2i_affine() const; void convert_to_guides(); private: @@ -240,7 +240,7 @@ public: SPObjectClass parent_class; /** BBox union in given coordinate system */ - void (* bbox) (SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); + void (* bbox) (SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); /** Printing method. Assumes ctm is set to item affine matrix */ /* \todo Think about it, and maybe implement generic export method instead (Lauris) */ @@ -258,7 +258,7 @@ public: void (* snappoints) (SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); /** Apply the transform optimally, and return any residual transformation */ - Geom::Matrix (* set_transform)(SPItem *item, Geom::Matrix const &transform); + Geom::Affine (* set_transform)(SPItem *item, Geom::Affine const &transform); /** Convert the item to guidelines */ void (* convert_to_guides)(SPItem *item); @@ -275,8 +275,8 @@ public: // Utility -Geom::Matrix i2anc_affine(SPObject const *item, SPObject const *ancestor); -Geom::Matrix i2i_affine(SPObject const *src, SPObject const *dest); +Geom::Affine i2anc_affine(SPObject const *item, SPObject const *ancestor); +Geom::Affine i2i_affine(SPObject const *src, SPObject const *dest); /* fixme: - these are evil, but OK */ @@ -286,8 +286,9 @@ Geom::Matrix i2i_affine(SPObject const *src, SPObject const *dest); * * \return TRANSFORM. */ -int sp_item_repr_compare_position(SPItem *first, SPItem *second); +int sp_item_repr_compare_position(SPItem const *first, SPItem const *second); SPItem *sp_item_first_item_child (SPObject *obj); +SPItem const *sp_item_first_item_child (SPObject const *obj); #endif // SEEN_SP_ITEM_H diff --git a/src/sp-line.cpp b/src/sp-line.cpp index 67a88e17a..b21122566 100644 --- a/src/sp-line.cpp +++ b/src/sp-line.cpp @@ -179,7 +179,7 @@ void SPLine::convertToGuides(SPItem *item) SPLine *line = SP_LINE(item); Geom::Point points[2]; - Geom::Matrix const i2d(item->i2d_affine()); + Geom::Affine const i2d(item->i2d_affine()); points[0] = Geom::Point(line->x1.computed, line->y1.computed)*i2d; points[1] = Geom::Point(line->x2.computed, line->y2.computed)*i2d; @@ -187,7 +187,7 @@ void SPLine::convertToGuides(SPItem *item) SPGuide::createSPGuide(inkscape_active_desktop(), points[0], points[1]); } -Geom::Matrix SPLine::setTransform(SPItem *item, Geom::Matrix const &xform) +Geom::Affine SPLine::setTransform(SPItem *item, Geom::Affine const &xform) { SPLine *line = SP_LINE(item); Geom::Point points[2]; @@ -220,6 +220,9 @@ void SPLine::setShape(SPShape *shape) c->lineto(line->x2.computed, line->y2.computed); shape->setCurveInsync(c, TRUE); // *_insync does not call update, avoiding infinite recursion when set_shape is called by update + shape->setCurveBeforeLPE(c); + + // LPE's cannot be applied to lines. (the result can (generally) not be represented as SPLine) c->unref(); } diff --git a/src/sp-line.h b/src/sp-line.h index 8bcb81645..182f85a5c 100644 --- a/src/sp-line.h +++ b/src/sp-line.h @@ -44,7 +44,7 @@ private: static Inkscape::XML::Node *write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static gchar *getDescription(SPItem * item); - static Geom::Matrix setTransform(SPItem *item, Geom::Matrix const &xform); + static Geom::Affine setTransform(SPItem *item, Geom::Affine const &xform); static void update(SPObject *object, SPCtx *ctx, guint flags); static void setShape(SPShape *shape); diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index afd36d2dd..7d42400fa 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -434,7 +434,7 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) } } else if (SP_IS_PATH(lpeitem)) { - Inkscape::XML::Node *pathrepr = SP_OBJECT_REPR(lpeitem); + Inkscape::XML::Node *pathrepr = lpeitem->getRepr(); if ( !pathrepr->attribute("inkscape:original-d") ) { pathrepr->setAttribute("inkscape:original-d", pathrepr->attribute("d")); } @@ -454,7 +454,7 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) } } else if (SP_IS_PATH(lpeitem)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(lpeitem); + Inkscape::XML::Node *repr = lpeitem->getRepr(); if (!sp_lpe_item_has_path_effect_recursive(lpeitem) && repr->attribute("inkscape:original-d")) { repr->setAttribute("d", repr->attribute("inkscape:original-d")); @@ -485,7 +485,7 @@ void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset) hreflist.push_back( std::string(value) ); std::string hrefs = hreflist_write_svg(hreflist); - SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", hrefs.c_str()); + lpeitem->getRepr()->setAttribute("inkscape:path-effect", hrefs.c_str()); // make sure there is an original-d for paths!!! sp_lpe_item_create_original_path_recursive(lpeitem); @@ -516,7 +516,7 @@ void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, gchar *value, bool reset) void sp_lpe_item_add_path_effect(SPLPEItem *lpeitem, LivePathEffectObject * new_lpeobj) { - const gchar * repr_id = SP_OBJECT_REPR(new_lpeobj)->attribute("id"); + const gchar * repr_id = new_lpeobj->getRepr()->attribute("id"); gchar *hrefstr = g_strdup_printf("#%s", repr_id); sp_lpe_item_add_path_effect(lpeitem, hrefstr, false); g_free(hrefstr); @@ -533,9 +533,9 @@ void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths) std::string r = patheffectlist_write_svg(new_list); if (!r.empty()) { - SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str()); + lpeitem->getRepr()->setAttribute("inkscape:path-effect", r.c_str()); } else { - SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL); + lpeitem->getRepr()->setAttribute("inkscape:path-effect", NULL); } if (!keep_paths) { @@ -545,7 +545,7 @@ void sp_lpe_item_remove_current_path_effect(SPLPEItem *lpeitem, bool keep_paths) void sp_lpe_item_remove_all_path_effects(SPLPEItem *lpeitem, bool keep_paths) { - SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", NULL); + lpeitem->getRepr()->setAttribute("inkscape:path-effect", NULL); if (!keep_paths) { sp_lpe_item_cleanup_original_path_recursive(lpeitem); @@ -568,7 +568,7 @@ void sp_lpe_item_down_current_path_effect(SPLPEItem *lpeitem) } } std::string r = patheffectlist_write_svg(new_list); - SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str()); + lpeitem->getRepr()->setAttribute("inkscape:path-effect", r.c_str()); sp_lpe_item_cleanup_original_path_recursive(lpeitem); } @@ -588,7 +588,7 @@ void sp_lpe_item_up_current_path_effect(SPLPEItem *lpeitem) } std::string r = patheffectlist_write_svg(new_list); - SP_OBJECT_REPR(lpeitem)->setAttribute("inkscape:path-effect", r.c_str()); + lpeitem->getRepr()->setAttribute("inkscape:path-effect", r.c_str()); sp_lpe_item_cleanup_original_path_recursive(lpeitem); } @@ -785,7 +785,7 @@ void SPLPEItem::replacePathEffects( std::vector<LivePathEffectObject const *> co std::vector<LivePathEffectObject const *>::const_iterator found_it(std::find(old_lpeobjs.begin(), old_lpeobjs.end(), current_lpeobj)); if ( found_it != old_lpeobjs.end() ) { std::vector<LivePathEffectObject const *>::difference_type found_index = std::distance (old_lpeobjs.begin(), found_it); - const gchar * repr_id = SP_OBJECT_REPR(new_lpeobjs[found_index])->attribute("id"); + const gchar * repr_id = new_lpeobjs[found_index]->getRepr()->attribute("id"); gchar *hrefstr = g_strdup_printf("#%s", repr_id); hreflist.push_back( std::string(hrefstr) ); g_free(hrefstr); @@ -795,7 +795,7 @@ void SPLPEItem::replacePathEffects( std::vector<LivePathEffectObject const *> co } } std::string r = hreflist_write_svg(hreflist); - SP_OBJECT_REPR(this)->setAttribute("inkscape:path-effect", r.c_str()); + this->getRepr()->setAttribute("inkscape:path-effect", r.c_str()); } /** @@ -815,7 +815,7 @@ bool sp_lpe_item_fork_path_effects_if_necessary(SPLPEItem *lpeitem, unsigned int // Clones of the LPEItem will increase the refcount of the lpeobjects. // Therefore, nr_of_allowed_users should be increased with the number of clones (i.e. refs to the lpeitem) - nr_of_allowed_users += SP_OBJECT(lpeitem)->hrefcount; + nr_of_allowed_users += lpeitem->hrefcount; std::vector<LivePathEffectObject const *> old_lpeobjs, new_lpeobjs; PathEffectList effect_list = sp_lpe_item_get_effect_list(lpeitem); diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index 1af7f2797..d1baa4309 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -15,7 +15,6 @@ */ #include "sp-item.h" -#include "display/display-forward.h" #include <list> @@ -26,12 +25,17 @@ #define SP_IS_LPE_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_LPE_ITEM)) struct LivePathEffectObject; +struct SPCurve; + namespace Inkscape{ +namespace Display { + class TemporaryItem; +} namespace LivePathEffect{ class LPEObjectReference; class Effect; -}; -}; +} +} typedef std::list<Inkscape::LivePathEffect::LPEObjectReference *> PathEffectList; diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index 54dc51608..65f88afde 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -110,23 +110,22 @@ sp_mask_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr document->addResource("mask", object); } -static void -sp_mask_release (SPObject * object) +static void sp_mask_release (SPObject * object) { - if (SP_OBJECT_DOCUMENT (object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("mask", object); - } + if (object->document) { + // Unregister ourselves + object->document->removeResource("mask", object); + } - SPMask *cp = SP_MASK (object); - while (cp->display) { - /* We simply unref and let item manage this in handler */ - cp->display = sp_mask_view_list_remove (cp->display, cp->display); - } + SPMask *cp = SP_MASK (object); + while (cp->display) { + // We simply unref and let item manage this in handler + cp->display = sp_mask_view_list_remove (cp->display, cp->display); + } - if (((SPObjectClass *) (parent_class))->release) { - ((SPObjectClass *) parent_class)->release (object); - } + if (((SPObjectClass *) (parent_class))->release) { + ((SPObjectClass *) parent_class)->release (object); + } } static void @@ -175,7 +174,7 @@ sp_mask_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML ((SPObjectClass *) (parent_class))->child_added (object, child, ref); /* Show new object */ - SPObject *ochild = SP_OBJECT_DOCUMENT (object)->getObjectByRepr(child); + SPObject *ochild = object->document->getObjectByRepr(child); if (SP_IS_ITEM (ochild)) { SPMask *cp = SP_MASK (object); for (SPMaskView *v = cp->display; v != NULL; v = v->next) { @@ -216,7 +215,7 @@ static void sp_mask_update(SPObject *object, SPCtx *ctx, guint flags) SPMask *mask = SP_MASK(object); for (SPMaskView *v = mask->display; v != NULL; v = v->next) { if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix t(Geom::Scale(v->bbox.x1 - v->bbox.x0, v->bbox.y1 - v->bbox.y0)); + Geom::Affine t(Geom::Scale(v->bbox.x1 - v->bbox.x0, v->bbox.y1 - v->bbox.y0)); t[4] = v->bbox.x0; t[5] = v->bbox.y0; nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), &t); @@ -266,9 +265,9 @@ sp_mask_write (SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML // Create a mask element (using passed elements), add it to <defs> const gchar * -sp_mask_create (GSList *reprs, SPDocument *document, Geom::Matrix const* applyTransform) +sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform) { - Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); + Inkscape::XML::Node *defsrepr = SP_DOCUMENT_DEFS(document)->getRepr(); Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:mask"); @@ -283,9 +282,9 @@ sp_mask_create (GSList *reprs, SPDocument *document, Geom::Matrix const* applyTr SPItem *item = SP_ITEM(mask_object->appendChildRepr(node)); if (NULL != applyTransform) { - Geom::Matrix transform (item->transform); + Geom::Affine transform (item->transform); transform *= (*applyTransform); - item->doWriteTransform(SP_OBJECT_REPR(item), transform); + item->doWriteTransform(item->getRepr(), transform); } } @@ -317,7 +316,7 @@ NRArenaItem *sp_mask_show(SPMask *mask, NRArena *arena, unsigned int key) } if (mask->maskContentUnits == SP_CONTENT_UNITS_OBJECTBOUNDINGBOX) { - Geom::Matrix t(Geom::Scale(mask->display->bbox.x1 - mask->display->bbox.x0, mask->display->bbox.y1 - mask->display->bbox.y0)); + Geom::Affine t(Geom::Scale(mask->display->bbox.x1 - mask->display->bbox.x0, mask->display->bbox.y1 - mask->display->bbox.y0)); t[4] = mask->display->bbox.x0; t[5] = mask->display->bbox.y0; nr_arena_group_set_child_transform (NR_ARENA_GROUP (ai), &t); diff --git a/src/sp-mask.h b/src/sp-mask.h index d8b6b33ea..5a98ac8c5 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -95,6 +95,6 @@ void sp_mask_hide (SPMask *mask, unsigned int key); void sp_mask_set_bbox (SPMask *mask, unsigned int key, NRRect *bbox); -const gchar *sp_mask_create (GSList *reprs, SPDocument *document, Geom::Matrix const* applyTransform); +const gchar *sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform); #endif // SEEN_SP_MASK_H diff --git a/src/sp-metadata.cpp b/src/sp-metadata.cpp index 426810c7d..21410d4fd 100644 --- a/src/sp-metadata.cpp +++ b/src/sp-metadata.cpp @@ -188,11 +188,11 @@ sp_metadata_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML: debug("0x%08x",(unsigned int)object); //SPMetadata *metadata = SP_METADATA(object); - if ( repr != SP_OBJECT_REPR(object) ) { + if ( repr != object->getRepr() ) { if (repr) { - repr->mergeFrom(SP_OBJECT_REPR (object), "id"); + repr->mergeFrom(object->getRepr(), "id"); } else { - repr = SP_OBJECT_REPR (object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } } @@ -221,4 +221,13 @@ sp_document_metadata (SPDocument *document) } -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/sp-missing-glyph.cpp b/src/sp-missing-glyph.cpp index 9604fe0ca..fdf75253e 100644 --- a/src/sp-missing-glyph.cpp +++ b/src/sp-missing-glyph.cpp @@ -175,7 +175,7 @@ static Inkscape::XML::Node *sp_missing_glyph_write(SPObject *object, Inkscape::X sp_repr_set_svg_double(repr, "vert-origin-y", glyph->vert_origin_y); sp_repr_set_svg_double(repr, "vert-adv-y", glyph->vert_adv_y); */ - if (repr != SP_OBJECT_REPR(object)) { + if (repr != object->getRepr()) { // All the COPY_ATTR functions below use // XML Tree directly while they shouldn't. diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 59ef4762d..001f7731f 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -269,7 +269,7 @@ static void sp_namedview_build(SPObject *object, SPDocument *document, Inkscape: object->readAttr( "inkscape:connector-spacing" ); /* Construct guideline list */ - for (SPObject *o = SP_OBJECT(og)->firstChild() ; o; o = o->getNext() ) { + for (SPObject *o = og->firstChild() ; o; o = o->getNext() ) { if (SP_IS_GUIDE(o)) { SPGuide * g = SP_GUIDE(o); nv->guides = g_slist_prepend(nv->guides, g); @@ -696,7 +696,7 @@ static void sp_namedview_remove_child(SPObject *object, Inkscape::XML::Node *chi } else { GSList **ref = &nv->guides; for ( GSList *iter = nv->guides ; iter ; iter = iter->next ) { - if ( SP_OBJECT_REPR((SPObject *)iter->data) == child ) { + if ( reinterpret_cast<SPObject *>(iter->data)->getRepr() == child ) { *ref = iter->next; iter->next = NULL; g_slist_free_1(iter); @@ -714,12 +714,12 @@ static void sp_namedview_remove_child(SPObject *object, Inkscape::XML::Node *chi static Inkscape::XML::Node *sp_namedview_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { if ( ( flags & SP_OBJECT_WRITE_EXT ) && - repr != SP_OBJECT_REPR(object) ) + repr != object->getRepr() ) { if (repr) { - repr->mergeFrom(SP_OBJECT_REPR(object), "id"); + repr->mergeFrom(object->getRepr(), "id"); } else { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } } @@ -739,7 +739,7 @@ void SPNamedView::show(SPDesktop *desktop) views = g_slist_prepend(views, desktop); // generate grids specified in SVG: - Inkscape::XML::Node *repr = SP_OBJECT_REPR(this); + Inkscape::XML::Node *repr = this->getRepr(); if (repr) { for (Inkscape::XML::Node * child = repr->firstChild() ; child != NULL; child = child->next() ) { if (!strcmp(child->name(), "inkscape:grid")) { @@ -850,7 +850,7 @@ void sp_namedview_document_from_window(SPDesktop *desktop) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool save_geometry_in_file = prefs->getBool("/options/savewindowgeometry/value", 0); - Inkscape::XML::Node *view = SP_OBJECT_REPR(desktop->namedview); + Inkscape::XML::Node *view = desktop->namedview->getRepr(); Geom::Rect const r = desktop->get_display_area(); // saving window geometry is not undoable @@ -943,8 +943,8 @@ void sp_namedview_show_grids(SPNamedView * namedview, bool show, bool dirty_docu { namedview->grids_visible = show; - SPDocument *doc = SP_OBJECT_DOCUMENT (namedview); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(namedview); + SPDocument *doc = namedview->document; + Inkscape::XML::Node *repr = namedview->getRepr(); bool saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); @@ -962,7 +962,7 @@ gchar const *SPNamedView::getName() const { SPException ex; SP_EXCEPTION_INIT(&ex); - return SP_OBJECT(this)->getAttribute("id", &ex); + return this->getAttribute("id", &ex); } guint SPNamedView::getViewCount() diff --git a/src/sp-object.h b/src/sp-object.h index 8581fd35a..38d39c4cd 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -46,21 +46,13 @@ class SPObjectClass; /* Parent, Style, Viewport, User */ #define SP_OBJECT_MODIFIED_CASCADE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG)) -/* Generic */ -#define SP_OBJECT_IS_CLONED(o) (((SPObject *) (o))->cloned) - /* Write flags */ #define SP_OBJECT_WRITE_BUILD (1 << 0) #define SP_OBJECT_WRITE_EXT (1 << 1) #define SP_OBJECT_WRITE_ALL (1 << 2) -/* Convenience stuff */ -#define SP_OBJECT_REPR(o) (((SPObject *) (o))->getRepr()) -#define SP_OBJECT_DOCUMENT(o) (((SPObject *) (o))->document) -#define SP_OBJECT_PARENT(o) (((SPObject *) (o))->parent) -#define SP_OBJECT_STYLE(o) (((SPObject *) (o))->style) - #include <glib-object.h> +#include <stddef.h> #include <sigc++/connection.h> #include <sigc++/functors/slot.h> #include <sigc++/signal.h> diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 019942892..460421492 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -36,7 +36,7 @@ #include "sp-use-reference.h" #include "uri.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <2geom/pathvector.h> #include "xml/repr.h" @@ -90,7 +90,7 @@ static void refresh_offset_source(SPOffset* offset); static void sp_offset_start_listening(SPOffset *offset,SPObject* to); static void sp_offset_quit_listening(SPOffset *offset); static void sp_offset_href_changed(SPObject *old_ref, SPObject *ref, SPOffset *offset); -static void sp_offset_move_compensate(Geom::Matrix const *mp, SPItem *original, SPOffset *self); +static void sp_offset_move_compensate(Geom::Affine const *mp, SPItem *original, SPOffset *self); static void sp_offset_delete_self(SPObject *deleted, SPOffset *self); static void sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *item); @@ -183,7 +183,7 @@ sp_offset_init(SPOffset *offset) new (&offset->_changed_connection) sigc::connection(); new (&offset->_transformed_connection) sigc::connection(); // set up the uri reference - offset->sourceRef = new SPUseReference(SP_OBJECT(offset)); + offset->sourceRef = new SPUseReference(offset); offset->_changed_connection = offset->sourceRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_offset_href_changed), offset)); } @@ -457,12 +457,13 @@ sp_offset_set_shape(SPShape *shape) // it's also useless to compute the offset with a 0 radius //XML Tree being used directly here while it shouldn't be. - const char *res_d = SP_OBJECT(shape)->getRepr()->attribute("inkscape:original"); + const char *res_d = shape->getRepr()->attribute("inkscape:original"); if ( res_d ) { Geom::PathVector pv = sp_svg_read_pathv(res_d); SPCurve *c = new SPCurve(pv); g_assert(c != NULL); ((SPShape *) offset)->setCurveInsync (c, TRUE); + ((SPShape *) offset)->setCurveBeforeLPE(c); c->unref(); } return; @@ -712,6 +713,7 @@ sp_offset_set_shape(SPShape *shape) SPCurve *c = new SPCurve(pv); g_assert(c != NULL); ((SPShape *) offset)->setCurveInsync (c, TRUE); + ((SPShape *) offset)->setCurveBeforeLPE(c); c->unref(); free (res_d); @@ -987,15 +989,16 @@ sp_offset_top_point (SPOffset * offset, Geom::Point *px) // the listening functions static void sp_offset_start_listening(SPOffset *offset,SPObject* to) { - if ( to == NULL ) + if ( to == NULL ) { return; + } offset->sourceObject = to; - offset->sourceRepr = SP_OBJECT_REPR(to); + offset->sourceRepr = to->getRepr(); - offset->_delete_connection = SP_OBJECT(to)->connectDelete(sigc::bind(sigc::ptr_fun(&sp_offset_delete_self), offset)); + offset->_delete_connection = to->connectDelete(sigc::bind(sigc::ptr_fun(&sp_offset_delete_self), offset)); offset->_transformed_connection = SP_ITEM(to)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_offset_move_compensate), offset)); - offset->_modified_connection = SP_OBJECT(to)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_offset_source_modified), offset)); + offset->_modified_connection = to->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_offset_source_modified), offset)); } static void sp_offset_quit_listening(SPOffset *offset) @@ -1019,41 +1022,48 @@ sp_offset_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPOffset *offse SPItem *refobj = offset->sourceRef->getObject(); if (refobj) sp_offset_start_listening(offset,refobj); offset->sourceDirty=true; - SP_OBJECT(offset)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } static void -sp_offset_move_compensate(Geom::Matrix const *mp, SPItem */*original*/, SPOffset *self) +sp_offset_move_compensate(Geom::Affine const *mp, SPItem */*original*/, SPOffset *self) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint mode = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_PARALLEL); - if (mode == SP_CLONE_COMPENSATION_NONE) return; - Geom::Matrix m(*mp); - if (!(m.isTranslation())) return; + SPItem *item = SP_ITEM(self); + + Geom::Affine m(*mp); + if (!(m.isTranslation()) || mode == SP_CLONE_COMPENSATION_NONE) { + self->sourceDirty=true; + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + return; + } // calculate the compensation matrix and the advertized movement matrix - SPItem *item = SP_ITEM(self); + item->readAttr("transform"); - Geom::Matrix compensate; - Geom::Matrix advertized_move; + Geom::Affine t = self->transform; + Geom::Affine offset_move = t.inverse() * m * t; - if (mode == SP_CLONE_COMPENSATION_UNMOVED) { - compensate = Geom::identity(); - advertized_move.setIdentity(); - } else if (mode == SP_CLONE_COMPENSATION_PARALLEL) { - compensate = m; + Geom::Affine advertized_move; + if (mode == SP_CLONE_COMPENSATION_PARALLEL) { + offset_move = offset_move.inverse() * m; advertized_move = m; + } else if (mode == SP_CLONE_COMPENSATION_UNMOVED) { + offset_move = offset_move.inverse(); + advertized_move.setIdentity(); } else { g_assert_not_reached(); } - item->transform *= compensate; + self->sourceDirty=true; // commit the compensation - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform, &advertized_move); - SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + item->transform *= offset_move; + item->doWriteTransform(item->getRepr(), item->transform, &advertized_move); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } static void @@ -1069,17 +1079,18 @@ sp_offset_delete_self(SPObject */*deleted*/, SPOffset *offset) offset->sourceHref = NULL; offset->sourceRef->detach(); } else if (mode == SP_CLONE_ORPHANS_DELETE) { - SP_OBJECT(offset)->deleteObject(); + offset->deleteObject(); } } static void -sp_offset_source_modified (SPObject */*iSource*/, guint /*flags*/, SPItem *item) +sp_offset_source_modified (SPObject */*iSource*/, guint flags, SPItem *item) { SPOffset *offset = SP_OFFSET(item); offset->sourceDirty=true; - refresh_offset_source(offset); - ((SPShape *) offset)->setShape (); + if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG)) { + offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + } } static void @@ -1110,6 +1121,15 @@ refresh_offset_source(SPOffset* offset) orig->LoadPathVector(curve->get_pathvector()); curve->unref(); + if (!item->transform.isIdentity()) { + gchar const *t_attr = item->getRepr()->attribute("transform"); + if (t_attr) { + Geom::Affine t; + if (sp_svg_transform_read(t_attr, &t)) { + orig->Transform(t); + } + } + } // Finish up. { @@ -1148,8 +1168,9 @@ refresh_offset_source(SPOffset* offset) delete res; delete orig; + // TODO fix: //XML Tree being used diectly here while it shouldn't be. - SP_OBJECT (offset)->getRepr()->setAttribute("inkscape:original", res_d); + offset->getRepr()->setAttribute("inkscape:original", res_d); free (res_d); } diff --git a/src/sp-offset.h b/src/sp-offset.h index 47e597c28..a229e0bb6 100644 --- a/src/sp-offset.h +++ b/src/sp-offset.h @@ -16,6 +16,7 @@ #include "sp-shape.h" +#include <stddef.h> #include <sigc++/sigc++.h> #define SP_TYPE_OFFSET (sp_offset_get_type ()) diff --git a/src/sp-path.cpp b/src/sp-path.cpp index dbba440da..c8022d351 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -58,7 +58,7 @@ static void sp_path_build(SPObject *object, SPDocument *document, Inkscape::XML: static void sp_path_set(SPObject *object, unsigned key, gchar const *value); static Inkscape::XML::Node *sp_path_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static Geom::Matrix sp_path_set_transform(SPItem *item, Geom::Matrix const &xform); +static Geom::Affine sp_path_set_transform(SPItem *item, Geom::Affine const &xform); static gchar * sp_path_description(SPItem *item); static void sp_path_convert_to_guides(SPItem *item); @@ -169,7 +169,7 @@ sp_path_convert_to_guides(SPItem *item) std::list<std::pair<Geom::Point, Geom::Point> > pts; - Geom::Matrix const i2d (SP_ITEM(path)->i2d_affine()); + Geom::Affine const i2d (SP_ITEM(path)->i2d_affine()); Geom::PathVector const & pv = curve->get_pathvector(); for(Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { @@ -371,8 +371,8 @@ sp_path_update(SPObject *object, SPCtx *ctx, guint flags) /** * Writes the given transform into the repr for the given item. */ -static Geom::Matrix -sp_path_set_transform(SPItem *item, Geom::Matrix const &xform) +static Geom::Affine +sp_path_set_transform(SPItem *item, Geom::Affine const &xform) { SPShape *shape = (SPShape *) item; SPPath *path = (SPPath *) item; @@ -413,7 +413,7 @@ sp_path_update_patheffect(SPLPEItem *lpeitem, bool write) { SPShape * const shape = (SPShape *) lpeitem; SPPath * const path = (SPPath *) lpeitem; - Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); + Inkscape::XML::Node *repr = shape->getRepr(); #ifdef PATH_VERBOSE g_message("sp_path_update_patheffect"); @@ -424,10 +424,11 @@ g_message("sp_path_update_patheffect"); /* if a path does not have an lpeitem applied, then reset the curve to the original_curve. * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ shape->setCurveInsync(curve, TRUE); + shape->setCurveBeforeLPE(path->original_curve); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM(shape), curve); if (success && write) { - // could also do SP_OBJECT(shape)->updateRepr(); but only the d attribute needs updating. + // could also do shape->getRepr()->updateRepr(); but only the d attribute needs updating. #ifdef PATH_VERBOSE g_message("sp_path_update_patheffect writes 'd' attribute"); #endif @@ -449,7 +450,7 @@ g_message("sp_path_update_patheffect writes 'd' attribute"); } } } - SP_OBJECT(shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + shape->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); curve->unref(); } } @@ -477,7 +478,7 @@ sp_path_set_original_curve (SPPath *path, SPCurve *curve, unsigned int owner, bo } } sp_lpe_item_update_patheffect(path, true, write); - SP_OBJECT(path)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + path->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } /** diff --git a/src/sp-path.h b/src/sp-path.h index bf294c37c..5cfa34913 100644 --- a/src/sp-path.h +++ b/src/sp-path.h @@ -1,5 +1,5 @@ -#ifndef __SP_PATH_H__ -#define __SP_PATH_H__ +#ifndef SEEN_SP_PATH_H +#define SEEN_SP_PATH_H /* * SVG <path> implementation @@ -16,6 +16,7 @@ #include "sp-shape.h" #include "sp-conn-end-pair.h" +struct SPCurve; #define SP_TYPE_PATH (sp_path_get_type ()) #define SP_PATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_PATH, SPPath)) @@ -39,7 +40,7 @@ SPCurve* sp_path_get_original_curve (SPPath *path); SPCurve* sp_path_get_curve_for_edit (SPPath *path); const SPCurve* sp_path_get_curve_reference (SPPath *path); -#endif +#endif // SEEN_SP_PATH_H /* Local Variables: diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 7a17f0a2a..4cf84835c 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -29,6 +29,7 @@ #include "uri.h" #include "sp-pattern.h" #include "xml/repr.h" +#include "display/grayscale.h" #include <sigc++/functors/ptr_fun.h> #include <sigc++/adaptors/bind.h> @@ -100,7 +101,7 @@ sp_pattern_class_init (SPPatternClass *klass) static void sp_pattern_init (SPPattern *pat) { - pat->ref = new SPPatternReference(SP_OBJECT(pat)); + pat->ref = new SPPatternReference(pat); pat->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(pattern_ref_changed), pat)); pat->patternUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; @@ -142,29 +143,27 @@ sp_pattern_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *r document->addResource("pattern", object); } -static void -sp_pattern_release (SPObject *object) +static void sp_pattern_release(SPObject *object) { - SPPattern *pat; - - pat = (SPPattern *) object; + SPPattern *pat = reinterpret_cast<SPPattern *>(object); - if (SP_OBJECT_DOCUMENT (object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT (object)->removeResource("pattern", SP_OBJECT (object)); - } + if (object->document) { + // Unregister ourselves + object->document->removeResource("pattern", object); + } - if (pat->ref) { - pat->modified_connection.disconnect(); - pat->ref->detach(); - delete pat->ref; - pat->ref = NULL; - } + if (pat->ref) { + pat->modified_connection.disconnect(); + pat->ref->detach(); + delete pat->ref; + pat->ref = NULL; + } - pat->modified_connection.~connection(); + pat->modified_connection.~connection(); - if (((SPObjectClass *) pattern_parent_class)->release) - ((SPObjectClass *) pattern_parent_class)->release (object); + if (((SPObjectClass *) pattern_parent_class)->release) { + ((SPObjectClass *) pattern_parent_class)->release (object); + } } static void @@ -200,7 +199,7 @@ sp_pattern_set (SPObject *object, unsigned int key, const gchar *value) object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_PATTERNTRANSFORM: { - Geom::Matrix t; + Geom::Affine t; if (value && sp_svg_transform_read (value, &t)) { pat->patternTransform = t; pat->patternTransform_set = TRUE; @@ -370,12 +369,12 @@ pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat) /** Gets called when the referenced <pattern> is changed */ -static void -pattern_ref_modified (SPObject */*ref*/, guint /*flags*/, SPPattern *pattern) +static void pattern_ref_modified (SPObject */*ref*/, guint /*flags*/, SPPattern *pattern) { - if (SP_IS_OBJECT (pattern)) - SP_OBJECT (pattern)->requestModified(SP_OBJECT_MODIFIED_FLAG); - /* Conditional to avoid causing infinite loop if there's a cycle in the href chain. */ + if ( SP_IS_OBJECT(pattern) ) { + pattern->requestModified(SP_OBJECT_MODIFIED_FLAG); + } + // Conditional to avoid causing infinite loop if there's a cycle in the href chain. } @@ -390,7 +389,7 @@ count_pattern_hrefs(SPObject *o, SPPattern *pat) guint i = 0; - SPStyle *style = SP_OBJECT_STYLE(o); + SPStyle *style = o->style; if (style && style->fill.isPaintserver() && SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style)) @@ -415,13 +414,13 @@ count_pattern_hrefs(SPObject *o, SPPattern *pat) SPPattern *pattern_chain(SPPattern *pattern) { - SPDocument *document = SP_OBJECT_DOCUMENT (pattern); + SPDocument *document = pattern->document; Inkscape::XML::Document *xml_doc = document->getReprDoc(); - Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); + Inkscape::XML::Node *defsrepr = SP_DOCUMENT_DEFS(document)->getRepr(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern"); repr->setAttribute("inkscape:collect", "always"); - gchar *parent_ref = g_strconcat ("#", SP_OBJECT_REPR(pattern)->attribute("id"), NULL); + gchar *parent_ref = g_strconcat("#", pattern->getRepr()->attribute("id"), NULL); repr->setAttribute("xlink:href", parent_ref); g_free (parent_ref); @@ -438,20 +437,20 @@ sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *pr { if (!pattern->href || pattern->hrefcount > count_pattern_hrefs(item, pattern)) { pattern = pattern_chain (pattern); - gchar *href = g_strconcat ("url(#", SP_OBJECT_REPR (pattern)->attribute("id"), ")", NULL); + gchar *href = g_strconcat("url(#", pattern->getRepr()->attribute("id"), ")", NULL); SPCSSAttr *css = sp_repr_css_attr_new (); sp_repr_css_set_property (css, property, href); - sp_repr_css_change_recursive (SP_OBJECT_REPR (item), css, "style"); + sp_repr_css_change_recursive(item->getRepr(), css, "style"); } return pattern; } void -sp_pattern_transform_multiply (SPPattern *pattern, Geom::Matrix postmul, bool set) +sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set) { // this formula is for a different interpretation of pattern transforms as described in (*) in sp-pattern.cpp - // for it to work, we also need sp_object_read_attr (SP_OBJECT (item), "transform"); + // for it to work, we also need sp_object_read_attr( item, "transform"); //pattern->patternTransform = premul * item->transform * pattern->patternTransform * item->transform.inverse() * postmul; // otherwise the formula is much simpler @@ -463,14 +462,14 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Matrix postmul, bool se pattern->patternTransform_set = TRUE; gchar *c=sp_svg_transform_write(pattern->patternTransform); - SP_OBJECT_REPR(pattern)->setAttribute("patternTransform", c); + pattern->getRepr()->setAttribute("patternTransform", c); g_free(c); } -const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Matrix transform, Geom::Matrix move) +const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) { Inkscape::XML::Document *xml_doc = document->getReprDoc(); - Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); + Inkscape::XML::Node *defsrepr = SP_DOCUMENT_DEFS(document)->getRepr(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern"); repr->setAttribute("patternUnits", "userSpaceOnUse"); @@ -489,13 +488,13 @@ const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document Inkscape::XML::Node *node = (Inkscape::XML::Node *)(i->data); SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); - Geom::Matrix dup_transform; + Geom::Affine dup_transform; if (!sp_svg_transform_read (node->attribute("transform"), &dup_transform)) dup_transform = Geom::identity(); dup_transform *= move; - copy->doWriteTransform(SP_OBJECT_REPR(copy), dup_transform, NULL, false); - } + copy->doWriteTransform(copy->getRepr(), dup_transform, NULL, false); + } Inkscape::GC::release(repr); return pat_id; @@ -534,7 +533,7 @@ guint pattern_patternContentUnits (SPPattern *pat) return pat->patternContentUnits; } -Geom::Matrix const &pattern_patternTransform(SPPattern const *pat) +Geom::Affine const &pattern_patternTransform(SPPattern const *pat) { for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->patternTransform_set) @@ -606,8 +605,8 @@ sp_pattern_create_pattern(SPPaintServer *ps, double opacity) { SPPattern *pat = SP_PATTERN (ps); - Geom::Matrix ps2user; - Geom::Matrix vb2ps = Geom::identity(); + Geom::Affine ps2user; + Geom::Affine vb2ps = Geom::identity(); bool needs_opacity = (1.0 - opacity) >= 1e-3; bool visible = opacity >= 1e-3; @@ -648,13 +647,13 @@ sp_pattern_create_pattern(SPPaintServer *ps, gdouble tmp_y = pattern_height (pat) / (pattern_viewBox(pat)->y1 - pattern_viewBox(pat)->y0); // FIXME: preserveAspectRatio must be taken into account here too! - vb2ps = Geom::Matrix(tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - pattern_viewBox(pat)->x0 * tmp_x, pattern_y(pat) - pattern_viewBox(pat)->y0 * tmp_y); + vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - pattern_viewBox(pat)->x0 * tmp_x, pattern_y(pat) - pattern_viewBox(pat)->y0 * tmp_y); } ps2user = pattern_patternTransform(pat); if (!pat->viewBox_set && pattern_patternContentUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { /* BBox to user coordinate system */ - Geom::Matrix bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + Geom::Affine bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); ps2user *= bbox2user; } ps2user = Geom::Translate (pattern_x (pat), pattern_y (pat)) * ps2user; @@ -665,20 +664,20 @@ sp_pattern_create_pattern(SPPaintServer *ps, if (pattern_patternUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { // interpret x, y, width, height in relation to bbox - Geom::Matrix bbox2user(bbox->x1 - bbox->x0, 0,0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + Geom::Affine bbox2user(bbox->x1 - bbox->x0, 0,0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); pattern_tile = pattern_tile * bbox2user; } cairo_matrix_t cm; cairo_get_matrix(base_ct, &cm); - Geom::Matrix full(cm.xx, cm.yx, cm.xy, cm.yy, 0, 0); + Geom::Affine full(cm.xx, cm.yx, cm.xy, cm.yy, 0, 0); // oversample the pattern slightly // TODO: find optimum value Geom::Point c(pattern_tile.dimensions()*ps2user.descrim()*full.descrim()*1.2); c[Geom::X] = ceil(c[Geom::X]); c[Geom::Y] = ceil(c[Geom::Y]); - Geom::Matrix t = Geom::Scale(c) * Geom::Scale(pattern_tile.dimensions()).inverse(); + Geom::Affine t = Geom::Scale(c) * Geom::Scale(pattern_tile.dimensions()).inverse(); NRRectL one_tile; one_tile.x0 = (int) floor(pattern_tile[Geom::X].min()); diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 6ed7a1482..52f3859a6 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -32,6 +32,7 @@ class SPPatternClass; #include "sp-paint-server.h" #include "uri-references.h" +#include <stddef.h> #include <sigc++/connection.h> class SPPatternReference : public Inkscape::URIReference { @@ -63,7 +64,7 @@ struct SPPattern : public SPPaintServer { guint patternContentUnits : 1; guint patternContentUnits_set : 1; /* patternTransform attribute */ - Geom::Matrix patternTransform; + Geom::Affine patternTransform; guint patternTransform_set : 1; /* Tile rectangle */ SVGLength x; @@ -84,15 +85,15 @@ struct SPPatternClass { guint pattern_users (SPPattern *pattern); SPPattern *pattern_chain (SPPattern *pattern); SPPattern *sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *property); -void sp_pattern_transform_multiply (SPPattern *pattern, Geom::Matrix postmul, bool set); +void sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set); -const gchar *pattern_tile (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Matrix transform, Geom::Matrix move); +const gchar *pattern_tile (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); SPPattern *pattern_getroot (SPPattern *pat); guint pattern_patternUnits (SPPattern *pat); guint pattern_patternContentUnits (SPPattern *pat); -Geom::Matrix const &pattern_patternTransform(SPPattern const *pat); +Geom::Affine const &pattern_patternTransform(SPPattern const *pat); gdouble pattern_x (SPPattern *pat); gdouble pattern_y (SPPattern *pat); gdouble pattern_width (SPPattern *pat); diff --git a/src/sp-polyline.cpp b/src/sp-polyline.cpp index d0954f239..705b9a10b 100644 --- a/src/sp-polyline.cpp +++ b/src/sp-polyline.cpp @@ -140,8 +140,8 @@ Inkscape::XML::Node *SPPolyLine::write(SPObject *object, Inkscape::XML::Document repr = xml_doc->createElement("svg:polyline"); } - if (repr != SP_OBJECT_REPR (object)) { - repr->mergeFrom(SP_OBJECT_REPR (object), "id"); + if (repr != object->getRepr()) { + repr->mergeFrom(object->getRepr(), "id"); } if (((SPObjectClass *) (SPPolyLineClass::static_parent_class))->write) { diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index 377a4f0b7..94a453ae6 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -40,7 +40,7 @@ static void sp_rect_update(SPObject *object, SPCtx *ctx, guint flags); static Inkscape::XML::Node *sp_rect_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static gchar *sp_rect_description(SPItem *item); -static Geom::Matrix sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform); +static Geom::Affine sp_rect_set_transform(SPItem *item, Geom::Affine const &xform); static void sp_rect_convert_to_guides(SPItem *item); static void sp_rect_set_shape(SPShape *shape); @@ -230,6 +230,7 @@ sp_rect_set_shape(SPShape *shape) if ((rect->height.computed < 1e-18) || (rect->width.computed < 1e-18)) { SP_SHAPE(rect)->setCurveInsync( NULL, TRUE); + SP_SHAPE(rect)->setCurveBeforeLPE( NULL ); return; } @@ -280,6 +281,10 @@ sp_rect_set_shape(SPShape *shape) c->closepath(); SP_SHAPE(rect)->setCurveInsync( c, TRUE); + SP_SHAPE(rect)->setCurveBeforeLPE( c ); + + // LPE is not applied because result can generally not be represented as SPRect + c->unref(); } @@ -331,8 +336,8 @@ sp_rect_set_ry(SPRect *rect, gboolean set, gdouble value) /* fixme: Use preferred units somehow (Lauris) */ /* fixme: Alternately preserve whatever units there are (lauris) */ -static Geom::Matrix -sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform) +static Geom::Affine +sp_rect_set_transform(SPItem *item, Geom::Affine const &xform) { SPRect *rect = SP_RECT(item); @@ -341,7 +346,7 @@ sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform) /* This function takes care of translation and scaling, we return whatever parts we can't handle. */ - Geom::Matrix ret(Geom::Matrix(xform).without_translation()); + Geom::Affine ret(Geom::Affine(xform).withoutTranslation()); gdouble const sw = hypot(ret[0], ret[1]); gdouble const sh = hypot(ret[2], ret[3]); if (sw > 1e-9) { @@ -395,7 +400,7 @@ sp_rect_set_transform(SPItem *item, Geom::Matrix const &xform) Returns the ratio in which the vector from p0 to p1 is stretched by transform */ static gdouble -vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Matrix xform) +vector_stretch(Geom::Point p0, Geom::Point p1, Geom::Affine xform) { if (p0 == p1) return 0; @@ -465,7 +470,7 @@ sp_rect_get_rect (SPRect *rect) } void -sp_rect_compensate_rxry(SPRect *rect, Geom::Matrix xform) +sp_rect_compensate_rxry(SPRect *rect, Geom::Affine xform) { if (rect->rx.computed == 0 && rect->ry.computed == 0) return; // nothing to compensate @@ -568,7 +573,7 @@ static void sp_rect_snappoints(SPItem const *item, std::vector<Inkscape::SnapCan SPRect *rect = SP_RECT(item); - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); Geom::Point p0 = Geom::Point(rect->x.computed, rect->y.computed) * i2d; Geom::Point p1 = Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d; @@ -607,7 +612,7 @@ sp_rect_convert_to_guides(SPItem *item) { std::list<std::pair<Geom::Point, Geom::Point> > pts; - Geom::Matrix const i2d (SP_ITEM(rect)->i2d_affine()); + Geom::Affine const i2d (SP_ITEM(rect)->i2d_affine()); Geom::Point A1(Geom::Point(rect->x.computed, rect->y.computed) * i2d); Geom::Point A2(Geom::Point(rect->x.computed, rect->y.computed + rect->height.computed) * i2d); diff --git a/src/sp-rect.h b/src/sp-rect.h index 09d96739b..7bc85dd8a 100644 --- a/src/sp-rect.h +++ b/src/sp-rect.h @@ -63,7 +63,7 @@ void sp_rect_set_visible_height (SPRect *rect, gdouble ry); gdouble sp_rect_get_visible_width (SPRect *rect); gdouble sp_rect_get_visible_height (SPRect *rect); -void sp_rect_compensate_rxry (SPRect *rect, Geom::Matrix xform); +void sp_rect_compensate_rxry (SPRect *rect, Geom::Affine xform); #endif // SEEN_SP_RECT_H diff --git a/src/sp-root.cpp b/src/sp-root.cpp index 40287f3d8..b1eef65d2 100644 --- a/src/sp-root.cpp +++ b/src/sp-root.cpp @@ -371,7 +371,7 @@ static void sp_root_remove_child(SPObject *object, Inkscape::XML::Node *child) { SPRoot *root = (SPRoot *) object; - if ( root->defs && SP_OBJECT_REPR(root->defs) == child ) { + if ( root->defs && (root->defs->getRepr() == child) ) { SPObject *iter = 0; // We search for first remaining <defs> node - it is not beautiful, but works for ( iter = object->firstChild() ; iter ; iter = iter->getNext() ) { @@ -433,7 +433,7 @@ sp_root_update(SPObject *object, SPCtx *ctx, guint flags) * fixme: height seems natural, as this makes the inner svg element * fixme: self-contained. The spec is vague here. */ - root->c2p = Geom::Matrix(Geom::Translate(root->x.computed, + root->c2p = Geom::Affine(Geom::Translate(root->x.computed, root->y.computed)); } @@ -562,7 +562,7 @@ sp_root_modified(SPObject *object, guint flags) /* fixme: (Lauris) */ if (!object->parent && (flags & SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - SP_OBJECT_DOCUMENT(root)->emitResizedSignal(root->width.computed, root->height.computed); + root->document->emitResizedSignal(root->width.computed, root->height.computed); } } diff --git a/src/sp-root.h b/src/sp-root.h index 28ed43154..ab379fb50 100644 --- a/src/sp-root.h +++ b/src/sp-root.h @@ -47,7 +47,7 @@ struct SPRoot : public SPGroup { unsigned int aspect_clip : 1; /** Child to parent additional transform. */ - Geom::Matrix c2p; + Geom::Affine c2p; gchar *onload; diff --git a/src/sp-script.cpp b/src/sp-script.cpp index 3b6a8796d..f18d231b0 100644 --- a/src/sp-script.cpp +++ b/src/sp-script.cpp @@ -90,13 +90,14 @@ sp_script_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep static void sp_script_release(SPObject *object) { - if (SP_OBJECT_DOCUMENT(object)) { - /* Unregister ourselves */ - SP_OBJECT_DOCUMENT(object)->removeResource("script", SP_OBJECT(object)); + if (object->document) { + // Unregister ourselves + object->document->removeResource("script", object); } - if (((SPObjectClass *) parent_class)->release) + if (((SPObjectClass *) parent_class)->release) { ((SPObjectClass *) parent_class)->release(object); + } } static void sp_script_update(SPObject */*object*/, SPCtx */*ctx*/, guint /*flags*/) diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp index a2e8b52f4..28d729b61 100644 --- a/src/sp-shape.cpp +++ b/src/sp-shape.cpp @@ -122,6 +122,7 @@ void SPShape::sp_shape_init(SPShape *shape) shape->marker[i] = NULL; } shape->curve = NULL; + shape->curve_before_lpe = NULL; } void SPShape::sp_shape_finalize(GObject *object) @@ -191,6 +192,9 @@ void SPShape::sp_shape_release(SPObject *object) if (shape->curve) { shape->curve = shape->curve->unref(); } + if (shape->curve_before_lpe) { + shape->curve_before_lpe = shape->curve_before_lpe->unref(); + } if (((SPObjectClass *) SPShapeClass::parent_class)->release) { ((SPObjectClass *) SPShapeClass::parent_class)->release (object); @@ -238,8 +242,7 @@ void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) } if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - SPStyle *style; - style = SP_OBJECT_STYLE (object); + SPStyle *style = object->style; if (style->stroke_width.unit == SP_CSS_UNIT_PERCENT) { SPItemCtx *ictx = (SPItemCtx *) ctx; double const aw = 1.0 / ictx->i2vp.descrim(); @@ -303,7 +306,7 @@ void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags) * Reference for behaviour of zero-length segments: * http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes */ -Geom::Matrix sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2) +Geom::Affine sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2) { Geom::Point p = c1.pointAt(1); Geom::Curve * c1_reverse = c1.reverse(); @@ -330,10 +333,10 @@ Geom::Matrix sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve c return Geom::Rotate(ret_angle) * Geom::Translate(p); } -Geom::Matrix sp_shape_marker_get_transform_at_start(Geom::Curve const & c) +Geom::Affine sp_shape_marker_get_transform_at_start(Geom::Curve const & c) { Geom::Point p = c.pointAt(0); - Geom::Matrix ret = Geom::Translate(p); + Geom::Affine ret = Geom::Translate(p); if ( !c.isDegenerate() ) { Geom::Point tang = c.unitTangentAt(0); @@ -347,10 +350,10 @@ Geom::Matrix sp_shape_marker_get_transform_at_start(Geom::Curve const & c) return ret; } -Geom::Matrix sp_shape_marker_get_transform_at_end(Geom::Curve const & c) +Geom::Affine sp_shape_marker_get_transform_at_end(Geom::Curve const & c) { Geom::Point p = c.pointAt(1); - Geom::Matrix ret = Geom::Translate(p); + Geom::Affine ret = Geom::Translate(p); if ( !c.isDegenerate() ) { Geom::Curve * c_reverse = c.reverse(); @@ -389,7 +392,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) // START marker { - Geom::Matrix const m (sp_shape_marker_get_transform_at_start(pathv.begin()->front())); + Geom::Affine const m (sp_shape_marker_get_transform_at_start(pathv.begin()->front())); for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( shape->marker[i] ) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, @@ -407,7 +410,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) if ( path_it != pathv.begin() && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, don't draw mid marker there { - Geom::Matrix const m (sp_shape_marker_get_transform_at_start(path_it->front())); + Geom::Affine const m (sp_shape_marker_get_transform_at_start(path_it->front())); for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID if ( shape->marker[i] ) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, @@ -427,7 +430,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) * Loop to end_default (so including closing segment), because when a path is closed, * there should be a midpoint marker between last segment and closing straight line segment */ - Geom::Matrix const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2)); + Geom::Affine const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2)); for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID if (shape->marker[i]) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, @@ -444,7 +447,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) // END position if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); - Geom::Matrix const m = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID if (shape->marker[i]) { sp_marker_show_instance ((SPMarker* ) shape->marker[i], ai, @@ -467,7 +470,7 @@ void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai) index--; } Geom::Curve const &lastcurve = path_last[index]; - Geom::Matrix const m = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END if (shape->marker[i]) { @@ -502,9 +505,11 @@ void SPShape::sp_shape_modified(SPObject *object, unsigned int flags) * Calculates the bounding box for item, storing it into bbox. * This also includes the bounding boxes of any markers included in the shape. */ -void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags) +void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags) { SPShape const *shape = SP_SHAPE (item); + SPItem::BBoxType bboxtype = (SPItem::BBoxType) flags; + if (shape->curve) { Geom::OptRect geombbox = bounds_exact_transformed(shape->curve->get_pathvector(), transform); if (geombbox) { @@ -514,14 +519,14 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const cbbox.x1 = (*geombbox)[0][1]; cbbox.y1 = (*geombbox)[1][1]; - switch ((SPItem::BBoxType) flags) { + switch (bboxtype) { case SPItem::GEOMETRIC_BBOX: { // do nothing break; } case SPItem::RENDERING_BBOX: { // convert the stroke to a path and calculate that path's geometric bbox - SPStyle* style=SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if (!style->stroke.isNone()) { Geom::PathVector *pathv = item_outline(item); if (pathv) { @@ -541,7 +546,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const } default: case SPItem::APPROXIMATE_BBOX: { - SPStyle* style=SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if (!style->stroke.isNone()) { double const scale = transform.descrim(); if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord @@ -563,10 +568,10 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const for (unsigned i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( shape->marker[i] ) { SPMarker* marker = SP_MARKER (shape->marker[i]); - SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker)); + SPItem* marker_item = sp_item_first_item_child( marker ); if (marker_item) { - Geom::Matrix tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front())); + Geom::Affine tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front())); if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); @@ -590,7 +595,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const for (unsigned i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID SPMarker* marker = SP_MARKER (shape->marker[i]); if ( !shape->marker[i] ) continue; - SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker)); + SPItem* marker_item = sp_item_first_item_child( marker ); if ( !marker_item ) continue; for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { @@ -598,7 +603,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const if ( path_it != pathv.begin() && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { - Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front())); + Geom::Affine tr(sp_shape_marker_get_transform_at_start(path_it->front())); if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); @@ -622,10 +627,10 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const * there should be a midpoint marker between last segment and closing straight line segment */ SPMarker* marker = SP_MARKER (shape->marker[i]); - SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker)); + SPItem* marker_item = sp_item_first_item_child( marker ); if (marker_item) { - Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2)); + Geom::Affine tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2)); if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); @@ -646,7 +651,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const // END position if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); - Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); @@ -665,7 +670,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const for (unsigned i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END if ( shape->marker[i] ) { SPMarker* marker = SP_MARKER (shape->marker[i]); - SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker)); + SPItem* marker_item = sp_item_first_item_child( marker ); if (marker_item) { /* Get reference to last curve in the path. @@ -677,7 +682,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const } Geom::Curve const &lastcurve = path_last[index]; - Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); if (!marker->orient_auto) { Geom::Point transl = tr.translation(); tr = Geom::Rotate::from_degrees(marker->orient) * Geom::Translate(transl); @@ -709,16 +714,16 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const } static void -sp_shape_print_invoke_marker_printing(SPObject* obj, Geom::Matrix tr, SPStyle* style, SPPrintContext *ctx) { +sp_shape_print_invoke_marker_printing(SPObject* obj, Geom::Affine tr, SPStyle* style, SPPrintContext *ctx) { SPMarker *marker = SP_MARKER(obj); if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = Geom::Scale(style->stroke_width.computed) * tr; } - SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker)); + SPItem* marker_item = sp_item_first_item_child( marker ); tr = marker_item->transform * marker->c2p * tr; - Geom::Matrix old_tr = marker_item->transform; + Geom::Affine old_tr = marker_item->transform; marker_item->transform = tr; marker_item->invoke_print (ctx); marker_item->transform = old_tr; @@ -745,7 +750,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) gint add_comments = prefs->getBool("/printing/debug/add-label-comments"); if (add_comments) { gchar * comment = g_strdup_printf("begin '%s'", - SP_OBJECT(item)->defaultLabel()); + item->defaultLabel()); sp_print_comment(ctx, comment); g_free(comment); } @@ -754,12 +759,12 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) item->invoke_bbox( &pbox, Geom::identity(), TRUE); dbox.x0 = 0.0; dbox.y0 = 0.0; - dbox.x1 = SP_OBJECT_DOCUMENT (item)->getWidth (); - dbox.y1 = SP_OBJECT_DOCUMENT (item)->getHeight (); + dbox.x1 = item->document->getWidth(); + dbox.y1 = item->document->getHeight(); item->getBboxDesktop (&bbox); - Geom::Matrix const i2d(item->i2d_affine()); + Geom::Affine const i2d(item->i2d_affine()); - SPStyle* style = SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if (!style->fill.isNone()) { sp_print_fill (ctx, pathv, &i2d, style, &pbox, &dbox, &bbox); @@ -773,7 +778,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) // START marker for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( shape->marker[i] ) { - Geom::Matrix tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front())); + Geom::Affine tr(sp_shape_marker_get_transform_at_start(pathv.begin()->front())); sp_shape_print_invoke_marker_printing(shape->marker[i], tr, style, ctx); } } @@ -785,7 +790,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) if ( path_it != pathv.begin() && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { - Geom::Matrix tr(sp_shape_marker_get_transform_at_start(path_it->front())); + Geom::Affine tr(sp_shape_marker_get_transform_at_start(path_it->front())); sp_shape_print_invoke_marker_printing(shape->marker[i], tr, style, ctx); } // MID position @@ -797,7 +802,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) /* Put marker between curve_it1 and curve_it2. * Loop to end_default (so including closing segment), because when a path is closed, * there should be a midpoint marker between last segment and closing straight line segment */ - Geom::Matrix tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2)); + Geom::Affine tr(sp_shape_marker_get_transform(*curve_it1, *curve_it2)); sp_shape_print_invoke_marker_printing(shape->marker[i], tr, style, ctx); @@ -807,7 +812,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) } if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); - Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); sp_shape_print_invoke_marker_printing(shape->marker[i], tr, style, ctx); } } @@ -824,7 +829,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) } Geom::Curve const &lastcurve = path_last[index]; - Geom::Matrix tr = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine tr = sp_shape_marker_get_transform_at_end(lastcurve); for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END if (shape->marker[i]) { @@ -835,7 +840,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) if (add_comments) { gchar * comment = g_strdup_printf("end '%s'", - SP_OBJECT(item)->defaultLabel()); + item->defaultLabel()); sp_print_comment(ctx, comment); g_free(comment); } @@ -846,7 +851,7 @@ sp_shape_print (SPItem *item, SPPrintContext *ctx) */ NRArenaItem * SPShape::sp_shape_show(SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/) { - SPObject *object = SP_OBJECT(item); + SPObject *object = item; SPShape *shape = SP_SHAPE(item); NRArenaItem *arenaitem = NRArenaShape::create(arena); @@ -1046,7 +1051,7 @@ sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value) return; } - SPObject *mrk = sp_css_uri_reference_resolve (SP_OBJECT_DOCUMENT (object), value); + SPObject *mrk = sp_css_uri_reference_resolve(object->document, value); if (mrk != shape->marker[key]) { if (shape->marker[key]) { SPItemView *v; @@ -1106,7 +1111,21 @@ void SPShape::setCurve(SPCurve *curve, unsigned int owner) this->curve = curve->copy(); } } - SP_OBJECT(this)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); +} + +/** + * Sets curve_before_lpe to refer to the curve. + */ +void +SPShape::setCurveBeforeLPE (SPCurve *curve) +{ + if (this->curve_before_lpe) { + this->curve_before_lpe = this->curve_before_lpe->unref(); + } + if (curve) { + this->curve_before_lpe = curve->ref(); + } } /** @@ -1121,6 +1140,24 @@ SPCurve * SPShape::getCurve() } /** + * Return duplicate of curve *before* LPE (if any exists) or NULL if there is no curve + */ +SPCurve * +SPShape::getCurveBeforeLPE() +{ + if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(this))) { + if (this->curve_before_lpe) { + return this->curve_before_lpe->copy(); + } + } else { + if (this->curve) { + return this->curve->copy(); + } + } + return NULL; +} + +/** * Same as sp_shape_set_curve but without updating the display */ void SPShape::setCurveInsync(SPCurve *curve, unsigned int owner) @@ -1159,7 +1196,7 @@ void SPShape::sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::Snap if (pathv.empty()) return; - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); if (snapprefs->getSnapObjectMidpoints()) { Geom::OptRect bbox = item->getBounds(item->i2d_affine()); diff --git a/src/sp-shape.h b/src/sp-shape.h index 78855c1c7..b91850d1f 100644 --- a/src/sp-shape.h +++ b/src/sp-shape.h @@ -16,11 +16,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/display-forward.h" #include "sp-lpe-item.h" #include "sp-marker-loc.h" #include <2geom/forward.h> +#include <stddef.h> #include <sigc++/connection.h> #define SP_TYPE_SHAPE (SPShape::getType ()) @@ -44,11 +44,16 @@ public: static GType getType (void); void setShape (); SPCurve * getCurve (); + SPCurve * getCurveBeforeLPE (); void setCurve (SPCurve *curve, unsigned int owner); void setCurveInsync (SPCurve *curve, unsigned int owner); + void setCurveBeforeLPE (SPCurve *curve); int hasMarkers () const; int numberOfMarkers (int type); +protected: + SPCurve *curve_before_lpe; + private: static void sp_shape_init (SPShape *shape); static void sp_shape_finalize (GObject *object); @@ -61,7 +66,7 @@ private: static void sp_shape_modified (SPObject *object, unsigned int flags); static Inkscape::XML::Node *sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); - static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); + static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static NRArenaItem *sp_shape_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_shape_hide (SPItem *item, unsigned int key); static void sp_shape_snappoints (SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); @@ -89,9 +94,9 @@ private: void sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value); -Geom::Matrix sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2); -Geom::Matrix sp_shape_marker_get_transform_at_start(Geom::Curve const & c); -Geom::Matrix sp_shape_marker_get_transform_at_end(Geom::Curve const & c); +Geom::Affine sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2); +Geom::Affine sp_shape_marker_get_transform_at_start(Geom::Curve const & c); +Geom::Affine sp_shape_marker_get_transform_at_end(Geom::Curve const & c); #endif // SEEN_SP_SHAPE_H diff --git a/src/sp-skeleton.cpp b/src/sp-skeleton.cpp index 42fc5289f..8910613f3 100644 --- a/src/sp-skeleton.cpp +++ b/src/sp-skeleton.cpp @@ -188,9 +188,9 @@ sp_skeleton_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML: if (flags & SP_OBJECT_WRITE_EXT) { if (repr) { // is this sane? - repr->mergeFrom(SP_OBJECT_REPR(object), "id"); + repr->mergeFrom(object->getRepr(), "id"); } else { - repr = SP_OBJECT_REPR(object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } } diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index cfe02947a..05c6bc9cd 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -300,7 +300,7 @@ sp_spiral_update_patheffect(SPLPEItem *lpeitem, bool write) sp_spiral_set_shape(shape); if (write) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); + Inkscape::XML::Node *repr = shape->getRepr(); if ( shape->curve != NULL ) { gchar *str = sp_svg_write_path(shape->curve->get_pathvector()); repr->setAttribute("d", str); @@ -422,11 +422,12 @@ sp_spiral_set_shape (SPShape *shape) if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) { g_warning ("The spiral shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as spiral will remove the bad LPE"); - if (SP_OBJECT_REPR(shape)->attribute("d")) { + if (shape->getRepr()->attribute("d")) { // unconditionally read the curve from d, if any, to preserve appearance - Geom::PathVector pv = sp_svg_read_pathv(SP_OBJECT_REPR(shape)->attribute("d")); + Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); SPCurve *cold = new SPCurve(pv); shape->setCurveInsync( cold, TRUE); + shape->setCurveBeforeLPE( cold ); cold->unref(); } return; @@ -435,7 +436,7 @@ sp_spiral_set_shape (SPShape *shape) Geom::Point darray[SAMPLE_SIZE + 1]; double t; - SP_OBJECT (spiral)->requestModified(SP_OBJECT_MODIFIED_FLAG); + spiral->requestModified(SP_OBJECT_MODIFIED_FLAG); SPCurve *c = new SPCurve (); @@ -470,6 +471,7 @@ sp_spiral_set_shape (SPShape *shape) /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ shape->setCurveInsync( c, TRUE); + shape->setCurveBeforeLPE( c ); if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { SPCurve *c_lpe = c->copy(); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); @@ -532,7 +534,7 @@ static void sp_spiral_snappoints(SPItem const *item, std::vector<Inkscape::SnapC } if (snapprefs->getSnapObjectMidpoints()) { - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); SPSpiral *spiral = SP_SPIRAL(item); p.push_back(Inkscape::SnapCandidatePoint(Geom::Point(spiral->cx, spiral->cy) * i2d, Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); // This point is the start-point of the spiral, which is also returned when _snap_to_itemnode has been set diff --git a/src/sp-star.cpp b/src/sp-star.cpp index 6b6914500..39efe2537 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -284,7 +284,7 @@ sp_star_update_patheffect(SPLPEItem *lpeitem, bool write) sp_star_set_shape(shape); if (write) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(shape); + Inkscape::XML::Node *repr = shape->getRepr(); if ( shape->curve != NULL ) { gchar *str = sp_svg_write_path(shape->curve->get_pathvector()); repr->setAttribute("d", str); @@ -411,7 +411,7 @@ sp_star_get_curvepoint (SPStar *star, SPStarPoint point, gint index, bool previ) guint32 seed = point_unique_int (o); // randomly rotate (by step 3 from the seed) and scale (by step 4) the vector - ret = ret * Geom::Matrix (Geom::Rotate (star->randomized * M_PI * rnd (seed, 3))); + ret = ret * Geom::Affine (Geom::Rotate (star->randomized * M_PI * rnd (seed, 3))); ret *= ( 1 + star->randomized * rnd (seed, 4)); // the randomized corner point @@ -435,11 +435,12 @@ sp_star_set_shape (SPShape *shape) // by disabling the entire stack (including the shape LPE) if (sp_lpe_item_has_broken_path_effect(SP_LPE_ITEM(shape))) { g_warning ("The star shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as star will remove the bad LPE"); - if (SP_OBJECT_REPR(shape)->attribute("d")) { + if (shape->getRepr()->attribute("d")) { // unconditionally read the curve from d, if any, to preserve appearance - Geom::PathVector pv = sp_svg_read_pathv(SP_OBJECT_REPR(shape)->attribute("d")); + Geom::PathVector pv = sp_svg_read_pathv(shape->getRepr()->attribute("d")); SPCurve *cold = new SPCurve(pv); shape->setCurveInsync( cold, TRUE); + shape->setCurveBeforeLPE(cold); cold->unref(); } return; @@ -510,6 +511,7 @@ sp_star_set_shape (SPShape *shape) /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ shape->setCurveInsync( c, TRUE); + shape->setCurveBeforeLPE( c ); if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(shape)) && sp_lpe_item_path_effects_enabled(SP_LPE_ITEM(shape))) { SPCurve *c_lpe = c->copy(); bool success = sp_lpe_item_perform_path_effect(SP_LPE_ITEM (shape), c_lpe); @@ -540,7 +542,7 @@ sp_star_position_set (SPStar *star, gint sides, Geom::Point center, gdouble r1, star->flatsided = isflat; star->rounded = rounded; star->randomized = randomized; - SP_OBJECT(star)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + star->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } static void sp_star_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs) @@ -560,7 +562,7 @@ static void sp_star_snappoints(SPItem const *item, std::vector<Inkscape::SnapCan } if (snapprefs->getSnapObjectMidpoints()) { - Geom::Matrix const i2d (item->i2d_affine ()); + Geom::Affine const i2d (item->i2d_affine ()); p.push_back(Inkscape::SnapCandidatePoint(SP_STAR(item)->center * i2d,Inkscape::SNAPSOURCE_OBJECT_MIDPOINT, Inkscape::SNAPTARGET_OBJECT_MIDPOINT)); } } diff --git a/src/sp-string.cpp b/src/sp-string.cpp index c116e8dd8..3512aa45a 100644 --- a/src/sp-string.cpp +++ b/src/sp-string.cpp @@ -146,7 +146,7 @@ sp_string_read_content(SPObject *object) whitespace = false; } } - if (whitespace && SP_OBJECT_REPR(object)->next() != NULL) { // can't use SPObject::getNext() when the SPObject tree is still being built + if (whitespace && object->getRepr()->next() != NULL) { // can't use SPObject::getNext() when the SPObject tree is still being built string->string += ' '; } } diff --git a/src/sp-style-elem.cpp b/src/sp-style-elem.cpp index 02ed80445..2e14ae5ff 100644 --- a/src/sp-style-elem.cpp +++ b/src/sp-style-elem.cpp @@ -366,7 +366,7 @@ sp_style_elem_read_content(SPObject *const object) // Below is a partial hack that fixes this for a single case: when the <style> is a child of the object // that uses a style from it. It just forces the parent of <style> to reread its style as soon as the stylesheet // is fully loaded. Naturally, this won't work if the user of the stylesheet is its grandparent or precedent. - SPObject *parent = SP_OBJECT_PARENT (object); + SPObject *parent = object->parent; if ( parent ) { sp_style_read_from_object(parent->style, parent); } diff --git a/src/sp-switch.h b/src/sp-switch.h index 91fdcae46..310655a23 100644 --- a/src/sp-switch.h +++ b/src/sp-switch.h @@ -14,6 +14,7 @@ #include "sp-item-group.h" +#include <stddef.h> #include <sigc++/connection.h> #define SP_TYPE_SWITCH (CSwitch::getType()) diff --git a/src/sp-symbol.cpp b/src/sp-symbol.cpp index 9031e87ed..1d4bdec0f 100644 --- a/src/sp-symbol.cpp +++ b/src/sp-symbol.cpp @@ -38,7 +38,7 @@ static Inkscape::XML::Node *sp_symbol_write (SPObject *object, Inkscape::XML::Do static NRArenaItem *sp_symbol_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags); static void sp_symbol_hide (SPItem *item, unsigned int key); -static void sp_symbol_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_symbol_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_symbol_print (SPItem *item, SPPrintContext *ctx); static SPGroupClass *parent_class; @@ -257,7 +257,7 @@ sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags) symbol = SP_SYMBOL (object); ictx = (SPItemCtx *) ctx; - if (SP_OBJECT_IS_CLONED (object)) { + if (object->cloned) { /* Cloned <symbol> is actually renderable */ /* fixme: We have to set up clip here too */ @@ -267,7 +267,7 @@ sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags) /* Calculate child to parent transformation */ /* Apply parent <use> translation (set up as vewport) */ - symbol->c2p = Geom::Matrix(Geom::Translate(rctx.vp.x0, rctx.vp.y0)); + symbol->c2p = Geom::Affine(Geom::Translate(rctx.vp.x0, rctx.vp.y0)); if (symbol->viewBox_set) { double x, y, width, height; @@ -330,7 +330,7 @@ sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags) } } /* Compose additional transformation from scale and position */ - Geom::Matrix q; + Geom::Affine q; q[0] = width / (symbol->viewBox.x1 - symbol->viewBox.x0); q[1] = 0.0; q[2] = 0.0; @@ -341,7 +341,7 @@ sp_symbol_update (SPObject *object, SPCtx *ctx, guint flags) symbol->c2p = q * symbol->c2p; } - rctx.i2doc = symbol->c2p * (Geom::Matrix)rctx.i2doc; + rctx.i2doc = symbol->c2p * (Geom::Affine)rctx.i2doc; /* If viewBox is set initialize child viewport */ /* Otherwise <use> has set it up already */ @@ -411,7 +411,7 @@ sp_symbol_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int fla symbol = SP_SYMBOL (item); - if (SP_OBJECT_IS_CLONED (symbol)) { + if (symbol->cloned) { /* Cloned <symbol> is actually renderable */ if (((SPItemClass *) (parent_class))->show) { ai = ((SPItemClass *) (parent_class))->show (item, arena, key, flags); @@ -435,7 +435,7 @@ sp_symbol_hide (SPItem *item, unsigned int key) symbol = SP_SYMBOL (item); - if (SP_OBJECT_IS_CLONED (symbol)) { + if (symbol->cloned) { /* Cloned <symbol> is actually renderable */ if (((SPItemClass *) (parent_class))->hide) ((SPItemClass *) (parent_class))->hide (item, key); @@ -443,15 +443,15 @@ sp_symbol_hide (SPItem *item, unsigned int key) } static void -sp_symbol_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags) +sp_symbol_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags) { SPSymbol const *symbol = SP_SYMBOL(item); - if (SP_OBJECT_IS_CLONED (symbol)) { + if (symbol->cloned) { /* Cloned <symbol> is actually renderable */ if (((SPItemClass *) (parent_class))->bbox) { - Geom::Matrix const a( symbol->c2p * transform ); + Geom::Affine const a( symbol->c2p * transform ); ((SPItemClass *) (parent_class))->bbox(item, bbox, a, flags); } } @@ -461,7 +461,7 @@ static void sp_symbol_print (SPItem *item, SPPrintContext *ctx) { SPSymbol *symbol = SP_SYMBOL(item); - if (SP_OBJECT_IS_CLONED (symbol)) { + if (symbol->cloned) { /* Cloned <symbol> is actually renderable */ sp_print_bind(ctx, &symbol->c2p, 1.0); diff --git a/src/sp-symbol.h b/src/sp-symbol.h index eb0b144c6..120591459 100644 --- a/src/sp-symbol.h +++ b/src/sp-symbol.h @@ -24,7 +24,7 @@ class SPSymbol; class SPSymbolClass; -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <libnr/nr-rect.h> #include "svg/svg-length.h" #include "enums.h" @@ -41,7 +41,7 @@ struct SPSymbol : public SPGroup { unsigned int aspect_clip : 1; /* Child to parent additional transform */ - Geom::Matrix c2p; + Geom::Affine c2p; }; struct SPSymbolClass { diff --git a/src/sp-text.cpp b/src/sp-text.cpp index f779903fe..3f30c2422 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -27,7 +27,7 @@ # include "config.h" #endif -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <libnrtype/FontFactory.h> #include <libnrtype/font-instance.h> #include <libnrtype/font-style-to-pos.h> @@ -71,12 +71,12 @@ static void sp_text_update (SPObject *object, SPCtx *ctx, guint flags); static void sp_text_modified (SPObject *object, guint flags); static Inkscape::XML::Node *sp_text_write (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static NRArenaItem *sp_text_show (SPItem *item, NRArena *arena, unsigned key, unsigned flags); static void sp_text_hide (SPItem *item, unsigned key); static char *sp_text_description (SPItem *item); static void sp_text_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); -static Geom::Matrix sp_text_set_transform(SPItem *item, Geom::Matrix const &xform); +static Geom::Affine sp_text_set_transform(SPItem *item, Geom::Affine const &xform); static void sp_text_print (SPItem *item, SPPrintContext *gpc); static SPItemClass *text_parent_class; @@ -226,18 +226,18 @@ static void sp_text_update(SPObject *object, SPCtx *ctx, guint flags) // Create temporary list of children GSList *l = NULL; for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - sp_object_ref (SP_OBJECT (child), object); + sp_object_ref(child, object); l = g_slist_prepend (l, child); } l = g_slist_reverse (l); while (l) { - SPObject *child = SP_OBJECT (l->data); + SPObject *child = reinterpret_cast<SPObject*>(l->data); // We just built this list, so cast is safe. l = g_slist_remove (l, child); if (cflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { /* fixme: Do we need transform? */ child->updateDisplay(ctx, cflags); } - sp_object_unref (SP_OBJECT (child), object); + sp_object_unref(child, object); } if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG | @@ -252,7 +252,7 @@ static void sp_text_update(SPObject *object, SPCtx *ctx, guint flags) text->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView* v = text->display; v != NULL; v = v->next) { text->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); // pass the bbox of the text object as paintbox (used for paintserver fills) text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); } @@ -280,7 +280,7 @@ static void sp_text_modified(SPObject *object, guint flags) text->invoke_bbox( &paintbox, Geom::identity(), TRUE); for (SPItemView* v = text->display; v != NULL; v = v->next) { text->_clearFlow(NR_ARENA_GROUP(v->arenaitem)); - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); text->layout.show(NR_ARENA_GROUP(v->arenaitem), &paintbox); } } @@ -288,17 +288,17 @@ static void sp_text_modified(SPObject *object, guint flags) // Create temporary list of children GSList *l = NULL; for (SPObject *child = object->firstChild() ; child ; child = child->getNext() ) { - sp_object_ref (SP_OBJECT (child), object); + sp_object_ref(child, object); l = g_slist_prepend (l, child); } l = g_slist_reverse (l); while (l) { - SPObject *child = SP_OBJECT (l->data); + SPObject *child = reinterpret_cast<SPObject*>(l->data); // We just built this list, so cast is safe. l = g_slist_remove (l, child); if (cflags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(cflags); } - sp_object_unref (SP_OBJECT (child), object); + sp_object_unref(child, object); } } @@ -336,7 +336,7 @@ static Inkscape::XML::Node *sp_text_write(SPObject *object, Inkscape::XML::Docum continue; } if (SP_IS_STRING(child)) { - SP_OBJECT_REPR(child)->setContent(SP_STRING(child)->string.c_str()); + child->getRepr()->setContent(SP_STRING(child)->string.c_str()); } else { child->updateRepr(flags); } @@ -349,9 +349,9 @@ static Inkscape::XML::Node *sp_text_write(SPObject *object, Inkscape::XML::Docum if (text->style->line_height.set && !text->style->line_height.inherit && !text->style->line_height.normal && text->style->line_height.unit == SP_CSS_UNIT_PERCENT) { Inkscape::SVGOStringStream os; os << (text->style->line_height.value * 100.0) << "%"; - SP_OBJECT_REPR(text)->setAttribute("sodipodi:linespacing", os.str().c_str()); + text->getRepr()->setAttribute("sodipodi:linespacing", os.str().c_str()); } else { - SP_OBJECT_REPR(text)->setAttribute("sodipodi:linespacing", NULL); + text->getRepr()->setAttribute("sodipodi:linespacing", NULL); } if (((SPObjectClass *) (text_parent_class))->write) { @@ -362,12 +362,12 @@ static Inkscape::XML::Node *sp_text_write(SPObject *object, Inkscape::XML::Docum } static void -sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) +sp_text_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const /*flags*/) { SP_TEXT(item)->layout.getBoundingBox(bbox, transform); // Add stroke width - SPStyle* style=SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if (!style->stroke.isNone()) { double const scale = transform.descrim(); if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord @@ -408,11 +408,10 @@ sp_text_hide(SPItem *item, unsigned key) ((SPItemClass *) text_parent_class)->hide (item, key); } -static char * -sp_text_description(SPItem *item) +static char * sp_text_description(SPItem *item) { - SPText *text = (SPText *) item; - SPStyle *style = SP_OBJECT_STYLE(text); + SPText *text = reinterpret_cast<SPText *>(item); + SPStyle *style = text->style; font_instance *tf = font_factory::Default()->FaceFromStyle(style); @@ -455,8 +454,8 @@ static void sp_text_snappoints(SPItem const *item, std::vector<Inkscape::SnapCan } } -static Geom::Matrix -sp_text_set_transform (SPItem *item, Geom::Matrix const &xform) +static Geom::Affine +sp_text_set_transform (SPItem *item, Geom::Affine const &xform) { SPText *text = SP_TEXT(item); @@ -478,7 +477,7 @@ sp_text_set_transform (SPItem *item, Geom::Matrix const &xform) return xform; } - Geom::Matrix ret(Geom::Matrix(xform).without_translation()); + Geom::Affine ret(Geom::Affine(xform).withoutTranslation()); ret[0] /= ex; ret[1] /= ex; ret[2] /= ex; @@ -514,9 +513,9 @@ sp_text_print (SPItem *item, SPPrintContext *ctx) item->getBboxDesktop (&bbox); dbox.x0 = 0.0; dbox.y0 = 0.0; - dbox.x1 = SP_OBJECT_DOCUMENT (item)->getWidth (); - dbox.y1 = SP_OBJECT_DOCUMENT (item)->getHeight (); - Geom::Matrix const ctm (item->i2d_affine()); + dbox.x1 = item->document->getWidth(); + dbox.y1 = item->document->getHeight(); + Geom::Affine const ctm (item->i2d_affine()); group->layout.print(ctx,&pbox,&dbox,&bbox,ctm); } @@ -622,7 +621,7 @@ void SPText::rebuildLayout() void SPText::_adjustFontsizeRecursive(SPItem *item, double ex, bool is_root) { - SPStyle *style = SP_OBJECT_STYLE (item); + SPStyle *style = item->style; if (style && !Geom::are_near(ex, 1.0)) { if (!style->font_size.set && is_root) { @@ -641,7 +640,7 @@ void SPText::_adjustFontsizeRecursive(SPItem *item, double ex, bool is_root) } } -void SPText::_adjustCoordsRecursive(SPItem *item, Geom::Matrix const &m, double ex, bool is_root) +void SPText::_adjustCoordsRecursive(SPItem *item, Geom::Affine const &m, double ex, bool is_root) { if (SP_IS_TSPAN(item)) SP_TSPAN(item)->attributes.transform(m, ex, ex, is_root); @@ -902,7 +901,7 @@ void TextTagAttributes::joinSingleAttribute(std::vector<SVGLength> *dest_vector, } } -void TextTagAttributes::transform(Geom::Matrix const &matrix, double scale_x, double scale_y, bool extend_zero_length) +void TextTagAttributes::transform(Geom::Affine const &matrix, double scale_x, double scale_y, bool extend_zero_length) { SVGLength zero_length; zero_length = 0.0; diff --git a/src/sp-text.h b/src/sp-text.h index e7c264b07..c98721ec9 100644 --- a/src/sp-text.h +++ b/src/sp-text.h @@ -14,6 +14,7 @@ */ #include <glib/gtypes.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include "sp-item.h" #include "sp-string.h" @@ -53,7 +54,7 @@ struct SPText : public SPItem { extend zero-length position vectors to length 1 in order to record the new position. This is necessary to convert from objects whose position is completely specified by transformations. */ - static void _adjustCoordsRecursive(SPItem *item, Geom::Matrix const &m, double ex, bool is_root = true); + static void _adjustCoordsRecursive(SPItem *item, Geom::Affine const &m, double ex, bool is_root = true); static void _adjustFontsizeRecursive(SPItem *item, double ex, bool is_root = true); /** discards the NRArena objects representing this text. */ diff --git a/src/sp-title.cpp b/src/sp-title.cpp index c820c70f0..d21c7b71e 100644 --- a/src/sp-title.cpp +++ b/src/sp-title.cpp @@ -66,11 +66,12 @@ static Inkscape::XML::Node * sp_title_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags) { if (!repr) { - repr = SP_OBJECT_REPR (object)->duplicate(doc); + repr = object->getRepr()->duplicate(doc); } - if (((SPObjectClass *) title_parent_class)->write) + if (((SPObjectClass *) title_parent_class)->write) { ((SPObjectClass *) title_parent_class)->write(object, doc, repr, flags); + } return repr; } diff --git a/src/sp-tref-reference.cpp b/src/sp-tref-reference.cpp index 181920669..e82f575e0 100644 --- a/src/sp-tref-reference.cpp +++ b/src/sp-tref-reference.cpp @@ -37,7 +37,7 @@ void SPTRefReference::updateObserver() delete subtreeObserved; } - subtreeObserved = new Inkscape::XML::Subtree(*SP_OBJECT_REPR(referred)); + subtreeObserved = new Inkscape::XML::Subtree(*referred->getRepr()); subtreeObserved->addObserver(*this); } } diff --git a/src/sp-tref-reference.h b/src/sp-tref-reference.h index c2264f83e..2e340f423 100644 --- a/src/sp-tref-reference.h +++ b/src/sp-tref-reference.h @@ -15,6 +15,7 @@ #include <forward.h> #include "sp-item.h" #include <uri-references.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include "util/share.h" diff --git a/src/sp-tref.cpp b/src/sp-tref.cpp index c206dac77..b301add7f 100644 --- a/src/sp-tref.cpp +++ b/src/sp-tref.cpp @@ -64,7 +64,7 @@ static void sp_tref_update(SPObject *object, SPCtx *ctx, guint flags); static void sp_tref_modified(SPObject *object, guint flags); static Inkscape::XML::Node *sp_tref_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); -static void sp_tref_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_tref_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static gchar *sp_tref_description(SPItem *item); static void sp_tref_href_changed(SPObject *old_ref, SPObject *ref, SPTRef *tref); @@ -122,7 +122,7 @@ sp_tref_init(SPTRef *tref) new (&tref->attributes) TextTagAttributes; tref->href = NULL; - tref->uriOriginalRef = new SPTRefReference(SP_OBJECT(tref)); + tref->uriOriginalRef = new SPTRefReference(tref); new (&tref->_delete_connection) sigc::connection(); new (&tref->_changed_connection) sigc::connection(); @@ -222,7 +222,7 @@ sp_tref_set(SPObject *object, unsigned int key, gchar const *value) } // No matter what happened, an update should be in order - SP_OBJECT(tref)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + tref->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } else { // default @@ -319,19 +319,23 @@ sp_tref_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML: * The code for this function is swiped from the tspan bbox code, since tref should work pretty much the same way */ static void -sp_tref_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) +sp_tref_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const /*flags*/) { // find out the ancestor text which holds our layout - SPObject *parent_text = SP_OBJECT(item); - for (; parent_text != NULL && !SP_IS_TEXT(parent_text); parent_text = SP_OBJECT_PARENT (parent_text)){}; - if (parent_text == NULL) return; + SPObject const *parent_text = item; + while ( parent_text && !SP_IS_TEXT(parent_text) ) { + parent_text = parent_text->parent; + } + if (parent_text == NULL) { + return; + } // get the bbox of our portion of the layout SP_TEXT(parent_text)->layout.getBoundingBox( bbox, transform, sp_text_get_length_upto(parent_text, item), sp_text_get_length_upto(item, NULL) - 1); // Add stroke width - SPStyle* style=SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if (!style->stroke.isNone()) { double const scale = transform.descrim(); if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord @@ -387,7 +391,7 @@ sp_tref_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPTRef *tref) tref->_delete_connection.disconnect(); if (tref->stringChild) { - SP_OBJECT(tref)->detach(tref->stringChild); + tref->detach(tref->stringChild); tref->stringChild = NULL; } @@ -398,7 +402,7 @@ sp_tref_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPTRef *tref) sp_tref_update_text(tref); // Restore the delete connection now that we're done messing with stuff - tref->_delete_connection = SP_OBJECT(refRoot)->connectDelete(sigc::bind(sigc::ptr_fun(&sp_tref_delete_self), tref)); + tref->_delete_connection = refRoot->connectDelete(sigc::bind(sigc::ptr_fun(&sp_tref_delete_self), tref)); } } @@ -411,7 +415,7 @@ sp_tref_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPTRef *tref) static void sp_tref_delete_self(SPObject */*deleted*/, SPTRef *self) { - SP_OBJECT(self)->deleteObject(); + self->deleteObject(); } /** @@ -422,7 +426,7 @@ SPObject * SPTRef::getObjectReferredTo(void) SPObject *referredObject = NULL; if (uriOriginalRef) { - referredObject = SP_OBJECT(uriOriginalRef->getObject()); + referredObject = uriOriginalRef->getObject(); } return referredObject; @@ -440,7 +444,7 @@ sp_tref_reference_allowed(SPTRef *tref, SPObject *possible_ref) if (tref && possible_ref) { if (tref != possible_ref) { bool ancestor = false; - for (SPObject *obj = tref; obj; obj = SP_OBJECT_PARENT(obj)) { + for (SPObject *obj = tref; obj; obj = obj->parent) { if (possible_ref == obj) { ancestor = true; break; @@ -469,15 +473,15 @@ sp_tref_fully_contained(SPObject *start_item, Glib::ustring::iterator &start, // If neither the beginning or the end is a tref then we return true (whether there // is a tref in the innards or not, because if there is one then it must be totally // contained) - if (!(SP_IS_STRING(start_item) && SP_IS_TREF(SP_OBJECT_PARENT(start_item))) - && !(SP_IS_STRING(end_item) && SP_IS_TREF(SP_OBJECT_PARENT(end_item)))) { + if (!(SP_IS_STRING(start_item) && SP_IS_TREF(start_item->parent)) + && !(SP_IS_STRING(end_item) && SP_IS_TREF(end_item->parent))) { fully_contained = true; } // Both the beginning and end are trefs; but in this case, the string iterators // must be at the right places - else if ((SP_IS_STRING(start_item) && SP_IS_TREF(SP_OBJECT_PARENT(start_item))) - && (SP_IS_STRING(end_item) && SP_IS_TREF(SP_OBJECT_PARENT(end_item)))) { + else if ((SP_IS_STRING(start_item) && SP_IS_TREF(start_item->parent)) + && (SP_IS_STRING(end_item) && SP_IS_TREF(end_item->parent))) { if (start == SP_STRING(start_item)->string.begin() && end == SP_STRING(start_item)->string.end()) { fully_contained = true; @@ -486,16 +490,16 @@ sp_tref_fully_contained(SPObject *start_item, Glib::ustring::iterator &start, // If the beginning is a string that is a child of a tref, the iterator has to be // at the beginning of the item - else if ((SP_IS_STRING(start_item) && SP_IS_TREF(SP_OBJECT_PARENT(start_item))) - && !(SP_IS_STRING(end_item) && SP_IS_TREF(SP_OBJECT_PARENT(end_item)))) { + else if ((SP_IS_STRING(start_item) && SP_IS_TREF(start_item->parent)) + && !(SP_IS_STRING(end_item) && SP_IS_TREF(end_item->parent))) { if (start == SP_STRING(start_item)->string.begin()) { fully_contained = true; } } // Same, but the for the end - else if (!(SP_IS_STRING(start_item) && SP_IS_TREF(SP_OBJECT_PARENT(start_item))) - && (SP_IS_STRING(end_item) && SP_IS_TREF(SP_OBJECT_PARENT(end_item)))) { + else if (!(SP_IS_STRING(start_item) && SP_IS_TREF(start_item->parent)) + && (SP_IS_STRING(end_item) && SP_IS_TREF(end_item->parent))) { if (end == SP_STRING(start_item)->string.end()) { fully_contained = true; } @@ -511,23 +515,23 @@ void sp_tref_update_text(SPTRef *tref) if (tref) { // Get the character data that will be used with this tref Glib::ustring charData = ""; - build_string_from_root(SP_OBJECT_REPR(tref->getObjectReferredTo()), &charData); + build_string_from_root(tref->getObjectReferredTo()->getRepr(), &charData); if (tref->stringChild) { - SP_OBJECT(tref)->detach(tref->stringChild); + tref->detach(tref->stringChild); tref->stringChild = NULL; } // Create the node and SPString to be the tref's child - Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(tref)->getReprDoc(); + Inkscape::XML::Document *xml_doc = tref->document->getReprDoc(); Inkscape::XML::Node *newStringRepr = xml_doc->createTextNode(charData.c_str()); tref->stringChild = SP_OBJECT(g_object_new(sp_repr_type_lookup(newStringRepr), NULL)); // Add this SPString as a child of the tref - SP_OBJECT(tref)->attach(tref->stringChild, tref->lastChild()); + tref->attach(tref->stringChild, tref->lastChild()); sp_object_unref(tref->stringChild, NULL); - (tref->stringChild)->invoke_build(SP_OBJECT(tref)->document, newStringRepr, TRUE); + (tref->stringChild)->invoke_build(tref->document, newStringRepr, TRUE); Inkscape::GC::release(newStringRepr); } @@ -580,10 +584,10 @@ sp_tref_convert_to_tspan(SPObject *obj) SPTRef *tref = SP_TREF(obj); if (tref && tref->stringChild) { - Inkscape::XML::Node *tref_repr = SP_OBJECT_REPR(tref); + Inkscape::XML::Node *tref_repr = tref->getRepr(); Inkscape::XML::Node *tref_parent = sp_repr_parent(tref_repr); - SPDocument *document = SP_OBJECT(tref)->document; + SPDocument *document = tref->document; Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *new_tspan_repr = xml_doc->createElement("svg:tspan"); @@ -595,35 +599,35 @@ sp_tref_convert_to_tspan(SPObject *obj) new_tspan = document->getObjectByRepr(new_tspan_repr); // Create a new string child for the tspan - Inkscape::XML::Node *new_string_repr = SP_OBJECT_REPR(tref->stringChild)->duplicate(xml_doc); + Inkscape::XML::Node *new_string_repr = tref->stringChild->getRepr()->duplicate(xml_doc); new_tspan_repr->addChild(new_string_repr, NULL); //SPObject * new_string_child = document->getObjectByRepr(new_string_repr); // Merge style from the tref - SPStyle *new_tspan_sty = SP_OBJECT_STYLE(new_tspan); - SPStyle const *tref_sty = SP_OBJECT_STYLE(tref); + SPStyle *new_tspan_sty = new_tspan->style; + SPStyle const *tref_sty = tref->style; sp_style_merge_from_dying_parent(new_tspan_sty, tref_sty); sp_style_merge_from_parent(new_tspan_sty, new_tspan->parent->style); - SP_OBJECT(new_tspan)->updateRepr(); + new_tspan->updateRepr(); // Hold onto our SPObject and repr for now. - sp_object_ref(SP_OBJECT(tref), NULL); + sp_object_ref(tref, NULL); Inkscape::GC::anchor(tref_repr); // Remove ourselves, not propagating delete events to avoid a // chain-reaction with other elements that might reference us. - SP_OBJECT(tref)->deleteObject(false); + tref->deleteObject(false); // Give the copy our old id and let go of our old repr. new_tspan_repr->setAttribute("id", tref_repr->attribute("id")); Inkscape::GC::release(tref_repr); // Establish the succession and let go of our object. - SP_OBJECT(tref)->setSuccessor(new_tspan); - sp_object_unref(SP_OBJECT(tref), NULL); + tref->setSuccessor(new_tspan); + sp_object_unref(tref, NULL); } } //////////////////// @@ -632,19 +636,19 @@ sp_tref_convert_to_tspan(SPObject *obj) else { GSList *l = NULL; for (SPObject *child = obj->firstChild() ; child != NULL ; child = child->getNext() ) { - sp_object_ref (SP_OBJECT (child), obj); + sp_object_ref(child, obj); l = g_slist_prepend (l, child); } l = g_slist_reverse (l); while (l) { - SPObject *child = SP_OBJECT (l->data); + SPObject *child = reinterpret_cast<SPObject *>(l->data); // We just built this list, so cast is safe. l = g_slist_remove (l, child); // Note that there may be more than one conversion happening here, so if it's not a // tref being passed into this function, the returned value can't be specifically known new_tspan = sp_tref_convert_to_tspan(child); - sp_object_unref (SP_OBJECT (child), obj); + sp_object_unref(child, obj); } } diff --git a/src/sp-tspan.cpp b/src/sp-tspan.cpp index 653f3e911..199d82e1b 100644 --- a/src/sp-tspan.cpp +++ b/src/sp-tspan.cpp @@ -56,7 +56,7 @@ static void sp_tspan_release(SPObject *object); static void sp_tspan_set(SPObject *object, unsigned key, gchar const *value); static void sp_tspan_update(SPObject *object, SPCtx *ctx, guint flags); static void sp_tspan_modified(SPObject *object, unsigned flags); -static void sp_tspan_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_tspan_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static Inkscape::XML::Node *sp_tspan_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags); static char *sp_tspan_description (SPItem *item); @@ -203,18 +203,22 @@ static void sp_tspan_modified(SPObject *object, unsigned flags) } } -static void sp_tspan_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const /*flags*/) +static void sp_tspan_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const /*flags*/) { // find out the ancestor text which holds our layout - SPObject *parent_text = SP_OBJECT(item); - for (; parent_text != NULL && !SP_IS_TEXT(parent_text); parent_text = SP_OBJECT_PARENT (parent_text)){}; - if (parent_text == NULL) return; + SPObject const *parent_text = item; + while (parent_text && !SP_IS_TEXT(parent_text)) { + parent_text = parent_text->parent; + } + if (parent_text == NULL) { + return; + } // get the bbox of our portion of the layout SP_TEXT(parent_text)->layout.getBoundingBox(bbox, transform, sp_text_get_length_upto(parent_text, item), sp_text_get_length_upto(item, NULL) - 1); // Add stroke width - SPStyle* style=SP_OBJECT_STYLE (item); + SPStyle* style = item->style; if (!style->stroke.isNone()) { double const scale = transform.descrim(); if ( fabs(style->stroke_width.computed * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord @@ -267,7 +271,7 @@ sp_tspan_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML } else if ( SP_IS_TEXTPATH(child) ) { //c_repr = child->updateRepr(xml_doc, NULL, flags); // shouldn't happen } else if ( SP_IS_STRING(child) ) { - SP_OBJECT_REPR(child)->setContent(SP_STRING(child)->string.c_str()); + child->getRepr()->setContent(SP_STRING(child)->string.c_str()); } } } @@ -364,7 +368,7 @@ sp_textpath_init(SPTextPath *textpath) textpath->originalPath = NULL; textpath->isUpdating=false; // set up the uri reference - textpath->sourcePath = new SPUsePath(SP_OBJECT(textpath)); + textpath->sourcePath = new SPUsePath(textpath); textpath->sourcePath->user_unlink = sp_textpath_to_text; } @@ -522,7 +526,7 @@ sp_textpath_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape:: if (textpath->startOffset.unit == SVGLength::PERCENT) { Inkscape::SVGOStringStream os; os << (textpath->startOffset.computed * 100.0) << "%"; - SP_OBJECT_REPR(textpath)->setAttribute("startOffset", os.str().c_str()); + textpath->getRepr()->setAttribute("startOffset", os.str().c_str()); } else { /* FIXME: This logic looks rather undesirable if e.g. startOffset is to be in ems. */ @@ -559,7 +563,7 @@ sp_textpath_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape:: } else if ( SP_IS_TEXTPATH(child) ) { //c_repr = child->updateRepr(xml_doc, NULL, flags); // shouldn't happen } else if ( SP_IS_STRING(child) ) { - SP_OBJECT_REPR(child)->setContent(SP_STRING(child)->string.c_str()); + child->getRepr()->setContent(SP_STRING(child)->string.c_str()); } } } @@ -586,7 +590,7 @@ sp_textpath_get_path_item(SPTextPath *tp) void sp_textpath_to_text(SPObject *tp) { - SPObject *text = SP_OBJECT_PARENT(tp); + SPObject *text = tp->parent; Geom::OptRect bbox; SP_ITEM(text)->invoke_bbox(bbox, SP_ITEM(text)->i2doc_affine(), TRUE); @@ -595,17 +599,17 @@ sp_textpath_to_text(SPObject *tp) // make a list of textpath children GSList *tp_reprs = NULL; - for (SPObject *o = SP_OBJECT(tp)->firstChild() ; o != NULL; o = o->next) { - tp_reprs = g_slist_prepend(tp_reprs, SP_OBJECT_REPR(o)); + for (SPObject *o = tp->firstChild() ; o != NULL; o = o->next) { + tp_reprs = g_slist_prepend(tp_reprs, o->getRepr()); } for ( GSList *i = tp_reprs ; i ; i = i->next ) { // make a copy of each textpath child - Inkscape::XML::Node *copy = ((Inkscape::XML::Node *) i->data)->duplicate(SP_OBJECT_REPR(text)->document()); + Inkscape::XML::Node *copy = ((Inkscape::XML::Node *) i->data)->duplicate(text->getRepr()->document()); // remove the old repr from under textpath - SP_OBJECT_REPR(tp)->removeChild((Inkscape::XML::Node *) i->data); + tp->getRepr()->removeChild((Inkscape::XML::Node *) i->data); // put its copy under text - SP_OBJECT_REPR(text)->addChild(copy, NULL); // fixme: copy id + text->getRepr()->addChild(copy, NULL); // fixme: copy id } //remove textpath @@ -615,8 +619,8 @@ sp_textpath_to_text(SPObject *tp) // set x/y on text /* fixme: Yuck, is this really the right test? */ if (xy[Geom::X] != 1e18 && xy[Geom::Y] != 1e18) { - sp_repr_set_svg_double(SP_OBJECT_REPR(text), "x", xy[Geom::X]); - sp_repr_set_svg_double(SP_OBJECT_REPR(text), "y", xy[Geom::Y]); + sp_repr_set_svg_double(text->getRepr(), "x", xy[Geom::X]); + sp_repr_set_svg_double(text->getRepr(), "y", xy[Geom::Y]); } } diff --git a/src/sp-use-reference.cpp b/src/sp-use-reference.cpp index a05dc0e93..ec03ffce6 100644 --- a/src/sp-use-reference.cpp +++ b/src/sp-use-reference.cpp @@ -27,8 +27,8 @@ bool SPUseReference::_acceptObject(SPObject * const obj) const { if (SP_IS_ITEM(obj)) { SPObject * const owner = getOwner(); - /* Refuse references to us or to an ancestor. */ - for ( SPObject *iter = owner ; iter ; iter = SP_OBJECT_PARENT(iter) ) { + // Refuse references to us or to an ancestor. + for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { if ( iter == obj ) { return false; } @@ -41,7 +41,7 @@ bool SPUseReference::_acceptObject(SPObject * const obj) const static void sp_usepath_href_changed(SPObject *old_ref, SPObject *ref, SPUsePath *offset); -static void sp_usepath_move_compensate(Geom::Matrix const *mp, SPItem *original, SPUsePath *self); +static void sp_usepath_move_compensate(Geom::Affine const *mp, SPItem *original, SPUsePath *self); static void sp_usepath_delete_self(SPObject *deleted, SPUsePath *offset); static void sp_usepath_source_modified(SPObject *iSource, guint flags, SPUsePath *offset); @@ -107,7 +107,7 @@ SPUsePath::start_listening(SPObject* to) return; } sourceObject = to; - sourceRepr = SP_OBJECT_REPR(to); + sourceRepr = to->getRepr(); _delete_connection = to->connectDelete(sigc::bind(sigc::ptr_fun(&sp_usepath_delete_self), this)); _transformed_connection = SP_ITEM(to)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_usepath_move_compensate), this)); _modified_connection = to->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_usepath_source_modified), this)); @@ -135,11 +135,11 @@ sp_usepath_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPUsePath *off offset->start_listening(refobj); } offset->sourceDirty=true; - SP_OBJECT(offset->owner)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + offset->owner->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } static void -sp_usepath_move_compensate(Geom::Matrix const *mp, SPItem *original, SPUsePath *self) +sp_usepath_move_compensate(Geom::Affine const *mp, SPItem *original, SPUsePath *self) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint mode = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_PARALLEL); @@ -150,15 +150,15 @@ sp_usepath_move_compensate(Geom::Matrix const *mp, SPItem *original, SPUsePath * // TODO kill naughty naughty #if 0 #if 0 - Geom::Matrix m(*mp); + Geom::Affine m(*mp); if (!(m.is_translation())) { return; } - Geom::Matrix const t(item->transform); - Geom::Matrix clone_move = t.inverse() * m * t; + Geom::Affine const t(item->transform); + Geom::Affine clone_move = t.inverse() * m * t; // Calculate the compensation matrix and the advertized movement matrix. - Geom::Matrix advertized_move; + Geom::Affine advertized_move; if (mode == SP_CLONE_COMPENSATION_PARALLEL) { //clone_move = clone_move.inverse(); advertized_move.set_identity(); @@ -171,14 +171,14 @@ sp_usepath_move_compensate(Geom::Matrix const *mp, SPItem *original, SPUsePath * // Commit the compensation. item->transform *= clone_move; - sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform, &advertized_move); + sp_item_write_transform(item, item->getRepr(), item->transform, &advertized_move); #else (void)mp; (void)original; #endif self->sourceDirty = true; - SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } static void diff --git a/src/sp-use-reference.h b/src/sp-use-reference.h index 73d46c8aa..25a67b85b 100644 --- a/src/sp-use-reference.h +++ b/src/sp-use-reference.h @@ -12,6 +12,7 @@ #include <forward.h> #include "sp-item.h" #include <uri-references.h> +#include <stddef.h> #include <sigc++/sigc++.h> class Path; diff --git a/src/sp-use.cpp b/src/sp-use.cpp index 33a05cc7b..a05b28a5f 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -49,7 +49,7 @@ static Inkscape::XML::Node *sp_use_write(SPObject *object, Inkscape::XML::Docume static void sp_use_update(SPObject *object, SPCtx *ctx, guint flags); static void sp_use_modified(SPObject *object, guint flags); -static void sp_use_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags); +static void sp_use_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags); static void sp_use_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs); static void sp_use_print(SPItem *item, SPPrintContext *ctx); static gchar *sp_use_description(SPItem *item); @@ -62,7 +62,7 @@ static void sp_use_delete_self(SPObject *deleted, SPUse *self); static SPItemClass *parent_class; -//void m_print(gchar *say, Geom::Matrix m) +//void m_print(gchar *say, Geom::Affine m) //{ g_print("%s %g %g %g %g %g %g\n", say, m[0], m[1], m[2], m[3], m[4], m[5]); } GType @@ -127,7 +127,7 @@ sp_use_init(SPUse *use) new (&use->_transformed_connection) sigc::connection(); - use->ref = new SPUseReference(SP_OBJECT(use)); + use->ref = new SPUseReference(use); use->_changed_connection = use->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_use_href_changed), use)); } @@ -135,15 +135,16 @@ sp_use_init(SPUse *use) static void sp_use_finalize(GObject *obj) { - SPUse *use = (SPUse *) obj; + SPUse *use = reinterpret_cast<SPUse *>(obj); if (use->child) { - SP_OBJECT(obj)->detach(use->child); + use->detach(use->child); use->child = NULL; } use->ref->detach(); delete use->ref; + use->ref = 0; use->_delete_connection.~connection(); use->_changed_connection.~connection(); @@ -276,13 +277,13 @@ sp_use_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML:: } static void -sp_use_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags) +sp_use_bbox(SPItem const *item, NRRect *bbox, Geom::Affine const &transform, unsigned const flags) { SPUse const *use = SP_USE(item); if (use->child && SP_IS_ITEM(use->child)) { SPItem *child = SP_ITEM(use->child); - Geom::Matrix const ct( child->transform + Geom::Affine const ct( child->transform * Geom::Translate(use->x.computed, use->y.computed) * transform ); @@ -304,7 +305,7 @@ sp_use_print(SPItem *item, SPPrintContext *ctx) SPUse *use = SP_USE(item); if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { - Geom::Matrix tp(Geom::Translate(use->x.computed, use->y.computed)); + Geom::Affine tp(Geom::Translate(use->x.computed, use->y.computed)); sp_print_bind(ctx, tp, 1.0); translated = true; } @@ -352,7 +353,7 @@ sp_use_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags) NRArenaItem *ai = NRArenaGroup::create(arena); nr_arena_group_set_transparent(NR_ARENA_GROUP(ai), FALSE); - nr_arena_group_set_style(NR_ARENA_GROUP(ai), SP_OBJECT_STYLE(item)); + nr_arena_group_set_style(NR_ARENA_GROUP(ai), item->style); if (use->child) { NRArenaItem *ac = SP_ITEM(use->child)->invoke_show(arena, key, flags); @@ -361,7 +362,7 @@ sp_use_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags) } Geom::Translate t(use->x.computed, use->y.computed); - nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), Geom::Matrix(t)); + nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), Geom::Affine(t)); } return ai; @@ -405,7 +406,7 @@ sp_use_root(SPUse *use) * Returns the effective transform that goes from the ultimate original to given SPUse, both ends * included. */ -Geom::Matrix +Geom::Affine sp_use_get_root_transform(SPUse *use) { //track the ultimate source of a chain of uses @@ -420,7 +421,7 @@ sp_use_get_root_transform(SPUse *use) //calculate the accummulated transform, starting from the original - Geom::Matrix t(Geom::identity()); + Geom::Affine t(Geom::identity()); for (GSList *i = chain; i != NULL; i = i->next) { SPItem *i_tem = SP_ITEM(i->data); @@ -445,10 +446,10 @@ sp_use_get_root_transform(SPUse *use) * Returns the transform that leads to the use from its immediate original. * Does not inlcude the original's transform if any. */ -Geom::Matrix +Geom::Affine sp_use_get_parent_transform(SPUse *use) { - Geom::Matrix t(Geom::identity()); + Geom::Affine t(Geom::identity()); if ((use->x._set && use->x.computed != 0) || (use->y._set && use->y.computed != 0)) { t *= Geom::Translate(use->x._set ? use->x.computed : 0, use->y._set ? use->y.computed : 0); @@ -464,16 +465,16 @@ sp_use_get_parent_transform(SPUse *use) * clone's transform. */ static void -sp_use_move_compensate(Geom::Matrix const *mp, SPItem */*original*/, SPUse *self) +sp_use_move_compensate(Geom::Affine const *mp, SPItem */*original*/, SPUse *self) { // the clone is orphaned; or this is not a real use, but a clone of another use; // we skip it, otherwise duplicate compensation will occur - if (SP_OBJECT_IS_CLONED(self)) { + if (self->cloned) { return; } // never compensate uses which are used in flowtext - if (SP_OBJECT_PARENT(self) && SP_IS_FLOWREGION(SP_OBJECT_PARENT(self))) { + if (self->parent && SP_IS_FLOWREGION(self->parent)) { return; } @@ -483,20 +484,20 @@ sp_use_move_compensate(Geom::Matrix const *mp, SPItem */*original*/, SPUse *self if (mode == SP_CLONE_COMPENSATION_NONE) return; - Geom::Matrix m(*mp); + Geom::Affine m(*mp); // this is not a simple move, do not try to compensate if (!(m.isTranslation())) return; // restore item->transform field from the repr, in case it was changed by seltrans - SP_OBJECT (self)->readAttr ("transform"); + self->readAttr ("transform"); - Geom::Matrix t = sp_use_get_parent_transform(self); - Geom::Matrix clone_move = t.inverse() * m * t; + Geom::Affine t = sp_use_get_parent_transform(self); + Geom::Affine clone_move = t.inverse() * m * t; // calculate the compensation matrix and the advertized movement matrix - Geom::Matrix advertized_move; + Geom::Affine advertized_move; if (mode == SP_CLONE_COMPENSATION_PARALLEL) { clone_move = clone_move.inverse() * m; advertized_move = m; @@ -508,10 +509,9 @@ sp_use_move_compensate(Geom::Matrix const *mp, SPItem */*original*/, SPUse *self } // commit the compensation - SPItem *item = SP_ITEM(self); - item->transform *= clone_move; - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform, &advertized_move); - SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + self->transform *= clone_move; + self->doWriteTransform(self->getRepr(), self->transform, &advertized_move); + self->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } static void @@ -523,21 +523,21 @@ sp_use_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPUse *use) use->_transformed_connection.disconnect(); if (use->child) { - SP_OBJECT(use)->detach(use->child); + use->detach(use->child); use->child = NULL; } if (use->href) { SPItem *refobj = use->ref->getObject(); if (refobj) { - Inkscape::XML::Node *childrepr = SP_OBJECT_REPR(refobj); + Inkscape::XML::Node *childrepr = refobj->getRepr(); GType type = sp_repr_type_lookup(childrepr); g_return_if_fail(type > G_TYPE_NONE); if (g_type_is_a(type, SP_TYPE_ITEM)) { use->child = (SPObject*) g_object_new(type, 0); - SP_OBJECT(use)->attach(use->child, use->lastChild()); - sp_object_unref(use->child, SP_OBJECT(use)); - (use->child)->invoke_build(SP_OBJECT(use)->document, childrepr, TRUE); + use->attach(use->child, use->lastChild()); + sp_object_unref(use->child, use); + (use->child)->invoke_build(use->document, childrepr, TRUE); for (SPItemView *v = item->display; v != NULL; v = v->next) { NRArenaItem *ai; @@ -548,7 +548,7 @@ sp_use_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPUse *use) } } - use->_delete_connection = SP_OBJECT(refobj)->connectDelete(sigc::bind(sigc::ptr_fun(&sp_use_delete_self), use)); + use->_delete_connection = refobj->connectDelete(sigc::bind(sigc::ptr_fun(&sp_use_delete_self), use)); use->_transformed_connection = SP_ITEM(refobj)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_use_move_compensate), use)); } } @@ -558,8 +558,8 @@ static void sp_use_delete_self(SPObject */*deleted*/, SPUse *self) { // always delete uses which are used in flowtext - if (SP_OBJECT_PARENT(self) && SP_IS_FLOWREGION(SP_OBJECT_PARENT(self))) { - SP_OBJECT(self)->deleteObject(); + if (self->parent && SP_IS_FLOWREGION(self->parent)) { + self->deleteObject(); return; } @@ -570,7 +570,7 @@ sp_use_delete_self(SPObject */*deleted*/, SPUse *self) if (mode == SP_CLONE_ORPHANS_UNLINK) { sp_use_unlink(self); } else if (mode == SP_CLONE_ORPHANS_DELETE) { - SP_OBJECT(self)->deleteObject(); + self->deleteObject(); } } @@ -585,12 +585,14 @@ sp_use_update(SPObject *object, SPCtx *ctx, unsigned flags) if (((SPObjectClass *) (parent_class))->update) ((SPObjectClass *) (parent_class))->update(object, ctx, flags); - if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } flags &= SP_OBJECT_MODIFIED_CASCADE; if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { for (SPItemView *v = SP_ITEM(object)->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); } } @@ -631,7 +633,7 @@ sp_use_update(SPObject *object, SPCtx *ctx, unsigned flags) /* As last step set additional transform of arena group */ for (SPItemView *v = item->display; v != NULL; v = v->next) { - Geom::Matrix t(Geom::Translate(use->x.computed, use->y.computed)); + Geom::Affine t(Geom::Translate(use->x.computed, use->y.computed)); nr_arena_group_set_child_transform(NR_ARENA_GROUP(v->arenaitem), t); } } @@ -648,7 +650,7 @@ sp_use_modified(SPObject *object, guint flags) if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) { for (SPItemView *v = SP_ITEM(object)->display; v != NULL; v = v->next) { - nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), SP_OBJECT_STYLE(object)); + nr_arena_group_set_style(NR_ARENA_GROUP(v->arenaitem), object->style); } } @@ -668,13 +670,13 @@ SPItem *sp_use_unlink(SPUse *use) return NULL; } - Inkscape::XML::Node *repr = SP_OBJECT_REPR(use); + Inkscape::XML::Node *repr = use->getRepr(); if (!repr) { return NULL; } Inkscape::XML::Node *parent = sp_repr_parent(repr); - SPDocument *document = SP_OBJECT(use)->document; + SPDocument *document = use->document; Inkscape::XML::Document *xml_doc = document->getReprDoc(); // Track the ultimate source of a chain of uses. @@ -684,17 +686,17 @@ SPItem *sp_use_unlink(SPUse *use) } // Calculate the accumulated transform, starting from the original. - Geom::Matrix t = sp_use_get_root_transform(use); + Geom::Affine t = sp_use_get_root_transform(use); Inkscape::XML::Node *copy = NULL; if (SP_IS_SYMBOL(orig)) { // make a group, copy children copy = xml_doc->createElement("svg:g"); - for (Inkscape::XML::Node *child = SP_OBJECT_REPR(orig)->firstChild() ; child != NULL; child = child->next()) { + for (Inkscape::XML::Node *child = orig->getRepr()->firstChild() ; child != NULL; child = child->next()) { Inkscape::XML::Node *newchild = child->duplicate(xml_doc); copy->appendChild(newchild); } } else { // just copy - copy = SP_OBJECT_REPR(orig)->duplicate(xml_doc); + copy = orig->getRepr()->duplicate(xml_doc); } // Add the duplicate repr just after the existing one. @@ -704,20 +706,20 @@ SPItem *sp_use_unlink(SPUse *use) SPObject *unlinked = document->getObjectByRepr(copy); // Merge style from the use. - SPStyle *unli_sty = SP_OBJECT_STYLE(unlinked); - SPStyle const *use_sty = SP_OBJECT_STYLE(use); + SPStyle *unli_sty = unlinked->style; + SPStyle const *use_sty = use->style; sp_style_merge_from_dying_parent(unli_sty, use_sty); sp_style_merge_from_parent(unli_sty, unlinked->parent->style); - SP_OBJECT(unlinked)->updateRepr(); + unlinked->updateRepr(); // Hold onto our SPObject and repr for now. - sp_object_ref(SP_OBJECT(use), NULL); + sp_object_ref(use, NULL); Inkscape::GC::anchor(repr); // Remove ourselves, not propagating delete events to avoid a // chain-reaction with other elements that might reference us. - SP_OBJECT(use)->deleteObject(false); + use->deleteObject(false); // Give the copy our old id and let go of our old repr. copy->setAttribute("id", repr->attribute("id")); @@ -731,15 +733,15 @@ SPItem *sp_use_unlink(SPUse *use) copy->setAttribute("inkscape:tile-cy", NULL); // Establish the succession and let go of our object. - SP_OBJECT(use)->setSuccessor(unlinked); - sp_object_unref(SP_OBJECT(use), NULL); + use->setSuccessor(unlinked); + sp_object_unref(use, NULL); SPItem *item = SP_ITEM(unlinked); // Set the accummulated transform. { - Geom::Matrix nomove(Geom::identity()); + Geom::Affine nomove(Geom::identity()); // Advertise ourselves as not moving. - item->doWriteTransform(SP_OBJECT_REPR(item), t, &nomove); + item->doWriteTransform(item->getRepr(), t, &nomove); } return item; } diff --git a/src/sp-use.h b/src/sp-use.h index c5c07158f..399f30a4c 100644 --- a/src/sp-use.h +++ b/src/sp-use.h @@ -13,6 +13,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <stddef.h> #include <sigc++/sigc++.h> #include "svg/svg-length.h" #include "sp-item.h" @@ -59,8 +60,8 @@ GType sp_use_get_type (void); SPItem *sp_use_unlink (SPUse *use); SPItem *sp_use_get_original (SPUse *use); -Geom::Matrix sp_use_get_parent_transform (SPUse *use); -Geom::Matrix sp_use_get_root_transform(SPUse *use); +Geom::Affine sp_use_get_parent_transform (SPUse *use); +Geom::Affine sp_use_get_root_transform(SPUse *use); SPItem *sp_use_root(SPUse *use); #endif diff --git a/src/spiral-context.h b/src/spiral-context.h index d80c9740e..29a5f41b2 100644 --- a/src/spiral-context.h +++ b/src/spiral-context.h @@ -16,6 +16,7 @@ */ #include <gtk/gtktypeutils.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include "event-context.h" #include "libnr/nr-point.h" diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 4ddb5b12c..e09639745 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -140,8 +140,8 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb if (bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice) { // check in the tree to find which element of the selection list is topmost (for 2-operand commands only) - Inkscape::XML::Node *a = SP_OBJECT_REPR(il->data); - Inkscape::XML::Node *b = SP_OBJECT_REPR(il->next->data); + Inkscape::XML::Node *a = reinterpret_cast<SPObject *>(il->data)->getRepr(); + Inkscape::XML::Node *b = reinterpret_cast<SPObject *>(il->next->data)->getRepr(); if (a == NULL || b == NULL) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut.")); @@ -205,7 +205,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb curOrig = 0; for (GSList *l = il; l != NULL; l = l->next) { - SPCSSAttr *css = sp_repr_css_attr(SP_OBJECT_REPR(il->data), "style"); + SPCSSAttr *css = sp_repr_css_attr(reinterpret_cast<SPObject *>(il->data)->getRepr(), "style"); gchar const *val = sp_repr_css_property(css, "fill-rule", NULL); if (val && strcmp(val, "nonzero") == 0) { origWind[curOrig]= fill_nonZero; @@ -451,13 +451,13 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb // adjust style properties that depend on a possible transform in the source object in order // to get a correct style attribute for the new path SPItem* item_source = SP_ITEM(source); - Geom::Matrix i2doc(item_source->i2doc_affine()); + Geom::Affine i2doc(item_source->i2doc_affine()); item_source->adjust_stroke(i2doc.descrim()); item_source->adjust_pattern(i2doc); item_source->adjust_gradient(i2doc); item_source->adjust_livepatheffect(i2doc); - Inkscape::XML::Node *repr_source = SP_OBJECT_REPR(source); + Inkscape::XML::Node *repr_source = source->getRepr(); // remember important aspects of the source path, to be restored gint pos = repr_source->position(); @@ -472,7 +472,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb selection->clear(); for (GSList *l = il; l != NULL; l = l->next) { // if this is the bottommost object, - if (!strcmp(SP_OBJECT_REPR(l->data)->attribute("id"), id)) { + if (!strcmp(reinterpret_cast<SPObject *>(l->data)->getRepr()->attribute("id"), id)) { // delete it so that its clones don't get alerted; this object will be restored shortly, with the same id SP_OBJECT(l->data)->deleteObject(false); } else { @@ -484,7 +484,7 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb // premultiply by the inverse of parent's repr SPItem *parent_item = SP_ITEM(sp_desktop_document(desktop)->getObjectByRepr(parent)); - Geom::Matrix local (parent_item->i2doc_affine()); + Geom::Affine local (parent_item->i2doc_affine()); gchar *transform = sp_svg_transform_write(local.inverse()); // now that we have the result, add it on the canvas @@ -600,14 +600,14 @@ sp_selected_path_boolop(SPDesktop *desktop, bool_op bop, const unsigned int verb } static -void sp_selected_path_outline_add_marker( SPObject *marker_object, Geom::Matrix marker_transform, - Geom::Scale stroke_scale, Geom::Matrix transform, +void sp_selected_path_outline_add_marker( SPObject *marker_object, Geom::Affine marker_transform, + Geom::Scale stroke_scale, Geom::Affine transform, Inkscape::XML::Node *g_repr, Inkscape::XML::Document *xml_doc, SPDocument * doc ) { SPMarker* marker = SP_MARKER (marker_object); - SPItem* marker_item = sp_item_first_item_child (SP_OBJECT (marker_object)); + SPItem* marker_item = sp_item_first_item_child(marker_object); - Geom::Matrix tr(marker_transform); + Geom::Affine tr(marker_transform); if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = stroke_scale * tr; @@ -616,8 +616,8 @@ void sp_selected_path_outline_add_marker( SPObject *marker_object, Geom::Matrix // total marker transform tr = marker_item->transform * marker->c2p * tr * transform; - if (SP_OBJECT_REPR(marker_item)) { - Inkscape::XML::Node *m_repr = SP_OBJECT_REPR(marker_item)->duplicate(xml_doc); + if (marker_item->getRepr()) { + Inkscape::XML::Node *m_repr = marker_item->getRepr()->duplicate(xml_doc); g_repr->appendChild(m_repr); SPItem *marker_item = (SPItem *) doc->getObjectByRepr(m_repr); marker_item->doWriteTransform(m_repr, tr); @@ -625,42 +625,62 @@ void sp_selected_path_outline_add_marker( SPObject *marker_object, Geom::Matrix } static -void item_outline_add_marker( SPObject const *marker_object, Geom::Matrix marker_transform, +void item_outline_add_marker_child( SPItem const *item, Geom::Affine marker_transform, Geom::PathVector* pathv_in ) +{ + Geom::Affine tr(marker_transform); + tr = item->transform * tr; + + // note: a marker child item can be an item group! + if (SP_IS_GROUP(item)) { + // recurse through all childs: + for (SPObject const *o = item->firstChild() ; o ; o = o->getNext() ) { + if ( SP_IS_ITEM(o) ) { + item_outline_add_marker_child(SP_ITEM(o), tr, pathv_in); + } + } + } else { + Geom::PathVector* marker_pathv = item_outline(item); + + if (marker_pathv) { + for (unsigned int j=0; j < marker_pathv->size(); j++) { + pathv_in->push_back((*marker_pathv)[j] * tr); + } + delete marker_pathv; + } + } +} + +static +void item_outline_add_marker( SPObject const *marker_object, Geom::Affine marker_transform, Geom::Scale stroke_scale, Geom::PathVector* pathv_in ) { - SPMarker* marker = SP_MARKER (marker_object); - SPItem* marker_item = sp_item_first_item_child(SP_OBJECT(marker_object)); + SPMarker const * marker = SP_MARKER(marker_object); - Geom::Matrix tr(marker_transform); + Geom::Affine tr(marker_transform); if (marker->markerUnits == SP_MARKER_UNITS_STROKEWIDTH) { tr = stroke_scale * tr; } // total marker transform - tr = marker_item->transform * marker->c2p * tr; + tr = marker->c2p * tr; - Geom::PathVector* marker_pathv = item_outline(marker_item); - - if (marker_pathv) { - for (unsigned int j=0; j < marker_pathv->size(); j++) { - pathv_in->push_back((*marker_pathv)[j] * tr); - } - delete marker_pathv; - } + SPItem const * marker_item = sp_item_first_item_child(marker_object); // why only consider the first item? can a marker only consist of a single item (that may be a group)? + item_outline_add_marker_child(marker_item, tr, pathv_in); } /** * Returns a pathvector that is the outline of the stroked item, with markers. - * item must be SPShape of SPText. + * item must be SPShape or SPText. */ Geom::PathVector* item_outline(SPItem const *item) { Geom::PathVector *ret_pathv = NULL; - if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) + if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) { return ret_pathv; + } // no stroke: no outline - if (!SP_OBJECT_STYLE(item) || SP_OBJECT_STYLE(item)->stroke.noneSet) { + if (!item->style || item->style->stroke.noneSet) { return ret_pathv; } @@ -679,9 +699,9 @@ Geom::PathVector* item_outline(SPItem const *item) } // remember old stroke style, to be set on fill - SPStyle *i_style = SP_OBJECT_STYLE(item); + SPStyle *i_style = item->style; - Geom::Matrix const transform(item->transform); + Geom::Affine const transform(item->transform); float const scale = transform.descrim(); float o_width, o_miter; @@ -793,7 +813,7 @@ Geom::PathVector* item_outline(SPItem const *item) // START marker for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( SPObject *marker_obj = shape->marker[i] ) { - Geom::Matrix const m (sp_shape_marker_get_transform_at_start(pathv.front().front())); + Geom::Affine const m (sp_shape_marker_get_transform_at_start(pathv.front().front())); item_outline_add_marker( marker_obj, m, Geom::Scale(i_style->stroke_width.computed), ret_pathv ); @@ -808,7 +828,7 @@ Geom::PathVector* item_outline(SPItem const *item) if ( path_it != pathv.begin() && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { - Geom::Matrix const m (sp_shape_marker_get_transform_at_start(path_it->front())); + Geom::Affine const m (sp_shape_marker_get_transform_at_start(path_it->front())); item_outline_add_marker( midmarker_obj, m, Geom::Scale(i_style->stroke_width.computed), ret_pathv ); @@ -823,7 +843,7 @@ Geom::PathVector* item_outline(SPItem const *item) * Loop to end_default (so including closing segment), because when a path is closed, * there should be a midpoint marker between last segment and closing straight line segment */ - Geom::Matrix const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2)); + Geom::Affine const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2)); item_outline_add_marker( midmarker_obj, m, Geom::Scale(i_style->stroke_width.computed), ret_pathv); @@ -835,7 +855,7 @@ Geom::PathVector* item_outline(SPItem const *item) // END position if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); - Geom::Matrix const m = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); item_outline_add_marker( midmarker_obj, m, Geom::Scale(i_style->stroke_width.computed), ret_pathv ); @@ -854,7 +874,7 @@ Geom::PathVector* item_outline(SPItem const *item) } Geom::Curve const &lastcurve = path_last[index]; - Geom::Matrix const m = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); item_outline_add_marker( marker_obj, m, Geom::Scale(i_style->stroke_width.computed), ret_pathv ); @@ -909,14 +929,14 @@ sp_selected_path_outline(SPDesktop *desktop) } // pas de stroke pas de chocolat - if (!SP_OBJECT_STYLE(item) || SP_OBJECT_STYLE(item)->stroke.noneSet) { + if (!item->style || item->style->stroke.noneSet) { curve->unref(); continue; } // remember old stroke style, to be set on fill - SPStyle *i_style = SP_OBJECT_STYLE(item); - SPCSSAttr *ncss; + SPStyle *i_style = item->style; + SPCSSAttr *ncss = 0; { ncss = sp_css_attr_from_style(i_style, SP_STYLE_FLAG_ALWAYS); gchar const *s_val = sp_repr_css_property(ncss, "stroke", NULL); @@ -935,10 +955,10 @@ sp_selected_path_outline(SPDesktop *desktop) sp_repr_css_unset_property(ncss, "marker-end"); } - Geom::Matrix const transform(item->transform); + Geom::Affine const transform(item->transform); float const scale = transform.descrim(); - gchar const *mask = SP_OBJECT_REPR(item)->attribute("mask"); - gchar const *clip_path = SP_OBJECT_REPR(item)->attribute("clip-path"); + gchar const *mask = item->getRepr()->attribute("mask"); + gchar const *clip_path = item->getRepr()->attribute("clip-path"); float o_width, o_miter; JoinType o_join; @@ -1052,11 +1072,11 @@ sp_selected_path_outline(SPDesktop *desktop) did = true; // remember the position of the item - gint pos = SP_OBJECT_REPR(item)->position(); + gint pos = item->getRepr()->position(); // remember parent - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); + Inkscape::XML::Node *parent = item->getRepr()->parent(); // remember id - char const *id = SP_OBJECT_REPR(item)->attribute("id"); + char const *id = item->getRepr()->attribute("id"); // remember title gchar *title = item->title(); // remember description @@ -1111,7 +1131,7 @@ sp_selected_path_outline(SPDesktop *desktop) // START marker for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( SPObject *marker_obj = shape->marker[i] ) { - Geom::Matrix const m (sp_shape_marker_get_transform_at_start(pathv.front().front())); + Geom::Affine const m (sp_shape_marker_get_transform_at_start(pathv.front().front())); sp_selected_path_outline_add_marker( marker_obj, m, Geom::Scale(i_style->stroke_width.computed), transform, g_repr, xml_doc, doc ); @@ -1126,7 +1146,7 @@ sp_selected_path_outline(SPDesktop *desktop) if ( path_it != pathv.begin() && ! ((path_it == (pathv.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { - Geom::Matrix const m (sp_shape_marker_get_transform_at_start(path_it->front())); + Geom::Affine const m (sp_shape_marker_get_transform_at_start(path_it->front())); sp_selected_path_outline_add_marker( midmarker_obj, m, Geom::Scale(i_style->stroke_width.computed), transform, g_repr, xml_doc, doc ); @@ -1141,7 +1161,7 @@ sp_selected_path_outline(SPDesktop *desktop) * Loop to end_default (so including closing segment), because when a path is closed, * there should be a midpoint marker between last segment and closing straight line segment */ - Geom::Matrix const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2)); + Geom::Affine const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2)); sp_selected_path_outline_add_marker(midmarker_obj, m, Geom::Scale(i_style->stroke_width.computed), transform, g_repr, xml_doc, doc); @@ -1153,7 +1173,7 @@ sp_selected_path_outline(SPDesktop *desktop) // END position if ( path_it != (pathv.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); - Geom::Matrix const m = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); sp_selected_path_outline_add_marker( midmarker_obj, m, Geom::Scale(i_style->stroke_width.computed), transform, g_repr, xml_doc, doc ); @@ -1172,7 +1192,7 @@ sp_selected_path_outline(SPDesktop *desktop) } Geom::Curve const &lastcurve = path_last[index]; - Geom::Matrix const m = sp_shape_marker_get_transform_at_end(lastcurve); + Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); sp_selected_path_outline_add_marker( marker_obj, m, Geom::Scale(i_style->stroke_width.computed), transform, g_repr, xml_doc, doc ); @@ -1212,11 +1232,17 @@ sp_selected_path_outline(SPDesktop *desktop) curve->unref(); selection->remove(item); - SP_OBJECT(item)->deleteObject(false); + item->deleteObject(false); } - if (title) g_free(title); - if (desc) g_free(desc); + if (title) { + g_free(title); + title = 0; + } + if (desc) { + g_free(desc); + desc = 0; + } delete res; delete orig; @@ -1326,24 +1352,23 @@ sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updat return; } - Geom::Matrix const transform(item->transform); + Geom::Affine const transform(item->transform); - item->doWriteTransform(SP_OBJECT_REPR(item), Geom::identity()); + item->doWriteTransform(item->getRepr(), Geom::identity()); //XML Tree being used directly here while it shouldn't be... - style = g_strdup(SP_OBJECT(item)->getRepr()->attribute("style")); + style = g_strdup(item->getRepr()->attribute("style")); // remember the position of the item - gint pos = SP_OBJECT_REPR(item)->position(); + gint pos = item->getRepr()->position(); // remember parent - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); + Inkscape::XML::Node *parent = item->getRepr()->parent(); { - SPStyle *i_style = SP_OBJECT(item)->style; - int jointype, captype; + SPStyle *i_style = item->style; + int jointype = i_style->stroke_linejoin.value; + int captype = i_style->stroke_linecap.value; - jointype = i_style->stroke_linejoin.value; - captype = i_style->stroke_linecap.value; o_width = i_style->stroke_width.computed; if (jointype == SP_STROKE_LINEJOIN_MITER) { @@ -1398,7 +1423,7 @@ sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updat orig->ConvertWithBackData(1.0); orig->Fill(theShape, 0); - SPCSSAttr *css = sp_repr_css_attr(SP_OBJECT_REPR(item), "style"); + SPCSSAttr *css = sp_repr_css_attr(item->getRepr(), "style"); gchar const *val = sp_repr_css_property(css, "fill-rule", NULL); if (val && strcmp(val, "nonzero") == 0) { @@ -1461,7 +1486,8 @@ sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updat if ( updating ) { //XML Tree being used directly here while it shouldn't be - char const *id = SP_OBJECT(item)->getRepr()->attribute("id"); + item->doWriteTransform(item->getRepr(), transform); + char const *id = item->getRepr()->attribute("id"); char const *uri = g_strdup_printf("#%s", id); repr->setAttribute("xlink:href", uri); g_free((void *) uri); @@ -1479,19 +1505,15 @@ sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updat SPItem *nitem = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); - if ( updating ) { - // on conserve l'original - // we reapply the transform to the original (offset will feel it) - item->doWriteTransform(SP_OBJECT_REPR(item), transform); - } else { + if ( !updating ) { // delete original, apply the transform to the offset - SP_OBJECT(item)->deleteObject(false); + item->deleteObject(false); nitem->doWriteTransform(repr, transform); } // The object just created from a temporary repr is only a seed. // We need to invoke its write which will update its real repr (in particular adding d=) - SP_OBJECT(nitem)->updateRepr(); + nitem->updateRepr(); Inkscape::GC::release(repr); @@ -1554,22 +1576,21 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) continue; } - Geom::Matrix const transform(item->transform); + Geom::Affine const transform(item->transform); - item->doWriteTransform(SP_OBJECT_REPR(item), Geom::identity()); + item->doWriteTransform(item->getRepr(), Geom::identity()); - gchar *style = g_strdup(SP_OBJECT_REPR(item)->attribute("style")); + gchar *style = g_strdup(item->getRepr()->attribute("style")); float o_width, o_miter; JoinType o_join; ButtType o_butt; { - SPStyle *i_style = SP_OBJECT(item)->style; - int jointype, captype; + SPStyle *i_style = item->style; + int jointype = i_style->stroke_linejoin.value; + int captype = i_style->stroke_linecap.value; - jointype = i_style->stroke_linejoin.value; - captype = i_style->stroke_linecap.value; o_width = i_style->stroke_width.computed; switch (jointype) { @@ -1620,7 +1641,7 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) orig->ConvertWithBackData(0.03); orig->Fill(theShape, 0); - SPCSSAttr *css = sp_repr_css_attr(SP_OBJECT_REPR(item), "style"); + SPCSSAttr *css = sp_repr_css_attr(item->getRepr(), "style"); gchar const *val = sp_repr_css_property(css, "fill-rule", NULL); if (val && strcmp(val, "nonzero") == 0) { @@ -1696,14 +1717,14 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) curve->unref(); // remember the position of the item - gint pos = SP_OBJECT_REPR(item)->position(); + gint pos = item->getRepr()->position(); // remember parent - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); + Inkscape::XML::Node *parent = item->getRepr()->parent(); // remember id - char const *id = SP_OBJECT_REPR(item)->attribute("id"); + char const *id = item->getRepr()->attribute("id"); selection->remove(item); - SP_OBJECT(item)->deleteObject(false); + item->deleteObject(false); if (res->descr_cmd.size() > 1) { // if there's 0 or 1 node left, drop this path altogether @@ -1782,64 +1803,48 @@ sp_selected_path_simplify_item(SPDesktop *desktop, false); } - - SPCurve *curve = NULL; - - if (SP_IS_SHAPE(item)) { - curve = SP_SHAPE(item)->getCurve(); - if (!curve) - return false; - } - - if (SP_IS_TEXT(item)) { - curve = SP_TEXT(item)->getNormalizedBpath(); - if (!curve) - return false; + // get path to simplify (note that the path *before* LPE calculation is needed) + Path *orig = Path_for_item_before_LPE(item, false); + if (orig == NULL) { + return false; } // correct virtual size by full transform (bug #166937) size /= item->i2doc_affine().descrim(); // save the transform, to re-apply it after simplification - Geom::Matrix const transform(item->transform); + Geom::Affine const transform(item->transform); /* reset the transform, effectively transforming the item by transform.inverse(); this is necessary so that the item is transformed twice back and forth, allowing all compensations to cancel out regardless of the preferences */ - item->doWriteTransform(SP_OBJECT_REPR(item), Geom::identity()); + item->doWriteTransform(item->getRepr(), Geom::identity()); - gchar *style = g_strdup(SP_OBJECT_REPR(item)->attribute("style")); - gchar *mask = g_strdup(SP_OBJECT_REPR(item)->attribute("mask")); - gchar *clip_path = g_strdup(SP_OBJECT_REPR(item)->attribute("clip-path")); - - Path *orig = Path_for_item(item, false); - if (orig == NULL) { - g_free(style); - curve->unref(); - return false; - } + gchar *style = g_strdup(item->getRepr()->attribute("style")); + gchar *mask = g_strdup(item->getRepr()->attribute("mask")); + gchar *clip_path = g_strdup(item->getRepr()->attribute("clip-path")); - curve->unref(); // remember the position of the item - gint pos = SP_OBJECT_REPR(item)->position(); + gint pos = item->getRepr()->position(); // remember parent - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); + Inkscape::XML::Node *parent = item->getRepr()->parent(); // remember id - char const *id = SP_OBJECT_REPR(item)->attribute("id"); + char const *id = item->getRepr()->attribute("id"); // remember path effect - char const *patheffect = SP_OBJECT_REPR(item)->attribute("inkscape:path-effect"); + char const *patheffect = item->getRepr()->attribute("inkscape:path-effect"); // remember title gchar *title = item->title(); // remember description gchar *desc = item->desc(); //If a group was selected, to not change the selection list - if (modifySelection) + if (modifySelection) { selection->remove(item); + } - SP_OBJECT(item)->deleteObject(false); + item->deleteObject(false); if ( justCoalesce ) { orig->Coalesce(threshold * size); @@ -2083,12 +2088,33 @@ Path_for_item(SPItem *item, bool doTransformation, bool transformFull) return dest; } +/** + * Obtains an item's Path before the LPE stack has been applied. + */ +Path * +Path_for_item_before_LPE(SPItem *item, bool doTransformation, bool transformFull) +{ + SPCurve *curve = curve_for_item_before_LPE(item); + + if (curve == NULL) + return NULL; + + Geom::PathVector *pathv = pathvector_for_curve(item, curve, doTransformation, transformFull, Geom::identity(), Geom::identity()); + curve->unref(); + + Path *dest = new Path; + dest->LoadPathVector(*pathv); + delete pathv; + + return dest; +} + /* * NOTE: Returns empty pathvector if curve == NULL * TODO: see if calling this method can be optimized. All the pathvector copying might be slow. */ Geom::PathVector* -pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Matrix extraPreAffine, Geom::Matrix extraPostAffine) +pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Affine extraPreAffine, Geom::Affine extraPostAffine) { if (curve == NULL) return NULL; @@ -2100,7 +2126,7 @@ pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool t if (transformFull) { *dest *= extraPreAffine * item->i2doc_affine() * extraPostAffine; } else { - *dest *= extraPreAffine * (Geom::Matrix)item->transform * extraPostAffine; + *dest *= extraPreAffine * (Geom::Affine)item->transform * extraPostAffine; } } else { *dest *= extraPreAffine * extraPostAffine; @@ -2109,6 +2135,10 @@ pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool t return dest; } +/** + * Obtains an item's curve. For SPPath, it is the path *before* LPE. For SPShapes other than path, it is the path *after* LPE. + * So the result is somewhat ill-defined, and probably this method should not be used... See curve_for_item_before_LPE. + */ SPCurve* curve_for_item(SPItem *item) { if (!item) @@ -2134,6 +2164,31 @@ SPCurve* curve_for_item(SPItem *item) return curve; // do not forget to unref the curve at some point! } +/** + * Obtains an item's curve *before* LPE. + * The returned SPCurve should be unreffed by the caller. + */ +SPCurve* curve_for_item_before_LPE(SPItem *item) +{ + if (!item) + return NULL; + + SPCurve *curve = NULL; + if (SP_IS_SHAPE(item)) { + curve = SP_SHAPE(item)->getCurveBeforeLPE(); + } + else if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) + { + curve = te_get_layout(item)->convertToCurves(); + } + else if (SP_IS_IMAGE(item)) + { + curve = sp_image_get_curve(SP_IMAGE(item)); + } + + return curve; // do not forget to unref the curve at some point! +} + boost::optional<Path::cut_position> get_nearest_position_on_Path(Path *path, Geom::Point p, unsigned seg) { //get nearest position on path diff --git a/src/splivarot.h b/src/splivarot.h index d85ae030a..40089ad71 100644 --- a/src/splivarot.h +++ b/src/splivarot.h @@ -49,8 +49,10 @@ Geom::PathVector* item_outline(SPItem const *item); void sp_selected_path_simplify (SPDesktop *desktop); Path *Path_for_item(SPItem *item, bool doTransformation, bool transformFull = true); -Geom::PathVector* pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Matrix extraPreAffine, Geom::Matrix extraPostAffine); +Path *Path_for_item_before_LPE(SPItem *item, bool doTransformation, bool transformFull = true); +Geom::PathVector* pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool transformFull, Geom::Affine extraPreAffine, Geom::Affine extraPostAffine); SPCurve *curve_for_item(SPItem *item); +SPCurve *curve_for_item_before_LPE(SPItem *item); boost::optional<Path::cut_position> get_nearest_position_on_Path(Path *path, Geom::Point p, unsigned seg = 0); Geom::Point get_point_on_Path(Path *path, int piece, double t); diff --git a/src/spray-context.cpp b/src/spray-context.cpp index 9a499a64c..36c135924 100644 --- a/src/spray-context.cpp +++ b/src/spray-context.cpp @@ -27,7 +27,6 @@ #include <numeric> #include "svg/svg.h" -#include "display/canvas-bpath.h" #include <glib/gmem.h> #include "macros.h" @@ -36,7 +35,6 @@ #include "desktop.h" #include "desktop-events.h" #include "desktop-handles.h" -#include "desktop-style.h" #include "message-context.h" #include "pixmaps/cursor-spray.xpm" #include <boost/optional.hpp> @@ -44,21 +42,16 @@ #include "context-fns.h" #include "sp-item.h" #include "inkscape.h" -#include "color.h" -#include "svg/svg-color.h" + #include "splivarot.h" #include "sp-item-group.h" #include "sp-shape.h" #include "sp-path.h" #include "path-chemistry.h" -#include "sp-gradient.h" -#include "sp-stop.h" -#include "sp-gradient-reference.h" -#include "sp-linear-gradient.h" -#include "sp-radial-gradient.h" -#include "gradient-chemistry.h" + #include "sp-text.h" #include "sp-flowtext.h" +#include "display/sp-canvas.h" #include "display/canvas-bpath.h" #include "display/canvas-arena.h" #include "display/curve.h" @@ -69,6 +62,7 @@ #include "style.h" #include "box3d.h" #include "sp-item-transform.h" +#include "filter-chemistry.h" #include "spray-context.h" #include "ui/dialog/dialog-manager.h" @@ -79,9 +73,7 @@ using Inkscape::DocumentUndo; using namespace std; - #define DDC_RED_RGBA 0xff0000ff - #define DYNA_MIN_WIDTH 1.0e-6 static void sp_spray_context_class_init(SPSprayContextClass *klass); @@ -100,13 +92,12 @@ static SPEventContextClass *parent_class = 0; * @param mu : mean * @param sigma : standard deviation ( > 0 ) */ -inline double NormalDistribution(double mu,double sigma) +inline double NormalDistribution(double mu, double sigma) { // use Box Muller's algorithm return mu + sigma * sqrt( -2.0 * log(g_random_double_range(0, 1)) ) * cos( 2.0*M_PI*g_random_double_range(0, 1) ); } - GtkType sp_spray_context_get_type(void) { static GType type = 0; @@ -141,15 +132,15 @@ static void sp_spray_context_class_init(SPSprayContextClass *klass) } /* Method to rotate items */ -void sp_spray_rotate_rel(Geom::Point c,SPDesktop */*desktop*/,SPItem *item, Geom::Rotate const &rotation) +void sp_spray_rotate_rel(Geom::Point c, SPDesktop */*desktop*/, SPItem *item, Geom::Rotate const &rotation) { Geom::Point center = c; Geom::Translate const s(c); - Geom::Matrix affine = Geom::Matrix(s).inverse() * Geom::Matrix(rotation) * Geom::Matrix(s); + Geom::Affine affine = Geom::Affine(s).inverse() * Geom::Affine(rotation) * Geom::Affine(s); // Rotate item. - item->set_i2d_affine(item->i2d_affine() * (Geom::Matrix)affine); + item->set_i2d_affine(item->i2d_affine() * (Geom::Affine)affine); // Use each item's own transform writer, consistent with sp_selection_apply_affine() - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform); + item->doWriteTransform(item->getRepr(), item->transform); // Restore the center position (it's changed because the bbox center changed) if (item->isCenterSet()) { item->setCenter(c); @@ -158,11 +149,11 @@ void sp_spray_rotate_rel(Geom::Point c,SPDesktop */*desktop*/,SPItem *item, Geom } /* Method to scale items */ -void sp_spray_scale_rel(Geom::Point c, SPDesktop */*desktop*/, SPItem *item, Geom::Scale const &scale) +void sp_spray_scale_rel(Geom::Point c, SPDesktop */*desktop*/, SPItem *item, Geom::Scale const &scale) { Geom::Translate const s(c); - item->set_i2d_affine(item->i2d_affine() * s.inverse() * scale * s ); - item->doWriteTransform(SP_OBJECT_REPR(item), item->transform); + item->set_i2d_affine(item->i2d_affine() * s.inverse() * scale * s); + item->doWriteTransform(item->getRepr(), item->transform); } static void sp_spray_context_init(SPSprayContext *tc) @@ -179,28 +170,26 @@ static void sp_spray_context_init(SPSprayContext *tc) tc->width = 0.2; tc->force = 0.2; tc->ratio = 0; - tc->tilt=0; + tc->tilt = 0; tc->mean = 0.2; - tc->rotation_variation=0; - tc->standard_deviation=0.2; - tc->scale=1; + tc->rotation_variation = 0; + tc->standard_deviation = 0.2; + tc->scale = 1; tc->scale_variation = 1; tc->pressure = TC_DEFAULT_PRESSURE; tc->is_dilating = false; tc->has_dilated = false; - tc->do_h = true; - tc->do_s = true; - tc->do_l = true; - tc->do_o = false; - new (&tc->style_set_connection) sigc::connection(); } static void sp_spray_context_dispose(GObject *object) { SPSprayContext *tc = SP_SPRAY_CONTEXT(object); + SPEventContext *ec = SP_EVENT_CONTEXT(object); + + ec->enableGrDrag(false); tc->style_set_connection.disconnect(); tc->style_set_connection.~connection(); @@ -227,8 +216,8 @@ bool is_transform_modes(gint mode) void sp_spray_update_cursor(SPSprayContext *tc, bool /*with_shift*/) { - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); - SPDesktop *desktop = event_context->desktop; + SPEventContext *event_context = SP_EVENT_CONTEXT(tc); + SPDesktop *desktop = event_context->desktop; guint num = 0; gchar *sel_message = NULL; @@ -242,13 +231,13 @@ void sp_spray_update_cursor(SPSprayContext *tc, bool /*with_shift*/) switch (tc->mode) { case SPRAY_MODE_COPY: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray <b>copies</b> of the initial selection"), sel_message); + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray <b>copies</b> of the initial selection."), sel_message); break; case SPRAY_MODE_CLONE: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray <b>clones</b> of the initial selection"), sel_message); + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray <b>clones</b> of the initial selection."), sel_message); break; case SPRAY_MODE_SINGLE_PATH: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray in a <b>single path</b> of the initial selection"), sel_message); + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray in a <b>single path</b> of the initial selection."), sel_message); break; default: break; @@ -261,8 +250,9 @@ static void sp_spray_context_setup(SPEventContext *ec) { SPSprayContext *tc = SP_SPRAY_CONTEXT(ec); - if (((SPEventContextClass *) parent_class)->setup) + if (((SPEventContextClass *) parent_class)->setup) { ((SPEventContextClass *) parent_class)->setup(ec); + } { /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ @@ -298,18 +288,11 @@ static void sp_spray_context_setup(SPEventContext *ec) sp_event_context_read(ec, "standard_deviation"); sp_event_context_read(ec, "usepressure"); sp_event_context_read(ec, "Scale"); - sp_event_context_read(ec, "doh"); - sp_event_context_read(ec, "dol"); - sp_event_context_read(ec, "dos"); - sp_event_context_read(ec, "doo"); - - ; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/spray/selcue")) { ec->enableSelectionCue(); } - if (prefs->getBool("/tools/spray/gradientdrag")) { ec->enableGrDrag(); } @@ -320,56 +303,47 @@ static void sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entr SPSprayContext *tc = SP_SPRAY_CONTEXT(ec); Glib::ustring path = val->getEntryName(); - if (path == "width") { - tc->width = 0.01 * CLAMP(val->getInt(10), 1, 100); - } else if (path == "mode") { + if (path == "mode") { tc->mode = val->getInt(); sp_spray_update_cursor(tc, false); - } else if (path == "distribution") { - tc->distrib = val->getInt(1); + } else if (path == "width") { + tc->width = 0.01 * CLAMP(val->getInt(10), 1, 100); + } else if (path == "usepressure") { + tc->usepressure = val->getBool(); } else if (path == "population") { tc->population = 0.01 * CLAMP(val->getInt(10), 1, 100); - } else if (path == "tilt") { - tc->tilt = CLAMP(val->getDouble(0.1), 0, 1000.0); - } else if (path == "ratio") { - tc->ratio = CLAMP(val->getDouble(), 0.0, 0.9); - } else if (path == "force") { - tc->force = CLAMP(val->getDouble(1.0), 0, 1.0); } else if (path == "rotation_variation") { tc->rotation_variation = CLAMP(val->getDouble(0.0), 0, 100.0); } else if (path == "scale_variation") { tc->scale_variation = CLAMP(val->getDouble(1.0), 0, 100.0); - } else if (path == "mean") { - tc->mean = 0.01 * CLAMP(val->getInt(10), 1, 100); } else if (path == "standard_deviation") { tc->standard_deviation = 0.01 * CLAMP(val->getInt(10), 1, 100); - } else if (path == "usepressure") { - tc->usepressure = val->getBool(); - } else if (path == "doh") { - tc->do_h = val->getBool(); - } else if (path == "dos") { - tc->do_s = val->getBool(); - } else if (path == "dol") { - tc->do_l = val->getBool(); - } else if (path == "doo") { - tc->do_o = val->getBool(); - } + } else if (path == "mean") { + tc->mean = 0.01 * CLAMP(val->getInt(10), 1, 100); +// Not implemented in the toolbar and preferences yet + } else if (path == "distribution") { + tc->distrib = val->getInt(1); + } else if (path == "tilt") { + tc->tilt = CLAMP(val->getDouble(0.1), 0, 1000.0); + } else if (path == "ratio") { + tc->ratio = CLAMP(val->getDouble(), 0.0, 0.9); + } else if (path == "force") { + tc->force = CLAMP(val->getDouble(1.0), 0, 1.0); + } } static void sp_spray_extinput(SPSprayContext *tc, GdkEvent *event) { - if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &tc->pressure)) - tc->pressure = CLAMP (tc->pressure, TC_MIN_PRESSURE, TC_MAX_PRESSURE); - else + if (gdk_event_get_axis(event, GDK_AXIS_PRESSURE, &tc->pressure)) { + tc->pressure = CLAMP(tc->pressure, TC_MIN_PRESSURE, TC_MAX_PRESSURE); + } else { tc->pressure = TC_DEFAULT_PRESSURE; + } } double get_dilate_radius(SPSprayContext *tc) { - return 250 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom(); - - } double get_path_force(SPSprayContext *tc) @@ -417,29 +391,25 @@ double get_move_standard_deviation(SPSprayContext *tc) * @param[in] choice : */ -void random_position( double &radius, double &angle, double &a, double &s, int /*choice*/) +void random_position(double &radius, double &angle, double &a, double &s, int /*choice*/) { // angle is taken from an uniform distribution angle = g_random_double_range(0, M_PI*2.0); // radius is taken from a Normal Distribution double radius_temp =-1; - while(!((radius_temp>=0)&&(radius_temp<=1))) + while(!((radius_temp >= 0) && (radius_temp <=1 ))) { - radius_temp = NormalDistribution( a, s ); + radius_temp = NormalDistribution(a, s); } // Because we are in polar coordinates, a special treatment has to be done to the radius. // Otherwise, positions taken from an uniform repartition on radius and angle will not seam to // be uniformily distributed on the disk (more at the center and less at the boundary). // We counter this effect with a 0.5 exponent. This is empiric. - radius = pow( radius_temp, 0.5); + radius = pow(radius_temp, 0.5); } - - - - bool sp_spray_recursive(SPDesktop *desktop, Inkscape::Selection *selection, SPItem *item, @@ -457,7 +427,7 @@ bool sp_spray_recursive(SPDesktop *desktop, double ratio, double tilt, double rotation_variation, - gint _distrib ) + gint _distrib) { bool did = false; @@ -467,7 +437,7 @@ bool sp_spray_recursive(SPDesktop *desktop, selection->add(item); } - double _fid = g_random_double_range(0,1); + double _fid = g_random_double_range(0, 1); double angle = g_random_double_range( - rotation_variation / 100.0 * M_PI , rotation_variation / 100.0 * M_PI ); double _scale = g_random_double_range( 1.0 - scale_variation / 100.0, 1.0 + scale_variation / 100.0 ); double dr; double dp; @@ -478,12 +448,12 @@ bool sp_spray_recursive(SPDesktop *desktop, Geom::OptRect a = item->getBounds(item->i2doc_affine()); if (a) { SPItem *item_copied; - if(_fid<=population) + if(_fid <= population) { // duplicate - SPDocument *doc = SP_OBJECT_DOCUMENT(item); + SPDocument *doc = item->document; Inkscape::XML::Document* xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item); + Inkscape::XML::Node *old_repr = item->getRepr(); Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); parent->appendChild(copy); @@ -491,12 +461,12 @@ bool sp_spray_recursive(SPDesktop *desktop, SPObject *new_obj = doc->getObjectByRepr(copy); item_copied = (SPItem *) new_obj; //convertion object->item Geom::Point center=item->getCenter(); - sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale)); - sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale)); + sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale,_scale)); + sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale,scale)); sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle)); //Move the cursor p - Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); did = true; } @@ -514,31 +484,31 @@ bool sp_spray_recursive(SPDesktop *desktop, items = items->next) { SPItem *item1 = (SPItem *) items->data; - if (i==1) { - father=item1; + if (i == 1) { + father = item1; } - if (i==2) { - unionResult=item1; + if (i == 2) { + unionResult = item1; } i++; } - SPDocument *doc = SP_OBJECT_DOCUMENT(father); + SPDocument *doc = father->document; Inkscape::XML::Document* xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(father); + Inkscape::XML::Node *old_repr = father->getRepr(); Inkscape::XML::Node *parent = old_repr->parent(); Geom::OptRect a = father->getBounds(father->i2doc_affine()); if (a) { - if (i==2) { + if (i == 2) { Inkscape::XML::Node *copy1 = old_repr->duplicate(xml_doc); parent->appendChild(copy1); SPObject *new_obj1 = doc->getObjectByRepr(copy1); son = (SPItem *) new_obj1; // conversion object->item - unionResult=son; + unionResult = son; Inkscape::GC::release(copy1); - } + } - if (_fid<=population) { // Rules the population of objects sprayed + if (_fid <= population) { // Rules the population of objects sprayed // duplicates the father Inkscape::XML::Node *copy2 = old_repr->duplicate(xml_doc); parent->appendChild(copy2); @@ -546,12 +516,12 @@ bool sp_spray_recursive(SPDesktop *desktop, item_copied = (SPItem *) new_obj2; // Move around the cursor - Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); Geom::Point center=father->getCenter(); - sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale)); - sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale)); - sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle)); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale)); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale)); + sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle)); sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); // union and duplication @@ -567,11 +537,11 @@ bool sp_spray_recursive(SPDesktop *desktop, } else if (mode == SPRAY_MODE_CLONE) { Geom::OptRect a = item->getBounds(item->i2doc_affine()); if (a) { - if(_fid<=population) { + if(_fid <= population) { SPItem *item_copied; - SPDocument *doc = SP_OBJECT_DOCUMENT(item); + SPDocument *doc = item->document; Inkscape::XML::Document* xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item); + Inkscape::XML::Node *old_repr = item->getRepr(); Inkscape::XML::Node *parent = old_repr->parent(); // Creation of the clone @@ -584,11 +554,11 @@ bool sp_spray_recursive(SPDesktop *desktop, SPObject *clone_object = doc->getObjectByRepr(clone); // conversion object->item item_copied = (SPItem *) clone_object; - Geom::Point center=item->getCenter(); - sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale)); - sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale)); - sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle)); - Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + Geom::Point center = item->getCenter(); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale)); + sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale)); + sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle)); + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); Inkscape::GC::release(clone); @@ -606,35 +576,12 @@ bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p, Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(tc)->desktop); SPDesktop *desktop = SP_EVENT_CONTEXT(tc)->desktop; - if (selection->isEmpty()) { return false; } bool did = false; double radius = get_dilate_radius(tc); - - - - bool do_fill = false, do_stroke = false, do_opacity = false; - guint32 fill_goal = sp_desktop_get_color_tool(desktop, "/tools/spray", true, &do_fill); - guint32 stroke_goal = sp_desktop_get_color_tool(desktop, "/tools/spray", false, &do_stroke); - double opacity_goal = sp_desktop_get_master_opacity_tool(desktop, "/tools/spray", &do_opacity); - if (reverse) { - // RGB inversion - fill_goal = SP_RGBA32_U_COMPOSE( - (255 - SP_RGBA32_R_U(fill_goal)), - (255 - SP_RGBA32_G_U(fill_goal)), - (255 - SP_RGBA32_B_U(fill_goal)), - (255 - SP_RGBA32_A_U(fill_goal))); - stroke_goal = SP_RGBA32_U_COMPOSE( - (255 - SP_RGBA32_R_U(stroke_goal)), - (255 - SP_RGBA32_G_U(stroke_goal)), - (255 - SP_RGBA32_B_U(stroke_goal)), - (255 - SP_RGBA32_A_U(stroke_goal))); - opacity_goal = 1 - opacity_goal; - } - double path_force = get_path_force(tc); if (radius == 0 || path_force == 0) { return false; @@ -651,7 +598,6 @@ bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p, double move_mean = get_move_mean(tc); double move_standard_deviation = get_move_standard_deviation(tc); - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { @@ -659,10 +605,10 @@ bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p, SPItem *item = (SPItem *) items->data; if (is_transform_modes(tc->mode)) { - if (sp_spray_recursive (desktop,selection, item, p, vector, tc->mode, radius, move_force, tc->population,tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation,tc->ratio,tc->tilt, tc->rotation_variation, tc->distrib)) + if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, move_force, tc->population, tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) did = true; } else { - if (sp_spray_recursive (desktop,selection, item, p, vector, tc->mode, radius, path_force, tc->population,tc->scale, tc->scale_variation, reverse, path_mean, path_standard_deviation,tc->ratio,tc->tilt, tc->rotation_variation, tc->distrib)) + if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, path_force, tc->population, tc->scale, tc->scale_variation, reverse, path_mean, path_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) did = true; } } @@ -672,36 +618,35 @@ bool sp_spray_dilate(SPSprayContext *tc, Geom::Point /*event_p*/, Geom::Point p, void sp_spray_update_area(SPSprayContext *tc) { - double radius = get_dilate_radius(tc); - Geom::Matrix const sm ( Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) ); - sp_canvas_item_affine_absolute(tc->dilate_area, (sm* Geom::Rotate(tc->tilt))* Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point())); - sp_canvas_item_show(tc->dilate_area); + double radius = get_dilate_radius(tc); + Geom::Affine const sm ( Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) ); + sp_canvas_item_affine_absolute(tc->dilate_area, (sm* Geom::Rotate(tc->tilt))* Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point())); + sp_canvas_item_show(tc->dilate_area); } void sp_spray_switch_mode(SPSprayContext *tc, gint mode, bool with_shift) { // select the button mode - SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("spray_tool_mode", mode); + SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue("spray_tool_mode", mode); // need to set explicitly, because the prefs may not have changed by the previous tc->mode = mode; - sp_spray_update_cursor (tc, with_shift); + sp_spray_update_cursor(tc, with_shift); } void sp_spray_switch_mode_temporarily(SPSprayContext *tc, gint mode, bool with_shift) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - // Juggling about so that prefs have the old value but tc->mode and the button show new mode: - gint now_mode = prefs->getInt("/tools/spray/mode", 0); - SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("spray_tool_mode", mode); - // button has changed prefs, restore - prefs->setInt("/tools/spray/mode", now_mode); - // changing prefs changed tc->mode, restore back :) - tc->mode = mode; - sp_spray_update_cursor (tc, with_shift); + // Juggling about so that prefs have the old value but tc->mode and the button show new mode: + gint now_mode = prefs->getInt("/tools/spray/mode", 0); + SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue("spray_tool_mode", mode); + // button has changed prefs, restore + prefs->setInt("/tools/spray/mode", now_mode); + // changing prefs changed tc->mode, restore back :) + tc->mode = mode; + sp_spray_update_cursor(tc, with_shift); } -gint sp_spray_context_root_handler(SPEventContext *event_context, - GdkEvent *event) +gint sp_spray_context_root_handler(SPEventContext *event_context, GdkEvent *event) { SPSprayContext *tc = SP_SPRAY_CONTEXT(event_context); SPDesktop *desktop = event_context->desktop; @@ -717,13 +662,11 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, break; case GDK_BUTTON_PRESS: if (event->button.button == 1 && !event_context->space_panning) { - if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) { return TRUE; } - Geom::Point const motion_w(event->button.x, - event->button.y); + Geom::Point const motion_w(event->button.x, event->button.y); Geom::Point const motion_dt(desktop->w2d(motion_w)); tc->last_push = desktop->dt2doc(motion_dt); @@ -732,23 +675,17 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); tc->is_drawing = true; tc->is_dilating = true; - tc->has_dilated = false; - - - - if(tc->is_dilating && event->button.button == 1 && !event_context->space_panning) + tc->has_dilated = false; - sp_spray_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); - - - - tc->has_dilated=true; + if(tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { + sp_spray_dilate(tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); + } + tc->has_dilated = true; ret = TRUE; } break; - case GDK_MOTION_NOTIFY: - { + case GDK_MOTION_NOTIFY: { Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point motion_dt(desktop->w2d(motion_w)); @@ -756,22 +693,22 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, sp_spray_extinput(tc, event); // draw the dilating cursor - double radius = get_dilate_radius(tc); - Geom::Matrix const sm (Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) ); - sp_canvas_item_affine_absolute(tc->dilate_area, (sm*Geom::Rotate(tc->tilt))*Geom::Translate(desktop->w2d(motion_w))); - sp_canvas_item_show(tc->dilate_area); - - guint num = 0; - if (!desktop->selection->isEmpty()) { - num = g_slist_length((GSList *) desktop->selection->itemList()); - } - if (num == 0) { - tc->_message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to spray.")); - } + double radius = get_dilate_radius(tc); + Geom::Affine const sm (Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) ); + sp_canvas_item_affine_absolute(tc->dilate_area, (sm*Geom::Rotate(tc->tilt))*Geom::Translate(desktop->w2d(motion_w))); + sp_canvas_item_show(tc->dilate_area); + + guint num = 0; + if (!desktop->selection->isEmpty()) { + num = g_slist_length((GSList *) desktop->selection->itemList()); + } + if (num == 0) { + tc->_message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to spray.")); + } // dilating: if (tc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { - sp_spray_dilate (tc, motion_w, motion_doc, motion_doc - tc->last_push, event->button.state & GDK_SHIFT_MASK? true : false); + sp_spray_dilate(tc, motion_w, motion_doc, motion_doc - tc->last_push, event->button.state & GDK_SHIFT_MASK? true : false); //tc->last_push = motion_doc; tc->has_dilated = true; @@ -779,254 +716,206 @@ gint sp_spray_context_root_handler(SPEventContext *event_context, gobble_motion_events(GDK_BUTTON1_MASK); return TRUE; } - } break; -/*Spray with the scroll*/ - case GDK_SCROLL: - { - if (event->scroll.state & GDK_BUTTON1_MASK) - { - double temp ; - temp=tc->population; - tc->population=1.0; - desktop->setToolboxAdjustmentValue ("population", tc->population * 100); - Geom::Point const scroll_w(event->button.x,event->button.y); - Geom::Point const scroll_dt = desktop->point();; - Geom::Point motion_doc(desktop->dt2doc(scroll_dt)); - switch (event->scroll.direction) - { - case GDK_SCROLL_UP: - { - if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) - { - return TRUE; - } - tc->last_push = desktop->dt2doc(scroll_dt); - sp_spray_extinput(tc, event); - sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); - tc->is_drawing = true; - tc->is_dilating = true; - tc->has_dilated = false; - if(tc->is_dilating && !event_context->space_panning) - - sp_spray_dilate (tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0),false); - - - - tc->has_dilated=true; - tc->population=temp; - - desktop->setToolboxAdjustmentValue ("population", tc->population * 100); - - ret = TRUE; - } - break; - case GDK_SCROLL_DOWN: - { - if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) - { - return TRUE; - } - tc->last_push = desktop->dt2doc(scroll_dt); - sp_spray_extinput(tc, event); - sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); - tc->is_drawing = true; - tc->is_dilating = true; - tc->has_dilated = false; - if(tc->is_dilating && !event_context->space_panning) - sp_spray_dilate (tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0), false); - - tc->has_dilated=true; - - ret = TRUE; - - - } - break; -case GDK_SCROLL_RIGHT: - {} break; -case GDK_SCROLL_LEFT: - {} break; - } - } - - - break; - - } - case GDK_BUTTON_RELEASE: - { - Geom::Point const motion_w(event->button.x, event->button.y); - Geom::Point const motion_dt(desktop->w2d(motion_w)); - - sp_canvas_end_forced_full_redraws(desktop->canvas); - tc->is_drawing = false; - - if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { - if (!tc->has_dilated) { - // if we did not rub, do a light tap - tc->pressure = 0.03; - sp_spray_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); - } - tc->is_dilating = false; - tc->has_dilated = false; - switch (tc->mode) { - case SPRAY_MODE_COPY: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_SPRAY, _("Spray with copies")); - break; - case SPRAY_MODE_CLONE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_SPRAY, _("Spray with clones")); - break; - case SPRAY_MODE_SINGLE_PATH: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_SPRAY, _("Spray in single path")); + /*Spray with the scroll*/ + case GDK_SCROLL: { + if (event->scroll.state & GDK_BUTTON1_MASK) { + double temp ; + temp = tc->population; + tc->population = 1.0; + desktop->setToolboxAdjustmentValue("population", tc->population * 100); + Geom::Point const scroll_w(event->button.x, event->button.y); + Geom::Point const scroll_dt = desktop->point();; + Geom::Point motion_doc(desktop->dt2doc(scroll_dt)); + switch (event->scroll.direction) { + case GDK_SCROLL_DOWN: + case GDK_SCROLL_UP: { + if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) { + return TRUE; + } + tc->last_push = desktop->dt2doc(scroll_dt); + sp_spray_extinput(tc, event); + sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); + tc->is_drawing = true; + tc->is_dilating = true; + tc->has_dilated = false; + if(tc->is_dilating && !event_context->space_panning) { + sp_spray_dilate(tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0), false); + } + tc->has_dilated = true; + + tc->population = temp; + desktop->setToolboxAdjustmentValue("population", tc->population * 100); + + ret = TRUE; + } break; - } - } - break; - } - - case GDK_KEY_PRESS: - switch (get_group0_keyval (&event->key)) { -case GDK_j: if (MOD__SHIFT_ONLY) { - sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT); - ret = TRUE; - } -case GDK_J: if (MOD__SHIFT_ONLY) { - sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT); - ret = TRUE; - } - -break; - case GDK_m: - case GDK_M: - case GDK_0: - - break; - case GDK_i: - case GDK_I: - case GDK_k: if (MOD__SHIFT_ONLY) { - sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT); - ret = TRUE; - } - case GDK_K:if (MOD__SHIFT_ONLY) { - sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT); - ret = TRUE; - } -break; - - case GDK_l: if (MOD__SHIFT_ONLY) { - sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT); - ret = TRUE; - } - - case GDK_L: - if (MOD__SHIFT_ONLY) { - sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT); - ret = TRUE; + case GDK_SCROLL_RIGHT: + {} break; + case GDK_SCROLL_LEFT: + {} break; + } } break; - case GDK_Up: - case GDK_KP_Up: - if (!MOD__CTRL_ONLY) { - tc->scale += 0.05; - - //desktop->setToolboxAdjustmentValue ("spray-force", tc->force * 100); - ret = TRUE; + } + + case GDK_BUTTON_RELEASE: { + Geom::Point const motion_w(event->button.x, event->button.y); + Geom::Point const motion_dt(desktop->w2d(motion_w)); + + sp_canvas_end_forced_full_redraws(desktop->canvas); + tc->is_drawing = false; + + if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { + if (!tc->has_dilated) { + // if we did not rub, do a light tap + tc->pressure = 0.03; + sp_spray_dilate(tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); + } + tc->is_dilating = false; + tc->has_dilated = false; + switch (tc->mode) { + case SPRAY_MODE_COPY: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_SPRAY, _("Spray with copies")); + break; + case SPRAY_MODE_CLONE: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_SPRAY, _("Spray with clones")); + break; + case SPRAY_MODE_SINGLE_PATH: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_SPRAY, _("Spray in single path")); + break; + } } break; - case GDK_Down: - case GDK_KP_Down: - if (!MOD__CTRL_ONLY) { - - tc->scale -= 0.05; - if (tc->scale < 0.0) - tc->scale = 0.0; - //desktop->setToolboxAdjustmentValue ("spray-force", tc->force * 100); - - ret = TRUE; + } - } - break; - case GDK_Right: - case GDK_KP_Right: - if (!MOD__CTRL_ONLY) { - tc->width += 0.01; - if (tc->width > 1.0) - tc->width = 1.0; - desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); // the same spinbutton is for alt+x - sp_spray_update_area(tc); - ret = TRUE; - } - break; - case GDK_Left: - case GDK_KP_Left: - if (!MOD__CTRL_ONLY) { - tc->width -= 0.01; - if (tc->width < 0.01) + case GDK_KEY_PRESS: + switch (get_group0_keyval (&event->key)) { + case GDK_j: + case GDK_J: + if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_k: + case GDK_K: + if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_l: + case GDK_L: + if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_Up: + case GDK_KP_Up: + if (!MOD__CTRL_ONLY) { + tc->population += 0.01; + if (tc->population > 1.0) { + tc->population = 1.0; + } + desktop->setToolboxAdjustmentValue("spray-population", tc->population * 100); + ret = TRUE; + } + break; + case GDK_Down: + case GDK_KP_Down: + if (!MOD__CTRL_ONLY) { + tc->population -= 0.01; + if (tc->population < 0.0) { + tc->population = 0.0; + } + desktop->setToolboxAdjustmentValue("spray-population", tc->population * 100); + ret = TRUE; + } + break; + case GDK_Right: + case GDK_KP_Right: + if (!MOD__CTRL_ONLY) { + tc->width += 0.01; + if (tc->width > 1.0) { + tc->width = 1.0; + } + // the same spinbutton is for alt+x + desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); + sp_spray_update_area(tc); + ret = TRUE; + } + break; + case GDK_Left: + case GDK_KP_Left: + if (!MOD__CTRL_ONLY) { + tc->width -= 0.01; + if (tc->width < 0.01) { + tc->width = 0.01; + } + desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); + sp_spray_update_area(tc); + ret = TRUE; + } + break; + case GDK_Home: + case GDK_KP_Home: tc->width = 0.01; - desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); - sp_spray_update_area(tc); - ret = TRUE; + desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); + sp_spray_update_area(tc); + ret = TRUE; + break; + case GDK_End: + case GDK_KP_End: + tc->width = 1.0; + desktop->setToolboxAdjustmentValue("altx-spray", tc->width * 100); + sp_spray_update_area(tc); + ret = TRUE; + break; + case GDK_x: + case GDK_X: + if (MOD__ALT_ONLY) { + desktop->setToolboxFocusTo("altx-spray"); + ret = TRUE; + } + break; + case GDK_Shift_L: + case GDK_Shift_R: + sp_spray_update_cursor(tc, true); + break; + case GDK_Control_L: + case GDK_Control_R: + break; + default: + break; } break; - case GDK_Home: - case GDK_KP_Home: - tc->width = 0.01; - desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); - sp_spray_update_area(tc); - ret = TRUE; - break; - case GDK_End: - case GDK_KP_End: - tc->width = 1.0; - desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); - sp_spray_update_area(tc); - ret = TRUE; - break; - case GDK_x: - case GDK_X: - if (MOD__ALT_ONLY) { - desktop->setToolboxFocusTo ("altx-spray"); - ret = TRUE; + + case GDK_KEY_RELEASE: { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + switch (get_group0_keyval(&event->key)) { + case GDK_Shift_L: + case GDK_Shift_R: + sp_spray_update_cursor(tc, false); + break; + case GDK_Control_L: + case GDK_Control_R: + sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT); + tc->_message_context->clear(); + break; + default: + sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT); + break; } - break; + } - case GDK_Shift_L: - case GDK_Shift_R: - sp_spray_update_cursor(tc, true); - break; -/*Set the scale to 1*/ - case GDK_Control_L: - tc->scale=1; default: break; - } - break; - - case GDK_KEY_RELEASE: { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - switch (get_group0_keyval(&event->key)) { - case GDK_Shift_L: - case GDK_Shift_R: - sp_spray_update_cursor(tc, false); - break; - case GDK_Control_L: - case GDK_Control_R: - sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT); - tc->_message_context->clear(); - break; - default: - sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT); - break; - } - } - - default: - break; } if (!ret) { diff --git a/src/spray-context.h b/src/spray-context.h index b559fa593..c485a6a96 100644 --- a/src/spray-context.h +++ b/src/spray-context.h @@ -19,7 +19,6 @@ */ #include "event-context.h" -#include <display/display-forward.h> #include <libnr/nr-point.h> //#include "ui/widget/spray-option.h" #include "ui/dialog/dialog.h" @@ -92,11 +91,6 @@ struct SPSprayContext Geom::Point last_push; SPCanvasItem *dilate_area; - bool do_h; - bool do_s; - bool do_l; - bool do_o; - sigc::connection style_set_connection; }; diff --git a/src/star-context.h b/src/star-context.h index 024bf8d74..3bc8ca386 100644 --- a/src/star-context.h +++ b/src/star-context.h @@ -14,6 +14,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <stddef.h> #include <sigc++/sigc++.h> #include "event-context.h" #include "libnr/nr-point.h" diff --git a/src/style.cpp b/src/style.cpp index d254ab6f4..bb25a5f46 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -568,7 +568,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) { g_assert(style != NULL); g_assert(repr != NULL); - g_assert(!object || (SP_OBJECT_REPR(object) == repr)); + g_assert(!object || (object->getRepr() == repr)); sp_style_clear(style); @@ -652,7 +652,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) val = repr->attribute("color"); if (val) { sp_style_read_icolor(&style->color, val, style, ( object - ? SP_OBJECT_DOCUMENT(object) + ? object->document : NULL )); } } @@ -660,7 +660,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) if (!style->fill.set) { val = repr->attribute("fill"); if (val) { - style->fill.read( val, *style, (object) ? SP_OBJECT_DOCUMENT(object) : NULL ); + style->fill.read( val, *style, (object) ? object->document : NULL ); } } /* fill-opacity */ @@ -676,7 +676,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) if (!style->stroke.set) { val = repr->attribute("stroke"); if (val) { - style->stroke.read( val, *style, (object) ? SP_OBJECT_DOCUMENT(object) : NULL ); + style->stroke.read( val, *style, (object) ? object->document : NULL ); } } SPS_READ_PLENGTH_IF_UNSET(&style->stroke_width, repr, "stroke-width"); @@ -762,7 +762,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) if (!style->filter.set) { val = repr->attribute("filter"); if (val) { - sp_style_read_ifilter(val, style, (object) ? SP_OBJECT_DOCUMENT(object) : NULL); + sp_style_read_ifilter(val, style, (object) ? object->document : NULL); } } SPS_READ_PENUM_IF_UNSET(&style->enable_background, repr, @@ -771,7 +771,7 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) /* 3. Merge from parent */ if (object) { if (object->parent) { - sp_style_merge_from_parent(style, SP_OBJECT_STYLE(object->parent)); + sp_style_merge_from_parent(style, object->parent->style); } } else { if (sp_repr_parent(repr)) { @@ -799,7 +799,7 @@ sp_style_read_from_object(SPStyle *style, SPObject *object) g_return_if_fail(object != NULL); g_return_if_fail(SP_IS_OBJECT(object)); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(object); + Inkscape::XML::Node *repr = object->getRepr(); g_return_if_fail(repr != NULL); sp_style_read(style, object, repr); @@ -987,7 +987,7 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) break; case SP_PROP_COLOR: if (!style->color.set) { - sp_style_read_icolor(&style->color, val, style, (style->object) ? SP_OBJECT_DOCUMENT(style->object) : NULL); + sp_style_read_icolor(&style->color, val, style, (style->object) ? style->object->document : NULL); } break; case SP_PROP_CURSOR: @@ -1044,7 +1044,7 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) /* Filter */ case SP_PROP_FILTER: if (!style->filter.set && !style->filter.inherit) { - sp_style_read_ifilter(val, style, (style->object) ? SP_OBJECT_DOCUMENT(style->object) : NULL); + sp_style_read_ifilter(val, style, (style->object) ? style->object->document : NULL); } break; case SP_PROP_FLOOD_COLOR: @@ -1085,7 +1085,7 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) } case SP_PROP_FILL: if (!style->fill.set) { - style->fill.read( val, *style, (style->object) ? SP_OBJECT_DOCUMENT(style->object) : NULL ); + style->fill.read( val, *style, (style->object) ? style->object->document : NULL ); } break; case SP_PROP_FILL_OPACITY: @@ -1152,7 +1152,7 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) case SP_PROP_STROKE: if (!style->stroke.set) { - style->stroke.read( val, *style, (style->object) ? SP_OBJECT_DOCUMENT(style->object) : NULL ); + style->stroke.read( val, *style, (style->object) ? style->object->document : NULL ); } break; case SP_PROP_STROKE_WIDTH: @@ -2274,8 +2274,8 @@ sp_style_merge_ifilter(SPStyle *style, SPIFilter const *parent) style->filter.href->detach(); // it may be that this style has not yet created its SPFilterReference - if (!style->filter.href && style->object && SP_OBJECT_DOCUMENT(style->object)) { - style->filter.href = new SPFilterReference(SP_OBJECT_DOCUMENT(style->object)); + if (!style->filter.href && style->object && style->object->document) { + style->filter.href = new SPFilterReference(style->object->document); style->filter.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style)); } @@ -4071,7 +4071,7 @@ sp_style_filter_clear(SPStyle *style) void sp_style_set_property_url (SPObject *item, gchar const *property, SPObject *linked, bool recursive) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(item); + Inkscape::XML::Node *repr = item->getRepr(); if (repr == NULL) return; @@ -4099,13 +4099,19 @@ sp_style_set_property_url (SPObject *item, gchar const *property, SPObject *link void sp_style_unset_property_attrs(SPObject *o) { - if (!o) return; + if (!o) { + return; + } - SPStyle *style = SP_OBJECT_STYLE(o); - if (!style) return; + SPStyle *style = o->style; + if (!style) { + return; + } - Inkscape::XML::Node *repr = SP_OBJECT_REPR(o); - if (!repr) return; + Inkscape::XML::Node *repr = o->getRepr(); + if (!repr) { + return; + } if (style->opacity.set) { repr->setAttribute("opacity", NULL); @@ -4198,16 +4204,16 @@ sp_css_attr_from_style(SPStyle const *const style, guint const flags) * \pre object != NULL * \pre flags in {IFSET, ALWAYS}. */ -SPCSSAttr * -sp_css_attr_from_object(SPObject *object, guint const flags) +SPCSSAttr *sp_css_attr_from_object(SPObject *object, guint const flags) { g_return_val_if_fail(((flags == SP_STYLE_FLAG_IFSET) || (flags == SP_STYLE_FLAG_ALWAYS) ), NULL); - SPStyle const *const style = SP_OBJECT_STYLE(object); - if (style == NULL) - return NULL; - return sp_css_attr_from_style(style, flags); + SPCSSAttr * result = 0; + if (object->style) { + result = sp_css_attr_from_style(object->style, flags); + } + return result; } /** diff --git a/src/style.h b/src/style.h index b4663e8f6..70e84ab42 100644 --- a/src/style.h +++ b/src/style.h @@ -24,6 +24,7 @@ #include "uri.h" #include "sp-paint-server.h" +#include <stddef.h> #include <sigc++/connection.h> namespace Inkscape { diff --git a/src/svg-view-widget.cpp b/src/svg-view-widget.cpp index d2a31966a..777c1b496 100644 --- a/src/svg-view-widget.cpp +++ b/src/svg-view-widget.cpp @@ -5,7 +5,9 @@ * Lauris Kaplinski <lauris@kaplinski.com> * Ralf Stephan <ralf@ark.in-berlin.de> * Abhishek Sharma + * Jon A. Cruz <jon@joncruz.org> * + * Copyright (C) 2010 authors * Copyright (C) 2001-2002 Lauris Kaplinski * Copyright (C) 2001 Ximian, Inc. * @@ -13,6 +15,8 @@ */ #include <gtk/gtkscrolledwindow.h> +#include "display/sp-canvas.h" +#include "display/sp-canvas-group.h" #include "display/canvas-arena.h" #include "document.h" #include "svg-view.h" @@ -220,22 +224,18 @@ sp_svg_view_widget_new (SPDocument *doc) /** * Flags the SPSVGSPViewWidget to have its size renegotiated with Gtk. */ -void -sp_svg_view_widget_set_resize (SPSVGSPViewWidget *vw, bool resize, gdouble width, gdouble height) +void SPSVGSPViewWidget::setResize(bool resize, gdouble width, gdouble height) { - g_return_if_fail (vw != NULL); + g_return_if_fail( !resize || (width > 0.0) ); + g_return_if_fail( !resize || (height > 0.0) ); - g_return_if_fail (SP_IS_SVG_VIEW_WIDGET (vw)); - g_return_if_fail (!resize || (width > 0.0)); - g_return_if_fail (!resize || (height > 0.0)); + this->resize = resize; + this->maxwidth = width; + this->maxheight = height; - vw->resize = resize; - vw->maxwidth = width; - vw->maxheight = height; - - if (resize) { - gtk_widget_queue_resize (GTK_WIDGET (vw)); - } + if ( resize ) { + gtk_widget_queue_resize( GTK_WIDGET(this) ); + } } diff --git a/src/svg-view-widget.h b/src/svg-view-widget.h index cd609b07a..e732841c7 100644 --- a/src/svg-view-widget.h +++ b/src/svg-view-widget.h @@ -1,19 +1,20 @@ -#ifndef __SP_SVG_VIEW_WIDGET_H__ -#define __SP_SVG_VIEW_WIDGET_H__ +#ifndef SEEN_SP_SVG_VIEW_WIDGET_H +#define SEEN_SP_SVG_VIEW_WIDGET_H /** \file * SPSVGView, SPSVGSPViewWidget: Generic SVG view and widget * * Authors: * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> * + * Copyright (C) 2010 Authors * Copyright (C) 2001-2002 Lauris Kaplinski * Copyright (C) 2001 Ximian, Inc. * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "display/display-forward.h" #include "ui/view/view-widget.h" class SPDocument; @@ -30,33 +31,39 @@ GtkType sp_svg_view_widget_get_type (void); GtkWidget *sp_svg_view_widget_new (SPDocument *doc); -void sp_svg_view_widget_set_resize (SPSVGSPViewWidget *vw, bool resize, gdouble width, gdouble height); - /** * An SPSVGSPViewWidget is an SVG view together with a canvas. */ struct SPSVGSPViewWidget { - public: - SPViewWidget widget; +public: + SPViewWidget widget; - GtkWidget *sw; - GtkWidget *canvas; + GtkWidget *sw; + GtkWidget *canvas; - /// Whether to resize automatically - bool resize; - gdouble maxwidth, maxheight; + /// Whether to resize automatically + bool resize; + gdouble maxwidth, maxheight; // C++ Wrappers /// Flags the SPSVGSPViewWidget to have its size changed with Gtk. - void setResize(bool resize, gdouble width, gdouble height) { - sp_svg_view_widget_set_resize(this, resize, width, height); - } + void setResize(bool resize, gdouble width, gdouble height); }; /// The SPSVGSPViewWidget vtable. struct SPSVGSPViewWidgetClass { - SPViewWidgetClass parent_class; + SPViewWidgetClass parent_class; }; -#endif +#endif // SEEN_SP_SVG_VIEW_WIDGET_H +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/svg-view.cpp b/src/svg-view.cpp index ef87b38ef..b35375736 100644 --- a/src/svg-view.cpp +++ b/src/svg-view.cpp @@ -14,7 +14,6 @@ */ #include "display/canvas-arena.h" -#include "display/display-forward.h" #include "document.h" #include "sp-item.h" #include "svg-view.h" diff --git a/src/svg/svg-affine-test.h b/src/svg/svg-affine-test.h index be5a941bb..11b9012a8 100644 --- a/src/svg/svg-affine-test.h +++ b/src/svg/svg-affine-test.h @@ -2,7 +2,7 @@ #include "svg/svg.h" #include "streq.h" -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <algorithm> #include <glib.h> #include <iostream> @@ -14,10 +14,10 @@ class SvgAffineTest : public CxxTest::TestSuite private: struct test_t { char const * str; - Geom::Matrix matrix; + Geom::Affine matrix; }; struct approx_equal_pred { - bool operator()(Geom::Matrix const &ref, Geom::Matrix const &cm) const + bool operator()(Geom::Affine const &ref, Geom::Affine const &cm) const { double maxabsdiff = 0; for(size_t i=0; i<6; i++) { @@ -59,7 +59,7 @@ public: "skewY(0)"}; size_t n = G_N_ELEMENTS(strs); for(size_t i=0; i<n; i++) { - Geom::Matrix cm; + Geom::Affine cm; TSM_ASSERT(strs[i] , sp_svg_transform_read(strs[i], &cm)); TSM_ASSERT_EQUALS(strs[i] , Geom::identity() , cm); } @@ -73,7 +73,7 @@ public: void testReadMatrix() { for(size_t i=0; i<G_N_ELEMENTS(read_matrix_tests); i++) { - Geom::Matrix cm; + Geom::Affine cm; TSM_ASSERT(read_matrix_tests[i].str , sp_svg_transform_read(read_matrix_tests[i].str, &cm)); TSM_ASSERT_RELATION(read_matrix_tests[i].str , approx_equal_pred , read_matrix_tests[i].matrix , cm); } @@ -82,7 +82,7 @@ public: void testReadTranslate() { for(size_t i=0; i<G_N_ELEMENTS(read_translate_tests); i++) { - Geom::Matrix cm; + Geom::Affine cm; TSM_ASSERT(read_translate_tests[i].str , sp_svg_transform_read(read_translate_tests[i].str, &cm)); TSM_ASSERT_RELATION(read_translate_tests[i].str , approx_equal_pred , read_translate_tests[i].matrix , cm); } @@ -91,7 +91,7 @@ public: void testReadScale() { for(size_t i=0; i<G_N_ELEMENTS(read_scale_tests); i++) { - Geom::Matrix cm; + Geom::Affine cm; TSM_ASSERT(read_scale_tests[i].str , sp_svg_transform_read(read_scale_tests[i].str, &cm)); TSM_ASSERT_RELATION(read_scale_tests[i].str , approx_equal_pred , read_scale_tests[i].matrix , cm); } @@ -100,7 +100,7 @@ public: void testReadRotate() { for(size_t i=0; i<G_N_ELEMENTS(read_rotate_tests); i++) { - Geom::Matrix cm; + Geom::Affine cm; TSM_ASSERT(read_rotate_tests[i].str , sp_svg_transform_read(read_rotate_tests[i].str, &cm)); TSM_ASSERT_RELATION(read_rotate_tests[i].str , approx_equal_pred , read_rotate_tests[i].matrix , cm); } @@ -109,7 +109,7 @@ public: void testReadSkew() { for(size_t i=0; i<G_N_ELEMENTS(read_skew_tests); i++) { - Geom::Matrix cm; + Geom::Affine cm; TSM_ASSERT(read_skew_tests[i].str , sp_svg_transform_read(read_skew_tests[i].str, &cm)); TSM_ASSERT_RELATION(read_skew_tests[i].str , approx_equal_pred , read_skew_tests[i].matrix , cm); } @@ -166,8 +166,8 @@ public: // there should be 1 or more comma-wsp sequences between transforms... This doesn't make sense and it seems // likely that instead of a + they meant a ? (zero or one comma-wsp sequences). char const * str = "skewY(17)skewX(9)translate(7,13)scale(2)rotate(13)translate(3,5)"; - Geom::Matrix ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica - Geom::Matrix cm; + Geom::Affine ref(2.0199976232558053, 1.0674773585906016, -0.14125199392774669, 1.9055550612095459, 14.412730624347654, 28.499820929377454); // Precomputed using Mathematica + Geom::Affine cm; TS_ASSERT(sp_svg_transform_read(str, &cm)); TS_ASSERT_RELATION(approx_equal_pred , ref , cm); } @@ -175,7 +175,7 @@ public: void testReadFailures() { for(size_t i=0; i<G_N_ELEMENTS(read_fail_tests); i++) { - Geom::Matrix cm; + Geom::Affine cm; TSM_ASSERT(read_fail_tests[i] , !sp_svg_transform_read(read_fail_tests[i], &cm)); } } @@ -184,26 +184,26 @@ public: static double const DEGREE = M_PI/180.; SvgAffineTest::test_t const SvgAffineTest::read_matrix_tests[3] = { - {"matrix(0,0,0,0,0,0)",Geom::Matrix(0,0,0,0,0,0)}, - {" matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)}, - {"matrix (1 2 -3,-4,5e6,-6e-7)",Geom::Matrix(1,2,-3,-4,5e6,-6e-7)}}; + {"matrix(0,0,0,0,0,0)",Geom::Affine(0,0,0,0,0,0)}, + {" matrix(1,2,3,4,5,6)",Geom::Affine(1,2,3,4,5,6)}, + {"matrix (1 2 -3,-4,5e6,-6e-7)",Geom::Affine(1,2,-3,-4,5e6,-6e-7)}}; SvgAffineTest::test_t const SvgAffineTest::read_translate_tests[3] = { - {"translate(1)",Geom::Matrix(1,0,0,1,1,0)}, - {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)}, - {"translate(-1e3 .123e2)",Geom::Matrix(1,0,0,1,-1e3,.123e2)}}; + {"translate(1)",Geom::Affine(1,0,0,1,1,0)}, + {"translate(1,1)",Geom::Affine(1,0,0,1,1,1)}, + {"translate(-1e3 .123e2)",Geom::Affine(1,0,0,1,-1e3,.123e2)}}; SvgAffineTest::test_t const SvgAffineTest::read_scale_tests[3] = { - {"scale(2)",Geom::Matrix(2,0,0,2,0,0)}, - {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)}, - {"scale(0.1e-2 -.475e0)",Geom::Matrix(0.1e-2,0,0,-.475e0,0,0)}}; + {"scale(2)",Geom::Affine(2,0,0,2,0,0)}, + {"scale(2,3)",Geom::Affine(2,0,0,3,0,0)}, + {"scale(0.1e-2 -.475e0)",Geom::Affine(0.1e-2,0,0,-.475e0,0,0)}}; SvgAffineTest::test_t const SvgAffineTest::read_rotate_tests[4] = { - {"rotate(13 )",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, - {"rotate(-13)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),0,0)}, - {"rotate(373)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, - {"rotate(13,7,11)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),(1-cos(13.*DEGREE))*7+sin(13.*DEGREE)*11,(1-cos(13.*DEGREE))*11-sin(13.*DEGREE)*7)}}; + {"rotate(13 )",Geom::Affine(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, + {"rotate(-13)",Geom::Affine(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),0,0)}, + {"rotate(373)",Geom::Affine(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, + {"rotate(13,7,11)",Geom::Affine(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),(1-cos(13.*DEGREE))*7+sin(13.*DEGREE)*11,(1-cos(13.*DEGREE))*11-sin(13.*DEGREE)*7)}}; SvgAffineTest::test_t const SvgAffineTest::read_skew_tests[3] = { - {"skewX( 30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)}, - {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)}, - {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}}; + {"skewX( 30)",Geom::Affine(1,0,tan(30.*DEGREE),1,0,0)}, + {"skewX(-30)",Geom::Affine(1,0,tan(-30.*DEGREE),1,0,0)}, + {"skewY(390)",Geom::Affine(1,tan(30.*DEGREE),0,1,0,0)}}; char const * const SvgAffineTest::read_fail_tests[25] = { "matrix((1,2,3,4,5,6)", "matrix((1,2,3,4,5,6))", @@ -232,22 +232,22 @@ char const * const SvgAffineTest::read_fail_tests[25] = { "skewY(1,2)"}; SvgAffineTest::test_t const SvgAffineTest::write_matrix_tests[2] = { - {"matrix(1,2,3,4,5,6)",Geom::Matrix(1,2,3,4,5,6)}, - {"matrix(-1,2123,3,0.4,1e-8,1e20)",Geom::Matrix(-1,2.123e3,3+1e-14,0.4,1e-8,1e20)}}; + {"matrix(1,2,3,4,5,6)",Geom::Affine(1,2,3,4,5,6)}, + {"matrix(-1,2123,3,0.4,1e-8,1e20)",Geom::Affine(-1,2.123e3,3+1e-14,0.4,1e-8,1e20)}}; SvgAffineTest::test_t const SvgAffineTest::write_translate_tests[3] = { - {"translate(1,1)",Geom::Matrix(1,0,0,1,1,1)}, - {"translate(1)",Geom::Matrix(1,0,0,1,1,0)}, - {"translate(-1345,0.123)",Geom::Matrix(1,0,0,1,-1.345e3,.123)}}; + {"translate(1,1)",Geom::Affine(1,0,0,1,1,1)}, + {"translate(1)",Geom::Affine(1,0,0,1,1,0)}, + {"translate(-1345,0.123)",Geom::Affine(1,0,0,1,-1.345e3,.123)}}; SvgAffineTest::test_t const SvgAffineTest::write_scale_tests[2] = { - {"scale(0)",Geom::Matrix(0,0,0,0,0,0)}, - {"scale(2,3)",Geom::Matrix(2,0,0,3,0,0)}}; + {"scale(0)",Geom::Affine(0,0,0,0,0,0)}, + {"scale(2,3)",Geom::Affine(2,0,0,3,0,0)}}; SvgAffineTest::test_t const SvgAffineTest::write_rotate_tests[2] = { - {"rotate(13)",Geom::Matrix(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, - {"rotate(-13,7,11)",Geom::Matrix(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),(1-cos(-13.*DEGREE))*7+sin(-13.*DEGREE)*11,(1-cos(-13.*DEGREE))*11-sin(-13.*DEGREE)*7)}}; + {"rotate(13)",Geom::Affine(cos(13.*DEGREE),sin(13.*DEGREE),-sin(13.*DEGREE),cos(13.*DEGREE),0,0)}, + {"rotate(-13,7,11)",Geom::Affine(cos(-13.*DEGREE),sin(-13.*DEGREE),-sin(-13.*DEGREE),cos(-13.*DEGREE),(1-cos(-13.*DEGREE))*7+sin(-13.*DEGREE)*11,(1-cos(-13.*DEGREE))*11-sin(-13.*DEGREE)*7)}}; SvgAffineTest::test_t const SvgAffineTest::write_skew_tests[3] = { - {"skewX(30)",Geom::Matrix(1,0,tan(30.*DEGREE),1,0,0)}, - {"skewX(-30)",Geom::Matrix(1,0,tan(-30.*DEGREE),1,0,0)}, - {"skewY(390)",Geom::Matrix(1,tan(30.*DEGREE),0,1,0,0)}}; + {"skewX(30)",Geom::Affine(1,0,tan(30.*DEGREE),1,0,0)}, + {"skewX(-30)",Geom::Affine(1,0,tan(-30.*DEGREE),1,0,0)}, + {"skewY(390)",Geom::Affine(1,tan(30.*DEGREE),0,1,0,0)}}; /* Local Variables: diff --git a/src/svg/svg-affine.cpp b/src/svg/svg-affine.cpp index b61d09a79..a986e5986 100644 --- a/src/svg/svg-affine.cpp +++ b/src/svg/svg-affine.cpp @@ -30,7 +30,7 @@ #endif bool -sp_svg_transform_read(gchar const *str, Geom::Matrix *transform) +sp_svg_transform_read(gchar const *str, Geom::Affine *transform) { int idx; char keyword[32]; @@ -40,7 +40,7 @@ sp_svg_transform_read(gchar const *str, Geom::Matrix *transform) if (str == NULL) return false; - Geom::Matrix a(Geom::identity()); + Geom::Affine a(Geom::identity()); idx = 0; while (str[idx]) { @@ -100,7 +100,7 @@ sp_svg_transform_read(gchar const *str, Geom::Matrix *transform) /* ok, have parsed keyword and args, now modify the transform */ if (!strcmp (keyword, "matrix")) { if (n_args != 6) return false; - a = (*((Geom::Matrix *) &(args)[0])) * a; + a = (*((Geom::Affine *) &(args)[0])) * a; } else if (!strcmp (keyword, "translate")) { if (n_args == 1) { args[1] = 0; @@ -124,19 +124,19 @@ sp_svg_transform_read(gchar const *str, Geom::Matrix *transform) a = ( Geom::Translate(-args[1], -args[2]) * rot * Geom::Translate(args[1], args[2]) - * Geom::Matrix(a) ); + * Geom::Affine(a) ); } else { a = rot * a; } } else if (!strcmp (keyword, "skewX")) { if (n_args != 1) return false; - a = ( Geom::Matrix(1, 0, + a = ( Geom::Affine(1, 0, tan(args[0] * M_PI / 180.0), 1, 0, 0) * a ); } else if (!strcmp (keyword, "skewY")) { if (n_args != 1) return false; - a = ( Geom::Matrix(1, tan(args[0] * M_PI / 180.0), + a = ( Geom::Affine(1, tan(args[0] * M_PI / 180.0), 0, 1, 0, 0) * a ); @@ -154,7 +154,7 @@ sp_svg_transform_read(gchar const *str, Geom::Matrix *transform) #define EQ(a,b) (fabs ((a) - (b)) < 1e-9) gchar * -sp_svg_transform_write(Geom::Matrix const &transform) +sp_svg_transform_write(Geom::Affine const &transform) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -243,7 +243,7 @@ sp_svg_transform_write(Geom::Matrix const &transform) gchar * -sp_svg_transform_write(Geom::Matrix const *transform) +sp_svg_transform_write(Geom::Affine const *transform) { return sp_svg_transform_write(*transform); } diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp index 22af18acb..8781d75e6 100644 --- a/src/svg/svg-path.cpp +++ b/src/svg/svg-path.cpp @@ -93,9 +93,9 @@ static void sp_svg_write_curve(Inkscape::SVG::PathString & str, Geom::Curve cons (*cubic_bezier)[3][0], (*cubic_bezier)[3][1] ); } else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast<Geom::SVGEllipticalArc const *>(c)) { - str.arcTo( svg_elliptical_arc->ray(0), svg_elliptical_arc->ray(1), - Geom::rad_to_deg(svg_elliptical_arc->rotation_angle()), - svg_elliptical_arc->large_arc_flag(), svg_elliptical_arc->sweep_flag(), + str.arcTo( svg_elliptical_arc->ray(Geom::X), svg_elliptical_arc->ray(Geom::Y), + Geom::rad_to_deg(svg_elliptical_arc->rotationAngle()), + svg_elliptical_arc->largeArc(), svg_elliptical_arc->sweep(), svg_elliptical_arc->finalPoint() ); } else if(Geom::HLineSegment const *hline_segment = dynamic_cast<Geom::HLineSegment const *>(c)) { diff --git a/src/svg/svg.h b/src/svg/svg.h index 237a5d348..d5335e1b4 100644 --- a/src/svg/svg.h +++ b/src/svg/svg.h @@ -54,10 +54,10 @@ unsigned int sp_svg_length_read_ldd( const gchar *str, SVGLength::Unit *unit, do std::string sp_svg_length_write_with_units(SVGLength const &length); -bool sp_svg_transform_read(gchar const *str, Geom::Matrix *transform); +bool sp_svg_transform_read(gchar const *str, Geom::Affine *transform); -gchar *sp_svg_transform_write(Geom::Matrix const &transform); -gchar *sp_svg_transform_write(Geom::Matrix const *transform); +gchar *sp_svg_transform_write(Geom::Affine const &transform); +gchar *sp_svg_transform_write(Geom::Affine const *transform); double sp_svg_read_percentage( const char * str, double def ); diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index 81737c890..873c214a7 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -129,12 +129,12 @@ text_put_on_path() if (!repr) return; - Inkscape::XML::Node *parent = SP_OBJECT_REPR(text)->parent(); + Inkscape::XML::Node *parent = text->getRepr()->parent(); parent->appendChild(repr); SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); new_item->doWriteTransform(repr, text->transform); - SP_OBJECT(new_item)->updateRepr(); + new_item->updateRepr(); Inkscape::GC::release(repr); text->deleteObject(); // delete the orignal flowtext @@ -151,23 +151,24 @@ text_put_on_path() // remove transform from text, but recursively scale text's fontsize by the expansion SP_TEXT(text)->_adjustFontsizeRecursive (text, SP_ITEM(text)->transform.descrim()); - SP_OBJECT_REPR(text)->setAttribute("transform", NULL); + text->getRepr()->setAttribute("transform", NULL); // make a list of text children GSList *text_reprs = NULL; - for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) { - text_reprs = g_slist_prepend(text_reprs, SP_OBJECT_REPR(o)); + for (SPObject *o = text->children; o != NULL; o = o->next) { + text_reprs = g_slist_prepend(text_reprs, o->getRepr()); } // create textPath and put it into the text Inkscape::XML::Node *textpath = xml_doc->createElement("svg:textPath"); // reference the shape - textpath->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(shape)->attribute("id"))); - if (text_alignment == Inkscape::Text::Layout::RIGHT) + textpath->setAttribute("xlink:href", g_strdup_printf("#%s", shape->getRepr()->attribute("id"))); + if (text_alignment == Inkscape::Text::Layout::RIGHT) { textpath->setAttribute("startOffset", "100%"); - else if (text_alignment == Inkscape::Text::Layout::CENTER) + } else if (text_alignment == Inkscape::Text::Layout::CENTER) { textpath->setAttribute("startOffset", "50%"); - SP_OBJECT_REPR(text)->addChild(textpath, NULL); + } + text->getRepr()->addChild(textpath, NULL); for ( GSList *i = text_reprs ; i ; i = i->next ) { // Make a copy of each text child @@ -179,14 +180,14 @@ text_put_on_path() copy->setAttribute("y", NULL); } // remove the old repr from under text - SP_OBJECT_REPR(text)->removeChild((Inkscape::XML::Node *) i->data); + text->getRepr()->removeChild(reinterpret_cast<Inkscape::XML::Node *>(i->data)); // put its copy into under textPath textpath->addChild(copy, NULL); // fixme: copy id } // x/y are useless with textpath, and confuse Batik 1.5 - SP_OBJECT_REPR(text)->setAttribute("x", NULL); - SP_OBJECT_REPR(text)->setAttribute("y", NULL); + text->getRepr()->setAttribute("x", NULL); + text->getRepr()->setAttribute("y", NULL); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Put text on path")); @@ -210,16 +211,15 @@ text_remove_from_path() for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; items = items->next) { + SPObject *obj = SP_OBJECT(items->data); - if (!SP_IS_TEXT_TEXTPATH(SP_OBJECT(items->data))) { - continue; - } - - SPObject *tp = SP_OBJECT(items->data)->firstChild(); + if (SP_IS_TEXT_TEXTPATH(obj)) { + SPObject *tp = obj->firstChild(); - did = true; + did = true; - sp_textpath_to_text(tp); + sp_textpath_to_text(tp); + } } if (!did) { @@ -234,19 +234,19 @@ text_remove_from_path() void text_remove_all_kerns_recursively(SPObject *o) { - SP_OBJECT_REPR(o)->setAttribute("dx", NULL); - SP_OBJECT_REPR(o)->setAttribute("dy", NULL); - SP_OBJECT_REPR(o)->setAttribute("rotate", NULL); + o->getRepr()->setAttribute("dx", NULL); + o->getRepr()->setAttribute("dy", NULL); + o->getRepr()->setAttribute("rotate", NULL); // if x contains a list, leave only the first value - gchar *x = (gchar *) SP_OBJECT_REPR(o)->attribute("x"); + gchar const *x = o->getRepr()->attribute("x"); if (x) { gchar **xa_space = g_strsplit(x, " ", 0); gchar **xa_comma = g_strsplit(x, ",", 0); if (xa_space && *xa_space && *(xa_space + 1)) { - SP_OBJECT_REPR(o)->setAttribute("x", g_strdup(*xa_space)); + o->getRepr()->setAttribute("x", g_strdup(*xa_space)); } else if (xa_comma && *xa_comma && *(xa_comma + 1)) { - SP_OBJECT_REPR(o)->setAttribute("x", g_strdup(*xa_comma)); + o->getRepr()->setAttribute("x", g_strdup(*xa_comma)); } g_strfreev(xa_space); g_strfreev(xa_comma); @@ -317,13 +317,13 @@ text_flow_into_shape() if (SP_IS_TEXT(text)) { // remove transform from text, but recursively scale text's fontsize by the expansion SP_TEXT(text)->_adjustFontsizeRecursive(text, SP_ITEM(text)->transform.descrim()); - SP_OBJECT_REPR(text)->setAttribute("transform", NULL); + text->getRepr()->setAttribute("transform", NULL); } Inkscape::XML::Node *root_repr = xml_doc->createElement("svg:flowRoot"); root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create - root_repr->setAttribute("style", SP_OBJECT_REPR(text)->attribute("style")); // fixme: transfer style attrs too - SP_OBJECT_REPR(SP_OBJECT_PARENT(shape))->appendChild(root_repr); + root_repr->setAttribute("style", text->getRepr()->attribute("style")); // fixme: transfer style attrs too + shape->parent->getRepr()->appendChild(root_repr); SPObject *root_object = doc->getObjectByRepr(root_repr); g_return_if_fail(SP_IS_FLOWTEXT(root_object)); @@ -341,7 +341,7 @@ text_flow_into_shape() Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); clone->setAttribute("x", "0"); clone->setAttribute("y", "0"); - clone->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(item)->attribute("id"))); + clone->setAttribute("xlink:href", g_strdup_printf("#%s", item->getRepr()->attribute("id"))); // add the new clone to the region region_repr->appendChild(clone); @@ -364,9 +364,9 @@ text_flow_into_shape() Inkscape::GC::release(text_repr); } else { // reflow an already flowed text, preserving paras - for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) { + for (SPObject *o = text->children; o != NULL; o = o->next) { if (SP_IS_FLOWPARA(o)) { - Inkscape::XML::Node *para_repr = SP_OBJECT_REPR(o)->duplicate(xml_doc); + Inkscape::XML::Node *para_repr = o->getRepr()->duplicate(xml_doc); root_repr->appendChild(para_repr); object = doc->getObjectByRepr(para_repr); g_return_if_fail(SP_IS_FLOWPARA(object)); @@ -375,7 +375,7 @@ text_flow_into_shape() } } - SP_OBJECT(text)->deleteObject (true); + text->deleteObject(true); DocumentUndo::done(doc, SP_VERB_CONTEXT_TEXT, _("Flow text into shape")); @@ -430,7 +430,7 @@ text_unflow () rtext->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create /* Set style */ - rtext->setAttribute("style", SP_OBJECT_REPR(flowtext)->attribute("style")); // fixme: transfer style attrs too; and from descendants + rtext->setAttribute("style", flowtext->getRepr()->attribute("style")); // fixme: transfer style attrs too; and from descendants Geom::OptRect bbox; SP_ITEM(flowtext)->invoke_bbox(bbox, SP_ITEM(flowtext)->i2doc_affine(), TRUE); @@ -450,7 +450,7 @@ text_unflow () free(text_string); rtspan->appendChild(text_repr); - SP_OBJECT_REPR(SP_OBJECT_PARENT(flowtext))->appendChild(rtext); + flowtext->parent->getRepr()->appendChild(rtext); SPObject *text_object = doc->getObjectByRepr(rtext); // restore the font size multiplier from the flowtext's transform @@ -514,12 +514,12 @@ flowtext_to_text() did = true; - Inkscape::XML::Node *parent = SP_OBJECT_REPR(item)->parent(); - parent->addChild(repr, SP_OBJECT_REPR(item)); + Inkscape::XML::Node *parent = item->getRepr()->parent(); + parent->addChild(repr, item->getRepr()); - SPItem *new_item = (SPItem *) sp_desktop_document(desktop)->getObjectByRepr(repr); + SPItem *new_item = reinterpret_cast<SPItem *>(sp_desktop_document(desktop)->getObjectByRepr(repr)); new_item->doWriteTransform(repr, item->transform); - SP_OBJECT(new_item)->updateRepr(); + new_item->updateRepr(); Inkscape::GC::release(repr); item->deleteObject(); diff --git a/src/text-context.cpp b/src/text-context.cpp index 66e5f9450..5af2c5ebc 100644 --- a/src/text-context.cpp +++ b/src/text-context.cpp @@ -721,7 +721,7 @@ sp_text_context_root_handler(SPEventContext *const event_context, GdkEvent *cons // otherwise even one line won't fit; most probably a slip of hand (even if bigger than tolerance) SPItem *ft = create_flowtext_with_internal_frame (desktop, tc->p0, p1); /* Set style */ - sp_desktop_apply_style_tool(desktop, SP_OBJECT_REPR(ft), "/tools/text", true); + sp_desktop_apply_style_tool(desktop, ft->getRepr(), "/tools/text", true); sp_desktop_selection(desktop)->set(ft); desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Flowed text is created.")); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, @@ -1526,11 +1526,13 @@ sp_text_context_style_set(SPCSSAttr const *css, SPTextContext *tc) static int sp_text_context_style_query(SPStyle *style, int property, SPTextContext *tc) { - if (tc->text == NULL) + if (tc->text == NULL) { return QUERY_STYLE_NOTHING; + } const Inkscape::Text::Layout *layout = te_get_layout(tc->text); - if (layout == NULL) + if (layout == NULL) { return QUERY_STYLE_NOTHING; + } sp_text_context_validate_cursor_iterators(tc); GSList *styles_list = NULL; @@ -1543,18 +1545,21 @@ sp_text_context_style_query(SPStyle *style, int property, SPTextContext *tc) begin_it = tc->text_sel_end; end_it = tc->text_sel_start; } - if (begin_it == end_it) - if (!begin_it.prevCharacter()) + if (begin_it == end_it) { + if (!begin_it.prevCharacter()) { end_it.nextCharacter(); + } + } for (Inkscape::Text::Layout::iterator it = begin_it ; it < end_it ; it.nextStartOfSpan()) { SPObject const *pos_obj = 0; void *rawptr = 0; layout->getSourceOfCharacter(it, &rawptr); - if (!rawptr || !SP_IS_OBJECT(rawptr)) + if (!rawptr || !SP_IS_OBJECT(rawptr)) { continue; + } pos_obj = SP_OBJECT(rawptr); - while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) { - pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style + while (SP_IS_STRING(pos_obj) && pos_obj->parent) { + pos_obj = pos_obj->parent; // SPStrings don't have style } styles_list = g_slist_prepend(styles_list, (gpointer)pos_obj); } @@ -1716,7 +1721,7 @@ sp_text_context_forget_text(SPTextContext *tc) */ /* if ((SP_IS_TEXT(ti) || SP_IS_FLOWTEXT(ti)) && sp_te_input_is_empty(ti)) { - Inkscape::XML::Node *text_repr=SP_OBJECT_REPR(ti); + Inkscape::XML::Node *text_repr = ti->getRepr(); // the repr may already have been unparented // if we were called e.g. as the result of // an undo or the element being removed from @@ -1756,7 +1761,7 @@ sptc_commit(GtkIMContext */*imc*/, gchar *string, SPTextContext *tc) sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); - DocumentUndo::done(SP_OBJECT_DOCUMENT(tc->text), SP_VERB_CONTEXT_TEXT, + DocumentUndo::done(tc->text->document, SP_VERB_CONTEXT_TEXT, _("Type text")); } diff --git a/src/text-context.h b/src/text-context.h index a6e2e8db7..ec1710da3 100644 --- a/src/text-context.h +++ b/src/text-context.h @@ -15,11 +15,11 @@ */ /* #include <gdk/gdkic.h> */ +#include <stddef.h> #include <sigc++/sigc++.h> #include <gtk/gtkimcontext.h> #include "event-context.h" -#include <display/display-forward.h> #include <2geom/point.h> #include "libnrtype/Layout-TNG.h" diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 4a9ccf1f3..18264fa56 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -87,7 +87,7 @@ bool sp_te_input_is_empty(SPObject const *item) Inkscape::Text::Layout::iterator sp_te_get_position_by_coords (SPItem const *item, Geom::Point const &i_p) { - Geom::Matrix im (item->i2d_affine ()); + Geom::Affine im (item->i2d_affine ()); im = im.inverse(); Geom::Point p = i_p * im; @@ -95,7 +95,7 @@ sp_te_get_position_by_coords (SPItem const *item, Geom::Point const &i_p) return layout->getNearestCursorPositionTo(p); } -std::vector<Geom::Point> sp_te_create_selection_quads(SPItem const *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, Geom::Matrix const &transform) +std::vector<Geom::Point> sp_te_create_selection_quads(SPItem const *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, Geom::Affine const &transform) { if (start == end) return std::vector<Geom::Point>(); @@ -118,23 +118,26 @@ sp_te_get_cursor_coords (SPItem const *item, Inkscape::Text::Layout::iterator co SPStyle const * sp_te_style_at_position(SPItem const *text, Inkscape::Text::Layout::iterator const &position) { SPObject const *pos_obj = sp_te_object_at_position(text, position); - if (pos_obj) - return SP_OBJECT_STYLE(pos_obj); - return NULL; + SPStyle *result = (pos_obj) ? pos_obj->style : 0; + return result; } SPObject const * sp_te_object_at_position(SPItem const *text, Inkscape::Text::Layout::iterator const &position) { Inkscape::Text::Layout const *layout = te_get_layout(text); - if (layout == NULL) + if (layout == NULL) { return NULL; + } SPObject const *pos_obj = 0; void *rawptr = 0; layout->getSourceOfCharacter(position, &rawptr); pos_obj = SP_OBJECT(rawptr); - if (pos_obj == 0) pos_obj = text; - while (SP_OBJECT_STYLE(pos_obj) == NULL) - pos_obj = SP_OBJECT_PARENT(pos_obj); // not interested in SPStrings + if (pos_obj == 0) { + pos_obj = text; + } + while (pos_obj->style == NULL) { + pos_obj = pos_obj->parent; // not interested in SPStrings + } return pos_obj; } @@ -240,7 +243,7 @@ unsigned sp_text_get_length_upto(SPObject const *item, SPObject const *upto) // Take care of new lines... if (is_line_break_object(item) && !SP_IS_TEXT(item)) { - if (item != SP_OBJECT_PARENT(item)->firstChild()) { + if (item != item->parent->firstChild()) { // add 1 for each newline length++; } @@ -303,7 +306,7 @@ to \a item at the same level. */ static unsigned sum_sibling_text_lengths_before(SPObject const *item) { unsigned char_index = 0; - for (SPObject *sibling = SP_OBJECT_PARENT(item)->firstChild() ; sibling && sibling != item ; sibling = sibling->getNext()) { + for (SPObject *sibling = item->parent->firstChild() ; sibling && sibling != item ; sibling = sibling->getNext()) { char_index += sp_text_get_length(sibling); } return char_index; @@ -327,20 +330,20 @@ parent of the first line break node encountered. */ static SPObject* split_text_object_tree_at(SPObject *split_obj, unsigned char_index) { - Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(split_obj)->getReprDoc(); + Inkscape::XML::Document *xml_doc = split_obj->document->getReprDoc(); if (is_line_break_object(split_obj)) { - Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, SP_OBJECT_REPR(split_obj)); - SP_OBJECT_REPR(SP_OBJECT_PARENT(split_obj))->addChild(new_node, SP_OBJECT_REPR(split_obj)); + Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, split_obj->getRepr()); + split_obj->parent->getRepr()->addChild(new_node, split_obj->getRepr()); Inkscape::GC::release(new_node); split_attributes(split_obj, split_obj->getNext(), char_index); return split_obj->getNext(); } unsigned char_count_before = sum_sibling_text_lengths_before(split_obj); - SPObject *duplicate_obj = split_text_object_tree_at(SP_OBJECT_PARENT(split_obj), char_index + char_count_before); + SPObject *duplicate_obj = split_text_object_tree_at(split_obj->parent, char_index + char_count_before); // copy the split node - Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, SP_OBJECT_REPR(split_obj)); - SP_OBJECT_REPR(duplicate_obj)->appendChild(new_node); + Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, split_obj->getRepr()); + duplicate_obj->getRepr()->appendChild(new_node); Inkscape::GC::release(new_node); // sort out the copied attributes (x/y/dx/dy/rotate) @@ -349,11 +352,11 @@ static SPObject* split_text_object_tree_at(SPObject *split_obj, unsigned char_in // then move all the subsequent nodes split_obj = split_obj->getNext(); while (split_obj) { - Inkscape::XML::Node *move_repr = SP_OBJECT_REPR(split_obj); + Inkscape::XML::Node *move_repr = split_obj->getRepr(); SPObject *next_obj = split_obj->getNext(); // this is about to become invalidated by removeChild() Inkscape::GC::anchor(move_repr); - SP_OBJECT_REPR(SP_OBJECT_PARENT(split_obj))->removeChild(move_repr); - SP_OBJECT_REPR(duplicate_obj)->appendChild(move_repr); + split_obj->parent->getRepr()->removeChild(move_repr); + duplicate_obj->getRepr()->appendChild(move_repr); Inkscape::GC::release(move_repr); split_obj = next_obj; @@ -392,14 +395,14 @@ Inkscape::Text::Layout::iterator sp_te_insert_line (SPItem *item, Inkscape::Text } if (split_obj) { - Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(split_obj)->getReprDoc(); - Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, SP_OBJECT_REPR(split_obj)); - SP_OBJECT_REPR(SP_OBJECT_PARENT(split_obj))->addChild(new_node, SP_OBJECT_REPR(split_obj)); + Inkscape::XML::Document *xml_doc = split_obj->document->getReprDoc(); + Inkscape::XML::Node *new_node = duplicate_node_without_children(xml_doc, split_obj->getRepr()); + split_obj->parent->getRepr()->addChild(new_node, split_obj->getRepr()); Inkscape::GC::release(new_node); } } else if (SP_IS_STRING(split_obj)) { // If the parent is a tref, editing on this particular string is disallowed. - if (SP_IS_TREF(SP_OBJECT_PARENT(split_obj))) { + if (SP_IS_TREF(split_obj->parent)) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message); return position; } @@ -410,9 +413,9 @@ Inkscape::Text::Layout::iterator sp_te_insert_line (SPItem *item, Inkscape::Text char_index++; // we need to split the entire text tree into two SPString *new_string = SP_STRING(split_text_object_tree_at(split_obj, char_index)); - SP_OBJECT_REPR(new_string)->setContent(&*split_text_iter.base()); // a little ugly + new_string->getRepr()->setContent(&*split_text_iter.base()); // a little ugly string->erase(split_text_iter, string->end()); - SP_OBJECT_REPR(split_obj)->setContent(string->c_str()); + split_obj->getRepr()->setContent(string->c_str()); // TODO: if the split point was at the beginning of a span we have a whole load of empty elements to clean up } else { // TODO @@ -461,7 +464,7 @@ static void insert_into_spstring(SPString *string_item, Glib::ustring::iterator SPObject *parent_item = string_item; for ( ; ; ) { char_index += sum_sibling_text_lengths_before(parent_item); - parent_item = SP_OBJECT_PARENT(parent_item); + parent_item = parent_item->parent; TextTagAttributes *attributes = attributes_for_object(parent_item); if (!attributes) break; attributes->insert(char_index, char_count); @@ -494,7 +497,7 @@ sp_te_insert(SPItem *item, Inkscape::Text::Layout::iterator const &position, gch source_obj = SP_OBJECT(rawptr); if (SP_IS_STRING(source_obj)) { // If the parent is a tref, editing on this particular string is disallowed. - if (SP_IS_TREF(SP_OBJECT_PARENT(source_obj))) { + if (SP_IS_TREF(source_obj->parent)) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message); return position; } @@ -505,7 +508,7 @@ sp_te_insert(SPItem *item, Inkscape::Text::Layout::iterator const &position, gch insert_into_spstring(string_item, cursor_at_end ? string_item->string.end() : iter_text, utf8); } else { // the not-so-simple case where we're at a line break or other control char; add to the next child/sibling SPString - Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(item)->document(); + Inkscape::XML::Document *xml_doc = item->getRepr()->document(); if (cursor_at_start) { source_obj = item; if (source_obj->hasChildren()) { @@ -521,7 +524,7 @@ sp_te_insert(SPItem *item, Inkscape::Text::Layout::iterator const &position, gch } if (source_obj == item && SP_IS_FLOWTEXT(item)) { Inkscape::XML::Node *para = xml_doc->createElement("svg:flowPara"); - SP_OBJECT_REPR(item)->appendChild(para); + item->getRepr()->appendChild(para); source_obj = item->lastChild(); } } else @@ -532,13 +535,13 @@ sp_te_insert(SPItem *item, Inkscape::Text::Layout::iterator const &position, gch if (string_item == NULL) { // need to add an SPString in this (pathological) case Inkscape::XML::Node *rstring = xml_doc->createTextNode(""); - SP_OBJECT_REPR(source_obj)->addChild(rstring, NULL); + source_obj->getRepr()->addChild(rstring, NULL); Inkscape::GC::release(rstring); g_assert(SP_IS_STRING(source_obj->firstChild())); string_item = SP_STRING(source_obj->firstChild()); } // If the parent is a tref, editing on this particular string is disallowed. - if (SP_IS_TREF(SP_OBJECT_PARENT(string_item))) { + if (SP_IS_TREF(string_item->parent)) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message); return position; } @@ -581,10 +584,10 @@ static SPObject* get_common_ancestor(SPObject *text, SPObject *one, SPObject *tw return text; SPObject *common_ancestor = one; if (SP_IS_STRING(common_ancestor)) - common_ancestor = SP_OBJECT_PARENT(common_ancestor); + common_ancestor = common_ancestor->parent; while (!(common_ancestor == two || common_ancestor->isAncestorOf(two))) { g_assert(common_ancestor != text); - common_ancestor = SP_OBJECT_PARENT(common_ancestor); + common_ancestor = common_ancestor->parent; } return common_ancestor; } @@ -605,7 +608,7 @@ the next suitable object and deleting \a item. Returns the object after the ones that have just been moved and sets \a next_is_sibling accordingly. */ static SPObject* delete_line_break(SPObject *root, SPObject *item, bool *next_is_sibling) { - Inkscape::XML::Node *this_repr = SP_OBJECT_REPR(item); + Inkscape::XML::Node *this_repr = item->getRepr(); SPObject *next_item = NULL; unsigned moved_char_count = sp_text_get_length(item) - 1; // the -1 is because it's going to count the line break @@ -614,7 +617,7 @@ static SPObject* delete_line_break(SPObject *root, SPObject *item, bool *next_is <p><div></div>*text</p> <p><div></div></p><p>*text</p> */ - Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(item)->document(); + Inkscape::XML::Document *xml_doc = item->getRepr()->document(); Inkscape::XML::Node *new_span_repr = xml_doc->createElement(span_name_for_text_object(root)); if (gchar const *a = this_repr->attribute("dx")) @@ -626,15 +629,15 @@ static SPObject* delete_line_break(SPObject *root, SPObject *item, bool *next_is SPObject *following_item = item; while (following_item->getNext() == NULL) { - following_item = SP_OBJECT_PARENT(following_item); + following_item = following_item->parent; g_assert(following_item != root); } following_item = following_item->getNext(); SPObject *new_parent_item; if (SP_IS_STRING(following_item)) { - new_parent_item = SP_OBJECT_PARENT(following_item); - SP_OBJECT_REPR(new_parent_item)->addChild(new_span_repr, following_item->getPrev() ? SP_OBJECT_REPR(following_item->getPrev()) : NULL); + new_parent_item = following_item->parent; + new_parent_item->getRepr()->addChild(new_span_repr, following_item->getPrev() ? following_item->getPrev()->getRepr() : NULL); next_item = following_item; *next_is_sibling = true; } else { @@ -645,13 +648,13 @@ static SPObject* delete_line_break(SPObject *root, SPObject *item, bool *next_is next_item = new_parent_item; *next_is_sibling = false; } - SP_OBJECT_REPR(new_parent_item)->addChild(new_span_repr, NULL); + new_parent_item->getRepr()->addChild(new_span_repr, NULL); } // work around a bug in sp_style_write_difference() which causes the difference // not to be written if the second param has a style set which the first does not // by causing the first param to have everything set - SPCSSAttr *dest_node_attrs = sp_repr_css_attr(SP_OBJECT_REPR(new_parent_item), "style"); + SPCSSAttr *dest_node_attrs = sp_repr_css_attr(new_parent_item->getRepr(), "style"); SPCSSAttr *this_node_attrs = sp_repr_css_attr(this_repr, "style"); SPCSSAttr *this_node_attrs_inherited = sp_repr_css_attr_inherited(this_repr, "style"); Inkscape::Util::List<Inkscape::XML::AttributeRecord const> attrs = dest_node_attrs->attributeList(); @@ -687,17 +690,19 @@ static void erase_from_spstring(SPString *string_item, Glib::ustring::iterator i for (Glib::ustring::iterator it = iter_from ; it != iter_to ; it++) char_count++; string->erase(iter_from, iter_to); - SP_OBJECT_REPR(string_item)->setContent(string->c_str()); + string_item->getRepr()->setContent(string->c_str()); SPObject *parent_item = string_item; for ( ; ; ) { char_index += sum_sibling_text_lengths_before(parent_item); - parent_item = SP_OBJECT_PARENT(parent_item); + parent_item = parent_item->parent; TextTagAttributes *attributes = attributes_for_object(parent_item); - if (attributes == NULL) break; + if (attributes == NULL) { + break; + } attributes->erase(char_index, char_count); - attributes->writeTo(SP_OBJECT_REPR(parent_item)); + attributes->writeTo(parent_item->getRepr()); } } @@ -732,16 +737,18 @@ sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, start_item = SP_OBJECT(rawptr); layout->getSourceOfCharacter(iter_pair.second, &rawptr, &end_text_iter); end_item = SP_OBJECT(rawptr); - if (start_item == 0) + if (start_item == 0) { return success; // start is at end of text - if (is_line_break_object(start_item)) + } + if (is_line_break_object(start_item)) { move_to_end_of_paragraph(&start_item, &start_text_iter); + } if (end_item == 0) { end_item = item->lastChild(); move_to_end_of_paragraph(&end_item, &end_text_iter); - } - else if (is_line_break_object(end_item)) + } else if (is_line_break_object(end_item)) { move_to_end_of_paragraph(&end_item, &end_text_iter); + } SPObject *common_ancestor = get_common_ancestor(item, start_item, end_item); @@ -749,7 +756,7 @@ sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, // the quick case where we're deleting stuff all from the same string if (SP_IS_STRING(start_item)) { // always true (if it_start != it_end anyway) // If the parent is a tref, editing on this particular string is disallowed. - if (SP_IS_TREF(SP_OBJECT_PARENT(start_item))) { + if (SP_IS_TREF(start_item->parent)) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message); } else { erase_from_spstring(SP_STRING(start_item), start_text_iter, end_text_iter); @@ -763,7 +770,7 @@ sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, if (sub_item == end_item) { if (SP_IS_STRING(sub_item)) { // If the parent is a tref, editing on this particular string is disallowed. - if (SP_IS_TREF(SP_OBJECT_PARENT(sub_item))) { + if (SP_IS_TREF(sub_item->parent)) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, tref_edit_message); break; } @@ -791,7 +798,7 @@ sp_te_delete (SPItem *item, Inkscape::Text::Layout::iterator const &start, bool is_sibling = true; next_item = sub_item->getNext(); if (next_item == NULL) { - next_item = SP_OBJECT_PARENT(sub_item); + next_item = sub_item->parent; is_sibling = false; } @@ -875,10 +882,11 @@ sp_te_get_string_multiline (SPItem const *text, Inkscape::Text::Layout::iterator Glib::ustring::iterator text_iter; layout->getSourceOfCharacter(first, &rawptr, &text_iter); char_item = SP_OBJECT(rawptr); - if (SP_IS_STRING(char_item)) + if (SP_IS_STRING(char_item)) { result += *text_iter; - else + } else { result += '\n'; + } } return result; } @@ -889,20 +897,22 @@ sp_te_set_repr_text_multiline(SPItem *text, gchar const *str) g_return_if_fail (text != NULL); g_return_if_fail (SP_IS_TEXT(text) || SP_IS_FLOWTEXT(text)); - Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(text)->document(); + Inkscape::XML::Document *xml_doc = text->getRepr()->document(); Inkscape::XML::Node *repr; SPObject *object; bool is_textpath = false; if (SP_IS_TEXT_TEXTPATH (text)) { - repr = SP_OBJECT_REPR(text->firstChild()); + repr = text->firstChild()->getRepr(); object = text->firstChild(); is_textpath = true; } else { - repr = SP_OBJECT_REPR (text); - object = SP_OBJECT (text); + repr = text->getRepr(); + object = text; } - if (!str) str = ""; + if (!str) { + str = ""; + } gchar *content = g_strdup (str); repr->setContent(""); @@ -910,7 +920,7 @@ sp_te_set_repr_text_multiline(SPItem *text, gchar const *str) while (child) { SPObject *next = child->getNext(); if (!SP_IS_FLOWREGION(child) && !SP_IS_FLOWREGIONEXCLUDE(child)) { - repr->removeChild(SP_OBJECT_REPR(child)); + repr->removeChild(child->getRepr()); } child = next; } @@ -954,8 +964,9 @@ which represents the iterator \a position. */ TextTagAttributes* text_tag_attributes_at_position(SPItem *item, Inkscape::Text::Layout::iterator const &position, unsigned *char_index) { - if (item == NULL || char_index == NULL || !SP_IS_TEXT(item)) + if (item == NULL || char_index == NULL || !SP_IS_TEXT(item)) { return NULL; // flowtext doesn't support kerning yet + } SPText *text = SP_TEXT(item); SPObject *source_item = 0; @@ -964,13 +975,16 @@ text_tag_attributes_at_position(SPItem *item, Inkscape::Text::Layout::iterator c text->layout.getSourceOfCharacter(position, &rawptr, &source_text_iter); source_item = SP_OBJECT(rawptr); - if (!SP_IS_STRING(source_item)) return NULL; + if (!SP_IS_STRING(source_item)) { + return NULL; + } Glib::ustring *string = &SP_STRING(source_item)->string; *char_index = sum_sibling_text_lengths_before(source_item); - for (Glib::ustring::iterator it = string->begin() ; it != source_text_iter ; it++) + for (Glib::ustring::iterator it = string->begin() ; it != source_text_iter ; it++) { ++*char_index; + } - return attributes_for_object(SP_OBJECT_PARENT(source_item)); + return attributes_for_object(source_item->parent); } void @@ -979,7 +993,7 @@ sp_te_adjust_kerning_screen (SPItem *item, Inkscape::Text::Layout::iterator cons // divide increment by zoom // divide increment by matrix expansion gdouble factor = 1 / desktop->current_zoom(); - Geom::Matrix t (item->i2doc_affine()); + Geom::Affine t (item->i2doc_affine()); factor = factor / t.descrim(); by = factor * by; @@ -1037,7 +1051,7 @@ sp_te_adjust_rotation_screen(SPItem *text, Inkscape::Text::Layout::iterator cons // divide increment by zoom // divide increment by matrix expansion gdouble factor = 1 / desktop->current_zoom(); - Geom::Matrix t (text->i2doc_affine()); + Geom::Affine t (text->i2doc_affine()); factor = factor / t.descrim(); Inkscape::Text::Layout const *layout = te_get_layout(text); if (layout == NULL) return; @@ -1045,8 +1059,10 @@ sp_te_adjust_rotation_screen(SPItem *text, Inkscape::Text::Layout::iterator cons void *rawptr = 0; layout->getSourceOfCharacter(std::min(start, end), &rawptr); source_item = SP_OBJECT(rawptr); - if (source_item == 0) return; - gdouble degrees = (180/M_PI) * atan2(pixels, SP_OBJECT_PARENT(source_item)->style->font_size.computed / factor); + if (source_item == 0) { + return; + } + gdouble degrees = (180/M_PI) * atan2(pixels, source_item->parent->style->font_size.computed / factor); sp_te_adjust_rotation(text, start, end, desktop, degrees); } @@ -1113,7 +1129,7 @@ sp_te_adjust_tspan_letterspacing_screen(SPItem *text, Inkscape::Text::Layout::it source_obj = source_obj->parent; } - SPStyle *style = SP_OBJECT_STYLE (source_obj); + SPStyle *style = source_obj->style; // calculate real value /* TODO: Consider calculating val unconditionally, i.e. drop the first `if' line, and @@ -1131,8 +1147,9 @@ sp_te_adjust_tspan_letterspacing_screen(SPItem *text, Inkscape::Text::Layout::it } if (start == end) { - while (!is_line_break_object(source_obj)) // move up the tree so we apply to the closest paragraph - source_obj = SP_OBJECT_PARENT(source_obj); + while (!is_line_break_object(source_obj)) { // move up the tree so we apply to the closest paragraph + source_obj = source_obj->parent; + } nb_let = sp_text_get_length(source_obj); } else { nb_let = abs(layout->iteratorToCharIndex(end) - layout->iteratorToCharIndex(start)); @@ -1195,7 +1212,7 @@ sp_te_adjust_linespacing_screen (SPItem *text, Inkscape::Text::Layout::iterator g_return_if_fail (SP_IS_TEXT(text) || SP_IS_FLOWTEXT(text)); Inkscape::Text::Layout const *layout = te_get_layout(text); - SPStyle *style = SP_OBJECT_STYLE (text); + SPStyle *style = text->style; if (!style->line_height.set || style->line_height.inherit || style->line_height.normal) { style->line_height.set = TRUE; @@ -1215,7 +1232,7 @@ sp_te_adjust_linespacing_screen (SPItem *text, Inkscape::Text::Layout::iterator gdouble zby = by / (desktop->current_zoom() * (line_count == 0 ? 1 : line_count)); // divide increment by matrix expansion - Geom::Matrix t (SP_ITEM(text)->i2doc_affine ()); + Geom::Affine t (SP_ITEM(text)->i2doc_affine ()); zby = zby / t.descrim(); switch (style->line_height.unit) { @@ -1283,14 +1300,15 @@ as opposed to sp_style_merge_from_style_string which merges its parameter underneath the existing styles (ie ignoring already set properties). */ static void overwrite_style_with_string(SPObject *item, gchar const *style_string) { - SPStyle *new_style = sp_style_new(SP_OBJECT_DOCUMENT(item)); + SPStyle *new_style = sp_style_new(item->document); sp_style_merge_from_style_string(new_style, style_string); - gchar const *item_style_string = SP_OBJECT_REPR(item)->attribute("style"); - if (item_style_string && *item_style_string) + gchar const *item_style_string = item->getRepr()->attribute("style"); + if (item_style_string && *item_style_string) { sp_style_merge_from_style_string(new_style, item_style_string); + } gchar *new_style_string = sp_style_write_string(new_style); sp_style_unref(new_style); - SP_OBJECT_REPR(item)->setAttribute("style", new_style_string && *new_style_string ? new_style_string : NULL); + item->getRepr()->setAttribute("style", new_style_string && *new_style_string ? new_style_string : NULL); g_free(new_style_string); } @@ -1308,7 +1326,7 @@ static bool objects_have_equal_style(SPObject const *parent, SPObject const *chi gchar *parent_style = sp_style_write_string(parent->style, SP_STYLE_FLAG_ALWAYS); // we have to write parent_style then read it again, because some properties format their values // differently depending on whether they're set or not (*cough*dash-offset*cough*) - SPStyle *parent_spstyle = sp_style_new(SP_OBJECT_DOCUMENT(parent)); + SPStyle *parent_spstyle = sp_style_new(parent->document); sp_style_merge_from_style_string(parent_spstyle, parent_style); g_free(parent_style); parent_style = sp_style_write_string(parent_spstyle, SP_STYLE_FLAG_ALWAYS); @@ -1317,15 +1335,15 @@ static bool objects_have_equal_style(SPObject const *parent, SPObject const *chi Glib::ustring child_style_construction; while (child != parent) { // FIXME: this assumes that child's style is only in style= whereas it can also be in css attributes! - char const *style_text = SP_OBJECT_REPR(child)->attribute("style"); + char const *style_text = child->getRepr()->attribute("style"); if (style_text && *style_text) { child_style_construction.insert(0, style_text); child_style_construction.insert(0, 1, ';'); } - child = SP_OBJECT_PARENT(child); + child = child->parent; } child_style_construction.insert(0, parent_style); - SPStyle *child_spstyle = sp_style_new(SP_OBJECT_DOCUMENT(parent)); + SPStyle *child_spstyle = sp_style_new(parent->document); sp_style_merge_from_style_string(child_spstyle, child_style_construction.c_str()); gchar *child_style = sp_style_write_string(child_spstyle, SP_STYLE_FLAG_ALWAYS); sp_style_unref(child_spstyle); @@ -1361,7 +1379,7 @@ Annoyingly similar to sp_desktop_apply_css_recursive(), except without the transform stuff. */ static void apply_css_recursive(SPObject *o, SPCSSAttr const *css) { - sp_repr_css_change(SP_OBJECT_REPR(o), const_cast<SPCSSAttr*>(css), "style"); + sp_repr_css_change(o->getRepr(), const_cast<SPCSSAttr*>(css), "style"); for (SPObject *child = o->firstChild() ; child ; child = child->getNext() ) { if (sp_repr_css_property(const_cast<SPCSSAttr*>(css), "opacity", NULL) != NULL) { @@ -1386,7 +1404,7 @@ name of the xml for a text span (ie tspan or flowspan). */ static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const *css, SPObject *start_item, Glib::ustring::iterator start_text_iter, SPObject *end_item, Glib::ustring::iterator end_text_iter, char const *span_object_name) { bool passed_start = start_item == NULL ? true : false; - Inkscape::XML::Document *xml_doc = SP_OBJECT_DOCUMENT(common_ancestor)->getReprDoc(); + Inkscape::XML::Document *xml_doc = common_ancestor->document->getReprDoc(); for (SPObject *child = common_ancestor->firstChild() ; child ; child = child->getNext()) { if (start_item == child) { @@ -1409,7 +1427,7 @@ static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const * Inkscape::XML::Node *child_span = xml_doc->createElement(span_object_name); sp_repr_css_set(child_span, const_cast<SPCSSAttr*>(css), "style"); // better hope that prototype wasn't nonconst for a good reason SPObject *prev_item = child->getPrev(); - Inkscape::XML::Node *prev_repr = prev_item ? SP_OBJECT_REPR(prev_item) : NULL; + Inkscape::XML::Node *prev_repr = prev_item ? prev_item->getRepr() : NULL; if (child == start_item || child == end_item) { surround_entire_string = false; @@ -1419,33 +1437,31 @@ static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const * unsigned end_char_index = char_index_of_iterator(string_item->string, end_text_iter); Inkscape::XML::Node *text_before = xml_doc->createTextNode(string_item->string.substr(0, start_char_index).c_str()); - SP_OBJECT_REPR(common_ancestor)->addChild(text_before, prev_repr); - SP_OBJECT_REPR(common_ancestor)->addChild(child_span, text_before); + common_ancestor->getRepr()->addChild(text_before, prev_repr); + common_ancestor->getRepr()->addChild(child_span, text_before); Inkscape::GC::release(text_before); Inkscape::XML::Node *text_in_span = xml_doc->createTextNode(string_item->string.substr(start_char_index, end_char_index - start_char_index).c_str()); child_span->appendChild(text_in_span); Inkscape::GC::release(text_in_span); - SP_OBJECT_REPR(child)->setContent(string_item->string.substr(end_char_index).c_str()); - + child->getRepr()->setContent(string_item->string.substr(end_char_index).c_str()); } else if (child == end_item) { // eg "ABCdef" -> <span>"ABC"</span>"def" // (includes case where start_text_iter == begin()) // NB: we might create an empty string here. Doesn't matter, it'll get cleaned up later unsigned end_char_index = char_index_of_iterator(string_item->string, end_text_iter); - SP_OBJECT_REPR(common_ancestor)->addChild(child_span, prev_repr); + common_ancestor->getRepr()->addChild(child_span, prev_repr); Inkscape::XML::Node *text_in_span = xml_doc->createTextNode(string_item->string.substr(0, end_char_index).c_str()); child_span->appendChild(text_in_span); Inkscape::GC::release(text_in_span); - SP_OBJECT_REPR(child)->setContent(string_item->string.substr(end_char_index).c_str()); - + child->getRepr()->setContent(string_item->string.substr(end_char_index).c_str()); } else if (start_text_iter != string_item->string.begin()) { // eg "abcDEF" -> "abc"<span>"DEF"</span> unsigned start_char_index = char_index_of_iterator(string_item->string, start_text_iter); Inkscape::XML::Node *text_before = xml_doc->createTextNode(string_item->string.substr(0, start_char_index).c_str()); - SP_OBJECT_REPR(common_ancestor)->addChild(text_before, prev_repr); - SP_OBJECT_REPR(common_ancestor)->addChild(child_span, text_before); + common_ancestor->getRepr()->addChild(text_before, prev_repr); + common_ancestor->getRepr()->addChild(child_span, text_before); Inkscape::GC::release(text_before); Inkscape::XML::Node *text_in_span = xml_doc->createTextNode(string_item->string.substr(start_char_index).c_str()); child_span->appendChild(text_in_span); @@ -1457,10 +1473,10 @@ static void recursively_apply_style(SPObject *common_ancestor, SPCSSAttr const * surround_entire_string = true; } if (surround_entire_string) { - Inkscape::XML::Node *child_repr = SP_OBJECT_REPR(child); - SP_OBJECT_REPR(common_ancestor)->addChild(child_span, child_repr); + Inkscape::XML::Node *child_repr = child->getRepr(); + common_ancestor->getRepr()->addChild(child_span, child_repr); Inkscape::GC::anchor(child_repr); - SP_OBJECT_REPR(common_ancestor)->removeChild(child_repr); + common_ancestor->getRepr()->removeChild(child_repr); child_span->appendChild(child_repr); Inkscape::GC::release(child_repr); child = common_ancestor->get_child_by_repr(child_span); @@ -1501,11 +1517,13 @@ static SPObject* ascend_while_first(SPObject *item, Glib::ustring::iterator text if (text_iter != SP_STRING(item)->string.begin()) return item; for ( ; ; ) { - SPObject *parent = SP_OBJECT_PARENT(item); - if (parent == common_ancestor) + SPObject *parent = item->parent; + if (parent == common_ancestor) { break; - if (item != parent->firstChild()) + } + if (item != parent->firstChild()) { break; + } item = parent; } return item; @@ -1535,18 +1553,28 @@ the repeated strings will be merged by another operator. */ static bool tidy_operator_inexplicable_spans(SPObject **item) { //XML Tree being directly used here while it shouldn't be. - if (*item && sp_repr_is_meta_element((*item)->getRepr())) return false; - if (SP_IS_STRING(*item)) return false; - if (is_line_break_object(*item)) return false; + if (*item && sp_repr_is_meta_element((*item)->getRepr())) { + return false; + } + if (SP_IS_STRING(*item)) { + return false; + } + if (is_line_break_object(*item)) { + return false; + } TextTagAttributes *attrs = attributes_for_object(*item); - if (attrs && attrs->anyAttributesSet()) return false; - if (!objects_have_equal_style(SP_OBJECT_PARENT(*item), *item)) return false; + if (attrs && attrs->anyAttributesSet()) { + return false; + } + if (!objects_have_equal_style((*item)->parent, *item)) { + return false; + } SPObject *next = *item; while ((*item)->hasChildren()) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((*item)->firstChild()); + Inkscape::XML::Node *repr = (*item)->firstChild()->getRepr(); Inkscape::GC::anchor(repr); - SP_OBJECT_REPR(*item)->removeChild(repr); - SP_OBJECT_REPR(SP_OBJECT_PARENT(*item))->addChild(repr, SP_OBJECT_REPR(next)); + (*item)->getRepr()->removeChild(repr); + (*item)->parent->getRepr()->addChild(repr, next->getRepr()); Inkscape::GC::release(repr); next = next->getNext(); } @@ -1563,15 +1591,15 @@ static bool tidy_operator_repeated_spans(SPObject **item) SPObject *second = first->getNext(); if (second == NULL) return false; - Inkscape::XML::Node *first_repr = SP_OBJECT_REPR(first); - Inkscape::XML::Node *second_repr = SP_OBJECT_REPR(second); + Inkscape::XML::Node *first_repr = first->getRepr(); + Inkscape::XML::Node *second_repr = second->getRepr(); if (first_repr->type() != second_repr->type()) return false; if (SP_IS_STRING(first) && SP_IS_STRING(second)) { // also amalgamate consecutive SPStrings into one Glib::ustring merged_string = SP_STRING(first)->string + SP_STRING(second)->string; - SP_OBJECT_REPR(first)->setContent(merged_string.c_str()); + first->getRepr()->setContent(merged_string.c_str()); second_repr->parent()->removeChild(second_repr); return true; } @@ -1605,18 +1633,30 @@ static bool tidy_operator_repeated_spans(SPObject **item) -> <font a,size 1>abc</font> */ static bool tidy_operator_excessive_nesting(SPObject **item) { - if (!(*item)->hasChildren()) return false; - if ((*item)->firstChild() != (*item)->lastChild()) return false; - if (SP_IS_FLOWREGION((*item)->firstChild()) || SP_IS_FLOWREGIONEXCLUDE((*item)->firstChild())) + if (!(*item)->hasChildren()) { return false; - if (SP_IS_STRING((*item)->firstChild())) return false; - if (is_line_break_object((*item)->firstChild())) return false; + } + if ((*item)->firstChild() != (*item)->lastChild()) { + return false; + } + if (SP_IS_FLOWREGION((*item)->firstChild()) || SP_IS_FLOWREGIONEXCLUDE((*item)->firstChild())) { + return false; + } + if (SP_IS_STRING((*item)->firstChild())) { + return false; + } + if (is_line_break_object((*item)->firstChild())) { + return false; + } TextTagAttributes *attrs = attributes_for_object((*item)->firstChild()); - if (attrs && attrs->anyAttributesSet()) return false; - gchar const *child_style = SP_OBJECT_REPR((*item)->firstChild())->attribute("style"); - if (child_style && *child_style) + if (attrs && attrs->anyAttributesSet()) { + return false; + } + gchar const *child_style = (*item)->firstChild()->getRepr()->attribute("style"); + if (child_style && *child_style) { overwrite_style_with_string(*item, child_style); - move_child_nodes(SP_OBJECT_REPR((*item)->firstChild()), SP_OBJECT_REPR(*item)); + } + move_child_nodes((*item)->firstChild()->getRepr(), (*item)->getRepr()); (*item)->firstChild()->deleteObject(); return true; } @@ -1624,26 +1664,37 @@ static bool tidy_operator_excessive_nesting(SPObject **item) /** helper for tidy_operator_redundant_double_nesting() */ static bool redundant_double_nesting_processor(SPObject **item, SPObject *child, bool prepend) { - if (SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child)) + if (SP_IS_FLOWREGION(child) || SP_IS_FLOWREGIONEXCLUDE(child)) { return false; - if (SP_IS_STRING(child)) return false; - if (is_line_break_object(child)) return false; - if (is_line_break_object(*item)) return false; + } + if (SP_IS_STRING(child)) { + return false; + } + if (is_line_break_object(child)) { + return false; + } + if (is_line_break_object(*item)) { + return false; + } TextTagAttributes *attrs = attributes_for_object(child); - if (attrs && attrs->anyAttributesSet()) return false; - if (!objects_have_equal_style(SP_OBJECT_PARENT(*item), child)) return false; + if (attrs && attrs->anyAttributesSet()) { + return false; + } + if (!objects_have_equal_style((*item)->parent, child)) { + return false; + } Inkscape::XML::Node *insert_after_repr = 0; if (!prepend) { - insert_after_repr = SP_OBJECT_REPR(*item); + insert_after_repr = (*item)->getRepr(); } else if ((*item)->getPrev()) { - insert_after_repr = SP_OBJECT_REPR((*item)->getPrev()); + insert_after_repr = (*item)->getPrev()->getRepr(); } - while (SP_OBJECT_REPR(child)->childCount()) { - Inkscape::XML::Node *move_repr = SP_OBJECT_REPR(child)->firstChild(); + while (child->getRepr()->childCount()) { + Inkscape::XML::Node *move_repr = child->getRepr()->firstChild(); Inkscape::GC::anchor(move_repr); - SP_OBJECT_REPR(child)->removeChild(move_repr); - SP_OBJECT_REPR(SP_OBJECT_PARENT(*item))->addChild(move_repr, insert_after_repr); + child->getRepr()->removeChild(move_repr); + (*item)->parent->getRepr()->addChild(move_repr, insert_after_repr); Inkscape::GC::release(move_repr); insert_after_repr = move_repr; // I think this will stay valid long enough. It's garbage collected these days. } @@ -1686,11 +1737,11 @@ static bool redundant_semi_nesting_processor(SPObject **item, SPObject *child, b SPCSSAttr *css_child_and_item = sp_repr_css_attr_new(); SPCSSAttr *css_child_only = sp_repr_css_attr_new(); - gchar const *item_style = SP_OBJECT_REPR(*item)->attribute("style"); + gchar const *item_style = (*item)->getRepr()->attribute("style"); if (item_style && *item_style) { sp_repr_css_attr_add_from_string(css_child_and_item, item_style); } - gchar const *child_style = SP_OBJECT_REPR(child)->attribute("style"); + gchar const *child_style = child->getRepr()->attribute("style"); if (child_style && *child_style) { sp_repr_css_attr_add_from_string(css_child_and_item, child_style); sp_repr_css_attr_add_from_string(css_child_only, child_style); @@ -1700,15 +1751,16 @@ static bool redundant_semi_nesting_processor(SPObject **item, SPObject *child, b sp_repr_css_attr_unref(css_child_only); if (!equal) return false; - Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(*item)->document(); - Inkscape::XML::Node *new_span = xml_doc->createElement(SP_OBJECT_REPR(*item)->name()); + Inkscape::XML::Document *xml_doc = (*item)->getRepr()->document(); + Inkscape::XML::Node *new_span = xml_doc->createElement((*item)->getRepr()->name()); if (prepend) { SPObject *prev = (*item)->getPrev(); - SP_OBJECT_REPR(SP_OBJECT_PARENT(*item))->addChild(new_span, prev ? SP_OBJECT_REPR(prev) : NULL); - } else - SP_OBJECT_REPR(SP_OBJECT_PARENT(*item))->addChild(new_span, SP_OBJECT_REPR(*item)); - new_span->setAttribute("style", SP_OBJECT_REPR(child)->attribute("style")); - move_child_nodes(SP_OBJECT_REPR(child), new_span); + (*item)->parent->getRepr()->addChild(new_span, prev ? prev->getRepr() : NULL); + } else { + (*item)->parent->getRepr()->addChild(new_span, (*item)->getRepr()); + } + new_span->setAttribute("style", child->getRepr()->attribute("style")); + move_child_nodes(child->getRepr(), new_span); Inkscape::GC::release(new_span); child->deleteObject(); return true; @@ -1751,10 +1803,15 @@ static SPString* find_last_string_child_not_equal_to(SPObject *root, SPObject *n -> abc<b><i>def</i></b> ghi */ static bool tidy_operator_styled_whitespace(SPObject **item) { - if (!SP_IS_STRING(*item)) return false; + if (!SP_IS_STRING(*item)) { + return false; + } Glib::ustring const &str = SP_STRING(*item)->string; - for (Glib::ustring::const_iterator it = str.begin() ; it != str.end() ; ++it) - if (!g_unichar_isspace(*it)) return false; + for (Glib::ustring::const_iterator it = str.begin() ; it != str.end() ; ++it) { + if (!g_unichar_isspace(*it)) { + return false; + } + } SPObject *test_item = *item; SPString *next_string; @@ -1765,9 +1822,13 @@ static bool tidy_operator_styled_whitespace(SPObject **item) break; } for ( ; ; ) { // go up one item in the xml - test_item = SP_OBJECT_PARENT(test_item); - if (is_line_break_object(test_item)) break; - if (SP_IS_FLOWTEXT(test_item)) return false; + test_item = test_item->parent; + if (is_line_break_object(test_item)) { + break; + } + if (SP_IS_FLOWTEXT(test_item)) { + return false; + } SPObject *next = test_item->getNext(); if (next) { test_item = next; @@ -1776,12 +1837,14 @@ static bool tidy_operator_styled_whitespace(SPObject **item) } if (is_line_break_object(test_item)) { // no next string, see if there's a prev string next_string = find_last_string_child_not_equal_to(test_item, *item); - if (next_string == NULL) return false; // an empty paragraph + if (next_string == NULL) { + return false; // an empty paragraph + } next_string->string += str; break; } } - SP_OBJECT_REPR(next_string)->setContent(next_string->string.c_str()); + next_string->getRepr()->setContent(next_string->string.c_str()); SPObject *delete_obj = *item; *item = (*item)->getNext(); delete_obj->deleteObject(); @@ -1908,7 +1971,7 @@ void sp_te_apply_style(SPItem *text, Inkscape::Text::Layout::iterator const &sta SPCSSAttr *css_set = sp_repr_css_attr_new(); sp_repr_css_merge(css_set, (SPCSSAttr*) css); { - Geom::Matrix const local(SP_ITEM(common_ancestor)->i2doc_affine()); + Geom::Affine const local(SP_ITEM(common_ancestor)->i2doc_affine()); double const ex(local.descrim()); if ( ( ex != 0. ) && ( ex != 1. ) ) { diff --git a/src/text-editing.h b/src/text-editing.h index 3d5efbbec..529b25ff5 100644 --- a/src/text-editing.h +++ b/src/text-editing.h @@ -43,7 +43,7 @@ unsigned sp_text_get_length(SPObject const *item); \a item, before and not including \a upto. Also adds 1 for each line break encountered. */ unsigned sp_text_get_length_upto(SPObject const *item, SPObject const *upto); -std::vector<Geom::Point> sp_te_create_selection_quads(SPItem const *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, Geom::Matrix const &transform); +std::vector<Geom::Point> sp_te_create_selection_quads(SPItem const *item, Inkscape::Text::Layout::iterator const &start, Inkscape::Text::Layout::iterator const &end, Geom::Affine const &transform); Inkscape::Text::Layout::iterator sp_te_get_position_by_coords (SPItem const *item, Geom::Point const &i_p); void sp_te_get_cursor_coords (SPItem const *item, Inkscape::Text::Layout::iterator const &position, Geom::Point &p0, Geom::Point &p1); diff --git a/src/text-tag-attributes.h b/src/text-tag-attributes.h index 11b751a2c..fdcfa8ce0 100644 --- a/src/text-tag-attributes.h +++ b/src/text-tag-attributes.h @@ -88,7 +88,7 @@ public: If \a extend_zero_length is true, then if the x or y vectors are empty they will be made length 1 in order to store the newly calculated position. */ - void transform(Geom::Matrix const &matrix, double scale_x, double scale_y, bool extend_zero_length = false); + void transform(Geom::Affine const &matrix, double scale_x, double scale_y, bool extend_zero_length = false); /** Gets current value of dx vector at \a index. */ double getDx(unsigned index); diff --git a/src/tools-switch.cpp b/src/tools-switch.cpp index e9fca952e..1f624cc35 100644 --- a/src/tools-switch.cpp +++ b/src/tools-switch.cpp @@ -140,7 +140,7 @@ tools_switch(SPDesktop *dt, int num) dt->set_event_context(SP_TYPE_SPRAY_CONTEXT, tool_names[num]); dt->activate_guides(true); inkscape_eventcontext_set(sp_desktop_event_context(dt)); - dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("To spray a path by pushing, select it and drag over it.")); + dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b>, <b>click</b> or <b>scroll</b> to spray the selected objects.")); break; case TOOLS_SHAPES_RECT: dt->set_event_context(SP_TYPE_RECT_CONTEXT, tool_names[num]); diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 5571e147b..813f532a4 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -514,7 +514,7 @@ void Tracer::traceThread() Geom::Scale scal(iwscale, ihscale); //# Convolve scale, translation, and the original transform - Geom::Matrix tf(scal * trans); + Geom::Affine tf(scal * trans); tf *= img->transform; diff --git a/src/transf_mat_3x4.cpp b/src/transf_mat_3x4.cpp index 533972e29..20eee658c 100644 --- a/src/transf_mat_3x4.cpp +++ b/src/transf_mat_3x4.cpp @@ -13,7 +13,7 @@ #include "transf_mat_3x4.h" #include <gtk/gtk.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "svg/stringstream.h" #include "syseq.h" #include "document.h" @@ -133,7 +133,7 @@ TransfMat3x4::operator==(const TransfMat3x4 &rhs) const /* Multiply a projective matrix by an affine matrix (by only multiplying the 'affine part' of the * projective matrix) */ TransfMat3x4 -TransfMat3x4::operator*(Geom::Matrix const &A) const { +TransfMat3x4::operator*(Geom::Affine const &A) const { TransfMat3x4 ret; for (int j = 0; j < 4; ++j) { @@ -148,7 +148,7 @@ TransfMat3x4::operator*(Geom::Matrix const &A) const { // FIXME: Shouldn't rather operator* call operator*= for efficiency? (Because in operator*= // there is in principle no need to create a temporary object, which happens in the assignment) TransfMat3x4 & -TransfMat3x4::operator*=(Geom::Matrix const &A) { +TransfMat3x4::operator*=(Geom::Affine const &A) { *this = *this * A; return *this; } diff --git a/src/transf_mat_3x4.h b/src/transf_mat_3x4.h index afe4f92a4..8542e5e00 100644 --- a/src/transf_mat_3x4.h +++ b/src/transf_mat_3x4.h @@ -47,8 +47,8 @@ public: gchar * pt_to_str (Proj::Axis axis); bool operator==(const TransfMat3x4 &rhs) const; - TransfMat3x4 operator*(Geom::Matrix const &A) const; - TransfMat3x4 &operator*=(Geom::Matrix const &A); + TransfMat3x4 operator*(Geom::Affine const &A) const; + TransfMat3x4 &operator*=(Geom::Affine const &A); void print() const; diff --git a/src/tweak-context.cpp b/src/tweak-context.cpp index 3f0db0b8d..faa08ee91 100644 --- a/src/tweak-context.cpp +++ b/src/tweak-context.cpp @@ -20,7 +20,6 @@ #include <numeric> #include "svg/svg.h" -#include "display/canvas-bpath.h" #include <glib/gmem.h> #include "macros.h" @@ -59,6 +58,7 @@ #include "gradient-chemistry.h" #include "sp-text.h" #include "sp-flowtext.h" +#include "display/sp-canvas.h" #include "display/canvas-bpath.h" #include "display/canvas-arena.h" #include "display/curve.h" @@ -156,7 +156,10 @@ static void sp_tweak_context_dispose(GObject *object) { SPTweakContext *tc = SP_TWEAK_CONTEXT(object); + SPEventContext *ec = SP_EVENT_CONTEXT(object); + ec->enableGrDrag(false); + tc->style_set_connection.disconnect(); tc->style_set_connection.~connection(); @@ -190,18 +193,17 @@ bool is_color_mode (gint mode) void sp_tweak_update_cursor (SPTweakContext *tc, bool with_shift) { - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); - SPDesktop *desktop = event_context->desktop; - - guint num = 0; - gchar *sel_message = NULL; - if (!desktop->selection->isEmpty()) { - num = g_slist_length((GSList *) desktop->selection->itemList()); - sel_message = g_strdup_printf(ngettext("<b>%i</b> object selected","<b>%i</b> objects selected",num), num); - } else { - sel_message = g_strdup_printf(_("<b>Nothing</b> selected")); - } + SPEventContext *event_context = SP_EVENT_CONTEXT(tc); + SPDesktop *desktop = event_context->desktop; + guint num = 0; + gchar *sel_message = NULL; + if (!desktop->selection->isEmpty()) { + num = g_slist_length((GSList *) desktop->selection->itemList()); + sel_message = g_strdup_printf(ngettext("<b>%i</b> object selected","<b>%i</b> objects selected",num), num); + } else { + sel_message = g_strdup_printf(_("<b>Nothing</b> selected")); + } switch (tc->mode) { case TWEAK_MODE_MOVE: @@ -282,14 +284,14 @@ sp_tweak_context_style_set(SPCSSAttr const *css, SPTweakContext *tc) return false; } - static void sp_tweak_context_setup(SPEventContext *ec) { SPTweakContext *tc = SP_TWEAK_CONTEXT(ec); - if (((SPEventContextClass *) parent_class)->setup) + if (((SPEventContextClass *) parent_class)->setup) { ((SPEventContextClass *) parent_class)->setup(ec); + } { /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ @@ -330,7 +332,6 @@ sp_tweak_context_setup(SPEventContext *ec) if (prefs->getBool("/tools/tweak/selcue")) { ec->enableSelectionCue(); } - if (prefs->getBool("/tools/tweak/gradientdrag")) { ec->enableGrDrag(); } @@ -367,10 +368,11 @@ sp_tweak_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) static void sp_tweak_extinput(SPTweakContext *tc, GdkEvent *event) { - if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &tc->pressure)) + if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &tc->pressure)) { tc->pressure = CLAMP (tc->pressure, TC_MIN_PRESSURE, TC_MAX_PRESSURE); - else + } else { tc->pressure = TC_DEFAULT_PRESSURE; + } } double @@ -413,7 +415,7 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P GSList *items = g_slist_prepend (NULL, item); GSList *selected = NULL; GSList *to_select = NULL; - SPDocument *doc = SP_OBJECT_DOCUMENT(item); + SPDocument *doc = item->document; sp_item_list_to_curves (items, &selected, &to_select); g_slist_free (items); SPObject* newObj = doc->getObjectByRepr((Inkscape::XML::Node *) to_select->data); @@ -518,13 +520,13 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P double chance = g_random_double_range(0, 1); if (chance <= prob) { if (reverse) { // delete - sp_object_ref(SP_OBJECT(item), NULL); - SP_OBJECT(item)->deleteObject(true, true); - sp_object_unref(SP_OBJECT(item), NULL); + sp_object_ref(item, NULL); + item->deleteObject(true, true); + sp_object_unref(item, NULL); } else { // duplicate - SPDocument *doc = SP_OBJECT_DOCUMENT(item); + SPDocument *doc = item->document; Inkscape::XML::Document* xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item); + Inkscape::XML::Node *old_repr = item->getRepr(); SPObject *old_obj = doc->getObjectByRepr(old_repr); Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); @@ -542,154 +544,152 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P } else if (SP_IS_PATH(item) || SP_IS_SHAPE(item)) { - Inkscape::XML::Node *newrepr = NULL; - gint pos = 0; - Inkscape::XML::Node *parent = NULL; - char const *id = NULL; - if (!SP_IS_PATH(item)) { - newrepr = sp_selected_item_to_curved_repr(item, 0); - if (!newrepr) - return false; + Inkscape::XML::Node *newrepr = NULL; + gint pos = 0; + Inkscape::XML::Node *parent = NULL; + char const *id = NULL; + if (!SP_IS_PATH(item)) { + newrepr = sp_selected_item_to_curved_repr(item, 0); + if (!newrepr) { + return false; + } - // remember the position of the item - pos = SP_OBJECT_REPR(item)->position(); - // remember parent - parent = SP_OBJECT_REPR(item)->parent(); - // remember id - id = SP_OBJECT_REPR(item)->attribute("id"); - } + // remember the position of the item + pos = item->getRepr()->position(); + // remember parent + parent = item->getRepr()->parent(); + // remember id + id = item->getRepr()->attribute("id"); + } + // skip those paths whose bboxes are entirely out of reach with our radius + Geom::OptRect bbox = item->getBounds(item->i2doc_affine()); + if (bbox) { + bbox->expandBy(radius); + if (!bbox->contains(p)) { + return false; + } + } - // skip those paths whose bboxes are entirely out of reach with our radius - Geom::OptRect bbox = item->getBounds(item->i2doc_affine()); - if (bbox) { - bbox->expandBy(radius); - if (!bbox->contains(p)) { + Path *orig = Path_for_item(item, false); + if (orig == NULL) { return false; } - } - Path *orig = Path_for_item(item, false); - if (orig == NULL) { - return false; - } + Path *res = new Path; + res->SetBackData(false); - Path *res = new Path; - res->SetBackData(false); + Shape *theShape = new Shape; + Shape *theRes = new Shape; + Geom::Affine i2doc(item->i2doc_affine()); - Shape *theShape = new Shape; - Shape *theRes = new Shape; - Geom::Matrix i2doc(item->i2doc_affine()); + orig->ConvertWithBackData((0.08 - (0.07 * fidelity)) / i2doc.descrim()); // default 0.059 + orig->Fill(theShape, 0); - orig->ConvertWithBackData((0.08 - (0.07 * fidelity)) / i2doc.descrim()); // default 0.059 - orig->Fill(theShape, 0); + SPCSSAttr *css = sp_repr_css_attr(item->getRepr(), "style"); + gchar const *val = sp_repr_css_property(css, "fill-rule", NULL); + if (val && strcmp(val, "nonzero") == 0) { + theRes->ConvertToShape(theShape, fill_nonZero); + } else if (val && strcmp(val, "evenodd") == 0) { + theRes->ConvertToShape(theShape, fill_oddEven); + } else { + theRes->ConvertToShape(theShape, fill_nonZero); + } - SPCSSAttr *css = sp_repr_css_attr(SP_OBJECT_REPR(item), "style"); - gchar const *val = sp_repr_css_property(css, "fill-rule", NULL); - if (val && strcmp(val, "nonzero") == 0) - { - theRes->ConvertToShape(theShape, fill_nonZero); - } - else if (val && strcmp(val, "evenodd") == 0) - { - theRes->ConvertToShape(theShape, fill_oddEven); - } - else - { - theRes->ConvertToShape(theShape, fill_nonZero); - } + if (Geom::L2(vector) != 0) { + vector = 1/Geom::L2(vector) * vector; + } - if (Geom::L2(vector) != 0) - vector = 1/Geom::L2(vector) * vector; - - bool did_this = false; - if (mode == TWEAK_MODE_SHRINK_GROW) { - if (theShape->MakeTweak(tweak_mode_grow, theRes, - reverse? force : -force, - join_straight, 4.0, - true, p, Geom::Point(0,0), radius, &i2doc) == 0) // 0 means the shape was actually changed - did_this = true; - } else if (mode == TWEAK_MODE_ATTRACT_REPEL) { - if (theShape->MakeTweak(tweak_mode_repel, theRes, - reverse? force : -force, - join_straight, 4.0, - true, p, Geom::Point(0,0), radius, &i2doc) == 0) - did_this = true; - } else if (mode == TWEAK_MODE_PUSH) { - if (theShape->MakeTweak(tweak_mode_push, theRes, - 1.0, - join_straight, 4.0, - true, p, force*2*vector, radius, &i2doc) == 0) - did_this = true; - } else if (mode == TWEAK_MODE_ROUGHEN) { - if (theShape->MakeTweak(tweak_mode_roughen, theRes, - force, - join_straight, 4.0, - true, p, Geom::Point(0,0), radius, &i2doc) == 0) - did_this = true; - } + bool did_this = false; + if (mode == TWEAK_MODE_SHRINK_GROW) { + if (theShape->MakeTweak(tweak_mode_grow, theRes, + reverse? force : -force, + join_straight, 4.0, + true, p, Geom::Point(0,0), radius, &i2doc) == 0) // 0 means the shape was actually changed + did_this = true; + } else if (mode == TWEAK_MODE_ATTRACT_REPEL) { + if (theShape->MakeTweak(tweak_mode_repel, theRes, + reverse? force : -force, + join_straight, 4.0, + true, p, Geom::Point(0,0), radius, &i2doc) == 0) + did_this = true; + } else if (mode == TWEAK_MODE_PUSH) { + if (theShape->MakeTweak(tweak_mode_push, theRes, + 1.0, + join_straight, 4.0, + true, p, force*2*vector, radius, &i2doc) == 0) + did_this = true; + } else if (mode == TWEAK_MODE_ROUGHEN) { + if (theShape->MakeTweak(tweak_mode_roughen, theRes, + force, + join_straight, 4.0, + true, p, Geom::Point(0,0), radius, &i2doc) == 0) + did_this = true; + } - // the rest only makes sense if we actually changed the path - if (did_this) { - theRes->ConvertToShape(theShape, fill_positive); + // the rest only makes sense if we actually changed the path + if (did_this) { + theRes->ConvertToShape(theShape, fill_positive); - res->Reset(); - theRes->ConvertToForme(res); + res->Reset(); + theRes->ConvertToForme(res); - double th_max = (0.6 - 0.59*sqrt(fidelity)) / i2doc.descrim(); - double threshold = MAX(th_max, th_max*force); - res->ConvertEvenLines(threshold); - res->Simplify(threshold / (selection->desktop()->current_zoom())); + double th_max = (0.6 - 0.59*sqrt(fidelity)) / i2doc.descrim(); + double threshold = MAX(th_max, th_max*force); + res->ConvertEvenLines(threshold); + res->Simplify(threshold / (selection->desktop()->current_zoom())); - if (newrepr) { // converting to path, need to replace the repr - bool is_selected = selection->includes(item); - if (is_selected) - selection->remove(item); + if (newrepr) { // converting to path, need to replace the repr + bool is_selected = selection->includes(item); + if (is_selected) { + selection->remove(item); + } - // It's going to resurrect, so we delete without notifying listeners. - SP_OBJECT(item)->deleteObject(false); + // It's going to resurrect, so we delete without notifying listeners. + item->deleteObject(false); - // restore id - newrepr->setAttribute("id", id); - // add the new repr to the parent - parent->appendChild(newrepr); - // move to the saved position - newrepr->setPosition(pos > 0 ? pos : 0); + // restore id + newrepr->setAttribute("id", id); + // add the new repr to the parent + parent->appendChild(newrepr); + // move to the saved position + newrepr->setPosition(pos > 0 ? pos : 0); - if (is_selected) - selection->add(newrepr); - } + if (is_selected) + selection->add(newrepr); + } - if (res->descr_cmd.size() > 1) { - gchar *str = res->svg_dump_path(); - if (newrepr) { - newrepr->setAttribute("d", str); - } else { - if (SP_IS_LPE_ITEM(item) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(item))) { - SP_OBJECT_REPR(item)->setAttribute("inkscape:original-d", str); + if (res->descr_cmd.size() > 1) { + gchar *str = res->svg_dump_path(); + if (newrepr) { + newrepr->setAttribute("d", str); } else { - SP_OBJECT_REPR(item)->setAttribute("d", str); + if (SP_IS_LPE_ITEM(item) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(item))) { + item->getRepr()->setAttribute("inkscape:original-d", str); + } else { + item->getRepr()->setAttribute("d", str); + } } + g_free(str); + } else { + // TODO: if there's 0 or 1 node left, delete this path altogether } - g_free(str); - } else { - // TODO: if there's 0 or 1 node left, delete this path altogether - } - if (newrepr) { - Inkscape::GC::release(newrepr); - newrepr = NULL; + if (newrepr) { + Inkscape::GC::release(newrepr); + newrepr = NULL; + } } - } - delete theShape; - delete theRes; - delete orig; - delete res; + delete theShape; + delete theRes; + delete orig; + delete res; - if (did_this) - did = true; - } + if (did_this) { + did = true; + } + } } @@ -706,12 +706,15 @@ tweak_colorpaint (float *color, guint32 goal, double force, bool do_h, bool do_s sp_color_rgb_to_hsl_floatv (hsl_g, SP_RGBA32_R_F(goal), SP_RGBA32_G_F(goal), SP_RGBA32_B_F(goal)); float hsl_c[3]; sp_color_rgb_to_hsl_floatv (hsl_c, color[0], color[1], color[2]); - if (!do_h) + if (!do_h) { hsl_g[0] = hsl_c[0]; - if (!do_s) + } + if (!do_s) { hsl_g[1] = hsl_c[1]; - if (!do_l) + } + if (!do_l) { hsl_g[2] = hsl_c[2]; + } sp_color_hsl_to_rgb_floatv (rgb_g, hsl_g[0], hsl_g[1], hsl_g[2]); } else { rgb_g[0] = SP_RGBA32_R_F(goal); @@ -733,10 +736,12 @@ tweak_colorjitter (float *color, double force, bool do_h, bool do_s, bool do_l) if (do_h) { hsl_c[0] += g_random_double_range(-0.5, 0.5) * force; - if (hsl_c[0] > 1) + if (hsl_c[0] > 1) { hsl_c[0] -= 1; - if (hsl_c[0] < 0) + } + if (hsl_c[0] < 0) { hsl_c[0] += 1; + } } if (do_s) { hsl_c[1] += g_random_double_range(-hsl_c[1], 1 - hsl_c[1]) * force; @@ -777,8 +782,9 @@ tweak_opacity (guint mode, SPIScale24 *style_opacity, double opacity_goal, doubl double tweak_profile (double dist, double radius) { - if (radius == 0) + if (radius == 0) { return 0; + } double x = dist / radius; double alpha = 1; if (x >= 1) { @@ -797,10 +803,11 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, { SPGradient *gradient = sp_item_gradient (item, fill_or_stroke); - if (!gradient || !SP_IS_GRADIENT(gradient)) + if (!gradient || !SP_IS_GRADIENT(gradient)) { return; + } - Geom::Matrix i2d (item->i2doc_affine ()); + Geom::Affine i2d (item->i2doc_affine ()); Geom::Point p = p_w * i2d.inverse(); p *= (gradient->gradientTransform).inverse(); // now p is in gradient's original coordinates @@ -817,7 +824,7 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, // This is the matrix which moves and rotates the gradient line // so it's oriented along the X axis: - Geom::Matrix norm = Geom::Matrix(Geom::Translate(-p1)) * Geom::Matrix(Geom::Rotate(-atan2(pdiff[Geom::Y], pdiff[Geom::X]))); + Geom::Affine norm = Geom::Affine(Geom::Translate(-p1)) * Geom::Affine(Geom::Rotate(-atan2(pdiff[Geom::Y], pdiff[Geom::X]))); // Transform the mouse point by it to find out its projection onto the gradient line: Geom::Point pnorm = p * norm; @@ -883,7 +890,7 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, tweak_color (mode, SP_STOP(child_prev)->specified_color.v.c, rgb_goal, force * (offset_h - pos_e) / (offset_h - offset_l), do_h, do_s, do_l); - SP_OBJECT(stop)->updateRepr(); + stop->updateRepr(); child_prev->updateRepr(); break; } else { @@ -900,7 +907,7 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, tweak_color (mode, stop->specified_color.v.c, rgb_goal, force * tweak_profile (fabs (pos_e - offset_h), r), do_h, do_s, do_l); - SP_OBJECT(stop)->updateRepr(); + stop->updateRepr(); } } } @@ -929,13 +936,14 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, stroke_goal, do_stroke, opacity_goal, do_opacity, do_blur, reverse, - p, radius, force, do_h, do_s, do_l, do_o)) + p, radius, force, do_h, do_s, do_l, do_o)) { did = true; + } } } } else { - SPStyle *style = SP_OBJECT_STYLE(item); + SPStyle *style = item->style; if (!style) { return false; } @@ -976,7 +984,7 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, } double blur_now = 0; - Geom::Matrix i2d = item->i2d_affine (); + Geom::Affine i2d = item->i2d_affine (); if (style->filter.set && style->getFilter()) { //cycle through filter primitives SPObject *primitive_obj = style->getFilter()->children; @@ -997,20 +1005,19 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, blur_now = blur_now / perimeter; double blur_new; - if (reverse) + if (reverse) { blur_new = blur_now - 0.06 * force; - else + } else { blur_new = blur_now + 0.06 * force; + } if (blur_new < 0.0005 && blur_new < blur_now) { blur_new = 0; } - if (blur_new == 0) { remove_filter(item, false); } else { double radius = blur_new * perimeter; - SPFilter *filter = modify_filter_gaussian_blur_from_item(SP_OBJECT_DOCUMENT(item), item, radius); - + SPFilter *filter = modify_filter_gaussian_blur_from_item(item->document, item, radius); sp_style_set_property_url(item, "filter", filter, false); } return true; // do not do colors, blur is a separate mode @@ -1118,15 +1125,18 @@ sp_tweak_dilate (SPTweakContext *tc, Geom::Point event_p, Geom::Point p, Geom::P stroke_goal, do_stroke, opacity_goal, do_opacity, tc->mode == TWEAK_MODE_BLUR, reverse, - p, radius, color_force, tc->do_h, tc->do_s, tc->do_l, tc->do_o)) - did = true; + p, radius, color_force, tc->do_h, tc->do_s, tc->do_l, tc->do_o)) { + did = true; + } } } else if (is_transform_mode(tc->mode)) { - if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, move_force, tc->fidelity, reverse)) + if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, move_force, tc->fidelity, reverse)) { did = true; + } } else { - if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, path_force, tc->fidelity, reverse)) + if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, path_force, tc->fidelity, reverse)) { did = true; + } } } @@ -1137,7 +1147,7 @@ void sp_tweak_update_area (SPTweakContext *tc) { double radius = get_dilate_radius(tc); - Geom::Matrix const sm (Geom::Scale(radius, radius) * Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point())); + Geom::Affine const sm (Geom::Scale(radius, radius) * Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point())); sp_canvas_item_affine_absolute(tc->dilate_area, sm); sp_canvas_item_show(tc->dilate_area); } @@ -1213,7 +1223,7 @@ sp_tweak_context_root_handler(SPEventContext *event_context, // draw the dilating cursor double radius = get_dilate_radius(tc); - Geom::Matrix const sm (Geom::Scale(radius, radius) * Geom::Translate(desktop->w2d(motion_w))); + Geom::Affine const sm (Geom::Scale(radius, radius) * Geom::Translate(desktop->w2d(motion_w))); sp_canvas_item_affine_absolute(tc->dilate_area, sm); sp_canvas_item_show(tc->dilate_area); @@ -1237,286 +1247,287 @@ sp_tweak_context_root_handler(SPEventContext *event_context, } break; + case GDK_BUTTON_RELEASE: + { + Geom::Point const motion_w(event->button.x, event->button.y); + Geom::Point const motion_dt(desktop->w2d(motion_w)); + sp_canvas_end_forced_full_redraws(desktop->canvas); + tc->is_drawing = false; - case GDK_BUTTON_RELEASE: - { - Geom::Point const motion_w(event->button.x, event->button.y); - Geom::Point const motion_dt(desktop->w2d(motion_w)); - - sp_canvas_end_forced_full_redraws(desktop->canvas); - tc->is_drawing = false; - - if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { - if (!tc->has_dilated) { - // if we did not rub, do a light tap - tc->pressure = 0.03; - sp_tweak_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); + if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { + if (!tc->has_dilated) { + // if we did not rub, do a light tap + tc->pressure = 0.03; + sp_tweak_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); + } + tc->is_dilating = false; + tc->has_dilated = false; + switch (tc->mode) { + case TWEAK_MODE_MOVE: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Move tweak")); + break; + case TWEAK_MODE_MOVE_IN_OUT: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Move in/out tweak")); + break; + case TWEAK_MODE_MOVE_JITTER: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Move jitter tweak")); + break; + case TWEAK_MODE_SCALE: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Scale tweak")); + break; + case TWEAK_MODE_ROTATE: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Rotate tweak")); + break; + case TWEAK_MODE_MORELESS: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Duplicate/delete tweak")); + break; + case TWEAK_MODE_PUSH: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Push path tweak")); + break; + case TWEAK_MODE_SHRINK_GROW: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Shrink/grow path tweak")); + break; + case TWEAK_MODE_ATTRACT_REPEL: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Attract/repel path tweak")); + break; + case TWEAK_MODE_ROUGHEN: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Roughen path tweak")); + break; + case TWEAK_MODE_COLORPAINT: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Color paint tweak")); + break; + case TWEAK_MODE_COLORJITTER: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Color jitter tweak")); + break; + case TWEAK_MODE_BLUR: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Blur tweak")); + break; + } } - tc->is_dilating = false; - tc->has_dilated = false; - switch (tc->mode) { - case TWEAK_MODE_MOVE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Move tweak")); + break; + } + case GDK_KEY_PRESS: + { + switch (get_group0_keyval (&event->key)) { + case GDK_m: + case GDK_M: + case GDK_0: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_MOVE_IN_OUT: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Move in/out tweak")); + case GDK_i: + case GDK_I: + case GDK_1: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_IN_OUT, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_MOVE_JITTER: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Move jitter tweak")); + case GDK_z: + case GDK_Z: + case GDK_2: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_JITTER, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_SCALE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Scale tweak")); + case GDK_less: + case GDK_comma: + case GDK_greater: + case GDK_period: + case GDK_3: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_SCALE, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_ROTATE: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Rotate tweak")); + case GDK_bracketright: + case GDK_bracketleft: + case GDK_4: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_ROTATE, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_MORELESS: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Duplicate/delete tweak")); + case GDK_d: + case GDK_D: + case GDK_5: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_MORELESS, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_PUSH: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Push path tweak")); + case GDK_p: + case GDK_P: + case GDK_6: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_PUSH, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_SHRINK_GROW: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Shrink/grow path tweak")); + case GDK_s: + case GDK_S: + case GDK_7: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_ATTRACT_REPEL: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Attract/repel path tweak")); + case GDK_a: + case GDK_A: + case GDK_8: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_ATTRACT_REPEL, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_ROUGHEN: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Roughen path tweak")); + case GDK_r: + case GDK_R: + case GDK_9: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_ROUGHEN, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_COLORPAINT: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Color paint tweak")); + case GDK_c: + case GDK_C: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_COLORPAINT, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_COLORJITTER: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Color jitter tweak")); + case GDK_j: + case GDK_J: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_COLORJITTER, MOD__SHIFT); + ret = TRUE; + } break; - case TWEAK_MODE_BLUR: - DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Blur tweak")); + case GDK_b: + case GDK_B: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_BLUR, MOD__SHIFT); + ret = TRUE; + } break; - } - } - break; - } - case GDK_KEY_PRESS: - switch (get_group0_keyval (&event->key)) { - case GDK_m: - case GDK_M: - case GDK_0: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_i: - case GDK_I: - case GDK_1: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_IN_OUT, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_z: - case GDK_Z: - case GDK_2: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_JITTER, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_less: - case GDK_comma: - case GDK_greater: - case GDK_period: - case GDK_3: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_SCALE, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_bracketright: - case GDK_bracketleft: - case GDK_4: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ROTATE, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_d: - case GDK_D: - case GDK_5: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_MORELESS, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_p: - case GDK_P: - case GDK_6: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_PUSH, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_s: - case GDK_S: - case GDK_7: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_a: - case GDK_A: - case GDK_8: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ATTRACT_REPEL, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_r: - case GDK_R: - case GDK_9: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ROUGHEN, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_c: - case GDK_C: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_COLORPAINT, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_j: - case GDK_J: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_COLORJITTER, MOD__SHIFT); - ret = TRUE; - } - break; - case GDK_b: - case GDK_B: - if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_BLUR, MOD__SHIFT); - ret = TRUE; - } - break; - - case GDK_Up: - case GDK_KP_Up: - if (!MOD__CTRL_ONLY) { - tc->force += 0.05; - if (tc->force > 1.0) - tc->force = 1.0; - desktop->setToolboxAdjustmentValue ("tweak-force", tc->force * 100); - ret = TRUE; - } - break; - case GDK_Down: - case GDK_KP_Down: - if (!MOD__CTRL_ONLY) { - tc->force -= 0.05; - if (tc->force < 0.0) - tc->force = 0.0; - desktop->setToolboxAdjustmentValue ("tweak-force", tc->force * 100); - ret = TRUE; - } - break; - case GDK_Right: - case GDK_KP_Right: - if (!MOD__CTRL_ONLY) { - tc->width += 0.01; - if (tc->width > 1.0) - tc->width = 1.0; - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); // the same spinbutton is for alt+x - sp_tweak_update_area(tc); - ret = TRUE; - } - break; - case GDK_Left: - case GDK_KP_Left: - if (!MOD__CTRL_ONLY) { - tc->width -= 0.01; - if (tc->width < 0.01) + case GDK_Up: + case GDK_KP_Up: + if (!MOD__CTRL_ONLY) { + tc->force += 0.05; + if (tc->force > 1.0) { + tc->force = 1.0; + } + desktop->setToolboxAdjustmentValue ("tweak-force", tc->force * 100); + ret = TRUE; + } + break; + case GDK_Down: + case GDK_KP_Down: + if (!MOD__CTRL_ONLY) { + tc->force -= 0.05; + if (tc->force < 0.0) { + tc->force = 0.0; + } + desktop->setToolboxAdjustmentValue ("tweak-force", tc->force * 100); + ret = TRUE; + } + break; + case GDK_Right: + case GDK_KP_Right: + if (!MOD__CTRL_ONLY) { + tc->width += 0.01; + if (tc->width > 1.0) { + tc->width = 1.0; + } + desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); // the same spinbutton is for alt+x + sp_tweak_update_area(tc); + ret = TRUE; + } + break; + case GDK_Left: + case GDK_KP_Left: + if (!MOD__CTRL_ONLY) { + tc->width -= 0.01; + if (tc->width < 0.01) { + tc->width = 0.01; + } + desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); + sp_tweak_update_area(tc); + ret = TRUE; + } + break; + case GDK_Home: + case GDK_KP_Home: tc->width = 0.01; - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); - sp_tweak_update_area(tc); - ret = TRUE; - } - break; - case GDK_Home: - case GDK_KP_Home: - tc->width = 0.01; - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); - sp_tweak_update_area(tc); - ret = TRUE; - break; - case GDK_End: - case GDK_KP_End: - tc->width = 1.0; - desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); - sp_tweak_update_area(tc); - ret = TRUE; - break; - case GDK_x: - case GDK_X: - if (MOD__ALT_ONLY) { - desktop->setToolboxFocusTo ("altx-tweak"); - ret = TRUE; - } - break; + desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); + sp_tweak_update_area(tc); + ret = TRUE; + break; + case GDK_End: + case GDK_KP_End: + tc->width = 1.0; + desktop->setToolboxAdjustmentValue ("altx-tweak", tc->width * 100); + sp_tweak_update_area(tc); + ret = TRUE; + break; + case GDK_x: + case GDK_X: + if (MOD__ALT_ONLY) { + desktop->setToolboxFocusTo ("altx-tweak"); + ret = TRUE; + } + break; - case GDK_Shift_L: - case GDK_Shift_R: - sp_tweak_update_cursor(tc, true); - break; + case GDK_Shift_L: + case GDK_Shift_R: + sp_tweak_update_cursor(tc, true); + break; - case GDK_Control_L: - case GDK_Control_R: - sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT); - break; - default: + case GDK_Control_L: + case GDK_Control_R: + sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT); + break; + default: + break; + } break; } - break; - - case GDK_KEY_RELEASE: { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - switch (get_group0_keyval(&event->key)) { - case GDK_Shift_L: - case GDK_Shift_R: - sp_tweak_update_cursor(tc, false); - break; - case GDK_Control_L: - case GDK_Control_R: - sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT); - tc->_message_context->clear(); - break; - default: - sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT); - break; + case GDK_KEY_RELEASE: { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + switch (get_group0_keyval(&event->key)) { + case GDK_Shift_L: + case GDK_Shift_R: + sp_tweak_update_cursor(tc, false); + break; + case GDK_Control_L: + case GDK_Control_R: + sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT); + tc->_message_context->clear(); + break; + default: + sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT); + break; + } } - } - - default: - break; + default: + break; } if (!ret) { diff --git a/src/tweak-context.h b/src/tweak-context.h index ad688b025..542254b91 100644 --- a/src/tweak-context.h +++ b/src/tweak-context.h @@ -13,7 +13,6 @@ */ #include "event-context.h" -#include <display/display-forward.h> #include <libnr/nr-point.h> #define SP_TYPE_TWEAK_CONTEXT (sp_tweak_context_get_type()) diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index 5a03366fc..fd7070bab 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -35,7 +35,7 @@ GdkPixbuf* render_pixbuf(NRArenaItem* root, double scale_factor, const Geom::Rect& dbox, unsigned psize) { NRGC gc(NULL); - Geom::Matrix t(Geom::Scale(scale_factor, scale_factor)); + Geom::Affine t(Geom::Scale(scale_factor, scale_factor)); nr_arena_item_set_transform(root, t); gc.transform.setIdentity(); diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index d405afb8f..4f4f8a022 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -82,6 +82,7 @@ #include "svg/svg-color.h" #include "sp-namedview.h" #include "snap.h" +#include "persp3d.h" /// @brief Made up mimetype to represent Gdk::Pixbuf clipboard contents #define CLIPBOARD_GDK_PIXBUF_TARGET "image/x-gdk-pixbuf" @@ -602,7 +603,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) if (!SP_IS_ITEM(i->data)) { continue; } - Inkscape::XML::Node *obj = SP_OBJECT_REPR(i->data); + Inkscape::XML::Node *obj = reinterpret_cast<SPObject *>(i->data)->getRepr(); Inkscape::XML::Node *obj_copy = _copyNode(obj, _doc, _root); // copy complete inherited style @@ -628,7 +629,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) // copy path effect from the first path if (SP_IS_OBJECT(sorted_items->data)) { - gchar const *effect = SP_OBJECT_REPR(sorted_items->data)->attribute("inkscape:path-effect"); + gchar const *effect = reinterpret_cast<SPObject *>(sorted_items->data)->getRepr()->attribute("inkscape:path-effect"); if (effect) { _clipnode->setAttribute("inkscape:path-effect", effect); } @@ -677,7 +678,7 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item) SPShape *shape = SP_SHAPE (item); for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) { if (shape->marker[i]) { - _copyNode(SP_OBJECT_REPR(SP_OBJECT(shape->marker[i])), _doc, _defs); + _copyNode(shape->marker[i]->getRepr(), _doc, _defs); } } } @@ -689,14 +690,14 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item) { LivePathEffectObject *lpeobj = (*it)->lpeobject; if (lpeobj) { - _copyNode(SP_OBJECT_REPR(SP_OBJECT(lpeobj)), _doc, _defs); + _copyNode(lpeobj->getRepr(), _doc, _defs); } } } } // For 3D boxes, copy perspectives if (SP_IS_BOX3D(item)) { - _copyNode(SP_OBJECT_REPR(SP_OBJECT(box3d_get_perspective(SP_BOX3D(item)))), _doc, _defs); + _copyNode(box3d_get_perspective(SP_BOX3D(item))->getRepr(), _doc, _defs); } // Copy text paths if (SP_IS_TEXT_TEXTPATH(item)) { @@ -704,14 +705,14 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item) } // Copy clipping objects if (item->clip_ref->getObject()) { - _copyNode(SP_OBJECT_REPR(item->clip_ref->getObject()), _doc, _defs); + _copyNode(item->clip_ref->getObject()->getRepr(), _doc, _defs); } // Copy mask objects if (item->mask_ref->getObject()) { SPObject *mask = item->mask_ref->getObject(); - _copyNode(SP_OBJECT_REPR(mask), _doc, _defs); + _copyNode(mask->getRepr(), _doc, _defs); // recurse into the mask for its gradients etc. - for (SPObject *o = SP_OBJECT(mask)->children ; o != NULL ; o = o->next) { + for (SPObject *o = mask->children ; o != NULL ; o = o->next) { if (SP_IS_ITEM(o)) { _copyUsedDefs(SP_ITEM(o)); } @@ -721,12 +722,12 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item) if (style->getFilter()) { SPObject *filter = style->getFilter(); if (SP_IS_FILTER(filter)) { - _copyNode(SP_OBJECT_REPR(filter), _doc, _defs); + _copyNode(filter->getRepr(), _doc, _defs); } } // recurse - for (SPObject *o = SP_OBJECT(item)->children ; o != NULL ; o = o->next) { + for (SPObject *o = item->children ; o != NULL ; o = o->next) { if (SP_IS_ITEM(o)) { _copyUsedDefs(SP_ITEM(o)); } @@ -741,7 +742,7 @@ void ClipboardManagerImpl::_copyGradient(SPGradient *gradient) { while (gradient) { // climb up the refs, copying each one in the chain - _copyNode(SP_OBJECT_REPR(gradient), _doc, _defs); + _copyNode(gradient->getRepr(), _doc, _defs); gradient = gradient->ref->getObject(); } } @@ -754,7 +755,7 @@ void ClipboardManagerImpl::_copyPattern(SPPattern *pattern) { // climb up the references, copying each one in the chain while (pattern) { - _copyNode(SP_OBJECT_REPR(pattern), _doc, _defs); + _copyNode(pattern->getRepr(), _doc, _defs); // items in the pattern may also use gradients and other patterns, so recurse for ( SPObject *child = pattern->firstChild() ; child ; child = child->getNext() ) { @@ -777,7 +778,7 @@ void ClipboardManagerImpl::_copyTextPath(SPTextPath *tp) if (!path) { return; } - Inkscape::XML::Node *path_node = SP_OBJECT_REPR(path); + Inkscape::XML::Node *path_node = path->getRepr(); // Do not copy the text path to defs if it's already copied if (sp_repr_lookup_child(_root, "id", path_node->attribute("id"))) { @@ -813,7 +814,7 @@ void ClipboardManagerImpl::_pasteDocument(SPDesktop *desktop, SPDocument *clipdo { SPDocument *target_document = sp_desktop_document(desktop); Inkscape::XML::Node *root = clipdoc->getReprRoot(); - Inkscape::XML::Node *target_parent = SP_OBJECT_REPR(desktop->currentLayer()); + Inkscape::XML::Node *target_parent = desktop->currentLayer()->getRepr(); Inkscape::XML::Document *target_xmldoc = target_document->getReprDoc(); // copy definitions @@ -844,7 +845,7 @@ void ClipboardManagerImpl::_pasteDocument(SPDesktop *desktop, SPDocument *clipdo selection->setReprList(pasted_objects); // invers apply parent transform - Geom::Matrix doc2parent = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + Geom::Affine doc2parent = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); sp_selection_apply_affine(selection, desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false); // Update (among other things) all curves in paths, for bounds() to work @@ -893,7 +894,7 @@ void ClipboardManagerImpl::_pasteDefs(SPDesktop *desktop, SPDocument *clipdoc) SPDocument *target_document = sp_desktop_document(desktop); Inkscape::XML::Node *root = clipdoc->getReprRoot(); Inkscape::XML::Node *defs = sp_repr_lookup_name(root, "svg:defs", 1); - Inkscape::XML::Node *target_defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(target_document)); + Inkscape::XML::Node *target_defs = SP_DOCUMENT_DEFS(target_document)->getRepr(); Inkscape::XML::Document *target_xmldoc = target_document->getReprDoc(); prevent_id_clashes(clipdoc, target_document); @@ -1253,7 +1254,7 @@ void ClipboardManagerImpl::_createInternalClipboard() if ( _clipboardSPDoc == NULL ) { _clipboardSPDoc = SPDocument::createNewDoc(NULL, false, true); //g_assert( _clipboardSPDoc != NULL ); - _defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(_clipboardSPDoc)); + _defs = SP_DOCUMENT_DEFS(_clipboardSPDoc)->getRepr(); _doc = _clipboardSPDoc->getReprDoc(); _root = _clipboardSPDoc->getReprRoot(); diff --git a/src/ui/context-menu.cpp b/src/ui/context-menu.cpp index c544d1999..05fe9a459 100644 --- a/src/ui/context-menu.cpp +++ b/src/ui/context-menu.cpp @@ -278,20 +278,20 @@ sp_item_create_link(GtkMenuItem *menuitem, SPItem *item) Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:a"); - SP_OBJECT_REPR(SP_OBJECT_PARENT(item))->addChild(repr, SP_OBJECT_REPR(item)); - SPObject *object = SP_OBJECT_DOCUMENT(item)->getObjectByRepr(repr); + item->parent->getRepr()->addChild(repr, item->getRepr()); + SPObject *object = item->document->getObjectByRepr(repr); g_return_if_fail(SP_IS_ANCHOR(object)); - const char *id = SP_OBJECT_REPR(item)->attribute("id"); - Inkscape::XML::Node *child = SP_OBJECT_REPR(item)->duplicate(xml_doc); - SP_OBJECT(item)->deleteObject(false); + const char *id = item->getRepr()->attribute("id"); + Inkscape::XML::Node *child = item->getRepr()->duplicate(xml_doc); + item->deleteObject(false); repr->addChild(child, NULL); child->setAttribute("id", id); Inkscape::GC::release(repr); Inkscape::GC::release(child); - DocumentUndo::done(SP_OBJECT_DOCUMENT(object), SP_VERB_NONE, + DocumentUndo::done(object->document, SP_VERB_NONE, _("Create link")); sp_object_attributes_dialog(object, "SPAnchor"); @@ -371,7 +371,7 @@ sp_anchor_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) static void sp_anchor_link_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor) { - sp_object_attributes_dialog(SP_OBJECT(anchor), "Link"); + sp_object_attributes_dialog(anchor, "Link"); } static void @@ -420,7 +420,7 @@ sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(sp_image_image_edit), item); gtk_widget_show(w); gtk_menu_append(GTK_MENU(m), w); - Inkscape::XML::Node *ir = SP_OBJECT_REPR(object); + Inkscape::XML::Node *ir = object->getRepr(); const gchar *href = ir->attribute("xlink:href"); if ( (!href) || ((strncmp(href, "data:", 5) == 0)) ) { gtk_widget_set_sensitive( w, FALSE ); @@ -430,23 +430,16 @@ sp_image_menu(SPObject *object, SPDesktop *desktop, GtkMenu *m) static void sp_image_image_properties(GtkMenuItem */*menuitem*/, SPAnchor *anchor) { - sp_object_attributes_dialog(SP_OBJECT(anchor), "Image"); + sp_object_attributes_dialog(anchor, "Image"); } static gchar* getImageEditorName() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gchar* value = 0; - Glib::ustring choices = prefs->getString("/options/bitmapeditor/choices"); + Glib::ustring choices = prefs->getString("/options/bitmapeditor/value"); if (!choices.empty()) { - gchar** splits = g_strsplit(choices.data(), ",", 0); - gint numIems = g_strv_length(splits); - - int setting = prefs->getIntLimited("/options/bitmapeditor/value", 0, 0, numIems); - value = g_strdup(splits[setting]); - - g_strfreev(splits); + value = g_strdup(choices.c_str()); } - if (!value) { value = g_strdup("gimp"); } @@ -455,21 +448,51 @@ static gchar* getImageEditorName() { static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor) { - SPObject* obj = SP_OBJECT(anchor); - Inkscape::XML::Node *ir = SP_OBJECT_REPR(obj); + SPObject* obj = anchor; + Inkscape::XML::Node *ir = obj->getRepr(); const gchar *href = ir->attribute("xlink:href"); GError* errThing = 0; - gchar* editorBin = getImageEditorName(); - gchar const* args[] = {editorBin, href, 0}; - g_spawn_async(0, // working dir - const_cast<gchar **>(args), - 0, //envp - G_SPAWN_SEARCH_PATH, - 0, // child_setup - 0, // user_data - 0, //GPid *child_pid - &errThing); + Glib::ustring cmdline = getImageEditorName(); + Glib::ustring fullname; + +#ifdef WIN32 + // g_spawn_command_line_sync parsing is done according to Unix shell rules, + // not Windows command interpreter rules. Thus we need to enclose the + // executable path with sigle quotes. + int index = cmdline.find(".exe"); + if ( index < 0 ) index = cmdline.find(".bat"); + if ( index < 0 ) index = cmdline.find(".com"); + if ( index >= 0 ) { + Glib::ustring editorBin = cmdline.substr(0, index + 4).c_str(); + Glib::ustring args = cmdline.substr(index + 4, cmdline.length()).c_str(); + editorBin.insert(0, "'"); + editorBin.append("'"); + cmdline = editorBin; + cmdline.append(args); + } else { + // Enclose the whole command line if no executable path can be extracted. + cmdline.insert(0, "'"); + cmdline.append("'"); + } +#endif + + if (strncmp (href,"file:",5) == 0) { + // URI to filename conversion + fullname = g_filename_from_uri(href, NULL, NULL); + } else { + fullname.append(href); + } + + cmdline.append(" '"); + cmdline.append(fullname.c_str()); + cmdline.append("'"); + + //printf("##Command line: %s\n", cmdline.c_str()); + + g_spawn_command_line_async(cmdline.c_str(), + &errThing); + if ( errThing ) { g_warning("Problem launching editor (%d). %s", errThing->code, errThing->message); SPDesktop *desktop = (SPDesktop*)gtk_object_get_data(GTK_OBJECT(menuitem), "desktop"); @@ -477,7 +500,6 @@ static void sp_image_image_edit(GtkMenuItem *menuitem, SPAnchor *anchor) g_error_free(errThing); errThing = 0; } - g_free(editorBin); } /* Fill and Stroke entry */ diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp index 8db5e7c0b..d1bc255b0 100644 --- a/src/ui/dialog/aboutbox.cpp +++ b/src/ui/dialog/aboutbox.cpp @@ -104,10 +104,11 @@ AboutBox::AboutBox() : Gtk::Dialog(_("About Inkscape")) { Gtk::Label *label=new Gtk::Label(); gchar *label_text = - g_strdup_printf("<small><i>Inkscape %s</i></small>", + g_strdup_printf("<small>Inkscape %s</small>", Inkscape::version_string); label->set_markup(label_text); label->set_alignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER); + label->set_padding(5,0); g_free(label_text); label->set_selectable(true); label->show(); @@ -165,7 +166,7 @@ Gtk::Widget *build_splash_widget() { doc->doUnref(); - sp_svg_view_widget_set_resize(SP_SVG_VIEW_WIDGET(v), FALSE, (int)width, (int)height); + SP_SVG_VIEW_WIDGET(v)->setResize(false, static_cast<int>(width), static_cast<int>(height)); Gtk::AspectFrame *frame=new Gtk::AspectFrame(); frame->unset_label(); @@ -225,152 +226,155 @@ void AboutBox::initStrings() { * and paste the result from the combo box here. */ authors_text = - "Maximilian Albert\n" - "Josh Andler\n" - "Tavmjong Bah\n" - "Pierre Barbry-Blot\n" - "Jean-François Barraud\n" - "Bill Baxter\n" - "John Beard\n" - "John Bintz\n" - "Arpad Biro\n" - "Nicholas Bishop\n" - "Joshua L. Blocher\n" - "Henrik Bohre\n" - "Boldewyn\n" - "Daniel Borgmann\n" - "Bastien Bouclet\n" - "Hans Breuer\n" - "Gustav Broberg\n" - "Christopher Brown\n" - "Marcus Brubaker\n" - "Luca Bruno\n" - "Nicu Buculei\n" - "Bulia Byak\n" - "Pierre Caclin\n" - "Ian Caldwell\n" - "Gail Carmichael\n" - "Ed Catmur\n" - "Chema Celorio\n" - "Johan Ceuppens\n" - "Zbigniew Chyla\n" - "Alexander Clausen\n" - "John Cliff\n" - "Kees Cook\n" - "Ben Cromwell\n" - "Robert Crosbie\n" - "Jon Cruz\n" - "AurĂ©lie De-Cooman\n" - "Milosz Derezynski\n" - "Daniel DĂaz\n" - "Bruno Dilly\n" - "Larry Doolittle\n" - "Tim Dwyer\n" - "Maxim V. Dziumanenko\n" - "Johan Engelen\n" - "Miklos Erdelyi\n" - "Ulf Erikson\n" - "NoĂ© Falzon\n" - "Frank Felfe\n" - "Andrew Fitzsimon\n" - "Edward Flick\n" - "Marcin Floryan\n" - "Ben Fowler\n" - "Fred\n" - "Cedric Gemy\n" - "Steren Giannini\n" - "Olivier Gondouin\n" - "Ted Gould\n" - "Toine de Greef\n" - "Michael Grosberg\n" - "Bryce Harrington\n" - "Dale Harvey\n" - "AurĂ©lio A. Heckert\n" - "Carl Hetherington\n" - "Jos Hirth\n" - "Hannes Hochreiner\n" - "Thomas Holder\n" - "Joel Holdsworth\n" - "Alan Horkan\n" - "Karl Ove Hufthammer\n" - "Richard Hughes\n" - "Nathan Hurst\n" - "inductiveload\n" - "Thomas Ingham\n" - "Jean-Olivier Irisson\n" - "Bob Jamison\n" - "jEsuSdA\n" - "Lauris Kaplinski\n" - "Lynn Kerby\n" - "Niko Kiirala\n" - "James Kilfiger\n" - "Jason Kivlighn\n" - "Adrian Knoth\n" - "Krzysztof KosiĆski\n" - "Petr Kovar\n" - "BenoĂźt Lavorata\n" - "Alex Leone\n" - "Julien Leray\n" - "Raph Levien\n" - "Diederik van Lierop\n" - "Nicklas Lindgren\n" - "Vitaly Lipatov\n" - "Ivan Louette\n" - "Pierre-Antoine Marc\n" - "Aurel-AimĂ© Marmion\n" - "Colin Marquardt\n" - "Dmitry G. Mastrukov\n" - "Matiphas\n" - "Michael Meeks\n" - "Federico Mena\n" - "MenTaLguY\n" - "Aubanel Monnier\n" - "Vincent Montagne\n" - "Tim Mooney\n" - "Derek P. Moore\n" - "Peter Moulder\n" - "Jörg MĂŒller\n" - "Yukihiro Nakai\n" - "Victor Navez\n" - "Christian Neumair\n" - "Andreas Nilsson\n" - "Mitsuru Oka\n" - "Marten Owens\n" - "Alvin Penner\n" - "Jon Phillips\n" - "Zdenko Podobny\n" - "Alexandre Prokoudine\n" - "Jean-RenĂ© Reinhard\n" - "Alexey Remizov\n" - "Frederic Rodrigo\n" - "Hugo Rodrigues\n" - "Juarez Rudsatz\n" - "Xavier Conde Rueda\n" - "Felipe CorrĂȘa da Silva Sanches\n" - "Christian Schaller\n" - "Marco Scholten\n" - "Tom von Schwerdtner\n" - "Danilo Ć egan\n" - "Shivaken\n" - "Michael Sloan\n" - "BoĆĄtjan Ć petiÄ\n" - "Aaron Spike\n" - "Kaushik Sridharan\n" - "Ralf Stephan\n" - "Dariusz Stojek\n" - "Martin Sucha\n" - "Pat Suwalski\n" - "Adib Taraben\n" - "Hugh Tebby\n" - "Jonas Termeau\n" - "David Turner\n" - "Andre Twupack\n" - "Aleksandar UroĆĄeviÄ\n" - "Lucas Vieites\n" - "Michael Wybrow\n" - "Daniel Yacob\n" - "Masatake Yamato\n" - "David Yip"; +"Maximilian Albert\n" +"Josh Andler\n" +"Tavmjong Bah\n" +"Pierre Barbry-Blot\n" +"Jean-François Barraud\n" +"Bill Baxter\n" +"John Beard\n" +"John Bintz\n" +"Arpad Biro\n" +"Nicholas Bishop\n" +"Joshua L. Blocher\n" +"Henrik Bohre\n" +"Boldewyn\n" +"Daniel Borgmann\n" +"Bastien Bouclet\n" +"Hans Breuer\n" +"Gustav Broberg\n" +"Christopher Brown\n" +"Marcus Brubaker\n" +"Luca Bruno\n" +"Nicu Buculei\n" +"Bulia Byak\n" +"Pierre Caclin\n" +"Ian Caldwell\n" +"Gail Carmichael\n" +"Ed Catmur\n" +"Chema Celorio\n" +"Johan Ceuppens\n" +"Zbigniew Chyla\n" +"Alexander Clausen\n" +"John Cliff\n" +"Kees Cook\n" +"Ben Cromwell\n" +"Robert Crosbie\n" +"Jon Cruz\n" +"AurĂ©lie De-Cooman\n" +"Milosz Derezynski\n" +"Daniel DĂaz\n" +"Bruno Dilly\n" +"Larry Doolittle\n" +"Nicolas Dufour\n" +"Tim Dwyer\n" +"Maxim V. Dziumanenko\n" +"Johan Engelen\n" +"Miklos Erdelyi\n" +"Ulf Erikson\n" +"NoĂ© Falzon\n" +"Frank Felfe\n" +"Andrew Fitzsimon\n" +"Edward Flick\n" +"Marcin Floryan\n" +"Ben Fowler\n" +"Fred\n" +"Cedric Gemy\n" +"Steren Giannini\n" +"Olivier Gondouin\n" +"Ted Gould\n" +"Toine de Greef\n" +"Michael Grosberg\n" +"Bryce Harrington\n" +"Dale Harvey\n" +"AurĂ©lio Adnauer Heckert\n" +"Carl Hetherington\n" +"Jos Hirth\n" +"Hannes Hochreiner\n" +"Thomas Holder\n" +"Joel Holdsworth\n" +"Alan Horkan\n" +"Karl Ove Hufthammer\n" +"Richard Hughes\n" +"Nathan Hurst\n" +"inductiveload\n" +"Thomas Ingham\n" +"Jean-Olivier Irisson\n" +"Bob Jamison\n" +"jEsuSdA\n" +"Lauris Kaplinski\n" +"Lynn Kerby\n" +"Niko Kiirala\n" +"James Kilfiger\n" +"Jason Kivlighn\n" +"Adrian Knoth\n" +"Krzysztof KosiĆski\n" +"Petr Kovar\n" +"BenoĂźt Lavorata\n" +"Alex Leone\n" +"Julien Leray\n" +"Raph Levien\n" +"Diederik van Lierop\n" +"Nicklas Lindgren\n" +"Vitaly Lipatov\n" +"Ivan Louette\n" +"Pierre-Antoine Marc\n" +"Aurel-AimĂ© Marmion\n" +"Colin Marquardt\n" +"Craig Marshall\n" +"Dmitry G. Mastrukov\n" +"Matiphas\n" +"Michael Meeks\n" +"Federico Mena\n" +"MenTaLguY\n" +"Aubanel Monnier\n" +"Vincent Montagne\n" +"Tim Mooney\n" +"Derek P. Moore\n" +"Peter Moulder\n" +"Jörg MĂŒller\n" +"Yukihiro Nakai\n" +"Victor Navez\n" +"Christian Neumair\n" +"Andreas Nilsson\n" +"Mitsuru Oka\n" +"Marten Owens\n" +"Alvin Penner\n" +"Jon Phillips\n" +"Zdenko Podobny\n" +"Alexandre Prokoudine\n" +"Jean-RenĂ© Reinhard\n" +"Alexey Remizov\n" +"Frederic Rodrigo\n" +"Hugo Rodrigues\n" +"Juarez Rudsatz\n" +"Xavier Conde Rueda\n" +"Felipe CorrĂȘa da Silva Sanches\n" +"Christian Schaller\n" +"Marco Scholten\n" +"Tom von Schwerdtner\n" +"Danilo Ć egan\n" +"Abhishek Sharma\n" +"Shivaken\n" +"Michael Sloan\n" +"BoĆĄtjan Ć petiÄ\n" +"Aaron Spike\n" +"Kaushik Sridharan\n" +"Ralf Stephan\n" +"Dariusz Stojek\n" +"Martin Sucha\n" +"Pat Suwalski\n" +"Adib Taraben\n" +"Hugh Tebby\n" +"Jonas Termeau\n" +"David Turner\n" +"Andre Twupack\n" +"Aleksandar UroĆĄeviÄ\n" +"Lucas Vieites\n" +"Michael Wybrow\n" +"Daniel Yacob\n" +"Masatake Yamato\n" +"David Yip"; //############################## //# T R A N S L A T O R S @@ -409,133 +413,136 @@ void AboutBox::initStrings() { * and paste the result from the combo box here. */ gchar const *allTranslators = - "3ARRANO.com <3arrano@3arrano.com>, 2005.\n" - "Adib Taraben <theadib@googlemail.com>, 2004.\n" - "Alan Monfort <alan.monfort@free.fr>, 2009-2010.\n" - "Alastair McKinstry <mckinstry@computer.org>, 2000.\n" - "Aleksandar UroĆĄeviÄ <urke@users.sourceforge.net>, 2004, 2005, 2006.\n" - "Alessio Frusciante <algol@firenze.linux.it>, 2002, 2003.\n" - "Alexander Shopov <ash@contact.bg>, 2006.\n" - "Alexandre Prokoudine <alexandre.prokoudine@gmail.com>, 2005.\n" - "Alexey Remizov <alexey@remizov.pp.ru>, 2004.\n" - "Ali Ghanavatian <ghanvatian.ali@gmail.com>, 2010.\n" - "Ălvaro Lopes <alvieboy@alvie.com>, 2001, 2002.\n" - "Andreas Hyden <a.hyden@cyberpoint.se>, 2000.\n" - "Andrius Ramanauskas <knutux@gmail.com>, 2006.\n" - "Antonio Codazzi <f_sophia@libero.it>, 2006, 2007.\n" - "AntĂŽnio ClĂĄudio (LedStyle) <ledstyle@gmail.com>, 2006.\n" - "Amanpreet Singh Brar Alamwalia <apbrar@gmail.com>, 2005.\n" - "Arman Aksoy <armish@linux-sevenler.de>, 2003.\n" - "Arpad Biro <biro_arpad@yahoo.com>, 2004, 2005.\n" - "Benedikt Roth <Benedikt.Roth@gmx.net>, 2000.\n" - "Benno Schulenberg <benno@vertaalt.nl>, 2008.\n" - "BoĆĄtjan Ć petiÄ <igzebedze@cyberpipe.org>, 2004, 2005.\n" - "Brisa Francesco <fbrisa@yahoo.it>, 2000.\n" - "bulia byak <buliabyak@users.sf.net>, 2004.\n" - "Chris jia <Chrisjiasl@gmail.com>, 2006.\n" - "Christian Meyer <chrisime@gnome.org>, 2000-2002.\n" - "Christian Neumair <chris@gnome-de.org>, 2002, 2003.\n" - "Christian Rose <menthos@menthos.com>, 2000, 2001, 2002, 2003.\n" - "Cristian SecarÄ <cristi@secarica.ro>, 2010.\n" - "Christophe Merlet (RedFox) <redfox@redfoxcenter.org>, 2000-2002.\n" - "Clytie Siddall <clytie@riverland.net.au>, 2004-2008.\n" - "Colin Marquardt <colin@marquardt-home.de>, 2004-2006.\n" - "CĂ©dric Gemy <radar.map35@free.fr>, 2006.\n" - "Daniel DĂaz <yosoy@danieldiaz.org>, 2004.\n" - "Didier Conchaudron <conchaudron@free.fr>, 2003.\n" - "Dorji Tashi <dorjee_doss@hotmail.com>, 2006.\n" - "Duarte Loreto <happyguy_pt@hotmail.com> 2002, 2003 (Maintainer).\n" - "Equipe de Tradução Inkscape Brasil <www.inkscapebrasil.org>, 2007.\n" - "Fatih Demir <kabalak@gtranslator.org>, 2000.\n" - "Foppe Benedictus <foppe.benedictus@gmail.com>, 2007-2009.\n" - "Francesc Dorca <f.dorca@filnet.es>, 2003. TraducciĂł sodipodi.\n" - "Francisco Javier F. Serrador <serrador@arrakis.es>, 2003.\n" - "Francisco XosĂ© VĂĄzquez Grandal <fxvazquez@arrakis.es>, 2001.\n" - "Frederic Rodrigo <f.rodrigo free.fr>, 2004-2005.\n" - "Ge'ez Frontier Foundation <locales@geez.org>, 2002.\n" - "Hleb Valoshka <375gnu@gmail.com>, 2008-2009.\n" - "Hizkuntza Politikarako Sailburuordetza <hizkpol@ej-gv.es>, 2005.\n" - "Ilia Penev <lichopicho@gmail.com>, 2006.\n" - "Ivan MasĂĄr <helix84@centrum.sk>, 2006, 2007, 2008, 2009, 2010. \n" - "Iñaki Larrañaga <dooteo@euskalgnu.org>, 2006.\n" - "Jeffrey Steve BorbĂłn Sanabria <jeff_kerokid@yahoo.com>, 2005.\n" - "Joaquim Perez i Noguer <noguer@gmail.com>, 2008-2009.\n" - "Jörg MĂŒller <jfm@ram-brand.de>, 2005.\n" - "Jeroen van der Vegt <jvdvegt@gmail.com>, 2003, 2005, 2008.\n" - "Jin-Hwan Jeong <yongdoria@gmail.com>, 2009.\n" - "Jonathan Ernst <jernst@users.sourceforge.net>, 2006.\n" - "Jose Antonio Salgueiro Aquino <developer@telefonica.net>, 2003.\n" - "Josef Vybiral <josef.vybiral@gmail.com>, 2005-2006.\n" - "Juarez Rudsatz <juarez@correio.com>, 2004.\n" - "Junichi Uekawa <dancer@debian.org>, 2002.\n" - "Jurmey Rabgay <jur_gay@yahoo.com>, 2006.\n" - "Kai Lahmann <kailahmann@01019freenet.de>, 2000.\n" - "Karl Ove Hufthammer <karl@huftis.org>, 2004, 2005.\n" - "KATSURAGAWA Naoki <naopon@private.email.ne.jp>, 2006.\n" - "Keld Simonsen <keld@dkuug.dk>, 2000, 2001.\n" - "Kenji Inoue <kenz@oct.zaq.ne.jp>, 2006-2007.\n" - "Khandakar Mujahidul Islam <suzan@bengalinux.org>, 2006.\n" - "Kitae <bluetux@gmail.com>, 2006.\n" - "Kjartan Maraas <kmaraas@gnome.org>, 2000-2002.\n" - "Kris De Gussem <kris.DeGussem@gmail.com>, 2008-2010.\n" - "Lauris Kaplinski <lauris@ariman.ee>, 2000.\n" - "Leandro Regueiro <leandro.regueiro@gmail.com>, 2006-2008,2010.\n" - "Liu Xiaoqin <liuxqsmile@gmail.com>, 2008.\n" - "Luca Bruno <luca.br@uno.it>, 2005.\n" - "Lucas Vieites Fariña<lucas@codexion.com>, 2003-2010.\n" - "Mahesh subedi <submanesh@hotmail.com>, 2006.\n" - "Martin Srebotnjak, <miles@filmsi.net>, 2005, 2010.\n" - "Masatake YAMATO <jet@gyve.org>, 2002.\n" - "Masato Hashimoto <cabezon.hashimoto@gmail.com>, 2009-2010.\n" - "Matiphas <matiphas _a_ free _point_ fr>, 2004-2006.\n" - "Mattias Hultgren <mattias_hultgren@tele2.se>, 2005.\n" - "Maxim Dziumanenko <mvd@mylinux.com.ua>, 2004.\n" - "MÉtin Æmirov <metin@karegen.com>, 2003.\n" - "Mitsuru Oka <oka326@parkcity.ne.jp>, 2002.\n" - "Morphix User <pchitrakar@gmail.com>, 2006.\n" - "Mufit Eribol <meribol@ere.com.tr>, 2000.\n" - "Muhammad Bashir Al-Noimi <mhdbnoimi@gmail.com>, 2008.\n" - "Myckel Habets <myckel@sdf.lonestar.org>, 2008.\n" - "Nguyen Dinh Trung <nguyendinhtrung141@gmail.com>, 2007, 2008.\n" - "Nicolas Dufour <nicoduf@yahoo.fr>, 2008-2010.\n" - "Pawan Chitrakar <pchitrakar@gmail.com>, 2006.\n" - "PrzemysĆaw Loesch <p_loesch@poczta.onet.pl>, 2005.\n" - "Quico Llach <quico@softcatala.org>, 2000. TraducciĂł sodipodi.\n" - "Raymond Ostertag <raymond@linuxgraphic.org>, 2002, 2003.\n" - "Riku Leino <tsoots@gmail.com>, 2006.\n" - "Rune RĂžnde Laursen <runerl@skjoldhoej.dk>, 2006.\n" - "Ruud Steltenpool <svg@steltenpower.com>, 2006.\n" - "Serdar Soytetir <sendirom@gmail.com>, 2005.\n" - "shivaken <shivaken@owls-nest.net>, 2004.\n" - "Shyam Krishna Bal <shyamkrishna_bal@yahoo.com>, 2006.\n" - "Simos Xenitellis <simos@hellug.gr>, 2001.\n" - "Spyros Blanas <cid_e@users.sourceforge.net>, 2006.\n" - "Stefan Graubner <pflaumenmus92@gmx.net>, 2005.\n" - "Supranee Thirawatthanasuk <supranee@opentle.org>, 2006.\n" - "Takeshi Aihana <aihana@muc.biglobe.ne.jp>, 2000, 2001.\n" - "Tim Sheridan <tim.sheridan@gmail.com>, 2007-2010.\n" - "Theppitak Karoonboonyanan <thep@linux.thai.net>, 2006.\n" - "Thiago Pimentel <thiago.merces@gmail.com>, 2006.\n" - "Toshifumi Sato <sato@centrosystem.com>, 2005.\n" - "Jon South <striker@lunar-linux.org>, 2006. \n" - "Uwe Schöler <oss@oss-marketplace.com>, 2006.\n" - "Valek Filippov <frob@df.ru>, 2000, 2003.\n" - "Victor Dachev <vdachev@gmail.com>, 2006.\n" - "Vincent van Adrighem <V.vanAdrighem@dirck.mine.nu>, 2003.\n" - "Vital Khilko <dojlid@mova.org>, 2003.\n" - "Vitaly Lipatov <lav@altlinux.ru>, 2002, 2004.\n" - "vonHalenbach <vonHalenbach@users.sourceforge.net>, 2005.\n" - "Wang Li <charlesw1234@163.com>, 2002.\n" - "Wei-Lun Chao <william.chao@ossii.com.tw>, 2006.\n" - "Wolfram Strempfer <wolfram@strempfer.de>, 2006.\n" - "Xavier Conde Rueda <xavi.conde@gmail.com>, 2004-2008.\n" - "Yaron Shahrabani <sh.yaron@gmail.com>, 2009.\n" - "Yukihiro Nakai <nakai@gnome.gr.jp>, 2000, 2003.\n" - "Yuri Beznos <zhiz0id@gmail.com>, 2006.\n" - "Yuri Chornoivan <yurchor@ukr.net>, 2007-2010.\n" - "Yuri Syrota <rasta@renome.rovno.ua>, 2000.\n" - "Yves Guillou <yvesguillou@users.sourceforge.net>, 2004.\n" - "Zdenko PodobnĂœ <zdpo@mailbox.sk>, 2003, 2004." +"3ARRANO.com <3arrano@3arrano.com>, 2005.\n" +"Adib Taraben <theadib@googlemail.com>, 2004.\n" +"Alan Monfort <alan.monfort@free.fr>, 2009-2010.\n" +"Alastair McKinstry <mckinstry@computer.org>, 2000.\n" +"Aleksandar UroĆĄeviÄ <urke@users.sourceforge.net>, 2004-2006.\n" +"Alessio Frusciante <algol@firenze.linux.it>, 2002, 2003.\n" +"Alexander Shopov <ash@contact.bg>, 2006.\n" +"Alexandre Prokoudine <alexandre.prokoudine@gmail.com>, 2005.\n" +"Alexey Remizov <alexey@remizov.pp.ru>, 2004.\n" +"Ali Ghanavatian <ghanvatian.ali@gmail.com>, 2010.\n" +"Ălvaro Lopes <alvieboy@alvie.com>, 2001, 2002.\n" +"Andreas Hyden <a.hyden@cyberpoint.se>, 2000.\n" +"Andrius Ramanauskas <knutux@gmail.com>, 2006.\n" +"Antonio Codazzi <f_sophia@libero.it>, 2006, 2007.\n" +"AntĂŽnio ClĂĄudio (LedStyle) <ledstyle@gmail.com>, 2006.\n" +"Amanpreet Singh Brar Alamwalia <apbrar@gmail.com>, 2005.\n" +"Arman Aksoy <armish@linux-sevenler.de>, 2003.\n" +"Arpad Biro <biro_arpad@yahoo.com>, 2004, 2005.\n" +"Benedikt Roth <Benedikt.Roth@gmx.net>, 2000.\n" +"Benno Schulenberg <benno@vertaalt.nl>, 2008.\n" +"BoĆĄtjan Ć petiÄ <igzebedze@cyberpipe.org>, 2004, 2005.\n" +"Brisa Francesco <fbrisa@yahoo.it>, 2000.\n" +"bulia byak <buliabyak@users.sf.net>, 2004.\n" +"Chris jia <Chrisjiasl@gmail.com>, 2006.\n" +"Christian Meyer <chrisime@gnome.org>, 2000-2002.\n" +"Christian Neumair <chris@gnome-de.org>, 2002, 2003.\n" +"Christian Rose <menthos@menthos.com>, 2000-2003.\n" +"Cristian SecarÄ <cristi@secarica.ro>, 2010.\n" +"Christophe Merlet (RedFox) <redfox@redfoxcenter.org>, 2000-2002.\n" +"Clytie Siddall <clytie@riverland.net.au>, 2004-2008.\n" +"Colin Marquardt <colin@marquardt-home.de>, 2004-2006.\n" +"CĂ©dric Gemy <radar.map35@free.fr>, 2006.\n" +"Daniel DĂaz <yosoy@danieldiaz.org>, 2004.\n" +"Didier Conchaudron <conchaudron@free.fr>, 2003.\n" +"Dorji Tashi <dorjee_doss@hotmail.com>, 2006.\n" +"Duarte Loreto <happyguy_pt@hotmail.com> 2002, 2003 (Maintainer).\n" +"Elias Norberg <elno0959 at student.su.se>, 2009.\n" +"Equipe de Tradução Inkscape Brasil <www.inkscapebrasil.org>, 2007.\n" +"Fatih Demir <kabalak@gtranslator.org>, 2000.\n" +"Foppe Benedictus <foppe.benedictus@gmail.com>, 2007-2009.\n" +"Francesc Dorca <f.dorca@filnet.es>, 2003. TraducciĂł sodipodi.\n" +"Francisco Javier F. Serrador <serrador@arrakis.es>, 2003.\n" +"Francisco XosĂ© VĂĄzquez Grandal <fxvazquez@arrakis.es>, 2001.\n" +"Frederic Rodrigo <f.rodrigo free.fr>, 2004-2005.\n" +"Ge'ez Frontier Foundation <locales@geez.org>, 2002.\n" +"George Boukeas <boukeas@gmail.com>, 2011.\n" +"Hleb Valoshka <375gnu@gmail.com>, 2008-2009.\n" +"Hizkuntza Politikarako Sailburuordetza <hizkpol@ej-gv.es>, 2005.\n" +"Ilia Penev <lichopicho@gmail.com>, 2006.\n" +"Ivan MasĂĄr <helix84@centrum.sk>, 2006, 2007, 2008, 2009, 2010. \n" +"Iñaki Larrañaga <dooteo@euskalgnu.org>, 2006.\n" +"Jeffrey Steve BorbĂłn Sanabria <jeff_kerokid@yahoo.com>, 2005.\n" +"Jesper Ăqvist <jesper@llbit.se>, 2010, 2011.\n" +"Joaquim Perez i Noguer <noguer@gmail.com>, 2008-2009.\n" +"Jörg MĂŒller <jfm@ram-brand.de>, 2005.\n" +"Jeroen van der Vegt <jvdvegt@gmail.com>, 2003, 2005, 2008.\n" +"Jin-Hwan Jeong <yongdoria@gmail.com>, 2009.\n" +"Jonathan Ernst <jernst@users.sourceforge.net>, 2006.\n" +"Jose Antonio Salgueiro Aquino <developer@telefonica.net>, 2003.\n" +"Josef Vybiral <josef.vybiral@gmail.com>, 2005-2006.\n" +"Juarez Rudsatz <juarez@correio.com>, 2004.\n" +"Junichi Uekawa <dancer@debian.org>, 2002.\n" +"Jurmey Rabgay <jur_gay@yahoo.com>, 2006.\n" +"Kai Lahmann <kailahmann@01019freenet.de>, 2000.\n" +"Karl Ove Hufthammer <karl@huftis.org>, 2004, 2005.\n" +"KATSURAGAWA Naoki <naopon@private.email.ne.jp>, 2006.\n" +"Keld Simonsen <keld@dkuug.dk>, 2000, 2001.\n" +"Kenji Inoue <kenz@oct.zaq.ne.jp>, 2006-2007.\n" +"Khandakar Mujahidul Islam <suzan@bengalinux.org>, 2006.\n" +"Kitae <bluetux@gmail.com>, 2006.\n" +"Kjartan Maraas <kmaraas@gnome.org>, 2000-2002.\n" +"Kris De Gussem <kris.DeGussem@gmail.com>, 2008-2010.\n" +"Lauris Kaplinski <lauris@ariman.ee>, 2000.\n" +"Leandro Regueiro <leandro.regueiro@gmail.com>, 2006-2008, 2010.\n" +"Liu Xiaoqin <liuxqsmile@gmail.com>, 2008.\n" +"Luca Bruno <luca.br@uno.it>, 2005.\n" +"Lucas Vieites Fariña<lucas@codexion.com>, 2003-2010.\n" +"Mahesh subedi <submanesh@hotmail.com>, 2006.\n" +"Martin Srebotnjak, <miles@filmsi.net>, 2005, 2010.\n" +"Masatake YAMATO <jet@gyve.org>, 2002.\n" +"Masato Hashimoto <cabezon.hashimoto@gmail.com>, 2009-2011.\n" +"Matiphas <matiphas _a_ free _point_ fr>, 2004-2006.\n" +"Mattias Hultgren <mattias_hultgren@tele2.se>, 2005, 2006.\n" +"Maxim Dziumanenko <mvd@mylinux.com.ua>, 2004.\n" +"MÉtin Æmirov <metin@karegen.com>, 2003.\n" +"Mitsuru Oka <oka326@parkcity.ne.jp>, 2002.\n" +"Morphix User <pchitrakar@gmail.com>, 2006.\n" +"Mufit Eribol <meribol@ere.com.tr>, 2000.\n" +"Muhammad Bashir Al-Noimi <mhdbnoimi@gmail.com>, 2008.\n" +"Myckel Habets <myckel@sdf.lonestar.org>, 2008.\n" +"Nguyen Dinh Trung <nguyendinhtrung141@gmail.com>, 2007, 2008.\n" +"Nicolas Dufour <nicoduf@yahoo.fr>, 2008-2011.\n" +"Pawan Chitrakar <pchitrakar@gmail.com>, 2006.\n" +"PrzemysĆaw Loesch <p_loesch@poczta.onet.pl>, 2005.\n" +"Quico Llach <quico@softcatala.org>, 2000. TraducciĂł sodipodi.\n" +"Raymond Ostertag <raymond@linuxgraphic.org>, 2002, 2003.\n" +"Riku Leino <tsoots@gmail.com>, 2006.\n" +"Rune RĂžnde Laursen <runerl@skjoldhoej.dk>, 2006.\n" +"Ruud Steltenpool <svg@steltenpower.com>, 2006.\n" +"Serdar Soytetir <sendirom@gmail.com>, 2005.\n" +"shivaken <shivaken@owls-nest.net>, 2004.\n" +"Shyam Krishna Bal <shyamkrishna_bal@yahoo.com>, 2006.\n" +"Simos Xenitellis <simos@hellug.gr>, 2001, 2011.\n" +"Spyros Blanas <cid_e@users.sourceforge.net>, 2006, 2011.\n" +"Stefan Graubner <pflaumenmus92@gmx.net>, 2005.\n" +"Supranee Thirawatthanasuk <supranee@opentle.org>, 2006.\n" +"Takeshi Aihana <aihana@muc.biglobe.ne.jp>, 2000, 2001.\n" +"Tim Sheridan <tim.sheridan@gmail.com>, 2007-2010.\n" +"Theppitak Karoonboonyanan <thep@linux.thai.net>, 2006.\n" +"Thiago Pimentel <thiago.merces@gmail.com>, 2006.\n" +"Toshifumi Sato <sato@centrosystem.com>, 2005.\n" +"Jon South <striker@lunar-linux.org>, 2006. \n" +"Uwe Schöler <oss@oss-marketplace.com>, 2006.\n" +"Valek Filippov <frob@df.ru>, 2000, 2003.\n" +"Victor Dachev <vdachev@gmail.com>, 2006.\n" +"Vincent van Adrighem <V.vanAdrighem@dirck.mine.nu>, 2003.\n" +"Vital Khilko <dojlid@mova.org>, 2003.\n" +"Vitaly Lipatov <lav@altlinux.ru>, 2002, 2004.\n" +"vonHalenbach <vonHalenbach@users.sourceforge.net>, 2005.\n" +"Wang Li <charlesw1234@163.com>, 2002.\n" +"Wei-Lun Chao <william.chao@ossii.com.tw>, 2006.\n" +"Wolfram Strempfer <wolfram@strempfer.de>, 2006.\n" +"Xavier Conde Rueda <xavi.conde@gmail.com>, 2004-2008.\n" +"Yaron Shahrabani <sh.yaron@gmail.com>, 2009.\n" +"Yukihiro Nakai <nakai@gnome.gr.jp>, 2000, 2003.\n" +"Yuri Beznos <zhiz0id@gmail.com>, 2006.\n" +"Yuri Chornoivan <yurchor@ukr.net>, 2007-2010.\n" +"Yuri Syrota <rasta@renome.rovno.ua>, 2000.\n" +"Yves Guillou <yvesguillou@users.sourceforge.net>, 2004.\n" +"Zdenko PodobnĂœ <zdpo@mailbox.sk>, 2003, 2004." ; translators_text.append(allTranslators); diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 48f0fbf22..f974ec6ce 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -467,7 +467,8 @@ public: dialog.tooltips().set_tip(removeOverlapXGap, _("Minimum horizontal gap (in px units) between bounding boxes")); //TRANSLATORS: "H:" stands for horizontal gap - removeOverlapXGapLabel.set_label(C_("Gap", "H:")); + removeOverlapXGapLabel.set_text_with_mnemonic(C_("Gap", "_H:")); + removeOverlapXGapLabel.set_mnemonic_widget(removeOverlapXGap); removeOverlapYGap.set_digits(1); removeOverlapYGap.set_size_request(60, -1); @@ -477,7 +478,8 @@ public: dialog.tooltips().set_tip(removeOverlapYGap, _("Minimum vertical gap (in px units) between bounding boxes")); /* TRANSLATORS: Vertical gap */ - removeOverlapYGapLabel.set_label(C_("Gap", "V:")); + removeOverlapYGapLabel.set_text_with_mnemonic(C_("Gap", "_V:")); + removeOverlapYGapLabel.set_mnemonic_widget(removeOverlapYGap); dialog.removeOverlap_table().attach(removeOverlapXGapLabel, column, column+1, row, row+1, Gtk::FILL, Gtk::FILL); dialog.removeOverlap_table().attach(removeOverlapXGap, column+1, column+2, row, row+1, Gtk::FILL, Gtk::FILL); @@ -896,7 +898,7 @@ AlignAndDistribute::AlignAndDistribute() _removeOverlapTable(1, 5, false), _nodesTable(1, 4, true), _anchorLabel(_("Relative to: ")), - _selgrpLabel(_("Treat selection as group: ")) + _selgrpLabel(_("_Treat selection as group: "), 1) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -1038,6 +1040,7 @@ AlignAndDistribute::AlignAndDistribute() _anchorBox.pack_start(_anchorLabel); _anchorBox.pack_start(_combo); + _selgrpLabel.set_mnemonic_widget(_selgrp); _selgrpBox.pack_start(_selgrpLabel); _selgrpBox.pack_start(_selgrp); _selgrp.set_active(prefs->getBool("/dialogs/align/sel-as-groups")); diff --git a/src/ui/dialog/desktop-tracker.h b/src/ui/dialog/desktop-tracker.h index edde110af..d73071194 100644 --- a/src/ui/dialog/desktop-tracker.h +++ b/src/ui/dialog/desktop-tracker.h @@ -11,6 +11,7 @@ #ifndef SEEN_DIALOG_DESKTOP_TRACKER #define SEEN_DIALOG_DESKTOP_TRACKER +#include <stddef.h> #include <sigc++/connection.h> #include <glib/gtypes.h> diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index ff31c91c4..0c49690cc 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -42,6 +42,7 @@ #include "ui/dialog/floating-behavior.h" #include "ui/dialog/dock-behavior.h" //#include "ui/dialog/print-colors-preview-dialog.h" +#include "util/ege-appear-time-tracker.h" #include "preferences.h" #ifdef ENABLE_SVG_FONTS @@ -232,10 +233,23 @@ void DialogManager::showDialog(gchar const *name) { * Shows the named dialog, creating it if necessary. */ void DialogManager::showDialog(GQuark name) { - Dialog *dialog=getDialog(name); - if (dialog) { + bool wantTiming = Inkscape::Preferences::get()->getBool("/dialogs/debug/trackAppear", false); + GTimer *timer = (wantTiming) ? g_timer_new() : 0; // if needed, must be created/started before getDialog() + Dialog *dialog = getDialog(name); + if ( dialog ) { + if ( wantTiming ) { + gchar const * nameStr = g_quark_to_string(name); + ege::AppearTimeTracker *tracker = new ege::AppearTimeTracker(timer, dialog->gobj(), nameStr); + tracker->setAutodelete(true); + timer = 0; + } dialog->present(); } + + if ( timer ) { + g_timer_destroy(timer); + timer = 0; + } } } // namespace Dialog diff --git a/src/ui/dialog/dialog.cpp b/src/ui/dialog/dialog.cpp index 43863625f..88724a90c 100644 --- a/src/ui/dialog/dialog.cpp +++ b/src/ui/dialog/dialog.cpp @@ -93,15 +93,22 @@ void unhideCallback(GtkObject */*object*/, gpointer dlgPtr) Dialog::Dialog(Behavior::BehaviorFactory behavior_factory, const char *prefs_path, int verb_num, Glib::ustring const &apply_label) - : _hiddenF12 (false), - _prefs_path (prefs_path), + : _user_hidden(false), + _hiddenF12(false), + retransientize_suppress(false), + // + _prefs_path(prefs_path), _verb_num(verb_num), - _apply_label (apply_label) + _title(), + _apply_label(apply_label), + tooltips(), + _behavior(0) { gchar title[500]; - if (verb_num) + if (verb_num) { sp_ui_dialog_title_string (Inkscape::Verb::get(verb_num), title); + } _title = title; diff --git a/src/ui/dialog/document-metadata.cpp b/src/ui/dialog/document-metadata.cpp index a8a0fa191..08479275b 100644 --- a/src/ui/dialog/document-metadata.cpp +++ b/src/ui/dialog/document-metadata.cpp @@ -85,7 +85,7 @@ DocumentMetadata::init() { update(); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(getDesktop())); + Inkscape::XML::Node *repr = sp_desktop_namedview(getDesktop())->getRepr(); repr->addListener (&_repr_events, this); show_all_children(); @@ -93,7 +93,7 @@ DocumentMetadata::init() DocumentMetadata::~DocumentMetadata() { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(getDesktop())); + Inkscape::XML::Node *repr = sp_desktop_namedview(getDesktop())->getRepr(); repr->removeListenerByData (this); for (RDElist::iterator it = _rdflist.begin(); it != _rdflist.end(); it++) @@ -211,7 +211,7 @@ DocumentMetadata::update() void DocumentMetadata::_handleDocumentReplaced(SPDesktop* desktop, SPDocument *) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(desktop)); + Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr(); repr->addListener (&_repr_events, this); update(); } @@ -219,7 +219,7 @@ DocumentMetadata::_handleDocumentReplaced(SPDesktop* desktop, SPDocument *) void DocumentMetadata::_handleActivateDesktop(Inkscape::Application *, SPDesktop *desktop) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(desktop)); + Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr(); repr->addListener(&_repr_events, this); update(); } @@ -227,7 +227,7 @@ DocumentMetadata::_handleActivateDesktop(Inkscape::Application *, SPDesktop *des void DocumentMetadata::_handleDeactivateDesktop(Inkscape::Application *, SPDesktop *desktop) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(desktop)); + Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr(); repr->removeListenerByData(this); } diff --git a/src/ui/dialog/document-metadata.h b/src/ui/dialog/document-metadata.h index 21915c00f..8194b9920 100644 --- a/src/ui/dialog/document-metadata.h +++ b/src/ui/dialog/document-metadata.h @@ -14,6 +14,7 @@ #define INKSCAPE_UI_DIALOG_DOCUMENT_METADATA_H #include <list> +#include <stddef.h> #include <sigc++/sigc++.h> #include <gtkmm/notebook.h> #include <glibmm/i18n.h> diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index 16212bef7..0c001da4b 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -143,9 +143,9 @@ DocumentProperties::init() { update(); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(getDesktop())); + Inkscape::XML::Node *repr = sp_desktop_namedview(getDesktop())->getRepr(); repr->addListener (&_repr_events, this); - Inkscape::XML::Node *root = SP_OBJECT_REPR(sp_desktop_document(getDesktop())->root); + Inkscape::XML::Node *root = sp_desktop_document(getDesktop())->root->getRepr(); root->addListener (&_repr_events, this); show_all_children(); @@ -154,9 +154,9 @@ DocumentProperties::init() DocumentProperties::~DocumentProperties() { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(getDesktop())); + Inkscape::XML::Node *repr = sp_desktop_namedview(getDesktop())->getRepr(); repr->removeListenerByData (this); - Inkscape::XML::Node *root = SP_OBJECT_REPR(sp_desktop_document(getDesktop())->root); + Inkscape::XML::Node *root = sp_desktop_document(getDesktop())->root->getRepr(); root->removeListenerByData (this); } @@ -439,7 +439,9 @@ DocumentProperties::populate_linked_profiles_box() { _LinkedProfilesListStore->clear(); const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" ); - if (current) _emb_profiles_observer.set(SP_OBJECT(current->data)->parent); + if (current) { + _emb_profiles_observer.set(SP_OBJECT(current->data)->parent); + } while ( current ) { SPObject* obj = SP_OBJECT(current->data); Inkscape::ColorProfile* prof = reinterpret_cast<Inkscape::ColorProfile*>(obj); @@ -807,7 +809,7 @@ DocumentProperties::update() double const doc_w_px = sp_desktop_document(dt)->getWidth(); double const doc_h_px = sp_desktop_document(dt)->getHeight(); _page_sizer.setDim (doc_w_px, doc_h_px); - _page_sizer.updateFitMarginsUI(SP_OBJECT_REPR(nv)); + _page_sizer.updateFitMarginsUI(nv->getRepr()); //-----------------------------------------------------------guide page @@ -873,9 +875,9 @@ DocumentProperties::on_response (int id) void DocumentProperties::_handleDocumentReplaced(SPDesktop* desktop, SPDocument *document) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(desktop)); + Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr(); repr->addListener(&_repr_events, this); - Inkscape::XML::Node *root = SP_OBJECT_REPR(document->root); + Inkscape::XML::Node *root = document->root->getRepr(); root->addListener(&_repr_events, this); update(); } @@ -883,9 +885,9 @@ DocumentProperties::_handleDocumentReplaced(SPDesktop* desktop, SPDocument *docu void DocumentProperties::_handleActivateDesktop(Inkscape::Application *, SPDesktop *desktop) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(desktop)); + Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr(); repr->addListener(&_repr_events, this); - Inkscape::XML::Node *root = SP_OBJECT_REPR(sp_desktop_document(desktop)->root); + Inkscape::XML::Node *root = sp_desktop_document(desktop)->root->getRepr(); root->addListener(&_repr_events, this); update(); } @@ -893,9 +895,9 @@ DocumentProperties::_handleActivateDesktop(Inkscape::Application *, SPDesktop *d void DocumentProperties::_handleDeactivateDesktop(Inkscape::Application *, SPDesktop *desktop) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(desktop)); + Inkscape::XML::Node *repr = sp_desktop_namedview(desktop)->getRepr(); repr->removeListenerByData(this); - Inkscape::XML::Node *root = SP_OBJECT_REPR(sp_desktop_document(desktop)->root); + Inkscape::XML::Node *root = sp_desktop_document(desktop)->root->getRepr(); root->removeListenerByData(this); } @@ -934,7 +936,7 @@ void DocumentProperties::onNewGrid() { SPDesktop *dt = getDesktop(); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(sp_desktop_namedview(dt)); + Inkscape::XML::Node *repr = sp_desktop_namedview(dt)->getRepr(); SPDocument *doc = sp_desktop_document(dt); Glib::ustring typestring = _grids_combo_gridtype.get_active_text(); diff --git a/src/ui/dialog/document-properties.h b/src/ui/dialog/document-properties.h index dbefca235..b88f0db26 100644 --- a/src/ui/dialog/document-properties.h +++ b/src/ui/dialog/document-properties.h @@ -15,6 +15,7 @@ #define INKSCAPE_UI_DIALOG_DOCUMENT_PREFERENCES_H #include <list> +#include <stddef.h> #include <sigc++/sigc++.h>// #include <gtkmm/notebook.h> #include <glibmm/i18n.h> diff --git a/src/ui/dialog/filedialog.h b/src/ui/dialog/filedialog.h index 9f13308fb..a7441e9bb 100644 --- a/src/ui/dialog/filedialog.h +++ b/src/ui/dialog/filedialog.h @@ -46,7 +46,8 @@ namespace Dialog typedef enum { SVG_TYPES, IMPORT_TYPES, - EXPORT_TYPES + EXPORT_TYPES, + EXE_TYPES } FileDialogType; /** diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp index 855d5a223..8e0b9294b 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.cpp +++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp @@ -572,32 +572,36 @@ SVGPreview::~SVGPreview() void FileDialogBaseGtk::internalSetup() { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool enablePreview = prefs->getBool( preferenceBase + "/enable_preview", true); - - previewCheckbox.set_label( Glib::ustring(_("Enable preview")) ); - previewCheckbox.set_active( enablePreview ); + // Open executable file dialogs don't need the preview panel + if (_dialogType != EXE_TYPES) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool enablePreview = prefs->getBool( preferenceBase + "/enable_preview", true); - previewCheckbox.signal_toggled().connect( - sigc::mem_fun(*this, &FileDialogBaseGtk::_previewEnabledCB) ); + previewCheckbox.set_label( Glib::ustring(_("Enable preview")) ); + previewCheckbox.set_active( enablePreview ); - //Catch selection-changed events, so we can adjust the text widget - signal_update_preview().connect( - sigc::mem_fun(*this, &FileDialogBaseGtk::_updatePreviewCallback) ); + previewCheckbox.signal_toggled().connect( + sigc::mem_fun(*this, &FileDialogBaseGtk::_previewEnabledCB) ); - //###### Add a preview widget - set_preview_widget(svgPreview); - set_preview_widget_active( enablePreview ); - set_use_preview_label (false); + //Catch selection-changed events, so we can adjust the text widget + signal_update_preview().connect( + sigc::mem_fun(*this, &FileDialogBaseGtk::_updatePreviewCallback) ); + //###### Add a preview widget + set_preview_widget(svgPreview); + set_preview_widget_active( enablePreview ); + set_use_preview_label (false); + } } void FileDialogBaseGtk::cleanup( bool showConfirmed ) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if ( showConfirmed ) - prefs->setBool( preferenceBase + "/enable_preview", previewCheckbox.get_active() ); + if (_dialogType != EXE_TYPES) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if ( showConfirmed ) + prefs->setBool( preferenceBase + "/enable_preview", previewCheckbox.get_active() ); + } } @@ -648,9 +652,13 @@ FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow, { - /* One file at a time */ - /* And also Multiple Files */ - set_select_multiple(true); + if (_dialogType == EXE_TYPES) { + /* One file at a time */ + set_select_multiple(false); + } else { + /* And also Multiple Files */ + set_select_multiple(true); + } #ifdef WITH_GNOME_VFS if (gnome_vfs_initialized()) { @@ -668,19 +676,22 @@ FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow, /* Set the pwd and/or the filename */ - if (dir.size() > 0) - { + if (dir.size() > 0) { Glib::ustring udir(dir); Glib::ustring::size_type len = udir.length(); // leaving a trailing backslash on the directory name leads to the infamous // double-directory bug on win32 if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1); - set_current_folder(udir.c_str()); + if (_dialogType == EXE_TYPES) { + set_filename(udir.c_str()); + } else { + set_current_folder(udir.c_str()); } + } - - set_extra_widget( previewCheckbox ); - + if (_dialogType != EXE_TYPES) { + set_extra_widget( previewCheckbox ); + } //###### Add the file types menu createFilterMenu(); @@ -708,84 +719,91 @@ FileOpenDialogImplGtk::~FileOpenDialogImplGtk() void FileOpenDialogImplGtk::createFilterMenu() { - Gtk::FileFilter allInkscapeFilter; - allInkscapeFilter.set_name(_("All Inkscape Files")); - extensionMap[Glib::ustring(_("All Inkscape Files"))]=NULL; - add_filter(allInkscapeFilter); - - Gtk::FileFilter allFilter; - allFilter.set_name(_("All Files")); - extensionMap[Glib::ustring(_("All Files"))]=NULL; - allFilter.add_pattern("*"); - add_filter(allFilter); - - Gtk::FileFilter allImageFilter; - allImageFilter.set_name(_("All Images")); - extensionMap[Glib::ustring(_("All Images"))]=NULL; - add_filter(allImageFilter); - - Gtk::FileFilter allVectorFilter; - allVectorFilter.set_name(_("All Vectors")); - extensionMap[Glib::ustring(_("All Vectors"))]=NULL; - add_filter(allVectorFilter); - - Gtk::FileFilter allBitmapFilter; - allBitmapFilter.set_name(_("All Bitmaps")); - extensionMap[Glib::ustring(_("All Bitmaps"))]=NULL; - add_filter(allBitmapFilter); - - //patterns added dynamically below - Inkscape::Extension::DB::InputList extension_list; - Inkscape::Extension::db.get_input_list(extension_list); - - for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin(); - current_item != extension_list.end(); current_item++) - { - Inkscape::Extension::Input * imod = *current_item; - - // FIXME: would be nice to grey them out instead of not listing them - if (imod->deactivated()) continue; - - Glib::ustring upattern("*"); - Glib::ustring extension = imod->get_extension(); - fileDialogExtensionToPattern(upattern, extension); - - Gtk::FileFilter filter; - Glib::ustring uname(_(imod->get_filetypename())); - filter.set_name(uname); - filter.add_pattern(upattern); - add_filter(filter); - extensionMap[uname] = imod; - - //g_message("ext %s:%s '%s'\n", ioext->name, ioext->mimetype, upattern.c_str()); - allInkscapeFilter.add_pattern(upattern); - if ( strncmp("image", imod->get_mimetype(), 5)==0 ) - allImageFilter.add_pattern(upattern); - - // uncomment this to find out all mime types supported by Inkscape import/open - // g_print ("%s\n", imod->get_mimetype()); - - // I don't know of any other way to define "bitmap" formats other than by listing them - if ( - strncmp("image/png", imod->get_mimetype(), 9)==0 || - strncmp("image/jpeg", imod->get_mimetype(), 10)==0 || - strncmp("image/gif", imod->get_mimetype(), 9)==0 || - strncmp("image/x-icon", imod->get_mimetype(), 12)==0 || - strncmp("image/x-navi-animation", imod->get_mimetype(), 22)==0 || - strncmp("image/x-cmu-raster", imod->get_mimetype(), 18)==0 || - strncmp("image/x-xpixmap", imod->get_mimetype(), 15)==0 || - strncmp("image/bmp", imod->get_mimetype(), 9)==0 || - strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18)==0 || - strncmp("image/tiff", imod->get_mimetype(), 10)==0 || - strncmp("image/x-xbitmap", imod->get_mimetype(), 15)==0 || - strncmp("image/x-tga", imod->get_mimetype(), 11)==0 || - strncmp("image/x-pcx", imod->get_mimetype(), 11)==0 - ) - allBitmapFilter.add_pattern(upattern); - else - allVectorFilter.add_pattern(upattern); + if (_dialogType == EXE_TYPES) { + Gtk::FileFilter allFilter; + allFilter.set_name(_("All Files")); + extensionMap[Glib::ustring(_("All Files"))]=NULL; + allFilter.add_pattern("*"); + add_filter(allFilter); + } else { + Gtk::FileFilter allInkscapeFilter; + allInkscapeFilter.set_name(_("All Inkscape Files")); + extensionMap[Glib::ustring(_("All Inkscape Files"))]=NULL; + add_filter(allInkscapeFilter); + + Gtk::FileFilter allFilter; + allFilter.set_name(_("All Files")); + extensionMap[Glib::ustring(_("All Files"))]=NULL; + allFilter.add_pattern("*"); + add_filter(allFilter); + + Gtk::FileFilter allImageFilter; + allImageFilter.set_name(_("All Images")); + extensionMap[Glib::ustring(_("All Images"))]=NULL; + add_filter(allImageFilter); + + Gtk::FileFilter allVectorFilter; + allVectorFilter.set_name(_("All Vectors")); + extensionMap[Glib::ustring(_("All Vectors"))]=NULL; + add_filter(allVectorFilter); + + Gtk::FileFilter allBitmapFilter; + allBitmapFilter.set_name(_("All Bitmaps")); + extensionMap[Glib::ustring(_("All Bitmaps"))]=NULL; + add_filter(allBitmapFilter); + + //patterns added dynamically below + Inkscape::Extension::DB::InputList extension_list; + Inkscape::Extension::db.get_input_list(extension_list); + + for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin(); + current_item != extension_list.end(); current_item++) + { + Inkscape::Extension::Input * imod = *current_item; + + // FIXME: would be nice to grey them out instead of not listing them + if (imod->deactivated()) continue; + + Glib::ustring upattern("*"); + Glib::ustring extension = imod->get_extension(); + fileDialogExtensionToPattern(upattern, extension); + + Gtk::FileFilter filter; + Glib::ustring uname(_(imod->get_filetypename())); + filter.set_name(uname); + filter.add_pattern(upattern); + add_filter(filter); + extensionMap[uname] = imod; + + //g_message("ext %s:%s '%s'\n", ioext->name, ioext->mimetype, upattern.c_str()); + allInkscapeFilter.add_pattern(upattern); + if ( strncmp("image", imod->get_mimetype(), 5)==0 ) + allImageFilter.add_pattern(upattern); + + // uncomment this to find out all mime types supported by Inkscape import/open + // g_print ("%s\n", imod->get_mimetype()); + + // I don't know of any other way to define "bitmap" formats other than by listing them + if ( + strncmp("image/png", imod->get_mimetype(), 9)==0 || + strncmp("image/jpeg", imod->get_mimetype(), 10)==0 || + strncmp("image/gif", imod->get_mimetype(), 9)==0 || + strncmp("image/x-icon", imod->get_mimetype(), 12)==0 || + strncmp("image/x-navi-animation", imod->get_mimetype(), 22)==0 || + strncmp("image/x-cmu-raster", imod->get_mimetype(), 18)==0 || + strncmp("image/x-xpixmap", imod->get_mimetype(), 15)==0 || + strncmp("image/bmp", imod->get_mimetype(), 9)==0 || + strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18)==0 || + strncmp("image/tiff", imod->get_mimetype(), 10)==0 || + strncmp("image/x-xbitmap", imod->get_mimetype(), 15)==0 || + strncmp("image/x-tga", imod->get_mimetype(), 11)==0 || + strncmp("image/x-pcx", imod->get_mimetype(), 11)==0 + ) + allBitmapFilter.add_pattern(upattern); + else + allVectorFilter.add_pattern(upattern); + } } - return; } diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp index 9f33d8838..b3c71e8c8 100644 --- a/src/ui/dialog/filedialogimpl-win32.cpp +++ b/src/ui/dialog/filedialogimpl-win32.cpp @@ -122,11 +122,11 @@ FileDialogBaseWin32::FileDialogBaseWin32(Gtk::Window &parent, { _main_loop = NULL; - _filter_index = 1; - _filter_count = 0; + _filter_index = 1; + _filter_count = 0; _title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL); - g_assert(_title != NULL); + g_assert(_title != NULL); Glib::RefPtr<const Gdk::Window> parentWindow = parent.get_window(); g_assert(parentWindow->gobj() != NULL); @@ -183,7 +183,7 @@ FileOpenDialogImplWin32::FileOpenDialogImplWin32(Gtk::Window &parent, _preview_image_height = 0; _preview_emf_image = false; - _mutex = NULL; + _mutex = NULL; createFilterMenu(); } @@ -204,143 +204,180 @@ void FileOpenDialogImplWin32::createFilterMenu() { list<Filter> filter_list; - // Compose the filter string - Inkscape::Extension::DB::InputList extension_list; - Inkscape::Extension::db.get_input_list(extension_list); - - ustring all_inkscape_files_filter, all_image_files_filter, all_vectors_filter, all_bitmaps_filter; - Filter all_files, all_inkscape_files, all_image_files, all_vectors, all_bitmaps; - - const gchar *all_files_filter_name = _("All Files"); - const gchar *all_inkscape_files_filter_name = _("All Inkscape Files"); - const gchar *all_image_files_filter_name = _("All Images"); - const gchar *all_vectors_filter_name = _("All Vectors"); - const gchar *all_bitmaps_filter_name = _("All Bitmaps"); - - // Calculate the amount of memory required - int filter_count = 5; // 5 - one for each filter type + int extension_index = 0; int filter_length = 1; + + if (dialogType != EXE_TYPES) { + // Compose the filter string + Inkscape::Extension::DB::InputList extension_list; + Inkscape::Extension::db.get_input_list(extension_list); + + ustring all_inkscape_files_filter, all_image_files_filter, all_vectors_filter, all_bitmaps_filter; + Filter all_files, all_inkscape_files, all_image_files, all_vectors, all_bitmaps; + + const gchar *all_files_filter_name = _("All Files"); + const gchar *all_inkscape_files_filter_name = _("All Inkscape Files"); + const gchar *all_image_files_filter_name = _("All Images"); + const gchar *all_vectors_filter_name = _("All Vectors"); + const gchar *all_bitmaps_filter_name = _("All Bitmaps"); + + // Calculate the amount of memory required + int filter_count = 5; // 5 - one for each filter type + + for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin(); + current_item != extension_list.end(); current_item++) + { + Filter filter; - for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin(); - current_item != extension_list.end(); current_item++) - { - Filter filter; + Inkscape::Extension::Input *imod = *current_item; + if (imod->deactivated()) continue; - Inkscape::Extension::Input *imod = *current_item; - if (imod->deactivated()) continue; + // Type + filter.name = g_utf8_to_utf16(_(imod->get_filetypename()), + -1, NULL, &filter.name_length, NULL); - // Type - filter.name = g_utf8_to_utf16(_(imod->get_filetypename()), - -1, NULL, &filter.name_length, NULL); + // Extension + const gchar *file_extension_name = imod->get_extension(); + filter.filter = g_utf8_to_utf16(file_extension_name, + -1, NULL, &filter.filter_length, NULL); - // Extension - const gchar *file_extension_name = imod->get_extension(); - filter.filter = g_utf8_to_utf16(file_extension_name, - -1, NULL, &filter.filter_length, NULL); + filter.mod = imod; + filter_list.push_back(filter); - filter.mod = imod; - filter_list.push_back(filter); + filter_length += filter.name_length + + filter.filter_length + 3; // Add 3 for two \0s and a * - filter_length += filter.name_length + - filter.filter_length + 3; // Add 3 for two \0s and a * + // Add to the "All Inkscape Files" Entry + if(all_inkscape_files_filter.length() > 0) + all_inkscape_files_filter += ";*"; + all_inkscape_files_filter += file_extension_name; + if( strncmp("image", imod->get_mimetype(), 5) == 0) + { + // Add to the "All Image Files" Entry + if(all_image_files_filter.length() > 0) + all_image_files_filter += ";*"; + all_image_files_filter += file_extension_name; + } - // Add to the "All Inkscape Files" Entry - if(all_inkscape_files_filter.length() > 0) - all_inkscape_files_filter += ";*"; - all_inkscape_files_filter += file_extension_name; - if( strncmp("image", imod->get_mimetype(), 5) == 0) - { - // Add to the "All Image Files" Entry - if(all_image_files_filter.length() > 0) - all_image_files_filter += ";*"; - all_image_files_filter += file_extension_name; - } + // I don't know of any other way to define "bitmap" formats other than by listing them + // if you change it here, do the same change in filedialogimpl-gtkmm + if ( + strncmp("image/png", imod->get_mimetype(), 9)==0 || + strncmp("image/jpeg", imod->get_mimetype(), 10)==0 || + strncmp("image/gif", imod->get_mimetype(), 9)==0 || + strncmp("image/x-icon", imod->get_mimetype(), 12)==0 || + strncmp("image/x-navi-animation", imod->get_mimetype(), 22)==0 || + strncmp("image/x-cmu-raster", imod->get_mimetype(), 18)==0 || + strncmp("image/x-xpixmap", imod->get_mimetype(), 15)==0 || + strncmp("image/bmp", imod->get_mimetype(), 9)==0 || + strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18)==0 || + strncmp("image/tiff", imod->get_mimetype(), 10)==0 || + strncmp("image/x-xbitmap", imod->get_mimetype(), 15)==0 || + strncmp("image/x-tga", imod->get_mimetype(), 11)==0 || + strncmp("image/x-pcx", imod->get_mimetype(), 11)==0 + ) { + if(all_bitmaps_filter.length() > 0) + all_bitmaps_filter += ";*"; + all_bitmaps_filter += file_extension_name; + } else { + if(all_vectors_filter.length() > 0) + all_vectors_filter += ";*"; + all_vectors_filter += file_extension_name; + } - // I don't know of any other way to define "bitmap" formats other than by listing them - // if you change it here, do the same change in filedialogimpl-gtkmm - if ( - strncmp("image/png", imod->get_mimetype(), 9)==0 || - strncmp("image/jpeg", imod->get_mimetype(), 10)==0 || - strncmp("image/gif", imod->get_mimetype(), 9)==0 || - strncmp("image/x-icon", imod->get_mimetype(), 12)==0 || - strncmp("image/x-navi-animation", imod->get_mimetype(), 22)==0 || - strncmp("image/x-cmu-raster", imod->get_mimetype(), 18)==0 || - strncmp("image/x-xpixmap", imod->get_mimetype(), 15)==0 || - strncmp("image/bmp", imod->get_mimetype(), 9)==0 || - strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18)==0 || - strncmp("image/tiff", imod->get_mimetype(), 10)==0 || - strncmp("image/x-xbitmap", imod->get_mimetype(), 15)==0 || - strncmp("image/x-tga", imod->get_mimetype(), 11)==0 || - strncmp("image/x-pcx", imod->get_mimetype(), 11)==0 - ) { - if(all_bitmaps_filter.length() > 0) - all_bitmaps_filter += ";*"; - all_bitmaps_filter += file_extension_name; - } else { - if(all_vectors_filter.length() > 0) - all_vectors_filter += ";*"; - all_vectors_filter += file_extension_name; + filter_count++; } - filter_count++; + _extension_map = new Inkscape::Extension::Extension*[filter_count]; + + // Filter bitmap files + all_bitmaps.name = g_utf8_to_utf16(all_bitmaps_filter_name, + -1, NULL, &all_bitmaps.name_length, NULL); + all_bitmaps.filter = g_utf8_to_utf16(all_bitmaps_filter.data(), + -1, NULL, &all_bitmaps.filter_length, NULL); + all_bitmaps.mod = NULL; + filter_list.push_front(all_bitmaps); + + // Filter vector files + all_vectors.name = g_utf8_to_utf16(all_vectors_filter_name, + -1, NULL, &all_vectors.name_length, NULL); + all_vectors.filter = g_utf8_to_utf16(all_vectors_filter.data(), + -1, NULL, &all_vectors.filter_length, NULL); + all_vectors.mod = NULL; + filter_list.push_front(all_vectors); + + // Filter Image Files + all_image_files.name = g_utf8_to_utf16(all_image_files_filter_name, + -1, NULL, &all_image_files.name_length, NULL); + all_image_files.filter = g_utf8_to_utf16(all_image_files_filter.data(), + -1, NULL, &all_image_files.filter_length, NULL); + all_image_files.mod = NULL; + filter_list.push_front(all_image_files); + + // Filter Inkscape Files + all_inkscape_files.name = g_utf8_to_utf16(all_inkscape_files_filter_name, + -1, NULL, &all_inkscape_files.name_length, NULL); + all_inkscape_files.filter = g_utf8_to_utf16(all_inkscape_files_filter.data(), + -1, NULL, &all_inkscape_files.filter_length, NULL); + all_inkscape_files.mod = NULL; + filter_list.push_front(all_inkscape_files); + + // Filter All Files + all_files.name = g_utf8_to_utf16(all_files_filter_name, + -1, NULL, &all_files.name_length, NULL); + all_files.filter = NULL; + all_files.filter_length = 0; + all_files.mod = NULL; + filter_list.push_front(all_files); + + filter_length += all_files.name_length + 3 + + all_inkscape_files.filter_length + + all_inkscape_files.name_length + 3 + + all_image_files.filter_length + + all_image_files.name_length + 3 + + all_vectors.filter_length + + all_vectors.name_length + 3 + + all_bitmaps.filter_length + + all_bitmaps.name_length + 3 + + 1; + // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0 + } else { + // Executables only + ustring all_exe_files_filter = "*.exe;*.bat;*.com"; + Filter all_exe_files, all_files; + + const gchar *all_files_filter_name = _("All Files"); + const gchar *all_exe_files_filter_name = _("All Executable Files"); + + // Calculate the amount of memory required + int filter_count = 2; // 2 - All Files and All Executable Files + + _extension_map = new Inkscape::Extension::Extension*[filter_count]; + + // Filter Executable Files + all_exe_files.name = g_utf8_to_utf16(all_exe_files_filter_name, + -1, NULL, &all_exe_files.name_length, NULL); + all_exe_files.filter = g_utf8_to_utf16(all_exe_files_filter.data(), + -1, NULL, &all_exe_files.filter_length, NULL); + all_exe_files.mod = NULL; + filter_list.push_front(all_exe_files); + + // Filter All Files + all_files.name = g_utf8_to_utf16(all_files_filter_name, + -1, NULL, &all_files.name_length, NULL); + all_files.filter = NULL; + all_files.filter_length = 0; + all_files.mod = NULL; + filter_list.push_front(all_files); + + filter_length += all_files.name_length + 3 + + all_exe_files.filter_length + + all_exe_files.name_length + 3 + + 1; + // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0 } - - int extension_index = 0; - _extension_map = new Inkscape::Extension::Extension*[filter_count]; - - // Filter bitmap files - all_bitmaps.name = g_utf8_to_utf16(all_bitmaps_filter_name, - -1, NULL, &all_bitmaps.name_length, NULL); - all_bitmaps.filter = g_utf8_to_utf16(all_bitmaps_filter.data(), - -1, NULL, &all_bitmaps.filter_length, NULL); - all_bitmaps.mod = NULL; - filter_list.push_front(all_bitmaps); - - // Filter vector files - all_vectors.name = g_utf8_to_utf16(all_vectors_filter_name, - -1, NULL, &all_vectors.name_length, NULL); - all_vectors.filter = g_utf8_to_utf16(all_vectors_filter.data(), - -1, NULL, &all_vectors.filter_length, NULL); - all_vectors.mod = NULL; - filter_list.push_front(all_vectors); - - // Filter Image Files - all_image_files.name = g_utf8_to_utf16(all_image_files_filter_name, - -1, NULL, &all_image_files.name_length, NULL); - all_image_files.filter = g_utf8_to_utf16(all_image_files_filter.data(), - -1, NULL, &all_image_files.filter_length, NULL); - all_image_files.mod = NULL; - filter_list.push_front(all_image_files); - - // Filter Inkscape Files - all_inkscape_files.name = g_utf8_to_utf16(all_inkscape_files_filter_name, - -1, NULL, &all_inkscape_files.name_length, NULL); - all_inkscape_files.filter = g_utf8_to_utf16(all_inkscape_files_filter.data(), - -1, NULL, &all_inkscape_files.filter_length, NULL); - all_inkscape_files.mod = NULL; - filter_list.push_front(all_inkscape_files); - - // Filter All Files - all_files.name = g_utf8_to_utf16(all_files_filter_name, - -1, NULL, &all_files.name_length, NULL); - all_files.filter = NULL; - all_files.filter_length = 0; - all_files.mod = NULL; - filter_list.push_front(all_files); - - filter_length += all_files.name_length + 3 + - all_inkscape_files.filter_length + - all_inkscape_files.name_length + 3 + - all_image_files.filter_length + - all_image_files.name_length + 3 + - all_vectors.filter_length + - all_vectors.name_length + 3 + - all_bitmaps.filter_length + - all_bitmaps.name_length + 3 + - 1; - // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0 - - _filter = new wchar_t[filter_length]; + + _filter = new wchar_t[filter_length]; wchar_t *filterptr = _filter; for(list<Filter>::iterator filter_iterator = filter_list.begin(); @@ -369,7 +406,7 @@ void FileOpenDialogImplWin32::createFilterMenu() } *(filterptr++) = L'\0'; - _filter_count = extension_index; + _filter_count = extension_index; _filter_index = 2; // Select the 2nd filter in the list - 2 is NOT the 3rd } @@ -378,7 +415,7 @@ void FileOpenDialogImplWin32::GetOpenFileName_thread() OPENFILENAMEEXW ofn; g_assert(this != NULL); - g_assert(_mutex != NULL); + g_assert(_mutex != NULL); WCHAR* current_directory_string = (WCHAR*)g_utf8_to_utf16( _current_directory.data(), _current_directory.length(), @@ -409,7 +446,7 @@ void FileOpenDialogImplWin32::GetOpenFileName_thread() _result = GetOpenFileNameW(&ofn) != 0; - g_assert(ofn.nFilterIndex >= 1 && ofn.nFilterIndex <= _filter_count); + g_assert(ofn.nFilterIndex >= 1 && ofn.nFilterIndex <= _filter_count); _filter_index = ofn.nFilterIndex; _extension = _extension_map[ofn.nFilterIndex - 1]; @@ -457,56 +494,70 @@ UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc( HWND hParentWnd = GetParent(hdlg); HINSTANCE hInstance = GetModuleHandle(NULL); - // Make the window a bit wider - RECT rcRect; - GetWindowRect(hParentWnd, &rcRect); - MoveWindow(hParentWnd, rcRect.left, rcRect.top, - rcRect.right - rcRect.left + PREVIEW_WIDENING, - rcRect.bottom - rcRect.top, - FALSE); - // Set the pointer to the object OPENFILENAMEW *ofn = (OPENFILENAMEW*)lParam; SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData); SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData); pImpl = (FileOpenDialogImplWin32*)ofn->lCustData; + + // Make the window a bit wider + RECT rcRect; + GetWindowRect(hParentWnd, &rcRect); + + // Don't show the preview when opening executable files + if ( pImpl->dialogType == EXE_TYPES) { + MoveWindow(hParentWnd, rcRect.left, rcRect.top, + rcRect.right - rcRect.left, + rcRect.bottom - rcRect.top, + FALSE); + } else { + MoveWindow(hParentWnd, rcRect.left, rcRect.top, + rcRect.right - rcRect.left + PREVIEW_WIDENING, + rcRect.bottom - rcRect.top, + FALSE); + } // Subclass the parent pImpl->_base_window_proc = (WNDPROC)GetWindowLongPtr(hParentWnd, GWLP_WNDPROC); SetWindowLongPtr(hParentWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(file_dialog_subclass_proc)); - // Add a button to the toolbar - pImpl->_toolbar_wnd = FindWindowEx(hParentWnd, NULL, "ToolbarWindow32", NULL); - - pImpl->_show_preview_button_bitmap = LoadBitmap( - hInstance, MAKEINTRESOURCE(IDC_SHOW_PREVIEW)); - TBADDBITMAP tbAddBitmap = {NULL, reinterpret_cast<UINT_PTR>(pImpl->_show_preview_button_bitmap)}; - const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd, - TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap); - - TBBUTTON tbButton; - memset(&tbButton, 0, sizeof(TBBUTTON)); - tbButton.iBitmap = iBitmapIndex; - tbButton.idCommand = IDC_SHOW_PREVIEW; - tbButton.fsState = (pImpl->_show_preview ? TBSTATE_CHECKED : 0) - | TBSTATE_ENABLED; - tbButton.fsStyle = TBSTYLE_CHECK; - tbButton.iString = (INT_PTR)_("Show Preview"); - SendMessage(pImpl->_toolbar_wnd, TB_ADDBUTTONS, 1, (LPARAM)&tbButton); - - // Create preview pane - register_preview_wnd_class(); + if ( pImpl->dialogType != EXE_TYPES) { + // Add a button to the toolbar + pImpl->_toolbar_wnd = FindWindowEx(hParentWnd, NULL, "ToolbarWindow32", NULL); + + pImpl->_show_preview_button_bitmap = LoadBitmap( + hInstance, MAKEINTRESOURCE(IDC_SHOW_PREVIEW)); + TBADDBITMAP tbAddBitmap = {NULL, reinterpret_cast<UINT_PTR>(pImpl->_show_preview_button_bitmap)}; + const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd, + TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap); + + + TBBUTTON tbButton; + memset(&tbButton, 0, sizeof(TBBUTTON)); + tbButton.iBitmap = iBitmapIndex; + tbButton.idCommand = IDC_SHOW_PREVIEW; + tbButton.fsState = (pImpl->_show_preview ? TBSTATE_CHECKED : 0) + | TBSTATE_ENABLED; + tbButton.fsStyle = TBSTYLE_CHECK; + tbButton.iString = (INT_PTR)_("Show Preview"); + SendMessage(pImpl->_toolbar_wnd, TB_ADDBUTTONS, 1, (LPARAM)&tbButton); + + // Create preview pane + register_preview_wnd_class(); + } pImpl->_mutex->lock(); - pImpl->_file_dialog_wnd = hParentWnd; + pImpl->_file_dialog_wnd = hParentWnd; + if ( pImpl->dialogType != EXE_TYPES) { pImpl->_preview_wnd = CreateWindowA(PreviewWindowClassName, "", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hParentWnd, NULL, hInstance, NULL); SetWindowLongPtr(pImpl->_preview_wnd, GWLP_USERDATA, ofn->lCustData); - + } + pImpl->_mutex->unlock(); pImpl->layout_dialog(); @@ -773,7 +824,7 @@ void FileOpenDialogImplWin32::layout_dialog() rcClient.right - iPadding, rcFileList.r.bottom}; rcFileList.r.right = rcBody.right; - if(_show_preview) + if(_show_preview && dialogType != EXE_TYPES) { rcPreview.top = rcBody.top; rcPreview.left = rcClient.right - (rcBody.bottom - rcBody.top); @@ -951,7 +1002,7 @@ bool FileOpenDialogImplWin32::set_svg_preview() arena, key, SP_ITEM_SHOW_DISPLAY); NRGC gc(NULL); - gc.transform = Geom::Matrix(Geom::Scale(scaleFactor, scaleFactor)); + gc.transform = Geom::Affine(Geom::Scale(scaleFactor, scaleFactor)); nr_arena_item_invoke_update (root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE); @@ -1529,6 +1580,17 @@ FileSaveDialogImplWin32::FileSaveDialogImplWin32(Gtk::Window &parent, { FileSaveDialog::myDocTitle = docTitle; createFilterMenu(); + + /* The code below sets the default file name */ + myFilename = ""; + if (dir.size() > 0) { + Glib::ustring udir(dir); + Glib::ustring::size_type len = udir.length(); + // leaving a trailing backslash on the directory name leads to the infamous + // double-directory bug on win32 + if (len != 0 && udir[len - 1] == '\\') udir.erase(len - 1); + myFilename = udir.substr(0, udir.find_last_of( '.' ) ); // this removes the extension, or actually, removes everything past the last dot (hopefully this is what most people want) + } } FileSaveDialogImplWin32::~FileSaveDialogImplWin32() @@ -1606,7 +1668,7 @@ void FileSaveDialogImplWin32::createFilterMenu() } *(filterptr++) = 0; - _filter_count = extension_index; + _filter_count = extension_index; _filter_index = 1; // A value of 1 selects the 1st filter - NOT the 2nd } @@ -1646,7 +1708,7 @@ void FileSaveDialogImplWin32::GetSaveFileName_thread() _result = GetSaveFileNameW(&ofn) != 0; - g_assert(ofn.nFilterIndex >= 1 && ofn.nFilterIndex <= _filter_count); + g_assert(ofn.nFilterIndex >= 1 && ofn.nFilterIndex <= _filter_count); _filter_index = ofn.nFilterIndex; _extension = _extension_map[ofn.nFilterIndex - 1]; diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h index 00d9cf37f..a6f7d6239 100644 --- a/src/ui/dialog/filedialogimpl-win32.h +++ b/src/ui/dialog/filedialogimpl-win32.h @@ -150,9 +150,10 @@ public: private: - /// Create a filter menu for this type of dialog + /// Create filter menu for this type of dialog void createFilterMenu(); + /// The handle of the preview pane window HWND _preview_wnd; diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp index 0c234003e..19bcadc00 100644 --- a/src/ui/dialog/fill-and-stroke.cpp +++ b/src/ui/dialog/fill-and-stroke.cpp @@ -54,7 +54,7 @@ FillAndStroke::FillAndStroke() contents->pack_start(_notebook, true, true); - _notebook.append_page(_page_fill, _createPageTabLabel(_("Fill"), INKSCAPE_ICON_OBJECT_FILL)); + _notebook.append_page(_page_fill, _createPageTabLabel(_("_Fill"), INKSCAPE_ICON_OBJECT_FILL)); _notebook.append_page(_page_stroke_paint, _createPageTabLabel(_("Stroke _paint"), INKSCAPE_ICON_OBJECT_STROKE)); _notebook.append_page(_page_stroke_style, _createPageTabLabel(_("Stroke st_yle"), INKSCAPE_ICON_OBJECT_STROKE_STYLE)); diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 63f387911..f7911f79a 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -1181,29 +1181,32 @@ void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel) { std::set<SPObject*> used; - for(GSList const *i = sel->itemList(); i != NULL; i = i->next) { + for (GSList const *i = sel->itemList(); i != NULL; i = i->next) { SPObject *obj = SP_OBJECT (i->data); - SPStyle *style = SP_OBJECT_STYLE (obj); - if(!style || !SP_IS_ITEM(obj)) continue; + SPStyle *style = obj->style; + if (!style || !SP_IS_ITEM(obj)) { + continue; + } - if(style->filter.set && style->getFilter()) + if (style->filter.set && style->getFilter()) { used.insert(style->getFilter()); - else + } else { used.insert(0); + } } const int size = used.size(); - for(Gtk::TreeIter iter = _model->children().begin(); - iter != _model->children().end(); ++iter) { - if(used.find((*iter)[_columns.filter]) != used.end()) { + for (Gtk::TreeIter iter = _model->children().begin(); iter != _model->children().end(); ++iter) { + if (used.find((*iter)[_columns.filter]) != used.end()) { // If only one filter is in use by the selection, select it - if(size == 1) + if (size == 1) { _list.get_selection()->select(iter); + } (*iter)[_columns.sel] = size; - } - else + } else { (*iter)[_columns.sel] = 0; + } } } @@ -1244,15 +1247,16 @@ void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustri for (GSList const *i = items; i != NULL; i = i->next) { SPItem * item = SP_ITEM(i->data); - SPStyle *style = SP_OBJECT_STYLE(item); + SPStyle *style = item->style; g_assert(style != NULL); - if(filter) - sp_style_set_property_url(SP_OBJECT(item), "filter", SP_OBJECT(filter), false); - else + if (filter) { + sp_style_set_property_url(item, "filter", filter, false); + } else { ::remove_filter(item, false); + } - SP_OBJECT(item)->requestDisplayUpdate((SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG )); + item->requestDisplayUpdate((SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG )); } update_selection(sel); @@ -1355,8 +1359,9 @@ void FilterEffectsDialog::FilterModifier::duplicate_filter() { SPFilter* filter = get_selected_filter(); - if(filter) { - Inkscape::XML::Node* repr = SP_OBJECT_REPR(filter), *parent = repr->parent(); + if (filter) { + Inkscape::XML::Node *repr = filter->getRepr(); + Inkscape::XML::Node *parent = repr->parent(); repr = repr->duplicate(repr->document()); parent->appendChild(repr); @@ -1902,7 +1907,7 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton* for(Gtk::TreeIter iter = _model->children().begin(); iter != get_selection()->get_selected(); ++iter) { if(iter == target_iter) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(target); + Inkscape::XML::Node *repr = target->getRepr(); // Make sure the target has a result const gchar *gres = repr->attribute("result"); if(!gres) { @@ -1979,22 +1984,23 @@ bool FilterEffectsDialog::PrimitiveList::on_button_release_event(GdkEventButton* // Checks all of prim's inputs, removes any that use result void check_single_connection(SPFilterPrimitive* prim, const int result) { - if(prim && result >= 0) { - - if(prim->image_in == result) - SP_OBJECT_REPR(prim)->setAttribute("in", 0); - - if(SP_IS_FEBLEND(prim)) { - if(SP_FEBLEND(prim)->in2 == result) - SP_OBJECT_REPR(prim)->setAttribute("in2", 0); + if (prim && (result >= 0)) { + if (prim->image_in == result) { + prim->getRepr()->setAttribute("in", 0); } - else if(SP_IS_FECOMPOSITE(prim)) { - if(SP_FECOMPOSITE(prim)->in2 == result) - SP_OBJECT_REPR(prim)->setAttribute("in2", 0); - } - else if(SP_IS_FEDISPLACEMENTMAP(prim)) { - if(SP_FEDISPLACEMENTMAP(prim)->in2 == result) - SP_OBJECT_REPR(prim)->setAttribute("in2", 0); + + if (SP_IS_FEBLEND(prim)) { + if (SP_FEBLEND(prim)->in2 == result) { + prim->getRepr()->setAttribute("in2", 0); + } + } else if (SP_IS_FECOMPOSITE(prim)) { + if (SP_FECOMPOSITE(prim)->in2 == result) { + prim->getRepr()->setAttribute("in2", 0); + } + } else if (SP_IS_FEDISPLACEMENTMAP(prim)) { + if (SP_FEDISPLACEMENTMAP(prim)->in2 == result) { + prim->getRepr()->setAttribute("in2", 0); + } } } } @@ -2025,19 +2031,19 @@ void FilterEffectsDialog::PrimitiveList::on_drag_end(const Glib::RefPtr<Gdk::Dra SPFilter* filter = _dialog._filter_modifier.get_selected_filter(); int ndx = 0; - for(Gtk::TreeModel::iterator iter = _model->children().begin(); + for (Gtk::TreeModel::iterator iter = _model->children().begin(); iter != _model->children().end(); ++iter, ++ndx) { SPFilterPrimitive* prim = (*iter)[_columns.primitive]; - if(prim && prim == _drag_prim) { - SP_OBJECT_REPR(prim)->setPosition(ndx); + if (prim && prim == _drag_prim) { + prim->getRepr()->setPosition(ndx); break; } } - for(Gtk::TreeModel::iterator iter = _model->children().begin(); + for (Gtk::TreeModel::iterator iter = _model->children().begin(); iter != _model->children().end(); ++iter, ++ndx) { SPFilterPrimitive* prim = (*iter)[_columns.primitive]; - if(prim && prim == _drag_prim) { + if (prim && prim == _drag_prim) { sanitize_connections(iter); get_selection()->select(iter); break; @@ -2369,10 +2375,10 @@ void FilterEffectsDialog::duplicate_primitive() SPFilter* filter = _filter_modifier.get_selected_filter(); SPFilterPrimitive* origprim = _primitive_list.get_selected(); - if(filter && origprim) { + if (filter && origprim) { Inkscape::XML::Node *repr; - repr = SP_OBJECT_REPR(origprim)->duplicate(SP_OBJECT_REPR(origprim)->document()); - SP_OBJECT_REPR(filter)->appendChild(repr); + repr = origprim->getRepr()->duplicate(origprim->getRepr()->document()); + filter->getRepr()->appendChild(repr); DocumentUndo::done(filter->document, SP_VERB_DIALOG_FILTER_EFFECTS, _("Duplicate filter primitive")); @@ -2382,7 +2388,7 @@ void FilterEffectsDialog::duplicate_primitive() void FilterEffectsDialog::convolve_order_changed() { - _convolve_matrix->set_from_attribute(SP_OBJECT(_primitive_list.get_selected())); + _convolve_matrix->set_from_attribute(_primitive_list.get_selected()); _convolve_target->get_spinbuttons()[0]->get_adjustment()->set_upper(_convolve_order->get_spinbutton1().get_value() - 1); _convolve_target->get_spinbuttons()[1]->get_adjustment()->set_upper(_convolve_order->get_spinbutton2().get_value() - 1); } @@ -2398,8 +2404,8 @@ void FilterEffectsDialog::set_filternode_attr(const AttrWidget* input) _attr_lock = true; SPFilter *filter = _filter_modifier.get_selected_filter(); const gchar* name = (const gchar*)sp_attribute_name(input->get_attribute()); - if (filter && name && SP_OBJECT_REPR(filter)){ - SP_OBJECT_REPR(filter)->setAttribute(name, input->get_as_attribute().c_str()); + if (filter && name && filter->getRepr()){ + filter->getRepr()->setAttribute(name, input->get_as_attribute().c_str()); filter->requestModified(SP_OBJECT_MODIFIED_FLAG); } _attr_lock = false; @@ -2421,7 +2427,7 @@ void FilterEffectsDialog::set_attr(SPObject* o, const SPAttributeEnum attr, cons if(filter && name && o) { update_settings_sensitivity(); - SP_OBJECT_REPR(o)->setAttribute(name, val); + o->getRepr()->setAttribute(name, val); filter->requestModified(SP_OBJECT_MODIFIED_FLAG); Glib::ustring undokey = "filtereffects:"; diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index b6d6a0319..bdae14c62 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -142,15 +142,18 @@ Find::~Find() bool Find::item_id_match (SPItem *item, const gchar *id, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) + if (item->getRepr() == NULL) { return false; + } - if (SP_IS_STRING(item)) // SPStrings have "on demand" ids which are useless for searching + if (SP_IS_STRING(item)) { // SPStrings have "on demand" ids which are useless for searching return false; + } - const gchar *item_id = (SP_OBJECT_REPR (item))->attribute("id"); - if (item_id == NULL) + const gchar *item_id = item->getRepr()->attribute("id"); + if (item_id == NULL) { return false; + } if (exact) { return ((bool) !strcmp(item_id, id)); @@ -163,8 +166,9 @@ Find::item_id_match (SPItem *item, const gchar *id, bool exact) bool Find::item_text_match (SPItem *item, const gchar *text, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) + if (item->getRepr() == NULL) { return false; + } if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { const gchar *item_text = sp_te_get_string_multiline (item); @@ -186,12 +190,14 @@ Find::item_text_match (SPItem *item, const gchar *text, bool exact) bool Find::item_style_match (SPItem *item, const gchar *text, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) + if (item->getRepr() == NULL) { return false; + } - const gchar *item_text = (SP_OBJECT_REPR (item))->attribute("style"); - if (item_text == NULL) + const gchar *item_text = item->getRepr()->attribute("style"); + if (item_text == NULL) { return false; + } if (exact) { return ((bool) !strcmp(item_text, text)); @@ -200,18 +206,18 @@ Find::item_style_match (SPItem *item, const gchar *text, bool exact) } } -bool -Find::item_attr_match (SPItem *item, const gchar *name, bool exact) +bool Find::item_attr_match(SPItem *item, const gchar *name, bool exact) { - if (SP_OBJECT_REPR (item) == NULL) - return false; - - if (exact) { - const gchar *attr_value = (SP_OBJECT_REPR (item))->attribute(name); - return ((bool) (attr_value != NULL)); - } else { - return SP_OBJECT_REPR (item)->matchAttributeName(name); + bool result = false; + if (item->getRepr()) { + if (exact) { + const gchar *attr_value = item->getRepr()->attribute(name); + result = (attr_value != NULL); + } else { + result = item->getRepr()->matchAttributeName(name); + } } + return result; } @@ -342,17 +348,20 @@ Find::all_items (SPObject *r, GSList *l, bool hidden, bool locked) { SPDesktop *desktop = getDesktop(); - if (SP_IS_DEFS(r)) + if (SP_IS_DEFS(r)) { return l; // we're not interested in items in defs + } - if (!strcmp (SP_OBJECT_REPR (r)->name(), "svg:metadata")) + if (!strcmp(r->getRepr()->name(), "svg:metadata")) { return l; // we're not interested in metadata + } for (SPObject *child = r->firstChild(); child; child = child->getNext()) { - if (SP_IS_ITEM (child) && !SP_OBJECT_IS_CLONED (child) && !desktop->isLayer(SP_ITEM(child))) { - if ((hidden || !desktop->itemIsHidden(SP_ITEM(child))) && (locked || !SP_ITEM(child)->isLocked())) { - l = g_slist_prepend (l, child); - } + if (SP_IS_ITEM(child) && !child->cloned && !desktop->isLayer(SP_ITEM(child))) { + SPItem *item = reinterpret_cast<SPItem *>(child); + if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) { + l = g_slist_prepend (l, child); + } } l = all_items (child, l, hidden, locked); } @@ -365,9 +374,10 @@ Find::all_selection_items (Inkscape::Selection *s, GSList *l, SPObject *ancestor SPDesktop *desktop = getDesktop(); for (GSList *i = (GSList *) s->itemList(); i != NULL; i = i->next) { - if (SP_IS_ITEM (i->data) && !SP_OBJECT_IS_CLONED (i->data) && !desktop->isLayer(SP_ITEM(i->data))) { - if (!ancestor || ancestor->isAncestorOf(SP_OBJECT (i->data))) { - if ((hidden || !desktop->itemIsHidden(SP_ITEM(i->data))) && (locked || !SP_ITEM(i->data)->isLocked())) { + if (SP_IS_ITEM (i->data) && !reinterpret_cast<SPItem *>(i->data)->cloned && !desktop->isLayer(SP_ITEM(i->data))) { + SPItem *item = reinterpret_cast<SPItem *>(i->data); + if (!ancestor || ancestor->isAncestorOf(item)) { + if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) { l = g_slist_prepend (l, i->data); } } @@ -524,3 +534,14 @@ Find::squeeze_window() } // namespace UI } // namespace Inkscape + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/guides.cpp b/src/ui/dialog/guides.cpp index 1ab0d51bc..bd9777048 100644 --- a/src/ui/dialog/guides.cpp +++ b/src/ui/dialog/guides.cpp @@ -109,7 +109,7 @@ void GuidelinePropertiesDialog::_onApply() sp_guide_moveto(*_guide, newpos, true); - DocumentUndo::done(SP_OBJECT_DOCUMENT(_guide), SP_VERB_NONE, + DocumentUndo::done(_guide->document, SP_VERB_NONE, _("Set guide properties")); } @@ -120,7 +120,7 @@ void GuidelinePropertiesDialog::_onOK() void GuidelinePropertiesDialog::_onDelete() { - SPDocument *doc = SP_OBJECT_DOCUMENT(_guide); + SPDocument *doc = _guide->document; sp_guide_remove(_guide); DocumentUndo::done(doc, SP_VERB_NONE, _("Delete guide")); @@ -235,7 +235,7 @@ void GuidelinePropertiesDialog::_setup() { } { - Inkscape::XML::Node *repr = SP_OBJECT_REPR (_guide); + Inkscape::XML::Node *repr = _guide->getRepr(); const gchar *guide_id = repr->attribute("id"); gchar *label = g_strdup_printf(_("Guideline ID: %s"), guide_id); _label_name.set_label(label); diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index 4ba63b448..4d98793bb 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -356,7 +356,7 @@ void IconPreviewPanel::refreshPreview() GSList const *items = sel->itemList(); while ( items && !target ) { SPItem* item = SP_ITEM( items->data ); - SPObject * obj = SP_OBJECT(item); + SPObject * obj = item; gchar const *id = obj->getId(); if ( id ) { targetId = id; @@ -428,7 +428,7 @@ void IconPreviewPanel::modeToggled() void IconPreviewPanel::renderPreview( SPObject* obj ) { - SPDocument * doc = SP_OBJECT_DOCUMENT(obj); + SPDocument * doc = obj->document; gchar const * id = obj->getId(); if ( !renderTimer ) { renderTimer = new Glib::Timer(); diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 13491312a..8681ed98f 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -393,7 +393,7 @@ void InkscapePreferences::initPageTools() Gtk::TreeModel::iterator iter_tools = this->AddPage(_page_tools, _("Tools"), PREFS_PAGE_TOOLS); _path_tools = _page_list.get_model()->get_path(iter_tools); - _page_tools.add_group_header( _("Bounding box to use:")); + _page_tools.add_group_header( _("Bounding box to use")); _t_bbox_visual.init ( _("Visual bounding box"), "/tools/bounding_box", 0, false, 0); // 0 means visual _page_tools.add_line( true, "", _t_bbox_visual, "", _("This bounding box includes stroke width, markers, filter margins, etc.")); @@ -401,7 +401,7 @@ void InkscapePreferences::initPageTools() _page_tools.add_line( true, "", _t_bbox_geometric, "", _("This bounding box includes only the bare path")); - _page_tools.add_group_header( _("Conversion to guides:")); + _page_tools.add_group_header( _("Conversion to guides")); _t_cvg_keep_objects.init ( _("Keep objects after conversion to guides"), "/tools/cvg_keep_objects", false); _page_tools.add_line( true, "", _t_cvg_keep_objects, "", _("When converting an object to guides, don't delete the object after the conversion")); @@ -418,14 +418,14 @@ void InkscapePreferences::initPageTools() this->AddPage(_page_selector, _("Selector"), iter_tools, PREFS_PAGE_TOOLS_SELECTOR); AddSelcueCheckbox(_page_selector, "/tools/select", false); - _page_selector.add_group_header( _("When transforming, show:")); + _page_selector.add_group_header( _("When transforming, show")); _t_sel_trans_obj.init ( _("Objects"), "/tools/select/show", "content", true, 0); _page_selector.add_line( true, "", _t_sel_trans_obj, "", _("Show the actual objects when moving or transforming")); _t_sel_trans_outl.init ( _("Box outline"), "/tools/select/show", "outline", false, &_t_sel_trans_obj); _page_selector.add_line( true, "", _t_sel_trans_outl, "", _("Show only a box outline of the objects when moving or transforming")); - _page_selector.add_group_header( _("Per-object selection cue:")); + _page_selector.add_group_header( _("Per-object selection cue")); _t_sel_cue_none.init ( _("None"), "/options/selcue/value", Inkscape::SelCue::NONE, false, 0); _page_selector.add_line( true, "", _t_sel_cue_none, "", _("No per-object selection indication")); @@ -646,20 +646,20 @@ void InkscapePreferences::initPageClones() _clone_option_delete.init ( _("Are deleted"), "/options/cloneorphans/value", SP_CLONE_ORPHANS_DELETE, false, &_clone_option_unlink); - _page_clones.add_group_header( _("When the original moves, its clones and linked offsets:")); + _page_clones.add_group_header( _("Moving original: clones and linked offsets")); _page_clones.add_line( true, "", _clone_option_parallel, "", _("Clones are translated by the same vector as their original")); _page_clones.add_line( true, "", _clone_option_stay, "", _("Clones preserve their positions when their original is moved")); _page_clones.add_line( true, "", _clone_option_transform, "", _("Each clone moves according to the value of its transform= attribute; for example, a rotated clone will move in a different direction than its original")); - _page_clones.add_group_header( _("When the original is deleted, its clones:")); + _page_clones.add_group_header( _("Deleting original: clones")); _page_clones.add_line( true, "", _clone_option_unlink, "", _("Orphaned clones are converted to regular objects")); _page_clones.add_line( true, "", _clone_option_delete, "", _("Orphaned clones are deleted along with their original")); - _page_clones.add_group_header( _("When duplicating original+clones:")); + _page_clones.add_group_header( _("Duplicating original+clones/linked offset")); _clone_relink_on_duplicate.init ( _("Relink duplicated clones"), "/options/relinkclonesonduplicate/value", false); _page_clones.add_line(true, "", _clone_relink_on_duplicate, "", @@ -1220,24 +1220,8 @@ void InkscapePreferences::initPageBitmaps() _misc_bitmap_autoreload.init(_("Automatically reload bitmaps"), "/options/bitmapautoreload/value", true); _page_bitmaps.add_line( false, "", _misc_bitmap_autoreload, "", _("Automatically reload linked images when file is changed on disk")); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Glib::ustring choices = prefs->getString("/options/bitmapeditor/choices"); - if (!choices.empty()) { - gchar** splits = g_strsplit(choices.data(), ",", 0); - gint numIems = g_strv_length(splits); - - Glib::ustring labels[numIems]; - int values[numIems]; - for ( gint i = 0; i < numIems; i++) { - values[i] = i; - labels[i] = splits[i]; - } - _misc_bitmap_editor.init("/options/bitmapeditor/value", labels, values, numIems, 0); - _page_bitmaps.add_line( false, _("Bitmap editor:"), _misc_bitmap_editor, "", "", false); - - g_strfreev(splits); - } - + _misc_bitmap_editor.init("/options/bitmapeditor/value", true); + _page_bitmaps.add_line( false, _("Bitmap editor:"), _misc_bitmap_editor, "", "", true); _bitmap_copy_res.init("/options/createbitmap/resolution", 1.0, 6000.0, 1.0, 1.0, PX_PER_IN, true, false); _page_bitmaps.add_line( false, _("Resolution for Create Bitmap Copy:"), _bitmap_copy_res, _("dpi"), _("Resolution used by the Create Bitmap Copy command"), false); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 5ee916e4c..a20278551 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -28,6 +28,7 @@ #include <gtkmm/frame.h> #include <gtkmm/notebook.h> #include "ui/widget/preferences-widget.h" +#include <stddef.h> #include <sigc++/sigc++.h> #include <glibmm/i18n.h> #include <gtkmm/textview.h> @@ -297,7 +298,7 @@ protected: UI::Widget::PrefCheckButton _spell_ignoreallcaps; UI::Widget::PrefCombo _misc_overs_bitmap; - UI::Widget::PrefCombo _misc_bitmap_editor; + UI::Widget::PrefEntryFileButtonHBox _misc_bitmap_editor; UI::Widget::PrefCheckButton _misc_bitmap_autoreload; UI::Widget::PrefSpinButton _bitmap_copy_res; diff --git a/src/ui/dialog/input.cpp b/src/ui/dialog/input.cpp index 8f19c90c4..6869aa97b 100644 --- a/src/ui/dialog/input.cpp +++ b/src/ui/dialog/input.cpp @@ -347,7 +347,7 @@ static std::map<Gdk::InputMode, Glib::ustring> &getModeToString() static std::map<Gdk::InputMode, Glib::ustring> mapping; if (mapping.empty()) { mapping[Gdk::MODE_DISABLED] = _("Disabled"); - mapping[Gdk::MODE_SCREEN] = _("Screen"); + mapping[Gdk::MODE_SCREEN] = C_("Input device", "Screen"); mapping[Gdk::MODE_WINDOW] = _("Window"); } @@ -877,8 +877,8 @@ InputDialogImpl::ConfPanel::ConfPanel() : tree(store), treeScroller(), watcher(*this), - useExt(_("Use pressure-sensitive tablet (requires restart)")), - save(_("Save")) + useExt(_("_Use pressure-sensitive tablet (requires restart)"), true), + save(_("_Save"), true) { pack_start(treeScroller); diff --git a/src/ui/dialog/ocaldialogs.cpp b/src/ui/dialog/ocaldialogs.cpp index d3887b1ca..2ae7d6989 100644 --- a/src/ui/dialog/ocaldialogs.cpp +++ b/src/ui/dialog/ocaldialogs.cpp @@ -470,7 +470,7 @@ void FileImportFromOCALDialog::searchTagEntryChangedCallback() doc = xmlReadIO ((xmlInputReadCallback) vfs_read_callback, (xmlInputCloseCallback) gnome_vfs_close, from_handle, uri.c_str(), NULL, - XML_PARSE_RECOVER); + XML_PARSE_RECOVER + XML_PARSE_NOWARNING + XML_PARSE_NOERROR); if (doc == NULL) { sp_ui_error_dialog(_("Server supplied malformed Clip Art feed")); g_warning("Failed to parse %s\n", uri.c_str()); diff --git a/src/ui/dialog/svg-fonts-dialog.cpp b/src/ui/dialog/svg-fonts-dialog.cpp index 042acb6e1..2d1b5ae39 100644 --- a/src/ui/dialog/svg-fonts-dialog.cpp +++ b/src/ui/dialog/svg-fonts-dialog.cpp @@ -114,7 +114,7 @@ void SvgFontsDialog::AttrEntry::on_attr_changed(){ const gchar* name = (const gchar*)sp_attribute_name(this->attr); if(name && o) { - SP_OBJECT_REPR(o)->setAttribute((const gchar*) name, this->entry.get_text().c_str()); + o->getRepr()->setAttribute((const gchar*) name, this->entry.get_text().c_str()); o->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); Glib::ustring undokey = "svgfonts:"; @@ -438,7 +438,7 @@ SPGlyph *new_glyph(SPDocument* document, SPFont *font, const int count) repr->setAttribute("glyph-name", os.str().c_str()); // Append the new glyph node to the current font - SP_OBJECT_REPR(font)->appendChild(repr); + font->getRepr()->appendChild(repr); Inkscape::GC::release(repr); // get corresponding object @@ -498,7 +498,7 @@ void SvgFontsDialog::set_glyph_description_from_selected_path(){ Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d")); //This matrix flips the glyph vertically - Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); + Geom::Affine m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); pathv*=m; //then we offset it pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x)); @@ -543,7 +543,7 @@ void SvgFontsDialog::missing_glyph_description_from_selected_path(){ Geom::PathVector pathv = sp_svg_read_pathv(node->attribute("d")); //This matrix flips the glyph vertically - Geom::Matrix m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); + Geom::Affine m(Geom::Coord(1),Geom::Coord(0),Geom::Coord(0),Geom::Coord(-1),Geom::Coord(0),Geom::Coord(0)); pathv*=m; //then we offset it // pathv+=Geom::Point(Geom::Coord(0),Geom::Coord(get_selected_spfont()->horiz_adv_x)); @@ -732,7 +732,7 @@ void SvgFontsDialog::add_kerning_pair(){ repr->setAttribute("k", "0"); // Append the new hkern node to the current font - SP_OBJECT_REPR(get_selected_spfont())->appendChild(repr); + get_selected_spfont()->getRepr()->appendChild(repr); Inkscape::GC::release(repr); // get corresponding object @@ -797,7 +797,7 @@ SPFont *new_font(SPDocument *document) repr->setAttribute("horiz-adv-x", "1024"); // Append the new font node to defs - SP_OBJECT_REPR(defs)->appendChild(repr); + defs->getRepr()->appendChild(repr); //create a missing glyph Inkscape::XML::Node *fontface; diff --git a/src/ui/dialog/tile.cpp b/src/ui/dialog/tile.cpp index fccf5c105..b0a39bd0e 100644 --- a/src/ui/dialog/tile.cpp +++ b/src/ui/dialog/tile.cpp @@ -316,7 +316,7 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h for (; current_row != NULL; current_row = current_row->next) { SPItem *item=SP_ITEM(current_row->data); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(item); + Inkscape::XML::Node *repr = item->getRepr(); Geom::OptRect b = item->getBounds(item->i2doc_affine()); Geom::Point min; if (b) { @@ -336,7 +336,7 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h // signs are inverted between x and y due to y inversion Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y); - Geom::Matrix const affine = Geom::Matrix(Geom::Translate(move)); + Geom::Affine const affine = Geom::Affine(Geom::Translate(move)); item->set_i2d_affine(item->i2d_affine() * affine); item->doWriteTransform(repr, item->transform, NULL); SP_OBJECT (current_row->data)->updateRepr(); @@ -656,7 +656,8 @@ TileDialog::TileDialog() g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount); #endif - NoOfRowsLabel.set_label(_("Rows:")); + NoOfRowsLabel.set_text_with_mnemonic(_("_Rows:")); + NoOfRowsLabel.set_mnemonic_widget(NoOfRowsSpinner); NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN); NoOfRowsSpinner.set_digits(0); @@ -668,7 +669,8 @@ TileDialog::TileDialog() NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN); gtk_size_group_add_widget(_col1, (GtkWidget *) NoOfRowsBox.gobj()); - RowHeightButton.set_label(_("Equal height")); + RowHeightButton.set_label(_("Equal _height")); + RowHeightButton.set_use_underline(true); double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15); if (AutoRow>0) AutoRowSize=true; @@ -726,7 +728,8 @@ TileDialog::TileDialog() /*#### Number of columns ####*/ - NoOfColsLabel.set_label(_("Columns:")); + NoOfColsLabel.set_text_with_mnemonic(_("_Columns:")); + NoOfColsLabel.set_mnemonic_widget(NoOfColsSpinner); NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN); NoOfColsSpinner.set_digits(0); @@ -738,7 +741,8 @@ TileDialog::TileDialog() NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN); gtk_size_group_add_widget(_col3, (GtkWidget *) NoOfColsBox.gobj()); - ColumnWidthButton.set_label(_("Equal width")); + ColumnWidthButton.set_label(_("Equal _width")); + ColumnWidthButton.set_use_underline(true); double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15); if (AutoCol>0) AutoColSize=true; @@ -793,13 +797,15 @@ TileDialog::TileDialog() { /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/ - SpaceByBBoxRadioButton.set_label(_("Fit into selection box")); + SpaceByBBoxRadioButton.set_label(_("_Fit into selection box")); + SpaceByBBoxRadioButton.set_use_underline (true); SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed)); SpacingGroup = SpaceByBBoxRadioButton.get_group(); SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN); - SpaceManualRadioButton.set_label(_("Set spacing:")); + SpaceManualRadioButton.set_label(_("_Set spacing:")); + SpaceManualRadioButton.set_use_underline (true); SpaceManualRadioButton.set_group(SpacingGroup); SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed)); SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN); @@ -867,7 +873,8 @@ TileDialog::TileDialog() SizesHBox.set_sensitive (ManualSpacing); //## The OK button - TileOkButton = addResponseButton(Q_("tileClonesDialog|Arrange"), GTK_RESPONSE_APPLY); + TileOkButton = addResponseButton(C_("Rows and columns dialog","_Arrange"), GTK_RESPONSE_APPLY); + TileOkButton->set_use_underline(true); tips.set_tip((*TileOkButton), _("Arrange selected objects")); show_all_children(); diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 1bca2ffff..901d02240 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -103,7 +103,7 @@ Transformation::Transformation() _scalar_transform_f ("_F:", _("Transformation matrix element F")), _check_move_relative (_("Rela_tive move"), _("Add the specified relative displacement to the current position; otherwise, edit the current absolute position directly")), - _check_scale_proportional (_("Scale proportionally"), _("Preserve the width/height ratio of the scaled objects")), + _check_scale_proportional (_("_Scale proportionally"), _("Preserve the width/height ratio of the scaled objects")), _check_apply_separately (_("Apply to each _object separately"), _("Apply the scale/rotate/skew to each selected object separately; otherwise, transform the selection as a whole")), _check_replace_matrix (_("Edit c_urrent matrix"), _("Edit the current transform= matrix; otherwise, post-multiply transform= by this matrix")) @@ -538,9 +538,9 @@ Transformation::updatePageTransform(Inkscape::Selection *selection) { if (selection && !selection->isEmpty()) { if (_check_replace_matrix.get_active()) { - Geom::Matrix current (SP_ITEM(selection->itemList()->data)->transform); // take from the first item in selection + Geom::Affine current (SP_ITEM(selection->itemList()->data)->transform); // take from the first item in selection - Geom::Matrix new_displayed = current; + Geom::Affine new_displayed = current; _scalar_transform_a.setValue(new_displayed[0]); _scalar_transform_b.setValue(new_displayed[1]); @@ -840,7 +840,7 @@ Transformation::applyPageTransform(Inkscape::Selection *selection) double e = _scalar_transform_e.getValue(); double f = _scalar_transform_f.getValue(); - Geom::Matrix displayed(a, b, c, d, e, f); + Geom::Affine displayed(a, b, c, d, e, f); if (_check_replace_matrix.get_active()) { for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { @@ -988,10 +988,10 @@ Transformation::onReplaceMatrixToggled() double e = _scalar_transform_e.getValue(); double f = _scalar_transform_f.getValue(); - Geom::Matrix displayed (a, b, c, d, e, f); - Geom::Matrix current = SP_ITEM(selection->itemList()->data)->transform; // take from the first item in selection + Geom::Affine displayed (a, b, c, d, e, f); + Geom::Affine current = SP_ITEM(selection->itemList()->data)->transform; // take from the first item in selection - Geom::Matrix new_displayed; + Geom::Affine new_displayed; if (_check_replace_matrix.get_active()) { new_displayed = current; } else { diff --git a/src/ui/dialog/undo-history.cpp b/src/ui/dialog/undo-history.cpp index 17d032758..e6f113e48 100644 --- a/src/ui/dialog/undo-history.cpp +++ b/src/ui/dialog/undo-history.cpp @@ -15,6 +15,7 @@ #include <glibmm/i18n.h> #include <gtk/gtkimage.h> +#include <stddef.h> #include <sigc++/sigc++.h> diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp index 91e0bc2c2..1fb98d78f 100644 --- a/src/ui/tool/control-point-selection.cpp +++ b/src/ui/tool/control-point-selection.cpp @@ -166,7 +166,7 @@ void ControlPointSelection::spatialGrow(SelectableControlPoint *origin, int dir) } /** Transform all selected control points by the given affine transformation. */ -void ControlPointSelection::transform(Geom::Matrix const &m) +void ControlPointSelection::transform(Geom::Affine const &m) { for (iterator i = _points.begin(); i != _points.end(); ++i) { SelectableControlPoint *cur = *i; @@ -273,7 +273,7 @@ void ControlPointSelection::_pointGrabbed(SelectableControlPoint *point) _grabbed_point = point; _farthest_point = point; double maxdist = 0; - Geom::Matrix m; + Geom::Affine m; m.setIdentity(); for (iterator i = _points.begin(); i != _points.end(); ++i) { _original_positions.insert(std::make_pair(*i, (*i)->position())); @@ -290,11 +290,11 @@ void ControlPointSelection::_pointDragged(Geom::Point &new_pos, GdkEventMotion * { Geom::Point abs_delta = new_pos - _original_positions[_grabbed_point]; double fdist = Geom::distance(_original_positions[_grabbed_point], _original_positions[_farthest_point]); - if (held_alt(*event) && fdist > 0) { + if (held_only_alt(*event) && fdist > 0) { // Sculpting for (iterator i = _points.begin(); i != _points.end(); ++i) { SelectableControlPoint *cur = (*i); - Geom::Matrix trans; + Geom::Affine trans; trans.setIdentity(); double dist = Geom::distance(_original_positions[cur], _original_positions[_grabbed_point]); double deltafrac = 0.5 + 0.5 * cos(M_PI * dist/fdist); @@ -323,7 +323,7 @@ void ControlPointSelection::_pointDragged(Geom::Point &new_pos, GdkEventMotion * Geom::Point newdx = (newpx - newp) / Geom::EPSILON; Geom::Point newdy = (newpy - newp) / Geom::EPSILON; - Geom::Matrix itrans(newdx[Geom::X], newdx[Geom::Y], newdy[Geom::X], newdy[Geom::Y], 0, 0); + Geom::Affine itrans(newdx[Geom::X], newdx[Geom::Y], newdy[Geom::X], newdy[Geom::Y], 0, 0); if (itrans.isSingular()) itrans.setIdentity(); @@ -502,7 +502,7 @@ bool ControlPointSelection::_keyboardRotate(GdkEventKey const &event, int dir) } // translate to origin, rotate, translate back to original position - Geom::Matrix m = Geom::Translate(-rc) + Geom::Affine m = Geom::Translate(-rc) * Geom::Rotate(angle) * Geom::Translate(rc); transform(m); signal_commit.emit(COMMIT_KEYBOARD_ROTATE); @@ -538,7 +538,7 @@ bool ControlPointSelection::_keyboardScale(GdkEventKey const &event, int dir) } double scale = (maxext + length_change) / maxext; - Geom::Matrix m = Geom::Translate(-center) * Geom::Scale(scale) * Geom::Translate(center); + Geom::Affine m = Geom::Translate(-center) * Geom::Scale(scale) * Geom::Translate(center); transform(m); signal_commit.emit(COMMIT_KEYBOARD_SCALE_UNIFORM); return true; @@ -559,7 +559,7 @@ bool ControlPointSelection::_keyboardFlip(Geom::Dim2 d) dynamic_cast<SelectableControlPoint*>(ControlPoint::mouseovered_point); Geom::Point center = scp ? scp->position() : _handles->rotationCenter().position(); - Geom::Matrix m = Geom::Translate(-center) * scale_transform * Geom::Translate(center); + Geom::Affine m = Geom::Translate(-center) * scale_transform * Geom::Translate(center); transform(m); signal_commit.emit(d == Geom::X ? COMMIT_FLIP_X : COMMIT_FLIP_Y); return true; @@ -642,6 +642,24 @@ bool ControlPointSelection::event(GdkEvent *event) return false; } +std::vector<Inkscape::SnapCandidatePoint> ControlPointSelection::getOriginalPoints() +{ + std::vector<Inkscape::SnapCandidatePoint> points; + for (iterator i = _points.begin(); i != _points.end(); ++i) { + points.push_back(Inkscape::SnapCandidatePoint(_original_positions[*i], SNAPSOURCE_NODE_HANDLE)); + } + return points; +} + +void ControlPointSelection::setOriginalPoints() +{ + _original_positions.clear(); + for (iterator i = _points.begin(); i != _points.end(); ++i) { + _original_positions.insert(std::make_pair(*i, (*i)->position())); + } +} + + } // namespace UI } // namespace Inkscape diff --git a/src/ui/tool/control-point-selection.h b/src/ui/tool/control-point-selection.h index 3aed6ae93..7e09d50f5 100644 --- a/src/ui/tool/control-point-selection.h +++ b/src/ui/tool/control-point-selection.h @@ -14,17 +14,19 @@ #include <memory> #include <boost/optional.hpp> +#include <stddef.h> #include <sigc++/sigc++.h> #include <2geom/forward.h> #include <2geom/point.h> #include <2geom/rect.h> -#include "display/display-forward.h" #include "util/accumulators.h" #include "util/unordered-containers.h" #include "ui/tool/commit-events.h" #include "ui/tool/manipulator.h" +#include "snap-candidate.h" class SPDesktop; +struct SPCanvasGroup; namespace Inkscape { namespace UI { @@ -90,7 +92,7 @@ public: virtual bool event(GdkEvent *); - void transform(Geom::Matrix const &m); + void transform(Geom::Affine const &m); void align(Geom::Dim2 d); void distribute(Geom::Dim2 d); @@ -108,6 +110,10 @@ public: sigc::signal<void> signal_update; sigc::signal<void, SelectableControlPoint *, bool> signal_point_changed; sigc::signal<void, CommitEvent> signal_commit; + + std::vector<Inkscape::SnapCandidatePoint> getOriginalPoints(); + void setOriginalPoints(); + private: // The functions below are invoked from SelectableControlPoint. // Previously they were connected to handlers when selecting, but this @@ -125,14 +131,14 @@ private: bool _keyboardRotate(GdkEventKey const &, int); bool _keyboardScale(GdkEventKey const &, int); bool _keyboardFlip(Geom::Dim2); - void _keyboardTransform(Geom::Matrix const &); + void _keyboardTransform(Geom::Affine const &); void _commitHandlesTransform(CommitEvent ce); double _rotationRadius(Geom::Point const &); set_type _points; set_type _all_points; INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Point> _original_positions; - INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Matrix> _last_trans; + INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Affine> _last_trans; boost::optional<double> _rot_radius; boost::optional<double> _mouseover_rot_radius; Geom::OptRect _bounds; diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp index d5e5b7dfe..bece1324b 100644 --- a/src/ui/tool/control-point.cpp +++ b/src/ui/tool/control-point.cpp @@ -14,6 +14,7 @@ #include <2geom/point.h> #include "desktop.h" #include "desktop-handles.h" +#include "display/sp-canvas.h" #include "display/snap-indicator.h" #include "event-context.h" #include "message-context.h" @@ -213,7 +214,7 @@ void ControlPoint::move(Geom::Point const &pos) /** Apply an arbitrary affine transformation to a control point. This is used * by ControlPointSelection, and is important for things like nodes with handles. * The default implementation simply moves the point according to the transform. */ -void ControlPoint::transform(Geom::Matrix const &m) { +void ControlPoint::transform(Geom::Affine const &m) { move(position() * m); } diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h index 4de5e5847..9f62fca42 100644 --- a/src/ui/tool/control-point.h +++ b/src/ui/tool/control-point.h @@ -12,12 +12,12 @@ #define SEEN_UI_TOOL_CONTROL_POINT_H #include <boost/utility.hpp> +#include <stddef.h> #include <sigc++/sigc++.h> #include <gdkmm.h> #include <gtkmm.h> #include <2geom/point.h> -#include "display/display-forward.h" #include "forward.h" #include "util/accumulators.h" #include "display/sodipodi-ctrl.h" @@ -57,7 +57,7 @@ public: operator Geom::Point const &() { return _position; } virtual void move(Geom::Point const &pos); virtual void setPosition(Geom::Point const &pos); - virtual void transform(Geom::Matrix const &m); + virtual void transform(Geom::Affine const &m); /// @} /// @name Toggle the point's visibility diff --git a/src/ui/tool/manipulator.h b/src/ui/tool/manipulator.h index fd24e7b61..6866ec9dd 100644 --- a/src/ui/tool/manipulator.h +++ b/src/ui/tool/manipulator.h @@ -13,6 +13,7 @@ #include <set> #include <map> +#include <stddef.h> #include <sigc++/sigc++.h> #include <glib.h> #include <gdk/gdk.h> diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index ef1c764bb..082ac194b 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -210,7 +210,78 @@ void MultiPathManipulator::selectSubpaths() void MultiPathManipulator::shiftSelection(int dir) { - invokeForAll(&PathManipulator::shiftSelection, dir); + if (empty()) return; + + // 1. find last selected node + // 2. select the next node; if the last node or nothing is selected, + // select first node + MapType::iterator last_i; + SubpathList::iterator last_j; + NodeList::iterator last_k; + bool anything_found = false; + + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + SubpathList &sp = i->second->subpathList(); + for (SubpathList::iterator j = sp.begin(); j != sp.end(); ++j) { + for (NodeList::iterator k = (*j)->begin(); k != (*j)->end(); ++k) { + if (k->selected()) { + last_i = i; + last_j = j; + last_k = k; + anything_found = true; + // when tabbing backwards, we want the first node + if (dir == -1) goto exit_loop; + } + } + } + } + exit_loop: + + // NOTE: we should not assume the _selection contains only nodes + // in future it might also contain handles and other types of control points + // this is why we use a flag instead in the loop above, instead of calling + // selection.empty() + if (!anything_found) { + // select first / last node + // this should never fail because there must be at least 1 non-empty manipulator + if (dir == 1) { + _selection.insert((*_mmap.begin()->second->subpathList().begin())->begin().ptr()); + } else { + _selection.insert((--(*--(--_mmap.end())->second->subpathList().end())->end()).ptr()); + } + return; + } + + // three levels deep - w00t! + if (dir == 1) { + if (++last_k == (*last_j)->end()) { + // here, last_k points to the node to be selected + ++last_j; + if (last_j == last_i->second->subpathList().end()) { + ++last_i; + if (last_i == _mmap.end()) { + last_i = _mmap.begin(); + } + last_j = last_i->second->subpathList().begin(); + } + last_k = (*last_j)->begin(); + } + } else { + if (!last_k || last_k == (*last_j)->begin()) { + if (last_j == last_i->second->subpathList().begin()) { + if (last_i == _mmap.begin()) { + last_i = _mmap.end(); + } + --last_i; + last_j = last_i->second->subpathList().end(); + } + --last_j; + last_k = (*last_j)->end(); + } + --last_k; + } + _selection.clear(); + _selection.insert(last_k.ptr()); } void MultiPathManipulator::invertSelectionInSubpaths() @@ -695,6 +766,14 @@ void MultiPathManipulator::_commit(CommitEvent cps) reason = _("Scale nodes vertically"); key = "node:scale:y"; break; + case COMMIT_MOUSE_SKEW_X: + reason = _("Skew nodes horizontally"); + key = "node:skew:x"; + break; + case COMMIT_MOUSE_SKEW_Y: + reason = _("Skew nodes vertically"); + key = "node:skew:y"; + break; case COMMIT_FLIP_X: reason = _("Flip nodes horizontally"); break; diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h index ddb74c1bc..c25719790 100644 --- a/src/ui/tool/multi-path-manipulator.h +++ b/src/ui/tool/multi-path-manipulator.h @@ -11,8 +11,8 @@ #ifndef SEEN_UI_TOOL_MULTI_PATH_MANIPULATOR_H #define SEEN_UI_TOOL_MULTI_PATH_MANIPULATOR_H +#include <stddef.h> #include <sigc++/connection.h> -#include "display/display-forward.h" #include "forward.h" #include "ui/tool/commit-events.h" #include "ui/tool/manipulator.h" diff --git a/src/ui/tool/node-tool.cpp b/src/ui/tool/node-tool.cpp index 8661e7946..f83f8c473 100644 --- a/src/ui/tool/node-tool.cpp +++ b/src/ui/tool/node-tool.cpp @@ -13,6 +13,7 @@ #include <glib/gi18n.h> #include "desktop.h" #include "desktop-handles.h" +#include "display/sp-canvas-group.h" #include "display/canvas-bpath.h" #include "display/curve.h" #include "display/sp-canvas.h" @@ -479,10 +480,11 @@ gint ink_node_tool_root_handler(SPEventContext *event_context, GdkEvent *event) nt->flash_tempitem = NULL; nt->flashed_item = NULL; } - if (!SP_IS_PATH(over_item)) break; // for now, handle only paths + if (!SP_IS_SHAPE(over_item)) break; // for now, handle only shapes nt->flashed_item = over_item; - SPCurve *c = sp_path_get_curve_for_edit(SP_PATH(over_item)); + SPCurve *c = SP_SHAPE(over_item)->getCurveBeforeLPE(); + if (!c) break; // break out when curve doesn't exist c->transform(over_item->i2d_affine()); SPCanvasItem *flash = sp_canvas_bpath_new(sp_desktop_tempgroup(desktop), c); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(flash), diff --git a/src/ui/tool/node-tool.h b/src/ui/tool/node-tool.h index 4d38e69e2..d005a0bdf 100644 --- a/src/ui/tool/node-tool.h +++ b/src/ui/tool/node-tool.h @@ -14,10 +14,10 @@ #include <memory> #include <boost/ptr_container/ptr_map.hpp> #include <glib.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include "event-context.h" #include "forward.h" -#include "display/display-forward.h" #include "ui/tool/node-types.h" #define INK_TYPE_NODE_TOOL (ink_node_tool_get_type ()) @@ -30,13 +30,17 @@ class InkNodeTool; class InkNodeToolClass; namespace Inkscape { + +namespace Display { +class TemporaryItem; +} // namespace Display namespace UI { class MultiPathManipulator; class ControlPointSelection; class Selector; struct PathSharedData; -} -} +} // namespace UI +} // namespace Inkscape typedef std::auto_ptr<Inkscape::UI::MultiPathManipulator> MultiPathPtr; typedef std::auto_ptr<Inkscape::UI::ControlPointSelection> CSelPtr; diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index 12d04dd2b..8e3da266b 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -113,12 +113,29 @@ void Handle::move(Geom::Point const &new_pos) Handle *towards_second = node_towards ? node_towards->handleToward(_parent) : NULL; if (Geom::are_near(new_pos, _parent->position())) { - // The handle becomes degenerate. If the segment between it and the node + // The handle becomes degenerate. + // Adjust node type as necessary. + if (other->isDegenerate()) { + // If both handles become degenerate, convert to parent cusp node + _parent->setType(NODE_CUSP, false); + } else { + // Only 1 handle becomes degenerate + switch (_parent->type()) { + case NODE_AUTO: + case NODE_SYMMETRIC: + _parent->setType(NODE_SMOOTH, false); + break; + default: + // do nothing for other node types + break; + } + } + // If the segment between the handle and the node // in its direction becomes linear and there are smooth nodes // at its ends, make their handles colinear with the segment - if (towards && towards->isDegenerate()) { + if (towards && towards_second->isDegenerate()) { if (node_towards->type() == NODE_SMOOTH) { - towards_second->setDirection(*_parent, *node_towards); + towards->setDirection(*_parent, *node_towards); } if (_parent->type() == NODE_SMOOTH) { other->setDirection(*node_towards, *_parent); @@ -160,6 +177,7 @@ void Handle::move(Geom::Point const &new_pos) void Handle::setPosition(Geom::Point const &p) { + Geom::Point old_pos = position(); ControlPoint::setPosition(p); sp_ctrlline_set_coords(SP_CTRLLINE(_handle_line), _parent->position(), position()); @@ -167,15 +185,12 @@ void Handle::setPosition(Geom::Point const &p) if (Geom::are_near(position(), _parent->position())) _degenerate = true; else _degenerate = false; + if (_parent->_handles_shown && _parent->visible() && !_degenerate) { setVisible(true); } else { setVisible(false); } - // If both handles become degenerate, convert to parent cusp node - if (_parent->isDegenerate()) { - _parent->setType(NODE_CUSP, false); - } } void Handle::setLength(double len) @@ -187,7 +202,7 @@ void Handle::setLength(double len) void Handle::retract() { - setPosition(_parent->position()); + move(_parent->position()); } void Handle::setDirection(Geom::Point const &from, Geom::Point const &to) @@ -212,6 +227,35 @@ char const *Handle::handle_type_to_localized_string(NodeType type) } } +bool Handle::_eventHandler(GdkEvent *event) +{ + switch (event->type) + { + case GDK_KEY_PRESS: + switch (shortcut_key(event->key)) + { + case GDK_s: + case GDK_S: + if (held_only_shift(event->key) && _parent->_type == NODE_CUSP) { + // when Shift+S is pressed when hovering over a handle belonging to a cusp node, + // hold this handle in place; otherwise process normally + // this handle is guaranteed not to be degenerate + other()->move(_parent->position() - (position() - _parent->position())); + _parent->setType(NODE_SMOOTH, false); + _parent->_pm().update(); // magic triple combo to add undo event + _parent->_pm().writeXML(); + _parent->_pm()._commit(_("Change node type")); + return true; + } + break; + default: break; + } + default: break; + } + + return ControlPoint::_eventHandler(event); +} + bool Handle::grabbed(GdkEventMotion *) { _saved_other_pos = other()->position(); @@ -226,6 +270,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) Geom::Point origin = _last_drag_origin(); SnapManager &sm = _desktop->namedview->snap_manager; bool snap = sm.someSnapperMightSnap(); + boost::optional<Inkscape::Snapper::SnapConstraint> ctrl_constraint; // with Alt, preserve length if (held_alt(*event)) { @@ -241,16 +286,23 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) // note: if snapping to the original position is only desired in the original // direction of the handle, change to Ray instead of Line Geom::Line original_line(parent_pos, origin); + Geom::Line perp_line(parent_pos, parent_pos + Geom::rot90(origin - parent_pos)); Geom::Point snap_pos = parent_pos + Geom::constrain_angle( Geom::Point(0,0), new_pos - parent_pos, snaps, Geom::Point(1,0)); Geom::Point orig_pos = original_line.pointAt(original_line.nearestPoint(new_pos)); + Geom::Point perp_pos = perp_line.pointAt(perp_line.nearestPoint(new_pos)); - if (Geom::distance(snap_pos, new_pos) < Geom::distance(orig_pos, new_pos)) { - new_pos = snap_pos; - } else { - new_pos = orig_pos; + Geom::Point result = snap_pos; + ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - snap_pos); + if (Geom::distance(orig_pos, new_pos) < Geom::distance(result, new_pos)) { + result = orig_pos; + ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - orig_pos); } - snap = false; + if (Geom::distance(perp_pos, new_pos) < Geom::distance(result, new_pos)) { + result = perp_pos; + ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - perp_pos); + } + new_pos = result; } std::vector<Inkscape::SnapCandidatePoint> unselected; @@ -264,13 +316,20 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) } sm.setupIgnoreSelection(_desktop, true, &unselected); - Node *node_away = (this == &_parent->_front ? _parent->_prev() : _parent->_next()); + Node *node_away = _parent->nodeAwayFrom(this); if (_parent->type() == NODE_SMOOTH && Node::_is_line_segment(_parent, node_away)) { Inkscape::Snapper::SnapConstraint cl(_parent->position(), _parent->position() - node_away->position()); Inkscape::SnappedPoint p; p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), cl); new_pos = p.getPoint(); + } else if (ctrl_constraint) { + // NOTE: this is subtly wrong. + // We should get all possible constraints and snap along them using + // multipleConstrainedSnaps, instead of first snapping to angle and the to objects + Inkscape::SnappedPoint p; + p = sm.constrainedSnap(Inkscape::SnapCandidatePoint(new_pos, SNAPSOURCE_NODE_HANDLE), *ctrl_constraint); + new_pos = p.getPoint(); } else { sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_NODE_HANDLE); } @@ -455,7 +514,7 @@ void Node::move(Geom::Point const &new_pos) _fixNeighbors(old_pos, new_pos); } -void Node::transform(Geom::Matrix const &m) +void Node::transform(Geom::Affine const &m) { Geom::Point old_pos = position(); setPosition(position() * m); @@ -770,26 +829,6 @@ bool Node::_eventHandler(GdkEvent *event) return ControlPoint::_eventHandler(event); } -// TODO Move this to 2Geom! -static double bezier_length (Geom::Point a0, Geom::Point a1, Geom::Point a2, Geom::Point a3) -{ - double lower = Geom::distance(a0, a3); - double upper = Geom::distance(a0, a1) + Geom::distance(a1, a2) + Geom::distance(a2, a3); - - if (upper - lower < Geom::EPSILON) return (lower + upper)/2; - - Geom::Point // Casteljau subdivision - b0 = a0, - c0 = a3, - b1 = 0.5*(a0 + a1), - t0 = 0.5*(a1 + a2), - c1 = 0.5*(a2 + a3), - b2 = 0.5*(b1 + t0), - c2 = 0.5*(t0 + c1), - b3 = 0.5*(b2 + c2); // == c3 - return bezier_length(b0, b1, b2, b3) + bezier_length(b3, c2, c1, c0); -} - /** Select or deselect a node in this node's subpath based on its path distance from this node. * @param dir If negative, shrink selection by one node; if positive, grow by one node */ void Node::_linearGrow(int dir) @@ -816,7 +855,7 @@ void Node::_linearGrow(int dir) // find first unselected nodes on both sides while (fwd && fwd->selected()) { NodeList::iterator n = fwd.next(); - distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n); + distance_front += Geom::bezier_length(*fwd, fwd->_front, n->_back, *n); fwd = n; if (fwd == this_iter) // there is no unselected node in this cyclic subpath @@ -827,7 +866,7 @@ void Node::_linearGrow(int dir) // so we are guaranteed to stop. while (rev && rev->selected()) { NodeList::iterator p = rev.prev(); - distance_back += bezier_length(*rev, rev->_back, p->_front, *p); + distance_back += Geom::bezier_length(*rev, rev->_back, p->_front, *p); rev = p; } @@ -858,7 +897,7 @@ void Node::_linearGrow(int dir) last_distance_front = distance_front; } NodeList::iterator n = fwd.next(); - if (n) distance_front += bezier_length(*fwd, fwd->_front, n->_back, *n); + if (n) distance_front += Geom::bezier_length(*fwd, fwd->_front, n->_back, *n); fwd = n; } else if (rev && (!fwd || distance_front > distance_back)) { if (rev->selected()) { @@ -866,7 +905,7 @@ void Node::_linearGrow(int dir) last_distance_back = distance_back; } NodeList::iterator p = rev.prev(); - if (p) distance_back += bezier_length(*rev, rev->_back, p->_front, *p); + if (p) distance_back += Geom::bezier_length(*rev, rev->_back, p->_front, *p); rev = p; } // Check whether we walked the entire cyclic subpath. @@ -876,8 +915,8 @@ void Node::_linearGrow(int dir) if (fwd && fwd == rev) { if (!fwd->selected()) break; NodeList::iterator fwdp = fwd.prev(), revn = rev.next(); - double df = distance_front + bezier_length(*fwdp, fwdp->_front, fwd->_back, *fwd); - double db = distance_back + bezier_length(*revn, revn->_back, rev->_front, *rev); + double df = distance_front + Geom::bezier_length(*fwdp, fwdp->_front, fwd->_back, *fwd); + double db = distance_back + Geom::bezier_length(*revn, revn->_back, rev->_front, *rev); if (df > db) { last_fwd = fwd; last_distance_front = df; diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 0194f5053..b7145790b 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -15,6 +15,7 @@ #include <iterator> #include <iosfwd> #include <stdexcept> +#include <cstddef> #include <tr1/functional> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> @@ -102,6 +103,7 @@ public: protected: Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent); + virtual bool _eventHandler(GdkEvent *event); virtual void dragged(Geom::Point &, GdkEventMotion *); virtual bool grabbed(GdkEventMotion *); virtual void ungrabbed(GdkEventButton *); @@ -127,7 +129,7 @@ class Node : ListNode, public SelectableControlPoint { public: Node(NodeSharedData const &data, Geom::Point const &pos); virtual void move(Geom::Point const &p); - virtual void transform(Geom::Matrix const &m); + virtual void transform(Geom::Affine const &m); virtual Geom::Rect bounds(); NodeType type() { return _type; } diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 5ae9c4137..7c2013872 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -102,14 +102,14 @@ private: void build_segment(Geom::PathBuilder &, Node *, Node *); PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path, - Geom::Matrix const &et, guint32 outline_color, Glib::ustring lpe_key) + Geom::Affine const &et, guint32 outline_color, Glib::ustring lpe_key) : PointManipulator(mpm._path_data.node_data.desktop, *mpm._path_data.node_data.selection) , _subpaths(*this) , _multi_path_manipulator(mpm) , _path(path) , _spcurve(new SPCurve()) , _dragpoint(new CurveDragPoint(*this)) - , /* XML Tree being used here directly while it shouldn't be*/_observer(new PathManipulatorObserver(this, SP_OBJECT(path)->getRepr())) + , /* XML Tree being used here directly while it shouldn't be*/_observer(new PathManipulatorObserver(this, path->getRepr())) , _edit_transform(et) , _num_selected(0) , _show_handles(true) @@ -191,7 +191,7 @@ void PathManipulator::writeXML() if (!_path) return; _observer->block(); if (!empty()) { - SP_OBJECT(_path)->updateRepr(); + _path->updateRepr(); _getXMLNode()->setAttribute(_nodetypesKey().data(), _createTypeString().data()); } else { // this manipulator will have to be destroyed right after this call @@ -215,7 +215,7 @@ void PathManipulator::clear() /** Select all nodes in subpaths that have something selected. */ void PathManipulator::selectSubpaths() { - for (std::list<SubpathPtr>::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { + for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { NodeList::iterator sp_start = (*i)->begin(), sp_end = (*i)->end(); for (NodeList::iterator j = sp_start; j != sp_end; ++j) { if (j->selected()) { @@ -229,63 +229,6 @@ void PathManipulator::selectSubpaths() } } -/** Move the selection forward or backward by one node in each subpath, based on the sign - * of the parameter. */ -void PathManipulator::shiftSelection(int dir) -{ - if (dir == 0) return; - if (_num_selected == 0) { - // select the first node of the path. - SubpathList::iterator s = _subpaths.begin(); - if (s == _subpaths.end()) return; - NodeList::iterator n = (*s)->begin(); - if (n != (*s)->end()) - _selection.insert(n.ptr()); - return; - } - // We cannot do any tricks here, like iterating in different directions based on - // the sign and only setting the selection of nodes behind us, because it would break - // for closed paths. - for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { - std::deque<bool> sels; // I hope this is specialized for bools! - unsigned num = 0; - - for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) { - sels.push_back(j->selected()); - _selection.erase(j.ptr()); - ++num; - } - if (num == 0) continue; // should never happen! zero-node subpaths are not allowed - - num = 0; - // In closed subpath, shift the selection cyclically. In an open one, - // let the selection 'slide into nothing' at ends. - if (dir > 0) { - if ((*i)->closed()) { - bool last = sels.back(); - sels.pop_back(); - sels.push_front(last); - } else { - sels.push_front(false); - } - } else { - if ((*i)->closed()) { - bool first = sels.front(); - sels.pop_front(); - sels.push_back(first); - } else { - sels.push_back(false); - num = 1; - } - } - - for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) { - if (sels[num]) _selection.insert(j.ptr()); - ++num; - } - } -} - /** Invert selection in the selected subpaths. */ void PathManipulator::invertSelectionInSubpaths() { @@ -332,22 +275,31 @@ void PathManipulator::duplicateNodes() NodeList::iterator k = j.next(); Node *n = new Node(_multi_path_manipulator._path_data.node_data, *j); - // Move the new node to the bottom of the Z-order. This way you can drag all - // nodes that were selected before this operation without deselecting - // everything because there is a new node above. - n->sink(); + if (k) { + // Move the new node to the bottom of the Z-order. This way you can drag all + // nodes that were selected before this operation without deselecting + // everything because there is a new node above. + n->sink(); + } n->front()->setPosition(*j->front()); j->front()->retract(); j->setType(NODE_CUSP, false); (*i)->insert(k, n); - // We need to manually call the selection change callback to refresh - // the handle display correctly. - // This call changes num_selected, but we call this once for a selected node - // and once for an unselected node, so in the end the number stays correct. - _selectionChanged(j.ptr(), true); - _selectionChanged(n, false); + if (k) { + // We need to manually call the selection change callback to refresh + // the handle display correctly. + // This call changes num_selected, but we call this once for a selected node + // and once for an unselected node, so in the end the number stays correct. + _selectionChanged(j.ptr(), true); + _selectionChanged(n, false); + } else { + // select the new end node instead of the node just before it + _selection.erase(j.ptr()); + _selection.insert(n); + break; // this was the end node, nothing more to do + } } } } @@ -895,9 +847,9 @@ void PathManipulator::setLiveObjects(bool set) _live_objects = set; } -void PathManipulator::setControlsTransform(Geom::Matrix const &tnew) +void PathManipulator::setControlsTransform(Geom::Affine const &tnew) { - Geom::Matrix delta = _i2d_transform.inverse() * _edit_transform.inverse() * tnew * _i2d_transform; + Geom::Affine delta = _i2d_transform.inverse() * _edit_transform.inverse() * tnew * _i2d_transform; _edit_transform = tnew; for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) { @@ -1023,7 +975,7 @@ void PathManipulator::_externalChange(unsigned type) _updateOutline(); } break; case PATH_CHANGE_TRANSFORM: { - Geom::Matrix i2d_change = _d2i_transform; + Geom::Affine i2d_change = _d2i_transform; _i2d_transform = SP_ITEM(_path)->i2d_affine(); _d2i_transform = _i2d_transform.inverse(); i2d_change *= _i2d_transform; @@ -1087,13 +1039,14 @@ void PathManipulator::_createControlPointsFromGeometry() subpath->push_back(current_node); } // if this is a bezier segment, move handles appropriately - if (Geom::CubicBezier const *cubic_bezier = - dynamic_cast<Geom::CubicBezier const*>(&*cit)) + // TODO: I don't know why the dynamic cast below doesn't want to work + // when I replace BezierCurve with CubicBezier. Might be a bug + // somewhere in pathv_to_linear_and_cubic_beziers + Geom::BezierCurve const *bezier = dynamic_cast<Geom::BezierCurve const*>(&*cit); + if (bezier && bezier->order() == 3) { - std::vector<Geom::Point> points = cubic_bezier->points(); - - previous_node->front()->setPosition(points[1]); - current_node ->back() ->setPosition(points[2]); + previous_node->front()->setPosition((*bezier)[1]); + current_node ->back() ->setPosition((*bezier)[2]); } previous_node = current_node; } @@ -1436,7 +1389,7 @@ void PathManipulator::_commit(Glib::ustring const &annotation, gchar const *key) * point of the path. */ void PathManipulator::_updateDragPoint(Geom::Point const &evp) { - Geom::Matrix to_desktop = _edit_transform * _i2d_transform; + Geom::Affine to_desktop = _edit_transform * _i2d_transform; Geom::PathVector pv = _spcurve->get_pathvector(); boost::optional<Geom::PathVectorPosition> pvp = Geom::nearestPoint(pv, _desktop->w2d(evp) * to_desktop.inverse()); @@ -1477,8 +1430,8 @@ double PathManipulator::_getStrokeTolerance() * drag tolerance setting. */ Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double ret = prefs->getIntLimited("/options/dragtolerance/value", 2, 0, 100); - if (_path && SP_OBJECT_STYLE(_path) && !SP_OBJECT_STYLE(_path)->stroke.isNone()) { - ret += SP_OBJECT_STYLE(_path)->stroke_width.computed * 0.5 + if (_path && _path->style && !_path->style->stroke.isNone()) { + ret += _path->style->stroke_width.computed * 0.5 * (_edit_transform * _i2d_transform).descrim() // scale to desktop coords * _desktop->current_zoom(); // == _d2w.descrim() - scale to window coords } diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 87b88fc77..27a83f06b 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -14,15 +14,15 @@ #include <string> #include <memory> #include <2geom/pathvector.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include <boost/shared_ptr.hpp> #include <boost/weak_ptr.hpp> -#include "display/display-forward.h" #include "forward.h" #include "ui/tool/node.h" #include "ui/tool/manipulator.h" struct SPCanvasItem; +struct SPCurve; namespace Inkscape { namespace XML { class Node; } @@ -53,7 +53,7 @@ class PathManipulator : public PointManipulator { public: typedef SPPath *ItemType; - PathManipulator(MultiPathManipulator &mpm, SPPath *path, Geom::Matrix const &edit_trans, + PathManipulator(MultiPathManipulator &mpm, SPPath *path, Geom::Affine const &edit_trans, guint32 outline_color, Glib::ustring lpe_key); ~PathManipulator(); virtual bool event(GdkEvent *); @@ -65,7 +65,6 @@ public: SPPath *item() { return _path; } void selectSubpaths(); - void shiftSelection(int dir); void invertSelectionInSubpaths(); void insertNodes(); @@ -86,7 +85,7 @@ public: void showPathDirection(bool show); void setLiveOutline(bool set); void setLiveObjects(bool set); - void setControlsTransform(Geom::Matrix const &); + void setControlsTransform(Geom::Affine const &); void hideDragPoint(); MultiPathManipulator &mpm() { return _multi_path_manipulator; } @@ -94,6 +93,9 @@ public: NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected, bool search_unselected, bool closest); + // this is necessary for Tab-selection in MultiPathManipulator + SubpathList &subpathList() { return _subpaths; } + static bool is_item_type(void *item); private: typedef NodeList Subpath; @@ -132,9 +134,9 @@ private: SPCanvasItem *_outline; CurveDragPoint *_dragpoint; // an invisible control point hoverng over curve PathManipulatorObserver *_observer; - Geom::Matrix _d2i_transform; ///< desktop-to-item transform - Geom::Matrix _i2d_transform; ///< item-to-desktop transform, inverse of _d2i_transform - Geom::Matrix _edit_transform; ///< additional transform to apply to editing controls + Geom::Affine _d2i_transform; ///< desktop-to-item transform + Geom::Affine _i2d_transform; ///< item-to-desktop transform, inverse of _d2i_transform + Geom::Affine _edit_transform; ///< additional transform to apply to editing controls unsigned _num_selected; ///< number of selected nodes bool _show_handles; bool _show_outline; diff --git a/src/ui/tool/selector.h b/src/ui/tool/selector.h index e61668d9e..05d72c208 100644 --- a/src/ui/tool/selector.h +++ b/src/ui/tool/selector.h @@ -14,7 +14,6 @@ #include <memory> #include <gdk/gdk.h> #include <2geom/rect.h> -#include "display/display-forward.h" #include "ui/tool/manipulator.h" class SPDesktop; diff --git a/src/ui/tool/shape-record.h b/src/ui/tool/shape-record.h index 893231404..646e6f4f6 100644 --- a/src/ui/tool/shape-record.h +++ b/src/ui/tool/shape-record.h @@ -14,7 +14,7 @@ #include <glibmm/ustring.h> #include <boost/operators.hpp> -#include <2geom/matrix.h> +#include <2geom/affine.h> class SPItem; namespace Inkscape { @@ -32,7 +32,7 @@ struct ShapeRecord : public boost::totally_ordered<ShapeRecord> { SPItem *item; // SP node for the edited shape - Geom::Matrix edit_transform; // how to transform controls - used for clipping paths and masks + Geom::Affine edit_transform; // how to transform controls - used for clipping paths and masks ShapeRole role; Glib::ustring lpe_key; // name of LPE shape param being edited diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp index ef93a3767..26263c26b 100644 --- a/src/ui/tool/transform-handle-set.cpp +++ b/src/ui/tool/transform-handle-set.cpp @@ -18,10 +18,16 @@ #include "desktop-handles.h" #include "display/sodipodi-ctrlrect.h" #include "preferences.h" +#include "snap.h" +#include "snap-candidate.h" +#include "sp-namedview.h" #include "ui/tool/commit-events.h" #include "ui/tool/control-point.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tool/selectable-control-point.h" #include "ui/tool/event-utils.h" #include "ui/tool/transform-handle-set.h" +#include "ui/tool/node-tool.h" // FIXME BRAIN DAMAGE WARNING: this is a global variable in select-context.cpp // It should be moved to a header @@ -88,12 +94,14 @@ public: protected: virtual void startTransform() {} virtual void endTransform() {} - virtual Geom::Matrix computeTransform(Geom::Point const &pos, GdkEventMotion *event) = 0; + virtual Geom::Affine computeTransform(Geom::Point const &pos, GdkEventMotion *event) = 0; virtual CommitEvent getCommitEvent() = 0; - Geom::Matrix _last_transform; + Geom::Affine _last_transform; Geom::Point _origin; TransformHandleSet &_th; + std::vector<Inkscape::SnapCandidatePoint> _snap_points; + private: virtual bool grabbed(GdkEventMotion *) { _origin = position(); @@ -103,19 +111,34 @@ private: _th._setActiveHandle(this); _cset = &invisible_cset; _setState(_state); + + // Collect the snap-candidates, one for each selected node. These will be stored in the _snap_points vector. + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SnapManager &m = desktop->namedview->snap_manager; + InkNodeTool *nt = INK_NODE_TOOL(_desktop->event_context); + ControlPointSelection *selection = nt->_selected_nodes.get(); + + _snap_points = selection->getOriginalPoints(); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/options/snapclosestonly/value", false)) { + m.keepClosestPointOnly(_snap_points, _origin); + } + return false; } virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event) { - Geom::Matrix t = computeTransform(new_pos, event); + Geom::Affine t = computeTransform(new_pos, event); // protect against degeneracies if (t.isSingular()) return; - Geom::Matrix incr = _last_transform.inverse() * t; + Geom::Affine incr = _last_transform.inverse() * t; if (incr.isSingular()) return; _th.signal_transform.emit(incr); _last_transform = t; } virtual void ungrabbed(GdkEventButton *) { + _snap_points.clear(); _th._clearActiveHandle(); _cset = &thandle_cset; _setState(_state); @@ -175,26 +198,66 @@ protected: _sc_center = _th.rotationCenter(); _sc_opposite = _th.bounds().corner(_corner + 2); _last_scale_x = _last_scale_y = 1.0; + InkNodeTool *nt = INK_NODE_TOOL(_desktop->event_context); + ControlPointSelection *selection = nt->_selected_nodes.get(); + selection->setOriginalPoints(); } - virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) { + virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) { Geom::Point scc = held_shift(*event) ? _sc_center : _sc_opposite; Geom::Point vold = _origin - scc, vnew = new_pos - scc; + // avoid exploding the selection if (Geom::are_near(vold[Geom::X], 0) || Geom::are_near(vold[Geom::Y], 0)) return Geom::identity(); double scale[2] = { vnew[Geom::X] / vold[Geom::X], vnew[Geom::Y] / vold[Geom::Y] }; + if (held_alt(*event)) { for (unsigned i = 0; i < 2; ++i) { if (scale[i] >= 1.0) scale[i] = round(scale[i]); else scale[i] = 1.0 / round(1.0 / scale[i]); } - } else if (held_control(*event)) { - scale[0] = scale[1] = std::min(scale[0], scale[1]); + } else { + //SPDesktop *desktop = _th._desktop; // Won't work as _desktop is protected + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SnapManager &m = desktop->namedview->snap_manager; + + // The lines below have been copied from Handle::dragged() in node.cpp, and need to be + // activated if we want to snap to unselected (i.e. stationary) nodes and stationary pieces of paths of the + // path that's currently being edited + /* + std::vector<Inkscape::SnapCandidatePoint> unselected; + typedef ControlPointSelection::Set Set; + Set &nodes = _parent->_selection.allPoints(); + for (Set::iterator i = nodes.begin(); i != nodes.end(); ++i) { + Node *n = static_cast<Node*>(*i); + Inkscape::SnapCandidatePoint p(n->position(), n->_snapSourceType(), n->_snapTargetType()); + unselected.push_back(p); + } + m.setupIgnoreSelection(_desktop, true, &unselected); + */ + + m.setupIgnoreSelection(_desktop); + + Inkscape::SnappedPoint sp; + if (held_control(*event)) { + scale[0] = scale[1] = std::min(scale[0], scale[1]); + sp = m.constrainedSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc); + } else { + sp = m.freeSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc); + } + m.unSetup(); + + if (sp.getSnapped()) { + Geom::Point result = sp.getTransformation(); + scale[0] = result[0]; + scale[1] = result[1]; + } } + _last_scale_x = scale[0]; _last_scale_y = scale[1]; - Geom::Matrix t = Geom::Translate(-scc) + Geom::Affine t = Geom::Translate(-scc) * Geom::Scale(scale[0], scale[1]) * Geom::Translate(scc); return t; @@ -231,7 +294,7 @@ protected: _sc_opposite = Geom::middle_point(b.corner(_side + 2), b.corner(_side + 3)); _last_scale_x = _last_scale_y = 1.0; } - virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) { + virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) { Geom::Point scc = held_shift(*event) ? _sc_center : _sc_opposite; Geom::Point vs; Geom::Dim2 d1 = static_cast<Geom::Dim2>((_side + 1) % 2); @@ -250,7 +313,7 @@ protected: _last_scale_x = vs[Geom::X]; _last_scale_y = vs[Geom::Y]; - Geom::Matrix t = Geom::Translate(-scc) + Geom::Affine t = Geom::Translate(-scc) * Geom::Scale(vs) * Geom::Translate(scc); return t; @@ -288,7 +351,7 @@ protected: _last_angle = 0; } - virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) + virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) { Geom::Point rotc = held_shift(*event) ? _rot_opposite : _rot_center; double angle = Geom::angle_between(_origin - rotc, new_pos - rotc); @@ -296,7 +359,7 @@ protected: angle = snap_angle(angle); } _last_angle = angle; - Geom::Matrix t = Geom::Translate(-rotc) + Geom::Affine t = Geom::Translate(-rotc) * Geom::Rotate(angle) * Geom::Translate(rotc); return t; @@ -362,7 +425,7 @@ protected: _last_horizontal = _side % 2; } - virtual Geom::Matrix computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) + virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) { Geom::Point scc = held_shift(*event) ? _skew_center : _skew_opposite; // d1 and d2 are reversed with respect to ScaleSideHandle @@ -395,12 +458,12 @@ protected: // skew matrix has the from [[1, k],[0, 1]] for horizontal skew // and [[1,0],[k,1]] for vertical skew. - Geom::Matrix skew = Geom::identity(); + Geom::Affine skew = Geom::identity(); // correct the sign of the tangent skew[d2 + 1] = (d1 == Geom::X ? -1.0 : 1.0) * tan(angle); _last_angle = angle; - Geom::Matrix t = Geom::Translate(-scc) + Geom::Affine t = Geom::Translate(-scc) * Geom::Scale(scale) * skew * Geom::Translate(scc); return t; @@ -473,7 +536,23 @@ public: } protected: - + virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event) { + SnapManager &sm = _desktop->namedview->snap_manager; + sm.setup(_desktop); + bool snap = !held_shift(*event) && sm.someSnapperMightSnap(); + if (held_control(*event)) { + // constrain to axes + Geom::Point origin = _last_drag_origin(); + std::vector<Inkscape::Snapper::SnapConstraint> constraints; + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(1, 0))); + constraints.push_back(Inkscape::Snapper::SnapConstraint(origin, Geom::Point(0, 1))); + new_pos = sm.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(new_pos, + SNAPSOURCE_ROTATION_CENTER), constraints, held_shift(*event)).getPoint(); + } else if (snap) { + sm.freeSnapReturnByRef(new_pos, SNAPSOURCE_ROTATION_CENTER); + } + sm.unSetup(); + } virtual Glib::ustring _getTip(unsigned /*state*/) { return C_("Transform handle tip", "<b>Rotation center</b>: drag to change the origin of transforms"); @@ -566,7 +645,7 @@ bool TransformHandleSet::event(GdkEvent*) return false; } -void TransformHandleSet::_emitTransform(Geom::Matrix const &t) +void TransformHandleSet::_emitTransform(Geom::Affine const &t) { signal_transform.emit(t); _center->transform(t); diff --git a/src/ui/tool/transform-handle-set.h b/src/ui/tool/transform-handle-set.h index 2a4df8751..0557b1278 100644 --- a/src/ui/tool/transform-handle-set.h +++ b/src/ui/tool/transform-handle-set.h @@ -14,12 +14,11 @@ #include <memory> #include <gdk/gdk.h> #include <2geom/forward.h> -#include "display/display-forward.h" #include "ui/tool/commit-events.h" #include "ui/tool/manipulator.h" class SPDesktop; -class CtrlRect; // this is not present in display-forward.h! +class CtrlRect; namespace Inkscape { namespace UI { @@ -51,10 +50,10 @@ public: bool transforming() { return _in_transform; } ControlPoint &rotationCenter(); - sigc::signal<void, Geom::Matrix const &> signal_transform; + sigc::signal<void, Geom::Affine const &> signal_transform; sigc::signal<void, CommitEvent> signal_commit; private: - void _emitTransform(Geom::Matrix const &); + void _emitTransform(Geom::Affine const &); void _setActiveHandle(ControlPoint *h); void _clearActiveHandle(); void _updateVisibility(bool v); diff --git a/src/ui/view/view.h b/src/ui/view/view.h index 882746cea..e6853555f 100644 --- a/src/ui/view/view.h +++ b/src/ui/view/view.h @@ -15,6 +15,7 @@ */ #include <gdk/gdktypes.h> +#include <stddef.h> #include <sigc++/connection.h> #include "message.h" #include "gc-managed.h" diff --git a/src/ui/widget/attr-widget.h b/src/ui/widget/attr-widget.h index b9924a2ef..7b9c35ab7 100644 --- a/src/ui/widget/attr-widget.h +++ b/src/ui/widget/attr-widget.h @@ -149,7 +149,7 @@ protected: { const gchar* name = (const gchar*)sp_attribute_name(_attr); if(name && o) { - const gchar* val = SP_OBJECT_REPR(o)->attribute(name); + const gchar* val = o->getRepr()->attribute(name); return val; } return 0; diff --git a/src/ui/widget/color-picker.h b/src/ui/widget/color-picker.h index 2c246aaa3..346ce5121 100644 --- a/src/ui/widget/color-picker.h +++ b/src/ui/widget/color-picker.h @@ -13,6 +13,7 @@ #ifndef __COLOR_PICKER_H__ #define __COLOR_PICKER_H__ +#include <stddef.h> #include <sigc++/sigc++.h> #include <gtkmm/button.h> #include <gtkmm/dialog.h> diff --git a/src/ui/widget/filter-effect-chooser.cpp b/src/ui/widget/filter-effect-chooser.cpp index 309730600..37202c8b4 100644 --- a/src/ui/widget/filter-effect-chooser.cpp +++ b/src/ui/widget/filter-effect-chooser.cpp @@ -22,8 +22,8 @@ namespace UI { namespace Widget { SimpleFilterModifier::SimpleFilterModifier(int flags) - : _lb_blend(_("_Blend mode:")), - _lb_blur(_("Blur:"), Gtk::ALIGN_LEFT), + : _lb_blend(_("Blend mode:")), + _lb_blur(_("_Blur:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, true), _blend(BlendModeConverter, SP_ATTR_INVALID, false), _blur(0, 0, 100, 1, 0.01, 1) { diff --git a/src/ui/widget/layer-selector.cpp b/src/ui/widget/layer-selector.cpp index 6d1da0af0..ba4629c82 100644 --- a/src/ui/widget/layer-selector.cpp +++ b/src/ui/widget/layer-selector.cpp @@ -236,6 +236,8 @@ void LayerSelector::_selectLayer(SPObject *layer) { using Inkscape::Util::reverse_list; _selection_changed_connection.block(); + _visibility_toggled_connection.block(); + _lock_toggled_connection.block(); while (!_layer_model->children().empty()) { Gtk::ListStore::iterator first_row(_layer_model->children().begin()); @@ -285,6 +287,8 @@ void LayerSelector::_selectLayer(SPObject *layer) { _lock_toggle.set_active(( SP_IS_ITEM(layer) ? SP_ITEM(layer)->isLocked() : false )); } + _lock_toggled_connection.unblock(); + _visibility_toggled_connection.unblock(); _selection_changed_connection.unblock(); } @@ -460,7 +464,7 @@ void LayerSelector::_buildEntry(unsigned depth, SPObject &object) { ); SPObject *layer=_desktop->currentLayer(); - if ( &object == layer || &object == SP_OBJECT_PARENT(layer) ) { + if ( (&object == layer) || (&object == layer->parent) ) { callbacks->update_list = sigc::bind( sigc::mem_fun(*this, &LayerSelector::_protectUpdate), sigc::bind( @@ -498,12 +502,12 @@ void LayerSelector::_buildEntry(unsigned depth, SPObject &object) { sp_object_ref(&object, NULL); row->set_value(_model_columns.object, &object); - Inkscape::GC::anchor(SP_OBJECT_REPR(&object)); - row->set_value(_model_columns.repr, SP_OBJECT_REPR(&object)); + Inkscape::GC::anchor(object.getRepr()); + row->set_value(_model_columns.repr, object.getRepr()); row->set_value(_model_columns.callbacks, reinterpret_cast<void *>(callbacks)); - sp_repr_add_listener(SP_OBJECT_REPR(&object), vector, callbacks); + sp_repr_add_listener(object.getRepr(), vector, callbacks); } /** Removes a row from the _model_columns object, disconnecting listeners @@ -536,13 +540,13 @@ void LayerSelector::_prepareLabelRenderer( // (or before one has been selected) something appears to // "invent" an iterator with null data and try to render it; // where does it come from, and how can we avoid it? - if ( object && SP_OBJECT_REPR(object) ) { + if ( object && object->getRepr() ) { SPObject *layer=( _desktop ? _desktop->currentLayer() : NULL ); SPObject *root=( _desktop ? _desktop->currentRoot() : NULL ); - bool isancestor = !( (layer && (SP_OBJECT_PARENT(object) == SP_OBJECT_PARENT(layer))) || ((layer == root) && (SP_OBJECT_PARENT(object) == root))); + bool isancestor = !( (layer && (object->parent == layer->parent)) || ((layer == root) && (object->parent == root))); - bool iscurrent = ( object == layer && object != root ); + bool iscurrent = ( (object == layer) && (object != root) ); gchar *format = g_strdup_printf ( "<span size=\"smaller\" %s><tt>%*s%s</tt>%s%s%s%%s%s%s%s</span>", diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index 1de425da3..06d57c4ac 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -60,7 +60,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _opacity_tag(Glib::ustring(history_prefix) + ":opacity"), _opacity_vbox(false, 0), _opacity_label_box(false, 0), - _opacity_label(_("Opacity (%):"), 0.0, 1.0, true), + _opacity_label(_("_Opacity (%):"), 0.0, 1.0, true), _opacity_adjustment(100.0, 0.0, 100.0, 1.0, 1.0, 0.0), _opacity_hscale(_opacity_adjustment), _opacity_spin_button(_opacity_adjustment, 0.01, 1), @@ -86,6 +86,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _opacity_hscale.set_draw_value(false); _opacity_hscale.set_update_policy(Gtk::UPDATE_DELAYED); _opacity_adjustment.signal_value_changed().connect(sigc::mem_fun(*this, &ObjectCompositeSettings::_opacityValueChanged)); + _opacity_label.set_mnemonic_widget(_opacity_hscale); show_all_children(); @@ -145,7 +146,7 @@ ObjectCompositeSettings::_blendBlurValueChanged() } SPItem * item = SP_ITEM(*i); - SPStyle *style = SP_OBJECT_STYLE(item); + SPStyle *style = item->style; g_assert(style != NULL); if (blendmode != "normal") { diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp index f7cb6f145..f306b9eea 100644 --- a/src/ui/widget/page-sizer.cpp +++ b/src/ui/widget/page-sizer.cpp @@ -422,7 +422,7 @@ PageSizer::setDim (double w, double h, bool changeList) // The origin for the user is in the lower left corner; this point should remain stationary when // changing the page size. The SVG's origin however is in the upper left corner, so we must compensate for this Geom::Translate const vert_offset(Geom::Point(0, (old_height - h))); - SP_GROUP(SP_ROOT(doc->root))->translateChildItems(vert_offset); + SP_GROUP(SP_ROOT(doc->root))->translateChildItems(vert_offset); DocumentUndo::done(doc, SP_VERB_NONE, _("Set page size")); } @@ -538,8 +538,8 @@ PageSizer::fire_fit_canvas_to_selection_or_drawing() SPNamedView *nv; Inkscape::XML::Node *nv_repr; if ((doc = sp_desktop_document(SP_ACTIVE_DESKTOP)) - && (nv = sp_document_namedview(doc, 0)) - && (nv_repr = SP_OBJECT_REPR(nv))) { + && (nv = sp_document_namedview(doc, 0)) + && (nv_repr = nv->getRepr())) { sp_repr_set_svg_double(nv_repr, "fit-margin-top", _marginTop.getValue()); sp_repr_set_svg_double(nv_repr, "fit-margin-left", _marginLeft.getValue()); sp_repr_set_svg_double(nv_repr, "fit-margin-right", _marginRight.getValue()); diff --git a/src/ui/widget/page-sizer.h b/src/ui/widget/page-sizer.h index ba6c8dd13..2072aeccd 100644 --- a/src/ui/widget/page-sizer.h +++ b/src/ui/widget/page-sizer.h @@ -13,6 +13,7 @@ #define INKSCAPE_UI_WIDGET_PAGE_SIZER__H #include <gtkmm.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include "helper/units.h" diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index 4816304db..afcaa338e 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -14,6 +14,10 @@ # include <config.h> #endif +#ifdef WIN32 +#include <windows.h> +#endif + #include <gtkmm/frame.h> #include <gtkmm/alignment.h> #include <gtkmm/box.h> @@ -22,7 +26,9 @@ #include "ui/widget/preferences-widget.h" #include "verbs.h" #include "selcue.h" +#include "io/sys.h" #include <iostream> +#include "desktop.h" #include "enums.h" #include "inkscape.h" #include "desktop-handles.h" @@ -30,6 +36,7 @@ #include "style.h" #include "selection.h" #include "selection-chemistry.h" +#include "ui/dialog/filedialog.h" #include "xml/repr.h" using namespace Inkscape::UI::Widget; @@ -618,6 +625,137 @@ void PrefEntryButtonHBox::onRelatedButtonClickedCallback() } } +void PrefEntryFileButtonHBox::init(Glib::ustring const &prefs_path, + bool visibility) +{ + _prefs_path = prefs_path; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + relatedEntry = new Gtk::Entry(); + relatedEntry->set_invisible_char('*'); + relatedEntry->set_visibility(visibility); + relatedEntry->set_text(prefs->getString(_prefs_path)); + + relatedButton = new Gtk::Button(); + Gtk::HBox* pixlabel = new Gtk::HBox(false, 3); + Gtk::Image *im = new Gtk::Image(Gtk::StockID(Gtk::Stock::INDEX), + Gtk::ICON_SIZE_BUTTON); + pixlabel->pack_start(*im); + Gtk::Label *l = new Gtk::Label(); + l->set_markup_with_mnemonic(_("_Browse...")); + pixlabel->pack_start(*l); + relatedButton->add(*pixlabel); + + this->pack_end(*relatedButton, false, false, 4); + this->pack_start(*relatedEntry, true, true, 0); + + relatedButton->signal_clicked().connect( + sigc::mem_fun(*this, &PrefEntryFileButtonHBox::onRelatedButtonClickedCallback)); + relatedEntry->signal_changed().connect( + sigc::mem_fun(*this, &PrefEntryFileButtonHBox::onRelatedEntryChangedCallback)); +} + +void PrefEntryFileButtonHBox::onRelatedEntryChangedCallback() +{ + if (this->is_visible()) //only take action if user changed value + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(_prefs_path, relatedEntry->get_text()); + } +} + +static Inkscape::UI::Dialog::FileOpenDialog * selectPrefsFileInstance = NULL; + +void PrefEntryFileButtonHBox::onRelatedButtonClickedCallback() +{ + if (this->is_visible()) //only take action if user changed value + { + //# Get the current directory for finding files + static Glib::ustring open_path; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + + Glib::ustring attr = prefs->getString(_prefs_path); + if (!attr.empty()) open_path = attr; + + //# Test if the open_path directory exists + if (!Inkscape::IO::file_test(open_path.c_str(), + (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) + open_path = ""; + +#ifdef WIN32 + //# If no open path, default to our win32 documents folder + if (open_path.empty()) + { + // The path to the My Documents folder is read from the + // value "HKEY_CURRENT_USER\Software\Windows\CurrentVersion\Explorer\Shell Folders\Personal" + HKEY key = NULL; + if(RegOpenKeyExA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", + 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) + { + WCHAR utf16path[_MAX_PATH]; + DWORD value_type; + DWORD data_size = sizeof(utf16path); + if(RegQueryValueExW(key, L"Personal", NULL, &value_type, + (BYTE*)utf16path, &data_size) == ERROR_SUCCESS) + { + g_assert(value_type == REG_SZ); + gchar *utf8path = g_utf16_to_utf8( + (const gunichar2*)utf16path, -1, NULL, NULL, NULL); + if(utf8path) + { + open_path = Glib::ustring(utf8path); + g_free(utf8path); + } + } + } + } +#endif + + //# If no open path, default to our home directory + if (open_path.empty()) + { + open_path = g_get_home_dir(); + open_path.append(G_DIR_SEPARATOR_S); + } + + //# Create a dialog + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (!selectPrefsFileInstance) { + selectPrefsFileInstance = + Inkscape::UI::Dialog::FileOpenDialog::create( + *desktop->getToplevel(), + open_path, + Inkscape::UI::Dialog::EXE_TYPES, + _("Select a bitmap editor")); + } + + //# Show the dialog + bool const success = selectPrefsFileInstance->show(); + + if (!success) { + return; + } + + //# User selected something. Get name and type + Glib::ustring fileName = selectPrefsFileInstance->getFilename(); + + if (!fileName.empty()) + { + Glib::ustring newFileName = Glib::filename_to_utf8(fileName); + + if ( newFileName.size() > 0) + open_path = newFileName; + else + g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" ); + + prefs->setString(_prefs_path, open_path); + } + + relatedEntry->set_text(fileName); + } +} void PrefFileButton::init(Glib::ustring const &prefs_path) { diff --git a/src/ui/widget/preferences-widget.h b/src/ui/widget/preferences-widget.h index 6c4533451..6c7f9ce4a 100644 --- a/src/ui/widget/preferences-widget.h +++ b/src/ui/widget/preferences-widget.h @@ -26,6 +26,7 @@ #include <gtkmm/drawingarea.h> #include <gtkmm/frame.h> #include <gtkmm/filechooserbutton.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include <glibmm/i18n.h> @@ -176,6 +177,19 @@ protected: void onRelatedButtonClickedCallback(); }; +class PrefEntryFileButtonHBox : public Gtk::HBox +{ +public: + void init(Glib::ustring const &prefs_path, + bool mask); +protected: + Glib::ustring _prefs_path; + Gtk::Button *relatedButton; + Gtk::Entry *relatedEntry; + void onRelatedEntryChangedCallback(); + void onRelatedButtonClickedCallback(); +}; + class PrefFileButton : public Gtk::FileChooserButton { public: diff --git a/src/ui/widget/registered-widget.cpp b/src/ui/widget/registered-widget.cpp index 04bd27285..c2580013a 100644 --- a/src/ui/widget/registered-widget.cpp +++ b/src/ui/widget/registered-widget.cpp @@ -344,7 +344,7 @@ RegisteredColorPicker::on_changed (guint32 rgba) SPDesktop *dt = SP_ACTIVE_DESKTOP; if (!dt) return; - local_repr = SP_OBJECT_REPR (sp_desktop_namedview(dt)); + local_repr = sp_desktop_namedview(dt)->getRepr(); local_doc = sp_desktop_document(dt); } @@ -553,7 +553,7 @@ RegisteredTransformedPoint::setValue(Geom::Point const & p) } void -RegisteredTransformedPoint::setTransform(Geom::Matrix const & canvas_to_svg) +RegisteredTransformedPoint::setTransform(Geom::Affine const & canvas_to_svg) { // check if matrix is singular / has inverse if ( ! canvas_to_svg.isSingular() ) { diff --git a/src/ui/widget/registered-widget.h b/src/ui/widget/registered-widget.h index efb5eb70e..560c63dd4 100644 --- a/src/ui/widget/registered-widget.h +++ b/src/ui/widget/registered-widget.h @@ -18,7 +18,7 @@ #include <gtkmm/adjustment.h> #include <gtkmm/tooltips.h> #include <gtkmm/togglebutton.h> -#include <2geom/matrix.h> +#include <2geom/affine.h> #include "xml/node.h" #include "registry.h" @@ -101,7 +101,7 @@ protected: if (!local_repr) { // no repr specified, use active desktop's namedview's repr SPDesktop* dt = SP_ACTIVE_DESKTOP; - local_repr = SP_OBJECT_REPR (sp_desktop_namedview(dt)); + local_repr = reinterpret_cast<SPObject *>(sp_desktop_namedview(dt))->getRepr(); local_doc = sp_desktop_document(dt); } @@ -326,14 +326,14 @@ public: // redefine setValue, because transform must be applied void setValue(Geom::Point const & p); - void setTransform(Geom::Matrix const & canvas_to_svg); + void setTransform(Geom::Affine const & canvas_to_svg); protected: sigc::connection _value_x_changed_connection; sigc::connection _value_y_changed_connection; void on_value_changed(); - Geom::Matrix to_svg; + Geom::Affine to_svg; }; diff --git a/src/ui/widget/ruler.cpp b/src/ui/widget/ruler.cpp index 107f4e8c6..a220a54ad 100644 --- a/src/ui/widget/ruler.cpp +++ b/src/ui/widget/ruler.cpp @@ -26,6 +26,7 @@ #include "ui/widget/ruler.h" #include "xml/repr.h" +#include "display/sp-canvas.h" #include "display/guideline.h" #include "desktop.h" #include "desktop-handles.h" @@ -101,7 +102,7 @@ Ruler::on_button_press_event(GdkEventButton *evb) { g_assert(_dt); Geom::Point const &event_dt = get_event_dt(); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(_dt->namedview); + Inkscape::XML::Node *repr = _dt->namedview->getRepr(); if (evb->button == 1) { _dragging = true; @@ -152,7 +153,7 @@ Ruler::on_button_release_event(GdkEventButton *evb) repr->setAttribute("orientation", _horiz_f ? "horizontal" : "vertical"); double const guide_pos_dt = event_dt[ _horiz_f ? Geom::Y : Geom::X ]; sp_repr_set_svg_double(repr, "position", guide_pos_dt); - SP_OBJECT_REPR(_dt->namedview)->appendChild(repr); + _dt->namedview->getRepr()->appendChild(repr); Inkscape::GC::release(repr); DocumentUndo::done(sp_desktop_document(_dt), SP_VERB_NONE, /* TODO: annotate */ "ruler.cpp:157"); diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp index e7d8ac5a3..50476dc65 100644 --- a/src/ui/widget/selected-style.cpp +++ b/src/ui/widget/selected-style.cpp @@ -950,7 +950,7 @@ SelectedStyle::update() if (paint->set && paint->isPaintserver()) { SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query); if ( server ) { - Inkscape::XML::Node *srepr = SP_OBJECT_REPR(server); + Inkscape::XML::Node *srepr = server->getRepr(); _paintserver_id[i] += "url(#"; _paintserver_id[i] += srepr->attribute("id"); _paintserver_id[i] += ")"; diff --git a/src/ui/widget/selected-style.h b/src/ui/widget/selected-style.h index 0229364c7..e74d5b1ae 100644 --- a/src/ui/widget/selected-style.h +++ b/src/ui/widget/selected-style.h @@ -23,6 +23,7 @@ #include <gtkmm/adjustment.h> #include <gtkmm/spinbutton.h> +#include <stddef.h> #include <sigc++/sigc++.h> #include <glibmm/i18n.h> diff --git a/src/ui/widget/style-subject.h b/src/ui/widget/style-subject.h index 77e4c4846..6d5c96350 100644 --- a/src/ui/widget/style-subject.h +++ b/src/ui/widget/style-subject.h @@ -14,6 +14,7 @@ #include "libnr/nr-rect.h" #include <2geom/rect.h> #include "sp-item.h" +#include <stddef.h> #include <sigc++/sigc++.h> class SPDesktop; diff --git a/src/ui/widget/svg-canvas.cpp b/src/ui/widget/svg-canvas.cpp index 64657296d..7d37ec355 100644 --- a/src/ui/widget/svg-canvas.cpp +++ b/src/ui/widget/svg-canvas.cpp @@ -12,8 +12,8 @@ #include <gtkmm/widget.h> #include "desktop.h" #include "desktop-events.h" +#include "display/sp-canvas.h" #include "display/canvas-arena.h" -#include "display/display-forward.h" #include "ui/widget/svg-canvas.h" namespace Inkscape { diff --git a/src/ui/widget/tolerance-slider.cpp b/src/ui/widget/tolerance-slider.cpp index cc179ddbc..51e0a262f 100644 --- a/src/ui/widget/tolerance-slider.cpp +++ b/src/ui/widget/tolerance-slider.cpp @@ -189,7 +189,7 @@ ToleranceSlider::update (double val) SPDocument *doc = sp_desktop_document(dt); bool saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); - Inkscape::XML::Node *repr = SP_OBJECT_REPR (sp_desktop_namedview(dt)); + Inkscape::XML::Node *repr = sp_desktop_namedview(dt)->getRepr(); repr->setAttribute(_key.c_str(), os.str().c_str()); DocumentUndo::setUndoSensitive(doc, saved); diff --git a/src/unclump.cpp b/src/unclump.cpp index 1039351a3..d027a6986 100644 --- a/src/unclump.cpp +++ b/src/unclump.cpp @@ -287,7 +287,7 @@ unclump_push (SPItem *from, SPItem *what, double dist) Geom::Point p = unclump_center (from); Geom::Point by = dist * Geom::unit_vector (- (p - it)); - Geom::Matrix move = Geom::Translate (by); + Geom::Affine move = Geom::Translate (by); std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(what->getId()); if ( i != c_cache.end() ) { @@ -297,7 +297,7 @@ unclump_push (SPItem *from, SPItem *what, double dist) //g_print ("push %s at %g,%g from %g,%g by %g,%g, dist %g\n", what->getId(), it[Geom::X],it[Geom::Y], p[Geom::X],p[Geom::Y], by[Geom::X],by[Geom::Y], dist); what->set_i2d_affine(what->i2d_affine() * move); - what->doWriteTransform(SP_OBJECT_REPR(what), what->transform, NULL); + what->doWriteTransform(what->getRepr(), what->transform, NULL); } /** @@ -310,7 +310,7 @@ unclump_pull (SPItem *to, SPItem *what, double dist) Geom::Point p = unclump_center (to); Geom::Point by = dist * Geom::unit_vector (p - it); - Geom::Matrix move = Geom::Translate (by); + Geom::Affine move = Geom::Translate (by); std::map<const gchar *, Geom::Point>::iterator i = c_cache.find(what->getId()); if ( i != c_cache.end() ) { @@ -320,7 +320,7 @@ unclump_pull (SPItem *to, SPItem *what, double dist) //g_print ("pull %s at %g,%g to %g,%g by %g,%g, dist %g\n", what->getId(), it[Geom::X],it[Geom::Y], p[Geom::X],p[Geom::Y], by[Geom::X],by[Geom::Y], dist); what->set_i2d_affine(what->i2d_affine() * move); - what->doWriteTransform(SP_OBJECT_REPR(what), what->transform, NULL); + what->doWriteTransform(what->getRepr(), what->transform, NULL); } diff --git a/src/uri-references.cpp b/src/uri-references.cpp index d979fe292..2c09695d4 100644 --- a/src/uri-references.cpp +++ b/src/uri-references.cpp @@ -47,7 +47,7 @@ void URIReference::attach(const URI &uri) throw(BadURIException) { SPDocument *document; if (_owner) { - document = SP_OBJECT_DOCUMENT(_owner); + document = _owner->document; } else if (_owner_document) { document = _owner_document; } else { diff --git a/src/uri-references.h b/src/uri-references.h index c0f9190b1..938dd4cd8 100644 --- a/src/uri-references.h +++ b/src/uri-references.h @@ -14,6 +14,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <stddef.h> #include <sigc++/connection.h> #include <sigc++/trackable.h> diff --git a/src/util/Makefile_insert b/src/util/Makefile_insert index d2f005531..deff951d4 100644 --- a/src/util/Makefile_insert +++ b/src/util/Makefile_insert @@ -5,6 +5,8 @@ ink_common_sources += \ util/compose.hpp \ util/copy.h \ util/enums.h \ + util/ege-appear-time-tracker.cpp \ + util/ege-appear-time-tracker.h \ util/ege-tags.h \ util/ege-tags.cpp \ util/filter-list.h \ diff --git a/src/util/ege-appear-time-tracker.cpp b/src/util/ege-appear-time-tracker.cpp new file mode 100644 index 000000000..d53e86742 --- /dev/null +++ b/src/util/ege-appear-time-tracker.cpp @@ -0,0 +1,162 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Appear Time Tracker. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "ege-appear-time-tracker.h" +#include <glib-object.h> +#include <gtk/gtk.h> + + +namespace ege +{ + +namespace { + +void unhookHandler( gulong &id, GtkWidget *obj ) +{ + if ( id ) { + if ( obj ) { + g_signal_handler_disconnect( G_OBJECT(obj), id ); + } + id = 0; + } +} + +} // namespace + + +AppearTimeTracker::AppearTimeTracker(GTimer *timer, GtkWidget *widget, gchar const* name) : + _name(name ? name : ""), + _timer(timer), + _widget(widget), + _topMost(widget), + _autodelete(false), + _mapId(0), + _realizeId(0), + _hierarchyId(0) + +{ + while (_topMost->parent) { + _topMost = _topMost->parent; + } + _mapId = g_signal_connect( G_OBJECT(_topMost), "map-event", G_CALLBACK(mapCB), this ); + _realizeId = g_signal_connect( G_OBJECT(_topMost), "realize", G_CALLBACK(realizeCB), this ); + _hierarchyId = g_signal_connect( G_OBJECT(_widget), "hierarchy-changed", G_CALLBACK(hierarchyCB), this ); +} + +AppearTimeTracker::~AppearTimeTracker() +{ + if ( _timer ) { + g_timer_destroy(_timer); + _timer = 0; + } + + unhookHandler( _mapId, _topMost ); + unhookHandler( _realizeId, _topMost ); + unhookHandler( _hierarchyId, _widget ); +} + +void AppearTimeTracker::stop() { + if (_timer) { + g_timer_stop(_timer); + } +} + +void AppearTimeTracker::setAutodelete(bool autodelete) +{ + if ( autodelete != _autodelete ) { + _autodelete = autodelete; + } +} + +void AppearTimeTracker::report(gchar const* msg) +{ + gulong msCount = 0; + gdouble secs = g_timer_elapsed( _timer, &msCount ); + g_message("Time ended at %2.3f with [%s] on [%s]", secs, msg, _name.c_str()); +} + +void AppearTimeTracker::handleHierarchyChange( GtkWidget * /*prevTop*/ ) +{ + GtkWidget *newTop = _widget; + while (newTop->parent) { + newTop = newTop->parent; + } + + if ( newTop != _topMost ) { + unhookHandler( _mapId, _topMost ); + unhookHandler( _realizeId, _topMost ); + + _topMost = newTop; + _mapId = g_signal_connect( G_OBJECT(_topMost), "map-event", G_CALLBACK(mapCB), this ); + _realizeId = g_signal_connect( G_OBJECT(_topMost), "realize", G_CALLBACK(realizeCB), this ); + } +} + +gboolean AppearTimeTracker::mapCB(GtkWidget * /*widget*/, GdkEvent * /*event*/, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast<AppearTimeTracker*>(userData); + tracker->report("MAP"); + if ( tracker->_autodelete ) { + delete tracker; + } + return FALSE; +} + +void AppearTimeTracker::realizeCB(GtkWidget * /*widget*/, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast<AppearTimeTracker*>(userData); + tracker->report("REALIZE"); +} + +void AppearTimeTracker::hierarchyCB(GtkWidget * /*widget*/, GtkWidget *prevTop, gpointer userData) +{ + AppearTimeTracker *tracker = reinterpret_cast<AppearTimeTracker*>(userData); + tracker->handleHierarchyChange( prevTop ); +} + +} // namespace ege + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/util/ege-appear-time-tracker.h b/src/util/ege-appear-time-tracker.h new file mode 100644 index 000000000..b5ea8b5d2 --- /dev/null +++ b/src/util/ege-appear-time-tracker.h @@ -0,0 +1,89 @@ +#ifndef SEEN_APPEAR_TIME_TRACKER_H +#define SEEN_APPEAR_TIME_TRACKER_H + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Appear Time Tracker. + * + * The Initial Developer of the Original Code is + * Jon A. Cruz. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <glib/gtimer.h> +#include <glibmm/ustring.h> + +typedef union _GdkEvent GdkEvent; +typedef struct _GtkWidget GtkWidget; + +namespace ege +{ + +class AppearTimeTracker { +public: + AppearTimeTracker(GTimer *timer, GtkWidget *widget, gchar const* name); + ~AppearTimeTracker(); + + void stop(); + + bool isAutodelete() const { return _autodelete; } + void setAutodelete(bool autodelete); + +private: + Glib::ustring _name; + GTimer *_timer; + GtkWidget *_widget; + GtkWidget *_topMost; + bool _autodelete; + gulong _mapId; + gulong _realizeId; + gulong _hierarchyId; + + static gboolean mapCB(GtkWidget *widget, GdkEvent *event, gpointer userData); + static void realizeCB(GtkWidget *widget, gpointer userData); + static void hierarchyCB(GtkWidget *widget, GtkWidget *prevTop, gpointer userData); + + void report(gchar const* msg); + void handleHierarchyChange( GtkWidget *prevTop ); +}; + +} // namespace ege + +#endif // SEEN_APPEAR_TIME_TRACKER_H +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/util/forward-pointer-iterator.h b/src/util/forward-pointer-iterator.h index 198225d5f..4d1cfa413 100644 --- a/src/util/forward-pointer-iterator.h +++ b/src/util/forward-pointer-iterator.h @@ -15,6 +15,7 @@ #define SEEN_INKSCAPE_UTIL_FORWARD_POINTER_ITERATOR_H #include <iterator> +#include <cstddef> #include "util/reference.h" namespace Inkscape { diff --git a/src/util/share.h b/src/util/share.h index 4891b9588..6b5e6a4ef 100644 --- a/src/util/share.h +++ b/src/util/share.h @@ -14,6 +14,7 @@ #include "gc-core.h" #include <cstring> +#include <cstddef> namespace Inkscape { namespace Util { diff --git a/src/util/unordered-containers.h b/src/util/unordered-containers.h index 9411657a5..6f738f0ce 100644 --- a/src/util/unordered-containers.h +++ b/src/util/unordered-containers.h @@ -41,6 +41,8 @@ # define INK_UNORDERED_MAP __gnu_cxx::hash_map # define INK_HASH __gnu_cxx::hash +#include <cstddef> + namespace __gnu_cxx { // hash function for pointers // TR1 and Boost have this defined by default, __gnu_cxx doesn't diff --git a/src/verbs.cpp b/src/verbs.cpp index a218e85db..1ad68b792 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1580,7 +1580,7 @@ TextVerb::perform(SPAction *action, void */*data*/, void */*pdata*/) SPDocument *doc = sp_desktop_document(dt); (void)doc; - Inkscape::XML::Node *repr = SP_OBJECT_REPR(dt->namedview); + Inkscape::XML::Node *repr = dt->namedview->getRepr(); (void)repr; } @@ -1595,7 +1595,7 @@ ZoomVerb::perform(SPAction *action, void *data, void */*pdata*/) SPDocument *doc = sp_desktop_document(dt); - Inkscape::XML::Node *repr = SP_OBJECT_REPR(dt->namedview); + Inkscape::XML::Node *repr = dt->namedview->getRepr(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); gdouble zoom_inc = @@ -1715,12 +1715,21 @@ ZoomVerb::perform(SPAction *action, void *data, void */*pdata*/) case SP_VERB_VIEW_MODE_OUTLINE: dt->setDisplayModeOutline(); break; -// case SP_VERB_VIEW_MODE_PRINT_COLORS_PREVIEW: -// dt->setDisplayModePrintColorsPreview(); -// break; case SP_VERB_VIEW_MODE_TOGGLE: dt->displayModeToggle(); break; + case SP_VERB_VIEW_COLOR_MODE_NORMAL: + dt->setDisplayColorModeNormal(); + break; + case SP_VERB_VIEW_COLOR_MODE_GRAYSCALE: + dt->setDisplayColorModeGrayscale(); + break; +// case SP_VERB_VIEW_COLOR_MODE_PRINT_COLORS_PREVIEW: +// dt->setDisplayColorModePrintColorsPreview(); +// break; + case SP_VERB_VIEW_COLOR_MODE_TOGGLE: + dt->displayColorModeToggle(); + break; case SP_VERB_VIEW_CMS_TOGGLE: dt->toggleColorProfAdjust(); break; @@ -2414,7 +2423,7 @@ Verb *Verb::_base_verbs[] = { // Advanced tutorial for more info new SelectionVerb(SP_VERB_SELECTION_BREAK_APART, "SelectionBreakApart", N_("Break _Apart"), N_("Break selected paths into subpaths"), INKSCAPE_ICON_PATH_BREAK_APART), - new SelectionVerb(SP_VERB_SELECTION_GRIDTILE, "DialogGridArrange", N_("Rows and Columns..."), + new SelectionVerb(SP_VERB_SELECTION_GRIDTILE, "DialogGridArrange", N_("Ro_ws and Columns..."), N_("Arrange selected objects in a table"), INKSCAPE_ICON_DIALOG_ROWS_AND_COLUMNS), /* Layer */ new LayerVerb(SP_VERB_LAYER_NEW, "LayerNew", N_("_Add Layer..."), @@ -2437,7 +2446,7 @@ Verb *Verb::_base_verbs[] = { N_("Raise the current layer"), INKSCAPE_ICON_LAYER_RAISE), new LayerVerb(SP_VERB_LAYER_LOWER, "LayerLower", N_("_Lower Layer"), N_("Lower the current layer"), INKSCAPE_ICON_LAYER_LOWER), - new LayerVerb(SP_VERB_LAYER_DUPLICATE, "LayerDuplicate", N_("Duplicate Current Layer"), + new LayerVerb(SP_VERB_LAYER_DUPLICATE, "LayerDuplicate", N_("D_uplicate Current Layer"), N_("Duplicate an existing layer"), NULL), new LayerVerb(SP_VERB_LAYER_DELETE, "LayerDelete", N_("_Delete Current Layer"), N_("Delete the current layer"), INKSCAPE_ICON_LAYER_DELETE), @@ -2602,10 +2611,16 @@ Verb *Verb::_base_verbs[] = { N_("Switch to normal display without filters"), NULL), new ZoomVerb(SP_VERB_VIEW_MODE_OUTLINE, "ViewModeOutline", N_("_Outline"), N_("Switch to outline (wireframe) display mode"), NULL), -// new ZoomVerb(SP_VERB_VIEW_MODE_PRINT_COLORS_PREVIEW, "ViewModePrintColorsPreview", N_("_Print Colors Preview"), -// N_("Switch to print colors preview mode"), NULL), new ZoomVerb(SP_VERB_VIEW_MODE_TOGGLE, "ViewModeToggle", N_("_Toggle"), N_("Toggle between normal and outline display modes"), NULL), + new ZoomVerb(SP_VERB_VIEW_COLOR_MODE_NORMAL, "ViewColorModeNormal", N_("_Normal"), + N_("Switch to normal color display mode"), NULL), + new ZoomVerb(SP_VERB_VIEW_COLOR_MODE_GRAYSCALE, "ViewColorModeGrayscale", N_("_Grayscale"), + N_("Switch to grayscale display mode"), NULL), +// new ZoomVerb(SP_VERB_VIEW_COLOR_MODE_PRINT_COLORS_PREVIEW, "ViewColorModePrintColorsPreview", N_("_Print Colors Preview"), +// N_("Switch to print colors preview mode"), NULL), + new ZoomVerb(SP_VERB_VIEW_COLOR_MODE_TOGGLE, "ViewColorModeToggle", N_("_Toggle"), + N_("Toggle between normal and grayscale color display modes"), NULL), new ZoomVerb(SP_VERB_VIEW_CMS_TOGGLE, "ViewCmsToggle", N_("Color-managed view"), N_("Toggle color-managed display for this document window"), INKSCAPE_ICON_COLOR_MANAGEMENT), @@ -2673,7 +2688,7 @@ Verb *Verb::_base_verbs[] = { N_("Query information about extensions"), NULL), new DialogVerb(SP_VERB_DIALOG_LAYERS, "DialogLayers", N_("Layer_s..."), N_("View Layers"), INKSCAPE_ICON_DIALOG_LAYERS), - new DialogVerb(SP_VERB_DIALOG_LIVE_PATH_EFFECT, "DialogLivePathEffect", N_("Path Effect Editor..."), + new DialogVerb(SP_VERB_DIALOG_LIVE_PATH_EFFECT, "DialogLivePathEffect", N_("Path E_ffect Editor..."), N_("Manage, edit, and apply path effects"), NULL), new DialogVerb(SP_VERB_DIALOG_FILTER_EFFECTS, "DialogFilterEffects", N_("Filter Editor..."), N_("Manage, edit, and apply SVG filters"), NULL), diff --git a/src/verbs.h b/src/verbs.h index f118014d2..0c781f0b6 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -214,8 +214,11 @@ enum { SP_VERB_VIEW_MODE_NORMAL, SP_VERB_VIEW_MODE_NO_FILTERS, SP_VERB_VIEW_MODE_OUTLINE, -// SP_VERB_VIEW_MODE_PRINT_COLORS_PREVIEW, SP_VERB_VIEW_MODE_TOGGLE, + SP_VERB_VIEW_COLOR_MODE_NORMAL, + SP_VERB_VIEW_COLOR_MODE_GRAYSCALE, +// SP_VERB_VIEW_COLOR_MODE_PRINT_COLORS_PREVIEW, + SP_VERB_VIEW_COLOR_MODE_TOGGLE, SP_VERB_VIEW_CMS_TOGGLE, SP_VERB_VIEW_ICON_PREVIEW, SP_VERB_ZOOM_PAGE, diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 7a3e337de..63fdc5930 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -33,6 +33,7 @@ #include "desktop-events.h" #include "desktop-handles.h" #include "desktop-widget.h" +#include "display/sp-canvas.h" #include "display/canvas-arena.h" #include "display/nr-arena.h" #include "document.h" @@ -56,6 +57,7 @@ #include "ui/widget/layer-selector.h" #include "ui/widget/selected-style.h" #include "ui/uxmanager.h" +#include "util/ege-appear-time-tracker.h" // We're in the "widgets" directory, so no need to explicitly prefix these: #include "button.h" @@ -73,6 +75,7 @@ using Inkscape::round; using Inkscape::UnitTracker; using Inkscape::UI::UXManager; using Inkscape::UI::ToolboxFactory; +using ege::AppearTimeTracker; #ifdef WITH_INKBOARD #endif @@ -243,6 +246,8 @@ SPDesktopWidget::window_get_pointer() return Geom::Point(x,y); } +static GTimer *overallTimer = 0; + /** * Registers SPDesktopWidget class and returns its type number. */ @@ -263,6 +268,8 @@ GType SPDesktopWidget::getType(void) 0 // value_table }; type = g_type_register_static(SP_TYPE_VIEW_WIDGET, "SPDesktopWidget", &info, static_cast<GTypeFlags>(0)); + // Begin a timer to watch for the first desktop to appear on-screen + overallTimer = g_timer_new(); } return type; } @@ -564,6 +571,18 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) gtk_widget_show_all (dtw->vbox); gtk_widget_grab_focus (GTK_WIDGET(dtw->canvas)); + + // If this is the first desktop created, report the time it takes to show up + if ( overallTimer ) { + if ( prefs->getBool("/dialogs/debug/trackAppear", false) ) { + // Time tracker takes ownership of the timer. + AppearTimeTracker *tracker = new AppearTimeTracker(overallTimer, GTK_WIDGET(dtw), "first SPDesktopWidget"); + tracker->setAutodelete(true); + } else { + g_timer_destroy(overallTimer); + } + overallTimer = 0; + } } /** @@ -619,25 +638,37 @@ SPDesktopWidget::updateTitle(gchar const* uri) ? uri : g_basename(uri) ); GString *name = g_string_new (""); + + gchar const *grayscalename = "(grayscale) "; + gchar const *grayscalenamecomma = ", grayscale"; + gchar const *printcolorsname = "(print colors preview) "; + gchar const *printcolorsnamecomma = ", print colors preview"; + gchar const *colormodename = ""; + gchar const *colormodenamecomma = ""; + + if (this->desktop->getColorMode() == Inkscape::COLORRENDERMODE_GRAYSCALE) { + colormodename = grayscalename; + colormodenamecomma = grayscalenamecomma; + } else if (this->desktop->getColorMode() == Inkscape::COLORRENDERMODE_PRINT_COLORS_PREVIEW) { + colormodename = printcolorsname; + colormodenamecomma = printcolorsnamecomma; + } + if (this->desktop->number > 1) { if (this->desktop->getMode() == Inkscape::RENDERMODE_OUTLINE) { - g_string_printf (name, _("%s: %d (outline) - Inkscape"), fname, this->desktop->number); + g_string_printf (name, _("%s: %d (outline%s) - Inkscape"), fname, this->desktop->number, colormodenamecomma); } else if (this->desktop->getMode() == Inkscape::RENDERMODE_NO_FILTERS) { - g_string_printf (name, _("%s: %d (no filters) - Inkscape"), fname, this->desktop->number); - } else if (this->desktop->getMode() == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW) { - g_string_printf (name, _("%s: %d (print colors preview) - Inkscape"), fname, this->desktop->number); + g_string_printf (name, _("%s: %d (no filters%s) - Inkscape"), fname, this->desktop->number, colormodenamecomma); } else { - g_string_printf (name, _("%s: %d - Inkscape"), fname, this->desktop->number); + g_string_printf (name, _("%s: %d %s- Inkscape"), fname, this->desktop->number, colormodename); } } else { if (this->desktop->getMode() == Inkscape::RENDERMODE_OUTLINE) { - g_string_printf (name, _("%s (outline) - Inkscape"), fname); + g_string_printf (name, _("%s (outline%s) - Inkscape"), fname, colormodenamecomma); } else if (this->desktop->getMode() == Inkscape::RENDERMODE_NO_FILTERS) { - g_string_printf (name, _("%s (no filters) - Inkscape"), fname); - } else if (this->desktop->getMode() == Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW) { - g_string_printf (name, _("%s (print colors preview) - Inkscape"), fname); + g_string_printf (name, _("%s (no filters%s) - Inkscape"), fname, colormodenamecomma); } else { - g_string_printf (name, _("%s - Inkscape"), fname); + g_string_printf (name, _("%s %s- Inkscape"), fname, colormodename); } } window->set_title (name->str); @@ -912,10 +943,9 @@ SPDesktopWidget::shutdown() GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, - _("<span weight=\"bold\" size=\"larger\">The file \"%s\" was saved with a format (%s) that may cause data loss!</span>\n\n" + _("<span weight=\"bold\" size=\"larger\">The file \"%s\" was saved with a format that may cause data loss!</span>\n\n" "Do you want to save this file as Inkscape SVG?"), - doc->getName() ? doc->getName() : "Unnamed", - SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE); + doc->getName() ? doc->getName() : "Unnamed"); // fix for bug 1767940: GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(GTK_MESSAGE_DIALOG(dialog)->label), GTK_CAN_FOCUS); diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index 4edd434af..0102897e5 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -15,7 +15,6 @@ #include <gtk/gtktooltips.h> #include <gtk/gtkwindow.h> -#include "display/display-forward.h" #include "libnr/nr-point.h" #include "forward.h" #include "sp-object.h" @@ -23,10 +22,12 @@ #include "ui/view/view-widget.h" #include "ui/view/edit-widget-interface.h" +#include <stddef.h> #include <sigc++/connection.h> // forward declaration typedef struct _EgeColorProfTracker EgeColorProfTracker; +struct SPCanvas; #define SP_TYPE_DESKTOP_WIDGET SPDesktopWidget::getType() diff --git a/src/widgets/gradient-image.h b/src/widgets/gradient-image.h index 3ddd14e35..e098beab4 100644 --- a/src/widgets/gradient-image.h +++ b/src/widgets/gradient-image.h @@ -18,6 +18,7 @@ class SPGradient; #include <glib.h> +#include <stddef.h> #include <sigc++/connection.h> #define SP_TYPE_GRADIENT_IMAGE (sp_gradient_image_get_type ()) diff --git a/src/widgets/gradient-selector.cpp b/src/widgets/gradient-selector.cpp index 49549de1c..f7a981c9f 100644 --- a/src/widgets/gradient-selector.cpp +++ b/src/widgets/gradient-selector.cpp @@ -259,7 +259,7 @@ SPGradientSpread SPGradientSelector::getSpread() void SPGradientSelector::setVector(SPDocument *doc, SPGradient *vector) { g_return_if_fail(!vector || SP_IS_GRADIENT(vector)); - g_return_if_fail(!vector || (SP_OBJECT_DOCUMENT(vector) == doc)); + g_return_if_fail(!vector || (vector->document == doc)); if (vector && !vector->hasStops()) { return; @@ -312,7 +312,7 @@ sp_gradient_selector_vector_set (SPGradientVectorSelector */*gvs*/, SPGradient * if (!blocked) { blocked = TRUE; gr = sp_gradient_ensure_vector_normalized (gr); - sel->setVector((gr) ? SP_OBJECT_DOCUMENT (gr) : 0, gr); + sel->setVector((gr) ? gr->document : 0, gr); g_signal_emit (G_OBJECT (sel), signals[CHANGED], 0, gr); blocked = FALSE; } @@ -344,9 +344,9 @@ sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *s Inkscape::XML::Node *repr = NULL; - if (gr) - repr = SP_OBJECT_REPR (gr)->duplicate(xml_doc); - else { + if (gr) { + repr = gr->getRepr()->duplicate(xml_doc); + } else { repr = xml_doc->createElement("svg:linearGradient"); Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop"); stop->setAttribute("offset", "0"); @@ -360,7 +360,7 @@ sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *s Inkscape::GC::release(stop); } - SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL); + SP_DOCUMENT_DEFS(doc)->getRepr()->addChild(repr, NULL); gr = (SPGradient *) doc->getObjectByRepr(repr); sp_gradient_vector_selector_set_gradient( diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index dbb934fb1..737b3d7bb 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -162,7 +162,7 @@ GtkWidget *sp_gradient_vector_selector_new(SPDocument *doc, SPGradient *gr) GtkWidget *gvs; g_return_val_if_fail(!gr || SP_IS_GRADIENT(gr), NULL); - g_return_val_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc), NULL); + g_return_val_if_fail(!gr || (gr->document == doc), NULL); gvs = static_cast<GtkWidget*>(gtk_type_new(SP_TYPE_GRADIENT_VECTOR_SELECTOR)); @@ -187,7 +187,7 @@ void sp_gradient_vector_selector_set_gradient(SPGradientVectorSelector *gvs, SPD g_return_if_fail(SP_IS_GRADIENT_VECTOR_SELECTOR(gvs)); g_return_if_fail(!gr || (doc != NULL)); g_return_if_fail(!gr || SP_IS_GRADIENT(gr)); - g_return_if_fail(!gr || (SP_OBJECT_DOCUMENT(gr) == doc)); + g_return_if_fail(!gr || (gr->document == doc)); g_return_if_fail(!gr || gr->hasStops()); if (doc != gvs->doc) { @@ -256,7 +256,7 @@ static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs) /* Pick up all gradients with vectors */ GSList *gl = NULL; if (gvs->gr) { - const GSList *gradients = SP_OBJECT_DOCUMENT(gvs->gr)->getResourceList("gradient"); + const GSList *gradients = gvs->gr->document->getResourceList("gradient"); for (const GSList *curr = gradients; curr; curr = curr->next) { SPGradient* grad = SP_GRADIENT(curr->data); if ( grad->hasStops() && (grad->isSwatch() == gvs->swatched) ) { @@ -371,7 +371,7 @@ static void sp_gvs_gradient_activate(GtkMenuItem *mi, SPGradientVectorSelector * /* We do extra undo push here */ /* If handler has already done it, it is just NOP */ // FIXME: looks like this is never a valid undo step, consider removing this - DocumentUndo::done(SP_OBJECT_DOCUMENT(norm), SP_VERB_CONTEXT_GRADIENT, + DocumentUndo::done(norm->document, SP_VERB_CONTEXT_GRADIENT, /* TODO: annotate */ "gradient-vector.cpp:350"); } } @@ -479,7 +479,7 @@ static void verify_grad(SPGradient *gradient) } Inkscape::XML::Document *xml_doc; - xml_doc = SP_OBJECT_REPR(gradient)->document(); + xml_doc = gradient->getRepr()->document(); if (i < 1) { Inkscape::CSSOStringStream os; @@ -490,20 +490,20 @@ static void verify_grad(SPGradient *gradient) child = xml_doc->createElement("svg:stop"); sp_repr_set_css_double(child, "offset", 0.0); child->setAttribute("style", os.str().c_str()); - SP_OBJECT_REPR(gradient)->addChild(child, NULL); + gradient->getRepr()->addChild(child, NULL); Inkscape::GC::release(child); child = xml_doc->createElement("svg:stop"); sp_repr_set_css_double(child, "offset", 1.0); child->setAttribute("style", os.str().c_str()); - SP_OBJECT_REPR(gradient)->addChild(child, NULL); + gradient->getRepr()->addChild(child, NULL); Inkscape::GC::release(child); } if (i < 2) { - sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", 0.0); - Inkscape::XML::Node *child = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document()); + sp_repr_set_css_double(stop->getRepr(), "offset", 0.0); + Inkscape::XML::Node *child = stop->getRepr()->duplicate(gradient->getRepr()->document()); sp_repr_set_css_double(child, "offset", 1.0); - SP_OBJECT_REPR(gradient)->addChild(child, SP_OBJECT_REPR(stop)); + gradient->getRepr()->addChild(child, stop->getRepr()); Inkscape::GC::release(child); } } @@ -513,7 +513,7 @@ static void select_stop_in_list( GtkWidget *mnu, SPGradient *gradient, SPStop *n int i = 0; for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) { if (SP_IS_STOP(ochild)) { - if (SP_OBJECT(ochild) == SP_OBJECT(new_stop)) { + if (ochild == new_stop) { gtk_option_menu_set_history(GTK_OPTION_MENU(mnu), i); break; } @@ -566,7 +566,7 @@ static void update_stop_list( GtkWidget *mnu, SPGradient *gradient, SPStop *new_ gtk_widget_show(cpv); gtk_container_add( GTK_CONTAINER(hb), cpv ); g_object_set_data( G_OBJECT(i), "preview", cpv ); - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) sl->data); + Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr(); GtkWidget *l = gtk_label_new(repr->attribute("id")); gtk_widget_show(l); gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5); @@ -660,9 +660,9 @@ static void offadjustmentChanged( GtkAdjustment *adjustment, GtkWidget *vb) SPStop *stop = SP_STOP(g_object_get_data(G_OBJECT(gtk_menu_get_active(GTK_MENU(gtk_option_menu_get_menu(mnu)))), "stop")); stop->offset = adjustment->value; - sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset); + sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); - DocumentUndo::maybeDone(SP_OBJECT_DOCUMENT(stop), "gradient:stop:offset", SP_VERB_CONTEXT_GRADIENT, + DocumentUndo::maybeDone(stop->document, "gradient:stop:offset", SP_VERB_CONTEXT_GRADIENT, _("Change gradient stop offset")); blocked = FALSE; @@ -706,15 +706,15 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) } if (next != NULL) { - new_stop_repr = SP_OBJECT_REPR(stop)->duplicate(SP_OBJECT_REPR(gradient)->document()); - SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop)); + new_stop_repr = stop->getRepr()->duplicate(gradient->getRepr()->document()); + gradient->getRepr()->addChild(new_stop_repr, stop->getRepr()); } else { next = stop; - new_stop_repr = SP_OBJECT_REPR(stop->getPrevStop())->duplicate(SP_OBJECT_REPR(gradient)->document()); - SP_OBJECT_REPR(gradient)->addChild(new_stop_repr, SP_OBJECT_REPR(stop->getPrevStop())); + new_stop_repr = stop->getPrevStop()->getRepr()->duplicate(gradient->getRepr()->document()); + gradient->getRepr()->addChild(new_stop_repr, stop->getPrevStop()->getRepr()); } - SPStop *newstop = (SPStop *) SP_OBJECT_DOCUMENT(gradient)->getObjectByRepr(new_stop_repr); + SPStop *newstop = reinterpret_cast<SPStop *>(gradient->document->getObjectByRepr(new_stop_repr)); newstop->offset = (stop->offset + next->offset) * 0.5 ; @@ -727,8 +727,8 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) sp_svg_write_color(c, sizeof(c), cnew); gdouble opacity = static_cast<gdouble>(SP_RGBA32_A_F(cnew)); os << "stop-color:" << c << ";stop-opacity:" << opacity <<";"; - SP_OBJECT_REPR (newstop)->setAttribute("style", os.str().c_str()); - sp_repr_set_css_double( SP_OBJECT_REPR(newstop), "offset", (double)newstop->offset); + newstop->getRepr()->setAttribute("style", os.str().c_str()); + sp_repr_set_css_double( newstop->getRepr(), "offset", (double)newstop->offset); sp_gradient_vector_widget_load_gradient(vb, gradient); Inkscape::GC::release(new_stop_repr); @@ -737,7 +737,7 @@ static void sp_grd_ed_add_stop(GtkWidget */*widget*/, GtkWidget *vb) GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(vb), "offslide")); gtk_widget_set_sensitive(offslide, TRUE); gtk_widget_set_sensitive(GTK_WIDGET(offspin), TRUE); - DocumentUndo::done(SP_OBJECT_DOCUMENT(gradient), SP_VERB_CONTEXT_GRADIENT, + DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT, _("Add gradient stop")); } @@ -755,20 +755,20 @@ static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) SPStop *next = stop->getNextStop(); if (next) { next->offset = 0; - sp_repr_set_css_double(SP_OBJECT_REPR(next), "offset", 0); + sp_repr_set_css_double(next->getRepr(), "offset", 0); } } else if (stop->offset == 1) { SPStop *prev = stop->getPrevStop(); if (prev) { prev->offset = 1; - sp_repr_set_css_double(SP_OBJECT_REPR(prev), "offset", 1); + sp_repr_set_css_double(prev->getRepr(), "offset", 1); } } - SP_OBJECT_REPR(gradient)->removeChild(SP_OBJECT_REPR(stop)); + gradient->getRepr()->removeChild(stop->getRepr()); sp_gradient_vector_widget_load_gradient(vb, gradient); update_stop_list(GTK_WIDGET(mnu), gradient, NULL); - DocumentUndo::done(SP_OBJECT_DOCUMENT(gradient), SP_VERB_CONTEXT_GRADIENT, + DocumentUndo::done(gradient->document, SP_VERB_CONTEXT_GRADIENT, _("Delete gradient stop")); } @@ -788,7 +788,7 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s gtk_widget_show(w); gtk_box_pack_start(GTK_BOX(vb), w, TRUE, TRUE, PAD); - sp_repr_add_listener(SP_OBJECT_REPR(gradient), &grad_edit_dia_repr_events, vb); + sp_repr_add_listener(gradient->getRepr(), &grad_edit_dia_repr_events, vb); GtkTooltips *tt = gtk_tooltips_new(); /* Stop list */ @@ -1032,11 +1032,11 @@ static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradien update_stop_list(GTK_WIDGET(mnu), gradient, NULL); // Once the user edits a gradient, it stops being auto-collectable - if (SP_OBJECT_REPR(gradient)->attribute("inkscape:collect")) { - SPDocument *document = SP_OBJECT_DOCUMENT(gradient); + if (gradient->getRepr()->attribute("inkscape:collect")) { + SPDocument *document = gradient->document; bool saved = DocumentUndo::getUndoSensitive(document); DocumentUndo::setUndoSensitive(document, false); - SP_OBJECT_REPR(gradient)->setAttribute("inkscape:collect", NULL); + gradient->getRepr()->setAttribute("inkscape:collect", NULL); DocumentUndo::setUndoSensitive(document, saved); } } else { // no gradient, disable everything @@ -1078,9 +1078,7 @@ static gboolean sp_gradient_vector_dialog_delete(GtkWidget */*widget*/, GdkEvent static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data*/) { - GObject *gradient; - - gradient = (GObject*)g_object_get_data(G_OBJECT(object), "gradient"); + SPObject *gradient = reinterpret_cast<SPObject*>(g_object_get_data(G_OBJECT(object), "gradient")); sigc::connection *release_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_release_connection"); sigc::connection *modified_connection = (sigc::connection *)g_object_get_data(G_OBJECT(object), "gradient_modified_connection"); @@ -1093,8 +1091,8 @@ static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data sp_signal_disconnect_by_data(gradient, object); } - if (gradient && SP_OBJECT_REPR(gradient)) { - sp_repr_remove_listener_by_data(SP_OBJECT_REPR(gradient), object); + if (gradient && gradient->getRepr()) { + sp_repr_remove_listener_by_data(gradient->getRepr(), object); } } @@ -1179,14 +1177,14 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GtkObject *o float alpha = 0; csel->base->getColorAlpha( color, alpha ); - sp_repr_set_css_double(SP_OBJECT_REPR(stop), "offset", stop->offset); + sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); Inkscape::CSSOStringStream os; os << "stop-color:" << color.toString() << ";stop-opacity:" << static_cast<gdouble>(alpha) <<";"; - SP_OBJECT_REPR(stop)->setAttribute("style", os.str().c_str()); + stop->getRepr()->setAttribute("style", os.str().c_str()); // g_snprintf(c, 256, "stop-color:#%06x;stop-opacity:%g;", rgb >> 8, static_cast<gdouble>(alpha)); - //SP_OBJECT_REPR(stop)->setAttribute("style", c); + //stop->getRepr()->setAttribute("style", c); - DocumentUndo::done(SP_OBJECT_DOCUMENT(ngr), SP_VERB_CONTEXT_GRADIENT, + DocumentUndo::done(ngr->document, SP_VERB_CONTEXT_GRADIENT, _("Change gradient stop color")); blocked = FALSE; diff --git a/src/widgets/gradient-vector.h b/src/widgets/gradient-vector.h index 9147f9cc1..012d4e9a3 100644 --- a/src/widgets/gradient-vector.h +++ b/src/widgets/gradient-vector.h @@ -17,6 +17,7 @@ #include <glib.h> +#include <stddef.h> #include <sigc++/connection.h> #include <gtk/gtkvbox.h> diff --git a/src/widgets/icon.cpp b/src/widgets/icon.cpp index 1b6878c32..88cf43588 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -18,8 +18,11 @@ #include <cstring> #include <glib/gmem.h> +#include <glib/gstdio.h> #include <gtk/gtk.h> #include <gtkmm.h> +#include <gdkmm/pixbuf.h> +#include <glibmm/fileutils.h> #include "path-prefix.h" #include "preferences.h" @@ -33,36 +36,76 @@ #include "icon.h" -static gboolean icon_prerender_task(gpointer data); +// Bring in work-around for Glib versions missing GStatBuf +#if !GLIB_CHECK_VERSION(2,25,0) +#if defined (_MSC_VER) && !defined(_WIN64) +typedef struct _stat32 GStatBuf; +#else //defined (_MSC_VER) && !defined(_WIN64) +typedef struct stat GStatBuf; +#endif //defined (_MSC_VER) && !defined(_WIN64) +#endif //!GLIB_CHECK_VERSION(2,25,0) -static void addPreRender( GtkIconSize lsize, gchar const *name ); +struct IconImpl { + static void classInit(SPIconClass *klass); + static void init(SPIcon *icon); -static void sp_icon_class_init(SPIconClass *klass); -static void sp_icon_init(SPIcon *icon); -static void sp_icon_dispose(GObject *object); + static GtkWidget *newFull( Inkscape::IconSize lsize, gchar const *name ); -static void sp_icon_reset(SPIcon *icon); -static void sp_icon_clear(SPIcon *icon); + static void dispose(GObject *object); -static void sp_icon_size_request(GtkWidget *widget, GtkRequisition *requisition); -static void sp_icon_size_allocate(GtkWidget *widget, GtkAllocation *allocation); -static int sp_icon_expose(GtkWidget *widget, GdkEventExpose *event); + static void reset(SPIcon *icon); + static void clear(SPIcon *icon); -static void sp_icon_paint(SPIcon *icon, GdkRectangle const *area); + static void sizeRequest(GtkWidget *widget, GtkRequisition *requisition); + static void sizeAllocate(GtkWidget *widget, GtkAllocation *allocation); + static int expose(GtkWidget *widget, GdkEventExpose *event); -static void sp_icon_screen_changed( GtkWidget *widget, GdkScreen *previous_screen ); -static void sp_icon_style_set( GtkWidget *widget, GtkStyle *previous_style ); -static void sp_icon_theme_changed( SPIcon *icon ); + static void paint(SPIcon *icon, GdkRectangle const *area); -static GdkPixbuf *sp_icon_image_load_pixmap(gchar const *name, unsigned lsize, unsigned psize); -static GdkPixbuf *sp_icon_image_load_svg(gchar const *name, GtkIconSize lsize, unsigned psize); + static void screenChanged( GtkWidget *widget, GdkScreen *previous_screen ); + static void styleSet( GtkWidget *widget, GtkStyle *previous_style ); + static void themeChanged( SPIcon *icon ); -static void sp_icon_overlay_pixels( guchar *px, int width, int height, int stride, - unsigned r, unsigned g, unsigned b ); + static int getPhysSize(int size); + static void fetchPixbuf( SPIcon *icon ); -static void injectCustomSize(); + static gboolean prerenderTask(gpointer data); + static void addPreRender( GtkIconSize lsize, gchar const *name ); + static GdkPixbuf* renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize ); + + + static GdkPixbuf *loadPixmap(gchar const *name, unsigned lsize, unsigned psize); + static GdkPixbuf *loadSvg(std::list<Glib::ustring> const &names, GtkIconSize lsize, unsigned psize); + + static void overlayPixels( guchar *px, int width, int height, int stride, + unsigned r, unsigned g, unsigned b ); + + static void injectCustomSize(); + + static void imageMapCB(GtkWidget* widget, gpointer user_data); + static void imageMapNamedCB(GtkWidget* widget, gpointer user_data); + static bool prerenderIcon(gchar const *name, GtkIconSize lsize, unsigned psize); + + + static std::list<gchar*> &icons_svg_paths(); + static guchar *load_svg_pixels(std::list<Glib::ustring> const &names, + unsigned psize, unsigned &stride); + + static std::string fileEscape( std::string const & str ); + + static void validateCache(); + static void setupLegacyNaming(); + +private: + static const std::string magicNumber; + static GtkWidgetClass *parent_class; + static std::map<Glib::ustring, Glib::ustring> legacyNames; +}; + +const std::string IconImpl::magicNumber = "1.0"; +GtkWidgetClass *IconImpl::parent_class = 0; +std::map<Glib::ustring, Glib::ustring> IconImpl::legacyNames; -static GtkWidgetClass *parent_class; static bool sizeDirty = true; @@ -78,8 +121,6 @@ static GtkIconSize iconSizeLookup[] = { GTK_ICON_SIZE_MENU, // for Inkscape::ICON_SIZE_DECORATION }; -static std::map<Glib::ustring, Glib::ustring> legacyNames; - class IconCacheItem { public: @@ -94,8 +135,7 @@ public: static std::map<Glib::ustring, std::vector<IconCacheItem> > iconSetCache; static std::set<Glib::ustring> internalNames; -GType -sp_icon_get_type() +GType SPIcon::getType() { static GType type = 0; if (!type) { @@ -103,12 +143,12 @@ sp_icon_get_type() sizeof(SPIconClass), NULL, NULL, - (GClassInitFunc) sp_icon_class_init, + reinterpret_cast<GClassInitFunc>(IconImpl::classInit), NULL, NULL, sizeof(SPIcon), 0, - (GInstanceInitFunc) sp_icon_init, + reinterpret_cast<GInstanceInitFunc>(IconImpl::init), NULL }; type = g_type_register_static(GTK_TYPE_WIDGET, "SPIcon", &info, (GTypeFlags)0); @@ -116,8 +156,7 @@ sp_icon_get_type() return type; } -static void -sp_icon_class_init(SPIconClass *klass) +void IconImpl::classInit(SPIconClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; @@ -127,18 +166,16 @@ sp_icon_class_init(SPIconClass *klass) parent_class = (GtkWidgetClass*)g_type_class_peek_parent(klass); - object_class->dispose = sp_icon_dispose; + object_class->dispose = IconImpl::dispose; - widget_class->size_request = sp_icon_size_request; - widget_class->size_allocate = sp_icon_size_allocate; - widget_class->expose_event = sp_icon_expose; - widget_class->screen_changed = sp_icon_screen_changed; - widget_class->style_set = sp_icon_style_set; + widget_class->size_request = IconImpl::sizeRequest; + widget_class->size_allocate = IconImpl::sizeAllocate; + widget_class->expose_event = IconImpl::expose; + widget_class->screen_changed = IconImpl::screenChanged; + widget_class->style_set = IconImpl::styleSet; } - -static void -sp_icon_init(SPIcon *icon) +void IconImpl::init(SPIcon *icon) { GTK_WIDGET_FLAGS(icon) |= GTK_NO_WINDOW; icon->lsize = Inkscape::ICON_SIZE_BUTTON; @@ -147,11 +184,10 @@ sp_icon_init(SPIcon *icon) icon->pb = 0; } -static void -sp_icon_dispose(GObject *object) +void IconImpl::dispose(GObject *object) { SPIcon *icon = SP_ICON(object); - sp_icon_clear(icon); + clear(icon); if ( icon->name ) { g_free( icon->name ); icon->name = 0; @@ -160,32 +196,32 @@ sp_icon_dispose(GObject *object) ((GObjectClass *) (parent_class))->dispose(object); } -static void sp_icon_reset( SPIcon *icon ) { +void IconImpl::reset( SPIcon *icon ) +{ icon->psize = 0; - sp_icon_clear(icon); + clear(icon); } -static void sp_icon_clear( SPIcon *icon ) { +void IconImpl::clear( SPIcon *icon ) +{ if (icon->pb) { g_object_unref(G_OBJECT(icon->pb)); icon->pb = NULL; } } -static void -sp_icon_size_request(GtkWidget *widget, GtkRequisition *requisition) +void IconImpl::sizeRequest(GtkWidget *widget, GtkRequisition *requisition) { SPIcon const *icon = SP_ICON(widget); int const size = ( icon->psize ? icon->psize - : sp_icon_get_phys_size(icon->lsize) ); + : getPhysSize(icon->lsize) ); requisition->width = size; requisition->height = size; } -static void -sp_icon_size_allocate(GtkWidget *widget, GtkAllocation *allocation) +void IconImpl::sizeAllocate(GtkWidget *widget, GtkAllocation *allocation) { widget->allocation = *allocation; @@ -194,34 +230,37 @@ sp_icon_size_allocate(GtkWidget *widget, GtkAllocation *allocation) } } -static int sp_icon_expose(GtkWidget *widget, GdkEventExpose *event) +int IconImpl::expose(GtkWidget *widget, GdkEventExpose *event) { if ( GTK_WIDGET_DRAWABLE(widget) ) { SPIcon *icon = SP_ICON(widget); if ( !icon->pb ) { - sp_icon_fetch_pixbuf( icon ); + fetchPixbuf( icon ); } - sp_icon_paint(SP_ICON(widget), &event->area); + paint(icon, &event->area); } return TRUE; } -static GdkPixbuf* renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize ); - // PUBLIC CALL: void sp_icon_fetch_pixbuf( SPIcon *icon ) { + return IconImpl::fetchPixbuf(icon); +} + +void IconImpl::fetchPixbuf( SPIcon *icon ) +{ if ( icon ) { if ( !icon->pb ) { - icon->psize = sp_icon_get_phys_size(icon->lsize); + icon->psize = getPhysSize(icon->lsize); icon->pb = renderup(icon->name, icon->lsize, icon->psize); } } } -GdkPixbuf* renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize ) { +GdkPixbuf* IconImpl::renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize ) { GtkIconTheme *theme = gtk_icon_theme_get_default(); GdkPixbuf *pb = 0; @@ -229,21 +268,24 @@ GdkPixbuf* renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize pb = gtk_icon_theme_load_icon(theme, name, psize, (GtkIconLookupFlags) 0, NULL); } if (!pb) { - pb = sp_icon_image_load_svg( name, Inkscape::getRegisteredIconSize(lsize), psize ); - if (!pb && (legacyNames.find(name) != legacyNames.end())) { + std::list<Glib::ustring> names; + names.push_back(name); + if ( legacyNames.find(name) != legacyNames.end() ) { if ( Inkscape::Preferences::get()->getBool("/debug/icons/dumpSvg") ) { g_message("Checking fallback [%s]->[%s]", name, legacyNames[name].c_str()); } - pb = sp_icon_image_load_svg( legacyNames[name].c_str(), Inkscape::getRegisteredIconSize(lsize), psize ); + names.push_back(legacyNames[name]); } + pb = loadSvg( names, Inkscape::getRegisteredIconSize(lsize), psize ); + // if this was loaded from SVG, add it as a builtin icon if (pb) { gtk_icon_theme_add_builtin_icon(name, psize, pb); } } if (!pb) { - pb = sp_icon_image_load_pixmap( name, lsize, psize ); + pb = loadPixmap( name, lsize, psize ); } if ( !pb ) { // TODO: We should do something more useful if we can't load the image. @@ -252,43 +294,176 @@ GdkPixbuf* renderup( gchar const* name, Inkscape::IconSize lsize, unsigned psize return pb; } -static void sp_icon_screen_changed( GtkWidget *widget, GdkScreen *previous_screen ) +void IconImpl::screenChanged( GtkWidget *widget, GdkScreen *previous_screen ) { if ( GTK_WIDGET_CLASS( parent_class )->screen_changed ) { GTK_WIDGET_CLASS( parent_class )->screen_changed( widget, previous_screen ); } SPIcon *icon = SP_ICON(widget); - sp_icon_theme_changed(icon); + themeChanged(icon); } -static void sp_icon_style_set( GtkWidget *widget, GtkStyle *previous_style ) +void IconImpl::styleSet( GtkWidget *widget, GtkStyle *previous_style ) { if ( GTK_WIDGET_CLASS( parent_class )->style_set ) { GTK_WIDGET_CLASS( parent_class )->style_set( widget, previous_style ); } SPIcon *icon = SP_ICON(widget); - sp_icon_theme_changed(icon); + themeChanged(icon); } -static void sp_icon_theme_changed( SPIcon *icon ) +void IconImpl::themeChanged( SPIcon *icon ) { bool const dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpSvg"); if ( dump ) { g_message("Got a change bump for this icon"); } sizeDirty = true; - sp_icon_reset(icon); + reset(icon); gtk_widget_queue_draw( GTK_WIDGET(icon) ); } +std::string IconImpl::fileEscape( std::string const & str ) +{ + std::string result; + result.reserve(str.size()); + for ( size_t i = 0; i < str.size(); ++i ) { + char ch = str[i]; + if ( (0x20 <= ch) && !(0x80 & ch) ) { + result += ch; + } else { + result += "\\x"; + gchar *tmp = g_strdup_printf("%02X", (0x0ff & ch)); + result += tmp; + g_free(tmp); + } + } + return result; +} -static void imageMapCB(GtkWidget* widget, gpointer user_data); -static void imageMapNamedCB(GtkWidget* widget, gpointer user_data); -static bool prerender_icon(gchar const *name, GtkIconSize lsize, unsigned psize); -static Glib::ustring icon_cache_key(gchar const *name, unsigned psize); +static bool isSizedSubdir( std::string const &name ) +{ + bool isSized = false; + if ( (name.size() > 2) && (name.size() & 1) ) { // needs to be an odd length 3 or more + size_t mid = (name.size() - 1) / 2; + if ( (name[mid] == 'x') && (name.substr(0, mid) == name.substr(mid + 1)) ) { + isSized = true; + for ( size_t i = 0; (i < mid) && isSized; ++i ) { + isSized &= g_ascii_isdigit(name[i]); + } + } + } + return isSized; +} + +void IconImpl::validateCache() +{ + std::list<gchar *> &sources = icons_svg_paths(); + std::string iconCacheDir = Glib::build_filename(Glib::build_filename(Glib::get_user_cache_dir(), "inkscape"), "icons"); + std::string iconCacheFile = Glib::build_filename( iconCacheDir, "cache.info" ); + + std::vector<std::string> filesFound; + + for (std::list<gchar*>::iterator i = sources.begin(); i != sources.end(); ++i) { + gchar const* potentialFile = *i; + if ( Glib::file_test(potentialFile, Glib::FILE_TEST_EXISTS) && Glib::file_test(potentialFile, Glib::FILE_TEST_IS_REGULAR) ) { + filesFound.push_back(*i); + } + } + + unsigned long lastSeen = 0; + std::ostringstream out; + out << "Inkscape cache v" << std::hex << magicNumber << std::dec << std::endl; + out << "Sourcefiles: " << filesFound.size() << std::endl; + for ( std::vector<std::string>::iterator it = filesFound.begin(); it != filesFound.end(); ++it ) { + GStatBuf st; + memset(&st, 0, sizeof(st)); + if ( !g_stat(it->c_str(), &st) ) { + unsigned long when = st.st_mtime; + lastSeen = std::max(lastSeen, when); + out << std::hex << when << std::dec << " " << fileEscape(*it) << std::endl; + } else { + out << "0 " << fileEscape(*it) << std::endl; + } + } + std::string wanted = out.str(); + + std::string present; + { + gchar *contents = 0; + if ( g_file_get_contents(iconCacheFile.c_str(), &contents, 0, 0) ) { + if ( contents ) { + present = contents; + } + g_free(contents); + contents = 0; + } + } + bool cacheValid = (present == wanted); + + if ( cacheValid ) { + // Check if any cached rasters are out of date + Glib::Dir dir(iconCacheDir); + for ( Glib::DirIterator it = dir.begin(); cacheValid && (it != dir.end()); ++it ) { + if ( isSizedSubdir(*it) ) { + std::string subdirName = Glib::build_filename( iconCacheDir, *it ); + if ( Glib::file_test(subdirName, Glib::FILE_TEST_IS_DIR) ) { + Glib::Dir subdir(subdirName); + for ( Glib::DirIterator subit = subdir.begin(); cacheValid && (subit != subdir.end()); ++subit ) { + std::string fullpath = Glib::build_filename( subdirName, *subit ); + if ( Glib::file_test(fullpath, Glib::FILE_TEST_EXISTS) && !Glib::file_test(fullpath, Glib::FILE_TEST_IS_DIR) ) { + GStatBuf st; + memset(&st, 0, sizeof(st)); + if ( !g_stat(fullpath.c_str(), &st) ) { + unsigned long when = st.st_mtime; + if ( when < lastSeen ) { + cacheValid = false; + } + } + } + } + } + } + } + } + + if ( !cacheValid ) { + if ( Glib::file_test(iconCacheDir, Glib::FILE_TEST_EXISTS) ) { + // Purge existing icons, but not possible future sub-directories. + if ( Glib::file_test(iconCacheDir, Glib::FILE_TEST_IS_DIR) ) { + Glib::Dir dir(iconCacheDir); + for ( Glib::DirIterator it = dir.begin(); it != dir.end(); ++it ) { + if ( isSizedSubdir(*it) ) { + std::string subdirName = Glib::build_filename( iconCacheDir, *it ); + if ( Glib::file_test(subdirName, Glib::FILE_TEST_IS_DIR) ) { + Glib::Dir subdir(subdirName); + for ( Glib::DirIterator subit = subdir.begin(); subit != subdir.end(); ++subit ) { + std::string fullpath = Glib::build_filename( subdirName, *subit ); + if ( Glib::file_test(fullpath, Glib::FILE_TEST_EXISTS) && !Glib::file_test(fullpath, Glib::FILE_TEST_IS_DIR) ) { + g_remove(fullpath.c_str()); + } + } + g_rmdir( subdirName.c_str() ); + } + } + } + } + } else { + g_mkdir_with_parents( iconCacheDir.c_str(), 0x1ED ); + } + + if ( g_file_set_contents(iconCacheFile.c_str(), wanted.c_str(), wanted.size(), 0) ) { + // Caching may proceed + } else { + g_warning("Unable to write cache info file."); + } + } +} + +static Glib::ustring icon_cache_key(Glib::ustring const &name, unsigned psize); static GdkPixbuf *get_cached_pixbuf(Glib::ustring const &key); -static void setupLegacyNaming() { +void IconImpl::setupLegacyNaming() { legacyNames["document-import"] ="file_import"; legacyNames["document-export"] ="file_export"; legacyNames["document-import-ocal"] ="ocal_import"; @@ -543,8 +718,7 @@ static void setupLegacyNaming() { legacyNames["zoom"] ="sticky_zoom"; } -static GtkWidget * -sp_icon_new_full( Inkscape::IconSize lsize, gchar const *name ) +GtkWidget *IconImpl::newFull( Inkscape::IconSize lsize, gchar const *name ) { static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk"); @@ -600,8 +774,8 @@ sp_icon_new_full( Inkscape::IconSize lsize, gchar const *name ) g_signal_connect( G_OBJECT(widget), "map", G_CALLBACK(imageMapNamedCB), GINT_TO_POINTER(0) ); if ( Inkscape::Preferences::get()->getBool("/options/iconrender/named_nodelay") ) { - int psize = sp_icon_get_phys_size(lsize); - prerender_icon(name, mappedSize, psize); + int psize = getPhysSize(lsize); + prerenderIcon(name, mappedSize, psize); } else { addPreRender( mappedSize, name ); } @@ -619,7 +793,7 @@ sp_icon_new_full( Inkscape::IconSize lsize, gchar const *name ) SPIcon *icon = (SPIcon *)g_object_new(SP_TYPE_ICON, NULL); icon->lsize = lsize; icon->name = g_strdup(name); - icon->psize = sp_icon_get_phys_size(lsize); + icon->psize = getPhysSize(lsize); widget = GTK_WIDGET(icon); } @@ -627,17 +801,17 @@ sp_icon_new_full( Inkscape::IconSize lsize, gchar const *name ) return widget; } -GtkWidget * -sp_icon_new( Inkscape::IconSize lsize, gchar const *name ) +// PUBLIC CALL: +GtkWidget *sp_icon_new( Inkscape::IconSize lsize, gchar const *name ) { - return sp_icon_new_full( lsize, name ); + return IconImpl::newFull( lsize, name ); } // PUBLIC CALL: Gtk::Widget *sp_icon_get_icon( Glib::ustring const &oid, Inkscape::IconSize size ) { Gtk::Widget *result = 0; - GtkWidget *widget = sp_icon_new_full( static_cast<Inkscape::IconSize>(Inkscape::getRegisteredIconSize(size)), oid.c_str() ); + GtkWidget *widget = IconImpl::newFull( static_cast<Inkscape::IconSize>(Inkscape::getRegisteredIconSize(size)), oid.c_str() ); if ( widget ) { if ( GTK_IS_IMAGE(widget) ) { @@ -651,22 +825,7 @@ Gtk::Widget *sp_icon_get_icon( Glib::ustring const &oid, Inkscape::IconSize size return result; } -GtkIconSize -sp_icon_get_gtk_size(int size) -{ - static GtkIconSize sizemap[64] = {(GtkIconSize)0}; - size = CLAMP(size, 4, 63); - if (!sizemap[size]) { - static int count = 0; - char c[64]; - g_snprintf(c, 64, "InkscapeIcon%d", count++); - sizemap[size] = gtk_icon_size_register(c, size, size); - } - return sizemap[size]; -} - - -static void injectCustomSize() +void IconImpl::injectCustomSize() { // TODO - still need to handle the case of theme changes and resize, especially as we can't re-register a string. if ( !sizeMapDone ) @@ -697,7 +856,7 @@ static void injectCustomSize() GtkIconSize Inkscape::getRegisteredIconSize( Inkscape::IconSize size ) { GtkIconSize other = GTK_ICON_SIZE_MENU; - injectCustomSize(); + IconImpl::injectCustomSize(); size = CLAMP( size, Inkscape::ICON_SIZE_MENU, Inkscape::ICON_SIZE_DECORATION ); if ( size == Inkscape::ICON_SIZE_DECORATION ) { other = gtk_icon_size_from_name("inkscape-decoration"); @@ -712,6 +871,11 @@ GtkIconSize Inkscape::getRegisteredIconSize( Inkscape::IconSize size ) // PUBLIC CALL: int sp_icon_get_phys_size(int size) { + return IconImpl::getPhysSize(size); +} + +int IconImpl::getPhysSize(int size) +{ static bool init = false; static int lastSys[Inkscape::ICON_SIZE_DECORATION + 1]; static int vals[Inkscape::ICON_SIZE_DECORATION + 1]; @@ -825,7 +989,7 @@ int sp_icon_get_phys_size(int size) return vals[size]; } -static void sp_icon_paint(SPIcon *icon, GdkRectangle const */*area*/) +void IconImpl::paint(SPIcon *icon, GdkRectangle const */*area*/) { GtkWidget &widget = *GTK_WIDGET(icon); GdkPixbuf *image = icon->pb; @@ -861,7 +1025,7 @@ static void sp_icon_paint(SPIcon *icon, GdkRectangle const */*area*/) } } -GdkPixbuf *sp_icon_image_load_pixmap(gchar const *name, unsigned /*lsize*/, unsigned psize) +GdkPixbuf *IconImpl::loadPixmap(gchar const *name, unsigned /*lsize*/, unsigned psize) { gchar *path = (gchar *) g_strdup_printf("%s/%s.png", INKSCAPE_PIXMAPDIR, name); // TODO: bulia, please look over @@ -921,10 +1085,10 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, SPObject *object = doc->getObjectById(name); if (object && SP_IS_ITEM(object)) { /* Find bbox in document */ - Geom::Matrix const i2doc(SP_ITEM(object)->i2doc_affine()); + Geom::Affine const i2doc(SP_ITEM(object)->i2doc_affine()); Geom::OptRect dbox = SP_ITEM(object)->getBounds(i2doc); - if ( SP_OBJECT_PARENT(object) == NULL ) + if ( object->parent == NULL ) { dbox = Geom::Rect(Geom::Point(0, 0), Geom::Point(doc->getWidth(), doc->getHeight())); @@ -935,7 +1099,7 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, NRGC gc(NULL); /* Update to renderable state */ double sf = 1.0; - nr_arena_item_set_transform(root, (Geom::Matrix)Geom::Scale(sf, sf)); + nr_arena_item_set_transform(root, (Geom::Affine)Geom::Scale(sf, sf)); gc.transform.setIdentity(); nr_arena_item_invoke_update( root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, @@ -967,7 +1131,7 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, } sf = (double)psize / (double)block; - nr_arena_item_set_transform(root, (Geom::Matrix)Geom::Scale(sf, sf)); + nr_arena_item_set_transform(root, (Geom::Affine)Geom::Scale(sf, sf)); gc.transform.setIdentity(); nr_arena_item_invoke_update( root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, @@ -1035,7 +1199,7 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, convert_pixels_argb32_to_pixbuf(px, psize, psize, stride); if ( Inkscape::Preferences::get()->getBool("/debug/icons/overlaySvg") ) { - sp_icon_overlay_pixels( px, psize, psize, stride, 0x00, 0x00, 0xff ); + IconImpl::overlayPixels( px, psize, psize, stride, 0x00, 0x00, 0xff ); } } } @@ -1046,18 +1210,20 @@ sp_icon_doc_icon( SPDocument *doc, NRArenaItem *root, -struct svg_doc_cache_t +class SVGDocCache { +public: + SVGDocCache( SPDocument *doc, NRArenaItem *root ) : doc(doc), root(root) {} SPDocument *doc; NRArenaItem *root; }; -static std::map<Glib::ustring, svg_doc_cache_t *> doc_cache; +static std::map<Glib::ustring, SVGDocCache *> doc_cache; static std::map<Glib::ustring, GdkPixbuf *> pb_cache; -Glib::ustring icon_cache_key(gchar const *name, unsigned psize) +Glib::ustring icon_cache_key(Glib::ustring const & name, unsigned psize) { - Glib::ustring key=name; + Glib::ustring key = name; key += ":"; key += psize; return key; @@ -1072,7 +1238,7 @@ GdkPixbuf *get_cached_pixbuf(Glib::ustring const &key) { return pb; } -static std::list<gchar*> &icons_svg_paths() +std::list<gchar*> &IconImpl::icons_svg_paths() { static std::list<gchar *> sources; static bool initialized = false; @@ -1088,91 +1254,59 @@ static std::list<gchar*> &icons_svg_paths() } // this function renders icons from icons.svg and returns the pixels. -static guchar *load_svg_pixels(gchar const *name, unsigned psize, unsigned &stride) +guchar *IconImpl::load_svg_pixels(std::list<Glib::ustring> const &names, + unsigned psize, unsigned &stride) { - SPDocument *doc = NULL; - NRArenaItem *root = NULL; - svg_doc_cache_t *info = NULL; - + bool const dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpSvg"); std::list<gchar *> &sources = icons_svg_paths(); // Try each document in turn until we successfully load the icon from one - guchar *px=NULL; - for (std::list<gchar*>::iterator i = sources.begin(); i != sources.end() && !px; ++i) { + guchar *px = NULL; + for (std::list<gchar*>::iterator i = sources.begin(); (i != sources.end()) && !px; ++i) { gchar *doc_filename = *i; + SVGDocCache *info = 0; // Did we already load this doc? Glib::ustring key(doc_filename); - info = 0; { - std::map<Glib::ustring, svg_doc_cache_t *>::iterator i = doc_cache.find(key); + std::map<Glib::ustring, SVGDocCache *>::iterator i = doc_cache.find(key); if ( i != doc_cache.end() ) { info = i->second; } } - /* Try to load from document. */ - if (!info && - Inkscape::IO::file_test( doc_filename, G_FILE_TEST_IS_REGULAR ) && - (doc = SPDocument::createNewDoc( doc_filename, FALSE )) ) { - - //g_message("Loaded icon file %s", doc_filename); - // prep the document - doc->ensureUpToDate(); - /* Create new arena */ - NRArena *arena = NRArena::create(); - /* Create ArenaItem and set transform */ - unsigned visionkey = SPItem::display_key_new(1); - /* fixme: Memory manage root if needed (Lauris) */ - // This needs to be fixed indeed; this leads to a memory leak of a few megabytes these days - // because shapes are being rendered which are not being freed - // Valgrind output: - /*==7014== 1,548,344 bytes in 599 blocks are possibly lost in loss record 20,361 of 20,362 - ==7014== at 0x4A05974: operator new(unsigned long) (vg_replace_malloc.c:220) - ==7014== by 0x4F1015: __gnu_cxx::new_allocator<Shape::point_data>::allocate(unsigned long, void const*) (new_allocator.h:89) - ==7014== by 0x4F02AC: std::_Vector_base<Shape::point_data, std::allocator<Shape::point_data> >::_M_allocate(unsigned long) (stl_vector.h:140) - ==7014== by 0xCF62D7: std::vector<Shape::point_data, std::allocator<Shape::point_data> >::_M_fill_insert(__gnu_cxx::__normal_iterator<Shape::point_data*, std::vector<Shape::point_data, std::allocator<Shape::point_data> > >, unsigned long, Shape::point_data const&) (vector.tcc:414) - ==7014== by 0xCF4D45: std::vector<Shape::point_data, std::allocator<Shape::point_data> >::insert(__gnu_cxx::__normal_iterator<Shape::point_data*, std::vector<Shape::point_data, std::allocator<Shape::point_data> > >, unsigned long, Shape::point_data const&) (stl_vector.h:851) - ==7014== by 0xCF3DCD: std::vector<Shape::point_data, std::allocator<Shape::point_data> >::resize(unsigned long, Shape::point_data) (stl_vector.h:557) - ==7014== by 0xCEA771: Shape::AddPoint(Geom::Point) (Shape.cpp:326) - ==7014== by 0xD0F413: Shape::ConvertToShape(Shape*, fill_typ, bool) (ShapeSweep.cpp:257) - ==7014== by 0x5ECD4F: nr_arena_shape_update_stroke(NRArenaShape*, NRGC*, NRRectL*) (nr-arena-shape.cpp:651) - ==7014== by 0x5EE0DA: nr_arena_shape_render(_cairo*, NRArenaItem*, NRRectL*, NRPixBlock*, unsigned int) (nr-arena-shape.cpp:862) - ==7014== by 0x5E72FB: nr_arena_item_invoke_render(_cairo*, NRArenaItem*, NRRectL const*, NRPixBlock*, unsigned int) (nr-arena-item.cpp:578) - ==7014== by 0x5E9DDE: nr_arena_group_render(_cairo*, NRArenaItem*, NRRectL*, NRPixBlock*, unsigned int) (nr-arena-group.cpp:228) - ==7014== by 0x5E72FB: nr_arena_item_invoke_render(_cairo*, NRArenaItem*, NRRectL const*, NRPixBlock*, unsigned int) (nr-arena-item.cpp:578) - ==7014== by 0x5E9DDE: nr_arena_group_render(_cairo*, NRArenaItem*, NRRectL*, NRPixBlock*, unsigned int) (nr-arena-group.cpp:228) - ==7014== by 0x5E72FB: nr_arena_item_invoke_render(_cairo*, NRArenaItem*, NRRectL const*, NRPixBlock*, unsigned int) (nr-arena-item.cpp:578) - */ - root = SP_ITEM(doc->getRoot())->invoke_show(arena, visionkey, SP_ITEM_SHOW_DISPLAY ); - - // store into the cache - info = new svg_doc_cache_t; - g_assert(info); - - info->doc=doc; - info->root=root; - doc_cache[key]=info; + // Try to load from document. + if (!info && Inkscape::IO::file_test( doc_filename, G_FILE_TEST_IS_REGULAR ) ) { + SPDocument *doc = SPDocument::createNewDoc( doc_filename, FALSE ); + if ( doc ) { + if ( dump ) { + g_message("Loaded icon file %s", doc_filename); + } + // prep the document + doc->ensureUpToDate(); + + // Create new arena + NRArena *arena = NRArena::create(); + + // Create ArenaItem and set transform + unsigned visionkey = SPItem::display_key_new(1); + // fixme: Memory manage root if needed (Lauris) + // This needs to be fixed indeed; this leads to a memory leak of a few megabytes these days + // because shapes are being rendered which are not being freed + NRArenaItem *root = SP_ITEM(doc->getRoot())->invoke_show( arena, visionkey, SP_ITEM_SHOW_DISPLAY ); + + // store into the cache + info = new SVGDocCache(doc, root); + doc_cache[key] = info; + } } if (info) { - doc=info->doc; - root=info->root; - } - - // move on to the next document if we couldn't get anything - if (!info && !doc) { - continue; + for (std::list<Glib::ustring>::const_iterator it = names.begin(); !px && (it != names.end()); ++it ) { + px = sp_icon_doc_icon( info->doc, info->root, it->c_str(), psize, stride ); + } } - - px = sp_icon_doc_icon( doc, root, name, psize, stride); -// if (px) { -// g_message("Found icon %s in %s", name, doc_filename); -// } } -// if (!px) { -// g_message("Not found icon %s", name); -// } return px; } @@ -1196,76 +1330,152 @@ void Inkscape::queueIconPrerender( Glib::ustring const &name, Inkscape::IconSize if (!stockFound && !themedFound ) { gint trySize = CLAMP( static_cast<gint>(lsize), 0, static_cast<gint>(G_N_ELEMENTS(iconSizeLookup) - 1) ); if ( !sizeMapDone ) { - injectCustomSize(); + IconImpl::injectCustomSize(); } GtkIconSize mappedSize = iconSizeLookup[trySize]; - int psize = sp_icon_get_phys_size(lsize); + int psize = IconImpl::getPhysSize(lsize); // TODO place in a queue that is triggered by other map events - prerender_icon(name.c_str(), mappedSize, psize); + IconImpl::prerenderIcon(name.c_str(), mappedSize, psize); + } +} + +static std::map<unsigned, Glib::ustring> sizePaths; + +static std::string getDestDir( unsigned psize ) +{ + if ( sizePaths.find(psize) == sizePaths.end() ) { + gchar *tmp = g_strdup_printf("%dx%d", psize, psize); + sizePaths[psize] = tmp; + g_free(tmp); } + + return sizePaths[psize]; } // returns true if icon needed preloading, false if nothing was done -bool prerender_icon(gchar const *name, GtkIconSize lsize, unsigned psize) +bool IconImpl::prerenderIcon(gchar const *name, GtkIconSize lsize, unsigned psize) { bool loadNeeded = false; static bool dump = Inkscape::Preferences::get()->getBool("/debug/icons/dumpGtk"); + static bool useCache = Inkscape::Preferences::get()->getBool("/debug/icons/useCache", true); + static bool cacheValidated = false; + if (!cacheValidated) { + cacheValidated = true; + if ( useCache ) { + validateCache(); + } + } Glib::ustring key = icon_cache_key(name, psize); if ( !get_cached_pixbuf(key) ) { if ((internalNames.find(name) != internalNames.end()) || (!gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), name))) { if (dump) { - g_message("prerender_icon [%s] %d:%d", name, lsize, psize); + g_message("prerenderIcon [%s] %d:%d", name, lsize, psize); } - unsigned stride; - guchar* px = load_svg_pixels(name, psize, stride); - if ( !px ) { - // check for a fallback name + + std::string potentialFile; + bool dataLoaded = false; + if ( useCache ) { + // In file encoding: + std::string iconCacheDir = Glib::build_filename(Glib::build_filename(Glib::get_user_cache_dir(), "inkscape"), "icons"); + std::string subpart = getDestDir(psize); + std::string subdir = Glib::build_filename( iconCacheDir, subpart ); + if ( !Glib::file_test(subdir, Glib::FILE_TEST_EXISTS) ) { + g_mkdir_with_parents( subdir.c_str(), 0x1ED ); + } + potentialFile = Glib::build_filename( subdir, name ); + potentialFile += ".png"; + + if ( Glib::file_test(potentialFile, Glib::FILE_TEST_EXISTS) && Glib::file_test(potentialFile, Glib::FILE_TEST_IS_REGULAR) ) { + bool badFile = false; + try { + Glib::RefPtr<Gdk::Pixbuf> pb = Gdk::Pixbuf::create_from_file(potentialFile); + if (pb) { + dataLoaded = true; + GdkPixbuf *obj = pb->gobj(); + g_object_ref(obj); + pb_cache[key] = obj; + addToIconSet(obj, name, lsize, psize); + loadNeeded = true; + if (internalNames.find(name) == internalNames.end()) { + internalNames.insert(name); + } + } + } catch ( Glib::FileError &ex ) { + //g_warning("FileError [%s]", ex.what().c_str()); + badFile = true; + } catch ( Gdk::PixbufError &ex ) { + //g_warning("PixbufError [%s]", ex.what().c_str()); + // Invalid contents. Remove cached item + badFile = true; + } + if ( badFile ) { + g_remove(potentialFile.c_str()); + } + } + } + + if (!dataLoaded) { + std::list<Glib::ustring> names; + names.push_back(name); if ( legacyNames.find(name) != legacyNames.end() ) { + names.push_back(legacyNames[name]); if ( dump ) { - g_message("load_svg_pixels([%s]=%s, %d, %d)", name, legacyNames[name].c_str(), lsize, psize); + g_message("load_svg_pixels([%s] = %s, %d, %d)", name, legacyNames[name].c_str(), lsize, psize); } - px = load_svg_pixels(legacyNames[name].c_str(), psize, stride); } - } - if (px) { - GdkPixbuf* pb = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, TRUE, 8, - psize, psize, stride, - reinterpret_cast<GdkPixbufDestroyNotify>(g_free), NULL ); - pb_cache[key] = pb; - addToIconSet(pb, name, lsize, psize); - loadNeeded = true; - if (internalNames.find(name) == internalNames.end()) { - internalNames.insert(name); + unsigned stride; + guchar* px = load_svg_pixels(names, psize, stride); + if (px) { + GdkPixbuf* pb = gdk_pixbuf_new_from_data( px, GDK_COLORSPACE_RGB, TRUE, 8, + psize, psize, stride, + reinterpret_cast<GdkPixbufDestroyNotify>(g_free), NULL ); + pb_cache[key] = pb; + addToIconSet(pb, name, lsize, psize); + loadNeeded = true; + if (internalNames.find(name) == internalNames.end()) { + internalNames.insert(name); + } + if (useCache) { + g_object_ref(pb); + Glib::RefPtr<Gdk::Pixbuf> ppp = Glib::wrap(pb); + try { + ppp->save( potentialFile, "png" ); + } catch ( Glib::FileError &ex ) { + //g_warning("FileError [%s]", ex.what().c_str()); + } catch ( Gdk::PixbufError &ex ) { + //g_warning("PixbufError [%s]", ex.what().c_str()); + } + } + } else if (dump) { + g_message("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX error!!! pixels not found for '%s'", name); } - } else if (dump) { - g_message("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX error!!! pixels not found for '%s'", name); } } else if (dump) { - g_message("prerender_icon [%s] %d NOT!!!!!!", name, psize); + g_message("prerenderIcon [%s] %d NOT!!!!!!", name, psize); } } return loadNeeded; } -static GdkPixbuf *sp_icon_image_load_svg(gchar const *name, GtkIconSize lsize, unsigned psize) +GdkPixbuf *IconImpl::loadSvg(std::list<Glib::ustring> const &names, GtkIconSize lsize, unsigned psize) { - Glib::ustring key = icon_cache_key(name, psize); + Glib::ustring key = icon_cache_key(*names.begin(), psize); // did we already load this icon at this scale/size? GdkPixbuf* pb = get_cached_pixbuf(key); if (!pb) { unsigned stride; - guchar *px = load_svg_pixels(name, psize, stride); + guchar *px = load_svg_pixels(names, psize, stride); if (px) { pb = gdk_pixbuf_new_from_data(px, GDK_COLORSPACE_RGB, TRUE, 8, psize, psize, stride, (GdkPixbufDestroyNotify)g_free, NULL); pb_cache[key] = pb; - addToIconSet(pb, name, lsize, psize); + addToIconSet(pb, names.begin()->c_str(), lsize, psize); } } @@ -1276,7 +1486,7 @@ static GdkPixbuf *sp_icon_image_load_svg(gchar const *name, GtkIconSize lsize, u return pb; } -void sp_icon_overlay_pixels(guchar *px, int width, int height, int stride, +void IconImpl::overlayPixels(guchar *px, int width, int height, int stride, unsigned r, unsigned g, unsigned b) { int bytesPerPixel = 4; @@ -1348,18 +1558,18 @@ public: static std::vector<preRenderItem> pendingRenders; static bool callbackHooked = false; -static void addPreRender( GtkIconSize lsize, gchar const *name ) +void IconImpl::addPreRender( GtkIconSize lsize, gchar const *name ) { if ( !callbackHooked ) { callbackHooked = true; - g_idle_add_full( G_PRIORITY_LOW, &icon_prerender_task, NULL, NULL ); + g_idle_add_full( G_PRIORITY_LOW, &prerenderTask, NULL, NULL ); } pendingRenders.push_back(preRenderItem(lsize, name)); } -gboolean icon_prerender_task(gpointer /*data*/) { +gboolean IconImpl::prerenderTask(gpointer /*data*/) { if ( inkscapeIsCrashing() ) { // stop } else if (!pendingRenders.empty()) { @@ -1367,8 +1577,8 @@ gboolean icon_prerender_task(gpointer /*data*/) { do { preRenderItem single = pendingRenders.front(); pendingRenders.erase(pendingRenders.begin()); - int psize = sp_icon_get_phys_size(single._lsize); - workDone = prerender_icon(single._name.c_str(), single._lsize, psize); + int psize = getPhysSize(single._lsize); + workDone = prerenderIcon(single._name.c_str(), single._lsize, psize); } while (!pendingRenders.empty() && !workDone); } @@ -1381,22 +1591,23 @@ gboolean icon_prerender_task(gpointer /*data*/) { } -void imageMapCB(GtkWidget* widget, gpointer user_data) { +void IconImpl::imageMapCB(GtkWidget* widget, gpointer user_data) +{ gchar* id = 0; GtkIconSize size = GTK_ICON_SIZE_INVALID; gtk_image_get_stock(GTK_IMAGE(widget), &id, &size); GtkIconSize lsize = static_cast<GtkIconSize>(GPOINTER_TO_INT(user_data)); if ( id ) { - int psize = sp_icon_get_phys_size(lsize); + int psize = getPhysSize(lsize); g_message("imageMapCB(%p) for [%s]:%d:%d", widget, id, lsize, psize); for ( std::vector<preRenderItem>::iterator it = pendingRenders.begin(); it != pendingRenders.end(); ++it ) { if ( (it->_name == id) && (it->_lsize == lsize) ) { - prerender_icon(id, lsize, psize); + prerenderIcon(id, lsize, psize); pendingRenders.erase(it); g_message(" prerender for %s:%d:%d", id, lsize, psize); if (lsize != size) { - int psize = sp_icon_get_phys_size(size); - prerender_icon(id, size, psize); + int psize = getPhysSize(size); + prerenderIcon(id, size, psize); } break; } @@ -1406,7 +1617,8 @@ void imageMapCB(GtkWidget* widget, gpointer user_data) { g_signal_handlers_disconnect_by_func(widget, (gpointer)imageMapCB, user_data); } -static void imageMapNamedCB(GtkWidget* widget, gpointer user_data) { +void IconImpl::imageMapNamedCB(GtkWidget* widget, gpointer user_data) +{ GtkImage* img = GTK_IMAGE(widget); gchar const* iconName = 0; GtkIconSize size = GTK_ICON_SIZE_INVALID; @@ -1426,8 +1638,8 @@ static void imageMapNamedCB(GtkWidget* widget, gpointer user_data) { for ( std::vector<preRenderItem>::iterator it = pendingRenders.begin(); it != pendingRenders.end(); ++it ) { if ( (it->_name == iconName) && (it->_lsize == size) ) { - int psize = sp_icon_get_phys_size(size); - prerender_icon(iconName, size, psize); + int psize = getPhysSize(size); + prerenderIcon(iconName, size, psize); pendingRenders.erase(it); break; } diff --git a/src/widgets/icon.h b/src/widgets/icon.h index f70423702..a20fad73a 100644 --- a/src/widgets/icon.h +++ b/src/widgets/icon.h @@ -6,8 +6,10 @@ * * Author: * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> * * Copyright (C) 2002 Lauris Kaplinski + * Copyright (C) 2010 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -16,12 +18,16 @@ #include "icon-size.h" -#define SP_TYPE_ICON (sp_icon_get_type ()) +#define SP_TYPE_ICON SPIcon::getType() #define SP_ICON(o) (GTK_CHECK_CAST ((o), SP_TYPE_ICON, SPIcon)) #define SP_IS_ICON(o) (GTK_CHECK_TYPE ((o), SP_TYPE_ICON)) #include <gtk/gtkwidget.h> +struct SPIconClass { + GtkWidgetClass parent_class; +}; + struct SPIcon { GtkWidget widget; @@ -30,13 +36,12 @@ struct SPIcon { gchar *name; GdkPixbuf *pb; -}; -struct SPIconClass { - GtkWidgetClass parent_class; + static GType getType(void); + + friend class SPIconImpl; }; -GType sp_icon_get_type (void); GtkWidget *sp_icon_new( Inkscape::IconSize size, const gchar *name ); @@ -54,3 +59,14 @@ namespace Inkscape { } #endif // SEEN_SP_ICON_H + +/* + 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:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 1d8acb40a..f0b55cf13 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -457,7 +457,7 @@ void SPPaintSelector::setSwatch(SPGradient *vector ) SwatchSelector *swatchsel = static_cast<SwatchSelector*>(g_object_get_data(G_OBJECT(selector), "swatch-selector")); if (swatchsel) { - swatchsel->setVector( (vector) ? SP_OBJECT_DOCUMENT(vector) : 0, vector ); + swatchsel->setVector( (vector) ? vector->document : 0, vector ); } } @@ -471,7 +471,7 @@ void SPPaintSelector::setGradientLinear(SPGradient *vector) SPGradientSelector *gsel = getGradientFromData(this); gsel->setMode(SPGradientSelector::MODE_LINEAR); - gsel->setVector((vector) ? SP_OBJECT_DOCUMENT(vector) : 0, vector); + gsel->setVector((vector) ? vector->document : 0, vector); } void SPPaintSelector::setGradientRadial(SPGradient *vector) @@ -485,7 +485,7 @@ void SPPaintSelector::setGradientRadial(SPGradient *vector) gsel->setMode(SPGradientSelector::MODE_RADIAL); - gsel->setVector((vector) ? SP_OBJECT_DOCUMENT(vector) : 0, vector); + gsel->setVector((vector) ? vector->document : 0, vector); } void SPPaintSelector::setGradientProperties( SPGradientUnits units, SPGradientSpread spread ) @@ -541,7 +541,7 @@ void SPPaintSelector::pushAttrsToGradient( SPGradient *gr ) const getGradientProperties( units, spread ); gr->setUnits(units); gr->setSpread(spread); - SP_OBJECT(gr)->updateRepr(); + gr->updateRepr(); } static void @@ -804,7 +804,7 @@ sp_pattern_menu_build (GtkWidget *m, GSList *pattern_list, SPDocument */*source* { for (; pattern_list != NULL; pattern_list = pattern_list->next) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) pattern_list->data); + Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(pattern_list->data)->getRepr(); GtkWidget *i = gtk_menu_item_new(); gtk_widget_show(i); @@ -950,7 +950,7 @@ void SPPaintSelector::updatePatternList( SPPattern *pattern ) gtk_object_set_data(GTK_OBJECT(mnu), "update", GINT_TO_POINTER(TRUE)); - gchar *patname = (gchar *) SP_OBJECT_REPR(pattern)->attribute("id"); + gchar const *patname = pattern->getRepr()->attribute("id"); GtkMenu *m = GTK_MENU(gtk_option_menu_get_menu(GTK_OPTION_MENU(mnu))); diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp index a0ec248ca..89253983b 100644 --- a/src/widgets/select-toolbar.cpp +++ b/src/widgets/select-toolbar.cpp @@ -242,7 +242,7 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw) gdouble strokewidth = stroke_average_width (selection->itemList()); int transform_stroke = prefs->getBool("/options/transform/stroke", true) ? 1 : 0; - Geom::Matrix scaler = get_scale_transform_with_stroke (*bbox, strokewidth, transform_stroke, x0, y0, x1, y1); + Geom::Affine scaler = get_scale_transform_with_stroke (*bbox, strokewidth, transform_stroke, x0, y0, x1, y1); sp_selection_apply_affine(selection, scaler); DocumentUndo::maybeDone(document, actionkey, SP_VERB_CONTEXT_SELECT, diff --git a/src/widgets/sp-attribute-widget.cpp b/src/widgets/sp-attribute-widget.cpp index 0c31c2f74..a64a03f4e 100644 --- a/src/widgets/sp-attribute-widget.cpp +++ b/src/widgets/sp-attribute-widget.cpp @@ -154,14 +154,12 @@ sp_attribute_widget_changed (GtkEditable *editable) if (!*text) text = NULL; - if (spaw->hasobj && spaw->src.object) { - - SP_OBJECT_REPR (spaw->src.object)->setAttribute(spaw->attribute, text, false); - DocumentUndo::done(SP_OBJECT_DOCUMENT (spaw->src.object), SP_VERB_NONE, + if (spaw->hasobj && spaw->src.object) { + spaw->src.object->getRepr()->setAttribute(spaw->attribute, text, false); + DocumentUndo::done(spaw->src.object->document, SP_VERB_NONE, _("Set attribute")); } else if (spaw->src.repr) { - spaw->src.repr->setAttribute(spaw->attribute, text, false); /* TODO: Warning! Undo will not be flushed in given case */ } @@ -248,7 +246,7 @@ sp_attribute_widget_set_object ( SPAttributeWidget *spaw, spaw->attribute = g_strdup (attribute); - val = SP_OBJECT_REPR (object)->attribute(attribute); + val = object->getRepr()->attribute(attribute); gtk_entry_set_text (GTK_ENTRY (spaw), val ? val : (const gchar *) ""); spaw->blocked = FALSE; } @@ -317,7 +315,7 @@ sp_attribute_widget_object_modified ( SPObject */*object*/, if (flags && SP_OBJECT_MODIFIED_FLAG) { const gchar *val, *text; - val = SP_OBJECT_REPR (spaw->src.object)->attribute(spaw->attribute); + val = spaw->src.object->getRepr()->attribute(spaw->attribute); text = gtk_entry_get_text (GTK_ENTRY (spaw)); if (val || text) { @@ -588,7 +586,7 @@ sp_attribute_table_set_object ( SPAttributeTable *spat, XPAD, YPAD ); w = gtk_entry_new (); gtk_widget_show (w); - val = SP_OBJECT_REPR (object)->attribute(attributes[i]); + val = object->getRepr()->attribute(attributes[i]); gtk_entry_set_text (GTK_ENTRY (w), val ? val : (const gchar *) ""); gtk_table_attach ( GTK_TABLE (spat->table), w, 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), @@ -719,7 +717,7 @@ sp_attribute_table_object_modified ( SPObject */*object*/, gint i; for (i = 0; i < spat->num_attr; i++) { const gchar *val, *text; - val = SP_OBJECT_REPR (spat->src.object)->attribute(spat->attributes[i]); + val = spat->src.object->getRepr()->attribute(spat->attributes[i]); text = gtk_entry_get_text (GTK_ENTRY (spat->entries[i])); if (val || text) { if (!val || !text || strcmp (val, text)) { @@ -763,8 +761,8 @@ sp_attribute_table_entry_changed ( GtkEditable *editable, text = NULL; if (spat->hasobj && spat->src.object) { - SP_OBJECT_REPR (spat->src.object)->setAttribute(spat->attributes[i], text, false); - DocumentUndo::done(SP_OBJECT_DOCUMENT (spat->src.object), SP_VERB_NONE, + spat->src.object->getRepr()->setAttribute(spat->attributes[i], text, false); + DocumentUndo::done(spat->src.object->document, SP_VERB_NONE, _("Set attribute")); } else if (spat->src.repr) { diff --git a/src/widgets/sp-attribute-widget.h b/src/widgets/sp-attribute-widget.h index 2703bd98a..617c5b012 100644 --- a/src/widgets/sp-attribute-widget.h +++ b/src/widgets/sp-attribute-widget.h @@ -14,6 +14,7 @@ #define SEEN_DIALOGS_SP_ATTRIBUTE_WIDGET_H #include <glib.h> +#include <stddef.h> #include <sigc++/connection.h> #define SP_TYPE_ATTRIBUTE_WIDGET (sp_attribute_widget_get_type ()) diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 8429434a6..174971555 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -22,6 +22,7 @@ #include <cstring> #include <string> #include <cstdlib> +#include <cstddef> #include <gtk/gtk.h> #include <glibmm/i18n.h> diff --git a/src/widgets/spw-utilities.cpp b/src/widgets/spw-utilities.cpp index 7c2956c65..49e3a7495 100644 --- a/src/widgets/spw-utilities.cpp +++ b/src/widgets/spw-utilities.cpp @@ -34,11 +34,19 @@ * position in the table. */ Gtk::Label * -spw_label(Gtk::Table *table, const gchar *label_text, int col, int row) +spw_label(Gtk::Table *table, const gchar *label_text, int col, int row, Gtk::Widget* target) { - Gtk::Label *label_widget = new Gtk::Label(label_text); + Gtk::Label *label_widget = new Gtk::Label(); g_assert(label_widget != NULL); - + if (target != NULL) + { + label_widget->set_text_with_mnemonic(label_text); + label_widget->set_mnemonic_widget(*target); + } + else + { + label_widget->set_text(label_text); + } label_widget->set_alignment(1.0, 0.5); label_widget->show(); table->attach(*label_widget, col, col+1, row, row+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 4, 0); diff --git a/src/widgets/spw-utilities.h b/src/widgets/spw-utilities.h index d17762811..9a387454f 100644 --- a/src/widgets/spw-utilities.h +++ b/src/widgets/spw-utilities.h @@ -20,6 +20,7 @@ #include <glib/gtypes.h> #include <gtk/gtkstyle.h> /* GtkWidget */ +#include <gtkmm/widget.h> namespace Gtk { class Label; @@ -28,7 +29,7 @@ namespace Gtk { } Gtk::Label * -spw_label(Gtk::Table *table, gchar const *label_text, int col, int row); +spw_label(Gtk::Table *table, gchar const *label_text, int col, int row, Gtk::Widget *target); GtkWidget * spw_label_old(GtkWidget *table, gchar const *label_text, int col, int row); diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 7226b970e..5288b5102 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -161,11 +161,11 @@ sp_marker_prev_new(unsigned psize, gchar const *mname, // Create a copy repr of the marker with id="sample" Inkscape::XML::Document *xml_doc = sandbox->getReprDoc(); - Inkscape::XML::Node *mrepr = SP_OBJECT_REPR (marker)->duplicate(xml_doc); + Inkscape::XML::Node *mrepr = marker->getRepr()->duplicate(xml_doc); mrepr->setAttribute("id", "sample"); // Replace the old sample in the sandbox by the new one - Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (sandbox->getObjectById("defs")); + Inkscape::XML::Node *defsrepr = sandbox->getObjectById("defs")->getRepr(); SPObject *oldmarker = sandbox->getObjectById("sample"); if (oldmarker) oldmarker->deleteObject(false); @@ -186,7 +186,7 @@ sp_marker_prev_new(unsigned psize, gchar const *mname, return NULL; // sandbox broken? // Find object's bbox in document - Geom::Matrix const i2doc(SP_ITEM(object)->i2doc_affine()); + Geom::Affine const i2doc(SP_ITEM(object)->i2doc_affine()); Geom::OptRect dbox = SP_ITEM(object)->getBounds(i2doc); if (!dbox) { @@ -225,7 +225,7 @@ ink_marker_list_get (SPDocument *source) GSList *ml = NULL; SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS (source); - for ( SPObject *child = SP_OBJECT(defs)->firstChild(); child; child = child->getNext() ) + for ( SPObject *child = defs->firstChild(); child; child = child->getNext() ) { if (SP_IS_MARKER(child)) { ml = g_slist_prepend (ml, child); @@ -248,14 +248,15 @@ sp_marker_menu_build (Gtk::Menu *m, GSList *marker_list, SPDocument *source, SPD NRArenaItem *root = SP_ITEM(sandbox->getRoot())->invoke_show((NRArena *) arena, visionkey, SP_ITEM_SHOW_DISPLAY); for (; marker_list != NULL; marker_list = marker_list->next) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) marker_list->data); + Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(marker_list->data)->getRepr(); Gtk::MenuItem *i = new Gtk::MenuItem(); i->show(); - if (repr->attribute("inkscape:stockid")) + if (repr->attribute("inkscape:stockid")) { i->set_data("stockid", (void *) "true"); - else + } else { i->set_data("stockid", (void *) "false"); + } gchar const *markid = repr->attribute("id"); i->set_data("marker", (void *) markid); @@ -468,7 +469,7 @@ sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const wh if (!strcmp(stockid,"true")) markurn = g_strconcat("urn:inkscape:marker:",markid,NULL); SPObject *mark = get_stock_item(markurn); if (mark) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR(mark); + Inkscape::XML::Node *repr = mark->getRepr(); marker = g_strconcat("url(#", repr->attribute("id"), ")", NULL); } } else { @@ -486,16 +487,17 @@ sp_marker_select(Gtk::OptionMenu *mnu, Gtk::Container *spw, SPMarkerLoc const wh Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); for (; items != NULL; items = items->next) { - SPItem *item = (SPItem *) items->data; - if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) // can't set marker to rect, until it's converted to using <path> - continue; - Inkscape::XML::Node *selrepr = SP_OBJECT_REPR((SPItem *) items->data); - if (selrepr) { - sp_repr_css_change_recursive(selrepr, css, "style"); - } - SP_OBJECT(items->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); - SP_OBJECT(items->data)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); - } + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using <path> + continue; + } + Inkscape::XML::Node *selrepr = item->getRepr(); + if (selrepr) { + sp_repr_css_change_recursive(selrepr, css, "style"); + } + item->requestModified(SP_OBJECT_MODIFIED_FLAG); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + } sp_repr_css_attr_unref(css); css = 0; @@ -673,7 +675,7 @@ sp_stroke_style_line_widget_new(void) gint i = 0; - spw_label(t, C_("Stroke width", "Width:"), 0, i); + //spw_label(t, C_("Stroke width", "_Width:"), 0, i); hb = spw_hbox(t, 3, 1, i); @@ -689,6 +691,7 @@ sp_stroke_style_line_widget_new(void) sb = new Gtk::SpinButton(*a, 0.1, 3); tt->set_tip(*sb, _("Stroke width")); sb->show(); + spw_label(t, C_("Stroke width", "_Width:"), 0, i, sb); sp_dialog_defocus_on_enter_cpp(sb); @@ -711,7 +714,7 @@ sp_stroke_style_line_widget_new(void) /* Join type */ // TRANSLATORS: The line join style specifies the shape to be used at the // corners of paths. It can be "miter", "round" or "bevel". - spw_label(t, _("Join:"), 0, i); + spw_label(t, _("Join:"), 0, i, NULL); hb = spw_hbox(t, 3, 1, i); @@ -755,7 +758,7 @@ sp_stroke_style_line_widget_new(void) // spike that extends well beyond the connection point. The purpose of the // miter limit is to cut off such spikes (i.e. convert them into bevels) // when they become too long. - spw_label(t, _("Miter limit:"), 0, i); + //spw_label(t, _("Miter _limit:"), 0, i); hb = spw_hbox(t, 3, 1, i); @@ -765,6 +768,7 @@ sp_stroke_style_line_widget_new(void) sb = new Gtk::SpinButton(*a, 0.1, 2); tt->set_tip(*sb, _("Maximum length of the miter (in units of stroke width)")); sb->show(); + spw_label(t, _("Miter _limit:"), 0, i, sb); spw->set_data("miterlimit_sb", sb); sp_dialog_defocus_on_enter_cpp(sb); @@ -775,7 +779,8 @@ sp_stroke_style_line_widget_new(void) /* Cap type */ // TRANSLATORS: cap type specifies the shape for the ends of lines - spw_label(t, _("Cap:"), 0, i); + //spw_label(t, _("_Cap:"), 0, i); + spw_label(t, _("Cap:"), 0, i, NULL); hb = spw_hbox(t, 3, 1, i); @@ -809,7 +814,11 @@ sp_stroke_style_line_widget_new(void) /* Dash */ - spw_label(t, _("Dashes:"), 0, i); + spw_label(t, _("Dashes:"), 0, i, NULL); //no mnemonic for now + //decide what to do: + // implement a set_mnemonic_source function in the + // SPDashSelector class, so that we do not have to + // expose any of the underlying widgets? ds = manage(new SPDashSelector); ds->show(); @@ -826,8 +835,9 @@ sp_stroke_style_line_widget_new(void) // TRANSLATORS: Path markers are an SVG feature that allows you to attach arbitrary shapes // (arrowheads, bullets, faces, whatever) to the start, end, or middle nodes of a path. - spw_label(t, _("Start Markers:"), 0, i); + //spw_label(t, _("_Start Markers:"), 0, i); marker_start_menu = ink_marker_menu(spw ,"marker-start", sandbox); + spw_label(t, _("_Start Markers:"), 0, i, marker_start_menu); tt->set_tip(*marker_start_menu, _("Start Markers are drawn on the first node of a path or shape")); marker_start_menu_connection = marker_start_menu->signal_changed().connect( sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( @@ -837,8 +847,9 @@ sp_stroke_style_line_widget_new(void) spw->set_data("start_mark_menu", marker_start_menu); i++; - spw_label(t, _("Mid Markers:"), 0, i); + //spw_label(t, _("_Mid Markers:"), 0, i); marker_mid_menu = ink_marker_menu(spw ,"marker-mid", sandbox); + spw_label(t, _("_Mid Markers:"), 0, i, marker_mid_menu); tt->set_tip(*marker_mid_menu, _("Mid Markers are drawn on every node of a path or shape except the first and last nodes")); marker_mid_menu_connection = marker_mid_menu->signal_changed().connect( sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( @@ -848,8 +859,9 @@ sp_stroke_style_line_widget_new(void) spw->set_data("mid_mark_menu", marker_mid_menu); i++; - spw_label(t, _("End Markers:"), 0, i); + //spw_label(t, _("_End Markers:"), 0, i); marker_end_menu = ink_marker_menu(spw ,"marker-end", sandbox); + spw_label(t, _("_End Markers:"), 0, i, marker_end_menu); tt->set_tip(*marker_end_menu, _("End Markers are drawn on the last node of a path or shape")); marker_end_menu_connection = marker_end_menu->signal_changed().connect( sigc::bind<Gtk::OptionMenu *, Gtk::Container *, SPMarkerLoc>( @@ -1081,7 +1093,7 @@ sp_stroke_style_line_update(Gtk::Container *spw, Inkscape::Selection *sel) GSList const *objects = sel->itemList(); SPObject * const object = SP_OBJECT(objects->data); - SPStyle * const style = SP_OBJECT_STYLE(object); + SPStyle * const style = object->style; /* Markers */ sp_stroke_style_update_marker_menus(spw, objects); // FIXME: make this desktop query too @@ -1164,7 +1176,7 @@ sp_stroke_style_scale_line(Gtk::Container *spw) if (unit->base == SP_UNIT_ABSOLUTE || unit->base == SP_UNIT_DEVICE) { width = sp_units_get_pixels (width_typed, *unit); } else { // percentage - gdouble old_w = SP_OBJECT_STYLE (i->data)->stroke_width.computed; + gdouble old_w = SP_OBJECT(i->data)->style->stroke_width.computed; width = old_w * width_typed / 100; } @@ -1352,14 +1364,16 @@ ink_marker_menu_set_current(SPObject *marker, Gtk::OptionMenu *mnu) Gtk::Menu *m = mnu->get_menu(); if (marker != NULL) { bool mark_is_stock = false; - if (SP_OBJECT_REPR(marker)->attribute("inkscape:stockid")) + if (marker->getRepr()->attribute("inkscape:stockid")) { mark_is_stock = true; + } - gchar *markname; - if (mark_is_stock) - markname = g_strdup(SP_OBJECT_REPR(marker)->attribute("inkscape:stockid")); - else - markname = g_strdup(SP_OBJECT_REPR(marker)->attribute("id")); + gchar *markname = 0; + if (mark_is_stock) { + markname = g_strdup(marker->getRepr()->attribute("inkscape:stockid")); + } else { + markname = g_strdup(marker->getRepr()->attribute("id")); + } int markpos = ink_marker_menu_get_pos(m, markname); mnu->set_history(markpos); @@ -1417,7 +1431,7 @@ sp_stroke_style_update_marker_menus(Gtk::Container *spw, GSList const *objects) // If the object has this type of markers, // Extract the name of the marker that the object uses - SPObject *marker = ink_extract_marker_name(object->style->marker[keyloc[i].loc].value, SP_OBJECT_DOCUMENT(object)); + SPObject *marker = ink_extract_marker_name(object->style->marker[keyloc[i].loc].value, object->document); // Scroll the menu to that marker ink_marker_menu_set_current(marker, mnu); diff --git a/src/widgets/swatch-selector.cpp b/src/widgets/swatch-selector.cpp index 935282a3a..cd624630b 100644 --- a/src/widgets/swatch-selector.cpp +++ b/src/widgets/swatch-selector.cpp @@ -133,9 +133,9 @@ void SwatchSelector::_changedCb(SPColorSelector */*csel*/, void *data) gchar c[64]; sp_svg_write_color(c, sizeof(c), rgb); os << "stop-color:" << c << ";stop-opacity:" << static_cast<gdouble>(alpha) <<";"; - SP_OBJECT_REPR(stop)->setAttribute("style", os.str().c_str()); + stop->getRepr()->setAttribute("style", os.str().c_str()); - DocumentUndo::done(SP_OBJECT_DOCUMENT(ngr), SP_VERB_CONTEXT_GRADIENT, + DocumentUndo::done(ngr->document, SP_VERB_CONTEXT_GRADIENT, _("Change swatch color")); } } @@ -169,7 +169,7 @@ void SwatchSelector::connectchangedHandler( GCallback handler, void *data ) void SwatchSelector::setVector(SPDocument */*doc*/, SPGradient *vector) { //GtkVBox * box = gobj(); - _gsel->setVector((vector) ? SP_OBJECT_DOCUMENT(vector) : 0, vector); + _gsel->setVector((vector) ? vector->document : 0, vector); if ( vector && vector->isSolid() ) { SPStop* stop = vector->getFirstStop(); diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 28b4c9fb2..db86ff8a0 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -332,7 +332,6 @@ static gchar const * ui_descr = " <toolbar name='SprayToolbar'>" " <toolitem action='SprayModeAction' />" " <separator />" - " <separator />" " <toolitem action='SprayWidthAction' />" " <toolitem action='SprayPressureAction' />" " <toolitem action='SprayPopulationAction' />" @@ -469,9 +468,9 @@ static gchar const * ui_descr = " </toolbar>" " <toolbar name='EraserToolbar'>" - " <toolitem action='EraserWidthAction' />" - " <separator />" " <toolitem action='EraserModeAction' />" + " <separator />" + " <toolitem action='EraserWidthAction' />" " </toolbar>" " <toolbar name='TextToolbar'>" @@ -2041,14 +2040,14 @@ static void toggle_snap_callback(GtkToggleAction *act, gpointer data) //data poi SPDesktop *dt = reinterpret_cast<SPDesktop*>(ptr); SPNamedView *nv = sp_desktop_namedview(dt); - SPDocument *doc = SP_OBJECT_DOCUMENT(nv); + SPDocument *doc = nv->document; if (dt == NULL || nv == NULL) { g_warning("No desktop or namedview specified (in toggle_snap_callback)!"); return; } - Inkscape::XML::Node *repr = SP_OBJECT_REPR(nv); + Inkscape::XML::Node *repr = nv->getRepr(); if (repr == NULL) { g_warning("This namedview doesn't have a xml representation attached!"); @@ -2520,13 +2519,14 @@ static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKlu Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); for (; items != NULL; items = items->next) { - if (SP_IS_STAR((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value); sp_repr_set_svg_double(repr, "sodipodi:arg2", (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5) + M_PI / (gint)adj->value)); - SP_OBJECT((SPItem *) items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -2561,8 +2561,9 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); for (; items != NULL; items = items->next) { - if (SP_IS_STAR((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0); gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0); @@ -2572,7 +2573,7 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value); } - SP_OBJECT((SPItem *) items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -2613,10 +2614,11 @@ static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *d } for (; items != NULL; items = items->next) { - if (SP_IS_STAR((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" ); - SP_OBJECT((SPItem *) items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -2651,10 +2653,11 @@ static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludg Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); for (; items != NULL; items = items->next) { - if (SP_IS_STAR((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value); - SP_OBJECT(items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -2688,10 +2691,11 @@ static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKl Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); for (; items != NULL; items = items->next) { - if (SP_IS_STAR((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { + Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value); - SP_OBJECT(items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -2783,9 +2787,10 @@ sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) items != NULL; items = items->next) { - if (SP_IS_STAR((SPItem *) items->data)) { + SPItem* item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_STAR(item)) { n_selected++; - repr = SP_OBJECT_REPR((SPItem *) items->data); + repr = item->getRepr(); } } @@ -3055,7 +3060,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * if (adj->value != 0) { setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit)); } else { - SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL); + SP_OBJECT(items->data)->getRepr()->setAttribute(value_name, NULL); } modmade = true; } @@ -3184,10 +3189,10 @@ static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GO for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { - if (SP_IS_RECT((SPItem *) items->data)) { + if (SP_IS_RECT(reinterpret_cast<SPItem *>(items->data))) { n_selected++; - item = (SPItem *) items->data; - repr = SP_OBJECT_REPR(item); + item = reinterpret_cast<SPItem *>(items->data); + repr = item->getRepr(); } } @@ -3474,7 +3479,7 @@ static void box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObj // FIXME: Also deal with multiple selected boxes SPBox3D *box = SP_BOX3D(item); Persp3D *persp = box3d_get_perspective(box); - persp_repr = SP_OBJECT_REPR(persp); + persp_repr = persp->getRepr(); if (persp_repr) { g_object_set_data(tbl, "repr", persp_repr); Inkscape::GC::anchor(persp_repr); @@ -3513,7 +3518,7 @@ static void box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, P Persp3D *persp = sel_persps.front(); persp->perspective_impl->tmat.set_infinite_direction (axis, adj->value); - SP_OBJECT(persp)->updateRepr(); + persp->updateRepr(); // TODO: use the correct axis here, too DocumentUndo::maybeDone(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)")); @@ -3731,10 +3736,11 @@ static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustr items != NULL; items = items->next) { - if (SP_IS_SPIRAL((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_SPIRAL(item)) { + Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double( repr, namespaced_name, adj->value ); - SP_OBJECT((SPItem *) items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -3841,9 +3847,10 @@ static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, items != NULL; items = items->next) { - if (SP_IS_SPIRAL((SPItem *) items->data)) { + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_SPIRAL(item)) { n_selected++; - repr = SP_OBJECT_REPR((SPItem *) items->data); + repr = item->getRepr(); } } @@ -4601,10 +4608,10 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction { /* Mean */ - gchar const* labels[] = {_("(minimum mean)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum mean)")}; - gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; + gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(maximum mean)")}; + gdouble values[] = {0, 5, 10, 20, 30, 50, 70, 100}; EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction", - _("Focus"), _("Focus:"), _("0 to spray a spot. Increase to enlarge the ring radius."), + _("Focus"), _("Focus:"), _("0 to spray a spot; increase to enlarge the ring radius"), "/tools/spray/mean", 0, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-mean", 0, 100, 1.0, 10.0, @@ -4617,13 +4624,10 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction { /* Standard_deviation */ - gchar const* labels[] = {_("(minimum scatter)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum scatter)")}; + gchar const* labels[] = {_("(minimum scatter)"), 0, 0, 0, 0, 0, _("(default)"), _("(maximum scatter)")}; gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; - - //TRANSLATORS: only translate "string" in "context|string". - // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction", - Q_("Toolbox|Scatter"), Q_("Toolbox|Scatter:"), _("Increase to scatter sprayed objects."), + C_("Spray tool", "Scatter"), C_("Spray tool", "Scatter:"), _("Increase to scatter sprayed objects"), "/tools/spray/standard_deviation", 70, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-standard_deviation", 1, 100, 1.0, 10.0, @@ -4680,11 +4684,11 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction } { /* Population */ - gchar const* labels[] = {_("(low population)"), 0, 0, _("(default)"), 0, 0, _("(high population)")}; - gdouble values[] = {10, 25, 35, 50, 60, 80, 100}; + gchar const* labels[] = {_("(low population)"), 0, 0, 0, _("(default)"), 0, _("(high population)")}; + gdouble values[] = {5, 20, 35, 50, 70, 85, 100}; EgeAdjustmentAction *eact = create_adjustment_action( "SprayPopulationAction", _("Amount"), _("Amount:"), - _("Adjusts the number of items sprayed per clic."), + _("Adjusts the number of items sprayed per clic"), "/tools/spray/population", 70, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-population", 1, 100, 1.0, 10.0, @@ -4700,21 +4704,22 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction { InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction", _("Pressure"), - _("Use the pressure of the input device to alter the amount of sprayed objects."), + _("Use the pressure of the input device to alter the amount of sprayed objects"), "use_pressure", Inkscape::ICON_SIZE_DECORATION ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_spray_pressure_state_changed), NULL); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/usepressure", true) ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressure"); + g_signal_connect(holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } { /* Rotation */ - gchar const* labels[] = {_("(low rotation variation)"), 0, 0, _("(default)"), 0, 0, _("(high rotation variation)")}; - gdouble values[] = {10, 25, 35, 50, 60, 80, 100}; + gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(high rotation variation)")}; + gdouble values[] = {0, 10, 25, 35, 50, 60, 80, 100}; EgeAdjustmentAction *eact = create_adjustment_action( "SprayRotationAction", _("Rotation"), _("Rotation:"), // xgettext:no-c-format - _("Variation of the rotation of the sprayed objects. 0% for the same rotation than the original object."), + _("Variation of the rotation of the sprayed objects; 0% for the same rotation than the original object"), "/tools/spray/rotation_variation", 0, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-rotation", 0, 100, 1.0, 10.0, @@ -4727,15 +4732,12 @@ static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction } { /* Scale */ - gchar const* labels[] = {_("(low scale variation)"), 0, 0, _("(default)"), 0, 0, _("(high scale variation)")}; - gdouble values[] = {10, 25, 35, 50, 60, 80, 100}; - - //TRANSLATORS: only translate "string" in "context|string". - // For more details, see http://developer.gnome.org/doc/API/2.0/glib/glib-I18N.html#Q-:CAPS + gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(high scale variation)")}; + gdouble values[] = {0, 10, 25, 35, 50, 60, 80, 100}; EgeAdjustmentAction *eact = create_adjustment_action( "SprayScaleAction", - Q_("Toolbox|Scale"), Q_("Toolbox|Scale:"), + C_("Spray tool", "Scale"), C_("Spray tool", "Scale:"), // xgettext:no-c-format - _("Variation in the scale of the sprayed objects. 0% for the same scale than the original object."), + _("Variation in the scale of the sprayed objects; 0% for the same scale than the original object"), "/tools/spray/scale_variation", 0, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-scale", 0, 100, 1.0, 10.0, @@ -5395,10 +5397,11 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) items != NULL; items = items->next) { - if (SP_IS_ARC((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem*>(items->data); + if (SP_IS_ARC(item)) { + Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", "true"); - SP_OBJECT((SPItem *) items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -5407,10 +5410,11 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) items != NULL; items = items->next) { - if (SP_IS_ARC((SPItem *) items->data)) { - Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data); + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_ARC(item)) { + Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", NULL); - SP_OBJECT((SPItem *) items->data)->updateRepr(); + item->updateRepr(); modmade = true; } } @@ -5496,9 +5500,10 @@ static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GOb items != NULL; items = items->next) { - if (SP_IS_ARC((SPItem *) items->data)) { + SPItem *item = reinterpret_cast<SPItem *>(items->data); + if (SP_IS_ARC(item)) { n_selected++; - repr = SP_OBJECT_REPR((SPItem *) items->data); + repr = item->getRepr(); } } @@ -6107,23 +6112,6 @@ static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl ) static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) { { - /* Width */ - gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")}; - gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; - EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction", - _("Pen Width"), _("Width:"), - _("The width of the eraser pen (relative to the visible canvas area)"), - "/tools/eraser/width", 15, - GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser", - 1, 100, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - sp_erc_width_value_changed, 1, 0); - ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } - - { GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); GtkTreeIter iter; @@ -6142,9 +6130,10 @@ static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio -1 ); EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act, "short_label", _("Mode:"), NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); g_object_set_data( holder, "eraser_mode_action", act ); - + ege_select_one_action_set_appearance( act, "full" ); ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); @@ -6158,6 +6147,23 @@ static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActio g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder ); } + { + /* Width */ + gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")}; + gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction", + _("Pen Width"), _("Width:"), + _("The width of the eraser pen (relative to the visible canvas area)"), + "/tools/eraser/width", 15, + GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_erc_width_value_changed, 1, 0); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + } //######################## @@ -6185,7 +6191,7 @@ static void sp_print_font( SPStyle *query ) { << (query->text->font_specification.value ? query->text->font_specification.value : "No value") << std::endl; } - + static void sp_print_fontweight( SPStyle *query ) { const gchar* names[] = {"100", "200", "300", "400", "500", "600", "700", "800", "900", "NORMAL", "BOLD", "LIGHTER", "BOLDER", "Out of range"}; @@ -6385,8 +6391,10 @@ static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GOb g_free (family); // Save for undo - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, + if (result_fontspec != QUERY_STYLE_NOTHING) { + DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, _("Text: Change font family")); + } sp_repr_css_attr_unref (css); // unfreeze @@ -6431,10 +6439,6 @@ static void sp_text_fontsize_value_changed( Ink_ComboBoxEntry_Action *act, GObje SPDesktop *desktop = SP_ACTIVE_DESKTOP; sp_desktop_set_style (desktop, css, true, true); - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE, - _("Text: Change font size")); - // If no selected objects, set default. SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); int result_numbers = @@ -6443,7 +6447,12 @@ static void sp_text_fontsize_value_changed( Ink_ComboBoxEntry_Action *act, GObje { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->mergeStyle("/tools/text/style", css); + } else { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE, + _("Text: Change font size")); } + sp_style_unref(query); sp_repr_css_attr_unref (css); @@ -6578,8 +6587,10 @@ static void sp_text_style_changed( InkToggleAction* act, GObject *tbl ) // Do we need to update other CSS values? SPDesktop *desktop = SP_ACTIVE_DESKTOP; sp_desktop_set_style (desktop, css, true, true); - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, + if (result_fontspec != QUERY_STYLE_NOTHING) { + DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, _("Text: Change font style")); + } sp_repr_css_attr_unref (css); g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); @@ -6655,9 +6666,10 @@ static void sp_text_script_changed( InkToggleAction* act, GObject *tbl ) sp_desktop_set_style (desktop, css, true, false); // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:script", SP_VERB_NONE, + if(result_baseline != QUERY_STYLE_NOTHING) { + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:script", SP_VERB_NONE, _("Text: Change superscript or subscript")); - + } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } @@ -6682,7 +6694,7 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) if (SP_IS_TEXT((SPItem *) items->data)) { SPItem *item = SP_ITEM(items->data); - unsigned writing_mode = SP_OBJECT_STYLE(item)->writing_mode.value; + unsigned writing_mode = item->style->writing_mode.value; // below, variable names suggest horizontal move, but we check the writing direction // and move in the corresponding axis int axis; @@ -6702,7 +6714,7 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) // frame (currently unused) double left_slack = 0; double right_slack = 0; - unsigned old_align = SP_OBJECT_STYLE(item)->text_align.value; + unsigned old_align = item->style->text_align.value; double move = 0; if (old_align == SP_CSS_TEXT_ALIGN_START || old_align == SP_CSS_TEXT_ALIGN_LEFT) { switch (mode) { @@ -6748,8 +6760,8 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) XY = XY + Geom::Point (0, move); } SP_TEXT(item)->attributes.setFirstXY(XY); - SP_OBJECT(item)->updateRepr(); - SP_OBJECT(item)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); + item->updateRepr(); + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } } @@ -6799,8 +6811,11 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) sp_style_unref(query); sp_desktop_set_style (desktop, css, true, true); - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, + if (result_numbers != QUERY_STYLE_NOTHING) + { + DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, _("Text: Change alignment")); + } sp_repr_css_attr_unref (css); gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas)); @@ -6831,15 +6846,19 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) // Until deprecated sodipodi:linespacing purged: Inkscape::Selection *selection = sp_desktop_selection(desktop); GSList const *items = selection->itemList(); + bool modmade = false; for (; items != NULL; items = items->next) { if (SP_IS_TEXT (items->data)) { - SP_OBJECT_REPR(items->data)->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); + SP_OBJECT(items->data)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); + modmade = true; } } // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:line-height", SP_VERB_NONE, + if(modmade) { + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:line-height", SP_VERB_NONE, _("Text: Change line-height")); + } // If no selected objects, set default. SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); @@ -6876,10 +6895,6 @@ static void sp_text_wordspacing_value_changed( GtkAdjustment *adj, GObject *tbl SPDesktop *desktop = SP_ACTIVE_DESKTOP; sp_desktop_set_style (desktop, css, true, false); - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:word-spacing", SP_VERB_NONE, - _("Text: Change word-spacing")); - // If no selected objects, set default. SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); int result_numbers = @@ -6888,6 +6903,10 @@ static void sp_text_wordspacing_value_changed( GtkAdjustment *adj, GObject *tbl { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->mergeStyle("/tools/text/style", css); + } else { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:word-spacing", SP_VERB_NONE, + _("Text: Change word-spacing")); } sp_style_unref(query); @@ -6915,9 +6934,6 @@ static void sp_text_letterspacing_value_changed( GtkAdjustment *adj, GObject *tb SPDesktop *desktop = SP_ACTIVE_DESKTOP; sp_desktop_set_style (desktop, css, true, false); - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:letter-spacing", SP_VERB_NONE, - _("Text: Change letter-spacing")); // If no selected objects, set default. SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); @@ -6928,8 +6944,16 @@ static void sp_text_letterspacing_value_changed( GtkAdjustment *adj, GObject *tb Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->mergeStyle("/tools/text/style", css); } + else + { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:letter-spacing", SP_VERB_NONE, + _("Text: Change letter-spacing")); + } + sp_style_unref(query); + sp_repr_css_attr_unref (css); g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); @@ -6945,6 +6969,7 @@ static void sp_text_dx_value_changed( GtkAdjustment *adj, GObject *tbl ) g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); gdouble new_dx = adj->value; + bool modmade = false; if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); @@ -6956,14 +6981,16 @@ static void sp_text_dx_value_changed( GtkAdjustment *adj, GObject *tbl ) double old_dx = attributes->getDx( char_index ); double delta_dx = new_dx - old_dx; sp_te_adjust_dx( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dx ); + modmade = true; } } } - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dx", SP_VERB_NONE, + if(modmade) { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dx", SP_VERB_NONE, _("Text: Change dx (kern)")); - + } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } @@ -6976,6 +7003,7 @@ static void sp_text_dy_value_changed( GtkAdjustment *adj, GObject *tbl ) g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); gdouble new_dy = adj->value; + bool modmade = false; if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); @@ -6987,13 +7015,16 @@ static void sp_text_dy_value_changed( GtkAdjustment *adj, GObject *tbl ) double old_dy = attributes->getDy( char_index ); double delta_dy = new_dy - old_dy; sp_te_adjust_dy( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_dy ); + modmade = true; } } } - // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dy", SP_VERB_NONE, + if(modmade) { + // Save for undo + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:dy", SP_VERB_NONE, _("Text: Change dy")); + } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } @@ -7008,6 +7039,7 @@ static void sp_text_rotation_value_changed( GtkAdjustment *adj, GObject *tbl ) gdouble new_degrees = adj->value; + bool modmade = false; if( SP_IS_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context) ) { SPTextContext *const tc = SP_TEXT_CONTEXT((SP_ACTIVE_DESKTOP)->event_context); if( tc ) { @@ -7018,13 +7050,16 @@ static void sp_text_rotation_value_changed( GtkAdjustment *adj, GObject *tbl ) double old_degrees = attributes->getRotate( char_index ); double delta_deg = new_degrees - old_degrees; sp_te_adjust_rotation( tc->text, tc->text_sel_start, tc->text_sel_end, SP_ACTIVE_DESKTOP, delta_deg ); - } + modmade = true; + } } } // Save for undo - DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:rotate", SP_VERB_NONE, + if(modmade) { + DocumentUndo::maybeDone(sp_desktop_document(SP_ACTIVE_DESKTOP), "ttb:rotate", SP_VERB_NONE, _("Text: Change rotate")); + } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } @@ -7068,8 +7103,11 @@ static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject * } sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true); - DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, + if(result_numbers != QUERY_STYLE_NOTHING) + { + DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, _("Text: Change orientation")); + } sp_repr_css_attr_unref (css); g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); @@ -7217,7 +7255,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ // Superscript gboolean superscriptSet = - ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && + ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && query->baseline_shift.set && query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER ); @@ -7228,7 +7266,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ // Subscript gboolean subscriptSet = - ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && + ((result_baseline == QUERY_STYLE_SINGLE || result_baseline == QUERY_STYLE_MULTIPLE_SAME ) && query->baseline_shift.set && query->baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && query->baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB ); @@ -7302,7 +7340,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ double letterSpacing; if (query->letter_spacing.normal) letterSpacing = 0.0; else letterSpacing = query->letter_spacing.computed; // Assume no units (change in desktop-style.cpp) - + GtkAction* letterSpacingAction = GTK_ACTION( g_object_get_data( tbl, "TextLetterSpacingAction" ) ); GtkAdjustment *letterSpacingAdjustment = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( letterSpacingAction )); @@ -7639,7 +7677,7 @@ static void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions /* Line height */ { // Drop down menu - gchar const* labels[] = {_("Smaller spacing"), 0, 0, 0, 0, _("Normal"), 0, 0, 0, 0, 0, _("Larger spacing")}; + gchar const* labels[] = {_("Smaller spacing"), 0, 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, _("Larger spacing")}; gdouble values[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1,2, 1.3, 1.4, 1.5, 2.0}; EgeAdjustmentAction *eact = create_adjustment_action( @@ -7670,7 +7708,7 @@ static void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions /* Word spacing */ { // Drop down menu - gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, _("Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; + gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; EgeAdjustmentAction *eact = create_adjustment_action( @@ -7701,7 +7739,7 @@ static void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions /* Letter spacing */ { // Drop down menu - gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, _("Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; + gchar const* labels[] = {_("Negative spacing"), 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, 0, 0, _("Positive spacing")}; gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; EgeAdjustmentAction *eact = create_adjustment_action( @@ -7913,10 +7951,11 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl if (!modmade) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setBool("/tools/connector/orthogonal", is_orthog); - } + } else { - DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, + DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, is_orthog ? _("Set connector type: orthogonal"): _("Set connector type: polyline")); + } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } @@ -7962,9 +8001,10 @@ static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setDouble(Glib::ustring("/tools/connector/curvature"), newValue); } - - DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, + else { + DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, _("Change connector curvature")); + } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } @@ -7979,7 +8019,7 @@ static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl) return; } - Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview); + Inkscape::XML::Node *repr = desktop->namedview->getRepr(); if ( !repr->attribute("inkscape:connector-spacing") && ( adj->value == defaultConnSpacing )) { @@ -7998,22 +8038,24 @@ static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl) g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE)); sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value); - SP_OBJECT(desktop->namedview)->updateRepr(); + desktop->namedview->updateRepr(); + bool modmade = false; GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop); for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) { SPItem *item = reinterpret_cast<SPItem *>(iter->data); - Geom::Matrix m = Geom::identity(); + Geom::Affine m = Geom::identity(); avoid_item_move(&m, item); + modmade = true; } if (items) { g_slist_free(items); } - - DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, + if(modmade) { + DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR, _("Change connector spacing")); - + } g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } @@ -8278,7 +8320,7 @@ static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainA // Code to watch for changes to the connector-spacing attribute in // the XML. - Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview); + Inkscape::XML::Node *repr = desktop->namedview->getRepr(); g_assert(repr != NULL); purge_repr_listener( holder, holder ); @@ -8411,7 +8453,7 @@ static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* main _("Grow/shrink by"), _("Grow/shrink by:"), _("The amount to grow (positive) or shrink (negative) the created fill path"), "/tools/paintbucket/offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, - "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5, + "inkscape:paintbucket-offset", -1e4, 1e4, 0.1, 0.5, 0, 0, 0, paintbucket_offset_changed, 1, 2); tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); diff --git a/src/xml/helper-observer.h b/src/xml/helper-observer.h index d028d390b..e7881cd4d 100644 --- a/src/xml/helper-observer.h +++ b/src/xml/helper-observer.h @@ -5,6 +5,7 @@ #include "node.h" #include "../sp-object.h" //#include "../sp-object-repr.h" +#include <stddef.h> #include <sigc++/sigc++.h> namespace Inkscape { diff --git a/src/xml/rebase-hrefs.cpp b/src/xml/rebase-hrefs.cpp index 065517160..33b31685d 100644 --- a/src/xml/rebase-hrefs.cpp +++ b/src/xml/rebase-hrefs.cpp @@ -230,15 +230,42 @@ void Inkscape::XML::rebase_hrefs(SPDocument *const doc, gchar const *const new_b * cases. */ GSList const *images = doc->getResourceList("image"); for (GSList const *l = images; l != NULL; l = l->next) { - Inkscape::XML::Node *ir = SP_OBJECT_REPR(l->data); + Inkscape::XML::Node *ir = static_cast<SPObject *>(l->data)->getRepr(); + + gchar * uri = g_strdup(ir->attribute("xlink:href")); + if (!uri) { + continue; + } + if (!strncmp(uri, "file://", 7)) { + uri = g_strdup(g_filename_from_uri(ir->attribute("xlink:href"), NULL, NULL)); + } + // The following two cases are for absolute hrefs that can be converted to relative. + // Imported images, first time rebased, need an old base. + gchar * href = uri; + if (g_path_is_absolute(href)) { + href = (gchar *) sp_relative_path_from_path(uri, old_abs_base); + } + // Files moved from a absolute path need a new one. + if (g_path_is_absolute(href)) { + href = (gchar *) sp_relative_path_from_path(uri, new_abs_base); + } + // Other bitmaps are either really absolute, or already relative. + +#ifdef WIN32 + /* Windows relative path needs their native separators before we + * compare it to native baserefs. */ + if (!g_path_is_absolute(href)) { + g_strdelimit(href, "/", '\\'); + } +#endif - gchar const *const href = ir->attribute("xlink:href"); /* TODO: Most of this function currently treats href as if it were a simple filename * (e.g. passing it to g_path_is_absolute, g_build_filename or IO::file_test, or avoiding * changing non-file hrefs), which breaks if href starts with a scheme or if href contains * any escaping. */ if (!href || !href_needs_rebasing(href)) { + g_free(uri); continue; } @@ -253,10 +280,21 @@ void Inkscape::XML::rebase_hrefs(SPDocument *const doc, gchar const *const new_b * of file hrefs. */ gchar const *const new_href = sp_relative_path_from_path(abs_href, new_abs_base); - ir->setAttribute("xlink:href", new_href); ir->setAttribute("sodipodi:absref", ( spns ? abs_href : NULL )); + if (!g_path_is_absolute(new_href)) { +#ifdef WIN32 + /* Native Windows path separators are replaced with / so that the href + * also works on Gnu/Linux and OSX */ + ir->setAttribute("xlink:href", g_strdelimit((gchar *) new_href, "\\", '/')); +#else + ir->setAttribute("xlink:href", new_href); +#endif + } else { + ir->setAttribute("xlink:href", g_filename_to_uri((gchar *) new_href, NULL, NULL)); + } + /* impl: I assume that if !spns then any existing sodipodi:absref is about to get * cleared (or is already cleared) anyway, in which case it doesn't matter whether we * clear or leave any existing sodipodi:absref value. If that assumption turns out to @@ -264,8 +302,10 @@ void Inkscape::XML::rebase_hrefs(SPDocument *const doc, gchar const *const new_b * referred to a different file than sodipodi:absref) while clearing it means risking * losing information. */ + g_free(uri); + // (No need to free href, it's guaranteed to point into uri.) g_free(abs_href); - /* (No need to free new_href, it's guaranteed to point into used_abs_href.) */ + // (No need to free new_href, it's guaranteed to point into abs_href.) } g_free(new_abs_base); diff --git a/src/zoom-context.cpp b/src/zoom-context.cpp index f8212069e..45de37652 100644 --- a/src/zoom-context.cpp +++ b/src/zoom-context.cpp @@ -1,5 +1,3 @@ -#define __SP_ZOOM_CONTEXT_C__ - /* * Handy zooming tool * @@ -18,6 +16,7 @@ #include "macros.h" #include "rubberband.h" +#include "display/sp-canvas-item.h" #include "display/sp-canvas-util.h" #include "desktop.h" #include "pixmaps/cursor-zoom.xpm" |
