diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2011-07-14 19:42:57 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2011-07-14 19:42:57 +0000 |
| commit | efbf9755460d4c4b7a3d9d43dd753afcc8a28865 (patch) | |
| tree | 41a259211da187e29f9983821b4cdfea221b6ad6 | |
| parent | Fix crashes in print preview (diff) | |
| parent | Make cms_key in SPDesktopWidget a regular ustring rather than a pointer (diff) | |
| download | inkscape-efbf9755460d4c4b7a3d9d43dd753afcc8a28865.tar.gz inkscape-efbf9755460d4c4b7a3d9d43dd753afcc8a28865.zip | |
Merge SPCanvasArena caching layer work
(bzr r10451)
193 files changed, 3506 insertions, 3686 deletions
diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index 4f7c3b6ef..08bcbff45 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -77,6 +77,7 @@ 2geom/quadtree.cpp \ 2geom/quadtree.h \ 2geom/ray.h \ + 2geom/rect.cpp \ 2geom/rect.h \ 2geom/region.cpp \ 2geom/region.h \ diff --git a/src/2geom/affine.cpp b/src/2geom/affine.cpp index 925f43820..2a1f18d77 100644 --- a/src/2geom/affine.cpp +++ b/src/2geom/affine.cpp @@ -1,9 +1,3 @@ -#define __Geom_MATRIX_C__ - -/** \file - * Various matrix routines. Currently includes some Geom::Rotate etc. routines too. - */ - /* * Authors: * Lauris Kaplinski <lauris@kaplinski.com> @@ -387,10 +381,10 @@ Coord Affine::descrim2() const { } /** @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. + * If the matrix doesn't contain a shearing or non-uniform scaling component, this value says + * how will the length of 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()); diff --git a/src/2geom/affine.h b/src/2geom/affine.h index 277d8b4ee..b07fba0f7 100644 --- a/src/2geom/affine.h +++ b/src/2geom/affine.h @@ -1,7 +1,8 @@ -/** \file - * \brief 3x3 affine transformation matrix. +/** + * \file + * \brief 3x3 affine transformation matrix. *//* - * Main authors: + * 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) @@ -10,8 +11,8 @@ * This code is in public domain. */ -#ifndef SEEN_LIB2GEOM_MATRIX_H -#define SEEN_LIB2GEOM_MATRIX_H +#ifndef SEEN_LIB2GEOM_AFFINE_H +#define SEEN_LIB2GEOM_AFFINE_H #include <boost/operators.hpp> #include <2geom/forward.h> @@ -236,9 +237,9 @@ inline Affine Affine::identity() { return ret; // allow NRVO } -} /* namespace Geom */ +} // end namespace Geom -#endif /* !__Geom_MATRIX_H__ */ +#endif // LIB2GEOM_SEEN_AFFINE_H /* Local Variables: diff --git a/src/2geom/angle.h b/src/2geom/angle.h index 42e3531f3..bdf546989 100644 --- a/src/2geom/angle.h +++ b/src/2geom/angle.h @@ -107,11 +107,18 @@ public: if (ret < 0) ret += 360; return ret; } - + /** @brief Create an angle from its measure in radians. */ + static Angle from_radians(Coord d) { + Angle a(d); + return a; + } + /** @brief Create an angle from its measure in degrees. */ static Angle from_degrees(Coord d) { Angle a(d * M_PI / 180); return a; } + /** @brief Create an angle from its measure in degrees in clock convention. + * @see Angle::degreesClock() */ static Angle from_degrees_clock(Coord d) { // first make sure d is in [0, 360) d = std::fmod(d, 360.0); @@ -208,9 +215,12 @@ protected: 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;} +/** @brief Given an angle in degrees, return radians + * @relates Angle */ +inline Coord deg_to_rad(Coord deg) { return deg*M_PI/180.0;} +/** @brief Given an angle in radians, return degrees + * @relates Angle */ +inline Coord rad_to_deg(Coord rad) { return rad*180.0/M_PI;} /* * start_angle and angle must belong to [0, 2PI[ @@ -294,8 +304,7 @@ bool arc_contains (double a, double sa, double ia, double ea) } // end namespace Geom -#endif - +#endif // LIB2GEOM_SEEN_ANGLE_H /* Local Variables: diff --git a/src/2geom/basic-intersection.h b/src/2geom/basic-intersection.h index b07052449..5a813ae99 100644 --- a/src/2geom/basic-intersection.h +++ b/src/2geom/basic-intersection.h @@ -1,6 +1,6 @@ /** * \file - * \brief \todo brief description + * \brief Basic intersection routines * * Authors: * ? <?@?.?> diff --git a/src/2geom/bezier-curve.cpp b/src/2geom/bezier-curve.cpp index bde0e3ef1..46aff8b49 100644 --- a/src/2geom/bezier-curve.cpp +++ b/src/2geom/bezier-curve.cpp @@ -1,8 +1,5 @@ -/** - * \file - * \brief Bezier curve +/* Bezier curve implementation * - *//* * Authors: * MenTaLguY <mental@rydia.net> * Marco Cecchetti <mrcekets at gmail.com> @@ -41,7 +38,7 @@ namespace Geom /** * @class BezierCurve - * @brief Two-dimensional Bezier curve of arbitrary order. (this is an abstract class) + * @brief Two-dimensional Bezier curve of arbitrary order. * * 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. @@ -82,28 +79,40 @@ namespace Geom * 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 + * 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. + * @par Implementation notes + * The order of a Bezier curve is immuable once it has been created. Normally, you should + * know the order at compile time and use the BezierCurveN template. If you need to determine + * the order at runtime, use the BezierCurve::create() function. It will create a BezierCurveN + * for orders 1, 2 and 3 (up to cubic Beziers), so you can later <tt>dynamic_cast</tt> + * to those types, and for higher orders it will create an instance of BezierCurve. * * @relates BezierCurveN * @ingroup Curves */ - /** +/** * @class BezierCurveN + * @brief Bezier curve with compile-time specified order. + * * @tparam degree unsigned value indicating the order of the bezier curve - * @brief Two-dimensional Bezier curve of specific order. * * @relates BezierCurve * @ingroup Curves */ - + +BezierCurve::BezierCurve(std::vector<Point> const &pts) +{ + inner = D2<Bezier>(Bezier::Order(pts.size()-1), Bezier::Order(pts.size()-1)); + for (unsigned d = 0; d < 2; ++d) { + for(unsigned i = 0; i <= pts.size(); i++) + inner[d][i] = pts[i][d]; + } +} + Coord BezierCurve::length(Coord tolerance) const { switch (order()) @@ -127,6 +136,48 @@ Coord BezierCurve::length(Coord tolerance) const } } +BezierCurve *BezierCurve::create(std::vector<Point> const &pts) +{ + switch (pts.size()) { + case 0: + case 1: + THROW_LOGICALERROR("BezierCurve::create: too few points in vector"); + return NULL; + case 2: + return new LineSegment(pts[0], pts[1]); + case 3: + return new QuadraticBezier(pts[0], pts[1], pts[2]); + case 4: + return new CubicBezier(pts[0], pts[1], pts[2], pts[3]); + default: + return new BezierCurve(pts); + } +} + +// optimized specializations for LineSegment + +template <> +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<> +Coord BezierCurveN<1>::nearestPoint(Point const& p, Coord from, Coord to) const +{ + 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); +} + + static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance) { /* The Bezier length algorithm used in 2Geom utilizes a simple fact: @@ -178,7 +229,7 @@ static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance) * After loop with i==2 * # # 2 3 4 * # 1 ? ? - * 0 ? ? -> wirte 0 to v2[2] + * 0 ? ? -> write 0 to v2[2] * ? ? * ? * @@ -204,7 +255,7 @@ static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance) } /** @brief Compute the length of a bezier curve given by a vector of its control points - * @relates BezierCurve */ + * @relatesalso BezierCurve */ Coord bezier_length(std::vector<Point> const &points, Coord tolerance) { if (points.size() < 2) return 0.0; @@ -213,7 +264,7 @@ Coord bezier_length(std::vector<Point> const &points, Coord tolerance) } /** @brief Compute the length of a quadratic bezier curve given by its control points - * @relates QuadraticBezier */ + * @relatesalso QuadraticBezier */ Coord bezier_length(Point a0, Point a1, Point a2, Coord tolerance) { Coord lower = distance(a0, a2); @@ -231,7 +282,7 @@ Coord bezier_length(Point a0, Point a1, Point a2, Coord tolerance) } /** @brief Compute the length of a cubic bezier curve given by its control points - * @relates CubicBezier */ + * @relatesalso CubicBezier */ Coord bezier_length(Point a0, Point a1, Point a2, Point a3, Coord tolerance) { Coord lower = distance(a0, a3); diff --git a/src/2geom/bezier-curve.h b/src/2geom/bezier-curve.h index 40da6f366..d13ff8321 100644 --- a/src/2geom/bezier-curve.h +++ b/src/2geom/bezier-curve.h @@ -1,14 +1,13 @@ /** * \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 + * Copyright 2007-2011 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -47,10 +46,13 @@ namespace Geom class BezierCurve : public Curve { protected: D2<Bezier> inner; + BezierCurve() {} + BezierCurve(BezierCurve const &b) : inner(b.inner) {} + BezierCurve(D2<Bezier> const &b) : inner(b) {} + BezierCurve(Bezier const &x, Bezier const &y) : inner(x, y) {} + BezierCurve(std::vector<Point> const &pts); public: - /// No constructors allowed! - /// @name Access and modify control points /// @{ /** @brief Get the order of the Bezier curve. @@ -66,8 +68,10 @@ public: 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. */ + /** @brief Set new control points. + * @param ps Vector which must contain order() + 1 points. + * Note that the caller is responsible for checking the size of this vector. + * @throws LogicalError Thrown when the size of the vector does not match the order. */ virtual void setPoints(std::vector<Point> const &ps) { // must be virtual, because HLineSegment will need to redefine it if (ps.size() != order() + 1) @@ -76,12 +80,18 @@ public: 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(). + /** @brief 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]); } /// @} + /// @name Construct a Bezier curve with runtime-determined order. + /// @{ + /** @brief Construct a curve from a vector of control points. */ + static BezierCurve *create(std::vector<Point> const &pts); + /// @} + // implementation of virtual methods goes here #ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Point initialPoint() const { return inner.at0(); } @@ -100,6 +110,27 @@ public: bounds_local(Geom::derivative(inner[Y]), i)); return OptRect(); } + virtual Curve *duplicate() const { + return new BezierCurve(*this); + } + virtual Curve *portion(Coord f, Coord t) const { + return new BezierCurve(Geom::portion(inner, f, t)); + } + virtual Curve *reverse() const { + return new BezierCurve(Geom::reverse(inner)); + } + virtual Curve *transformed(Affine 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; + } + virtual Curve *derivative() const { + return new BezierCurve(Geom::derivative(inner[X]), Geom::derivative(inner[Y])); + } virtual int degreesOfFreedom() const { return 2 * (order() + 1); } @@ -121,7 +152,7 @@ public: template <unsigned required_degree> static void assert_degree(BezierCurveN<required_degree> const *) {} - /// @name Construct the curve + /// @name Construct Bezier curves /// @{ /** @brief Construct a Bezier curve of the specified order with all points zero. */ BezierCurveN() { @@ -175,7 +206,19 @@ public: /// @} + /** @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)); + } +#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Curve *duplicate() const { return new BezierCurveN(*this); } @@ -207,31 +250,29 @@ public: } } 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 { + + // the method below is defined so that LineSegment can specialize it + virtual Coord nearestPoint(Point const& p, Coord from = 0, Coord to = 1) const { return Curve::nearestPoint(p, from, to); } - +#endif }; // BezierCurveN<0> is meaningless; specialize it out -template<> class BezierCurveN<0> : public BezierCurveN<1> { public: BezierCurveN();}; +template<> class BezierCurveN<0> : public BezierCurveN<1> { private: BezierCurveN();}; -// provide convenient names for common degree bezier curves +/** @brief Line segment. + * Line segments are Bezier curves of order 1. They have only two control points, + * the starting point and the ending point. + * @ingroup Curves */ typedef BezierCurveN<1> LineSegment; + +/** @brief Quadratic (order 2) Bezier curve. + * @ingroup Curves */ typedef BezierCurveN<2> QuadraticBezier; + +/** @brief Cubic (order 3) Bezier curve. + * @ingroup Curves */ typedef BezierCurveN<3> CubicBezier; template <unsigned degree> @@ -239,28 +280,10 @@ inline Curve *BezierCurveN<degree>::derivative() const { return new BezierCurveN<degree-1>(Geom::derivative(inner[X]), Geom::derivative(inner[Y])); } -template <> -inline -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 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; - 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); -} +// optimized specializations for LineSegment +template <> Curve *BezierCurveN<1>::derivative() const; +template <> Coord BezierCurveN<1>::nearestPoint(Point const &, Coord, Coord) const; inline Point middle_point(LineSegment const& _segment) { return ( _segment.initialPoint() + _segment.finalPoint() ) / 2; diff --git a/src/2geom/bezier-to-sbasis.h b/src/2geom/bezier-to-sbasis.h index ba98a8a34..8cd4bf444 100644 --- a/src/2geom/bezier-to-sbasis.h +++ b/src/2geom/bezier-to-sbasis.h @@ -1,7 +1,7 @@ /** - * \file bezier-to-sbasis.h - * \brief \todo brief description - * + * \file + * \brief Conversion between Bezier control points and SBasis curves + *//* * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> * * This library is free software; you can redistribute it and/or diff --git a/src/2geom/bezier-utils.cpp b/src/2geom/bezier-utils.cpp index eb317940f..af07db707 100644 --- a/src/2geom/bezier-utils.cpp +++ b/src/2geom/bezier-utils.cpp @@ -1,9 +1,5 @@ -#define __SP_BEZIER_UTILS_C__ - -/** \file - * Bezier interpolation for inkscape drawing code. - */ -/* +/* Bezier interpolation for inkscape drawing code. + * * Original code published in: * An Algorithm for Automatically Fitting Digitized Curves * by Philip J. Schneider @@ -52,8 +48,7 @@ #endif #include <2geom/bezier-utils.h> - -#include <2geom/isnan.h> +#include <2geom/math-utils.h> #include <assert.h> namespace Geom { diff --git a/src/2geom/bezier-utils.h b/src/2geom/bezier-utils.h index 9689db82d..3e56e6e25 100644 --- a/src/2geom/bezier-utils.h +++ b/src/2geom/bezier-utils.h @@ -1,10 +1,7 @@ -#ifndef SEEN_GEOM_BEZIER_UTILS_H -#define SEEN_GEOM_BEZIER_UTILS_H - /** * \file - * \brief \todo brief description - * + * \brief Bezier fitting algorithms + *//* * An Algorithm for Automatically Fitting Digitized Curves * by Philip J. Schneider * from "Graphics Gems", Academic Press, 1990 @@ -41,11 +38,13 @@ * */ +#ifndef LIB2GEOM_SEEN_BEZIER_UTILS_H +#define LIB2GEOM_SEEN_BEZIER_UTILS_H + #include <2geom/point.h> -namespace Geom{ +namespace Geom { -/* Bezier approximation utils */ Point bezier_pt(unsigned degree, Point const V[], double t); int bezier_fit_cubic(Point bezier[], Point const data[], int len, double error); @@ -84,8 +83,9 @@ cubic_bezier_poly_coeff(iterator b, Point *pc) { } } -} -#endif /* !SEEN_GEOM_BEZIER_UTILS_H */ +} // end namespace Geom + +#endif // LIB2GEOM_SEEN_BEZIER_UTILS_H /* Local Variables: diff --git a/src/2geom/bezier.h b/src/2geom/bezier.h index a7d75da45..48a1dc750 100644 --- a/src/2geom/bezier.h +++ b/src/2geom/bezier.h @@ -1,10 +1,13 @@ /** - * \file bezier.h - * \brief \todo brief description + * @file + * @brief Bezier polynomial + *//* + * Authors: + * MenTaLguY <mental@rydia.net> + * Michael Sloan <mgsloan@gmail.com> + * Nathan Hurst <njh@njhurst.com> * - * Copyright 2007 MenTaLguY <mental@rydia.net> - * Copyright 2007 Michael Sloan <mgsloan@gmail.com> - * Copyright 2007 Nathan Hurst <njh@njhurst.com> + * Copyright 2007 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -31,15 +34,15 @@ * */ -#ifndef SEEN_BEZIER_H -#define SEEN_BEZIER_H +#ifndef LIB2GEOM_SEEN_BEZIER_H +#define LIB2GEOM_SEEN_BEZIER_H -#include <2geom/coord.h> #include <valarray> -#include <2geom/isnan.h> +#include <boost/optional.hpp> +#include <2geom/coord.h> +#include <2geom/math-utils.h> #include <2geom/d2.h> #include <2geom/solver.h> -#include <boost/optional/optional.hpp> namespace Geom { @@ -280,7 +283,7 @@ public: } std::vector<double> roots(Interval const ivl) const { std::vector<double> solutions; - find_bernstein_roots(&const_cast<std::valarray<Coord>&>(c_)[0], order(), solutions, 0, ivl[0], ivl[1]); + find_bernstein_roots(&const_cast<std::valarray<Coord>&>(c_)[0], order(), solutions, 0, ivl.min(), ivl.max()); return solutions; } }; @@ -407,7 +410,7 @@ inline std::ostream &operator<< (std::ostream &out_file, const Bezier & b) { } } -#endif //SEEN_BEZIER_H +#endif // LIB2GEOM_SEEN_BEZIER_H /* Local Variables: diff --git a/src/2geom/choose.h b/src/2geom/choose.h index 3fecf1ba2..64ce76f39 100644 --- a/src/2geom/choose.h +++ b/src/2geom/choose.h @@ -1,7 +1,7 @@ /** - * \file choose.h - * \brief \todo brief description - * + * \file + * \brief Calculation of binomial cefficients + *//* * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> * * This library is free software; you can redistribute it and/or @@ -29,10 +29,13 @@ * */ -#ifndef _CHOOSE_H -#define _CHOOSE_H +#ifndef LIB2GEOM_SEEN_CHOOSE_H +#define LIB2GEOM_SEEN_CHOOSE_H + #include <vector> +namespace Geom { + // 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 @@ -121,13 +124,9 @@ class BinomialCoefficient container_type coefficients; }; +} // end namespace Geom - - - - - -#endif +#endif // LIB2GEOM_SEEN_CHOOSE_H /* Local Variables: diff --git a/src/2geom/circle.h b/src/2geom/circle.h index ec58e163a..67a638437 100644 --- a/src/2geom/circle.h +++ b/src/2geom/circle.h @@ -1,7 +1,7 @@ /** * \file - * \brief Circle Curve - * + * \brief Circles + *//* * Authors: * Marco Cecchetti <mrcekets at gmail.com> * @@ -31,18 +31,15 @@ * the specific language governing rights and limitations. */ +#ifndef LIB2GEOM_SEEN_CIRCLE_H +#define LIB2GEOM_SEEN_CIRCLE_H -#ifndef _2GEOM_CIRCLE_H_ -#define _2GEOM_CIRCLE_H_ - - +#include <vector> #include <2geom/point.h> #include <2geom/exception.h> #include <2geom/path.h> -#include <vector> -namespace Geom -{ +namespace Geom { class EllipticalArc; @@ -115,13 +112,9 @@ class Circle Coord m_ray; }; - } // end namespace Geom - - -#endif // _2GEOM_CIRCLE_H_ - +#endif // LIB2GEOM_SEEN_CIRCLE_H /* Local Variables: diff --git a/src/2geom/circulator.h b/src/2geom/circulator.h index 1a70dc4d3..9671ce4a9 100644 --- a/src/2geom/circulator.h +++ b/src/2geom/circulator.h @@ -1,7 +1,7 @@ /** - * \file circulator.h - * \brief \todo brief description - * + * @file circulator.h + * @brief Circular iterator adapter + *//* * Copyright 2006 MenTaLguY <mental@rydia.net> * * This library is free software; you can redistribute it and/or @@ -36,6 +36,9 @@ namespace Geom { +/** @brief Circular iterator adapter + * This iterator adapter will loop indefinitely over a set of values + * from a random access container. */ template <typename Iterator> class Circulator { public: diff --git a/src/2geom/concepts.h b/src/2geom/concepts.h index a03538d42..c89c3a224 100644 --- a/src/2geom/concepts.h +++ b/src/2geom/concepts.h @@ -1,7 +1,7 @@ /** * \file - * \brief Declares various mathematical concepts, for restriction of template parameters - * + * \brief Template concepts used by 2Geom + *//* * Copyright 2007 Michael Sloan <mgsloan@gmail.com> * * This library is free software; you can redistribute it and/or @@ -26,15 +26,15 @@ * 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_CONCEPTS_H -#define SEEN_CONCEPTS_H +#ifndef LIB2GEOM_SEEN_CONCEPTS_H +#define LIB2GEOM_SEEN_CONCEPTS_H #include <2geom/sbasis.h> #include <2geom/interval.h> #include <2geom/point.h> +#include <2geom/rect.h> #include <vector> #include <boost/concept_check.hpp> #include <2geom/forward.h> @@ -49,7 +49,7 @@ template <> struct ResultTraits<double> { typedef SBasis sb_type; }; -template <> struct ResultTraits<Point > { +template <> struct ResultTraits<Point> { typedef OptRect bounds_type; typedef D2<SBasis> sb_type; }; @@ -130,7 +130,7 @@ struct ScalableConcept { } }; -template <class T> +template <typename T> struct AddableConcept { T i, j; void constraints() { @@ -139,7 +139,7 @@ struct AddableConcept { } }; -template <class T> +template <typename T> struct MultiplicableConcept { T i, j; void constraints() { @@ -147,9 +147,9 @@ struct MultiplicableConcept { } }; -}; +} // end namespace Geom -#endif //SEEN_CONCEPTS_H +#endif // LIB2GEOM_SEEN_CONCEPTS_H /* Local Variables: diff --git a/src/2geom/conic_section_clipper_impl.cpp b/src/2geom/conic_section_clipper_impl.cpp index edfafb11c..33a218a8c 100644 --- a/src/2geom/conic_section_clipper_impl.cpp +++ b/src/2geom/conic_section_clipper_impl.cpp @@ -1,6 +1,4 @@ -/** - * \file - * \brief Conic section clipping with respect to a rectangle +/* Conic section clipping with respect to a rectangle * * Authors: * Marco Cecchetti <mrcekets at gmail> @@ -31,30 +29,13 @@ * 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. @@ -192,7 +173,7 @@ bool CLIPPER_CLASS::intersect (std::vector<Point> & crossing_points) const cpts.size()) // remove duplicates - std::sort (cpts.begin(), cpts.end(), lex_lesser()); + std::sort (cpts.begin(), cpts.end(), Point::LexOrder<X>()); cpts.erase (std::unique (cpts.begin(), cpts.end()), cpts.end()); diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp index 2a537a1f0..a7e8e0ad8 100644 --- a/src/2geom/conicsec.cpp +++ b/src/2geom/conicsec.cpp @@ -1,7 +1,4 @@ -/** - * \file - * \brief Circle Curve - * +/* * Authors: * Nathan Hurst <njh@njhurst.com * diff --git a/src/2geom/conjugate_gradient.h b/src/2geom/conjugate_gradient.h index 8ea1b83b4..a34307d4b 100644 --- a/src/2geom/conjugate_gradient.h +++ b/src/2geom/conjugate_gradient.h @@ -1,7 +1,7 @@ /** - * \file - * \brief \todo brief description - * + * @file + * @brief Routines for solving a system of linear equations using the conjugate gradient method + *//* * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> * * This library is free software; you can redistribute it and/or diff --git a/src/2geom/convex-cover.h b/src/2geom/convex-cover.h index d5e2dee44..e4b5de200 100644 --- a/src/2geom/convex-cover.h +++ b/src/2geom/convex-cover.h @@ -1,9 +1,6 @@ -#ifndef GEOM_CONVEX_COVER_H -#define GEOM_CONVEX_COVER_H - /** * \file - * \brief \todo brief description + * \brief Dynamic convex hull structure * * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> * Copyright 2006 Michael G. Sloan <mgsloan@gmail.com> @@ -33,15 +30,18 @@ * */ -/** A convex cover is a sequence of convex polygons that completely cover the path. For now a - * convex hull class is included here (the convex-hull header is wrong) - */ +#ifndef GEOM_CONVEX_COVER_H +#define GEOM_CONVEX_COVER_H #include <2geom/point.h> #include <vector> namespace Geom{ +/* A convex cover is a sequence of convex polygons that completely cover the path. For now a + * convex hull class is included here (the convex-hull header is wrong) + */ + /** ConvexHull * A convexhull is a convex region - every point between two points in the convex hull is also in * the convex hull. It is defined by a set of points travelling in a clockwise direction. We require the first point to be top most, and of the topmost, leftmost. diff --git a/src/2geom/coord.h b/src/2geom/coord.h index 9c42f6bfc..c7bbcdcd4 100644 --- a/src/2geom/coord.h +++ b/src/2geom/coord.h @@ -1,7 +1,7 @@ /** * \file * \brief Defines the Coord "real" type with sufficient precision for coordinates. - * + *//* * Copyright 2006 Nathan Hurst <njh@mail.csse.monash.edu.au> * * This library is free software; you can redistribute it and/or @@ -29,15 +29,16 @@ * */ -#ifndef SEEN_Geom_COORD_H -#define SEEN_Geom_COORD_H +#ifndef LIB2GEOM_SEEN_COORD_H +#define LIB2GEOM_SEEN_COORD_H #include <cmath> #include <limits> +#include <2geom/forward.h> namespace Geom { -/** @brief Axis enum (X or Y). */ +/** @brief 2D axis enumeration (X or Y). */ enum Dim2 { X=0, Y=1 }; /** @@ -48,6 +49,7 @@ enum Dim2 { X=0, Y=1 }; * differences of on-canvas points. */ typedef double Coord; +typedef int IntCoord; const Coord EPSILON = 1e-5; //1e-18; @@ -57,13 +59,36 @@ inline Coord infinity() { return std::numeric_limits<Coord>::infinity(); } 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; } +template <typename C> +struct CoordTraits {}; -typedef long IntCoord; +template<> +struct CoordTraits<IntCoord> { + typedef IntPoint PointType; + typedef IntInterval IntervalType; + typedef OptIntInterval OptIntervalType; + typedef IntRect RectType; + typedef OptIntRect OptRectType; + inline static bool contains(IntCoord low, IntCoord high, IntCoord testlow, IntCoord testhigh) { + return low <= testlow && testhigh < high; + } +}; -} /* namespace Geom */ +template<> +struct CoordTraits<Coord> { + typedef Point PointType; + typedef Interval IntervalType; + typedef OptInterval OptIntervalType; + typedef Rect RectType; + typedef OptRect OptRectType; + inline static bool contains(Coord low, Coord high, Coord testlow, Coord testhigh) { + return low <= testlow && testhigh <= high; + } +}; +} // end namespace Geom -#endif /* !SEEN_Geom_COORD_H */ +#endif // LIB2GEOM_SEEN_COORD_H /* Local Variables: diff --git a/src/2geom/crossing.h b/src/2geom/crossing.h index 62e447450..75c75fc24 100644 --- a/src/2geom/crossing.h +++ b/src/2geom/crossing.h @@ -1,10 +1,10 @@ /** - * \file - * \brief \todo brief description - * + * @file + * @brief Structure representing the intersection of two curves + *//* * Authors: - * Michael Sloane <?@?.?> - * Marco <?@?.?> + * Michael Sloan <mgsloan@gmail.com> + * Marco Cecchetti <mrcekets at gmail.com> * * Copyright 2006-2008 authors * diff --git a/src/2geom/curve.cpp b/src/2geom/curve.cpp index 49e011a8b..fe9d607d8 100644 --- a/src/2geom/curve.cpp +++ b/src/2geom/curve.cpp @@ -1,8 +1,5 @@ -/** - * \file - * \brief Abstract curve type - implementation of default methods +/* Abstract curve type - implementation of default methods * - *//* * Authors: * MenTaLguY <mental@rydia.net> * Marco Cecchetti <mrcekets at gmail.com> diff --git a/src/2geom/curves.h b/src/2geom/curves.h index 64cf3d4fb..319b1924d 100644 --- a/src/2geom/curves.h +++ b/src/2geom/curves.h @@ -32,9 +32,8 @@ * the specific language governing rights and limitations. */ -#ifndef _2GEOM_CURVES_H_ -#define _2GEOM_CURVES_H_ - +#ifndef LIB2GEOM_SEEN_CURVES_H +#define LIB2GEOM_SEEN_CURVES_H #include <2geom/curve.h> #include <2geom/sbasis-curve.h> @@ -43,7 +42,7 @@ #include <2geom/elliptical-arc.h> #include <2geom/svg-elliptical-arc.h> -#endif // _2GEOM_CURVES_H_ +#endif // LIB2GEOM_SEEN_CURVES_H /* Local Variables: diff --git a/src/2geom/d2-sbasis.h b/src/2geom/d2-sbasis.h index bd6c35805..e61067e1b 100644 --- a/src/2geom/d2-sbasis.h +++ b/src/2geom/d2-sbasis.h @@ -1,11 +1,10 @@ /** * \file - * \brief Do not include this file \todo brief description + * \brief Do not include this file * * We don't actually want anyone to - * include this, other than D2.h. If somone else tries, D2 - * won't be defined. If it is, this will already be included. - * + * include this, other than D2.h. + *//* * Authors: * ? <?@?.?> * @@ -36,11 +35,11 @@ * */ -#ifdef _2GEOM_D2 /*This is intentional: we don't actually want anyone to - include this, other than D2.h. If somone else tries, D2 - won't be defined. If it is, this will already be included. */ -#ifndef __2GEOM_SBASIS_CURVE_H -#define __2GEOM_SBASIS_CURVE_H +#ifdef SEEN_LIB2GEOM_D2_H /*This is intentional: we don't actually want anyone to + include this, other than D2.h. If somone else tries, D2 + won't be defined. If it is, this will already be included. */ +#ifndef SEEN_LIB2GEOM_D2_SBASIS_H +#define SEEN_LIB2GEOM_D2_SBASIS_H #include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> diff --git a/src/2geom/d2.h b/src/2geom/d2.h index 3e4de430e..4a4f45a63 100644 --- a/src/2geom/d2.h +++ b/src/2geom/d2.h @@ -1,7 +1,7 @@ /** * \file * \brief Lifts one dimensional objects into 2d - * + *//* * Copyright 2007 Michael Sloan <mgsloan@gmail.com> * * This library is free software; you can redistribute it and/or @@ -29,12 +29,13 @@ * */ -#ifndef _2GEOM_D2 //If this is change, change the guard in rect.h as well. -#define _2GEOM_D2 +#ifndef SEEN_LIB2GEOM_D2_H +#define SEEN_LIB2GEOM_D2_H #include <2geom/point.h> #include <2geom/interval.h> #include <2geom/affine.h> +#include <2geom/rect.h> #include <boost/concept_check.hpp> #include <2geom/concepts.h> @@ -426,7 +427,6 @@ inline std::ostream &operator<< (std::ostream &out_file, const Geom::D2<T> &in_d } //end namespace Geom -#include <2geom/rect.h> #include <2geom/d2-sbasis.h> namespace Geom{ diff --git a/src/2geom/forward.h b/src/2geom/forward.h index 399344dda..b1cad6f1f 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -41,11 +41,23 @@ namespace Geom { // basic types typedef double Coord; +typedef int IntCoord; class Point; -class Interval; -class OptInterval; +class IntPoint; class Line; class Ray; +template <typename> class GenericInterval; +template <typename> class GenericOptInterval; +class Interval; +typedef GenericOptInterval<Coord> OptInterval; +typedef GenericInterval<IntCoord> IntInterval; +typedef GenericOptInterval<IntCoord> OptIntInterval; +template <typename> class GenericRect; +template <typename> class GenericOptRect; +class Rect; +typedef GenericOptRect<Coord> OptRect; +typedef GenericRect<IntCoord> IntRect; +typedef GenericOptRect<IntCoord> OptIntRect; // fragments class Linear; @@ -90,9 +102,6 @@ class VShear; template <typename> class D2; template <typename> class Piecewise; -typedef D2<Interval> Rect; -class OptRect; - class Shape; class Region; class Hat; diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h new file mode 100644 index 000000000..d719c16c8 --- /dev/null +++ b/src/2geom/generic-interval.h @@ -0,0 +1,342 @@ +/** + * @file + * @brief Closed interval of generic values + *//* + * Copyright 2011 Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * 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 LIB2GEOM_SEEN_GENERIC_INTERVAL_H +#define LIB2GEOM_SEEN_GENERIC_INTERVAL_H + +#include <cassert> +#include <boost/none.hpp> +#include <boost/optional.hpp> +#include <boost/operators.hpp> + +namespace Geom { + +template <typename C> +class GenericOptInterval; + +/** + * @brief A range of numbers which is never empty. + * @ingroup Primitives + */ +template <typename C> +class GenericInterval + : boost::equality_comparable< GenericInterval<C> + , boost::additive< GenericInterval<C> + , boost::additive< GenericInterval<C>, C + , boost::orable< GenericInterval<C> + > > > > +{ + typedef GenericInterval<C> Self; +protected: + C _b[2]; +public: + /// @name Create intervals. + /// @{ + /** @brief Create an interval that contains only zero. */ + GenericInterval() { _b[0] = 0; _b[1] = 0; } + /** @brief Create an interval that contains a single point. */ + explicit GenericInterval(C u) { _b[0] = _b[1] = u; } + /** @brief Create an interval that contains all points between @c u and @c v. */ + GenericInterval(C u, C v) { + if (u <= v) { + _b[0] = u; _b[1] = v; + } else { + _b[0] = v; _b[1] = u; + } + } + + /** @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 C. The given range + * must not be empty. For potentially empty ranges, see GenericOptInterval. + * @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 Self from_range(InputIterator start, InputIterator end) { + assert(start != end); + Self result(*start++); + for (; start != end; ++start) result.expandTo(*start); + return result; + } + /** @brief Create an interval from a C-style array of values it should contain. */ + static Self from_array(C const *c, unsigned n) { + Self result = from_range(c, c+n); + return result; + } + /// @} + + /// @name Inspect endpoints. + /// @{ + C min() const { return _b[0]; } + C max() const { return _b[1]; } + C extent() const { return max() - min(); } + C middle() const { return (max() + min()) * 0.5; } + bool isSingular() const { return min() == max(); } + /// @} + + /// @name Test coordinates and other intervals for inclusion. + /// @{ + /** @brief Check whether the interval includes this number. */ + bool contains(C val) const { + return CoordTraits<C>::contains(min(), max(), val, val); + } + /** @brief Check whether the interval includes the given interval. */ + bool contains(Self const &val) const { + return CoordTraits<C>::contains(min(), max(), val.min(), val.max()); + } + /** @brief Check whether the intervals have any common elements. */ + bool intersects(Self const &val) const { + return contains(val.min()) || contains(val.max()) || val.contains(*this); + } + /// @} + + /// @name Modify the interval. + /// @{ + //TODO: NaN handleage for the next two? + /** @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(C val) { + if(val > _b[1]) { + _b[0] = _b[1] = val; + } else { + _b[0] = val; + } + } + /** @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(C val) { + if(val < _b[0]) { + _b[1] = _b[0] = val; + } else { + _b[1] = val; + } + } + /** @brief Extend the interval to include the given number. */ + void expandTo(C val) { + if(val < _b[0]) _b[0] = val; + if(val > _b[1]) _b[1] = val; //no else, as we want to handle NaN + } + /** @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(C amount) { + _b[0] -= amount; + _b[1] += amount; + if (_b[0] > _b[1]) { + C halfway = (_b[0]+_b[1])/2; + _b[0] = _b[1] = halfway; + } + } + /** @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(Self const &a) { + if(a._b[0] < _b[0]) _b[0] = a._b[0]; + if(a._b[1] > _b[1]) _b[1] = a._b[1]; + } + /// @} + + /// @name Operators + /// @{ + //IMPL: OffsetableConcept + //TODO: rename output_type to something else in the concept + typedef C output_type; + /** @brief Offset the interval by a specified amount */ + Self &operator+=(C amnt) { + _b[0] += amnt; _b[1] += amnt; + return *this; + } + /** @brief Offset the interval by the negation of the specified amount */ + Self &operator-=(C amnt) { + _b[0] -= amnt; _b[1] -= amnt; + return *this; + } + + /** @brief Return an interval mirrored about 0 */ + Self operator-() const { Self r(-_b[1], -_b[0]); return r; } + // 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$ */ + Self &operator+=(Self 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$ */ + Self &operator-=(Self const &o) { + // equal to *this += -o + _b[0] -= o._b[1]; + _b[1] -= o._b[0]; + return *this; + } + /** @brief Union two intervals. + * Note that the intersection-and-assignment operator is not defined, + * because the result of an intersection can be empty, while Interval cannot. */ + Self &operator|=(Self const &o) { + unionWith(o); + return *this; + } + /** @brief Test for interval equality. */ + bool operator==(Self const &other) const { + return min() == other.min() && max() == other.max(); + } + /// @} +}; + +/** @brief Union two intervals + * @relates GenericInterval */ +template <typename C> +inline GenericInterval<C> unify(GenericInterval<C> const &a, GenericInterval<C> const &b) { + return a | b; +} + +/** + * @brief A range of numbers that can be empty. + * @ingroup Primitives + */ +template <typename C> +class GenericOptInterval + : public boost::optional<typename CoordTraits<C>::IntervalType> + , boost::orable< GenericOptInterval<C>, typename CoordTraits<C>::OptIntervalType + , boost::andable< GenericOptInterval<C>, typename CoordTraits<C>::OptIntervalType + > > +{ + typedef typename CoordTraits<C>::IntervalType CInterval; + typedef typename CoordTraits<C>::OptIntervalType OptCInterval; + typedef boost::optional<CInterval> Base; +public: + /// @name Create optionally empty intervals of integers. + /// @{ + /** @brief Create an empty interval. */ + GenericOptInterval() : Base() {} + /** @brief Wrap an existing interval. */ + GenericOptInterval(GenericInterval<C> const &a) : Base(CInterval(a)) {} + /** @brief Create an interval containing a single point. */ + GenericOptInterval(C u) : Base(CInterval(u)) {} + /** @brief Create an interval containing a range of numbers. */ + GenericOptInterval(C u, C v) : Base(CInterval(u,v)) {} + + /** @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 C. 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 GenericOptInterval<C> from_range(InputIterator start, InputIterator end) { + if (start == end) { + GenericOptInterval<C> ret; + return ret; + } + GenericOptInterval<C> ret(CInterval::from_range(start, end)); + return ret; + } + /// @} + + /** @brief Check whether this interval is empty. */ + bool isEmpty() { return !*this; }; + + /** @brief Union with another interval, gracefully handling empty ones. */ + void unionWith(GenericOptInterval<C> const &a) { + if (*this) { // check that we are not empty + (*this)->unionWith(*a); + } else if (a) { + *this = *a; + } + } + void intersectWith(GenericOptInterval<C> const &o) { + if (o && *this) { + if (!*this) return; + C u = std::max((*this)->min(), o->min()); + C v = std::min((*this)->max(), o->max()); + if (u <= v) { + *this = CInterval(u, v); + return; + } + } + (*static_cast<Base*>(this)) = boost::none; + } + GenericOptInterval<C> &operator|=(OptCInterval const &o) { + unionWith(o); + return *this; + } + GenericOptInterval<C> &operator&=(OptCInterval const &o) { + intersectWith(o); + return *this; + } +}; + +/** @brief Intersect two intervals and return a possibly empty range of numbers + * @relates GenericOptInterval */ +template <typename C> +inline GenericOptInterval<C> intersect(GenericInterval<C> const &a, GenericInterval<C> const &b) { + return GenericOptInterval<C>(a) & GenericOptInterval<C>(b); +} +/** @brief Intersect two intervals and return a possibly empty range of numbers + * @relates GenericOptInterval */ +template <typename C> +inline GenericOptInterval<C> operator&(GenericInterval<C> const &a, GenericInterval<C> const &b) { + return GenericOptInterval<C>(a) & GenericOptInterval<C>(b); +} + +#ifdef _GLIBCXX_IOSTREAM +template <typename C> +inline std::ostream &operator<< (std::ostream &os, + Geom::GenericInterval<C> const &I) { + os << "Interval("<<I.min() << ", "<<I.max() << ")"; + return os; +} +#endif + +} // namespace Geom +#endif // !LIB2GEOM_SEEN_GENERIC_INTERVAL_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/generic-rect.h b/src/2geom/generic-rect.h new file mode 100644 index 000000000..d60c4bb0f --- /dev/null +++ b/src/2geom/generic-rect.h @@ -0,0 +1,390 @@ +/** + * \file + * \brief Axis-aligned rectangle + *//* + * Authors: + * Michael Sloan <mgsloan@gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * Copyright 2007-2011 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, output 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. + * + * Authors of original rect class: + * Lauris Kaplinski <lauris@kaplinski.com> + * Nathan Hurst <njh@mail.csse.monash.edu.au> + * bulia byak <buliabyak@users.sf.net> + * MenTaLguY <mental@rydia.net> + */ + +#ifndef LIB2GEOM_SEEN_GENERIC_RECT_H +#define LIB2GEOM_SEEN_GENERIC_RECT_H + +#include <boost/optional.hpp> + +namespace Geom { + +template <typename C> +class GenericOptRect; + +/** + * @brief Axis aligned, non-empty, generic rectangle. + * @ingroup Primitives + */ +template <typename C> +class GenericRect + : boost::additive< GenericRect<C>, typename CoordTraits<C>::PointType + , boost::equality_comparable< GenericRect<C> + , boost::orable< GenericRect<C> + , boost::orable< GenericRect<C>, typename CoordTraits<C>::OptRectType + > > > > +{ + typedef typename CoordTraits<C>::IntervalType CInterval; + typedef typename CoordTraits<C>::PointType CPoint; + typedef typename CoordTraits<C>::RectType CRect; + typedef typename CoordTraits<C>::OptRectType OptCRect; +protected: + CInterval f[2]; +public: + /// @name Create rectangles. + /// @{ + /** @brief Create a rectangle that contains only the point at (0,0). */ + GenericRect() { f[X] = f[Y] = CInterval(); } + /** @brief Create a rectangle from X and Y intervals. */ + GenericRect(CInterval const &a, CInterval const &b) { + f[X] = a; + f[Y] = b; + } + /** @brief Create a rectangle from two points. */ + GenericRect(CPoint const &a, CPoint const &b) { + f[X] = CInterval(a[X], b[X]); + f[Y] = CInterval(a[Y], b[Y]); + } + /** @brief Create rectangle from coordinates of two points. */ + GenericRect(C x0, C y0, C x1, C y1) { + f[X] = CInterval(x0, x1); + f[Y] = CInterval(y0, y1); + } + /** @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 GenericRect<C> from_range(InputIterator start, InputIterator end) { + assert(start != end); + CPoint p1 = *start++; + GenericRect<C> 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 GenericRect<C> from_array(CPoint const *c, unsigned n) { + GenericRect<C> result = GenericRect<C>::from_range(c, c+n); + return result; + } + /** @brief Create rectangle from origin and dimensions. */ + static GenericRect<C> from_xywh(C x, C y, C w, C h) { + CPoint xy(x, y); + CPoint wh(w, h); + GenericRect<C> result(xy, xy + wh); + return result; + } + /** @brief Create rectangle from origin and dimensions. */ + static GenericRect<C> from_xywh(CPoint const &xy, CPoint const &wh) { + GenericRect<C> result(xy, xy + wh); + return result; + } + /// @} + + /// @name Inspect dimensions. + /// @{ + CInterval &operator[](unsigned i) { return f[i]; } + CInterval const &operator[](unsigned i) const { return f[i]; } + + CPoint min() const { return CPoint(f[X].min(), f[Y].min()); } + CPoint max() const { return CPoint(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. */ + CPoint corner(unsigned i) const { + switch(i % 4) { + case 0: return CPoint(f[X].min(), f[Y].min()); + case 1: return CPoint(f[X].max(), f[Y].min()); + case 2: return CPoint(f[X].max(), f[Y].max()); + default: return CPoint(f[X].min(), f[Y].max()); + } + } + + //We should probably remove these - they're coord sys gnostic + /** @brief Return top coordinate of the rectangle (+Y is downwards). */ + C top() const { return f[Y].min(); } + /** @brief Return bottom coordinate of the rectangle (+Y is downwards). */ + C bottom() const { return f[Y].max(); } + /** @brief Return leftmost coordinate of the rectangle (+X is to the right). */ + C left() const { return f[X].min(); } + /** @brief Return rightmost coordinate of the rectangle (+X is to the right). */ + C right() const { return f[X].max(); } + + /** @brief Get the horizontal extent of the rectangle. */ + C width() const { return f[X].extent(); } + /** @brief Get the vertical extent of the rectangle. */ + C height() const { return f[Y].extent(); } + + /** @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. */ + CPoint dimensions() const { return CPoint(f[X].extent(), f[Y].extent()); } + /** @brief Get the point in the geometric center of the rectangle. */ + CPoint midpoint() const { return CPoint(f[X].middle(), f[Y].middle()); } + + /** @brief Compute rectangle's area. */ + C area() const { return f[X].extent() * f[Y].extent(); } + /** @brief Check whether the rectangle has zero area. */ + bool hasZeroArea() const { return (area() == 0); } + + /** @brief Get the larger extent (width or height) of the rectangle. */ + C maxExtent() const { return std::max(f[X].extent(), f[Y].extent()); } + /** @brief Get the smaller extent (width or height) of the rectangle. */ + C minExtent() const { return std::min(f[X].extent(), f[Y].extent()); } + /// @} + + /// @name Test other rectangles and points for inclusion. + /// @{ + /** @brief Check whether the rectangles have any common points. */ + bool intersects(GenericRect<C> const &r) const { + return f[X].intersects(r[X]) && f[Y].intersects(r[Y]); + } + /** @brief Check whether the rectangle includes all points in the given rectangle. */ + bool contains(GenericRect<C> const &r) const { + return f[X].contains(r[X]) && f[Y].contains(r[Y]); + } + + /** @brief Check whether the rectangles have any common points. + * A non-empty rectangle will not intersect empty rectangles. */ + inline bool intersects(OptCRect 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(OptCRect const &r) const; + + /** @brief Check whether the given point is within the rectangle. */ + bool contains(CPoint const &p) const { + return f[X].contains(p[X]) && f[Y].contains(p[Y]); + } + /// @} + + /// @name Modify the rectangle. + /// @{ + /** @brief Set the upper left point of the rectangle. */ + void setMin(CPoint const &p) { + f[X].setMin(p[X]); + f[Y].setMin(p[Y]); + } + /** @brief Set the lower right point of the rectangle. */ + void setMax(CPoint const &p) { + f[X].setMax(p[X]); + f[Y].setMax(p[Y]); + } + /** @brief Enlarge the rectangle to contain the given point. */ + void expandTo(CPoint const &p) { + f[X].expandTo(p[X]); f[Y].expandTo(p[Y]); + } + /** @brief Enlarge the rectangle to contain the given rectangle. */ + void unionWith(GenericRect<C> 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(OptCRect const &b); + + /** @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(C amount) { + f[X].expandBy(amount); f[Y].expandBy(amount); + } + /** @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(CPoint const &p) { + f[X].expandBy(p[X]); f[Y].expandBy(p[Y]); + } + /// @} + + /// @name Operators + /// @{ + /** @brief Offset the rectangle by a vector. */ + GenericRect<C> &operator+=(CPoint const &p) { + f[X] += p[X]; + f[Y] += p[Y]; + return *this; + } + /** @brief Offset the rectangle by the negation of a vector. */ + GenericRect<C> &operator-=(CPoint const &p) { + f[X] -= p[X]; + f[Y] -= p[Y]; + return *this; + } + /** @brief Union two rectangles. */ + GenericRect<C> &operator|=(GenericRect<C> const &o) { + unionWith(o); + return *this; + } + GenericRect<C> &operator|=(OptCRect const &o) { + unionWith(o); + return *this; + } + /** @brief Test for equality of rectangles. */ + bool operator==(GenericRect<C> const &o) const { return f[X] == o[X] && f[Y] == o[Y]; } + /// @} +}; + +/** + * @brief Axis-aligned generic rectangle that can be empty. + * @ingroup Primitives + */ +template <typename C> +class GenericOptRect + : public boost::optional<typename CoordTraits<C>::RectType> + , boost::orable< GenericOptRect<C> + , boost::andable< GenericOptRect<C> + , boost::andable< GenericOptRect<C>, typename CoordTraits<C>::RectType + > > > +{ + typedef typename CoordTraits<C>::IntervalType CInterval; + typedef typename CoordTraits<C>::OptIntervalType OptCInterval; + typedef typename CoordTraits<C>::PointType CPoint; + typedef typename CoordTraits<C>::RectType CRect; + typedef typename CoordTraits<C>::OptRectType OptCRect; + typedef boost::optional<CRect> Base; +public: + GenericOptRect() : Base() {} + GenericOptRect(GenericRect<C> const &a) : Base(CRect(a)) {} + GenericOptRect(CPoint const &a, CPoint const &b) : Base(CRect(a, b)) {} + /** + * Creates an empty OptRect when one of the argument intervals is empty. + */ + GenericOptRect(OptCInterval const &x_int, OptCInterval const &y_int) { + if (x_int && y_int) { + *this = CRect(*x_int, *y_int); + } + // else, stay empty. + } + + /** @brief Check for emptiness. */ + inline bool isEmpty() const { return !*this; }; + + bool intersects(CRect const &r) const { return r.intersects(*this); } + bool contains(CRect const &r) const { return *this && (*this)->contains(r); } + + bool intersects(OptCRect const &r) const { return *this && (*this)->intersects(r); } + bool contains(OptCRect const &r) const { return *this && (*this)->contains(r); } + + bool contains(CPoint const &p) const { return *this && (*this)->contains(p); } + + void unionWith(CRect const &b) { + if (*this) { + (*this)->unionWith(b); + } else { + *this = b; + } + } + void unionWith(OptCRect const &b) { + if (b) unionWith(*b); + } + void intersectWith(CRect const &b) { + if (!*this) return; + OptCInterval x = (**this)[X] & b[X], y = (**this)[Y] & b[Y]; + if (x && y) { + *this = CRect(*x, *y); + } else { + *(static_cast<Base*>(this)) = boost::none; + } + } + void intersectWith(OptCRect const &b) { + if (b) { + intersectWith(*b); + } else { + *(static_cast<Base*>(this)) = boost::none; + } + } + GenericOptRect<C> &operator|=(OptCRect const &b) { + unionWith(b); + return *this; + } + GenericOptRect<C> &operator&=(CRect const &b) { + intersectWith(b); + return *this; + } + GenericOptRect<C> &operator&=(OptCRect const &b) { + intersectWith(b); + return *this; + } +}; + +template <typename C> +inline void GenericRect<C>::unionWith(OptCRect const &b) { + if (b) { + unionWith(*b); + } +} +template <typename C> +inline bool GenericRect<C>::intersects(OptCRect const &r) const { + return r && intersects(*r); +} +template <typename C> +inline bool GenericRect<C>::contains(OptCRect const &r) const { + return !r || contains(*r); +} + +#ifdef _GLIBCXX_IOSTREAM +template <typename C> +inline std::ostream &operator<<(std::ostream &out, GenericRect<C> const &r) { + out << "X: " << r[X] << " Y: " << r[Y]; + return out; +} +#endif + +} // end namespace Geom + +#endif // LIB2GEOM_SEEN_RECT_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/hvlinesegment.h b/src/2geom/hvlinesegment.h index 9419be8f6..05252468e 100644 --- a/src/2geom/hvlinesegment.h +++ b/src/2geom/hvlinesegment.h @@ -1,8 +1,11 @@ /** * \file - * \brief Horizontal and Vertical Line Segment - * - * Copyright 2008 Marco Cecchetti <mrcekets at gmail.com> + * \brief Horizontal and vertical line segment + *//* + * Authors: + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * Copyright 2008-2011 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -28,14 +31,11 @@ * the specific language governing rights and limitations. */ - -#ifndef _2GEOM_HVLINESEGMENT_H_ -#define _2GEOM_HVLINESEGMENT_H_ - +#ifndef LIB2GEOM_SEEN_HVLINESEGMENT_H +#define LIB2GEOM_SEEN_HVLINESEGMENT_H #include <2geom/bezier-curve.h> - namespace Geom { @@ -44,6 +44,7 @@ class AxisLineSegment : public LineSegment { public: static const Dim2 other_axis = static_cast<Dim2>((axis + 1) % 2); +#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual void setInitial(Point const &p) { Point f = finalPoint(); f[axis] = p[axis]; @@ -106,10 +107,6 @@ public: if (d != axis) return initialPoint()[other_axis]; return initialPoint()[axis] + t * (finalPoint()[axis] - initialPoint()[axis]); } - - /** - * 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)); @@ -124,6 +121,7 @@ public: } return result; } +#endif protected: AxisLineSegment(Point const &p0, Point const &p1) : LineSegment(p0, p1) {} AxisLineSegment() {} @@ -171,6 +169,7 @@ public: return result; } +#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Curve* duplicate() const { return new HLineSegment(*this); } virtual Curve *portion(Coord f, Coord t) const { Point ip = pointAt(f); @@ -195,6 +194,7 @@ public: Coord x = finalPoint()[X] - initialPoint()[X]; return new HLineSegment(x, x, 0); } +#endif }; // end class HLineSegment @@ -241,6 +241,7 @@ public: return result; } +#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Curve *duplicate() const { return new VLineSegment(*this); } virtual Curve *portion(Coord f, Coord t) const { Point ip = pointAt(f); @@ -264,13 +265,12 @@ public: Coord y = finalPoint()[Y] - initialPoint()[Y]; return new VLineSegment(0, y, y); } +#endif }; // end class VLineSegment } // end namespace Geom - -#endif // _2GEOM_HVLINESEGMENT_H_ - +#endif // LIB2GEOM_SEEN_HVLINESEGMENT_H /* Local Variables: diff --git a/src/2geom/int-interval.h b/src/2geom/int-interval.h new file mode 100644 index 000000000..0faf48d80 --- /dev/null +++ b/src/2geom/int-interval.h @@ -0,0 +1,63 @@ +/** + * \file + * \brief Closed interval of integer values + *//* + * Copyright 2011 Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * 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 LIB2GEOM_SEEN_INT_INTERVAL_H +#define LIB2GEOM_SEEN_INT_INTERVAL_H + +#include <2geom/coord.h> +#include <2geom/generic-interval.h> + +namespace Geom { + +/** + * @brief Range of integers that is never empty. + * @ingroup Primitives + */ +typedef GenericInterval<IntCoord> IntInterval; + +/** + * @brief Range of integers that can be empty. + * @ingroup Primitives + */ +typedef GenericOptInterval<IntCoord> OptIntInterval; + +} // namespace Geom +#endif // !LIB2GEOM_SEEN_INT_INTERVAL_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/int-point.h b/src/2geom/int-point.h new file mode 100644 index 000000000..cf2fe720f --- /dev/null +++ b/src/2geom/int-point.h @@ -0,0 +1,157 @@ +/** + * \file + * \brief Cartesian point / 2D vector with integer coordinates + *//* + * Copyright 2011 Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * 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 LIB2GEOM_SEEN_INT_POINT_H +#define LIB2GEOM_SEEN_INT_POINT_H + +#include <stdexcept> +#include <boost/operators.hpp> +#include <2geom/coord.h> + +namespace Geom { + +/** + * @brief Two-dimensional point with integer coordinates. + * + * This class is an exact equivalent of Point, except it stores integer coordinates. + * Integer points are useful in contexts related to rasterized graphics, for example + * for bounding boxes when rendering SVG. + * + * @see Point + * @ingroup Primitives */ +class IntPoint + : boost::additive< IntPoint + , boost::totally_ordered< IntPoint + > > +{ + IntCoord _pt[2]; +public: + /// @name Creating integer points + /// @{ + IntPoint() { } + IntPoint(IntCoord x, IntCoord y) { + _pt[X] = x; + _pt[Y] = y; + } + IntPoint(IntPoint const &p) { + _pt[X] = p._pt[X]; + _pt[Y] = p._pt[Y]; + } + IntPoint &operator=(IntPoint const &p) { + _pt[X] = p._pt[X]; + _pt[Y] = p._pt[Y]; + return *this; + } + /// @} + + /// @name Access the coordinates of a point + /// @{ + IntCoord operator[](unsigned i) const { + if ( i > Y ) throw std::out_of_range("index out of range"); + return _pt[i]; + } + IntCoord &operator[](unsigned i) { + if ( i > Y ) throw std::out_of_range("index out of range"); + return _pt[i]; + } + IntCoord operator[](Dim2 d) const { return _pt[d]; } + IntCoord &operator[](Dim2 d) { return _pt[d]; } + /// @} + + /// @name Vector-like arithmetic operations + /// @{ + IntPoint &operator+=(IntPoint const &o) { + _pt[X] += o._pt[X]; + _pt[Y] += o._pt[Y]; + return *this; + } + IntPoint &operator-=(IntPoint const &o) { + _pt[X] -= o._pt[X]; + _pt[Y] -= o._pt[Y]; + return *this; + } + /// @} + + /// @name Various utilities + /// @{ + /** @brief Equality operator. */ + bool operator==(IntPoint const &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<(IntPoint const &p) const { + return ( ( _pt[Y] < p[Y] ) || + (( _pt[Y] == p[Y] ) && ( _pt[X] < p[X] ))); + } + /// @} + + /** @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()(IntPoint const &a, IntPoint const &b); + private: + Dim2 dim; + }; +}; + +template<> struct IntPoint::LexOrder<X> { + bool operator()(IntPoint const &a, IntPoint const &b) { + return a[X] < b[X] || (a[X] == b[X] && a[Y] < b[Y]); + } +}; +template<> struct IntPoint::LexOrder<Y> { + bool operator()(IntPoint const &a, IntPoint const &b) { + return a[Y] < b[Y] || (a[Y] == b[Y] && a[X] < b[X]); + } +}; +inline bool IntPoint::LexOrderRt::operator()(IntPoint const &a, IntPoint const &b) { + return dim ? IntPoint::LexOrder<Y>()(a, b) : IntPoint::LexOrder<X>()(a, b); +} + +} // namespace Geom + +#endif // !SEEN_GEOM_INT_POINT_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/int-rect.h b/src/2geom/int-rect.h new file mode 100644 index 000000000..a143b3ac5 --- /dev/null +++ b/src/2geom/int-rect.h @@ -0,0 +1,76 @@ +/** + * \file + * \brief Axis-aligned rectangle with integer coordinates + *//* + * Copyright 2011 Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * 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 LIB2GEOM_SEEN_INT_RECT_H +#define LIB2GEOM_SEEN_INT_RECT_H + +#include <2geom/coord.h> +#include <2geom/int-point.h> +#include <2geom/int-interval.h> +#include <2geom/generic-rect.h> + +namespace Geom { + +typedef GenericRect<IntCoord> IntRect; +typedef GenericOptRect<IntCoord> OptIntRect; + +// the functions below do not work when defined generically +inline OptIntRect operator&(IntRect const &a, IntRect const &b) { + OptIntRect ret(a); + ret.intersectWith(b); + return ret; +} +inline OptIntRect intersect(IntRect const &a, IntRect const &b) { + return a & b; +} +inline OptIntRect intersect(OptIntRect const &a, OptIntRect const &b) { + return a & b; +} +inline IntRect unify(IntRect const &a, IntRect const &b) { + return a | b; +} +inline OptIntRect unify(OptIntRect const &a, OptIntRect const &b) { + return a | b; +} + +} // end namespace Geom + +#endif // !LIB2GEOM_SEEN_INT_RECT_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/interval.h b/src/2geom/interval.h index a790a6c3b..ee6d674d2 100644 --- a/src/2geom/interval.h +++ b/src/2geom/interval.h @@ -37,19 +37,24 @@ #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 <2geom/isnan.h> +#include <2geom/math-utils.h> +#include <2geom/generic-interval.h> +#include <2geom/int-interval.h> namespace Geom { -class OptInterval; +/** + * @brief Range of real numbers that can be empty. + * @ingroup Primitives + */ +typedef GenericOptInterval<Coord> OptInterval; /** - * @brief Range of numbers that is never empty. + * @brief Range of real 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. @@ -57,32 +62,24 @@ class OptInterval; * @ingroup Primitives */ class Interval - : boost::equality_comparable< Interval - , boost::additive< Interval + : public GenericInterval<Coord> , boost::multipliable< Interval - , boost::arithmetic< Interval, Coord - , boost::orable< Interval - > > > > > + , boost::multipliable< Interval, Coord + > > { -private: - /// @invariant _b[0] <= _b[1] - Coord _b[2]; - + typedef GenericInterval<Coord> Base; public: /// @name Create intervals. /// @{ /** @brief Create an interval that contains only zero. */ - explicit Interval() { _b[0] = 0; _b[1] = 0; } + Interval() {} /** @brief Create an interval that contains a single point. */ - explicit Interval(Coord u) { _b[0] = _b[1] = u; } + explicit Interval(Coord u) : Base(u) {} /** @brief Create an interval that contains all points between @c u and @c v. */ - Interval(Coord u, Coord v) { - if (u <= v) { - _b[0] = u; _b[1] = v; - } else { - _b[0] = v; _b[1] = u; - } - } + Interval(Coord u, Coord v) : Base(u,v) {} + /** @brief Convert from integer interval */ + Interval(IntInterval const &i) : Base(i.min(), i.max()) {} + Interval(Base const &b) : Base(b) {} /** @brief Create an interval containing a range of values. * The resulting interval will contain all values from the given range. @@ -93,9 +90,7 @@ public: * @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); + Interval result = Base::from_range(start, end); return result; } /** @brief Create an interval from a C-style array of values it should contain. */ @@ -107,114 +102,38 @@ public: /// @name Inspect endpoints. /// @{ + /** @brief Access endpoints by value. + * @deprecated Use min() and max() instead */ Coord operator[](unsigned i) const { return _b[i]; } + /** @brief Access endpoints by reference. + * @deprecated Use min() and max() instead + * @todo Remove Interval index operator, which can be used to break the invariant */ 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]); + return IS_FINITE(min()) && IS_FINITE(max()); } /// @} /// @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]; } + bool interiorContains(Coord val) const { return min() < val && val < max(); } /** @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); - } + bool interiorContains(Interval const &val) const { return min() < val.min() && val.max() < max(); } /** @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? - /** @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] = val; - } else { - _b[0] = val; - } - } - /** @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] = val; - } else { - _b[1] = 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 - } - /** @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; - } - } - /** @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]; + return interiorContains(val.min()) || interiorContains(val.max()) || val.interiorContains(*this); } /// @} /// @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; - } + inline operator OptInterval() { return OptInterval(*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; @@ -229,25 +148,6 @@ public: 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: @@ -261,121 +161,25 @@ public: 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; - } /// @} -}; - -/** @brief Union two intervals - * @relates Interval */ -inline Interval unify(Interval const &a, Interval const &b) { - return a | b; -} - -/** - * @brief A range of numbers that can be empty. - * @ingroup Primitives - */ -class OptInterval - : public boost::optional<Interval> - , boost::orable< OptInterval - , boost::andable< OptInterval - > > -{ -public: - /// @name Create optionally empty intervals. + + /// @name Rounding to integer values /// @{ - /** @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)) {}; - - /** @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)); + /** @brief Return the smallest integer interval which contains this one. */ + IntInterval roundOutwards() const { + IntInterval ret(floor(min()), ceil(max())); 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); - } else { - *this = a; - } - } - } - 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; + /** @brief Return the largest integer interval which is contained in this one. */ + OptIntInterval roundInwards() const { + IntCoord u = ceil(min()), v = floor(max()); + if (u > v) { OptIntInterval e; return e; } + IntInterval ret(u, v); + return ret; } + /// @} }; -/** @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 -inline std::ostream &operator<< (std::ostream &os, - const Geom::Interval &I) { - os << "Interval("<<I[0] << ", "<<I[1] << ")"; - return os; -} -#endif - } #endif //SEEN_INTERVAL_H diff --git a/src/2geom/isnan.h b/src/2geom/isnan.h deleted file mode 100644 index e20ab7f87..000000000 --- a/src/2geom/isnan.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * \file - * \brief \todo brief description - * - * Authors: - * ? <?@?.?> - * - * Copyright ?-? 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_ISNAN_H__ -#define _2GEOM_ISNAN_H__ - -/* - * Temporary fix for various misdefinitions of isnan(). - * isnan() is becoming undef'd in some .h files. - * #include this last in your .cpp file to get it right. - * - * The problem is that isnan and isfinite are part of C99 but aren't part of - * the C++ standard (which predates C99). - * - * Authors: - * Inkscape groupies and obsessive-compulsives - * - * Copyright (C) 2004 authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - * - * 2005 modification hereby placed in public domain. Probably supercedes - * the 2004 copyright for the code itself. - */ - -#include <math.h> -/* You might try changing the above to <cmath> if you have problems. - * Whether you use math.h or cmath, you may need to edit the .cpp file - * and/or other .h files to use the same header file. - */ - -#if defined(__isnan) -# define IS_NAN(_a) (__isnan(_a)) -#elif defined(__APPLE__) && __GNUC__ == 3 -# define IS_NAN(_a) (__isnan(_a)) /* MacOSX/Darwin definition < 10.4 */ -#elif defined(WIN32) || defined(_isnan) -# define IS_NAN(_a) (_isnan(_a)) /* Win32 definition */ -#elif defined(isnan) || defined(__FreeBSD__) || defined(__osf__) -# define IS_NAN(_a) (isnan(_a)) /* GNU definition */ -#elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 -# define IS_NAN(_a) (isnan(_a)) /* GNU definition */ -#else -# define IS_NAN(_a) (std::isnan(_a)) -#endif -/* If the above doesn't work, then try (a != a). - * Also, please report a bug as per http://www.inkscape.org/report_bugs.php, - * giving information about what platform and compiler version you're using. - */ - - -#if defined(__isfinite) -# define IS_FINITE(_a) (__isfinite(_a)) -#elif defined(__APPLE__) && __GNUC__ == 3 -# define IS_FINITE(_a) (__isfinite(_a)) /* MacOSX/Darwin definition < 10.4 */ -#elif defined(__sgi) -# define IS_FINITE(_a) (_isfinite(_a)) -#elif defined(isfinite) -# define IS_FINITE(_a) (isfinite(_a)) -#elif defined(__osf__) -# define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a)) -#elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 -#include <ieeefp.h> -#define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a)) -#else -# define IS_FINITE(_a) (std::isfinite(_a)) -#endif -/* If the above doesn't work, then try (finite(_a) && !IS_NAN(_a)) or - * (!IS_NAN((_a) - (_a))). - * Also, please report a bug as per http://www.inkscape.org/report_bugs.php, - * giving information about what platform and compiler version you're using. - */ - - -#endif /* _2GEOM_ISNAN_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/line.h b/src/2geom/line.h index ccb0ae6c5..f2d31ecc6 100644 --- a/src/2geom/line.h +++ b/src/2geom/line.h @@ -1,8 +1,11 @@ /** * \file - * \brief Infinite Straight Line - * - * Copyright 2008 Marco Cecchetti <mrcekets at gmail.com> + * \brief Infinite straight line + *//* + * Authors: + * Marco Cecchetti <mrcekets at gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * Copyright 2008-2011 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -28,22 +31,17 @@ * the specific language governing rights and limitations. */ -#ifndef _2GEOM_LINE_H_ -#define _2GEOM_LINE_H_ - +#ifndef LIB2GEOM_SEEN_LINE_H +#define LIB2GEOM_SEEN_LINE_H #include <cmath> - +#include <boost/optional.hpp> #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 { @@ -226,8 +224,8 @@ public: * @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); + result.setOrigin(pointAt(t)); + result.setVersor(m_versor); return result; } @@ -448,17 +446,16 @@ OptCrossing intersection(LineSegment const& ls1, LineSegment const& ls2); } // end namespace Geom -#endif // _2GEOM_LINE_H_ +#endif // LIB2GEOM_SEEN_LINE_H /* Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(substatement-open . 0)) + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil - c-brace-offset:0 fill-column:99 End: - vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : */ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/linear.h b/src/2geom/linear.h index 1b6cca071..df6dd9904 100644 --- a/src/2geom/linear.h +++ b/src/2geom/linear.h @@ -35,7 +35,7 @@ #ifndef SEEN_LINEAR_H #define SEEN_LINEAR_H #include <2geom/interval.h> -#include <2geom/isnan.h> +#include <2geom/math-utils.h> //#define USE_SBASIS_OF diff --git a/src/2geom/math-utils.h b/src/2geom/math-utils.h index 2c348f54b..77280aa50 100644 --- a/src/2geom/math-utils.h +++ b/src/2geom/math-utils.h @@ -1,6 +1,3 @@ -#ifndef LIB2GEOM_MATH_UTILS_HEADER -#define LIB2GEOM_MATH_UTILS_HEADER - /** * \file * \brief Low level math functions and compatibility wrappers @@ -36,6 +33,9 @@ * */ +#ifndef LIB2GEOM_SEEN_MATH_UTILS_H +#define LIB2GEOM_SEEN_MATH_UTILS_H + #include "config.h" #include <math.h> // sincos is usually only available in math.h #include <cmath> @@ -92,10 +92,51 @@ inline void sincos(double angle, double &sin_, double &cos_) { #endif } -} +/* Temporary fix for various misdefinitions of isnan(). + * isnan() is becoming undef'd in some .h files. + * #include this last in your .cpp file to get it right. + * + * The problem is that isnan and isfinite are part of C99 but aren't part of + * the C++ standard (which predates C99). + */ + +#if defined(__isnan) +# define IS_NAN(_a) (__isnan(_a)) +#elif defined(__APPLE__) && __GNUC__ == 3 +# define IS_NAN(_a) (__isnan(_a)) /* MacOSX/Darwin definition < 10.4 */ +#elif defined(WIN32) || defined(_isnan) +# define IS_NAN(_a) (_isnan(_a)) /* Win32 definition */ +#elif defined(isnan) || defined(__FreeBSD__) || defined(__osf__) +# define IS_NAN(_a) (isnan(_a)) /* GNU definition */ +#elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 +# define IS_NAN(_a) (isnan(_a)) /* GNU definition */ +#else +# define IS_NAN(_a) (std::isnan(_a)) +#endif +/* If the above doesn't work, then try (a != a). */ + +#if defined(__isfinite) +# define IS_FINITE(_a) (__isfinite(_a)) +#elif defined(__APPLE__) && __GNUC__ == 3 +# define IS_FINITE(_a) (__isfinite(_a)) /* MacOSX/Darwin definition < 10.4 */ +#elif defined(__sgi) +# define IS_FINITE(_a) (_isfinite(_a)) +#elif defined(isfinite) +# define IS_FINITE(_a) (isfinite(_a)) +#elif defined(__osf__) +# define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a)) +#elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2 +#include <ieeefp.h> +#define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a)) +#else +# define IS_FINITE(_a) (std::isfinite(_a)) #endif +} // end namespace Geom + +#endif // LIB2GEOM_SEEN_MATH_UTILS_H + /* Local Variables: mode:c++ diff --git a/src/2geom/ord.h b/src/2geom/ord.h index ca91af579..ce524ebf7 100644 --- a/src/2geom/ord.h +++ b/src/2geom/ord.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Comparator template + *//* * Authors: * ? <?@?.?> * diff --git a/src/2geom/path-intersection.h b/src/2geom/path-intersection.h index de2a5b02c..2470e44fb 100644 --- a/src/2geom/path-intersection.h +++ b/src/2geom/path-intersection.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Path intersection + *//* * Authors: * ? <?@?.?> * diff --git a/src/2geom/path.h b/src/2geom/path.h index cbd449248..48d7acaaf 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -1,12 +1,12 @@ /** * \file * \brief Path - Series of continuous curves - * + *//* * Authors: - * MenTaLguY <mental@rydia.net> - * Marco Cecchetti <mrcekets at gmail.com> + * MenTaLguY <mental@rydia.net> + * Marco Cecchetti <mrcekets at gmail.com> * - * Copyright 2007-2008 authors + * Copyright 2007-2008 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,23 +32,16 @@ * the specific language governing rights and limitations. */ +#ifndef LIB2GEOM_SEEN_PATH_H +#define LIB2GEOM_SEEN_PATH_H - - -#ifndef SEEN_GEOM_PATH_H -#define SEEN_GEOM_PATH_H - - +#include <iterator> +#include <algorithm> #include <boost/shared_ptr.hpp> #include <2geom/curve.h> #include <2geom/bezier-curve.h> -#include <iterator> -#include <algorithm> - - -namespace Geom -{ +namespace Geom { class Path; @@ -696,17 +689,13 @@ Coord nearest_point(Point const& p, Path const& c) namespace std { template <> -inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b) -{ +inline void swap<Geom::Path>(Geom::Path &a, Geom::Path &b) { a.swap(b); } } // end namespace std -#endif // SEEN_GEOM_PATH_H - - - +#endif // LIB2GEOM_SEEN_PATH_H /* Local Variables: diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 2f45b9d86..2b690a005 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -1,10 +1,9 @@ /** * \file - * \brief PathVector - std::vector containing Geom::Path + * \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> * @@ -34,8 +33,8 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_GEOM_PATHVECTOR_H -#define SEEN_GEOM_PATHVECTOR_H +#ifndef LIB2GEOM_SEEN_PATHVECTOR_H +#define LIB2GEOM_SEEN_PATHVECTOR_H #include <2geom/forward.h> #include <2geom/path.h> @@ -122,11 +121,9 @@ Point pointAt(PathVector const & path_in, PathVectorPosition const pvp) { return path_in[pvp.path_nr].pointAt(pvp.t); } - - } // end namespace Geom -#endif // SEEN_GEOM_PATHVECTOR_H +#endif // LIB2GEOM_SEEN_PATHVECTOR_H /* Local Variables: diff --git a/src/2geom/piecewise.h b/src/2geom/piecewise.h index 19c66d8f0..837f33ea7 100644 --- a/src/2geom/piecewise.h +++ b/src/2geom/piecewise.h @@ -32,13 +32,13 @@ #ifndef SEEN_GEOM_PW_SB_H #define SEEN_GEOM_PW_SB_H -#include <2geom/sbasis.h> #include <vector> #include <map> - -#include <2geom/concepts.h> -#include <2geom/isnan.h> #include <boost/concept_check.hpp> +#include <2geom/concepts.h> +#include <2geom/math-utils.h> +#include <2geom/sbasis.h> + namespace Geom { /** diff --git a/src/2geom/point-l.h b/src/2geom/point-l.h deleted file mode 100644 index d57314a19..000000000 --- a/src/2geom/point-l.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef SEEN_Geom_POINT_L_H -#define SEEN_Geom_POINT_L_H - -#include <stdexcept> -#include <2geom/point.h> - -namespace Geom { - -typedef long ICoord; - -class IPoint { - ICoord _pt[2]; - - public: - IPoint() { } - - IPoint(ICoord x, ICoord y) { - _pt[X] = x; - _pt[Y] = y; - } - - IPoint(NRPointL const &p) { - _pt[X] = p.x; - _pt[Y] = p.y; - } - - IPoint(IPoint const &p) { - for (unsigned i = 0; i < 2; ++i) { - _pt[i] = p._pt[i]; - } - } - - IPoint &operator=(IPoint const &p) { - for (unsigned i = 0; i < 2; ++i) { - _pt[i] = p._pt[i]; - } - return *this; - } - - operator Point() { - return Point(_pt[X], _pt[Y]); - } - - ICoord operator[](unsigned i) const throw(std::out_of_range) { - if ( i > Y ) throw std::out_of_range("index out of range"); - return _pt[i]; - } - - ICoord &operator[](unsigned i) throw(std::out_of_range) { - if ( i > Y ) throw std::out_of_range("index out of range"); - return _pt[i]; - } - - ICoord operator[](Dim2 d) const throw() { return _pt[d]; } - ICoord &operator[](Dim2 d) throw() { return _pt[d]; } - - IPoint &operator+=(IPoint const &o) { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - _pt[i] += o._pt[i]; - } - return *this; - } - - IPoint &operator-=(IPoint const &o) { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - _pt[i] -= o._pt[i]; - } - return *this; - } -}; - - -} // namespace Geom - -#endif /* !SEEN_Geom_POINT_L_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/point.cpp b/src/2geom/point.cpp index a9005ef61..cafc0fdba 100644 --- a/src/2geom/point.cpp +++ b/src/2geom/point.cpp @@ -1,3 +1,38 @@ +/** + * \file + * \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 <assert.h> #include <math.h> #include <2geom/point.h> @@ -14,8 +49,8 @@ namespace Geom { * from the origin (point at 0,0) to the stored coordinates, * and has methods implementing several vector operations (like length()). * - * \par Operator note - * \par + * @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: @@ -149,12 +184,11 @@ Point unit_vector(Point const &a) * 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. + * @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. + * @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) { @@ -178,8 +212,8 @@ Point &Point::operator*=(Affine const &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 +/** @brief Snap the angle B - A - dir to multiples of \f$2\pi/n\f$. + * The 'dir' argument must be normalized (have 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) diff --git a/src/2geom/point.h b/src/2geom/point.h index 3c6e12eff..69da8a4ae 100644 --- a/src/2geom/point.h +++ b/src/2geom/point.h @@ -42,7 +42,7 @@ #include <boost/operators.hpp> #include <2geom/forward.h> #include <2geom/coord.h> -#include <2geom/isnan.h> //temporary fix for isnan() +#include <2geom/int-point.h> #include <2geom/math-utils.h> #include <2geom/utils.h> @@ -61,8 +61,9 @@ class Point > > > > > > > > > // this uses chaining so it looks weird, but works { Coord _pt[2]; - public: + /// @name Create points + /// @{ /** Construct a point on the origin. */ Point() { _pt[X] = _pt[Y] = 0; } @@ -71,6 +72,11 @@ public: Point(Coord x, Coord y) { _pt[X] = x; _pt[Y] = y; } + /** Construct from integer point. */ + Point(IntPoint const &p) { + _pt[X] = p[X]; + _pt[Y] = p[Y]; + } Point(Point const &p) { for (unsigned i = 0; i < 2; ++i) _pt[i] = p._pt[i]; @@ -80,6 +86,23 @@ public: _pt[i] = p._pt[i]; return *this; } + /** @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; + } + /// @} /// @name Access the coordinates of a point /// @{ @@ -157,57 +180,54 @@ public: } /// @} - /// @name Various utilities + /// @name Conversion to integer points /// @{ - /** @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; + /** @brief Round to nearest integer coordinates. */ + IntPoint round() const { + IntPoint ret(::round(_pt[X]), ::round(_pt[Y])); + return ret; + } + /** @brief Round coordinates downwards. */ + IntPoint floor() const { + IntPoint ret(::floor(_pt[X]), ::floor(_pt[Y])); + return ret; + } + /** @brief Round coordinates upwards. */ + IntPoint ceil() const { + IntPoint ret(::ceil(_pt[X]), ::ceil(_pt[Y])); + return ret; } + /// @} - /** @brief Check whether both coordinates are finite. - * @return True if neither coordinate is infinite. */ + /// @name Various utilities + /// @{ + /** @brief Check whether both coordinates are finite. */ bool isFinite() const { for ( unsigned i = 0 ; i < 2 ; ++i ) { if(!IS_FINITE(_pt[i])) return false; } return true; } + /** @brief Check whether both coordinates are zero. */ + bool isZero() const { + return _pt[X] == 0 && _pt[Y] == 0; + } + /** @brief Check whether the length of the vector is close to 1. */ + bool isNormalized(Coord eps=EPSILON) const { + return are_near(length(), 1.0, eps); + } /** @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])); + 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; + return _pt[Y] < p[Y] || (_pt[Y] == p[Y] && _pt[X] < p[X]); } /// @} @@ -315,7 +335,7 @@ inline Point lerp(double const t, Point const &a, Point const &b) * 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*/ + * @relates Point */ inline Coord dot(Point const &a, Point const &b) { return a[0] * b[0] + a[1] * b[1]; @@ -349,8 +369,8 @@ 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); +double atan2(Point const &p); +double angle_between(Point const &a, Point const &b); Point abs(Point const &b); Point constrain_angle(Point const &A, Point const &B, unsigned int n = 4, Geom::Point const &dir = Geom::Point(1,0)); diff --git a/src/2geom/poly.h b/src/2geom/poly.h index 3567bda6d..7d93d0a85 100644 --- a/src/2geom/poly.h +++ b/src/2geom/poly.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Polynomial in canonical (monomial) basis + *//* * Authors: * ? <?@?.?> * @@ -34,7 +34,6 @@ #ifndef LIB2GEOM_SEEN_POLY_H #define LIB2GEOM_SEEN_POLY_H - #include <assert.h> #include <vector> #include <iostream> diff --git a/src/2geom/quadtree.h b/src/2geom/quadtree.h index 01ea33ed7..949a9b898 100644 --- a/src/2geom/quadtree.h +++ b/src/2geom/quadtree.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Quad tree data structure + *//* * Authors: * ? <?@?.?> * diff --git a/src/2geom/ray.h b/src/2geom/ray.h index 638b86195..75cc72005 100644 --- a/src/2geom/ray.h +++ b/src/2geom/ray.h @@ -1,7 +1,7 @@ /** * \file - * \brief Infinite Straight Ray - * + * \brief Infinite straight ray + *//* * Copyright 2008 Marco Cecchetti <mrcekets at gmail.com> * * This library is free software; you can redistribute it and/or @@ -35,6 +35,7 @@ #include <2geom/point.h> #include <2geom/bezier-curve.h> // for LineSegment #include <2geom/exception.h> +#include <2geom/math-utils.h> namespace Geom { @@ -49,171 +50,88 @@ namespace Geom */ class Ray { private: - Point m_origin; - Point m_versor; + Point _origin; + Point _versor; public: - Ray() - : m_origin(0,0), m_versor(1,0) - { - } - - Ray(Point const& _origin, Coord angle ) - : m_origin(_origin), m_versor(std::cos(angle), std::sin(angle)) - { - } - - Ray(Point const& A, Point const& B) - { - setBy2Points(A, B); - } - - 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; - } - - Coord angle() const - { - double a = std::atan2(m_versor[Y], m_versor[X]); - if (a < 0) a += 2*M_PI; - 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 - { - if (t < 0) THROW_RANGEERROR("Ray::pointAt, negative t value passed"); - return m_origin + m_versor * t; - } - - Coord valueAt(Coord t, Dim2 d) const - { - if (t < 0) - THROW_RANGEERROR("Ray::valueAt, negative t value passed"); - 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 ) - { - double t = (v - m_origin[d]) / m_versor[d]; - if (t >= 0) result.push_back(t); - } - // 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 nearestPoint(Point const& _point) const - { - if ( isDegenerate() ) return 0; - double t = dot( _point - m_origin, m_versor ); - if (t < 0) t = 0; - return t; - } - - Ray reverse() const - { - Ray 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 transformed(Affine const& m) const - { - return Ray(m_origin * m, (m_origin + m_versor) * m); - } -}; // end class ray + Ray() : _origin(0,0), _versor(1,0) {} + Ray(Point const& origin, Coord angle) + : _origin(origin) + { + sincos(angle, _versor[Y], _versor[X]); + } + Ray(Point const& A, Point const& B) { + setPoints(A, B); + } + Point origin() const { return _origin; } + Point versor() const { return _versor; } + void setOrigin(Point const &o) { _origin = o; } + void setVersor(Point const& v) { _versor = v; } + Coord angle() const { return std::atan2(_versor[Y], _versor[X]); } + void setAngle(Coord a) { sincos(a, _versor[Y], _versor[X]); } + void setPoints(Point const &a, Point const &b) { + _origin = a; + _versor = b - a; + if (are_near(_versor, Point(0,0)) ) + _versor = Point(0,0); + else + _versor.normalize(); + } + bool isDegenerate() const { + return ( _versor[X] == 0 && _versor[Y] == 0 ); + } + Point pointAt(Coord t) const { + return _origin + _versor * t; + } + Coord valueAt(Coord t, Dim2 d) const { + return _origin[d] + _versor[d] * t; + } + std::vector<Coord> roots(Coord v, Dim2 d) const { + std::vector<Coord> result; + if ( _versor[d] != 0 ) { + double t = (v - _origin[d]) / _versor[d]; + if (t >= 0) result.push_back(t); + } else if (_versor[(d+1)%2] == v) { + THROW_INFINITESOLUTIONS(); + } + return result; + } + Coord nearestPoint(Point const& point) const { + if ( isDegenerate() ) return 0; + double t = dot(point - _origin, _versor); + if (t < 0) t = 0; + return t; + } + Ray reverse() const { + Ray result; + result.setOrigin(_origin); + result.setVersor(-_versor); + return result; + } + Curve *portion(Coord f, Coord t) const { + return new LineSegment(pointAt(f), pointAt(t)); + } + LineSegment segment(Coord f, Coord t) const { + return LineSegment(pointAt(f), pointAt(t)); + } + Ray transformed(Affine const& m) const { + return Ray(_origin * m, (_origin + _versor) * m); + } +}; // end class Ray inline -double distance(Point const& _point, Ray const& _ray) -{ +double distance(Point const& _point, Ray const& _ray) { double t = _ray.nearestPoint(_point); return ::Geom::distance(_point, _ray.pointAt(t)); } inline -bool are_near(Point const& _point, Ray const& _ray, double eps = EPSILON) -{ +bool are_near(Point const& _point, Ray const& _ray, double eps = EPSILON) { return are_near(distance(_point, _ray), 0, eps); } inline -bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) -{ +bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) { return are_near(r1.versor(), r2.versor(), eps) && are_near(r1.origin(), r2.origin(), eps); } @@ -221,15 +139,13 @@ bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) // evaluate the angle between r1 and r2 rotating r1 in cw or ccw direction on r2 // the returned value is an angle in the interval [0, 2PI[ inline -double angle_between(Ray const& r1, Ray const& r2, bool cw = true) -{ +double angle_between(Ray const& r1, Ray const& r2, bool cw = true) { double angle = angle_between(r1.versor(), r2.versor()); if (angle < 0) angle += 2*M_PI; if (!cw) angle = 2*M_PI - angle; return angle; } - inline Ray make_angle_bisector_ray(Ray const& r1, Ray const& r2) { @@ -243,22 +159,17 @@ Ray make_angle_bisector_ray(Ray const& r1, Ray const& r2) return Ray(r1.origin(), M); } - } // end namespace Geom - - -#endif /*_2GEOM_RAY_H_*/ - +#endif // LIB2GEOM_SEEN_RAY_H /* Local Variables: mode:c++ c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(substatement-open . 0)) + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil - c-brace-offset:0 fill-column:99 End: - vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : */ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/rect.cpp b/src/2geom/rect.cpp new file mode 100644 index 000000000..0cb842d29 --- /dev/null +++ b/src/2geom/rect.cpp @@ -0,0 +1,98 @@ +/* Axis-aligned rectangle + * + * Authors: + * Michael Sloan <mgsloan@gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * Copyright 2007-2011 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/rect.h> + +namespace Geom { + +/** @brief Transform the rectangle by an affine. + * The result of the transformation might not be axis-aligned. The return value + * of this operation will be the smallest axis-aligned rectangle containing + * all points of the true result. */ +Rect &Rect::operator*=(Affine const &m) { + Point pts[4]; + for (unsigned i=0; i<4; ++i) pts[i] = corner(i) * m; + Coord minx = std::min(std::min(pts[0][X], pts[1][X]), std::min(pts[2][X], pts[3][X])); + Coord miny = std::min(std::min(pts[0][Y], pts[1][Y]), std::min(pts[2][Y], pts[3][Y])); + Coord maxx = std::max(std::max(pts[0][X], pts[1][X]), std::max(pts[2][X], pts[3][X])); + Coord maxy = std::max(std::max(pts[0][Y], pts[1][Y]), std::max(pts[2][Y], pts[3][Y])); + f[X].setMin(minx); f[X].setMax(maxx); + f[Y].setMin(miny); f[Y].setMax(maxy); + return *this; +} + +Coord distanceSq(Point const &p, Rect const &rect) +{ + double dx = 0, dy = 0; + if ( p[X] < rect.left() ) { + dx = p[X] - rect.left(); + } else if ( p[X] > rect.right() ) { + dx = rect.right() - p[X]; + } + if (p[Y] < rect.top() ) { + dy = rect.top() - p[Y]; + } else if ( p[Y] > rect.bottom() ) { + dy = p[Y] - rect.bottom(); + } + return dx*dx+dy*dy; +} + +/** @brief Returns the smallest distance between p and rect. + * @relates Rect */ +Coord distance(Point const &p, Rect const &rect) +{ + // copy of distanceSq, because we need to use hypot() + double dx = 0, dy = 0; + if ( p[X] < rect.left() ) { + dx = p[X] - rect.left(); + } else if ( p[X] > rect.right() ) { + dx = rect.right() - p[X]; + } + if (p[Y] < rect.top() ) { + dy = rect.top() - p[Y]; + } else if ( p[Y] > rect.bottom() ) { + dy = p[Y] - rect.bottom(); + } + return hypot(dx, dy); +} + +} // namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/rect.h b/src/2geom/rect.h index 65bb1bb76..e9f6cbeb7 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -2,7 +2,10 @@ * \file * \brief Axis-aligned rectangle *//* - * Copyright 2007 Michael Sloan <mgsloan@gmail.com> + * Authors: + * Michael Sloan <mgsloan@gmail.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * Copyright 2007-2011 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -34,48 +37,42 @@ * MenTaLguY <mental@rydia.net> */ -#include <2geom/d2.h> - -#ifndef LIB2GEOM_RECT_H -#define LIB2GEOM_RECT_H +#ifndef LIB2GEOM_SEEN_RECT_H +#define LIB2GEOM_SEEN_RECT_H +#include <boost/optional.hpp> #include <2geom/affine.h> -#include <boost/optional/optional.hpp> +#include <2geom/interval.h> +#include <2geom/int-rect.h> namespace Geom { /** - * @brief Axis-aligned, non-empty rectangle - convenience typedef + * @brief Axis-aligned rectangle that can be empty. * @ingroup Primitives */ -typedef D2<Interval> Rect; -class OptRect; - -inline Rect unify(Rect const &, Rect const &); +typedef GenericOptRect<Coord> OptRect; /** * @brief Axis aligned, non-empty rectangle. * @ingroup Primitives */ -template<> -class D2<Interval> { -private: - Interval f[2]; +class Rect + : public GenericRect<Coord> + , boost::multipliable< Rect, Affine > +{ + typedef GenericRect<Coord> Base; public: /// @name Create rectangles. /// @{ /** @brief Create a rectangle that contains only the point at (0,0). */ - D2<Interval>() { f[X] = f[Y] = Interval(); } + Rect() {} /** @brief Create a rectangle from X and Y intervals. */ - D2<Interval>(Interval const &a, Interval const &b) { - f[X] = a; - f[Y] = b; - } + Rect(Interval const &a, Interval const &b) : Base(a,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]); - } + Rect(Point const &a, Point const &b) : Base(a,b) {} + Rect(Coord x0, Coord y0, Coord x1, Coord y1) : Base(x0, y0, x1, y1) {} + Rect(Base const &b) : Base(b) {} /** @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. @@ -85,12 +82,7 @@ public: * @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); - } + Rect result = Base::from_range(start, end); return result; } /** @brief Create a rectangle from a C-style array of points it should contain. */ @@ -98,264 +90,97 @@ public: Rect result = Rect::from_range(c, c+n); return result; } + static Rect from_xywh(Coord x, Coord y, Coord w, Coord h) { + Rect result = Base::from_xywh(x, y, w, h); + return result; + } + static Rect from_xywh(Point const &o, Point const &dim) { + Rect result = Base::from_xywh(o, dim); + return result; + } /// @} /// @name Inspect dimensions. /// @{ - Interval& operator[](unsigned i) { return f[i]; } - Interval const & operator[](unsigned i) const { return f[i]; } - - 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()); - case 1: return Point(f[X].max(), f[Y].min()); - case 2: return Point(f[X].max(), f[Y].max()); - default: return Point(f[X].min(), f[Y].max()); - } - } - - //We should probably remove these - they're coord sys gnostic - /** @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(); } - - /** @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. - * - * 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. - */ - /** @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); } - - /** @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()); } + bool hasZeroArea(Coord eps = EPSILON) const { return (area() <= eps); } /// @} /// @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]); - } /** @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]); } - /** @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]); + /// @name Rounding to integer coordinates + /// @{ + /** @brief Return the smallest integer rectangle which contains this one. */ + IntRect roundOutwards() const { + IntRect ir(f[X].roundOutwards(), f[Y].roundOutwards()); + return ir; } - /** @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]); + /** @brief Return the largest integer rectangle which is contained in this one. */ + OptIntRect roundInwards() const { + OptIntRect oir(f[X].roundInwards(), f[Y].roundInwards()); + return oir; } /// @} - /// @name Modify the rectangle. + /// @name Operators /// @{ - /** @brief Enlarge the rectangle to contain the given point. */ - void expandTo(Point p) { - f[X].expandTo(p[X]); f[Y].expandTo(p[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); - - //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); - } - /** @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]); - } + Rect &operator*=(Affine const &m); /// @} }; -inline Rect unify(Rect const & a, Rect const & b) { - return Rect(unify(a[X], b[X]), unify(a[Y], b[Y])); +Coord distanceSq(Point const &p, Rect const &rect); +Coord distance(Point const &p, Rect const &rect); + +inline bool Rect::interiorContains(OptRect const &r) const { + return !r || interiorContains(static_cast<Rect const &>(*r)); } -inline Rect union_list(std::vector<Rect> const &r) { - if(r.empty()) return Rect(Interval(0,0), Interval(0,0)); - Rect ret = r[0]; - for(unsigned i = 1; i < r.size(); i++) - ret.unionWith(r[i]); +// the functions below do not work when defined generically +inline OptRect operator&(Rect const &a, Rect const &b) { + OptRect ret(a); + ret.intersectWith(b); return ret; } - -inline -Coord distanceSq( Point const& p, Rect const& rect ) -{ - double dx = 0, dy = 0; - if ( p[X] < rect.left() ) - { - dx = p[X] - rect.left(); - } - else if ( p[X] > rect.right() ) - { - dx = rect.right() - p[X]; - } - if ( p[Y] < rect.top() ) - { - dy = rect.top() - p[Y]; - } - else if ( p[Y] > rect.bottom() ) - { - dy = p[Y] - rect.bottom(); - } - return dx*dx + dy*dy; +inline OptRect intersect(Rect const &a, Rect const &b) { + return a & b; } - -/** - * Returns the smallest distance between p and rect. - */ -inline -Coord distance( Point const& p, Rect const& rect ) -{ - return std::sqrt(distanceSq(p, rect)); +inline OptRect intersect(OptRect const &a, OptRect const &b) { + return a & b; } - -/** - * @brief Axis-aligned rectangle that can be empty. - * @ingroup Primitives - */ -class OptRect : public boost::optional<Rect> { -public: - OptRect() : boost::optional<Rect>() {}; - OptRect(Rect const &a) : boost::optional<Rect>(a) {}; - - /** - * Creates an empty OptRect when one of the argument intervals is empty. - */ - OptRect(OptInterval const &x_int, OptInterval const &y_int) { - if (x_int && y_int) { - *this = Rect(*x_int, *y_int); - } - // else, stay empty. - } - - /** @brief Check for emptiness. */ - inline bool isEmpty() const { return (*this == false); }; - - 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 (*this) { // check that we are not empty - (*this)->unionWith(b); - } else { - *this = b; - } - } -}; - - -/** - * Returns the smallest rectangle that encloses both rectangles. - * An empty argument is assumed to be an empty rectangle - */ -inline OptRect unify(OptRect const & a, OptRect const & b) { - if (!a) { - return b; - } else if (!b) { - return a; - } else { - return unify(*a, *b); - } +inline Rect unify(Rect const &a, Rect const &b) { + return a | b; } - -inline OptRect intersect(Rect const & a, Rect const & b) { - return OptRect(intersect(a[X], b[X]), intersect(a[Y], b[Y])); +inline OptRect unify(OptRect const &a, OptRect const &b) { + return a | b; } -inline void Rect::unionWith(OptRect const &b) { - if (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); +/** @brief Union a list of rectangles + * @deprecated Use OptRect::from_range instead */ +inline Rect union_list(std::vector<Rect> const &r) { + if(r.empty()) return Rect(Interval(0,0), Interval(0,0)); + Rect ret = r[0]; + for(unsigned i = 1; i < r.size(); i++) + ret.unionWith(r[i]); + return ret; } } // end namespace Geom -#endif //_2GEOM_RECT +#endif // LIB2GEOM_SEEN_RECT_H /* Local Variables: diff --git a/src/2geom/region.h b/src/2geom/region.h index e23d6a158..06a4f63e9 100644 --- a/src/2geom/region.h +++ b/src/2geom/region.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Uncrossed path for boolean algorithms + *//* * Authors: * ? <?@?.?> * diff --git a/src/2geom/sbasis-2d.h b/src/2geom/sbasis-2d.h index f1218b028..00429e259 100644 --- a/src/2geom/sbasis-2d.h +++ b/src/2geom/sbasis-2d.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Obsolete 2D SBasis function class + *//* * Authors: * Nathan Hurst <?@?.?> * JFBarraud <?@?.?> diff --git a/src/2geom/sbasis-curve.h b/src/2geom/sbasis-curve.h index 22fe4fc1f..554b702e6 100644 --- a/src/2geom/sbasis-curve.h +++ b/src/2geom/sbasis-curve.h @@ -33,8 +33,8 @@ * the specific language governing rights and limitations. */ -#ifndef _2GEOM_SBASIS_CURVE_H_ -#define _2GEOM_SBASIS_CURVE_H_ +#ifndef LIB2GEOM_SEEN_SBASIS_CURVE_H +#define LIB2GEOM_SEEN_SBASIS_CURVE_H #include <2geom/curve.h> #include <2geom/nearest-point.h> @@ -45,24 +45,45 @@ 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 + * Symmetric power basis (S-basis for short) polynomials are a versatile numeric + * representation of arbitrary continuous curves. They are the main representation of curves * in 2Geom. * + * S-basis is defined for odd degrees and composed of the following polynomials: + * \f{align*}{ + P_k^0(t) &= t^k (1-t)^{k+1} \\ + P_k^1(t) &= t^{k+1} (1-t)^k \f} + * This can be understood more easily with the help of the chart below. Each square + * represents a product of a specific number of \f$t\f$ and \f$(1-t)\f$ terms. Red dots + * are the canonical (monomial) basis, the green dots are the Bezier basis, and the blue + * dots are the S-basis, all of them of degree 7. + * + * @image html sbasis.png "Illustration of the monomial, Bezier and symmetric power bases" + * + * The S-Basis has several important properties: + * - S-basis polynomials are closed under multiplication. + * - Evaluation is fast, using a modified Horner scheme. + * - Degree change is as trivial as in the monomial basis. To elevate, just add extra + * zero coefficients. To reduce the degree, truncate the terms in the highest powers. + * Compare this with Bezier curves, where degree change is complicated. + * - Conversion between S-basis and Bezier basis is numerically stable. + * + * More in-depth information can be found in the following paper: + * J Sanchez-Reyes, "The symmetric analogue of the polynomial power basis". + * ACM Transactions on Graphics, Vol. 16, No. 3, July 1997, pages 319--357. + * http://portal.acm.org/citation.cfm?id=256162 + * * @ingroup Curves */ class SBasisCurve : public Curve { - private: - SBasisCurve(); D2<SBasis> inner; public: explicit SBasisCurve(D2<SBasis> const &sb) : inner(sb) {} explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {} +#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Curve *duplicate() const { return new SBasisCurve(*this); } virtual Point initialPoint() const { return inner.at0(); } virtual Point finalPoint() const { return inner.at1(); } @@ -104,16 +125,12 @@ public: virtual int degreesOfFreedom() const { return inner[0].degreesOfFreedom() + inner[1].degreesOfFreedom(); } +#endif }; - } // end namespace Geom - -#endif // _2GEOM_SBASIS_CURVE_H_ - - - +#endif // LIB2GEOM_SEEN_SBASIS_CURVE_H /* Local Variables: diff --git a/src/2geom/sbasis-to-bezier.h b/src/2geom/sbasis-to-bezier.h index 5b88a40fa..819aa87d6 100644 --- a/src/2geom/sbasis-to-bezier.h +++ b/src/2geom/sbasis-to-bezier.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Conversion between SBasis and Bezier basis polynomials + *//* * Authors: * ? <?@?.?> * diff --git a/src/2geom/sbasis.cpp b/src/2geom/sbasis.cpp index e313ad08d..89640af5c 100644 --- a/src/2geom/sbasis.cpp +++ b/src/2geom/sbasis.cpp @@ -34,7 +34,7 @@ #include <cmath> #include <2geom/sbasis.h> -#include <2geom/isnan.h> +#include <2geom/math-utils.h> namespace Geom{ diff --git a/src/2geom/sbasis.h b/src/2geom/sbasis.h index b1b0b6c2a..7a7e33fe4 100644 --- a/src/2geom/sbasis.h +++ b/src/2geom/sbasis.h @@ -345,7 +345,7 @@ SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, doubl \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])); } +inline SBasis portion(const SBasis &t, Interval ivl) { return compose(t, Linear(ivl.min(), ivl.max())); } // compute f(g) inline SBasis diff --git a/src/2geom/sturm.h b/src/2geom/sturm.h deleted file mode 100644 index 4fef1b954..000000000 --- a/src/2geom/sturm.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef LIB2GEOM_STURM_HEADER -#define LIB2GEOM_STURM_HEADER - -#include <2geom/poly.h> -#include <2geom/utils.h> - -namespace Geom { - -class sturm : public std::vector<Poly>{ -public: - sturm(Poly const &X) { - push_back(X); - push_back(derivative(X)); - Poly Xi = back(); - Poly Xim1 = X; - std::cout << "sturm:\n" << Xim1 << std::endl; - std::cout << Xi << std::endl; - while(Xi.size() > 1) { - Poly r; - divide(Xim1, Xi, r); - std::cout << r << std::endl; - assert(r.size() < Xi.size()); - Xim1 = Xi; - Xi = -r; - assert(Xim1.size() > Xi.size()); - push_back(Xi); - } - } - - unsigned count_signs(double t) { - unsigned n_signs = 0;/* Number of sign-changes */ - const double big = 1e20; // a number such that practical polys would overflow on evaluation - if(t >= big) { - int old_sign = sgn((*this)[0].back()); - for (unsigned i = 1; i < size(); i++) { - int sign = sgn((*this)[i].back()); - if (sign != old_sign) - n_signs++; - old_sign = sign; - } - } else { - int old_sign = sgn((*this)[0].eval(t)); - for (unsigned i = 1; i < size(); i++) { - int sign = sgn((*this)[i].eval(t)); - if (sign != old_sign) - n_signs++; - old_sign = sign; - } - } - return n_signs; - } - - unsigned n_roots_between(double l, double r) { - return count_signs(l) - count_signs(r); - } -}; - -} //namespace Geom - -#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/svg-elliptical-arc.h b/src/2geom/svg-elliptical-arc.h index 79497cdb3..ba0a18257 100644 --- a/src/2geom/svg-elliptical-arc.h +++ b/src/2geom/svg-elliptical-arc.h @@ -1,7 +1,6 @@ /** * \file * \brief SVG 1.1-compliant elliptical arc curve - * *//* * Authors: * MenTaLguY <mental@rydia.net> @@ -35,8 +34,8 @@ */ -#ifndef _2GEOM_SVG_ELLIPTICAL_ARC_H_ -#define _2GEOM_SVG_ELLIPTICAL_ARC_H_ +#ifndef LIB2GEOM_SEEN_SVG_ELLIPTICAL_ARC_H +#define LIB2GEOM_SEEN_SVG_ELLIPTICAL_ARC_H #include <2geom/curve.h> #include <2geom/angle.h> @@ -49,8 +48,7 @@ #include <2geom/numeric/fitting-model.h> #include <algorithm> -namespace Geom -{ +namespace Geom { class SVGEllipticalArc : public EllipticalArc { public: @@ -267,13 +265,9 @@ class make_elliptical_arc bool svg_compliant; }; - } // end namespace Geom - - - -#endif /* _2GEOM_SVG_ELLIPTICAL_ARC_H_ */ +#endif // LIB2GEOM_SEEN_SVG_ELLIPTICAL_ARC_H /* Local Variables: diff --git a/src/2geom/sweep.h b/src/2geom/sweep.h index 1c73efee0..91371e6fb 100644 --- a/src/2geom/sweep.h +++ b/src/2geom/sweep.h @@ -1,7 +1,7 @@ /** * \file - * \brief \todo brief description - * + * \brief Sweepline intersection of groups of rectangles + *//* * Authors: * ? <?@?.?> * diff --git a/src/2geom/toposweep.cpp b/src/2geom/toposweep.cpp new file mode 100644 index 000000000..cfb91857c --- /dev/null +++ b/src/2geom/toposweep.cpp @@ -0,0 +1,663 @@ +#include <2geom/toposweep.h> + +#include <2geom/path-intersection.h> +#include <2geom/basic-intersection.h> + +//using namespace Geom; + +namespace Geom { + +TopoGraph::Edge &TopoGraph::Vertex::operator[](unsigned ix) { + ix %= degree(); + return ix < enters.size() ? enters[ix] : exits[ix - enters.size()]; +} + +TopoGraph::Edge TopoGraph::Vertex::operator[](unsigned ix) const { + ix %= degree(); + return ix < enters.size() ? enters[ix] : exits[ix - enters.size()]; +} + +void TopoGraph::Vertex::erase(unsigned ix) { + ix %= degree(); + if(ix < enters.size()) + enters.erase(enters.begin() + ix); + else + exits.erase(exits.begin() + (ix - enters.size())); +} + +void TopoGraph::Vertex::insert(unsigned ix, Edge v) { + ix %= degree(); + if(ix < enters.size()) + enters.insert(enters.begin() + ix, v); + else + exits.insert(exits.begin() + (ix - enters.size()), v); +} + +unsigned TopoGraph::Vertex::find_section(boost::shared_ptr<Section> section) const { + unsigned i = 0; + for(; i < degree(); i++) + if((*this)[i].section == section) return i; + return i; +} + +TopoGraph::Edge TopoGraph::remove_edge(unsigned ix, unsigned jx) { + Vertex &v = vertices[ix]; + if(v.degree()) { + jx %= v.degree(); + Edge &ret = v[jx]; + v.erase(jx); + v = vertices[ret.other]; + if(v.degree()) { + v.erase(v.find_section(ret.section)); + return ret; + } + } + assert(0); +} + +void TopoGraph::cannonize() { + std::vector<unsigned> vix; + unsigned ix = 0; + for(unsigned i = 0; i < vertices.size(); i++) { + vix.push_back(ix); + if(vertices[i].degree() != 0) vertices[ix++] = vertices[i]; + } + + for(unsigned i = 0; i < ix; i++) + for(unsigned j = 0; j < vertices[i].degree(); j++) + vertices[i][j].other = vix[vertices[i][j].other]; +} + + +void TopoGraph::assert_invariants() const { + for(unsigned i = 0; i < vertices.size(); i++) { + for(unsigned j = 0; j < vertices[i].degree(); j++) { + Edge e = vertices[i][j]; + assert(e.other != i); + assert(are_near(e.section->fp, vertices[i].avg, tol) || are_near(e.section->tp, vertices[i].avg, tol)); + assert(!are_near(e.section->fp, e.section->tp, tol)); + assert(e.section.get()); + unsigned oix = vertices[e.other].find_section(e.section); + assert(oix != vertices[e.other].degree()); + } + } +} + +//near predicate utilized in process_splits +template<typename T> +struct NearPredicate { bool operator()(T x, T y) { return are_near(x, y); } }; + +// ensures that f and t are elements of a vector, sorts and uniqueifies +// also asserts that no values fall outside of f and t +// if f is greater than t, the sort is in reverse +void process_splits(std::vector<double> &splits, double f, double t) { + splits.push_back(f); + std::sort(splits.begin(), splits.end()); + while(are_near(splits.back(), t)) splits.erase(splits.end() - 1); + splits.push_back(t); + if(f > t) std::reverse(splits.begin(), splits.end()); + + //remove any splits which fall outside t / f + while(!splits.empty() && splits.front() != f) splits.erase(splits.begin()); + while(!splits.empty() && splits.back() != t) splits.erase(splits.end() - 1); + + std::vector<double>::iterator end = std::unique(splits.begin(), splits.end(), NearPredicate<double>()); + splits.resize(end - splits.begin()); +} + +// A little sugar for appending a list to another +template<typename T> +void concatenate(T &a, T const &b) { a.insert(a.end(), b.begin(), b.end()); } + +//returns a list of monotonic sections of a path +//TODO: handle saddle points +std::vector<boost::shared_ptr<Section> > mono_sections(PathVector const &ps, Dim2 d) { + std::vector<boost::shared_ptr<Section> > monos; + for(unsigned i = 0; i < ps.size(); i++) { + //TODO: necessary? can we have empty paths? + if(ps[i].size()) { + for(unsigned j = 0; j < ps[i].size(); j++) { + //find the points of 0 derivative + Curve* deriv = ps[i][j].derivative(); + std::vector<double> splits = deriv->roots(0, X); + concatenate(splits, deriv->roots(0, Y)); + delete deriv; + process_splits(splits, 0, 1); + //split on points of 0 derivative + for(unsigned k = 1; k < splits.size(); k++) + monos.push_back(boost::shared_ptr<Section>(new Section(CurveIx(i,j), splits[k-1], splits[k], ps, d))); + } + } + } + return monos; +} + +//finds the t-value on a section, which corresponds to a particular horizontal or vertical line +//d indicates the dimension along which the roots is performed. +//-1 is returned if no root is found +double section_root(Section const &s, PathVector const &ps, double v, Dim2 d) { + std::vector<double> roots = s.curve.get(ps).roots(v, d); + for(unsigned j = 0; j < roots.size(); j++) + if(Interval(s.f, s.t).contains(roots[j])) return roots[j]; + return -1; +} + +bool SectionSorter::section_order(Section const &a, double at, Section const &b, double bt) const { + Point ap = a.curve.get(ps).pointAt(at); + Point bp = b.curve.get(ps).pointAt(bt); + if(are_near(ap[dim], bp[dim], tol)) { + // since the sections are monotonic, if the endpoints are on opposite sides of this + // coincidence, the order is determinable + if(a.tp[dim] < ap[dim] && b.tp[dim] > bp[dim]) return true; + if(a.tp[dim] > ap[dim] && b.tp[dim] < bp[dim]) return false; + //TODO: sampling / higher derivatives when unit tangents match + Point ad = a.curve.get(ps).unitTangentAt(a.f); + Point bd = b.curve.get(ps).unitTangentAt(b.f); + // tangent can point backwards + if(ad[1-dim] < 0) ad = -ad; + if(bd[1-dim] < 0) bd = -bd; + return ad[dim] < bd[dim]; + } + return ap[dim] < bp[dim]; +} + +bool SectionSorter::operator()(Section const &a, Section const &b) const { + if(&a == &b) return false; + Rect ra = a.bbox(), rb = b.bbox(); + //TODO: should we use tol in these conditions? + if(ra[dim].max() <= rb[dim].min()) return true; + if(rb[dim].max() <= ra[dim].min()) return false; + //we know that the rects intersect on dim + //by referencing f / t we are assuming that the section was constructed with 1-dim + if(ra[1-dim].intersects(rb[1-dim])) { + if(are_near(a.fp[1-dim], b.fp[1-dim], tol)) { + return section_order(a, a.f > a.t ? a.f - 0.01 : a.f + 0.01, + b, b.f > b.t ? b.f - 0.01 : b.f + 0.01); + } else if(a.fp[1-dim] < b.fp[1-dim]) { + //b inside a + double ta = section_root(a, ps, b.fp[1-dim], Dim2(1-dim)); + //TODO: fix bug that necessitates this + if(ta == -1) ta = (a.t + a.f) / 2; + return section_order(a, ta, b, b.f); + } else { + //a inside b + double tb = section_root(b, ps, a.fp[1-dim], Dim2(1-dim)); + //TODO: fix bug that necessitates this + if(tb == -1) tb = (b.t + b.f) / 2; + return section_order(a, a.f, b, tb); + } + } + + return Point::LexOrderRt(dim)(a.fp, b.fp); +} + +// splits a section into pieces, as specified by an array of doubles, mutating the section to +// represent the first part, and returning the rest +//TODO: output iterator? +std::vector<boost::shared_ptr<Section> > split_section(boost::shared_ptr<Section> s, PathVector const &ps, std::vector<double> &cuts, Dim2 d) { + std::vector<boost::shared_ptr<Section> > ret; + + process_splits(cuts, s->f, s->t); + if(cuts.size() <= 2) return ret; + + s->t = cuts[1]; + s->tp = s->curve.get(ps)(cuts[1]); + assert(Point::LexOrderRt(d)(s->fp, s->tp)); + + ret.reserve(cuts.size() - 2); + for(int i = cuts.size() - 1; i > 1; i--) ret.push_back(boost::shared_ptr<Section>(new Section(s->curve, cuts[i-1], cuts[i], ps, d))); + return ret; +} + +//merges the sorted lists a and b according to comparison z +template<typename X, typename Z> +void merge(X &a, X const &b, Z const &z) { + a.reserve(a.size() + b.size()); + unsigned start = a.size(); + concatenate(a, b); + std::inplace_merge(a.begin(), a.begin() + start, a.end(), z); +} + +//TODO: faster than linear +unsigned find_vertex(std::vector<TopoGraph::Vertex> const &vertices, Point p, double tol) { + for(unsigned i = 0; i < vertices.size(); i++) + if(are_near(vertices[i].avg, p, tol)) return i; + return vertices.size(); +} + +//takes a vector of T pointers, and returns a vector of T with copies +template<typename T> +std::vector<T> deref_vector(std::vector<boost::shared_ptr<T> > const &xs, unsigned from = 0) { + std::vector<T> ret; + ret.reserve(xs.size() - from); + for(unsigned i = from; i < xs.size(); i++) + ret.push_back(T(*xs[i])); + return ret; +} + +//used to create reversed sorting predicates +template<typename C> +struct ReverseAdapter { + typedef typename C::second_argument_type first_argument_type; + typedef typename C::first_argument_type second_argument_type; + typedef typename C::result_type result_type; + const C ∁ + ReverseAdapter(const C &c) : comp(c) {} + result_type operator()(const first_argument_type &a, const second_argument_type &b) const { return comp(b, a); } +}; + +//used to sort std::vector<Section*> +template<typename C> +struct DerefAdapter { + typedef typename boost::shared_ptr<typename C::first_argument_type> first_argument_type; + typedef typename boost::shared_ptr<typename C::second_argument_type> second_argument_type; + typedef typename C::result_type result_type; + const C ∁ + DerefAdapter(const C &c) : comp(c) {} + result_type operator()(const first_argument_type a, const second_argument_type b) const { + if(!a) return false; + if(!b) return true; + return comp(*a, *b); + } +}; + +struct EdgeSorter { + typedef TopoGraph::Edge first_argument_type; + typedef TopoGraph::Edge second_argument_type; + typedef bool result_type; + SectionSorter s; + EdgeSorter(const PathVector &rs, Dim2 d, double t) : s(rs, d, t) {} + bool operator()(TopoGraph::Edge const &e1, TopoGraph::Edge const &e2) const { return s(*e1.section, *e2.section); } +}; + +#ifdef SWEEP_GRAPH_DEBUG +//used for debugging purposes - each element represents a subsequent iteration of the algorithm. +std::vector<std::vector<Section> > monoss; +std::vector<std::vector<Section> > chopss; +std::vector<std::vector<Section> > contexts; +#endif + +/* + 1) take item off sweep sorted todo + 2) find all of the to-values before the beginning of this section + 3) sort these lexicographically, process them in order, grouping other sections in the context, and constructing a vertex in one fell swoop. + 4) add our section into context, splitting on intersections + + 3 is novel, we perform it by storing + */ + +template<typename A, typename B, typename Z> +struct MergeIterator { + A const &a; + B &b; + Z const &z; + unsigned ai; + bool on_a; + MergeIterator(A const &av, B &bv, Z const &zv) : a(av), b(bv), z(zv), ai(0), on_a(b.empty() || z(a[0], b.back())) {} + MergeIterator &operator++() { + if(!done()) { + on_a = b.empty() ? true : (ai >= a.size() ? false : z(a[ai], b.back())); + if(on_a) { + ++ai; + if(ai >= a.size()) on_a = false; + } else { + b.erase(b.end()); + if(b.empty()) on_a = true; + } + } + return *this; + } + typename A::value_type operator*() { + assert(!done()); + return on_a ? a[ai] : b.back(); + } + bool done() { return b.empty() && ai >= a.size() - 1; } + typename A::value_type operator->() { assert(!done()); return on_a ? a[ai] : b.back(); } +}; + +void modify_windings(std::vector<int> &windings, boost::shared_ptr<Section> sec, Dim2 d) { + unsigned k = sec->curve.path; + if(k >= windings.size() || sec->fp[d] == sec->tp[d]) return; + if(sec->f < sec->t) windings[k]++; + if(sec->f > sec->t) windings[k]--; +} + +struct Context { + boost::shared_ptr<Section> section; + int from_vert; + int to_vert; + Context(boost::shared_ptr<Section> sect, int from) : section(sect), from_vert(from), to_vert(-1) {} +}; + +template<typename C> +struct ContextAdapter { + typedef Context first_argument_type; + typedef typename C::second_argument_type second_argument_type; + typedef typename C::result_type result_type; + const C ∁ + ContextAdapter(const C &c) : comp(c) {} + result_type operator()(const Context &a, const second_argument_type &b) const { return comp(a.section, b); } +}; + +#define DINF std::numeric_limits<double>::infinity() + +TopoGraph::TopoGraph(PathVector const &ps, Dim2 d, double t) : dim(d), tol(t) { + //s_sort = vertical section order + ContextAdapter<DerefAdapter<SectionSorter> > s_sort = DerefAdapter<SectionSorter>(SectionSorter(ps, (Dim2)(1-d), tol)); + //sweep_sort = horizontal sweep order + DerefAdapter<SweepSorter> sweep_sort = DerefAdapter<SweepSorter>(SweepSorter(d)); + //heap_sort = reverse horizontal sweep order + ReverseAdapter<DerefAdapter<SweepSorter> > heap_sort = ReverseAdapter<DerefAdapter<SweepSorter> >(sweep_sort); + //edge_sort = sorter for edges + EdgeSorter edge_sort = EdgeSorter(ps, (Dim2)(1-d), tol); + + std::vector<boost::shared_ptr<Section> > input_sections = mono_sections(ps, d), chops; + std::sort(input_sections.begin(), input_sections.end(), sweep_sort); + + std::vector<Context> context; + + vertices.reserve(input_sections.size()); + + //std::vector<unsigned> to_process; + + std::vector<int> windings(ps.size(), 0); + for(MergeIterator<Area, Area, DerefAdapter<SweepSorter> > iter(input_sections, chops, sweep_sort); ; ++iter) { + //represents our position in the sweep, which controls what we finalize + //if we have no more to process, finish the rest by setting our position to infinity + Point lim; + if(iter.done()) lim[X] = lim[Y] = DINF; else lim = iter->fp; + + /* + //finalize vertices + for(unsigned i = 0; i < to_process.size(); i++) { + if(vertices[to_process[i]].avg[d] + tol < lim[d]) + for(unsigned j = 0; j < context.size(); j++) { + + } + } */ + + //find all sections to remove + for(int i = context.size() - 1; i >= 0; i--) { + boost::shared_ptr<Section> sec = context[i].section; + if(Point::LexOrderRt(d)(lim, sec->tp)) { + //sec->tp is less than or equal to lim + if(context[i].to_vert == -1) { + //we need to create a new vertex; add everything that enters it + //Point avg; + //unsigned cnt; + std::vector<Edge> enters; + std::fill(windings.begin(), windings.end(), 0); + for(unsigned j = 0; j < context.size(); j++) { + modify_windings(windings, context[j].section, d); + if(are_near(sec->tp, context[j].section->tp, tol)) { + assert(-1 == context[j].to_vert); + context[j].section->windings = windings; + context[j].to_vert = vertices.size(); + enters.push_back(Edge(context[j].section, context[j].from_vert)); + //avg += context[j].section->tp; + //cnt++; + } + } + //Vertex &v(avg / (double)cnt); + Vertex v(context[i].section->tp); + v.enters = enters; + vertices.push_back(v); + //to_process.push_back(vertices.size() - 1); + } + context.erase(context.begin() + i); + } + } + + if(!iter.done()) { + boost::shared_ptr<Section> s = *iter; + + //create a new context, associate a beginning vertex, and insert it in the proper location + unsigned ix = find_vertex(vertices, s->fp, tol); + if(ix == vertices.size()) { + vertices.push_back(Vertex(s->fp)); + //to_process.push_back(vertices.size() - 1); + } + unsigned context_ix = std::lower_bound(context.begin(), context.end(), s, s_sort) - context.begin(); + + context.insert(context.begin() + context_ix, Context(s, ix)); + + Interval si = Interval(s->fp[1-d], s->tp[1-d]); + + // Now we intersect with neighbors - do a sweep! + std::vector<double> this_splits; + for(unsigned i = 0; i < context.size(); i++) { + if(context[i].section == context[context_ix].section) continue; + + boost::shared_ptr<Section> sec = context[i].section; + + if(!si.intersects(Interval(sec->fp[1-d], sec->tp[1-d]))) continue; + + std::vector<double> other_splits; + Crossings xs = mono_intersect(s->curve.get(ps), Interval(s->f, s->t), + sec->curve.get(ps), Interval(sec->f, sec->t)); + if(xs.empty()) continue; + + for(unsigned j = 0; j < xs.size(); j++) { + this_splits.push_back(xs[j].ta); + other_splits.push_back(xs[j].tb); + } + merge(chops, split_section(sec, ps, other_splits, d), heap_sort); + } + if(!this_splits.empty()) + merge(chops, split_section(context[context_ix].section, ps, this_splits, d), heap_sort); + + std::sort(chops.begin(), chops.end(), heap_sort); + + if(context[context_ix].section->tp[d] - context[context_ix].section->fp[d] <= tol) { + if(!are_near(context[context_ix].section->tp, context[context_ix].section->fp, tol)) { + ix = find_vertex(vertices, context[context_ix].section->tp, tol); + if(ix != vertices.size()) { + boost::shared_ptr<Section> sec = context[context_ix].section; + Edge e(sec, context[context_ix].from_vert); + + std::vector<Edge>::iterator it = std::lower_bound(vertices[ix].enters.begin(), vertices[ix].enters.end(), e, edge_sort); + + if(vertices[ix].enters.empty()) { + std::fill(windings.begin(), windings.end(), 0); + for(unsigned j = 0; j <= context_ix; j++) modify_windings(windings, context[j].section, d); + } else if(it == vertices[ix].enters.end()) { + windings = (it-1)->section->windings; + modify_windings(windings, (it-1)->section, d); + } else { + windings = it->section->windings; + } + + sec->windings = windings; + modify_windings(windings, sec, d); + + for(std::vector<Edge>::iterator it2 = it; it2 != vertices[ix].enters.end(); ++it2) { + it2->section->windings = windings; + modify_windings(windings, it2->section, d); + } + + vertices[ix].enters.insert(it, e); + context.erase(context.begin() + context_ix); + } + } else context.erase(context.begin() + context_ix); + } + } + + #ifdef SWEEP_GRAPH_DEBUG + std::vector<Section> rem; + for(unsigned i = iter.ai + 1; i < iter.a.size(); i++) rem.push_back(*iter.a[i]); + monoss.push_back(rem); + chopss.push_back(deref_vector(iter.b)); + rem.clear(); + for(unsigned i = 0; i < context.size(); i++) rem.push_back(*context[i].section); + contexts.push_back(rem); + #endif + + if(iter.done() && context.empty()) return; + } +} + +void trim_whiskers(TopoGraph &g) { + std::vector<unsigned> affected; + + for(unsigned i = 0; i < g.size(); i++) + if(g[i].degree() == 1) affected.push_back(i); + + while(!affected.empty()) { + unsigned j = 0; + for(unsigned i = 0; i < affected.size(); i++) + if(g[affected[i]].degree() == 1) + affected[j++] = g.remove_edge(affected[i], 0).other; + affected.resize(j); + } +} + +void add_edge_at(TopoGraph &g, unsigned ix, boost::shared_ptr<Section> s, TopoGraph::Edge jx, bool before = true) { + TopoGraph::Vertex &v = g[ix]; + for(unsigned i = 0; i < v.enters.size(); i++) { + if(v.enters[i].section == s) { + v.enters.insert(v.enters.begin() + (before ? i : i + 1), jx); + return; + } + } + for(unsigned i = 0; i < v.exits.size(); i++) { + if(v.exits[i].section == s) { + v.exits.insert(v.exits.begin() + (before ? i : i + 1), jx); + return; + } + } + //TODO: fix the fall through to here + //assert(false); +} + +void double_whiskers(TopoGraph &g) { + for(unsigned i = 0; i < g.size(); i++) { + if(g[i].degree() == 1) { + unsigned j = i; + TopoGraph::Edge e = g[i][0]; + while(true) { + TopoGraph::Edge next_edge = g[j][1 - g[j].find_section(e.section)]; + boost::shared_ptr<Section> new_section = boost::shared_ptr<Section>(new Section(*e.section)); + add_edge_at(g, j, e.section, TopoGraph::Edge(new_section, e.other), false); + add_edge_at(g, e.other, e.section, TopoGraph::Edge(new_section, j), true); + + if(g[e.other].degree() == 3) { + j = e.other; + e = next_edge; + } else break; + } + } + } +} + +/* +void remove_degenerate(TopoGraph &g) { + for(unsigned i = 0; i < g.size(); i++) { + for(int j = g[i].degree(); j >= 0; j--) { + if(g[i][j].other == i) + } + } +}*/ + +/* +void remove_vestigial(TopoGraph &g) { + for(unsigned i = 0; i < g.size(); i++) { + if(g[i].enters.size() == 1 && g[i].exits.size() == 1) { + TopoGraph::Edge &e1 = g[i][0], &e2 = g[i][1]; + if(e1.section == e2.section) { + //vestigial vert + Section *new_section = new Section(e1.section->curve, + e1.section->f, e2.section->t, + e1.section->fp, e2.section->tp); + + e1.other + + Vertex *v1 = e1.other, *v2 = e2.other; + v1->lookup_section(e1.section) = Edge(new_section, v2); + v2->lookup_section(e2.section) = Edge(new_section, v1); + g.erase(g.begin() + i); + } + } + } +}*/ + +//planar area finding +//linear on number of edges +Areas traverse_areas(TopoGraph const &g) { + Areas ret; + + //stores which edges we've visited + std::vector<std::vector<bool> > visited; + for(unsigned i = 0; i < g.size(); i++) visited.push_back(std::vector<bool>(g[i].degree(), false)); + + for(unsigned vix = 0; vix < g.size(); vix++) { + while(true) { + //find an unvisited edge to start on + + unsigned e_ix = std::find(visited[vix].begin(), visited[vix].end(), false) - visited[vix].begin(); + if(e_ix == g[vix].degree()) break; + + unsigned start = e_ix; + unsigned cur = vix; + + Area area; + //std::vector<std::vector<bool> > before(visited); + while(cur < g.size() && !visited[cur][e_ix]) { + visited[cur][e_ix] = true; + + TopoGraph::Edge e = g[cur][e_ix]; + + area.push_back(e.section); + + //go to clockwise edge + cur = e.other; + unsigned deg = g[cur].degree(); + e_ix = g[cur].find_section(e.section); + + if(deg == 1 || e_ix == deg) { + visited[cur][e_ix] = true; + break; + } + + e_ix = (e_ix + 1) % deg; + + if(cur == vix && start == e_ix) break; + } + //if(vix == cur && start == e_ix) { + ret.push_back(area); + //} else visited = before; + } + } + return ret; +} + +void remove_area_whiskers(Areas &areas) { + for(int i = areas.size() - 1; i >= 0; i--) + if(areas[i].size() == 2 && *areas[i][0] == *areas[i][1]) + areas.erase(areas.begin() + i); +} + +Path area_to_path(PathVector const &ps, Area const &area) { + Path ret; + if(area.size() == 0) return ret; + Point prev = area[0]->fp; + for(unsigned i = 0; i < area.size(); i++) { + bool forward = are_near(area[i]->fp, prev, 0.01); + Curve *curv = area[i]->curve.get(ps).portion( + forward ? area[i]->f : area[i]->t, + forward ? area[i]->t : area[i]->f); + ret.append(*curv, Path::STITCH_DISCONTINUOUS); + delete curv; + prev = forward ? area[i]->tp : area[i]->fp; + } + return ret; +} + +PathVector areas_to_paths(PathVector const &ps, Areas const &areas) { + std::vector<Path> ret; + ret.reserve(areas.size()); + for(unsigned i = 0; i < areas.size(); i++) + ret.push_back(area_to_path(ps, areas[i])); + return ret; +} + +} // end namespace Geom diff --git a/src/2geom/toposweep.h b/src/2geom/toposweep.h new file mode 100644 index 000000000..428115dd3 --- /dev/null +++ b/src/2geom/toposweep.h @@ -0,0 +1,222 @@ + +/** + * \file + * \brief TopoSweep - topology / graph representation of a PathVector, for boolean operations and related tasks + * + * Authors: + * Michael Sloan <mgsloan at gmail.com> + * Nathan Hurst <njhurst at njhurst.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. + */ + +#ifndef SEEN_GEOM_TOPOSWEEP_H +#define SEEN_GEOM_TOPOSWEEP_H + +#include <2geom/coord.h> +#include <2geom/point.h> +#include <2geom/pathvector.h> +#include <2geom/rect.h> +#include <2geom/path.h> +#include <2geom/curve.h> + +#include <boost/shared_ptr.hpp> + +namespace Geom { + +// indicates a particular curve in a pathvector +struct CurveIx { + unsigned path, ix; + CurveIx(unsigned p, unsigned i) : path(p), ix(i) {} + // retrieves the indicated curve from the pathvector + Curve const &get(PathVector const &ps) const { + return ps[path][ix]; + } + bool operator==(CurveIx const &other) const { + return other.path == path && other.ix == ix; + } +}; + +// represents a monotonic section of a path +struct Section { + CurveIx curve; + double f, t; + Point fp, tp; + std::vector<int> windings; + Section(CurveIx cix, double fd, double td, Point fdp, Point tdp) : curve(cix), f(fd), t(td), fp(fdp), tp(tdp) { } + Section(CurveIx cix, double fd, double td, PathVector ps, Dim2 d) : curve(cix), f(fd), t(td) { + fp = curve.get(ps).pointAt(f), tp = curve.get(ps).pointAt(t); + if (Point::LexOrderRt(d)(tp, fp)) { + //swap from and to, since tp is left or above fp + std::swap(f, t); + std::swap(fp, tp); + } + } + Rect bbox() const { return Rect(fp, tp); } + bool operator==(Section const &other) const { + return (curve == other.curve) && (f == other.f) && (t == other.t); + } +}; + +class TopoGraph { + public: + + // Represents an e double tol;dge on a vertex + class Edge { + public: + boost::shared_ptr<Section> section; // section associated with this edge + unsigned other; // index of the vertex this edge points to + Edge(boost::shared_ptr<Section> s, unsigned o) : section(s), other(o) {} + }; + + // Represents a vertex in the graph, in terms of a point and edges which enter and exit. + // A vertex has an "avg" point, which is a representative point for the vertex. All + // edges have an endpoint tol away. + class Vertex { + public: + std::vector<Edge> enters, exits; // indexes of the enter / exit edges + Point avg; + Vertex(Point p) : avg(p) {} + inline unsigned degree() const { return enters.size() + exits.size(); } + Edge operator[](unsigned ix) const; + Edge &operator[](unsigned ix); + void erase(unsigned ix); + void insert(unsigned ix, Edge e); + unsigned find_section(boost::shared_ptr<Section> section) const; + }; + + TopoGraph(PathVector const &ps, Dim2 d, double t); + + unsigned size() const { return vertices.size(); } + + Vertex &operator[](unsigned ix) { return vertices[ix]; } + Vertex const &operator[](unsigned ix) const { return vertices[ix]; } + + //removes both edges, and returns the vertices[ix][jx] one + Edge remove_edge(unsigned ix, unsigned jx); + + //returns a graph with all zero degree vertices and unused edges removed + void cannonize(); + + //checks invariants + void assert_invariants() const; + + std::vector<Vertex> vertices; + Dim2 dim; + double tol; +}; + +//TODO: convert to classes +typedef std::vector<boost::shared_ptr<Section> > Area; +typedef std::vector<Area> Areas; + +//TopoGraph sweep_graph(PathVector const &ps, Dim2 d = X, double tol = 0.00001); + +void trim_whiskers(TopoGraph &g); +void double_whiskers(TopoGraph &g); +//void remove_degenerate(TopoGraph &g); +//void remove_vestigial(TopoGraph &g); +//Areas traverse_areas(TopoGraph const &g); + + +void remove_area_whiskers(Areas &areas); +PathVector areas_to_paths(PathVector const &ps, Areas const &areas); + +class SectionSorter { + const PathVector &ps; + Dim2 dim; + double tol; + bool section_order(Section const &a, double at, Section const &b, double bt) const; + public: + typedef Section first_argument_type; + typedef Section second_argument_type; + typedef bool result_type; + + SectionSorter(const PathVector &rs, Dim2 d, double t = 0.00001) : ps(rs), dim(d), tol(t) {} + bool operator()(Section const &a, Section const &b) const; +}; + +//sorter used to create the initial sweep of sections, such that they are dealt with in order +struct SweepSorter { + typedef Section first_argument_type; + typedef Section second_argument_type; + typedef bool result_type; + Dim2 dim; + SweepSorter(Dim2 d) : dim(d) {} + bool operator()(const Section &a, const Section &b) const { + return Point::LexOrderRt(dim)(a.fp, b.fp); + } +}; + +struct UnionOp { + unsigned ix; + bool nz1, nz2; + UnionOp(unsigned i, bool a, bool b) : ix(i), nz1(a), nz2(b) {} + bool operator()(std::vector<int> const &windings) const { + int w1 = 0, w2 = 0; + for(unsigned j = 0; j < ix; j++) w1 += windings[j]; + for(unsigned j = ix; j < windings.size(); j++) w2 += windings[j]; + return (nz1 ? w1 : w1 % 2) != 0 || (nz2 ? w2 : w2 % 2) != 0; + } +}; + +//returns all areas for which the winding -> bool function yields true +template<class Z> +Areas filter_areas(PathVector const &ps, Areas const & areas, Z const &z) { + Areas ret; + SweepSorter sorty = SweepSorter(Y); + SectionSorter sortx = SectionSorter(ps, X); + for(unsigned i = 0; i < areas.size(); i++) { + if(areas[i].size() < 2) continue; + //find a representative section + unsigned rj = 0; + bool rev = are_near(areas[i][0]->fp, areas[i][1]->tp); + for(unsigned j = 1; j < areas[i].size(); j++) + if(sorty(*areas[i][rj], *areas[i][j])) rj = j; + if(sortx(*areas[i][rj], *areas[i][(rj+areas[i].size() - 1) % areas[i].size()])) { + rj = 0; + for(unsigned j = 1; j < areas[i].size(); j++) + if(sorty(*areas[i][j], *areas[i][rj])) rj = j; + } + if(z(areas[i][rj]->windings)) ret.push_back(areas[i]); + } + return ret; +} + +} // end namespace Geom + +#endif // SEEN_GEOM_TOPOSWEEP_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/transforms.cpp b/src/2geom/transforms.cpp index 3a1866c13..2658719c4 100644 --- a/src/2geom/transforms.cpp +++ b/src/2geom/transforms.cpp @@ -60,12 +60,12 @@ Point &Point::operator*=(Rotate const &r) } Point &Point::operator*=(HShear const &h) { - _pt[X] += h.f * _pt[Y]; + _pt[X] += h.f * _pt[X]; return *this; } Point &Point::operator*=(VShear const &v) { - _pt[Y] += v.f * _pt[X]; + _pt[Y] += v.f * _pt[Y]; return *this; } diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index 48d4b1dba..9623bed26 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -32,12 +32,12 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_Geom_TRANSFORMS_H -#define SEEN_Geom_TRANSFORMS_H +#ifndef LIB2GEOM_SEEN_TRANSFORMS_H +#define LIB2GEOM_SEEN_TRANSFORMS_H +#include <cmath> #include <2geom/forward.h> #include <2geom/affine.h> -#include <cmath> namespace Geom { @@ -66,7 +66,8 @@ struct TransformConcept { } }; -/** @brief Base template for transforms. */ +/** @brief Base template for transforms. + * This class is an implementation detail and should not be used directly. */ template <typename T> class TransformOperations : boost::equality_comparable< T @@ -198,6 +199,7 @@ public: }; /** @brief Common base for shearing transforms. + * This class is an implementation detail and should not be used directly. * @ingroup Transforms */ template <typename S> class ShearBase @@ -259,10 +261,9 @@ inline Translate pow(Translate const &t, int n) { //TODO: matrix to trans/scale/rotate -} /* namespace Geom */ - +} // end namespace Geom -#endif /* !SEEN_Geom_TRANSFORMS_H */ +#endif // LIB2GEOM_SEEN_TRANSFORMS_H /* Local Variables: diff --git a/src/2geom/utils.h b/src/2geom/utils.h index e90a4623b..6a72d42c4 100644 --- a/src/2geom/utils.h +++ b/src/2geom/utils.h @@ -1,10 +1,7 @@ -#ifndef LIB2GEOM_UTILS_HEADER -#define LIB2GEOM_UTILS_HEADER - /** * \file * \brief Various utility functions. - * + *//* * Copyright 2007 Johan Engelen <goejendaagh@zonnet.nl> * Copyright 2006 Michael G. Sloan <mgsloan@gmail.com> * @@ -33,6 +30,9 @@ * */ +#ifndef SEEN_LIB2GEOM_UTILS_H +#define SEEN_LIB2GEOM_UTILS_H + #include <cstddef> #include <vector> @@ -59,9 +59,9 @@ struct MultipliableNoncommutative : B } }; -} +} // end namespace Geom -#endif +#endif // SEEN_LIB2GEOM_UTILS_H /* Local Variables: diff --git a/src/axis-manip.h b/src/axis-manip.h index 835f67a97..d81da4164 100644 --- a/src/axis-manip.h +++ b/src/axis-manip.h @@ -12,8 +12,8 @@ #ifndef SEEN_AXIS_MANIP_H #define SEEN_AXIS_MANIP_H +#include <utility> #include <gtk/gtk.h> -#include "libnr/nr-point.h" namespace Proj { diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index 8bba30eb9..87b182d10 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -301,11 +301,11 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven m.setup(desktop, true, bc->item); m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - bc->center = from_2geom(button_dt); + bc->center = button_dt; - bc->drag_origin = from_2geom(button_dt); - bc->drag_ptB = from_2geom(button_dt); - bc->drag_ptC = from_2geom(button_dt); + bc->drag_origin = button_dt; + bc->drag_ptB = button_dt; + bc->drag_ptC = button_dt; // This can happen after saving when the last remaining perspective was purged and must be recreated. if (!cur_persp) { @@ -314,7 +314,7 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven } /* Projective preimages of clicked point under current perspective */ - bc->drag_origin_proj = cur_persp->perspective_impl->tmat.preimage (from_2geom(button_dt), 0, Proj::Z); + bc->drag_origin_proj = cur_persp->perspective_impl->tmat.preimage (button_dt, 0, Proj::Z); bc->drag_ptB_proj = bc->drag_origin_proj; bc->drag_ptC_proj = bc->drag_origin_proj; bc->drag_ptC_proj.normalize(); @@ -358,10 +358,10 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven } if (!bc->extruded) { - bc->drag_ptB = from_2geom(motion_dt); - bc->drag_ptC = from_2geom(motion_dt); + bc->drag_ptB = motion_dt; + bc->drag_ptC = motion_dt; - bc->drag_ptB_proj = cur_persp->perspective_impl->tmat.preimage (from_2geom(motion_dt), 0, Proj::Z); + bc->drag_ptB_proj = cur_persp->perspective_impl->tmat.preimage (motion_dt, 0, Proj::Z); bc->drag_ptC_proj = bc->drag_ptB_proj; bc->drag_ptC_proj.normalize(); bc->drag_ptC_proj[Proj::Z] = 0.25; @@ -371,15 +371,15 @@ static gint sp_box3d_context_root_handler(SPEventContext *event_context, GdkEven if (!bc->ctrl_dragged) { /* snapping */ Box3D::PerspectiveLine pline (bc->drag_ptB, Proj::Z, document->getCurrentPersp3D()); - bc->drag_ptC = pline.closest_to (from_2geom(motion_dt)); + bc->drag_ptC = pline.closest_to (motion_dt); bc->drag_ptB_proj.normalize(); bc->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (bc->drag_ptC, bc->drag_ptB_proj[Proj::X], Proj::X); } else { - bc->drag_ptC = from_2geom(motion_dt); + bc->drag_ptC = motion_dt; bc->drag_ptB_proj.normalize(); - bc->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (from_2geom(motion_dt), bc->drag_ptB_proj[Proj::X], Proj::X); + bc->drag_ptC_proj = cur_persp->perspective_impl->tmat.preimage (motion_dt, bc->drag_ptB_proj[Proj::X], Proj::X); } m.freeSnapReturnByRef(bc->drag_ptC, Inkscape::SNAPSOURCE_NODE_HANDLE); } diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index bbc7d10c5..b886e884e 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -155,9 +155,9 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge m.unSetup(); } - sp_guideline_set_position(SP_GUIDELINE(guide), from_2geom(event_dt)); - desktop->set_coordinate_status(to_2geom(event_dt)); - desktop->setPosition(to_2geom(event_dt)); + sp_guideline_set_position(SP_GUIDELINE(guide), event_dt); + desktop->set_coordinate_status(event_dt); + desktop->setPosition(event_dt); } break; case GDK_BUTTON_RELEASE: @@ -186,13 +186,13 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); Inkscape::XML::Node *repr = xml_doc->createElement("sodipodi:guide"); sp_repr_set_point(repr, "orientation", normal); - sp_repr_set_point(repr, "position", from_2geom(event_dt)); + sp_repr_set_point(repr, "position", event_dt); desktop->namedview->appendChild(repr); Inkscape::GC::release(repr); DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_NONE, _("Create guide")); } - desktop->set_coordinate_status(from_2geom(event_dt)); + desktop->set_coordinate_status(event_dt); } default: break; @@ -345,8 +345,8 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) break; } moved = true; - desktop->set_coordinate_status(from_2geom(motion_dt)); - desktop->setPosition(from_2geom(motion_dt)); + desktop->set_coordinate_status(motion_dt); + desktop->setPosition(motion_dt); ret = TRUE; } @@ -429,8 +429,8 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) _("Delete guide")); } moved = false; - desktop->set_coordinate_status(from_2geom(event_dt)); - desktop->setPosition (from_2geom(event_dt)); + desktop->set_coordinate_status(event_dt); + desktop->setPosition (event_dt); } drag_type = SP_DRAG_NONE; sp_canvas_item_ungrab(item, event->button.time); diff --git a/src/desktop.cpp b/src/desktop.cpp index d05c94790..4ff2716ca 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -57,6 +57,7 @@ #include <sigc++/functors/mem_fun.h> #include <gtkmm.h> +#include <2geom/transforms.h> #include <2geom/rect.h> #include "macros.h" #include "inkscape-private.h" diff --git a/src/dialogs/clonetiler.cpp b/src/dialogs/clonetiler.cpp index e79de069a..f8553f2aa 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -17,6 +17,7 @@ #include <glib/gmem.h> #include <gtk/gtk.h> #include <glibmm/i18n.h> +#include <2geom/transforms.h> #include "desktop.h" #include "desktop-handles.h" diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 6930e4d7c..dd4a4ed5c 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -31,7 +31,10 @@ static void sp_canvas_arena_destroy(GtkObject *object); 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 void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area); +static void sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area); static double sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); +static void sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event); static gint sp_canvas_arena_send_event (SPCanvasArena *arena, GdkEvent *event); @@ -93,6 +96,7 @@ sp_canvas_arena_class_init (SPCanvasArenaClass *klass) item_class->render = sp_canvas_arena_render; item_class->point = sp_canvas_arena_point; item_class->event = sp_canvas_arena_event; + item_class->visible_area_changed = sp_canvas_arena_visible_area_changed; } static void @@ -106,6 +110,9 @@ sp_canvas_arena_init (SPCanvasArena *arena) nr_arena_group_set_transparent (NR_ARENA_GROUP (arena->root), TRUE); arena->active = NULL; + arena->cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + arena->cache_area = Geom::IntRect::from_xywh(0,0,1,1); + arena->dirty = cairo_region_create(); nr_active_object_add_listener ((NRActiveObject *) arena->arena, (NRObjectEventVector *) &carenaev, sizeof (carenaev), arena); } @@ -131,6 +138,11 @@ sp_canvas_arena_destroy (GtkObject *object) nr_object_unref ((NRObject *) arena->arena); arena->arena = NULL; } + if (arena->cache) { + cairo_surface_destroy(arena->cache); + arena->cache = NULL; + } + cairo_region_destroy(arena->dirty); if (GTK_OBJECT_CLASS (parent_class)->destroy) (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); @@ -187,33 +199,74 @@ sp_canvas_arena_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned static void sp_canvas_arena_render (SPCanvasItem *item, SPCanvasBuf *buf) { - gint bw, bh; - SPCanvasArena *arena = SP_CANVAS_ARENA (item); //SPCanvas *canvas = item->canvas; - nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, - NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, - NR_ARENA_ITEM_STATE_NONE); + //nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, + // NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, + // NR_ARENA_ITEM_STATE_NONE); + + Geom::OptIntRect r = buf->rect; + if (!r || r->hasZeroArea()) return; + + cairo_rectangle_int_t crect; + crect.x = r->left(); + crect.y = r->top(); + crect.width = r->width(); + crect.height = r->height(); + if (cairo_region_contains_rectangle(arena->dirty, &crect) != CAIRO_REGION_OVERLAP_OUT) { + sp_canvas_arena_render_cache(item, *r); + cairo_region_subtract_rectangle(arena->dirty, &crect); + } - sp_canvas_prepare_buffer(buf); + cairo_save(buf->ct); + cairo_translate(buf->ct, -r->left(), -r->top()); + //cairo_rectangle(buf->ct, r->left(), r->top(), r->width(), r->height()); + //cairo_clip(buf->ct); + cairo_set_source_surface(buf->ct, arena->cache, arena->cache_area.left(), arena->cache_area.top()); + cairo_paint(buf->ct); + //nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0); + cairo_restore(buf->ct); +} - bw = buf->rect.x1 - buf->rect.x0; - bh = buf->rect.y1 - buf->rect.y0; - if ((bw < 1) || (bh < 1)) return; +static void sp_canvas_arena_render_cache (SPCanvasItem *item, Geom::IntRect const &area) +{ + SPCanvasArena *arena = SP_CANVAS_ARENA (item); + + Geom::OptIntRect r = Geom::intersect(arena->cache_area, area); + if (!r || r->hasZeroArea()) return; // nothing to do + + cairo_t *ct = cairo_create(arena->cache); + cairo_translate(ct, -arena->cache_area.left(), -arena->cache_area.top()); + + // clear area to paint + cairo_rectangle(ct, area.left(), area.top(), area.width(), area.height()); + cairo_clip(ct); + cairo_save(ct); + cairo_set_source_rgba(ct, 0,0,0,0); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_restore(ct); + + NRRectL nr_area(r); - NRRectL area; + nr_arena_item_invoke_update (arena->root, NULL, &arena->gc, + NR_ARENA_ITEM_STATE_BBOX | NR_ARENA_ITEM_STATE_RENDER, + NR_ARENA_ITEM_STATE_NONE); + nr_arena_item_invoke_render (ct, arena->root, &nr_area, NULL, 0); - area.x0 = buf->rect.x0; - area.y0 = buf->rect.y0; - area.x1 = buf->rect.x1; - area.y1 = buf->rect.y1; + cairo_destroy(ct); +} - sp_canvas_prepare_buffer(buf); - cairo_save(buf->ct); - cairo_translate(buf->ct, -area.x0, -area.y0); - nr_arena_item_invoke_render (buf->ct, arena->root, &area, NULL, 0); - cairo_restore(buf->ct); +static void +sp_canvas_arena_dirty_cache (SPCanvasArena *arena, NRRectL *area) +{ + cairo_rectangle_int_t rect; + rect.x = area->x0; + rect.y = area->y0; + rect.width = area->x1 - area->x0; + rect.height = area->y1 - area->y0; + cairo_region_union_rectangle(arena->dirty, &rect); } static double @@ -237,6 +290,67 @@ sp_canvas_arena_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_ return 1e18; } +static void +sp_canvas_arena_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area) +{ + SPCanvasArena *arena = SP_CANVAS_ARENA(item); + + cairo_surface_t *new_cache = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + new_area.width(), new_area.height()); + cairo_t *ct = cairo_create(new_cache); + cairo_set_source_surface(ct, arena->cache, old_area.left() - new_area.left(), old_area.top() - new_area.top()); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + cairo_surface_destroy(arena->cache); + arena->cache = new_cache; + arena->cache_area = new_area; + + cairo_rectangle_int_t crect; + crect.x = new_area.left(); + crect.y = new_area.top(); + crect.width = new_area.width(); + crect.height = new_area.height(); + cairo_region_intersect_rectangle(arena->dirty, &crect); + + // invalidate newly exposed areas + /* + * +----------------------+ + * | top strip | + * +-------+------+-------+ + * | | | | + * | left | old | right | + * | strip | area | strip | + * | | | | + * +-------+------+-------+ + * | bottom strip | + * +----------------------+ + */ + + // top strip + if (new_area.top() < old_area.top()) { + NRRectL top_strip(new_area.left(), new_area.top(), new_area.right(), old_area.top()); + sp_canvas_arena_dirty_cache(arena, &top_strip); + } + // left strip + if (new_area.left() < old_area.left()) { + NRRectL left_strip(new_area.left(), std::max(new_area.top(), old_area.top()), + old_area.left(), std::min(new_area.bottom(), old_area.bottom())); + sp_canvas_arena_dirty_cache(arena, &left_strip); + } + // right strip + if (new_area.right() > old_area.right()) { + NRRectL right_strip(old_area.right(), std::max(new_area.top(), old_area.top()), + new_area.right(), std::min(new_area.bottom(), old_area.bottom())); + sp_canvas_arena_dirty_cache(arena, &right_strip); + } + // bottom strip + if (new_area.bottom() > old_area.bottom()) { + NRRectL bottom_strip(new_area.left(), old_area.bottom(), new_area.right(), new_area.bottom()); + sp_canvas_arena_dirty_cache(arena, &bottom_strip); + } +} + static gint sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) { @@ -336,6 +450,8 @@ sp_canvas_arena_request_update (NRArena */*arena*/, NRArenaItem */*item*/, void static void sp_canvas_arena_request_render (NRArena */*arena*/, NRRectL *area, void *data) { + if (!area) return; + sp_canvas_arena_dirty_cache (SP_CANVAS_ARENA(data), area); sp_canvas_request_redraw (SP_CANVAS_ITEM (data)->canvas, area->x0, area->y0, area->x1, area->y1); } diff --git a/src/display/canvas-arena.h b/src/display/canvas-arena.h index 4cfeccb5a..220976da0 100644 --- a/src/display/canvas-arena.h +++ b/src/display/canvas-arena.h @@ -45,6 +45,10 @@ struct _SPCanvasArena { /* fixme: */ NRArenaItem *picked; gdouble delta; + + Geom::IntRect cache_area; + cairo_surface_t *cache; + cairo_region_t *dirty; }; struct _SPCanvasArenaClass { diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index dbf7b424d..ec2d35f69 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -33,6 +33,7 @@ #include "svg/svg-color.h" #include "util/mathfns.h" #include "xml/node-event-vector.h" +#include "round.h" #define SAFE_SETPIXEL //undefine this when it is certain that setpixel is never called with invalid params @@ -549,13 +550,13 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) // x-axis always goes from topleft to bottomright. (0,0) - (1,1) gdouble const xintercept_y_bc = (buf_tl_gc[Geom::X] * tan_angle[X]) - buf_tl_gc[Geom::Y] ; gdouble const xstart_y_sc = ( xintercept_y_bc - floor(xintercept_y_bc/lyw)*lyw ) + buf->rect.y0; - gint const xlinestart = (gint) Inkscape::round( (xstart_y_sc - buf->rect.x0*tan_angle[X] -ow[Geom::Y]) / lyw ); + gint const xlinestart = round( (xstart_y_sc - buf->rect.x0*tan_angle[X] -ow[Geom::Y]) / lyw ); gint xlinenum = xlinestart; // lines starting on left side. for (y = xstart_y_sc; y < buf->rect.y1; y += lyw, xlinenum++) { gint const x0 = buf->rect.x0; - gint const y0 = (gint) Inkscape::round(y); - gint const x1 = x0 + (gint) Inkscape::round( (buf->rect.y1 - y) / tan_angle[X] ); + gint const y0 = round(y); + gint const x1 = x0 + round( (buf->rect.y1 - y) / tan_angle[X] ); gint const y1 = buf->rect.y1; if (!scaled && (xlinenum % empspacing) != 0) { @@ -570,8 +571,8 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) for (x = xstart_x_sc; x < buf->rect.x1; x += lxw_x, xlinenum--) { gint const y0 = buf->rect.y0; gint const y1 = buf->rect.y1; - gint const x0 = (gint) Inkscape::round(x); - gint const x1 = x0 + (gint) Inkscape::round( (y1 - y0) / tan_angle[X] ); + gint const x0 = round(x); + gint const x1 = x0 + round( (y1 - y0) / tan_angle[X] ); if (!scaled && (xlinenum % empspacing) != 0) { sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color); @@ -582,10 +583,10 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) // y-axis lines (vertical) gdouble const ystart_x_sc = floor (buf_tl_gc[Geom::X] / spacing_ylines) * spacing_ylines + ow[Geom::X]; - gint const ylinestart = (gint) Inkscape::round((ystart_x_sc - ow[Geom::X]) / spacing_ylines); + gint const ylinestart = round((ystart_x_sc - ow[Geom::X]) / spacing_ylines); gint ylinenum = ylinestart; for (x = ystart_x_sc; x < buf->rect.x1; x += spacing_ylines, ylinenum++) { - gint const x0 = (gint) Inkscape::round(x); + gint const x0 = round(x); if (!scaled && (ylinenum % empspacing) != 0) { sp_grid_vline (buf, x0, buf->rect.y0, buf->rect.y1 - 1, color); @@ -597,13 +598,13 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) // z-axis always goes from bottomleft to topright. (0,1) - (1,0) gdouble const zintercept_y_bc = (buf_tl_gc[Geom::X] * -tan_angle[Z]) - buf_tl_gc[Geom::Y] ; gdouble const zstart_y_sc = ( zintercept_y_bc - floor(zintercept_y_bc/lyw)*lyw ) + buf->rect.y0; - gint const zlinestart = (gint) Inkscape::round( (zstart_y_sc + buf->rect.x0*tan_angle[Z] - ow[Geom::Y]) / lyw ); + gint const zlinestart = round( (zstart_y_sc + buf->rect.x0*tan_angle[Z] - ow[Geom::Y]) / lyw ); gint zlinenum = zlinestart; // lines starting from left side for (y = zstart_y_sc; y < buf->rect.y1; y += lyw, zlinenum++) { gint const x0 = buf->rect.x0; - gint const y0 = (gint) Inkscape::round(y); - gint const x1 = x0 + (gint) Inkscape::round( (y - buf->rect.y0 ) / tan_angle[Z] ); + gint const y0 = round(y); + gint const x1 = x0 + round( (y - buf->rect.y0 ) / tan_angle[Z] ); gint const y1 = buf->rect.y0; if (!scaled && (zlinenum % empspacing) != 0) { @@ -617,8 +618,8 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf) for (x = zstart_x_sc; x < buf->rect.x1; x += lxw_z, zlinenum++) { gint const y0 = buf->rect.y1; gint const y1 = buf->rect.y0; - gint const x0 = (gint) Inkscape::round(x); - gint const x1 = x0 + (gint) Inkscape::round( (buf->rect.y1 - buf->rect.y0) / tan_angle[Z] ); + gint const x0 = round(x); + gint const x1 = x0 + round( (buf->rect.y1 - buf->rect.y0) / tan_angle[Z] ); if (!scaled && (zlinenum % empspacing) != 0) { sp_caxonomgrid_drawline (buf, x0, y0, x1, y1, color); diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index e1673c8ef..aa38a14c9 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -920,9 +920,9 @@ void CanvasXYGrid::Render (SPCanvasBuf *buf) { gdouble const sxg = floor ((buf->rect.x0 - ow[Geom::X]) / sw[Geom::X]) * sw[Geom::X] + ow[Geom::X]; - gint const xlinestart = (gint) Inkscape::round((sxg - ow[Geom::X]) / sw[Geom::X]); + gint const xlinestart = round((sxg - ow[Geom::X]) / sw[Geom::X]); gdouble const syg = floor ((buf->rect.y0 - ow[Geom::Y]) / sw[Geom::Y]) * sw[Geom::Y] + ow[Geom::Y]; - gint const ylinestart = (gint) Inkscape::round((syg - ow[Geom::Y]) / sw[Geom::Y]); + gint const ylinestart = round((syg - ow[Geom::Y]) / sw[Geom::Y]); //set correct coloring, depending preference (when zoomed out, always major coloring or minor coloring) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -943,7 +943,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += sw[Geom::Y], ylinenum++) { - gint const y0 = (gint) Inkscape::round(y); + gint const y0 = round(y); if (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) { grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, color); } else { @@ -954,7 +954,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) gint xlinenum; gdouble x; for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += sw[Geom::X], xlinenum++) { - gint const ix = (gint) Inkscape::round(x); + gint const ix = round(x); if (!scaled[Geom::X] && (xlinenum % empspacing) != 0) { grid_vline (buf, ix, buf->rect.y0, buf->rect.y1, color); } else { @@ -965,12 +965,12 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += sw[Geom::Y], ylinenum++) { - gint const iy = (gint) Inkscape::round(y); + gint const iy = round(y); gint xlinenum; gdouble x; for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += sw[Geom::X], xlinenum++) { - gint const ix = (gint) Inkscape::round(x); + gint const ix = round(x); if ( (!scaled[Geom::X] && (xlinenum % empspacing) != 0) || (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) || ((scaled[Geom::X] || scaled[Geom::Y]) && no_emp_when_zoomed_out) ) diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp index c761fa74e..c1c3e7740 100644 --- a/src/display/guideline.cpp +++ b/src/display/guideline.cpp @@ -112,8 +112,8 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); cairo_set_font_size(buf->ct, 10); - int px = (int) Inkscape::round(gl->point_on_line[Geom::X]); - int py = (int) Inkscape::round(gl->point_on_line[Geom::Y]); + int px = round(gl->point_on_line[Geom::X]); + int py = round(gl->point_on_line[Geom::Y]); if (gl->label) { cairo_save(buf->ct); @@ -126,12 +126,12 @@ static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) } if (gl->is_vertical()) { - int position = (int) Inkscape::round(gl->point_on_line[Geom::X]); + int position = round(gl->point_on_line[Geom::X]); cairo_move_to(buf->ct, position + 0.5, buf->rect.y0 + 0.5); cairo_line_to(buf->ct, position + 0.5, buf->rect.y1 - 0.5); cairo_stroke(buf->ct); } else if (gl->is_horizontal()) { - int position = (int) Inkscape::round(gl->point_on_line[Geom::Y]); + int position = round(gl->point_on_line[Geom::Y]); cairo_move_to(buf->ct, buf->rect.x0 + 0.5, position + 0.5); cairo_line_to(buf->ct, buf->rect.x1 - 0.5, position + 0.5); cairo_stroke(buf->ct); @@ -193,9 +193,9 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, sp_canvas_item_request_update(SP_CANVAS_ITEM (gl->origin)); if (gl->is_horizontal()) { - sp_canvas_update_bbox (item, -1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y] - 16), 1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y] + 1)); + sp_canvas_update_bbox (item, -1000000, round(gl->point_on_line[Geom::Y] - 16), 1000000, round(gl->point_on_line[Geom::Y] + 1)); } else if (gl->is_vertical()) { - sp_canvas_update_bbox (item, (int) Inkscape::round(gl->point_on_line[Geom::X]), -1000000, (int) Inkscape::round(gl->point_on_line[Geom::X] + 16), 1000000); + sp_canvas_update_bbox (item, round(gl->point_on_line[Geom::X]), -1000000, round(gl->point_on_line[Geom::X] + 16), 1000000); } else { //TODO: labels in angled guidelines are not showing up for some reason. sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000); diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index 089d6de40..d09f66a2f 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -135,10 +135,10 @@ nr_arena_glyphs_update(NRArenaItem *item, NRRectL */*area*/, NRGC *gc, guint /*s } if (b) { - item->bbox.x0 = static_cast<NR::ICoord>(floor(b->left())); - item->bbox.y0 = static_cast<NR::ICoord>(floor(b->top())); - item->bbox.x1 = static_cast<NR::ICoord>(ceil (b->right())); - item->bbox.y1 = static_cast<NR::ICoord>(ceil (b->bottom())); + item->bbox.x0 = floor(b->left()); + item->bbox.y0 = floor(b->top()); + item->bbox.x1 = ceil (b->right()); + item->bbox.y1 = ceil (b->bottom()); } else { item->bbox.x0 = 0; item->bbox.y0 = 0; @@ -282,7 +282,8 @@ nr_arena_glyphs_group_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint s } -static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/) +static unsigned int +nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock * /*pb*/, unsigned int /*flags*/) { NRArenaItem *child = 0; @@ -352,20 +353,34 @@ static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, return item->state; } -static unsigned int nr_arena_glyphs_group_clip(cairo_t * /*ct*/, NRArenaItem *item, NRRectL * /*area*/) +static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) { - //NRArenaGroup *group = NR_ARENA_GROUP(item); + NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); - guint ret = item->state; + cairo_save(ct); + // handle clip-rule + if (ggroup->style) { + if (ggroup->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + } else { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + } + } + ink_cairo_transform(ct, ggroup->ctm); + + for (NRArenaItem *child = ggroup->children; child != NULL; child = child->next) { + NRArenaGlyphs *g = NR_ARENA_GLYPHS(child); + Geom::PathVector const &pathv = *g->font->PathVector(g->glyph); - // Render children fill mask - /* - for (NRArenaItem *child = group->children; child != NULL; child = child->next) { - ret = nr_arena_glyphs_fill_mask(NR_ARENA_GLYPHS(child), area, pb); - if (!(ret & NR_ARENA_ITEM_STATE_RENDER)) return ret; - }*/ + cairo_save(ct); + ink_cairo_transform(ct, g->g_transform); + feed_pathvector_to_cairo(ct, pathv); + cairo_restore(ct); + } + cairo_fill(ct); + cairo_restore(ct); - return ret; + return item->state; } static NRArenaItem * diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 97f92d02d..1d552fbc2 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -12,9 +12,12 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "display/canvas-bpath.h" +#include "display/nr-arena.h" #include "display/nr-arena-group.h" #include "display/nr-filter.h" #include "display/nr-filter-types.h" +#include "display/rendermode.h" #include "style.h" #include "sp-filter.h" #include "sp-filter-reference.h" @@ -163,10 +166,9 @@ static unsigned int nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int state, unsigned int reset) { unsigned int newstate; - NRArenaGroup *group = NR_ARENA_GROUP (item); - unsigned int beststate = NR_ARENA_ITEM_STATE_ALL; + bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); for (NRArenaItem *child = group->children; child != NULL; child = child->next) { NRGC cgc(gc); @@ -176,10 +178,10 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int } if (beststate & NR_ARENA_ITEM_STATE_BBOX) { - nr_rect_l_set_empty (&item->bbox); + item->bbox = NR_RECT_L_EMPTY; for (NRArenaItem *child = group->children; child != NULL; child = child->next) { if (child->visible) - nr_rect_l_union (&item->bbox, &item->bbox, &child->drawbox); + nr_rect_l_union (&item->bbox, &item->bbox, outline ? &child->bbox : &child->drawbox); } } @@ -234,10 +236,8 @@ static unsigned int nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) { NRArenaGroup *group = NR_ARENA_GROUP (item); - unsigned int ret = item->state; - /* Just compose children into parent buffer */ for (NRArenaItem *child = group->children; child != NULL; child = child->next) { ret = nr_arena_item_invoke_clip (ct, child, area); if (ret & NR_ARENA_ITEM_STATE_INVALID) break; diff --git a/src/display/nr-arena-image.cpp b/src/display/nr-arena-image.cpp index 36d733eb8..a943a6214 100644 --- a/src/display/nr-arena-image.cpp +++ b/src/display/nr-arena-image.cpp @@ -301,7 +301,7 @@ nr_arena_image_rect (NRArenaImage *image) Geom::Point p(image->ox, image->oy); Geom::Point wh(vw, vh); Geom::Rect view(p, p+wh); - Geom::OptRect res = Geom::intersect(r, view); + Geom::OptRect res = r & view; r = res ? *res : r; } diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 526882921..9ca5a7463 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -21,6 +21,7 @@ #include "display/cairo-utils.h" #include "display/cairo-templates.h" +#include "display/canvas-arena.h" #include "nr-arena.h" #include "nr-arena-item.h" #include "gc-core.h" @@ -214,6 +215,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, { NRGC childgc (gc); bool filter = (item->arena->rendermode == Inkscape::RENDERMODE_NORMAL); + bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), @@ -242,7 +244,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, return item->state; /* Test whether to return immediately */ if (area && (item->state & NR_ARENA_ITEM_STATE_BBOX)) { - if (!nr_rect_l_test_intersect_ptr(area, &item->drawbox)) + if (!nr_rect_l_test_intersect_ptr(area, outline ? &item->bbox : &item->drawbox)) return item->state; } @@ -275,8 +277,6 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, } else { memcpy(&item->drawbox, &item->bbox, sizeof(item->bbox)); } - // fixme: to fix the display glitches, in outline mode bbox must be a combination of - // full item bbox and its clip and mask (after we have the API to get these) /* Clipping */ if (item->clip) { @@ -288,8 +288,12 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - // for clipping, we need geometric bbox - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox); + if (outline) { + nr_rect_l_union(&item->bbox, &item->bbox, &item->clip->bbox); + } else { + // for clipping, we need geometric bbox + nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->clip->bbox); + } } /* Masking */ if (item->mask) { @@ -298,8 +302,12 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc, item->state |= NR_ARENA_ITEM_STATE_INVALID; return item->state; } - // for masking, we need full drawbox of mask - nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox); + if (outline) { + nr_rect_l_union(&item->bbox, &item->bbox, &item->mask->bbox); + } else { + // for masking, we need full drawbox of mask + nr_rect_l_intersect (&item->drawbox, &item->drawbox, &item->mask->drawbox); + } } // now that we know drawbox, dirty the corresponding rect on canvas: @@ -349,18 +357,14 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area if (!item->visible) return item->state | NR_ARENA_ITEM_STATE_RENDER; - // carea is the bounding box for intermediate rendering. - // NOTE: carea might be larger than area, because of filter effects. - NRRectL carea; - nr_rect_l_intersect (&carea, area, &item->drawbox); - if (nr_rect_l_test_empty(carea)) - return item->state | NR_ARENA_ITEM_STATE_RENDER; - if (item->filter && filter) { - item->filter->area_enlarge (carea, item); - nr_rect_l_intersect (&carea, &carea, &item->drawbox); - } - if (outline) { + // intersect with bbox rather than drawbox, as we want to render things outside + // of the clipping path as well + NRRectL carea; + nr_rect_l_intersect (&carea, area, &item->bbox); + if (nr_rect_l_test_empty(carea)) + return item->state | NR_ARENA_ITEM_STATE_RENDER; + // No caching in outline mode for now; investigate if it really gives any advantage with cairo. // Also no attempts to clip anything; just render everything: item, clip, mask // First, render the object itself @@ -388,121 +392,143 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area return item->state | NR_ARENA_ITEM_STATE_RENDER; } + + // carea is the bounding box for intermediate rendering. + // NOTE: carea might be larger than area, because of filter effects. + NRRectL carea; + nr_rect_l_intersect (&carea, area, &item->drawbox); + if (nr_rect_l_test_empty(carea)) + return item->state | NR_ARENA_ITEM_STATE_RENDER; + if (item->filter && filter) { + item->filter->area_enlarge (carea, item); + nr_rect_l_intersect (&carea, &carea, &item->drawbox); + } using namespace Inkscape; - // clipping and masks - unsigned int state; - - cairo_t *this_ct = ct; - NRRectL *this_area = const_cast<NRRectL*>(area); + unsigned state; + unsigned retstate; + // determine whether this shape needs intermediate rendering. bool needs_intermediate_rendering = false; bool &nir = needs_intermediate_rendering; bool needs_opacity = (item->opacity != 255 && !item->render_opacity); // this item needs an intermediate rendering if: - nir |= (item->mask != NULL); // 1. it has a mask - nir |= (item->filter != NULL && filter); // 2. it has a filter - nir |= needs_opacity; // 3. it is non-opaque + nir |= (item->clip != NULL); // 1. it has a clipping path + nir |= (item->mask != NULL); // 2. it has a mask + nir |= (item->filter != NULL && filter); // 3. it has a filter + nir |= needs_opacity; // 4. it is non-opaque double opacity = static_cast<double>(item->opacity) / 255.0; - if (needs_intermediate_rendering) { - cairo_surface_t *intermediate = cairo_surface_create_similar( - cairo_get_target(ct), CAIRO_CONTENT_COLOR_ALPHA, - carea.x1 - carea.x0, carea.y1 - carea.y0); - this_ct = cairo_create(intermediate); - cairo_translate(this_ct, -carea.x0, -carea.y0); - this_area = &carea; - cairo_surface_destroy(intermediate); // the surface will be held in memory by this_ct - } else { - cairo_reference(this_ct); - } + /* How the rendering is done. + * + * Clipping, masking and opacity are done by rendering them to a surface + * and then compositing the object's rendering onto it with the IN operator. + * The object itself is rendered to a group. + * + * Opacity is done by rendering the clipping path with an alpha + * value corresponding to the opacity. If there is no clipping path, + * the entire intermediate surface is painted with alpha corresponding + * to the opacity value. + */ - // The pipeline needs to be different for filters. - // First we render the item into an intermediate surface. Then the filter rotates - // the surface to user coordinates (if necessary) and runs the rendering. - // Once that's done we retrieve the result, rotating it back to screen coords. - // Clipping and masking happens after the filter result is ready. - if (item->filter && filter) { + // short-circuit the simple case. + if (!needs_intermediate_rendering) { + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags); + if (state & NR_ARENA_ITEM_STATE_INVALID) { + item->state |= NR_ARENA_ITEM_STATE_INVALID; + return item->state; + } + return item->state | NR_ARENA_ITEM_STATE_RENDER; } - Cairo::Context cct(this_ct, true); - Cairo::Context base_ct(ct); - Cairo::RefPtr<Cairo::Pattern> mask; - CairoSave clipsave(ct); // RAII for save / restore - CairoGroup maskgroup(this_ct); // RAII for push_group / pop_group - CairoGroup drawgroup(this_ct); - CairoGroup maskopacitygroup(this_ct); - - // always clip the base context, not the one on the intermediate surface - // this is because filters must be done before clipping + cairo_surface_t *intermediate = cairo_surface_create_similar( + cairo_get_group_target(ct), CAIRO_CONTENT_COLOR_ALPHA, + carea.x1 - carea.x0, carea.y1 - carea.y0); + cairo_t *ict = cairo_create(intermediate); + cairo_translate(ict, -carea.x0, -carea.y0); + + // 1. Render clipping path with alpha = opacity. + cairo_set_source_rgba(ict, 0,0,0,opacity); + // Since clip can be combined with opacity, the result could be incorrect + // for overlapping clip children. To fix this we use the SOURCE operator + // instead of the default OVER. + cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); if (item->clip) { - clipsave.save(); - state = nr_arena_item_invoke_clip(ct, item->clip, const_cast<NRRectL*>(area)); + state = nr_arena_item_invoke_clip(ict, item->clip, const_cast<NRRectL*>(area)); if (state & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; + retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); + goto cleanup; } - base_ct.clip(); + } else { + // if there is no clipping path, fill the entire surface with alpha = opacity. + cairo_paint(ict); } + // reset back to default + cairo_set_operator(ict, CAIRO_OPERATOR_OVER); - // render mask on the intermediate context and store it + // 2. Render the mask if present and compose it with the clipping path + opacity. if (item->mask) { - maskgroup.push_with_content(CAIRO_CONTENT_COLOR_ALPHA); - // handle opacity of a masked object by composing it with the mask - if (needs_opacity) { - maskopacitygroup.push(); - } - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (this_ct, item->mask, this_area, pb, flags); + cairo_push_group(ict); + state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; - } - if (needs_opacity) { - maskopacitygroup.pop_to_source(); - cct.paint_with_alpha(opacity); + retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); + goto cleanup; } - mask = maskgroup.popmm(); - // convert luminance to alpha - cairo_pattern_t *p = mask->cobj(); - cairo_surface_t *s; - cairo_pattern_get_surface(p, &s); - ink_cairo_surface_filter(s, s, MaskLuminanceToAlpha()); + cairo_surface_t *mask_s = cairo_get_group_target(ict); + // Convert mask's luminance to alpha + ink_cairo_surface_filter(mask_s, mask_s, MaskLuminanceToAlpha()); + cairo_pop_group_to_source(ict); + cairo_set_operator(ict, CAIRO_OPERATOR_IN); + cairo_paint(ict); + cairo_set_operator(ict, CAIRO_OPERATOR_OVER); } - // render the object (possibly to the intermediate surface) - state = NR_ARENA_ITEM_VIRTUAL (item, render) (this_ct, item, this_area, pb, flags); + // 3. Render object itself. + cairo_push_group(ict); + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags); if (state & NR_ARENA_ITEM_STATE_INVALID) { - /* Clean up and return error */ - item->state |= NR_ARENA_ITEM_STATE_INVALID; - return item->state; + retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); + goto cleanup; } - // apply filter + // 4. Apply filter. if (item->filter && filter) { - item->filter->render(item, ct, area, this_ct, &carea); - } - - if (needs_intermediate_rendering) { - cairo_surface_t *intermediate = cairo_get_target(this_ct); - cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); - if (mask) { - cairo_mask(ct, mask->cobj()); - // opacity of masked objects is handled by premultiplying the mask + // HACK: SPCanvasArena doesn't exist when this is called for offscreen rendering + // Proper fix: call this function with a drawing context class + // that contains information about the surface's bounds + NRRectL bgarea; + if (flags & NR_ARENA_ITEM_RENDER_NO_CACHE || !item->arena->canvasarena) { + bgarea = carea; } else { - // opacity of non-masked objects must be rendered explicitly - if (needs_opacity) { - cairo_paint_with_alpha(ct, opacity); - } else { - cairo_paint(ct); - } + bgarea = NRRectL(item->arena->canvasarena->cache_area); } - cairo_set_source_rgba(ct,0,0,0,0); + item->filter->render(item, ct, &bgarea, ict, &carea); + // Note that because the object was rendered to a group, + // the internals of the filter need to use cairo_get_group_target() + // instead of cairo_get_target(). } - return item->state | NR_ARENA_ITEM_STATE_RENDER; + // 5. Render object inside the composited mask + clip + cairo_pop_group_to_source(ict); + cairo_set_operator(ict, CAIRO_OPERATOR_IN); + cairo_paint(ict); + + // 6. Paint the completed rendering onto the base context + cairo_set_source_surface(ct, intermediate, carea.x0, carea.y0); + cairo_paint(ct); + cairo_set_source_rgba(ct, 0,0,0,0); + // the call above is to clear a ref on the intermediate surface held by ct + + retstate = item->state | NR_ARENA_ITEM_STATE_RENDER; + + cleanup: + cairo_destroy(ict); + cairo_surface_destroy(intermediate); + + return retstate; } unsigned int @@ -511,16 +537,6 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID); nr_return_val_if_fail (NR_IS_ARENA_ITEM (item), NR_ARENA_ITEM_STATE_INVALID); - /* we originally short-circuited if the object state included - * NR_ARENA_ITEM_STATE_CLIP (and showed a warning on the console); - * anyone know why we stopped doing so? - */ - /*nr_return_val_if_fail ((pb->area.x1 - pb->area.x0) >= - (area->x1 - area->x0), - NR_ARENA_ITEM_STATE_INVALID); - nr_return_val_if_fail ((pb->area.y1 - pb->area.y0) >= - (area->y1 - area->y0), - NR_ARENA_ITEM_STATE_INVALID);*/ #ifdef NR_ARENA_ITEM_VERBOSE printf ("Invoke clip by %p: %d %d - %d %d, item bbox %d %d - %d %d\n", @@ -528,15 +544,40 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) (&item->bbox)->y0, (&item->bbox)->x1, (&item->bbox)->y1); #endif + unsigned retstate = 0; + + // don't bother if the object does not implement clipping (e.g. NRArenaImage) + if (!((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) + return retstate; + if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { - /* Need render that item */ - if (((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))->clip) { - return ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> - clip (ct, item, area); + // The item used as the clipping path itself has a clipping path. + // Render this item's clipping path onto a temporary surface, then composite it with the item + // using the IN operator + if (item->clip) { + cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); + cairo_save(ct); + cairo_set_source_rgba(ct, 0,0,0,1); + nr_arena_item_invoke_clip(ct, item->clip, area); + cairo_restore(ct); + cairo_push_group_with_content(ct, CAIRO_CONTENT_ALPHA); + } + + // rasterize the clipping path + retstate = ((NRArenaItemClass *) NR_OBJECT_GET_CLASS (item))-> + clip (ct, item, area); + + if (item->clip) { + cairo_pop_group_to_source(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_IN); + cairo_paint(ct); + cairo_pop_group_to_source(ct); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); } } - return item->state; + return retstate; } NRArenaItem * @@ -597,7 +638,8 @@ nr_arena_item_request_render (NRArenaItem *item) nr_return_if_fail (item != NULL); nr_return_if_fail (NR_IS_ARENA_ITEM (item)); - nr_arena_request_render_rect (item->arena, &item->drawbox); + bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); + nr_arena_request_render_rect (item->arena, outline ? &item->bbox : &item->drawbox); } /* Public */ diff --git a/src/display/nr-arena-item.h b/src/display/nr-arena-item.h index 0fc4cbe48..d65a75ed8 100644 --- a/src/display/nr-arena-item.h +++ b/src/display/nr-arena-item.h @@ -15,6 +15,8 @@ #include <cairo.h> #include <2geom/affine.h> +#include <2geom/rect.h> +#include "libnr/nr-forward.h" #include "libnr/nr-rect-l.h" #include "libnr/nr-object.h" #include "gc-soft-ptr.h" diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index eb7a30e58..6d65611bf 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -21,6 +21,7 @@ #include <2geom/svg-path-parser.h> #include "display/cairo-utils.h" #include "display/canvas-arena.h" +#include "display/canvas-bpath.h" #include "display/curve.h" #include "display/nr-arena.h" #include "display/nr-arena-shape.h" @@ -223,10 +224,10 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g if (shape->curve) { boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); if (boundingbox) { - item->bbox.x0 = static_cast<NR::ICoord>(floor((*boundingbox)[0][0])); // Floor gives the coordinate in which the point resides - item->bbox.y0 = static_cast<NR::ICoord>(floor((*boundingbox)[1][0])); - item->bbox.x1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[0][1])); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[1][1])); + item->bbox.x0 = floor((*boundingbox)[0][0]); // Floor gives the coordinate in which the point resides + item->bbox.y0 = floor((*boundingbox)[1][0]); + item->bbox.x1 = ceil ((*boundingbox)[0][1]); // Ceil gives the first coordinate beyond the point + item->bbox.y1 = ceil ((*boundingbox)[1][1]); } else { item->bbox = NR_RECT_L_EMPTY; } @@ -274,10 +275,10 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g /// \todo just write item->bbox = boundingbox if (boundingbox) { - shape->approx_bbox.x0 = static_cast<NR::ICoord>(floor((*boundingbox)[0][0])); - shape->approx_bbox.y0 = static_cast<NR::ICoord>(floor((*boundingbox)[1][0])); - shape->approx_bbox.x1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[0][1])); - shape->approx_bbox.y1 = static_cast<NR::ICoord>(ceil ((*boundingbox)[1][1])); + shape->approx_bbox.x0 = floor(boundingbox->left()); + shape->approx_bbox.y0 = floor(boundingbox->top()); + shape->approx_bbox.x1 = ceil (boundingbox->right()); + shape->approx_bbox.y1 = ceil (boundingbox->bottom()); } else { shape->approx_bbox = NR_RECT_L_EMPTY; } @@ -396,22 +397,26 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*area*/) { - guint result = 0; - - // NOTE: for now this is incorrect, because it doesn't honor clip-rule, - // and will be incorrect for nested clipping paths. NRArenaShape *shape = NR_ARENA_SHAPE(item); if (!shape->curve) { - result = item->state; - } else { - cairo_save(ct); - ink_cairo_transform(ct, shape->ctm); - feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); - cairo_restore(ct); + return item->state; + } - result = item->state; + cairo_save(ct); + // handle clip-rule + if (shape->style) { + if (shape->style->clip_rule.computed == SP_WIND_RULE_EVENODD) { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_EVEN_ODD); + } else { + cairo_set_fill_rule(ct, CAIRO_FILL_RULE_WINDING); + } } - return result; + ink_cairo_transform(ct, shape->ctm); + feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); + cairo_fill(ct); + cairo_restore(ct); + + return item->state; } static NRArenaItem * diff --git a/src/display/nr-arena-shape.h b/src/display/nr-arena-shape.h index 2ee0d24c8..7b86f7f59 100644 --- a/src/display/nr-arena-shape.h +++ b/src/display/nr-arena-shape.h @@ -22,6 +22,7 @@ #include "forward.h" #include "nr-arena-item.h" #include "nr-style.h" +#include "libnr/nr-rect.h" NRType nr_arena_shape_get_type (void); diff --git a/src/display/nr-arena.cpp b/src/display/nr-arena.cpp index 43edb6918..ce62a81dc 100644 --- a/src/display/nr-arena.cpp +++ b/src/display/nr-arena.cpp @@ -18,6 +18,7 @@ #include "nr-filter-types.h" #include "preferences.h" #include "color.h" +#include "libnr/nr-rect.h" static void nr_arena_class_init (NRArenaClass *klass); static void nr_arena_init (NRArena *arena); diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp index d4cf47af4..694ccaec5 100644 --- a/src/display/nr-filter-composite.cpp +++ b/src/display/nr-filter-composite.cpp @@ -11,7 +11,6 @@ #include <cmath> -#include "2geom/isnan.h" #include "display/cairo-templates.h" #include "display/cairo-utils.h" #include "display/nr-filter-composite.h" diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index fdaf2c887..15200223b 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -28,128 +28,6 @@ FilterPrimitive * FilterDisplacementMap::create() { FilterDisplacementMap::~FilterDisplacementMap() {} -#if 0 -struct pixel_t { - unsigned char channels[4]; - inline unsigned char operator[](int c) const { return channels[c]; } - inline unsigned char& operator[](int c) { return channels[c]; } - static inline pixel_t blank() { - pixel_t p; - for(unsigned int i=0; i<4; i++) { - p[i] = 0; - } - return p; - } -}; - -static inline pixel_t pixelValue(NRPixBlock const* pb, int x, int y) { - if ( x < pb->area.x0 || x >= pb->area.x1 || y < pb->area.y0 || y >= pb->area.y1 ) return pixel_t::blank(); // This assumes anything outside the defined range is (0,0,0,0) - pixel_t const* rowData = reinterpret_cast<pixel_t const*>(NR_PIXBLOCK_PX(pb) + (y-pb->area.y0)*pb->rs); - return rowData[x-pb->area.x0]; -} - -template<bool PREMULTIPLIED> -static pixel_t interpolatePixels(NRPixBlock const* pb, double x, double y) { - // NOTE: The values of x and y are shifted by -0.5 (the "true" values would be x+0.5 and y+0.5). - // This is done because otherwise the pixel values first have to be shifted by +0.5 and then by -0.5 again... - unsigned int const sfl = 8u; - unsigned int const sf = 1u<<sfl; - unsigned int const sf2h = 1u<<(2u*sfl-1); - int xi = (int)floor(x), yi = (int)floor(y); - unsigned int xf = static_cast<unsigned int>(round(sf * (x - xi))), - yf = static_cast<unsigned int>(round(sf * (y - yi))); - pixel_t p00 = pixelValue(pb, xi+0, yi+0); - pixel_t p01 = pixelValue(pb, xi+1, yi+0); - pixel_t p10 = pixelValue(pb, xi+0, yi+1); - pixel_t p11 = pixelValue(pb, xi+1, yi+1); - - /* It's a good idea to interpolate premultiplied colors: - * - * Consider two pixels, one being rgba(255,0,0,0), which is fully transparent, - * and the other being rgba(0,0,255,255), or blue (fully opaque). - * If these two colors are interpolated the expected result would be bluish pixels - * containing no red. - * - * However, if our final alpha value is zero, then the RGB values aren't really determinate. - * We might as well avoid premultiplication in this case, which still gives us a fully - * transparent result, but with interpolated RGB parts. */ - - pixel_t r; - if (PREMULTIPLIED) { - /* Premultiplied, so do simple interpolation. */ - for (unsigned i = 0; i != 4; ++i) { - // y0,y1 have range [0,a*sf] - unsigned const y0 = sf*p00[i] + xf*((unsigned int)p01[i]-(unsigned int)p00[i]); - unsigned const y1 = sf*p10[i] + xf*((unsigned int)p11[i]-(unsigned int)p10[i]); - - unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,a*sf*sf] - r[i] = (ri + sf2h)>>(2*sfl); // range [0,a] - } - } else { - /* First calculate interpolated alpha value. */ - unsigned const y0 = sf*p00[3] + xf*((unsigned int)p01[3]-(unsigned int)p00[3]); // range [0,a*sf] - unsigned const y1 = sf*p10[3] + xf*((unsigned int)p11[3]-(unsigned int)p10[3]); - unsigned const ra = sf*y0 + yf*(y1-y0); // range [0,a*sf*sf] - - if (ra==0) { - /* Fully transparent, so do simple interpolation. */ - for (unsigned i = 0; i != 3; ++i) { - // y0,y1 have range [0,255*sf] - unsigned const y0 = sf*p00[i] + xf*((unsigned int)p01[i]-(unsigned int)p00[i]); - unsigned const y1 = sf*p10[i] + xf*((unsigned int)p11[i]-(unsigned int)p10[i]); - - unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,255*sf*sf] - r[i] = (ri + sf2h)>>(2*sfl); // range [0,255] - } - r[3] = 0; - } else { - /* Do premultiplication ourselves. */ - for (unsigned i = 0; i != 3; ++i) { - // Premultiplied versions. Range [0,255*a]. - unsigned const c00 = p00[i]*p00[3]; - unsigned const c01 = p01[i]*p01[3]; - unsigned const c10 = p10[i]*p10[3]; - unsigned const c11 = p11[i]*p11[3]; - - // Interpolation. - unsigned const y0 = sf*c00 + xf*(c01-c00); // range [0,255*a*sf] - unsigned const y1 = sf*c10 + xf*(c11-c10); // range [0,255*a*sf] - unsigned const ri = sf*y0 + yf*(y1-y0); // range [0,255*a*sf*sf] - r[i] = (ri + ra/2) / ra; // range [0,255] - } - r[3] = (ra + sf2h)>>(2*sfl); // range [0,a] - } - } - - return r; -} - -template<bool MAP_PREMULTIPLIED, bool DATA_PREMULTIPLIED> -static void performDisplacement(NRPixBlock const* texture, NRPixBlock const* map, int Xchannel, int Ychannel, NRPixBlock* out, double scalex, double scaley) { - bool Xneedsdemul = MAP_PREMULTIPLIED && Xchannel<3; - bool Yneedsdemul = MAP_PREMULTIPLIED && Ychannel<3; - if (!Xneedsdemul) scalex /= 255.0; - if (!Yneedsdemul) scaley /= 255.0; - - for (int yout=out->area.y0; yout < out->area.y1; yout++){ - pixel_t const* mapRowData = reinterpret_cast<pixel_t const*>(NR_PIXBLOCK_PX(map) + (yout-map->area.y0)*map->rs); - pixel_t* outRowData = reinterpret_cast<pixel_t*>(NR_PIXBLOCK_PX(out) + (yout-out->area.y0)*out->rs); - for (int xout=out->area.x0; xout < out->area.x1; xout++){ - pixel_t const mapValue = mapRowData[xout-map->area.x0]; - - double xtex = xout + (Xneedsdemul ? // Although the value of the pixel corresponds to the MIDDLE of the pixel, no +0.5 is needed because we're interpolating pixels anyway (so to get the actual pixel locations 0.5 would have to be subtracted again). - (mapValue[3]==0?0:(scalex * (mapValue[Xchannel] - mapValue[3]*0.5) / mapValue[3])) : - (scalex * (mapValue[Xchannel] - 127.5))); - double ytex = yout + (Yneedsdemul ? - (mapValue[3]==0?0:(scaley * (mapValue[Ychannel] - mapValue[3]*0.5) / mapValue[3])) : - (scaley * (mapValue[Ychannel] - 127.5))); - - outRowData[xout-out->area.x0] = interpolatePixels<DATA_PREMULTIPLIED>(texture, xtex, ytex); - } - } -} -#endif - struct Displace { Displace(cairo_surface_t *texture, cairo_surface_t *map, unsigned xch, unsigned ych, double scalex, double scaley) @@ -206,73 +84,6 @@ void FilterDisplacementMap::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -/* -int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) { - NRPixBlock *texture = slot.get(_input); - NRPixBlock *map = slot.get(_input2); - - // Bail out if either one of source images is missing - if (!map || !texture) { - g_warning("Missing source image for feDisplacementMap (map=%d texture=%d)", _input, _input2); - return 1; - } - - NR::IRect area = units.get_pixblock_filterarea_paraller(); - int x0 = std::max(map->area.x0,area.min()[NR::X]); - int y0 = std::max(map->area.y0,area.min()[NR::Y]); - int x1 = std::min(map->area.x1,area.max()[NR::X]); - int y1 = std::min(map->area.y1,area.max()[NR::Y]); - - //TODO: check whether we really need this check: - if (x1 <= x0 || y1 <= y0) return 0; //nothing to do! - - if (texture->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && texture->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - g_warning("Source images without an alpha channel are not supported by feDisplacementMap at the moment."); - return 1; - } - - NRPixBlock *out = new NRPixBlock; - nr_pixblock_setup_fast(out, texture->mode, x0, y0, x1, y1, true); - - // convert to a suitable format - bool free_map_on_exit = false; - if (map->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && map->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { - NRPixBlock *original_map = map; - map = new NRPixBlock; - nr_pixblock_setup_fast(map, NR_PIXBLOCK_MODE_R8G8B8A8N, - original_map->area.x0, original_map->area.y0, - original_map->area.x1, original_map->area.y1, - false); - nr_blit_pixblock_pixblock(map, original_map); - free_map_on_exit = true; - } - bool map_premultiplied = (map->mode == NR_PIXBLOCK_MODE_R8G8B8A8P); - bool data_premultiplied = (out->mode == NR_PIXBLOCK_MODE_R8G8B8A8P); - - Geom::Affine trans = units.get_matrix_primitiveunits2pb(); - double scalex = scale * trans.expansionX(); - double scaley = scale * trans.expansionY(); - - if (map_premultiplied && data_premultiplied) { - performDisplacement<true,true>(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else if (map_premultiplied && !data_premultiplied) { - performDisplacement<true,false>(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else if (data_premultiplied) { - performDisplacement<false,true>(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else { - performDisplacement<false,false>(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } - - if (free_map_on_exit) { - nr_pixblock_release(map); - delete map; - } - - out->empty = FALSE; - slot.set(_output, out); - return 0; -}*/ - void FilterDisplacementMap::set_input(int slot) { _input = slot; } diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index fca066ad4..3a6b425e1 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -23,8 +23,6 @@ #include <omp.h> #endif //HAVE_OPENMP -#include "2geom/isnan.h" - #include "display/cairo-utils.h" #include "display/nr-filter-primitive.h" #include "display/nr-filter-gaussian.h" diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index ce07ff086..3464fda66 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -156,7 +156,7 @@ cairo_surface_t *FilterSlot::_get_transformed_background() { Geom::Affine trans = _units.get_matrix_display2pb(); - cairo_surface_t *bg = cairo_get_target(_background_ct); + cairo_surface_t *bg = cairo_get_group_target(_background_ct); cairo_surface_t *tbg = cairo_surface_create_similar( bg, cairo_surface_get_content(bg), _slot_w, _slot_h); diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index f3b03c024..60d5ce872 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -299,7 +299,6 @@ FilterTurbulence::FilterTurbulence() , numOctaves(1) , seed(0) , updated(false) - , updated_area(NR::IPoint(), NR::IPoint()) , fTileWidth(10) //guessed , fTileHeight(10) //guessed , fTileX(1) //guessed diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h index 50161b6be..8d3639543 100644 --- a/src/display/nr-filter-turbulence.h +++ b/src/display/nr-filter-turbulence.h @@ -64,7 +64,6 @@ private: bool stitchTiles; FilterTurbulenceType type; bool updated; - NR::IRect updated_area; unsigned char *pix_data; double fTileWidth; diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp index b1c475c41..a8686545a 100644 --- a/src/display/nr-filter-units.cpp +++ b/src/display/nr-filter-units.cpp @@ -158,22 +158,13 @@ Geom::Affine FilterUnits::get_matrix_user2primitiveunits() const { return get_matrix_user2units(primitiveUnits); } -NR::IRect FilterUnits::get_pixblock_filterarea_paraller() const { +Geom::IntRect 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::Affine u2pb = get_matrix_user2pb(); - - for (int i = 0 ; i < 4 ; i++) { - Geom::Point p = filter_area->corner(i); - p *= u2pb; - if (p[X] < min_x) min_x = (int)std::floor(p[X]); - if (p[X] > max_x) max_x = (int)std::ceil(p[X]); - if (p[Y] < min_y) min_y = (int)std::floor(p[Y]); - if (p[Y] > max_y) max_y = (int)std::ceil(p[Y]); - } - NR::IRect ret(NR::IPoint(min_x, min_y), NR::IPoint(max_x, max_y)); - return ret; + Geom::Rect r = *filter_area * u2pb; + Geom::IntRect ir = r.roundOutwards(); + return ir; } FilterUnits& FilterUnits::operator=(FilterUnits const &other) { diff --git a/src/display/nr-filter-units.h b/src/display/nr-filter-units.h index 2fc3e5533..1cb4fdbce 100644 --- a/src/display/nr-filter-units.h +++ b/src/display/nr-filter-units.h @@ -133,7 +133,7 @@ public: * NOTE: use only in filters, that define TRAIT_PARALLER in * get_input_traits. The filter effects area may not be representable * by simple rectangle otherwise. */ - NR::IRect get_pixblock_filterarea_paraller() const; + Geom::IntRect get_pixblock_filterarea_paraller() const; FilterUnits& operator=(FilterUnits const &other); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index 6e0aa1a42..963d98654 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -160,7 +160,7 @@ int Filter::render(NRArenaItem const *item, cairo_t *bgct, NRRectL const *bgarea } } - FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_target(graphic), area, units); + FilterSlot slot(const_cast<NRArenaItem*>(item), bgct, bgarea, cairo_get_group_target(graphic), area, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); @@ -236,10 +236,10 @@ void Filter::compute_drawbox(NRArenaItem const *item, NRRectL &item_bbox) { Geom::Rect enlarged = filter_effect_area(tmp_bbox); enlarged = enlarged * item->ctm; - item_bbox.x0 = (NR::ICoord) floor(enlarged.min()[X]); - item_bbox.y0 = (NR::ICoord) floor(enlarged.min()[Y]); - item_bbox.x1 = (NR::ICoord) ceil(enlarged.max()[X]); - item_bbox.y1 = (NR::ICoord) ceil(enlarged.max()[Y]); + item_bbox.x0 = floor(enlarged.min()[X]); + item_bbox.y0 = floor(enlarged.min()[Y]); + item_bbox.x1 = ceil(enlarged.max()[X]); + item_bbox.y1 = ceil(enlarged.max()[Y]); } Geom::Rect Filter::filter_effect_area(Geom::Rect const &bbox) diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h index 9dbec547e..4c731e56b 100644 --- a/src/display/sp-canvas-item.h +++ b/src/display/sp-canvas-item.h @@ -24,8 +24,7 @@ #include <glib-object.h> #include <gtk/gtk.h> #include <gdk/gdk.h> - -#include "2geom/rect.h" +#include <2geom/rect.h> G_BEGIN_DECLS @@ -65,6 +64,7 @@ struct _SPCanvasItemClass : public GtkObjectClass { double (* point) (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); int (* event) (SPCanvasItem *item, GdkEvent *event); + void (* visible_area_changed) (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); }; SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GType type, const gchar *first_arg_name, ...); diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 37998437d..d7f34969f 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -689,6 +689,7 @@ static void sp_canvas_group_destroy (GtkObject *object); 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); +static void sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area); static SPCanvasItemClass *group_parent_class; @@ -732,6 +733,7 @@ sp_canvas_group_class_init (SPCanvasGroupClass *klass) item_class->update = sp_canvas_group_update; item_class->render = sp_canvas_group_render; item_class->point = sp_canvas_group_point; + item_class->visible_area_changed = sp_canvas_group_visible_area_changed; } /** @@ -875,6 +877,20 @@ sp_canvas_group_render (SPCanvasItem *item, SPCanvasBuf *buf) } } +static void +sp_canvas_group_visible_area_changed (SPCanvasItem *item, Geom::IntRect const &old_area, Geom::IntRect const &new_area) +{ + SPCanvasGroup *group = SP_CANVAS_GROUP (item); + + for (GList *list = group->items; list; list = list->next) { + SPCanvasItem *child = (SPCanvasItem *)list->data; + if (child->flags & SP_CANVAS_ITEM_VISIBLE) { + if (SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed) + SP_CANVAS_ITEM_GET_CLASS (child)->visible_area_changed (child, old_area, new_area); + } + } +} + /** * Adds an item to a canvas group. */ @@ -1045,7 +1061,7 @@ sp_canvas_init (SPCanvas *canvas) #if ENABLE_LCMS canvas->enable_cms_display_adj = false; - canvas->cms_key = new Glib::ustring(""); + new (&canvas->cms_key) Glib::ustring(""); #endif // ENABLE_LCMS canvas->is_scrolling = false; @@ -1105,6 +1121,8 @@ sp_canvas_destroy (GtkObject *object) shutdown_transients (canvas); + canvas->cms_key.~ustring(); + if (GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object); } @@ -1134,8 +1152,6 @@ sp_canvas_new_aa (void) static void sp_canvas_realize (GtkWidget *widget) { - SPCanvas *canvas = SP_CANVAS (widget); - GdkWindowAttr attributes; attributes.window_type = GDK_WINDOW_CHILD; attributes.x = widget->allocation.x; @@ -1171,8 +1187,6 @@ sp_canvas_realize (GtkWidget *widget) widget->style = gtk_style_attach (widget->style, widget->window); gtk_widget_set_realized (widget, TRUE); - - canvas->pixmap_gc = gdk_gc_new (SP_CANVAS_WINDOW (canvas)); } /** @@ -1189,9 +1203,6 @@ sp_canvas_unrealize (GtkWidget *widget) shutdown_transients (canvas); - gdk_gc_destroy (canvas->pixmap_gc); - canvas->pixmap_gc = NULL; - if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget); } @@ -1216,8 +1227,16 @@ sp_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { SPCanvas *canvas = SP_CANVAS (widget); + Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0, + widget->allocation.width, widget->allocation.height); + Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0, + allocation->width, allocation->height); + /* Schedule redraw of new region */ sp_canvas_resize_tiles(canvas,canvas->x0,canvas->y0,canvas->x0+allocation->width,canvas->y0+allocation->height); + if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed) + SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area); + if (allocation->width > widget->allocation.width) { sp_canvas_request_redraw (canvas, canvas->x0 + widget->allocation.width, @@ -1602,7 +1621,7 @@ sp_canvas_motion (GtkWidget *widget, GdkEventMotion *event) if (event->window != SP_CANVAS_WINDOW (canvas)) return FALSE; - if (canvas->pixmap_gc == NULL) // canvas being deleted + if (canvas->root == NULL) // canvas being deleted return FALSE; canvas->state = event->state; @@ -1670,7 +1689,7 @@ static void sp_canvas_paint_single_buffer(SPCanvas *canvas, int x0, int y0, int Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display"); if ( fromDisplay ) { - transf = Inkscape::CMSSystem::getDisplayPer( canvas->cms_key ? *(canvas->cms_key) : "" ); + transf = Inkscape::CMSSystem::getDisplayPer( canvas->cms_key ); } else { transf = Inkscape::CMSSystem::getDisplayTransform(); } @@ -1857,16 +1876,6 @@ sp_canvas_paint_rect (SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1) rect.x1 = MIN (rect.x1, canvas->x0/*draw_x1*/ + GTK_WIDGET (canvas)->allocation.width); rect.y1 = MIN (rect.y1, canvas->y0/*draw_y1*/ + GTK_WIDGET (canvas)->allocation.height); -#ifdef DEBUG_REDRAW - // paint the area to redraw yellow - gdk_rgb_gc_set_foreground (canvas->pixmap_gc, 0xFFFF00); - gdk_draw_rectangle (SP_CANVAS_WINDOW (canvas), - canvas->pixmap_gc, - TRUE, - rect.x0 - canvas->x0, rect.y0 - canvas->y0, - rect.x1 - rect.x0, rect.y1 - rect.y0); -#endif - PaintRectSetup setup; setup.canvas = canvas; @@ -2064,7 +2073,7 @@ paint (SPCanvas *canvas) static int do_update (SPCanvas *canvas) { - if (!canvas->root || !canvas->pixmap_gc) // canvas may have already be destroyed by closing desktop during interrupted display! + if (!canvas->root) // canvas may have already be destroyed by closing desktop during interrupted display! return TRUE; if (canvas->drawing_disabled) @@ -2150,12 +2159,17 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear, int dx = ix - canvas->x0; // dx and dy specify the displacement (scroll) of the int dy = iy - canvas->y0; // canvas w.r.t its previous position + Geom::IntRect old_area = canvas->getViewboxIntegers(); + Geom::IntRect new_area = old_area + Geom::IntPoint(dx, dy); + canvas->dx0 = cx; // here the 'd' stands for double, not delta! canvas->dy0 = cy; canvas->x0 = ix; canvas->y0 = iy; sp_canvas_resize_tiles (canvas, canvas->x0, canvas->y0, canvas->x0+canvas->widget.allocation.width, canvas->y0+canvas->widget.allocation.height); + if (SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed) + SP_CANVAS_ITEM_GET_CLASS (canvas->root)->visible_area_changed (canvas->root, old_area, new_area); if (!clear) { // scrolling without zoom; redraw only the newly exposed areas @@ -2168,7 +2182,6 @@ sp_canvas_scroll_to (SPCanvas *canvas, double cx, double cy, unsigned int clear, } else { // scrolling as part of zoom; do nothing here - the next do_update will perform full redraw } - } /** @@ -2301,13 +2314,15 @@ Geom::Rect SPCanvas::getViewbox() const } /** - * Return canvas window coordinates as IRect (a rectangle defined by integers). + * Return canvas window coordinates as integer rectangle. */ -NR::IRect SPCanvas::getViewboxIntegers() const +Geom::IntRect SPCanvas::getViewboxIntegers() const { GtkWidget const *w = GTK_WIDGET(this); - return NR::IRect(NR::IPoint(x0, y0), - NR::IPoint(x0 + w->allocation.width, y0 + w->allocation.height)); + Geom::IntRect ret; + ret.setMin(Geom::IntPoint(x0, y0)); + ret.setMax(Geom::IntPoint(x0 + w->allocation.width, y0 + w->allocation.height)); + return ret; } inline int sp_canvas_tile_floor(int x) diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 7a6b3295e..f284afdf2 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -112,9 +112,6 @@ struct SPCanvas { int close_enough; - /* GC for temporary draw pixmap */ - GdkGC *pixmap_gc; - unsigned int need_update : 1; unsigned int need_redraw : 1; unsigned int need_repick : 1; @@ -143,13 +140,13 @@ struct SPCanvas { #if ENABLE_LCMS bool enable_cms_display_adj; - Glib::ustring* cms_key; + Glib::ustring cms_key; #endif // ENABLE_LCMS bool is_scrolling; Geom::Rect getViewbox() const; - NR::IRect getViewboxIntegers() const; + Geom::IntRect getViewboxIntegers() const; }; GtkWidget *sp_canvas_new_aa(); diff --git a/src/document.cpp b/src/document.cpp index 90fc4c635..5bcf1bf40 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -40,6 +40,7 @@ #include <gtk/gtk.h> #include <string> #include <cstring> +#include <2geom/transforms.h> #include "desktop.h" #include "dir-util.h" @@ -647,7 +648,7 @@ void SPDocument::fitToRect(Geom::Rect const &rect, bool with_margins) Geom::Translate const tr( Geom::Point(0, old_height - rect_with_margins.height()) - - to_2geom(rect_with_margins.min())); + - rect_with_margins.min()); root->translateChildItems(tr); if(nv) { diff --git a/src/draw-context.h b/src/draw-context.h index 4266bdea4..17540649b 100644 --- a/src/draw-context.h +++ b/src/draw-context.h @@ -16,9 +16,9 @@ #include <stddef.h> #include <sigc++/sigc++.h> +#include <2geom/point.h> #include "event-context.h" #include <forward.h> -#include <libnr/nr-point.h> #include "live_effects/effect.h" /* Freehand context */ diff --git a/src/dropper-context.cpp b/src/dropper-context.cpp index e30d6b1e8..9fbbcdc27 100644 --- a/src/dropper-context.cpp +++ b/src/dropper-context.cpp @@ -15,11 +15,10 @@ # include <config.h> #endif -#include <glibmm/i18n.h> -#include <glibmm/ustring.h> -#include <glibmm/refptr.h> -#include <gtkmm/clipboard.h> -#include <gdk/gdkkeysyms.h> +#include <glibmm.h> +#include <gtkmm.h> +#include <gdk/gdk.h> +#include <2geom/transforms.h> #include "macros.h" #include "display/canvas-bpath.h" diff --git a/src/dyna-draw-context.cpp b/src/dyna-draw-context.cpp index aa7d840bc..a3a665b1c 100644 --- a/src/dyna-draw-context.cpp +++ b/src/dyna-draw-context.cpp @@ -34,7 +34,7 @@ #include "svg/svg.h" #include "display/canvas-bpath.h" #include "display/cairo-utils.h" -#include <2geom/isnan.h> +#include <2geom/math-utils.h> #include <2geom/pathvector.h> #include <2geom/bezier-utils.h> #include "display/curve.h" diff --git a/src/eraser-context.cpp b/src/eraser-context.cpp index 8ac765b9e..de6c7d86f 100644 --- a/src/eraser-context.cpp +++ b/src/eraser-context.cpp @@ -62,7 +62,7 @@ #include "display/canvas-bpath.h" #include "display/canvas-arena.h" #include "livarot/Shape.h" -#include <2geom/isnan.h> +#include <2geom/math-utils.h> #include <2geom/pathvector.h> #include "eraser-context.h" diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h index b9e417feb..bd3edb43b 100644 --- a/src/extension/implementation/implementation.h +++ b/src/extension/implementation/implementation.h @@ -19,9 +19,9 @@ #include "forward.h" #include "extension/extension-forward.h" #include "libnr/nr-forward.h" -#include "libnr/nr-point.h" #include "xml/node.h" #include <2geom/forward.h> +#include <2geom/point.h> namespace Inkscape { namespace Extension { diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index 676e9aa94..642ddba5b 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -1013,7 +1013,7 @@ Geom::Point sp_item_gradient_get_coords(SPItem *item, guint point_type, guint po Geom::Point p (0, 0); if (!gradient) - return from_2geom(p); + return p; if (SP_IS_LINEARGRADIENT(gradient)) { SPLinearGradient *lg = SP_LINEARGRADIENT(gradient); @@ -1071,7 +1071,7 @@ Geom::Point sp_item_gradient_get_coords(SPItem *item, guint point_type, guint po } } p *= Geom::Affine(gradient->gradientTransform) * (Geom::Affine)item->i2d_affine(); - return from_2geom(p); + return p; } diff --git a/src/gradient-context.cpp b/src/gradient-context.cpp index 8b4d2bc37..c4bef4683 100644 --- a/src/gradient-context.cpp +++ b/src/gradient-context.cpp @@ -548,9 +548,9 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) dragging = true; - Geom::Point button_dt = to_2geom(desktop->w2d(button_w)); + Geom::Point button_dt = desktop->w2d(button_w); if (event->button.state & GDK_SHIFT_MASK) { - Inkscape::Rubberband::get(desktop)->start(desktop, from_2geom(button_dt)); + Inkscape::Rubberband::get(desktop)->start(desktop, button_dt); } else { // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to // enable Ctrl+doubleclick of exactly the selected item(s) @@ -563,7 +563,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); } - rc->origin = from_2geom(button_dt); + rc->origin = button_dt; } ret = TRUE; diff --git a/src/graphlayout.cpp b/src/graphlayout.cpp index 2717c376a..57002bfb6 100644 --- a/src/graphlayout.cpp +++ b/src/graphlayout.cpp @@ -19,6 +19,7 @@ #include <cstring> #include <cstdlib> #include <float.h> +#include <2geom/transforms.h> #include "desktop.h" #include "inkscape.h" diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 64aa8bc48..fdfbdb9d3 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -511,15 +511,15 @@ namespace Geom { 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) && - NR_DF_TEST_CLOSE(m0[2], m1[2], epsilon) && - NR_DF_TEST_CLOSE(m0[3], m1[3], epsilon); + Geom::are_near(m0[0], m1[0], epsilon) && + Geom::are_near(m0[1], m1[1], epsilon) && + Geom::are_near(m0[2], m1[2], epsilon) && + Geom::are_near(m0[3], m1[3], 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); + return Geom::are_near(m0[4], m1[4], epsilon) && Geom::are_near(m0[5], m1[5], epsilon); } diff --git a/src/helper/geom.h b/src/helper/geom.h index b1015b185..630d67aba 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -13,8 +13,8 @@ */ #include <2geom/forward.h> -#include <libnr/nr-forward.h> -#include <libnr/nr-coord.h> +#include <2geom/rect.h> +#include <2geom/affine.h> 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); diff --git a/src/helper/pixbuf-ops.cpp b/src/helper/pixbuf-ops.cpp index 9ebbe13c7..e1ced31b4 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -18,6 +18,7 @@ #include <glib.h> #include <glib/gmessages.h> #include <png.h> +#include <2geom/transforms.h> #include "interface.h" #include "helper/png-write.h" diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 4667f631b..5a20ac363 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -18,6 +18,7 @@ #include "interface.h" #include <2geom/rect.h> +#include <2geom/transforms.h> #include <glib/gmessages.h> #include <png.h> #include "png-write.h" diff --git a/src/helper/recthull.h b/src/helper/recthull.h index a9cad4466..d82450ce8 100644 --- a/src/helper/recthull.h +++ b/src/helper/recthull.h @@ -38,7 +38,7 @@ public: void add(Rect const &r) { // Note that this is a hack. when convexhull actually works // you will need to add all four points. - _bounds = unify(_bounds, r); + _bounds.unionWith(r); } void add(RectHull const &h) { if (h._bounds) { diff --git a/src/libcola/cola.cpp b/src/libcola/cola.cpp index e2a233b5e..87fbf9f79 100644 --- a/src/libcola/cola.cpp +++ b/src/libcola/cola.cpp @@ -2,7 +2,7 @@ #include "conjugate_gradient.h" #include "straightener.h" #include "shortest_paths.h" -#include "2geom/isnan.h" +#include <2geom/math-utils.h> using namespace std; diff --git a/src/libcola/gradient_projection.cpp b/src/libcola/gradient_projection.cpp index fb8702ec7..47109a4b0 100644 --- a/src/libcola/gradient_projection.cpp +++ b/src/libcola/gradient_projection.cpp @@ -17,7 +17,7 @@ #include <libvpsc/constraint.h> #include "gradient_projection.h" #include <iostream> -#include "2geom/isnan.h" +#include <2geom/math-utils.h> #include "isinf.h" #include <math.h> diff --git a/src/libnr/Makefile_insert b/src/libnr/Makefile_insert index 1027e0600..57d82c8ef 100644 --- a/src/libnr/Makefile_insert +++ b/src/libnr/Makefile_insert @@ -3,25 +3,16 @@ ink_common_sources += \ libnr/in-svg-plane.h \ libnr/nr-convert2geom.h \ - libnr/nr-coord.h \ - libnr/nr-dim2.h \ libnr/nr-forward.h \ - libnr/nr-i-coord.h \ libnr/nr-macros.h \ libnr/nr-object.cpp \ libnr/nr-object.h \ - libnr/nr-point-fns.cpp \ - libnr/nr-point-fns.h \ - libnr/nr-point-l.h \ - libnr/nr-point-ops.h \ - libnr/nr-point.h \ + libnr/nr-point-fns.cpp \ + libnr/nr-point-fns.h \ libnr/nr-rect-l.cpp \ libnr/nr-rect-l.h \ libnr/nr-rect.cpp \ libnr/nr-rect.h \ - libnr/nr-rect-ops.h \ - libnr/nr-types.cpp \ - libnr/nr-types.h \ libnr/nr-values.cpp \ libnr/nr-values.h diff --git a/src/libnr/in-svg-plane.h b/src/libnr/in-svg-plane.h index c1937f0fc..68c9e92a0 100644 --- a/src/libnr/in-svg-plane.h +++ b/src/libnr/in-svg-plane.h @@ -1,8 +1,7 @@ #ifndef SEEN_LIBNR_IN_SVG_PLANE_H #define SEEN_LIBNR_IN_SVG_PLANE_H -#include "libnr/nr-point-fns.h" - +#include <2geom/point.h> /** * Returns true iff the coordinates of \a p are finite, non-NaN, and "small enough". Currently we @@ -13,7 +12,7 @@ * in SVG Tiny (which uses fixed-point arithmetic). */ inline bool -in_svg_plane(NR::Point const p) +in_svg_plane(Geom::Point const &p) { return Geom::LInfty(p) < 1e18; } diff --git a/src/libnr/libnr.def b/src/libnr/libnr.def deleted file mode 100644 index d8f224ca9..000000000 --- a/src/libnr/libnr.def +++ /dev/null @@ -1,89 +0,0 @@ -EXPORTS - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM - nr_R8G8B8A8_N_EMPTY_A8_RGBA32 - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_A8 - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P - nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_A8 - nr_R8G8B8A8_N_R8G8B8A8_N_A8_RGBA32 - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_A8 - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P - nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_A8 - nr_R8G8B8A8_P_EMPTY_A8_RGBA32 - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_A8 - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P - nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_A8 - nr_R8G8B8A8_P_R8G8B8A8_P_A8_RGBA32 - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_A8 - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P - nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_A8 -; nr_R8G8B8_EMPTY_A8_RGBA32 - nr_R8G8B8_R8G8B8_A8_RGBA32 - nr_R8G8B8_R8G8B8_R8G8B8A8_N - nr_R8G8B8_R8G8B8_R8G8B8A8_P - nr_active_object_add_listener - nr_active_object_get_type - nr_active_object_remove_listener_by_data - nr_blit_pixblock_mask_rgba32 - nr_blit_pixblock_pixblock_alpha - nr_blit_pixblock_pixblock_mask - nr_compose_pixblock_pixblock_pixel - nr_emit_fail_warning - nr_flat_free_list - nr_flat_free_one - nr_flat_insert_sorted - nr_flat_new_full - nr_lgradient_renderer_setup - nr_matrix_invert - nr_matrix_set_rotate - nr_matrix_set_scale - nr_matrix_set_translate - nr_matrix_multiply - nr_object_check_instance_cast - nr_object_check_instance_type - nr_object_delete - nr_object_get_type - nr_object_new - nr_object_ref - nr_object_register_type - nr_object_release - nr_object_setup - nr_object_unref - nr_path_duplicate_transform - nr_path_matrix_bbox_nion - nr_path_matrix_point_bbox_wind_distance - nr_pixblock_draw_line_rgba32 - nr_pixblock_free - nr_pixblock_new - nr_pixblock_release - nr_pixblock_render_gray_noise - nr_pixblock_render_svp_mask_or - nr_pixblock_setup - nr_pixblock_setup_extern - nr_pixblock_setup_fast - nr_pixelstore_16K_free - nr_pixelstore_16K_new - nr_pixelstore_4K_free - nr_pixelstore_4K_new - nr_pixelstore_64K_free - nr_pixelstore_64K_new - nr_rect_d_intersect - nr_rect_d_matrix_transform - nr_rect_d_union - nr_rect_l_intersect - nr_rect_l_union - nr_rgradient_renderer_setup - nr_svp_bbox - nr_svp_free - nr_svp_point_distance - nr_svp_point_wind - nr_type_is_a - nr_vertex_free_list - nr_vertex_free_one - nr_vertex_new - nr_vertex_new_xy - nr_vertex_reverse_list diff --git a/src/libnr/nr-convert2geom.h b/src/libnr/nr-convert2geom.h index 75098ce2b..7e2423ea6 100644 --- a/src/libnr/nr-convert2geom.h +++ b/src/libnr/nr-convert2geom.h @@ -10,34 +10,14 @@ */ #include <libnr/nr-rect.h> -#include <libnr/nr-point.h> -#include <2geom/affine.h> -#include <2geom/d2.h> -#include <2geom/transforms.h> -#include <2geom/point.h> +#include <2geom/rect.h> -inline Geom::Point to_2geom(NR::Point const & _pt) { - return Geom::Point(_pt[0], _pt[1]); -} -inline NR::Point from_2geom(Geom::Point const & _pt) { - return NR::Point(_pt[0], _pt[1]); -} - -inline Geom::Rect to_2geom(NR::Rect const & rect) { - Geom::Rect rect2geom(to_2geom(rect.min()), to_2geom(rect.max())); - return rect2geom; -} -inline NR::Rect from_2geom(Geom::Rect const & rect2geom) { - NR::Rect rect(rect2geom.min(), rect2geom.max()); - return rect; -} -inline Geom::OptRect to_2geom(boost::optional<NR::Rect> const & rect) { - Geom::OptRect rect2geom; - if (!rect) { - return rect2geom; - } - rect2geom = to_2geom(*rect); - return rect2geom; +inline Geom::OptRect to_2geom(NRRect const *nr) { + Geom::OptRect ret; + if (!nr) return ret; + if (nr->x1 < nr->x0 || nr->y1 < nr->y0) return ret; + ret = Geom::Rect(Geom::Point(nr->x0, nr->y0), Geom::Point(nr->x1, nr->y1)); + return ret; } #endif diff --git a/src/libnr/nr-coord.h b/src/libnr/nr-coord.h deleted file mode 100644 index e094caeb3..000000000 --- a/src/libnr/nr-coord.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SEEN_NR_COORD_H -#define SEEN_NR_COORD_H - -namespace NR { - -/** - * A "real" type with sufficient precision for 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 - * differences of on-canvas points. - */ -typedef double Coord; - -} /* namespace NR */ - - -#endif /* !SEEN_NR_COORD_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/libnr/nr-dim2.h b/src/libnr/nr-dim2.h deleted file mode 100644 index c068bc220..000000000 --- a/src/libnr/nr-dim2.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SEEN_NR_DIM2_H -#define SEEN_NR_DIM2_H - -namespace NR { - -enum Dim2 { X=0, Y }; - -} /* namespace NR */ - - -#endif /* !SEEN_NR_DIM2_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/libnr/nr-forward.h b/src/libnr/nr-forward.h index 82e29030c..4895ad407 100644 --- a/src/libnr/nr-forward.h +++ b/src/libnr/nr-forward.h @@ -10,20 +10,10 @@ * This code is in public domain */ -namespace NR { -class Matrix; -class Point; -class Rect; -class rotate; -class scale; -class translate; -} - struct NRPixBlock; struct NRRect; struct NRRectL; - #endif /* diff --git a/src/libnr/nr-i-coord.h b/src/libnr/nr-i-coord.h deleted file mode 100644 index a19d2ca46..000000000 --- a/src/libnr/nr-i-coord.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SEEN_NR_I_COORD_H -#define SEEN_NR_I_COORD_H - -#include <glib/gtypes.h> - -namespace NR { - -/** An integer type with sufficient precision for coordinates. */ -typedef gint32 ICoord; - -} /* namespace NR */ - - -#endif /* !SEEN_NR_I_COORD_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/libnr/nr-point-fns-test.h b/src/libnr/nr-point-fns-test.h deleted file mode 100644 index df166660c..000000000 --- a/src/libnr/nr-point-fns-test.h +++ /dev/null @@ -1,139 +0,0 @@ -// nr-point-fns-test.h -#include <cxxtest/TestSuite.h> - -#include <cassert> -#include <cmath> -#include <glib/gmacros.h> -#include <stdlib.h> - -#include "libnr/nr-point-fns.h" -#include "2geom/isnan.h" - -class NrPointFnsTest : public CxxTest::TestSuite -{ -public: - NrPointFnsTest() : - setupValid(true), - p3n4( 3.0, -4.0 ), - p0( 0.0, 0.0 ), - small( pow( 2.0, -1070 ) ), - inf( 1e400 ), - nan( inf - inf ), - small_left( -small, 0.0 ), - small_n3_4( -3.0 * small, 4.0 * small ), - part_nan( 3., nan ), - inf_left( -inf, 5.0 ) - { - TS_ASSERT( IS_NAN(nan) ); - TS_ASSERT( !IS_NAN(small) ); - - setupValid &= IS_NAN(nan); - setupValid &= !IS_NAN(small); - } - virtual ~NrPointFnsTest() {} - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrPointFnsTest *createSuite() { return new NrPointFnsTest(); } - static void destroySuite( NrPointFnsTest *suite ) { delete suite; } - -// Called before each test in this suite - void setUp() - { - TS_ASSERT( setupValid ); - } - - bool setupValid; - NR::Point const p3n4; - NR::Point const p0; - double const small; - double const inf; - double const nan; - - NR::Point const small_left; - NR::Point const small_n3_4; - NR::Point const part_nan; - NR::Point const inf_left; - - - void testL1(void) - { - TS_ASSERT_EQUALS( NR::L1(p0), 0.0 ); - TS_ASSERT_EQUALS( NR::L1(p3n4), 7.0 ); - TS_ASSERT_EQUALS( NR::L1(small_left), small ); - TS_ASSERT_EQUALS( NR::L1(inf_left), inf ); - TS_ASSERT_EQUALS( NR::L1(small_n3_4), 7.0 * small ); - TS_ASSERT(IS_NAN(NR::L1(part_nan))); - } - - void testL2(void) - { - TS_ASSERT_EQUALS( NR::L2(p0), 0.0 ); - TS_ASSERT_EQUALS( NR::L2(p3n4), 5.0 ); - TS_ASSERT_EQUALS( NR::L2(small_left), small ); - TS_ASSERT_EQUALS( NR::L2(inf_left), inf ); - TS_ASSERT_EQUALS( NR::L2(small_n3_4), 5.0 * small ); - TS_ASSERT( IS_NAN(NR::L2(part_nan)) ); - } - - void testLInfty(void) - { - TS_ASSERT_EQUALS( NR::LInfty(p0), 0.0 ); - TS_ASSERT_EQUALS( NR::LInfty(p3n4), 4.0 ); - TS_ASSERT_EQUALS( NR::LInfty(small_left), small ); - TS_ASSERT_EQUALS( NR::LInfty(inf_left), inf ); - TS_ASSERT_EQUALS( NR::LInfty(small_n3_4), 4.0 * small ); - TS_ASSERT( IS_NAN(NR::LInfty(part_nan)) ); - } - - void testIsZero(void) - { - TS_ASSERT( NR::is_zero(p0) ); - TS_ASSERT( !NR::is_zero(p3n4) ); - TS_ASSERT( !NR::is_zero(small_left) ); - TS_ASSERT( !NR::is_zero(inf_left) ); - TS_ASSERT( !NR::is_zero(small_n3_4) ); - TS_ASSERT( !NR::is_zero(part_nan) ); - } - - void testAtan2(void) - { - TS_ASSERT_EQUALS( NR::atan2(p3n4), atan2(-4.0, 3.0) ); - TS_ASSERT_EQUALS( NR::atan2(small_left), atan2(0.0, -1.0) ); - TS_ASSERT_EQUALS( NR::atan2(small_n3_4), atan2(4.0, -3.0) ); - } - - void testUnitVector(void) - { - TS_ASSERT_EQUALS( NR::unit_vector(p3n4), NR::Point(.6, -0.8) ); - TS_ASSERT_EQUALS( NR::unit_vector(small_left), NR::Point(-1.0, 0.0) ); - TS_ASSERT_EQUALS( NR::unit_vector(small_n3_4), NR::Point(-.6, 0.8) ); - } - - void testIsUnitVector(void) - { - TS_ASSERT( !NR::is_unit_vector(p3n4) ); - TS_ASSERT( !NR::is_unit_vector(small_left) ); - TS_ASSERT( !NR::is_unit_vector(small_n3_4) ); - TS_ASSERT( !NR::is_unit_vector(part_nan) ); - TS_ASSERT( !NR::is_unit_vector(inf_left) ); - TS_ASSERT( !NR::is_unit_vector(NR::Point(.5, 0.5)) ); - TS_ASSERT( NR::is_unit_vector(NR::Point(.6, -0.8)) ); - TS_ASSERT( NR::is_unit_vector(NR::Point(-.6, 0.8)) ); - TS_ASSERT( NR::is_unit_vector(NR::Point(-1.0, 0.0)) ); - TS_ASSERT( NR::is_unit_vector(NR::Point(1.0, 0.0)) ); - TS_ASSERT( NR::is_unit_vector(NR::Point(0.0, -1.0)) ); - TS_ASSERT( NR::is_unit_vector(NR::Point(0.0, 1.0)) ); - } -}; - -/* - 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/libnr/nr-point-fns.cpp b/src/libnr/nr-point-fns.cpp index cd6d6927b..a2e74c112 100644 --- a/src/libnr/nr-point-fns.cpp +++ b/src/libnr/nr-point-fns.cpp @@ -1,72 +1,11 @@ -#include <libnr/nr-point-fns.h> -#include <2geom/isnan.h> +#include "libnr/nr-point-fns.h" -using NR::Point; - -/** Compute the L infinity, or maximum, norm of \a p. */ -NR::Coord NR::LInfty(Point const &p) { - NR::Coord const a(fabs(p[0])); - NR::Coord const b(fabs(p[1])); - return ( a < b || IS_NAN(b) - ? b - : a ); -} - -/** Returns true iff p is a zero vector, i.e.\ Point(0, 0). - * - * (NaN is considered non-zero.) - */ -bool -NR::is_zero(Point const &p) -{ - return ( p[0] == 0 && - p[1] == 0 ); -} - -bool -NR::is_unit_vector(Point const &p) -{ - return fabs(1.0 - L2(p)) <= 1e-4; - /* The tolerance of 1e-4 is somewhat arbitrary. NR::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. */ -} - -NR::Coord NR::atan2(Point const p) { - return std::atan2(p[NR::Y], p[NR::X]); -} - -/** 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. - */ -Point NR::unit_vector(Point const &a) -{ - Point ret(a); - ret.normalize(); - return ret; -} - -NR::Point abs(NR::Point const &b) -{ - NR::Point ret; - for ( int i = 0 ; i < 2 ; i++ ) { - ret[i] = fabs(b[i]); - } - return ret; -} - -NR::Point -snap_vector_midpoint (NR::Point p, NR::Point begin, NR::Point end, double snap) +Geom::Point +snap_vector_midpoint (Geom::Point const &p, Geom::Point const &begin, Geom::Point const &end, double snap) { - double length = NR::L2(end - begin); - NR::Point be = (end - begin) / length; - double r = NR::dot(p - begin, be); + double length = Geom::distance(begin, end); + Geom::Point be = (end - begin) / length; + double r = Geom::dot(p - begin, be); if (r < 0.0) return begin; if (r > length) return end; @@ -78,11 +17,11 @@ snap_vector_midpoint (NR::Point p, NR::Point begin, NR::Point end, double snap) } double -get_offset_between_points (NR::Point p, NR::Point begin, NR::Point end) +get_offset_between_points (Geom::Point const &p, Geom::Point const &begin, Geom::Point const &end) { - double length = NR::L2(end - begin); - NR::Point be = (end - begin) / length; - double r = NR::dot(p - begin, be); + double length = Geom::distance(begin, end); + Geom::Point be = (end - begin) / length; + double r = Geom::dot(p - begin, be); if (r < 0.0) return 0.0; if (r > length) return 1.0; @@ -90,8 +29,8 @@ get_offset_between_points (NR::Point p, NR::Point begin, NR::Point end) return (r / length); } -NR::Point -project_on_linesegment(NR::Point const p, NR::Point const p1, NR::Point const p2) +Geom::Point +project_on_linesegment(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2) { // p_proj = projection of p on the linesegment running from p1 to p2 // p_proj = p1 + u (p2 - p1) @@ -104,9 +43,9 @@ project_on_linesegment(NR::Point const p, NR::Point const p1, NR::Point const p2 return p; } - NR::Point const d1(p-p1); // delta 1 - NR::Point const d2(p2-p1); // delta 2 - double const u = (d1[NR::X] * d2[NR::X] + d1[NR::Y] * d2[NR::Y]) / (NR::L2(d2) * NR::L2(d2)); + Geom::Point d1(p-p1); // delta 1 + Geom::Point d2(p2-p1); // delta 2 + double u = Geom::dot(d1, d2) / Geom::L2sq(d2); return (p1 + u*(p2-p1)); } diff --git a/src/libnr/nr-point-fns.h b/src/libnr/nr-point-fns.h index 05c4f718c..b26c969aa 100644 --- a/src/libnr/nr-point-fns.h +++ b/src/libnr/nr-point-fns.h @@ -1,100 +1,13 @@ #ifndef __NR_POINT_OPS_H__ #define __NR_POINT_OPS_H__ -#include <libnr/nr-point-ops.h> -#include <libnr/nr-dim2.h> -#include <libnr/nr-macros.h> +#include <2geom/point.h> -namespace NR { +Geom::Point snap_vector_midpoint (Geom::Point const &p, Geom::Point const &begin, Geom::Point const &end, double snap); -/** Compute the L1 norm, or manhattan distance, of \a p. */ -inline Coord L1(Point const &p) { - Coord d = 0; - for ( int i = 0 ; i < 2 ; i++ ) { - d += fabs(p[i]); - } - return d; -} +double get_offset_between_points (Geom::Point const &p, Geom::Point const &begin, Geom::Point const &end); -/** Compute the L2, or euclidean, norm of \a p. */ -inline Coord L2(Point const &p) { - return hypot(p[0], p[1]); -} - -extern double LInfty(Point const &p); - -bool is_zero(Point const &p); - -bool is_unit_vector(Point const &p); - -extern double atan2(Point const p); - -inline bool point_equalp(Point const &a, Point const &b, double const eps) -{ - return ( NR_DF_TEST_CLOSE(a[X], b[X], eps) && - NR_DF_TEST_CLOSE(a[Y], b[Y], eps) ); -} - -/** Returns p * NR::rotate_degrees(90), but more efficient. - * - * Angle direction in Inkscape code: 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]); -} - -/** Given two points and a parameter t \in [0, 1], return a point - * proportionally from a to b by t. */ -inline Point Lerp(double const t, Point const a, Point const b) -{ - return ( ( 1 - t ) * a - + t * b ); -} - -Point unit_vector(Point const &a); - -inline Coord dot(Point const &a, Point const &b) -{ - Coord ret = 0; - for ( int i = 0 ; i < 2 ; i++ ) { - ret += a[i] * b[i]; - } - return ret; -} - -inline Coord distance (Point const &a, Point const &b) -{ - Coord ret = 0; - for ( int i = 0 ; i < 2 ; i++ ) { - ret += (a[i] - b[i]) * (a[i] - b[i]); - } - return sqrt (ret); -} - -/** Defined as dot(a, b.cw()). */ -inline Coord cross(Point const &a, Point const &b) -{ - Coord ret = 0; - ret -= a[0] * b[1]; - ret += a[1] * b[0]; - return ret; -} - -Point abs(Point const &b); - -} /* namespace NR */ - -NR::Point snap_vector_midpoint (NR::Point p, NR::Point begin, NR::Point end, double snap); - -double get_offset_between_points (NR::Point p, NR::Point begin, NR::Point end); - -NR::Point project_on_linesegment(NR::Point const p, NR::Point const p1, NR::Point const p2); +Geom::Point project_on_linesegment(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2); #endif /* !__NR_POINT_OPS_H__ */ diff --git a/src/libnr/nr-point-l.h b/src/libnr/nr-point-l.h deleted file mode 100644 index 9bfe2c790..000000000 --- a/src/libnr/nr-point-l.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef SEEN_NR_POINT_L_H -#define SEEN_NR_POINT_L_H - -#include <stdexcept> -#include <libnr/nr-i-coord.h> -#include <libnr/nr-point.h> - -struct NRPointL { - NR::ICoord x, y; -}; - -namespace NR { - -class IPoint { -public: - IPoint() - { } - - IPoint(ICoord x, ICoord y) { - _pt[X] = x; - _pt[Y] = y; - } - - IPoint(NRPointL const &p) { - _pt[X] = p.x; - _pt[Y] = p.y; - } - - IPoint(IPoint const &p) { - for (unsigned i = 0; i < 2; ++i) { - _pt[i] = p._pt[i]; - } - } - - IPoint &operator=(IPoint const &p) { - for (unsigned i = 0; i < 2; ++i) { - _pt[i] = p._pt[i]; - } - return *this; - } - - operator Point() { - return Point(_pt[X], _pt[Y]); - } - - ICoord operator[](unsigned i) const throw(std::out_of_range) { - if ( i > Y ) { - throw std::out_of_range("index out of range"); - } - return _pt[i]; - } - - ICoord &operator[](unsigned i) throw(std::out_of_range) { - if ( i > Y ) { - throw std::out_of_range("index out of range"); - } - return _pt[i]; - } - - ICoord operator[](Dim2 d) const throw() { return _pt[d]; } - ICoord &operator[](Dim2 d) throw() { return _pt[d]; } - - IPoint &operator+=(IPoint const &o) { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - _pt[i] += o._pt[i]; - } - return *this; - } - - IPoint &operator-=(IPoint const &o) { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - _pt[i] -= o._pt[i]; - } - return *this; - } - - bool operator==(IPoint const &other) const { - return _pt[X] == other[X] && _pt[Y] == other[Y]; - } - - bool operator!=(IPoint const &other) const { - return _pt[X] != other[X] || _pt[Y] != other[Y]; - } - -private: - ICoord _pt[2]; -}; - - -} // namespace NR - -#endif /* !SEEN_NR_POINT_L_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/libnr/nr-point-ops.h b/src/libnr/nr-point-ops.h deleted file mode 100644 index aba981803..000000000 --- a/src/libnr/nr-point-ops.h +++ /dev/null @@ -1,88 +0,0 @@ -/* operator functions for NR::Point. */ -#ifndef SEEN_NR_POINT_OPS_H -#define SEEN_NR_POINT_OPS_H - -#include <libnr/nr-point.h> - -namespace NR { - -inline Point operator+(Point const &a, Point const &b) -{ - Point ret; - for (int i = 0; i < 2; i++) { - ret[i] = a[i] + b[i]; - } - return ret; -} - -inline Point operator-(Point const &a, Point const &b) -{ - Point ret; - for (int i = 0; i < 2; i++) { - ret[i] = a[i] - b[i]; - } - return ret; -} - -/** 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; -} - -inline Point operator-(Point const &a) -{ - Point ret; - for(unsigned i = 0; i < 2; i++) { - ret[i] = -a[i]; - } - return ret; -} - -inline Point operator*(double const s, Point const &b) -{ - Point ret; - for(int i = 0; i < 2; i++) { - ret[i] = s * b[i]; - } - return ret; -} - -inline Point operator/(Point const &b, double const d) -{ - Point ret; - for(int i = 0; i < 2; i++) { - ret[i] = b[i] / d; - } - return ret; -} - - -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] ) ); -} - - -} /* namespace NR */ - - -#endif /* !SEEN_NR_POINT_OPS_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/libnr/nr-point.h b/src/libnr/nr-point.h deleted file mode 100644 index 19add7dd1..000000000 --- a/src/libnr/nr-point.h +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef SEEN_NR_POINT_H -#define SEEN_NR_POINT_H - -/** \file - * Cartesian point class. - */ - -//#include <math.h> -//#include <stdexcept> -#include <iostream> -//#include <iomanip> - -#include <libnr/nr-coord.h> -#include <libnr/nr-dim2.h> -#include <libnr/nr-forward.h> - -//#include "round.h" -#include "decimal-round.h" - -#include <2geom/point.h> - -namespace NR { - -/// Cartesian point. -class Point { -public: - inline Point() - { _pt[X] = _pt[Y] = 0; } - - inline Point(Coord x, Coord y) { - _pt[X] = x; - _pt[Y] = y; - } - - inline Point(Point const &p) { - for (unsigned i = 0; i < 2; ++i) { - _pt[i] = p._pt[i]; - } - } - - inline Point(Geom::Point const &p) { - _pt[X] = p[Geom::X]; - _pt[Y] = p[Geom::Y]; - } - - inline 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]; - } - - Coord operator[](Dim2 d) const throw() { return _pt[d]; } - Coord &operator[](Dim2 d) throw() { return _pt[d]; } - - /** 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.) - **/ - 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)(Inkscape::decimal_round((double)_pt[X], places)); - _pt[Y] = (Coord)(Inkscape::decimal_round((double)_pt[Y], places)); - return; - } - - void normalize(); - - inline 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) { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - _pt[i] -= o._pt[i]; - } - return *this; - } - - inline Point &operator/=(double const s) { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - _pt[i] /= s; - } - return *this; - } - - inline Point &operator*=(double const s) { - for ( unsigned i = 0 ; i < 2 ; ++i ) { - _pt[i] *= s; - } - return *this; - } - - Point &operator*=(Matrix const &m); - - inline int operator == (const Point &in_pnt) { - return ((_pt[X] == in_pnt[X]) && (_pt[Y] == in_pnt[Y])); - } - - friend inline std::ostream &operator<< (std::ostream &out_file, const NR::Point &in_pnt); - - inline operator Geom::Point() const { return Geom::Point(_pt[X], _pt[Y]); } - -private: - Coord _pt[2]; -}; - -/** A function to print out the Point. It just prints out the coords - on the given output stream */ -inline std::ostream &operator<< (std::ostream &out_file, const NR::Point &in_pnt) { - out_file << "X: " << in_pnt[X] << " Y: " << in_pnt[Y]; - return out_file; -} - -} /* namespace NR */ - -#endif /* !SEEN_NR_POINT_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/libnr/nr-rect-l.cpp b/src/libnr/nr-rect-l.cpp index 9d1f80988..1cb268266 100644 --- a/src/libnr/nr-rect-l.cpp +++ b/src/libnr/nr-rect-l.cpp @@ -1,21 +1,50 @@ -#include <libnr/nr-rect-l.h> +#include "libnr/nr-rect-l.h" -boost::optional<NR::Rect> NRRectL::upgrade() const { - if (nr_rect_l_test_empty_ptr(this)) { - return boost::optional<NR::Rect>(); +NRRectL::NRRectL() +{ + x0 = G_MAXINT32; + y0 = G_MAXINT32; + x1 = G_MININT32; + y1 = G_MININT32; +} + +NRRectL::NRRectL(gint32 xmin, gint32 ymin, gint32 xmax, gint32 ymax) +{ + x0 = xmin; + y0 = ymin; + x1 = xmax; + y1 = ymax; +} + +NRRectL::NRRectL(Geom::OptIntRect const &r) +{ + if (r) { + x0 = r->left(); + y0 = r->top(); + x1 = r->right(); + y1 = r->bottom(); } else { - return NR::Rect(NR::Point(x0, y0), NR::Point(x1, y1)); + x0 = G_MAXINT32; + y0 = G_MAXINT32; + x1 = G_MININT32; + y1 = G_MININT32; } } -namespace NR { - -IRect::IRect(Rect const &r) : - _min(int(floor(r.min()[X])), int(floor(r.min()[Y]))), - _max(int(ceil(r.min()[X])), int(ceil(r.min()[Y]))) +NRRectL::NRRectL(Geom::IntRect const &r) { + x0 = r.left(); + y0 = r.top(); + x1 = r.right(); + y1 = r.bottom(); } +Geom::OptIntRect NRRectL::upgrade_2geom() const +{ + Geom::OptIntRect ret; + if (x0 > x1 || y0 > y1) return ret; + ret = Geom::IntRect(x0, y0, x1, y1); + return ret; } /* diff --git a/src/libnr/nr-rect-l.h b/src/libnr/nr-rect-l.h index 3493fa8f4..c4c5f5a6d 100644 --- a/src/libnr/nr-rect-l.h +++ b/src/libnr/nr-rect-l.h @@ -1,132 +1,19 @@ #ifndef SEEN_NR_RECT_L_H #define SEEN_NR_RECT_L_H -#include <libnr/nr-i-coord.h> -#include <boost/optional.hpp> -#include <libnr/nr-rect.h> -#include <libnr/nr-point-l.h> +#include <glib.h> +#include <2geom/int-rect.h> struct NRRectL { - boost::optional<NR::Rect> upgrade() const; - NR::ICoord x0, y0, x1, y1; + gint32 x0, y0, x1, y1; + NRRectL(); + NRRectL(gint32 xmin, gint32 ymin, gint32 xmax, gint32 ymax); + explicit NRRectL(Geom::IntRect const &r); + explicit NRRectL(Geom::OptIntRect const &r); + operator Geom::OptIntRect() const { Geom::OptIntRect r = upgrade_2geom(); return r; } + Geom::OptIntRect upgrade_2geom() const; }; - -namespace NR { - - -class IRect { -public: - IRect(const NRRectL& r) : _min(r.x0, r.y0), _max(r.x1, r.y1) {} - IRect(const IRect& r) : _min(r._min), _max(r._max) {} - IRect(const IPoint &p0, const IPoint &p1) : _min(p0), _max(p1) {} - - /** as not all Rects are representable by IRects this gives the smallest IRect that contains - * r. */ - IRect(const Rect& r); - - operator Rect() { - return Rect(Point(_min), Point(_max)); - } - - const IPoint &min() const { return _min; } - const IPoint &max() const { return _max; } - - /** returns a vector from min to max. */ - IPoint dimensions() const; - - /** does this rectangle have zero area? */ - bool isEmpty() const { - return isEmpty<X>() && isEmpty<Y>(); - } - - bool intersects(const IRect &r) const { - return intersects<X>(r) && intersects<Y>(r); - } - bool contains(const IRect &r) const { - return contains<X>(r) && contains<Y>(r); - } - bool contains(const IPoint &p) const { - return contains<X>(p) && contains<Y>(p); - } - - ICoord maxExtent() const { - return MAX(extent<X>(), extent<Y>()); - } - - ICoord extent(Dim2 axis) const { - switch (axis) { - case X: return extent<X>(); - case Y: return extent<Y>(); - }; - } - - ICoord extent(unsigned i) const throw(std::out_of_range) { - switch (i) { - case 0: return extent<X>(); - case 1: return extent<Y>(); - default: throw std::out_of_range("Dimension out of range"); - }; - } - - /** Translates the rectangle by p. */ - void offset(IPoint p); - - /** Makes this rectangle large enough to include the point p. */ - void expandTo(IPoint p); - - /** Makes this rectangle large enough to include the rectangle r. */ - void expandTo(const IRect &r); - - /** Returns the set of points shared by both rectangles. */ - static boost::optional<IRect> intersection(const IRect &a, const IRect &b); - - /** Returns the smallest rectangle that encloses both rectangles. */ - static IRect union_bounds(const IRect &a, const IRect &b); - - bool operator==(const IRect &other) const { - return (min() == other.min()) && (max() == other.max()); - } - - bool operator!=(const IRect &other) const { - return (min() != other.min()) || (max() != other.max()); - } - -private: - IRect() {} - - template <NR::Dim2 axis> - ICoord extent() const { - return _max[axis] - _min[axis]; - } - - template <Dim2 axis> - bool isEmpty() const { - return !( _min[axis] < _max[axis] ); - } - - template <Dim2 axis> - bool intersects(const IRect &r) const { - return _max[axis] >= r._min[axis] && _min[axis] <= r._max[axis]; - } - - template <Dim2 axis> - bool contains(const IRect &r) const { - return contains(r._min) && contains(r._max); - } - - template <Dim2 axis> - bool contains(const IPoint &p) const { - return p[axis] >= _min[axis] && p[axis] <= _max[axis]; - } - - IPoint _min, _max; -}; - - - -} // namespace NR - #endif /* !SEEN_NR_RECT_L_H */ /* diff --git a/src/libnr/nr-rect-ops.h b/src/libnr/nr-rect-ops.h deleted file mode 100644 index 870091a94..000000000 --- a/src/libnr/nr-rect-ops.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef SEEN_NR_RECT_OPS_H -#define SEEN_NR_RECT_OPS_H - -/* - * Rect operators - * - * Copyright 2004 MenTaLguY <mental@rydia.net>, - * bulia byak <buliabyak@users.sf.net> - * - * This code is licensed under the GNU GPL; see COPYING for more information. - */ - -#include <libnr/nr-rect.h> - -namespace NR { - -inline Rect expand(Rect const &r, double by) { - NR::Point const p(by, by); - return Rect(r.min() + p, r.max() - p); -} - -inline Rect expand(Rect const &r, NR::Point by) { - return Rect(r.min() + by, r.max() - by); -} - -#if 0 -inline ConvexHull operator*(Rect const &r, Matrix const &m) { - /* FIXME: no mention of m. Should probably be made non-inline. */ - ConvexHull points(r.corner(0)); - for ( unsigned i = 1 ; i < 4 ; i++ ) { - points.add(r.corner(i)); - } - return points; -} -#endif - -} /* namespace NR */ - - -#endif /* !SEEN_NR_RECT_OPS_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/libnr/nr-rect.cpp b/src/libnr/nr-rect.cpp index 8e3672e03..67857ad49 100644 --- a/src/libnr/nr-rect.cpp +++ b/src/libnr/nr-rect.cpp @@ -9,25 +9,9 @@ * This code is in public domain */ -#include "nr-rect-l.h" #include <algorithm> -#include "nr-point-ops.h" - -NRRect::NRRect(NR::Rect const &rect) -: x0(rect.min()[NR::X]), y0(rect.min()[NR::Y]), - x1(rect.max()[NR::X]), y1(rect.max()[NR::Y]) -{} - -NRRect::NRRect(boost::optional<NR::Rect> const &rect) { - if (rect) { - x0 = rect->min()[NR::X]; - y0 = rect->min()[NR::Y]; - x1 = rect->max()[NR::X]; - y1 = rect->max()[NR::Y]; - } else { - nr_rect_d_set_empty(this); - } -} +#include "nr-rect.h" +#include "nr-rect-l.h" NRRect::NRRect(Geom::OptRect const &rect) { if (rect) { @@ -36,20 +20,12 @@ NRRect::NRRect(Geom::OptRect const &rect) { x1 = rect->max()[Geom::X]; y1 = rect->max()[Geom::Y]; } else { - nr_rect_d_set_empty(this); - } -} - -boost::optional<NR::Rect> NRRect::upgrade() const { - if (nr_rect_d_test_empty_ptr(this)) { - return boost::optional<NR::Rect>(); - } else { - return NR::Rect(NR::Point(x0, y0), NR::Point(x1, y1)); + *this = NR_RECT_EMPTY; } } Geom::OptRect NRRect::upgrade_2geom() const { - if (nr_rect_d_test_empty_ptr(this)) { + if (x0 > x1 || y0 > y1) { return Geom::OptRect(); } else { return Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)); @@ -65,7 +41,7 @@ Geom::OptRect NRRect::upgrade_2geom() const { NRRectL *nr_rect_l_intersect(NRRectL *d, const NRRectL *r0, const NRRectL *r1) { - NR::ICoord t; + gint32 t; t = std::max(r0->x0, r1->x0); d->x1 = std::min(r0->x1, r1->x1); d->x0 = t; @@ -79,7 +55,7 @@ NRRectL *nr_rect_l_intersect(NRRectL *d, const NRRectL *r0, const NRRectL *r1) NRRect * nr_rect_d_intersect (NRRect *d, const NRRect *r0, const NRRect *r1) { - NR::Coord t; + gint32 t; t = MAX (r0->x0, r1->x0); d->x1 = MIN (r0->x1, r1->x1); d->x0 = t; @@ -100,7 +76,7 @@ nr_rect_l_subtract(NRRectL *d, NRRectL const *r0, NRRectL const *r1) bool inside4 = nr_rect_l_test_inside(r1, r0->x0, r0->y1); if (inside1 && inside2 && inside3) { - nr_rect_l_set_empty (d); + *d = NR_RECT_L_EMPTY; } else if (inside1 && inside2) { d->x0 = r0->x0; @@ -136,7 +112,7 @@ nr_rect_l_subtract(NRRectL *d, NRRectL const *r0, NRRectL const *r1) return d; } -NR::ICoord nr_rect_l_area(NRRectL *r) +gint32 nr_rect_l_area(NRRectL *r) { if (!r || NR_RECT_DFLS_TEST_EMPTY (r)) { return 0; @@ -149,7 +125,7 @@ nr_rect_d_union (NRRect *d, const NRRect *r0, const NRRect *r1) { if (NR_RECT_DFLS_TEST_EMPTY (r0)) { if (NR_RECT_DFLS_TEST_EMPTY (r1)) { - nr_rect_d_set_empty (d); + *d = NR_RECT_EMPTY; } else { *d = *r1; } @@ -157,7 +133,7 @@ nr_rect_d_union (NRRect *d, const NRRect *r0, const NRRect *r1) if (NR_RECT_DFLS_TEST_EMPTY (r1)) { *d = *r0; } else { - NR::Coord t; + double t; t = MIN (r0->x0, r1->x0); d->x1 = MAX (r0->x1, r1->x1); d->x0 = t; @@ -174,7 +150,7 @@ nr_rect_l_union (NRRectL *d, const NRRectL *r0, const NRRectL *r1) { if (NR_RECT_DFLS_TEST_EMPTY (r0)) { if (NR_RECT_DFLS_TEST_EMPTY (r1)) { - nr_rect_l_set_empty (d); + *d = NR_RECT_L_EMPTY; } else { *d = *r1; } @@ -182,7 +158,7 @@ nr_rect_l_union (NRRectL *d, const NRRectL *r0, const NRRectL *r1) if (NR_RECT_DFLS_TEST_EMPTY (r1)) { *d = *r0; } else { - NR::ICoord t; + double t; t = MIN (r0->x0, r1->x0); d->x1 = MAX (r0->x1, r1->x1); d->x0 = t; @@ -195,16 +171,13 @@ nr_rect_l_union (NRRectL *d, const NRRectL *r0, const NRRectL *r1) } NRRect * -nr_rect_union_pt(NRRect *dst, NR::Point const &p) +nr_rect_union_pt(NRRect *dst, Geom::Point const &p) { - using NR::X; - using NR::Y; - - return nr_rect_d_union_xy(dst, p[X], p[Y]); + return nr_rect_d_union_xy(dst, p[Geom::X], p[Geom::Y]); } NRRect * -nr_rect_d_union_xy (NRRect *d, NR::Coord x, NR::Coord y) +nr_rect_d_union_xy (NRRect *d, double x, double y) { if ((d->x0 <= d->x1) && (d->y0 <= d->y1)) { d->x0 = MIN (d->x0, x); @@ -218,147 +191,6 @@ nr_rect_d_union_xy (NRRect *d, NR::Coord x, NR::Coord y) return d; } -// TODO investigate for removal: -NRRect *nr_rect_d_matrix_transform(NRRect *d, NRRect const *const /*s*/, NR::Matrix const & /*m*/) -{ - // defunct - /* - using NR::X; - using NR::Y; - - if (nr_rect_d_test_empty_ptr(s)) { - nr_rect_d_set_empty(d); - } else { - NR::Point const c00(NR::Point(s->x0, s->y0) * m); - NR::Point const c01(NR::Point(s->x0, s->y1) * m); - NR::Point const c10(NR::Point(s->x1, s->y0) * m); - NR::Point const c11(NR::Point(s->x1, s->y1) * m); - d->x0 = std::min(std::min(c00[X], c01[X]), - std::min(c10[X], c11[X])); - d->y0 = std::min(std::min(c00[Y], c01[Y]), - std::min(c10[Y], c11[Y])); - d->x1 = std::max(std::max(c00[X], c01[X]), - std::max(c10[X], c11[X])); - d->y1 = std::max(std::max(c00[Y], c01[Y]), - std::max(c10[Y], c11[Y])); - }*/ - return d; -} - -NRRect * -nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NR::Matrix const *m) -{ - return nr_rect_d_matrix_transform(d, s, *m); -} - -/** Enlarges the rectangle given amount of pixels to all directions */ -NRRectL * -nr_rect_l_enlarge(NRRectL *d, int amount) -{ - d->x0 -= amount; - d->y0 -= amount; - d->x1 += amount; - d->y1 += amount; - return d; -} - -namespace NR { - -Rect::Rect(const Point &p0, const Point &p1) -: _min(std::min(p0[X], p1[X]), std::min(p0[Y], p1[Y])), - _max(std::max(p0[X], p1[X]), std::max(p0[Y], p1[Y])) -{} - -/** returns the four corners of the rectangle in the correct winding order */ -Point Rect::corner(unsigned i) const { - switch (i % 4) { - case 0: - return _min; - case 1: - return Point(_max[X], _min[Y]); - case 2: - return _max; - default: /* i.e. 3 */ - return Point(_min[X], _max[Y]); - } -} - -/** returns the midpoint of this rectangle */ -Point Rect::midpoint() const { - return ( _min + _max ) / 2; -} - -Point Rect::cornerFarthestFrom(Point const &p) const { - Point m = midpoint(); - unsigned i = 0; - if (p[X] < m[X]) { - i = 1; - } - if (p[Y] < m[Y]) { - i = 3 - i; - } - return corner(i); -} - -/** returns a vector from topleft to bottom right. */ -Point Rect::dimensions() const { - return _max - _min; -} - -/** Translates the rectangle by p. */ -void Rect::offset(Point p) { - _min += p; - _max += p; -} - -/** Makes this rectangle large enough to include the point p. */ -void Rect::expandTo(Point p) { - for ( int i=0 ; i < 2 ; i++ ) { - _min[i] = std::min(_min[i], p[i]); - _max[i] = std::max(_max[i], p[i]); - } -} - -void Rect::growBy(double size) { - for ( unsigned d = 0 ; d < 2 ; d++ ) { - _min[d] -= size; - _max[d] += size; - if ( _min[d] > _max[d] ) { - _min[d] = _max[d] = ( _min[d] + _max[d] ) / 2; - } - } -} - -/** Returns the set of points shared by both rectangles. */ -boost::optional<Rect> intersection(boost::optional<Rect> const & a, boost::optional<Rect> const & b) { - if ( !a || !b ) { - return boost::optional<Rect>(); - } else { - Rect r; - for ( int i=0 ; i < 2 ; i++ ) { - r._min[i] = std::max(a->_min[i], b->_min[i]); - r._max[i] = std::min(a->_max[i], b->_max[i]); - if ( r._min[i] > r._max[i] ) { - return boost::optional<Rect>(); - } - } - return r; - } -} - -/** returns the smallest rectangle containing both rectangles */ -Rect union_bounds(Rect const &a, Rect const &b) { - Rect r; - for ( int i=0 ; i < 2 ; i++ ) { - r._min[i] = std::min(a._min[i], b._min[i]); - r._max[i] = std::max(a._max[i], b._max[i]); - } - return r; -} - -} // namespace NR - - /* Local Variables: mode:c++ diff --git a/src/libnr/nr-rect.h b/src/libnr/nr-rect.h index aa5921309..4931b3e10 100644 --- a/src/libnr/nr-rect.h +++ b/src/libnr/nr-rect.h @@ -3,8 +3,7 @@ /** \file * Definitions of NRRect and NR::Rect types, and some associated functions \& macros. - */ -/* + *//* * Authors: * Lauris Kaplinski <lauris@kaplinski.com> * Nathan Hurst <njh@mail.csse.monash.edu.au> @@ -13,251 +12,33 @@ * This code is in public domain */ - #include <stdexcept> #include <limits> +#include <boost/optional.hpp> #include <glib.h> +#include <2geom/rect.h> +#include "libnr/nr-forward.h" #include "libnr/nr-values.h" -#include <libnr/nr-coord.h> -#include <libnr/nr-i-coord.h> -#include <libnr/nr-dim2.h> -#include <libnr/nr-point.h> -#include "libnr/nr-point-ops.h" #include "libnr/nr-macros.h" -#include <boost/optional.hpp> -#include <libnr/nr-forward.h> -#include <2geom/rect.h> - -namespace NR { - -class Matrix; - -/** A rectangle is always aligned to the X and Y axis. This means it - * can be defined using only 4 coordinates, and determining - * intersection is very efficient. The points inside a rectangle are - * min[dim] <= _pt[dim] <= max[dim]. A rectangle may be empty, in the - * sense of having zero area, but it will always contain at least one - * point. Infinities are also permitted. - */ -class Rect { -public: - Rect() : _min(-_inf(), -_inf()), _max(_inf(), _inf()) {} - Rect(Point const &p0, Point const &p1); - - Point const &min() const { return _min; } - Point const &max() const { return _max; } - - /** returns the four corners of the rectangle in order - * (clockwise if +Y is up, anticlockwise if +Y is down) */ - Point corner(unsigned i) const; - - /** returns a vector from min to max. */ - Point dimensions() const; - - /** returns the midpoint of this rect. */ - Point midpoint() const; - - Point cornerFarthestFrom(Point const &p) const; - - /** True iff either width or height is less than \a epsilon. */ - bool isEmpty(double epsilon=1e-6) const { - return isEmpty<X>(epsilon) || isEmpty<Y>(epsilon); - } - - bool intersects(Rect const &r) const { - return intersects<X>(r) && intersects<Y>(r); - } - bool contains(Rect const &r) const { - return contains<X>(r) && contains<Y>(r); - } - bool contains(Point const &p) const { - return contains<X>(p) && contains<Y>(p); - } - - double area() const { - return extent<X>() * extent<Y>(); - } - - double maxExtent() const { - return MAX(extent<X>(), extent<Y>()); - } - - double extent(Dim2 const axis) const { - switch (axis) { - case X: return extent<X>(); - case Y: return extent<Y>(); - default: g_error("invalid axis value %d", (int) axis); return 0; - }; - } - - double extent(unsigned i) const throw(std::out_of_range) { - switch (i) { - case 0: return extent<X>(); - case 1: return extent<Y>(); - default: throw std::out_of_range("Dimension out of range"); - }; - } - - /** - \brief Remove some precision from the Rect - \param places The number of decimal places left in the end - - This function just calls round on the \c _min and \c _max points. - */ - inline void round(int places = 0) { - _min.round(places); - _max.round(places); - return; - } - - /** Translates the rectangle by p. */ - void offset(Point p); - - /** Makes this rectangle large enough to include the point p. */ - void expandTo(Point p); - - /** Makes this rectangle large enough to include the rectangle r. */ - void expandTo(Rect const &r); - - inline void move_left (gdouble by) { - _min[NR::X] += by; - } - inline void move_right (gdouble by) { - _max[NR::X] += by; - } - inline void move_top (gdouble by) { - _min[NR::Y] += by; - } - inline void move_bottom (gdouble by) { - _max[NR::Y] += by; - } - - void growBy (gdouble by); - - /** Scales the rect by s, with origin at 0, 0 */ - inline Rect operator*(double const s) const { - return Rect(s * min(), s * max()); - } - - inline bool operator==(Rect const &in_rect) { - return ((this->min() == in_rect.min()) && (this->max() == in_rect.max())); - } - - friend inline std::ostream &operator<<(std::ostream &out_file, NR::Rect const &in_rect); - -private: -// Rect(Nothing) : _min(1, 1), _max(-1, -1) {} - - static double _inf() { - return std::numeric_limits<double>::infinity(); - } - - template <NR::Dim2 axis> - double extent() const { - return _max[axis] - _min[axis]; - } - - template <NR::Dim2 axis> - bool isEmpty(double epsilon) const { - return extent<axis>() < epsilon; - } - - template <Dim2 axis> - bool intersects(Rect const &r) const { - return _max[axis] >= r._min[axis] && _min[axis] <= r._max[axis]; - } - - template <Dim2 axis> - bool contains(Rect const &r) const { - return contains(r._min) && contains(r._max); - } - - template <Dim2 axis> - bool contains(Point const &p) const { - return p[axis] >= _min[axis] && p[axis] <= _max[axis]; - } - - Point _min, _max; - - friend boost::optional<Rect> intersection(boost::optional<Rect> const &, boost::optional<Rect> const &); - friend Rect union_bounds(Rect const &, Rect const &); -}; - -/** Returns the set of points shared by both rectangles. */ -boost::optional<Rect> intersection(boost::optional<Rect> const & a, boost::optional<Rect> const & b); - -/** Returns the smallest rectangle that encloses both rectangles. */ -Rect union_bounds(Rect const &a, Rect const &b); -inline Rect union_bounds(boost::optional<Rect> const & a, Rect const &b) { - if (a) { - return union_bounds(*a, b); - } else { - return b; - } -} -inline Rect union_bounds(Rect const &a, boost::optional<Rect> const & b) { - if (b) { - return union_bounds(a, *b); - } else { - return a; - } -} -inline boost::optional<Rect> union_bounds(boost::optional<Rect> const & a, boost::optional<Rect> const & b) -{ - if (!a) { - return b; - } else if (!b) { - return a; - } else { - return union_bounds(*a, *b); - } -} - -/** A function to print out the rectange if sent to an output - stream. */ -inline std::ostream -&operator<<(std::ostream &out_file, NR::Rect const &in_rect) -{ - out_file << "Rectangle:\n"; - out_file << "\tMin Point -> " << in_rect.min() << "\n"; - out_file << "\tMax Point -> " << in_rect.max() << "\n"; - - return out_file; -} - -} /* namespace NR */ /* legacy rect stuff */ - /* NULL rect is infinite */ struct NRRect { NRRect() : x0(0), y0(0), x1(0), y1(0) {} - NRRect(NR::Coord xmin, NR::Coord ymin, NR::Coord xmax, NR::Coord ymax) + NRRect(double xmin, double ymin, double xmax, double ymax) : x0(xmin), y0(ymin), x1(xmax), y1(ymax) {} - explicit NRRect(NR::Rect const &rect); - explicit NRRect(boost::optional<NR::Rect> const &rect); - operator boost::optional<NR::Rect>() const { return upgrade(); } - boost::optional<NR::Rect> upgrade() const; explicit NRRect(Geom::OptRect const &rect); operator Geom::OptRect() const { return upgrade_2geom(); } Geom::OptRect upgrade_2geom() const; - NR::Coord x0, y0, x1, y1; + double x0, y0, x1, y1; }; -#define nr_rect_d_set_empty(r) (*(r) = NR_RECT_EMPTY) -#define nr_rect_l_set_empty(r) (*(r) = NR_RECT_L_EMPTY) - -/** "Empty" here includes the case of zero width or zero height. */ -// TODO convert to static overloaded functions (pointer and ref) once performance can be tested: -#define nr_rect_d_test_empty_ptr(r) ((r) && NR_RECT_DFLS_TEST_EMPTY(r)) -#define nr_rect_d_test_empty(r) NR_RECT_DFLS_TEST_EMPTY_REF(r) - // TODO convert to static overloaded functions (pointer and ref) once performance can be tested: #define nr_rect_l_test_empty_ptr(r) ((r) && NR_RECT_DFLS_TEST_EMPTY(r)) #define nr_rect_l_test_empty(r) NR_RECT_DFLS_TEST_EMPTY_REF(r) @@ -282,7 +63,7 @@ struct NRRect { NRRectL *nr_rect_l_subtract(NRRectL *d, NRRectL const *r0, NRRectL const *r1); // returns the area of r -NR::ICoord nr_rect_l_area(NRRectL *r); +gint32 nr_rect_l_area(NRRectL *r); /* NULL values are OK for r0 and r1, but not for d */ NRRect *nr_rect_d_intersect(NRRect *d, NRRect const *r0, NRRect const *r1); @@ -291,13 +72,9 @@ NRRectL *nr_rect_l_intersect(NRRectL *d, NRRectL const *r0, NRRectL const *r1); NRRect *nr_rect_d_union(NRRect *d, NRRect const *r0, NRRect const *r1); NRRectL *nr_rect_l_union(NRRectL *d, NRRectL const *r0, NRRectL const *r1); -NRRect *nr_rect_union_pt(NRRect *dst, NR::Point const &p); -NRRect *nr_rect_d_union_xy(NRRect *d, NR::Coord x, NR::Coord y); -NRRectL *nr_rect_l_union_xy(NRRectL *d, NR::ICoord x, NR::ICoord y); - -NRRect *nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NR::Matrix const &m); -NRRect *nr_rect_d_matrix_transform(NRRect *d, NRRect const *s, NR::Matrix const *m); -NRRectL *nr_rect_l_enlarge(NRRectL *d, int amount); +NRRect *nr_rect_union_pt(NRRect *dst, Geom::Point const &p); +NRRect *nr_rect_d_union_xy(NRRect *d, double x, double y); +NRRectL *nr_rect_l_union_xy(NRRectL *d, gint32 x, gint32 y); #endif /* !LIBNR_NR_RECT_H_SEEN */ diff --git a/src/libnr/nr-render.h b/src/libnr/nr-render.h deleted file mode 100644 index 84215b7a3..000000000 --- a/src/libnr/nr-render.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __NR_RENDER_H__ -#define __NR_RENDER_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * - * This code is in public domain - */ - -#include <libnr/nr-pixblock.h> - -struct NRRenderer; - -typedef void (* NRRenderFunc) (NRRenderer *r, NRPixBlock *pb, NRPixBlock *m); - -struct NRRenderer { - NRRenderFunc render; -}; - -#define nr_render(r,pb,m) ((NRRenderer *) (r))->render ((NRRenderer *) (r), (pb), (m)) - -#endif diff --git a/src/libnr/nr-types-test.h b/src/libnr/nr-types-test.h deleted file mode 100644 index 77550351f..000000000 --- a/src/libnr/nr-types-test.h +++ /dev/null @@ -1,142 +0,0 @@ -// nr-types-test.h -#include <cxxtest/TestSuite.h> - -#include "libnr/nr-types.h" -#include "libnr/nr-point-fns.h" -#include <cmath> - -class NrTypesTest : public CxxTest::TestSuite -{ -public: - NrTypesTest() : - a( 1.5, 2.0 ), - b(-2.0, 3.0), - ab(-0.5, 5.0), - small(pow(2.0, -1070)), - small_left(-small, 0.0), - smallish_3_neg4(3.0 * small, -4.0 * small) - {} - virtual ~NrTypesTest() {} - -// createSuite and destroySuite get us per-suite setup and teardown -// without us having to worry about static initialization order, etc. - static NrTypesTest *createSuite() { return new NrTypesTest(); } - static void destroySuite( NrTypesTest *suite ) { delete suite; } - - NR::Point const a; - NR::Point const b; - NR::Point const ab; - double const small; - NR::Point const small_left; - NR::Point const smallish_3_neg4; - - - void testXYValues( void ) - { - TS_ASSERT_EQUALS( NR::X, 0 ); - TS_ASSERT_EQUALS( NR::Y, 1 ); - } - - void testXYCtorAndArrayConst(void) - { - TS_ASSERT_EQUALS( a[NR::X], 1.5 ); - TS_ASSERT_EQUALS( a[NR::Y], 2.0 ); - } - - void testCopyCtor(void) - { - NR::Point a_copy(a); - - TS_ASSERT_EQUALS( a, a_copy ); - TS_ASSERT( !(a != a_copy) ); - } - - void testNonConstArrayOperator(void) - { - NR::Point a_copy(a); - a_copy[NR::X] = -2.0; - TS_ASSERT_DIFFERS( a_copy, a ); - TS_ASSERT_DIFFERS( a_copy, b ); - a_copy[NR::Y] = 3.0; - TS_ASSERT_EQUALS( a_copy, b ); - } - - void testBinaryPlusMinus(void) - { - TS_ASSERT_DIFFERS( a, b ); - TS_ASSERT_EQUALS( a + b, ab ); - TS_ASSERT_EQUALS( ab - a, b ); - TS_ASSERT_EQUALS( ab - b, a ); - TS_ASSERT_DIFFERS( ab + a, b ); - } - - void testUnaryMinus(void) - { - TS_ASSERT_EQUALS( -a, NR::Point(-a[NR::X], -a[NR::Y]) ); - } - - void tetScaleDivide(void) - { - TS_ASSERT_EQUALS( -a, -1.0 * a ); - TS_ASSERT_EQUALS( a + a + a, 3.0 * a ); - TS_ASSERT_EQUALS( a / .5, 2.0 * a ); - } - - void testDot(void) - { - TS_ASSERT_EQUALS( dot(a, b), ( a[NR::X] * b[NR::X] + - a[NR::Y] * b[NR::Y] ) ); - TS_ASSERT_EQUALS( dot(a, NR::rot90(a)), 0.0 ); - TS_ASSERT_EQUALS( dot(-a, NR::rot90(a)), 0.0 ); - } - - void testL1L2LInftyNorms(void) - { - // TODO look at TS_ASSERT_DELTA - - TS_ASSERT_EQUALS( L1(small_left), small ); - TS_ASSERT_EQUALS( L2(small_left), small ); - TS_ASSERT_EQUALS( LInfty(small_left), small ); - - TS_ASSERT_EQUALS( L1(smallish_3_neg4), 7.0 * small ); - TS_ASSERT_EQUALS( L2(smallish_3_neg4), 5.0 * small ); - TS_ASSERT_EQUALS( LInfty(smallish_3_neg4), 4.0 * small ); - } - - void testOperatorPlusEquals(void) - { - NR::Point x(a); - x += b; - TS_ASSERT_EQUALS( x, ab ); - } - - void tetOperatorDivEquals(void) - { - NR::Point x(a); - x /= .5; - TS_ASSERT_EQUALS( x, a + a ); - } - - void testNormalize(void) - { - NR::Point x(small_left); - x.normalize(); - TS_ASSERT_EQUALS( x, NR::Point(-1.0, 0.0) ); - - x = smallish_3_neg4; - x.normalize(); - TS_ASSERT_EQUALS( x, NR::Point(0.6, -0.8) ); - } - -}; - -/* - 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/libnr/nr-types.cpp b/src/libnr/nr-types.cpp deleted file mode 100644 index 0231c91d5..000000000 --- a/src/libnr/nr-types.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/** \file - * Implements NR::Point::normalize() - */ - -#include <libnr/nr-types.h> - -#include "2geom/isnan.h" - -/** Scales this vector to make it 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 *this != Point(0, 0). - * \pre Neither coordinate is NaN. - * \post L2(*this) very near 1.0. - */ -void NR::Point::normalize() { - double len = hypot(_pt[0], _pt[1]); - g_return_if_fail(len != 0); - g_return_if_fail(!IS_NAN(len)); - static double const inf = 1e400; - if(len != inf) { - *this /= len; - } else { - unsigned n_inf_coords = 0; - /* Delay updating pt in case neither coord is infinite. */ - NR::Point tmp; - for ( unsigned i = 0 ; i < 2 ; ++i ) { - if ( _pt[i] == inf ) { - ++n_inf_coords; - tmp[i] = 1.0; - } else if ( _pt[i] == -inf ) { - ++n_inf_coords; - tmp[i] = -1.0; - } else { - tmp[i] = 0.0; - } - } - switch (n_inf_coords) { - case 0: - /* Can happen if both coords are near +/-DBL_MAX. */ - *this /= 4.0; - len = hypot(_pt[0], _pt[1]); - g_assert(len != inf); - *this /= len; - break; - - case 1: - *this = tmp; - break; - - case 2: - *this = sqrt(0.5) * tmp; - break; - } - } -} -/* - 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/libnr/nr-types.h b/src/libnr/nr-types.h deleted file mode 100644 index 685c29342..000000000 --- a/src/libnr/nr-types.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef __NR_TYPES_H__ -#define __NR_TYPES_H__ - -/* - * Pixel buffer rendering library - * - * Authors: - * Lauris Kaplinski <lauris@kaplinski.com> - * Class-ifying NRPoint, Nathan Hurst <njh@mail.csse.monash.edu.au> - * - * This code is in public domain - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <libnr/nr-coord.h> -#include <libnr/nr-dim2.h> -#include <libnr/nr-i-coord.h> -#include <libnr/nr-point.h> -#include <libnr/nr-point-l.h> -#include <libnr/nr-point-ops.h> -#include <libnr/nr-rect.h> -#include <libnr/nr-rect-l.h> -#include <libnr/nr-forward.h> - -#endif /* !__NR_TYPES_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/libnr/nr-values.cpp b/src/libnr/nr-values.cpp index 9193eff3b..06f33b13f 100644 --- a/src/libnr/nr-values.cpp +++ b/src/libnr/nr-values.cpp @@ -1,20 +1,18 @@ #define __NR_VALUES_C__ -#include <libnr/nr-rect-l.h> +#include "libnr/nr-values.h" #include "libnr/nr-rect.h" +#include "libnr/nr-rect-l.h" /* The following predefined objects are for reference and comparison. */ NRRect NR_RECT_EMPTY(NR_HUGE, NR_HUGE, -NR_HUGE, -NR_HUGE); -NRRectL NR_RECT_L_EMPTY = - {NR_HUGE_L, NR_HUGE_L, -NR_HUGE_L, -NR_HUGE_L}; -NRRectL NR_RECT_S_EMPTY = - {NR_HUGE_S, NR_HUGE_S, -NR_HUGE_S, -NR_HUGE_S}; +NRRectL NR_RECT_L_EMPTY(NR_HUGE_L, NR_HUGE_L, -NR_HUGE_L, -NR_HUGE_L); /** component_vectors[i] is like $e_i$ in common mathematical usage; or equivalently $I_i$ (where $I$ is the identity matrix). */ -NR::Point const component_vectors[] = {NR::Point(1., 0.), - NR::Point(0., 1.)}; +Geom::Point const component_vectors[] = {Geom::Point(1., 0.), + Geom::Point(0., 1.)}; diff --git a/src/libnr/nr-values.h b/src/libnr/nr-values.h index f85fca690..07faec9fa 100644 --- a/src/libnr/nr-values.h +++ b/src/libnr/nr-values.h @@ -11,12 +11,12 @@ */ #include <libnr/nr-forward.h> +#include <2geom/point.h> #define NR_EPSILON 1e-18 #define NR_HUGE 1e18 #define NR_HUGE_L (0x7fffffff) -#define NR_HUGE_S (0x7fff) /* The following predefined objects are for reference @@ -24,11 +24,10 @@ and comparison. They are defined in nr-values.cpp */ extern NRRect NR_RECT_EMPTY; extern NRRectL NR_RECT_L_EMPTY; -extern NRRectL NR_RECT_S_EMPTY; /** component_vectors[i] has 1.0 at position i, and 0.0 elsewhere (i.e. in the other position). */ -extern NR::Point const component_vectors[2]; +extern Geom::Point const component_vectors[2]; #endif diff --git a/src/libnr/nr_config.h.mingw b/src/libnr/nr_config.h.mingw deleted file mode 100644 index 6992cc6fc..000000000 --- a/src/libnr/nr_config.h.mingw +++ /dev/null @@ -1,12 +0,0 @@ -#define NR_SIZEOF_CHAR 1 -#define NR_SIZEOF_SHORT 2 -#define NR_SIZEOF_INT 4 -#define NR_SIZEOF_LONG 4 - -typedef signed char NRByte; -typedef unsigned char NRUByte; -typedef signed short NRShort; -typedef unsigned short NRUShort; -typedef signed int NRLong; -typedef unsigned long NRULong; - diff --git a/src/libnr/nr_config.h.win32 b/src/libnr/nr_config.h.win32 deleted file mode 100644 index e0bfbda3f..000000000 --- a/src/libnr/nr_config.h.win32 +++ /dev/null @@ -1,14 +0,0 @@ -#define NR_SIZEOF_CHAR 1 -#define NR_SIZEOF_SHORT 2 -#define NR_SIZEOF_INT 4 -#define NR_SIZEOF_LONG 4 - -typedef signed char NRByte; -typedef unsigned char NRUByte; -typedef signed short NRShort; -typedef unsigned short NRUShort; -typedef signed int NRLong; -typedef unsigned long NRULong; - - - diff --git a/src/libvpsc/generate-constraints.cpp b/src/libvpsc/generate-constraints.cpp index c57966e26..0c35ab51c 100644 --- a/src/libvpsc/generate-constraints.cpp +++ b/src/libvpsc/generate-constraints.cpp @@ -16,7 +16,7 @@ #include "generate-constraints.h" #include "constraint.h" -#include "2geom/isnan.h" /* Include last */ +#include <2geom/math-utils.h> using std::set; using std::vector; diff --git a/src/livarot/Path.h b/src/livarot/Path.h index b8041c63a..78e90c34f 100644 --- a/src/livarot/Path.h +++ b/src/livarot/Path.h @@ -12,9 +12,8 @@ #include <vector> #include "LivarotDefs.h" #include "livarot/livarot-forward.h" -#include "libnr/nr-point.h" #include <libnr/nr-rect-l.h> -#include <2geom/forward.h> +#include <2geom/point.h> struct SPStyle; diff --git a/src/livarot/PathSimplify.cpp b/src/livarot/PathSimplify.cpp index fb2aa55e2..fe1981e4d 100644 --- a/src/livarot/PathSimplify.cpp +++ b/src/livarot/PathSimplify.cpp @@ -7,6 +7,7 @@ */ #include <glib/gmem.h> +#include <2geom/affine.h> #include "livarot/Path.h" #include "livarot/path-description.h" diff --git a/src/livarot/Shape.cpp b/src/livarot/Shape.cpp index 9107844be..d24e4b99d 100644 --- a/src/livarot/Shape.cpp +++ b/src/livarot/Shape.cpp @@ -2225,7 +2225,7 @@ double distance(Shape const *s, Geom::Point const &p) if ( el > 0.001 ) { double const npr = Geom::dot(d, e); if ( npr > 0 && npr < el ) { - double const nl = fabs( NR::cross(d, e) ); + double const nl = fabs( Geom::cross(d, e) ); double ndot = nl * nl / el; if ( ndot < bdot ) { bdot = ndot; @@ -2271,7 +2271,7 @@ bool distanceLessThanOrEqual(Shape const *s, Geom::Point const &p, double const double const max_l1 = max_l2 * M_SQRT2; for (int i = 0; i < s->numberOfPoints(); i++) { Geom::Point const offset( p - s->getPoint(i).x ); - double const l1 = NR::L1(offset); + double const l1 = Geom::L1(offset); if ( (l1 <= max_l2) || ((l1 <= max_l1) && (Geom::L2(offset) <= max_l2)) ) { return true; } @@ -2288,7 +2288,7 @@ bool distanceLessThanOrEqual(Shape const *s, Geom::Point const &p, double const Geom::Point const e_unit(e / el); double const npr = Geom::dot(d, e_unit); if ( npr > 0 && npr < el ) { - double const nl = fabs(NR::cross(d, e_unit)); + double const nl = fabs(Geom::cross(d, e_unit)); if ( nl <= max_l2 ) { return true; } diff --git a/src/livarot/Shape.h b/src/livarot/Shape.h index 5649ff9e4..158977897 100644 --- a/src/livarot/Shape.h +++ b/src/livarot/Shape.h @@ -14,8 +14,8 @@ #include <cstdlib> #include <cstring> #include <vector> +#include <2geom/point.h> -#include "libnr/nr-point.h" #include "livarot/livarot-forward.h" #include "livarot/LivarotDefs.h" diff --git a/src/livarot/path-description.h b/src/livarot/path-description.h index 1d0dfb57e..e9818b55b 100644 --- a/src/livarot/path-description.h +++ b/src/livarot/path-description.h @@ -1,8 +1,8 @@ #ifndef SEEN_INKSCAPE_LIVAROT_PATH_DESCRIPTION_H #define SEEN_INKSCAPE_LIVAROT_PATH_DESCRIPTION_H +#include <2geom/point.h> #include "svg/stringstream.h" -#include "libnr/nr-point.h" // path description commands /* FIXME: these should be unnecessary once the refactoring of the path diff --git a/src/livarot/sweep-event.h b/src/livarot/sweep-event.h index dab006101..5df952731 100644 --- a/src/livarot/sweep-event.h +++ b/src/livarot/sweep-event.h @@ -4,7 +4,7 @@ * Intersection events. */ -#include <libnr/nr-point.h> +#include <2geom/point.h> class SweepTree; diff --git a/src/livarot/sweep-tree.h b/src/livarot/sweep-tree.h index 4a2efe5ec..bbb027b24 100644 --- a/src/livarot/sweep-tree.h +++ b/src/livarot/sweep-tree.h @@ -1,8 +1,8 @@ #ifndef INKSCAPE_LIVAROT_SWEEP_TREE_H #define INKSCAPE_LIVAROT_SWEEP_TREE_H -#include "libnr/nr-point.h" #include "livarot/AVL.h" +#include <2geom/point.h> class Shape; class SweepEvent; diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp index 54554ebb2..22974fe13 100644 --- a/src/live_effects/lpe-spiro.cpp +++ b/src/live_effects/lpe-spiro.cpp @@ -12,7 +12,6 @@ #include <2geom/affine.h> #include <2geom/bezier-curve.h> #include <2geom/hvlinesegment.h> -#include <2geom/isnan.h> #include "helper/geom-nodetype.h" #include "helper/geom-curves.h" diff --git a/src/marker.cpp b/src/marker.cpp index e82d3d952..2354d686c 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -19,6 +19,7 @@ #include "libnr/nr-convert2geom.h" #include <2geom/affine.h> +#include <2geom/transforms.h> #include "svg/svg.h" #include "display/nr-arena-group.h" #include "xml/repr.h" diff --git a/src/object-edit.cpp b/src/object-edit.cpp index 553c125a3..28c8d44db 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -35,7 +35,7 @@ #include <glibmm/i18n.h> #include "object-edit.h" #include "xml/repr.h" -#include "2geom/isnan.h" +#include <2geom/math-utils.h> #define sp_round(v,m) (((v) < 0.0) ? ((ceil((v) / (m) - 0.5)) * (m)) : ((floor((v) / (m) + 0.5)) * (m))) @@ -959,7 +959,7 @@ StarKnotHolderEntity1::knot_set(Geom::Point const &p, Geom::Point const &/*origi Geom::Point const s = snap_knot_position(p); - Geom::Point d = s - to_2geom(star->center); + Geom::Point d = s - star->center; double arg1 = atan2(d); double darg1 = arg1 - star->arg[0]; @@ -986,7 +986,7 @@ StarKnotHolderEntity2::knot_set(Geom::Point const &p, Geom::Point const &/*origi Geom::Point const s = snap_knot_position(p); if (star->flatsided == false) { - Geom::Point d = s - to_2geom(star->center); + Geom::Point d = s - star->center; double arg1 = atan2(d); double darg1 = arg1 - star->arg[1]; diff --git a/src/pen-context.cpp b/src/pen-context.cpp index 64137d56f..19e0351a3 100644 --- a/src/pen-context.cpp +++ b/src/pen-context.cpp @@ -38,7 +38,6 @@ #include "display/sp-ctrlline.h" #include "display/sodipodi-ctrl.h" #include <glibmm/i18n.h> -#include "libnr/nr-point-ops.h" #include "helper/units.h" #include "macros.h" #include "context-fns.h" @@ -913,7 +912,7 @@ pen_redraw_all (SPPenContext *const pc) if (last_seg) { Geom::CubicBezier const * cubic = dynamic_cast<Geom::CubicBezier const *>( last_seg ); if ( cubic && - (*cubic)[2] != to_2geom(pc->p[0]) ) + (*cubic)[2] != pc->p[0] ) { Geom::Point p2 = (*cubic)[2]; SP_CTRL(pc->c0)->moveto(p2); diff --git a/src/pencil-context.cpp b/src/pencil-context.cpp index a873eb6fc..57205a436 100644 --- a/src/pencil-context.cpp +++ b/src/pencil-context.cpp @@ -57,10 +57,10 @@ static gint pencil_handle_button_release(SPPencilContext *const pc, GdkEventButt static gint pencil_handle_key_press(SPPencilContext *const pc, guint const keyval, guint const state); static gint pencil_handle_key_release(SPPencilContext *const pc, guint const keyval, guint const state); -static void spdc_set_startpoint(SPPencilContext *pc, Geom::Point const p); -static void spdc_set_endpoint(SPPencilContext *pc, Geom::Point const p); +static void spdc_set_startpoint(SPPencilContext *pc, Geom::Point const &p); +static void spdc_set_endpoint(SPPencilContext *pc, Geom::Point const &p); static void spdc_finish_endpoint(SPPencilContext *pc); -static void spdc_add_freehand_point(SPPencilContext *pc, Geom::Point p, guint state); +static void spdc_add_freehand_point(SPPencilContext *pc, Geom::Point const &p, guint state); static void fit_and_split(SPPencilContext *pc); static void interpolate(SPPencilContext *pc); static void sketch_interpolate(SPPencilContext *pc); @@ -644,7 +644,7 @@ pencil_handle_key_release(SPPencilContext *const pc, guint const keyval, guint c * Reset points and set new starting point. */ static void -spdc_set_startpoint(SPPencilContext *const pc, Geom::Point const p) +spdc_set_startpoint(SPPencilContext *const pc, Geom::Point const &p) { pc->npoints = 0; pc->red_curve_is_valid = false; @@ -664,7 +664,7 @@ spdc_set_startpoint(SPPencilContext *const pc, Geom::Point const p) * We change RED curve. */ static void -spdc_set_endpoint(SPPencilContext *const pc, Geom::Point const p) +spdc_set_endpoint(SPPencilContext *const pc, Geom::Point const &p) { if (pc->npoints == 0) { return; @@ -716,7 +716,7 @@ spdc_finish_endpoint(SPPencilContext *const pc) static void -spdc_add_freehand_point(SPPencilContext *pc, Geom::Point p, guint /*state*/) +spdc_add_freehand_point(SPPencilContext *pc, Geom::Point const &p, guint /*state*/) { g_assert( pc->npoints > 0 ); g_return_if_fail(unsigned(pc->npoints) < G_N_ELEMENTS(pc->p)); diff --git a/src/rect-context.cpp b/src/rect-context.cpp index 7f32e09fa..188b5a9a3 100644 --- a/src/rect-context.cpp +++ b/src/rect-context.cpp @@ -281,14 +281,14 @@ static gint sp_rect_context_root_handler(SPEventContext *event_context, GdkEvent /* Position center */ Geom::Point button_dt(desktop->w2d(button_w)); - rc->center = from_2geom(button_dt); + rc->center = button_dt; /* Snap center */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop); m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - rc->center = from_2geom(button_dt); + rc->center = button_dt; sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | diff --git a/src/rect-context.h b/src/rect-context.h index e5d160788..b6fbb6854 100644 --- a/src/rect-context.h +++ b/src/rect-context.h @@ -16,8 +16,8 @@ #include <stddef.h> #include <sigc++/sigc++.h> +#include <2geom/point.h> #include "event-context.h" -#include "libnr/nr-point.h" #define SP_TYPE_RECT_CONTEXT (sp_rect_context_get_type ()) #define SP_RECT_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_RECT_CONTEXT, SPRectContext)) diff --git a/src/removeoverlap.cpp b/src/removeoverlap.cpp index b01ae5228..a503fea35 100644 --- a/src/removeoverlap.cpp +++ b/src/removeoverlap.cpp @@ -10,12 +10,13 @@ * * Released under GNU LGPL. Read the file 'COPYING' for more information. */ +#include <utility> +#include <2geom/transforms.h> #include "util/glib-list-iterators.h" #include "sp-item.h" #include "sp-item-transform.h" #include "libvpsc/generate-constraints.h" #include "libvpsc/remove_rectangle_overlap.h" -#include <utility> using vpsc::Rectangle; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 6f385b8f5..9b88077e7 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -777,7 +777,7 @@ enclose_items(GSList const *items) Geom::OptRect r; for (GSList const *i = items; i; i = i->next) { - r = Geom::unify(r, ((SPItem *) i->data)->getBboxDesktop()); + r.unionWith(((SPItem *) i->data)->getBboxDesktop()); } return r; } diff --git a/src/selection.cpp b/src/selection.cpp index 7564fad3a..3007a3d1f 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -375,7 +375,7 @@ Geom::OptRect Selection::bounds(SPItem::BBoxType type) const Geom::OptRect bbox; for ( GSList const *i = items ; i != NULL ; i = i->next ) { - bbox = unify(bbox, SP_ITEM(i->data)->getBboxDesktop(type)); + bbox.unionWith(SP_ITEM(i->data)->getBboxDesktop(type)); } return bbox; } @@ -403,7 +403,7 @@ NRRect *Selection::boundsInDocument(NRRect *bbox, SPItem::BBoxType type) const { Geom::OptRect Selection::boundsInDocument(SPItem::BBoxType type) const { NRRect r; - return to_2geom(boundsInDocument(&r, type)->upgrade()); + return to_2geom(boundsInDocument(&r, type)); } /** Extract the position of the center from the first selected object */ diff --git a/src/snap.cpp b/src/snap.cpp index bf1613d2c..3e79a221e 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -19,6 +19,7 @@ */ #include <utility> +#include <2geom/transforms.h> #include "sp-namedview.h" #include "snap.h" @@ -293,7 +294,7 @@ Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t, Geom::Point c // use getSnapDistance() instead of getWeightedDistance() here because the pointer's position // doesn't tell us anything about which node to snap success = true; - nearest_multiple = s.getPoint() - to_2geom(grid->origin); + nearest_multiple = s.getPoint() - grid->origin; nearest_distance = s.getSnapDistance(); bestSnappedPoint = s; } diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 147ece167..48e466628 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -89,6 +89,7 @@ void SPClipPath::build(SPObject *object, SPDocument *document, Inkscape::XML::No if (((SPObjectClass *) SPClipPathClass::static_parent_class)->build) ((SPObjectClass *) SPClipPathClass::static_parent_class)->build(object, document, repr); + object->readAttr( "style" ); object->readAttr( "clipPathUnits" ); /* Register ourselves */ @@ -132,8 +133,13 @@ void SPClipPath::set(SPObject *object, unsigned int key, gchar const *value) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; default: - if (((SPObjectClass *) SPClipPathClass::static_parent_class)->set) { - ((SPObjectClass *) SPClipPathClass::static_parent_class)->set(object, key, value); + if (SP_ATTRIBUTE_IS_CSS(key)) { + sp_style_read_from_object(object->style, object); + object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG); + } else { + if (((SPObjectClass *) SPClipPathClass::static_parent_class)->set) { + ((SPObjectClass *) SPClipPathClass::static_parent_class)->set(object, key, value); + } } break; } @@ -258,6 +264,7 @@ NRArenaItem *SPClipPath::show(NRArena *arena, unsigned int key) t[5] = display->bbox.y0; nr_arena_group_set_child_transform(NR_ARENA_GROUP(ai), &t); } + nr_arena_group_set_style(NR_ARENA_GROUP(ai), this->style); return ai; } diff --git a/src/sp-conn-end-pair.h b/src/sp-conn-end-pair.h index 6e62b9839..98096a246 100644 --- a/src/sp-conn-end-pair.h +++ b/src/sp-conn-end-pair.h @@ -14,7 +14,6 @@ #include <glib/gtypes.h> #include "forward.h" -#include "libnr/nr-point.h" #include <stddef.h> #include <sigc++/connection.h> #include <sigc++/functors/slot.h> diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index 3413999a9..ab545919f 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -361,7 +361,10 @@ sp_flowtext_print(SPItem *item, SPPrintContext *ctx) if (!bbox_maybe) { return; } - bbox = NRRect(from_2geom(*bbox_maybe)); + bbox.x0 = bbox_maybe->min()[Geom::X]; + bbox.y0 = bbox_maybe->min()[Geom::Y]; + bbox.x1 = bbox_maybe->max()[Geom::X]; + bbox.y1 = bbox_maybe->max()[Geom::Y]; NRRect dbox; dbox.x0 = 0.0; diff --git a/src/sp-image.cpp b/src/sp-image.cpp index ee70d2ca7..791e88b39 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -25,6 +25,7 @@ #include <string> #include <glib/gstdio.h> #include <2geom/rect.h> +#include <2geom/transforms.h> #include <glibmm/i18n.h> #include "display/nr-arena-image.h" @@ -1498,7 +1499,7 @@ static void sp_image_set_curve( SPImage *image ) } else { NRRect rect; sp_image_bbox(image, &rect, Geom::identity(), 0); - Geom::Rect rect2 = to_2geom(*rect.upgrade()); + Geom::Rect rect2 = *to_2geom(&rect); SPCurve *c = SPCurve::new_from_rect(rect2, true); if (image->curve) { diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 7e5f5f96a..8e1a4d92c 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -299,7 +299,7 @@ Geom::Point SPItem::getCenter() const { Geom::OptRect bbox = getBounds(i2d_affine()); if (bbox) { - return to_2geom(bbox->midpoint()) + Geom::Point (transform_center_x, transform_center_y); + return bbox->midpoint() + Geom::Point (transform_center_x, transform_center_y); } else { return Geom::Point(0, 0); // something's wrong! } @@ -825,7 +825,7 @@ void SPItem::invoke_bbox_full( Geom::OptRect &bbox, Geom::Affine const &transfor // would therefore be translated into empty Geom::OptRect() (see bug https://bugs.launchpad.net/inkscape/+bug/168684) Geom::OptRect temp_bbox_new = Geom::Rect(Geom::Point(temp_bbox.x0, temp_bbox.y0), Geom::Point(temp_bbox.x1, temp_bbox.y1)); - bbox = Geom::unify(bbox, temp_bbox_new); + bbox.unionWith(temp_bbox_new); } // DEPRECATED to phase out the use of NRRect in favor of Geom::OptRect diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index 76efb6b4b..38599188f 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -13,10 +13,11 @@ #include <cstring> #include <string> +#include <2geom/transforms.h> #include "display/nr-arena.h" #include "display/nr-arena-group.h" -#include <xml/repr.h> +#include "xml/repr.h" #include "enums.h" #include "attributes.h" diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 97fd97570..ac2d7dc1b 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -17,6 +17,7 @@ #include "config.h" #include <cstring> #include <string> +#include <2geom/transforms.h> #include "display/canvas-grid.h" #include "display/guideline.h" @@ -1107,8 +1108,7 @@ void SPNamedView::translateGuides(Geom::Translate const &tr) { for (GSList *l = guides; l != NULL; l = l->next) { SPGuide &guide = *SP_GUIDE(l->data); Geom::Point point_on_line = guide.point_on_line; - point_on_line[0] += tr[0]; - point_on_line[1] += tr[1]; + point_on_line *= tr; sp_guide_moveto(guide, point_on_line, true); } } diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 460421492..0dd65c7b9 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -844,7 +844,7 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) { // we have a new minimum distance // now we need to wheck if px is inside or outside (for the sign) - nx = px - to_2geom(theRes->getPoint(i).x); + nx = px - theRes->getPoint(i).x; double nlen = sqrt (dot(nx , nx)); nx /= nlen; int pb, cb, fb; diff --git a/src/sp-root.cpp b/src/sp-root.cpp index b1eef65d2..7d72b7695 100644 --- a/src/sp-root.cpp +++ b/src/sp-root.cpp @@ -19,6 +19,7 @@ #include <cstring> #include <string> +#include <2geom/transforms.h> #include "svg/svg.h" #include "display/nr-arena-group.h" diff --git a/src/sp-text.h b/src/sp-text.h index c98721ec9..cd103aa2a 100644 --- a/src/sp-text.h +++ b/src/sp-text.h @@ -19,7 +19,6 @@ #include "sp-item.h" #include "sp-string.h" #include "text-tag-attributes.h" -#include "libnr/nr-point.h" #include "libnrtype/Layout-TNG.h" diff --git a/src/spiral-context.cpp b/src/spiral-context.cpp index cbe7166c5..93ff48c3e 100644 --- a/src/spiral-context.cpp +++ b/src/spiral-context.cpp @@ -53,7 +53,7 @@ static void sp_spiral_context_set(SPEventContext *ec, Inkscape::Preferences::Ent static gint sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event); -static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point p, guint state); +static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point const &p, guint state); static void sp_spiral_finish(SPSpiralContext *sc); static void sp_spiral_cancel(SPSpiralContext *sc); @@ -275,7 +275,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.setup(desktop, true, sc->item); m.freeSnapReturnByRef(motion_dt, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); - sp_spiral_drag(sc, from_2geom(motion_dt), event->motion.state); + sp_spiral_drag(sc, motion_dt, event->motion.state); gobble_motion_events(GDK_BUTTON1_MASK); @@ -399,7 +399,7 @@ sp_spiral_context_root_handler(SPEventContext *event_context, GdkEvent *event) return ret; } -static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point p, guint state) +static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point const &p, guint state) { SPDesktop *desktop = SP_EVENT_CONTEXT(sc)->desktop; @@ -430,7 +430,7 @@ static void sp_spiral_drag(SPSpiralContext *sc, Geom::Point p, guint state) SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, sc->item); - Geom::Point pt2g = to_2geom(p); + Geom::Point pt2g = p; m.freeSnapReturnByRef(pt2g, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); Geom::Point const p0 = desktop->dt2doc(sc->center); diff --git a/src/spiral-context.h b/src/spiral-context.h index dd447dbfe..12c0b5d68 100644 --- a/src/spiral-context.h +++ b/src/spiral-context.h @@ -18,8 +18,8 @@ #include <gtk/gtk.h> #include <stddef.h> #include <sigc++/sigc++.h> +#include <2geom/point.h> #include "event-context.h" -#include "libnr/nr-point.h" #define SP_TYPE_SPIRAL_CONTEXT (sp_spiral_context_get_type ()) #define SP_SPIRAL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_SPIRAL_CONTEXT, SPSpiralContext)) diff --git a/src/spray-context.cpp b/src/spray-context.cpp index be0cb627f..b2d99a696 100644 --- a/src/spray-context.cpp +++ b/src/spray-context.cpp @@ -56,7 +56,6 @@ #include "display/canvas-arena.h" #include "display/curve.h" #include "livarot/Shape.h" -#include <2geom/isnan.h> #include <2geom/transforms.h> #include "preferences.h" #include "style.h" diff --git a/src/spray-context.h b/src/spray-context.h index 247c07130..f3564ac67 100644 --- a/src/spray-context.h +++ b/src/spray-context.h @@ -18,8 +18,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <2geom/point.h> #include "event-context.h" -#include <libnr/nr-point.h> //#include "ui/widget/spray-option.h" #include "ui/dialog/dialog.h" diff --git a/src/star-context.cpp b/src/star-context.cpp index 17a8e915f..878ecfbe7 100644 --- a/src/star-context.cpp +++ b/src/star-context.cpp @@ -225,9 +225,9 @@ sp_star_context_set (SPEventContext *ec, Inkscape::Preferences::Entry *val) Glib::ustring path = val->getEntryName(); if (path == "magnitude") { - sc->magnitude = NR_CLAMP(val->getInt(5), 3, 1024); + sc->magnitude = CLAMP(val->getInt(5), 3, 1024); } else if (path == "proportion") { - sc->proportion = NR_CLAMP(val->getDouble(0.5), 0.01, 2.0); + sc->proportion = CLAMP(val->getDouble(0.5), 0.01, 2.0); } else if (path == "isflatsided") { sc->isflatsided = val->getBool(); } else if (path == "rounded") { @@ -446,7 +446,7 @@ static void sp_star_drag(SPStarContext *sc, Geom::Point p, guint state) /* Snap corner point with no constraints */ SnapManager &m = desktop->namedview->snap_manager; m.setup(desktop, true, sc->item); - Geom::Point pt2g = to_2geom(p); + Geom::Point pt2g = p; m.freeSnapReturnByRef(pt2g, Inkscape::SNAPSOURCE_NODE_HANDLE); m.unSetup(); Geom::Point const p0 = desktop->dt2doc(sc->center); diff --git a/src/star-context.h b/src/star-context.h index d9ab8ce8f..7bcb26c41 100644 --- a/src/star-context.h +++ b/src/star-context.h @@ -16,8 +16,8 @@ #include <stddef.h> #include <sigc++/sigc++.h> +#include <2geom/point.h> #include "event-context.h" -#include "libnr/nr-point.h" #define SP_TYPE_STAR_CONTEXT (sp_star_context_get_type ()) #define SP_STAR_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_STAR_CONTEXT, SPStarContext)) diff --git a/src/style.cpp b/src/style.cpp index 303b347c4..44d2b0761 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -43,7 +43,6 @@ #include "xml/repr.h" #include "xml/simple-document.h" #include "unit-constants.h" -#include "2geom/isnan.h" #include "macros.h" #include "preferences.h" @@ -337,6 +336,12 @@ static SPStyleEnum const enum_enable_background[] = { {NULL, -1} }; +static SPStyleEnum const enum_clip_rule[] = { + {"nonzero", SP_WIND_RULE_NONZERO}, + {"evenodd", SP_WIND_RULE_EVENODD}, + {NULL, -1} +}; + /** * Release callback. */ @@ -769,6 +774,9 @@ sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr) SPS_READ_PENUM_IF_UNSET(&style->enable_background, repr, "enable-background", enum_enable_background, true); + /* clip-rule */ + SPS_READ_PENUM_IF_UNSET(&style->clip_rule, repr, "clip-rule", enum_clip_rule, true); + /* 3. Merge from parent */ if (object) { if (object->parent) { @@ -1151,7 +1159,9 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val) style->object->getRepr()->setAttribute("clip-path", val); break; case SP_PROP_CLIP_RULE: - g_warning("Unimplemented style property SP_PROP_CLIP_RULE: value: %s", val); + if (!style->clip_rule.set) { + sp_style_read_ienum(&style->clip_rule, val, enum_clip_rule, true); + } break; case SP_PROP_MASK: /** \todo @@ -1790,6 +1800,11 @@ sp_style_merge_from_parent(SPStyle *const style, SPStyle const *const parent) if(style->enable_background.inherit) { style->enable_background.value = parent->enable_background.value; } + + /* Clipping */ + if (!style->clip_rule.set || style->clip_rule.inherit) { + style->clip_rule.computed = parent->clip_rule.computed; + } } template <typename T> @@ -2079,7 +2094,7 @@ sp_style_merge_from_dying_parent(SPStyle *const style, SPStyle const *const pare /* Enum values that don't have any relative settings (other than `inherit'). */ { SPIEnum SPStyle::*const fields[] = { - //nyi: SPStyle::clip_rule, + &SPStyle::clip_rule, //nyi: SPStyle::color_interpolation, //nyi: SPStyle::color_interpolation_filters, //nyi: SPStyle::color_rendering, @@ -2619,6 +2634,9 @@ sp_style_write_string(SPStyle const *const style, guint const flags) p += sp_style_write_ienum(p, c + BMAX - p, "enable-background", enum_enable_background, &style->enable_background, NULL, flags); + /* clipping */ + p += sp_style_write_ienum(p, c + BMAX - p, "clip-rule", enum_clip_rule, &style->clip_rule, NULL, flags); + /* fixme: */ p += sp_text_style_write(p, c + BMAX - p, style->text, flags); @@ -2765,6 +2783,8 @@ sp_style_write_difference(SPStyle const *const from, SPStyle const *const to) p += sp_text_style_write(p, c + BMAX - p, from->text, SP_STYLE_FLAG_IFDIFF); + p += sp_style_write_ienum(p, c + BMAX - p, "clip-rule", enum_clip_rule, &from->clip_rule, &to->clip_rule, SP_STYLE_FLAG_IFDIFF); + /** \todo * The reason we use IFSET rather than IFDIFF is the belief that the IFDIFF * flag is mainly only for attributes that don't handle explicit unset well. @@ -2956,6 +2976,8 @@ sp_style_clear(SPStyle *style) style->enable_background.value = SP_CSS_BACKGROUND_ACCUMULATE; style->enable_background.set = false; style->enable_background.inherit = false; + + style->clip_rule.value = style->clip_rule.computed = SP_WIND_RULE_NONZERO; } @@ -4328,6 +4350,9 @@ sp_style_unset_property_attrs(SPObject *o) if (style->enable_background.set) { repr->setAttribute("enable-background", NULL); } + if (style->clip_rule.set) { + repr->setAttribute("clip-rule", NULL); + } } /** diff --git a/src/style.h b/src/style.h index d82a0dd5e..b8b3d6c0d 100644 --- a/src/style.h +++ b/src/style.h @@ -330,9 +330,11 @@ struct SPStyle { unsigned cursor_set : 1; unsigned overflow_set : 1; unsigned clip_path_set : 1; - unsigned clip_rule_set : 1; unsigned mask_set : 1; + /** clip-rule: 0 nonzero, 1 evenodd */ + SPIEnum clip_rule; + /** display */ SPIEnum display; diff --git a/src/svg-view.cpp b/src/svg-view.cpp index 5deff7421..03056de2e 100644 --- a/src/svg-view.cpp +++ b/src/svg-view.cpp @@ -13,6 +13,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include <2geom/transforms.h> #include "display/canvas-arena.h" #include "document.h" #include "sp-item.h" diff --git a/src/tweak-context.cpp b/src/tweak-context.cpp index b4f13d16f..974197786 100644 --- a/src/tweak-context.cpp +++ b/src/tweak-context.cpp @@ -63,7 +63,6 @@ #include "display/canvas-arena.h" #include "display/curve.h" #include "livarot/Shape.h" -#include <2geom/isnan.h> #include <2geom/transforms.h> #include "preferences.h" #include "style.h" diff --git a/src/tweak-context.h b/src/tweak-context.h index f7f1fcf7d..cb1cf301b 100644 --- a/src/tweak-context.h +++ b/src/tweak-context.h @@ -13,7 +13,7 @@ */ #include "event-context.h" -#include <libnr/nr-point.h> +#include <2geom/point.h> #define SP_TYPE_TWEAK_CONTEXT (sp_tweak_context_get_type()) #define SP_TWEAK_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_TWEAK_CONTEXT, SPTweakContext)) diff --git a/src/ui/cache/svg_preview_cache.cpp b/src/ui/cache/svg_preview_cache.cpp index edd7c9431..cd1d65ba7 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -21,6 +21,7 @@ #include <glib/gmem.h> #include <gtk/gtk.h> +#include <2geom/transforms.h> #include "sp-namedview.h" #include "selection.h" #include "inkscape.h" diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index a2169c0b3..f7cb06263 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -20,8 +20,8 @@ # include <config.h> #endif +#include <2geom/transforms.h> #include "ui/widget/spinbutton.h" - #include "desktop-handles.h" #include "unclump.h" #include "document.h" @@ -357,7 +357,7 @@ private : it < sorted.end(); it ++ ) { - if (!NR_DF_TEST_CLOSE (pos, it->bbox.min()[_orientation], 1e-6)) { + if (!Geom::are_near(pos, it->bbox.min()[_orientation], 1e-6)) { Geom::Point t(0.0, 0.0); t[_orientation] = pos - it->bbox.min()[_orientation]; sp_item_move_rel(it->item, Geom::Translate(t)); @@ -380,7 +380,7 @@ private : //new anchor position float pos = sorted.front().anchor + i * step; //Don't move if we are really close - if (!NR_DF_TEST_CLOSE (pos, it.anchor, 1e-6)) { + if (!Geom::are_near(pos, it.anchor, 1e-6)) { //Compute translation Geom::Point t(0.0, 0.0); t[_orientation] = pos - it.anchor; diff --git a/src/ui/dialog/align-and-distribute.h b/src/ui/dialog/align-and-distribute.h index 7c99d67c7..99b96463c 100644 --- a/src/ui/dialog/align-and-distribute.h +++ b/src/ui/dialog/align-and-distribute.h @@ -25,7 +25,6 @@ #include <gtkmm/table.h> #include <gtkmm/buttonbox.h> #include <gtkmm/label.h> -#include "libnr/nr-dim2.h" #include "libnr/nr-rect.h" diff --git a/src/ui/dialog/tile.cpp b/src/ui/dialog/tile.cpp index ae17214bf..7c7413ce5 100644 --- a/src/ui/dialog/tile.cpp +++ b/src/ui/dialog/tile.cpp @@ -21,6 +21,7 @@ #include <gtk/gtk.h> //for GTK_RESPONSE* types #include <glibmm/i18n.h> #include <gtkmm/stock.h> +#include <2geom/transforms.h> #include "verbs.h" #include "preferences.h" diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 901d02240..92c8bd349 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -16,6 +16,7 @@ #include <gtkmm/stock.h> #include <gtkmm/dialog.h> +#include <2geom/transforms.h> #include "document.h" #include "desktop-handles.h" diff --git a/src/ui/view/edit-widget-interface.h b/src/ui/view/edit-widget-interface.h index 4ff4f92f9..577beb5ce 100644 --- a/src/ui/view/edit-widget-interface.h +++ b/src/ui/view/edit-widget-interface.h @@ -16,9 +16,9 @@ #ifndef INKSCAPE_UI_VIEW_EDIT_WIDGET_IFACE_H #define INKSCAPE_UI_VIEW_EDIT_WIDGET_IFACE_H -#include "libnr/nr-point.h" #include "message.h" #include <gtkmm/window.h> +#include <2geom/point.h> namespace Inkscape { namespace UI { namespace Widget { class Dock; } } } diff --git a/src/ui/view/view.cpp b/src/ui/view/view.cpp index f05e024d1..dc6307ab0 100644 --- a/src/ui/view/view.cpp +++ b/src/ui/view/view.cpp @@ -16,7 +16,7 @@ # include "config.h" #endif -#include "libnr/nr-point.h" +#include <2geom/point.h> #include "document.h" #include "view.h" #include "message-stack.h" diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp index 5d71a4b38..f7759f103 100644 --- a/src/ui/widget/page-sizer.cpp +++ b/src/ui/widget/page-sizer.cpp @@ -24,6 +24,7 @@ #include <string> #include <string.h> #include <vector> +#include <2geom/transforms.h> #include "desktop-handles.h" #include "document.h" diff --git a/src/ui/widget/rotateable.cpp b/src/ui/widget/rotateable.cpp index 396280aee..23d5363ef 100644 --- a/src/ui/widget/rotateable.cpp +++ b/src/ui/widget/rotateable.cpp @@ -9,13 +9,12 @@ * Released under GNU GPL. Read the file 'COPYING' for more information. */ -#include "event-context.h" -#include "rotateable.h" -#include "libnr/nr-point.h" -#include "libnr/nr-point-fns.h" #include <gtkmm/box.h> #include <gtkmm/eventbox.h> #include <glibmm/i18n.h> +#include <2geom/point.h> +#include "event-context.h" +#include "rotateable.h" namespace Inkscape { namespace UI { diff --git a/src/ui/widget/ruler.h b/src/ui/widget/ruler.h index c315418d8..afe3a4ba7 100644 --- a/src/ui/widget/ruler.h +++ b/src/ui/widget/ruler.h @@ -13,7 +13,7 @@ */ #include <gtkmm/eventbox.h> -#include "libnr/nr-point.h" +#include <2geom/point.h> struct SPCanvasItem; struct SPDesktop; diff --git a/src/unclump.cpp b/src/unclump.cpp index d027a6986..baeeaff76 100644 --- a/src/unclump.cpp +++ b/src/unclump.cpp @@ -12,6 +12,7 @@ #include <algorithm> #include <map> +#include <2geom/transforms.h> #include "sp-item.h" diff --git a/src/widgets/dash-selector.cpp b/src/widgets/dash-selector.cpp index dead653de..3339c64d3 100644 --- a/src/widgets/dash-selector.cpp +++ b/src/widgets/dash-selector.cpp @@ -22,9 +22,9 @@ #include <cstring> #include <string> -#include <libnr/nr-macros.h> #include <gtk/gtk.h> #include <glibmm/i18n.h> +#include <2geom/coord.h> #include "style.h" #include "dialogs/dialog-events.h" @@ -144,7 +144,7 @@ SPDashSelector::set_dash (int ndash, double *dash, double o) if (np == ndash) { int j; for (j = 0; j < ndash; j++) { - if (!NR_DF_TEST_CLOSE (dash[j], pattern[j], delta)) + if (!Geom::are_near(dash[j], pattern[j], delta)) break; } if (j == ndash) { diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 34c3ab75a..970a094a9 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -24,8 +24,9 @@ # include "config.h" #endif -#include <gtkmm/paned.h> #include <gtk/gtk.h> +#include <gtkmm.h> +#include <2geom/rect.h> #include "box3d-context.h" #include "cms-system.h" @@ -543,10 +544,8 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) Glib::ustring id = Inkscape::CMSSystem::getDisplayId( 0, 0 ); bool enabled = false; - if ( dtw->canvas->cms_key ) { - *(dtw->canvas->cms_key) = id; - enabled = !dtw->canvas->cms_key->empty(); - } + dtw->canvas->cms_key = id; + enabled = !dtw->canvas->cms_key.empty(); cms_adjust_set_sensitive( dtw, enabled ); } #endif // ENABLE_LCMS @@ -807,11 +806,9 @@ void sp_dtw_color_profile_event(EgeColorProfTracker */*tracker*/, SPDesktopWidge gint monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_toplevel(GTK_WIDGET(dtw))->window); Glib::ustring id = Inkscape::CMSSystem::getDisplayId( screenNum, monitor ); bool enabled = false; - if ( dtw->canvas->cms_key ) { - *(dtw->canvas->cms_key) = id; - dtw->requestCanvasUpdate(); - enabled = !dtw->canvas->cms_key->empty(); - } + dtw->canvas->cms_key = id; + dtw->requestCanvasUpdate(); + enabled = !dtw->canvas->cms_key.empty(); cms_adjust_set_sensitive( dtw, enabled ); #endif // ENABLE_LCMS } @@ -1161,7 +1158,7 @@ bool SPDesktopWidget::showInfoDialog( Glib::ustring const &message ) GTK_BUTTONS_OK, "%s", message.c_str()); gtk_window_set_title( GTK_WINDOW(dialog), _("Note:")); // probably want to take this as a parameter. - gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } return result; @@ -1522,7 +1519,7 @@ sp_desktop_widget_update_hruler (SPDesktopWidget *dtw) * the latter is used for drawing e.g. the grids and guides. Only when the viewbox * coincides with the pixel buffer, everything will line up nicely. */ - NR::IRect viewbox = dtw->canvas->getViewboxIntegers(); + Geom::IntRect viewbox = dtw->canvas->getViewboxIntegers(); double const scale = dtw->desktop->current_zoom(); double s = viewbox.min()[Geom::X] / scale - dtw->ruler_origin[Geom::X]; @@ -1538,7 +1535,7 @@ sp_desktop_widget_update_vruler (SPDesktopWidget *dtw) * the latter is used for drawing e.g. the grids and guides. Only when the viewbox * coincides with the pixel buffer, everything will line up nicely. */ - NR::IRect viewbox = dtw->canvas->getViewboxIntegers(); + Geom::IntRect viewbox = dtw->canvas->getViewboxIntegers(); double const scale = dtw->desktop->current_zoom(); double s = viewbox.min()[Geom::Y] / -scale - dtw->ruler_origin[Geom::Y]; @@ -1887,7 +1884,7 @@ sp_desktop_widget_update_scrollbars (SPDesktopWidget *dtw, double scale) Geom::Rect darea ( Geom::Point(-doc->getWidth(), -doc->getHeight()), Geom::Point(2 * doc->getWidth(), 2 * doc->getHeight()) ); - Geom::OptRect deskarea = Geom::unify(darea, doc->getRoot()->getBboxDesktop()); + Geom::OptRect deskarea = darea | doc->getRoot()->getBboxDesktop(); /* Canvas region we always show unconditionally */ Geom::Rect carea( Geom::Point(deskarea->min()[Geom::X] * scale - 64, deskarea->max()[Geom::Y] * -scale - 64), diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index 79994a299..742411fb1 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -14,7 +14,6 @@ #include <gtk/gtk.h> -#include "libnr/nr-point.h" #include "forward.h" #include "sp-object.h" #include "message.h" @@ -23,6 +22,7 @@ #include <stddef.h> #include <sigc++/connection.h> +#include <2geom/point.h> // forward declaration typedef struct _EgeColorProfTracker EgeColorProfTracker; diff --git a/src/widgets/icon.cpp b/src/widgets/icon.cpp index 450c5f0d9..95cb23a22 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -23,6 +23,7 @@ #include <gtkmm.h> #include <gdkmm/pixbuf.h> #include <glibmm/fileutils.h> +#include <2geom/transforms.h> #include "path-prefix.h" #include "preferences.h" diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 5d065c3e9..3c1196e96 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -6808,11 +6808,11 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) 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; + Geom::Dim2 axis; if (writing_mode == SP_CSS_WRITING_MODE_LR_TB || writing_mode == SP_CSS_WRITING_MODE_RL_TB) { - axis = NR::X; + axis = Geom::X; } else { - axis = NR::Y; + axis = Geom::Y; } Geom::OptRect bbox @@ -6865,7 +6865,7 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) } } Geom::Point XY = SP_TEXT(item)->attributes.firstXY(); - if (axis == NR::X) { + if (axis == Geom::X) { XY = XY + Geom::Point (move, 0); } else { XY = XY + Geom::Point (0, move); |
