From 1079b1b4c0331e5d4bd62f3c93349aec50f520f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 23 Jun 2011 18:38:51 +0200 Subject: Update 2Geom to pull in integer rectangle class (bzr r10347.1.1) --- src/2geom/Makefile_insert | 1 + src/2geom/affine.cpp | 14 +- src/2geom/affine.h | 15 +- src/2geom/angle.h | 21 +- src/2geom/basic-intersection.h | 2 +- src/2geom/bezier-curve.cpp | 85 +++- src/2geom/bezier-curve.h | 117 +++--- src/2geom/bezier-to-sbasis.h | 6 +- src/2geom/bezier-utils.cpp | 11 +- src/2geom/bezier-utils.h | 18 +- src/2geom/bezier.h | 27 +- src/2geom/choose.h | 21 +- src/2geom/circle.h | 21 +- src/2geom/circulator.h | 9 +- src/2geom/concepts.h | 20 +- src/2geom/conic_section_clipper_impl.cpp | 23 +- src/2geom/conicsec.cpp | 5 +- src/2geom/conjugate_gradient.h | 6 +- src/2geom/convex-cover.h | 14 +- src/2geom/coord.h | 39 +- src/2geom/crossing.h | 10 +- src/2geom/curve.cpp | 5 +- src/2geom/curves.h | 7 +- src/2geom/d2-sbasis.h | 7 +- src/2geom/d2.h | 3 +- src/2geom/forward.h | 19 +- src/2geom/generic-interval.h | 342 ++++++++++++++++ src/2geom/generic-rect.h | 363 +++++++++++++++++ src/2geom/hvlinesegment.h | 30 +- src/2geom/int-interval.h | 63 +++ src/2geom/int-point.h | 157 ++++++++ src/2geom/int-rect.h | 74 ++++ src/2geom/interval.h | 280 ++----------- src/2geom/isnan.h | 116 ------ src/2geom/line.h | 31 +- src/2geom/linear.h | 2 +- src/2geom/math-utils.h | 49 ++- src/2geom/ord.h | 4 +- src/2geom/path-intersection.h | 4 +- src/2geom/path.h | 33 +- src/2geom/pathvector.h | 13 +- src/2geom/piecewise.h | 8 +- src/2geom/point.cpp | 48 ++- src/2geom/point.h | 94 +++-- src/2geom/poly.h | 5 +- src/2geom/quadtree.h | 4 +- src/2geom/ray.h | 241 ++++------- src/2geom/rect.cpp | 98 +++++ src/2geom/rect.h | 306 +++----------- src/2geom/region.h | 4 +- src/2geom/sbasis-2d.h | 4 +- src/2geom/sbasis-curve.h | 45 ++- src/2geom/sbasis-to-bezier.h | 4 +- src/2geom/sbasis.cpp | 2 +- src/2geom/sbasis.h | 2 +- src/2geom/sturm.h | 70 ---- src/2geom/svg-elliptical-arc.h | 14 +- src/2geom/sweep.h | 4 +- src/2geom/toposweep.cpp | 663 +++++++++++++++++++++++++++++++ src/2geom/toposweep.h | 222 +++++++++++ src/2geom/transforms.cpp | 4 +- src/2geom/transforms.h | 15 +- src/2geom/utils.h | 12 +- src/connector-context.cpp | 22 +- src/display/nr-arena-image.cpp | 2 +- src/display/nr-filter-composite.cpp | 1 - src/display/nr-filter-gaussian.cpp | 2 - src/dyna-draw-context.cpp | 2 +- src/eraser-context.cpp | 2 +- src/helper/recthull.h | 2 +- src/libcola/cola.cpp | 2 +- src/libcola/gradient_projection.cpp | 2 +- src/libnr/nr-point-fns.cpp | 2 +- src/libnr/nr-types.cpp | 3 +- src/libvpsc/generate-constraints.cpp | 2 +- src/live_effects/lpe-spiro.cpp | 1 - src/object-edit.cpp | 2 +- src/selection-chemistry.cpp | 2 +- src/selection.cpp | 2 +- src/sp-item.cpp | 2 +- src/spray-context.cpp | 1 - src/style.cpp | 1 - src/tweak-context.cpp | 1 - src/widgets/desktop-widget.cpp | 4 +- 84 files changed, 2751 insertions(+), 1265 deletions(-) create mode 100644 src/2geom/generic-interval.h create mode 100644 src/2geom/generic-rect.h create mode 100644 src/2geom/int-interval.h create mode 100644 src/2geom/int-point.h create mode 100644 src/2geom/int-rect.h delete mode 100644 src/2geom/isnan.h create mode 100644 src/2geom/rect.cpp delete mode 100644 src/2geom/sturm.h create mode 100644 src/2geom/toposweep.cpp create mode 100644 src/2geom/toposweep.h (limited to 'src') diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index 4f7c3b6ef..a668a2b3b 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -78,6 +78,7 @@ 2geom/quadtree.h \ 2geom/ray.h \ 2geom/rect.h \ + 2geom/rect.cpp \ 2geom/region.cpp \ 2geom/region.h \ 2geom/sbasis-2d.cpp \ 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 @@ -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 (Original NRAffine definition and related macros) * Nathan Hurst (Geom::Affine class version of the above) * Michael G. Sloan (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 #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 * Marco Cecchetti @@ -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 dynamic_cast + * 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 const &pts) +{ + inner = D2(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 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 &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 &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 &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 const &points, Coord tolerance) { if (points.size() < 2) return 0.0; @@ -213,7 +264,7 @@ Coord bezier_length(std::vector 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 * Marco Cecchetti * Krzysztof Kosiński * - * 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 inner; + BezierCurve() {} + BezierCurve(BezierCurve const &b) : inner(b.inner) {} + BezierCurve(D2 const &b) : inner(b) {} + BezierCurve(Bezier const &x, Bezier const &y) : inner(x, y) {} + BezierCurve(std::vector 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 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 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 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 static void assert_degree(BezierCurveN 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 subdivide(Coord t) const { + std::pair 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 subdivide(Coord t) const { - std::pair 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 @@ -239,28 +280,10 @@ inline Curve *BezierCurveN::derivative() const { return new BezierCurveN(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 * * 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 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 + * Michael Sloan + * Nathan Hurst * - * Copyright 2007 MenTaLguY - * Copyright 2007 Michael Sloan - * Copyright 2007 Nathan Hurst + * 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 -#include <2geom/isnan.h> +#include +#include <2geom/coord.h> +#include <2geom/math-utils.h> #include <2geom/d2.h> #include <2geom/solver.h> -#include namespace Geom { @@ -280,7 +283,7 @@ public: } std::vector roots(Interval const ivl) const { std::vector solutions; - find_bernstein_roots(&const_cast&>(c_)[0], order(), solutions, 0, ivl[0], ivl[1]); + find_bernstein_roots(&const_cast&>(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 * * 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 +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 * @@ -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 #include <2geom/point.h> #include <2geom/exception.h> #include <2geom/path.h> -#include -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 * * 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 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 * * 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 #include #include <2geom/forward.h> @@ -49,7 +49,7 @@ template <> struct ResultTraits { typedef SBasis sb_type; }; -template <> struct ResultTraits { +template <> struct ResultTraits { typedef OptRect bounds_type; typedef D2 sb_type; }; @@ -130,7 +130,7 @@ struct ScalableConcept { } }; -template +template struct AddableConcept { T i, j; void constraints() { @@ -139,7 +139,7 @@ struct AddableConcept { } }; -template +template 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 @@ -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 & crossing_points) const cpts.size()) // remove duplicates - std::sort (cpts.begin(), cpts.end(), lex_lesser()); + std::sort (cpts.begin(), cpts.end(), Point::LexOrder()); 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 * * 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 * Copyright 2006 Michael G. Sloan @@ -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 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 * * 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 #include +#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::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 +struct CoordTraits {}; -typedef long IntCoord; +template<> +struct CoordTraits { + 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 { + 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 + * Marco Cecchetti * * 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 * Marco Cecchetti 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..95c0da4ed 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: * ? * diff --git a/src/2geom/d2.h b/src/2geom/d2.h index 3e4de430e..73330295b 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 * * This library is free software; you can redistribute it and/or @@ -426,7 +426,6 @@ inline std::ostream &operator<< (std::ostream &out_file, const Geom::D2 &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 class GenericInterval; +template class GenericOptInterval; +class Interval; +typedef GenericOptInterval OptInterval; +typedef GenericInterval IntInterval; +typedef GenericOptInterval OptIntInterval; +template class GenericRect; +template class GenericOptRect; +class Rect; +typedef GenericOptRect OptRect; +typedef GenericRect IntRect; +typedef GenericOptRect OptIntRect; // fragments class Linear; @@ -90,9 +102,6 @@ class VShear; template class D2; template class Piecewise; -typedef D2 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 + * + * 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 +#include +#include +#include + +namespace Geom { + +template +class GenericOptInterval; + +/** + * @brief A range of numbers which is never empty. + * @ingroup Primitives + */ +template +class GenericInterval + : boost::equality_comparable< GenericInterval + , boost::additive< GenericInterval + , boost::additive< GenericInterval, C + , boost::orable< GenericInterval + > > > > +{ + typedef GenericInterval 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 + 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::contains(min(), max(), val, val); + } + /** @brief Check whether the interval includes the given interval. */ + bool contains(Self const &val) const { + return CoordTraits::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 + * amount * 2. 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 +inline GenericInterval unify(GenericInterval const &a, GenericInterval const &b) { + return a | b; +} + +/** + * @brief A range of numbers that can be empty. + * @ingroup Primitives + */ +template +class GenericOptInterval + : public boost::optional::IntervalType> + , boost::orable< GenericOptInterval, typename CoordTraits::OptIntervalType + , boost::andable< GenericOptInterval, typename CoordTraits::OptIntervalType + > > +{ + typedef typename CoordTraits::IntervalType CInterval; + typedef typename CoordTraits::OptIntervalType OptCInterval; + typedef boost::optional Base; +public: + /// @name Create optionally empty intervals of integers. + /// @{ + /** @brief Create an empty interval. */ + GenericOptInterval() : Base() {} + /** @brief Wrap an existing interval. */ + GenericOptInterval(GenericInterval 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 + static GenericOptInterval from_range(InputIterator start, InputIterator end) { + if (start == end) { + GenericOptInterval ret; + return ret; + } + GenericOptInterval 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 const &a) { + if (*this) { // check that we are not empty + (*this)->unionWith(*a); + } else if (a) { + *this = *a; + } + } + void intersectWith(GenericOptInterval 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(this)) = boost::none; + } + GenericOptInterval &operator|=(OptCInterval const &o) { + unionWith(o); + return *this; + } + GenericOptInterval &operator&=(OptCInterval const &o) { + intersectWith(o); + return *this; + } +}; + +/** @brief Intersect two intervals and return a possibly empty range of numbers + * @relates GenericOptInterval */ +template +inline GenericOptInterval intersect(GenericInterval const &a, GenericInterval const &b) { + return GenericOptInterval(a) & GenericOptInterval(b); +} +/** @brief Intersect two intervals and return a possibly empty range of numbers + * @relates GenericOptInterval */ +template +inline GenericOptInterval operator&(GenericInterval const &a, GenericInterval const &b) { + return GenericOptInterval(a) & GenericOptInterval(b); +} + +#ifdef _GLIBCXX_IOSTREAM +template +inline std::ostream &operator<< (std::ostream &os, + Geom::GenericInterval const &I) { + os << "Interval("< + * Krzysztof Kosiński + * 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 + * Nathan Hurst + * bulia byak + * MenTaLguY + */ + +#ifndef LIB2GEOM_SEEN_GENERIC_RECT_H +#define LIB2GEOM_SEEN_GENERIC_RECT_H + +#include + +namespace Geom { + +template +class GenericOptRect; + +/** + * @brief Axis aligned, non-empty, generic rectangle. + * @ingroup Primitives + */ +template +class GenericRect + : boost::additive< GenericRect, typename CoordTraits::PointType + , boost::equality_comparable< GenericRect + , boost::orable< GenericRect + , boost::orable< GenericRect, typename CoordTraits::OptRectType + > > > > +{ + typedef typename CoordTraits::IntervalType CInterval; + typedef typename CoordTraits::PointType CPoint; + typedef typename CoordTraits::RectType CRect; + typedef typename CoordTraits::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] = Interval(); } + /** @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] = Interval(a[X], b[X]); + f[Y] = Interval(a[Y], b[Y]); + } + /** @brief Create a rectangle from a range of points. + * The resulting rectangle will contain all ponts from the range. + * The return type of iterators must be convertible to Point. + * The range must not be empty. For possibly empty ranges, see OptRect. + * @param start Beginning of the range + * @param end End of the range + * @return Rectangle that contains all points from [start, end). */ + template + static GenericRect from_range(InputIterator start, InputIterator end) { + assert(start != end); + CPoint p1 = *start++; + GenericRect 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 from_array(CPoint const *c, unsigned n) { + GenericRect result = GenericRect::from_range(c, c+n); + 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 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 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 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 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 -amount 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 -p[X] 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 &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 &operator-=(CPoint const &p) { + f[X] -= p[X]; + f[Y] -= p[Y]; + return *this; + } + /** @brief Union two rectangles. */ + GenericRect &operator|=(GenericRect const &o) { + unionWith(o); + return *this; + } + GenericRect &operator|=(OptCRect const &o) { + unionWith(o); + return *this; + } + /** @brief Test for equality of rectangles. */ + bool operator==(GenericRect const &o) const { return f[X] == o[X] && f[Y] == o[Y]; } + /// @} +}; + +/** + * @brief Axis-aligned generic rectangle that can be empty. + * @ingroup Primitives + */ +template +class GenericOptRect + : public boost::optional::RectType> + , boost::orable< GenericOptRect + , boost::andable< GenericOptRect + , boost::andable< GenericOptRect, typename CoordTraits::RectType + > > > +{ + typedef typename CoordTraits::IntervalType CInterval; + typedef typename CoordTraits::OptIntervalType OptCInterval; + typedef typename CoordTraits::PointType CPoint; + typedef typename CoordTraits::RectType CRect; + typedef typename CoordTraits::OptRectType OptCRect; + typedef boost::optional Base; +public: + GenericOptRect() : Base() {} + GenericOptRect(GenericRect 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(this)) = boost::none; + } + } + void intersectWith(OptCRect const &b) { + if (b) { + intersectWith(*b); + } else { + *(static_cast(this)) = boost::none; + } + } + GenericOptRect &operator|=(OptCRect const &b) { + unionWith(b); + return *this; + } + GenericOptRect &operator&=(CRect const &b) { + intersectWith(b); + return *this; + } + GenericOptRect &operator&=(OptCRect const &b) { + intersectWith(b); + return *this; + } +}; + +template +inline void GenericRect::unionWith(OptCRect const &b) { + if (b) { + unionWith(*b); + } +} +template +inline bool GenericRect::intersects(OptCRect const &r) const { + return r && intersects(*r); +} +template +inline bool GenericRect::contains(OptCRect const &r) const { + return !r || contains(*r); +} + +#ifdef _GLIBCXX_IOSTREAM +template +inline std::ostream &operator<<(std::ostream &out, GenericRect 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 + * \brief Horizontal and vertical line segment + *//* + * Authors: + * Marco Cecchetti + * Krzysztof Kosiński + * 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((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 pointAndDerivatives(Coord t, unsigned n) const { std::vector 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 + * + * 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 IntInterval; + +/** + * @brief Range of integers that can be empty. + * @ingroup Primitives + */ +typedef GenericOptInterval 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 + * + * 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 +#include +#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 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 { + 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 { + 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()(a, b) : IntPoint::LexOrder()(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..27fb06dfe --- /dev/null +++ b/src/2geom/int-rect.h @@ -0,0 +1,74 @@ +/** + * \file + * \brief Axis-aligned rectangle with integer coordinates + *//* + * Copyright 2011 Krzysztof Kosiński + * + * 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/generic-rect.h> + +namespace Geom { + +typedef GenericRect IntRect; +typedef GenericOptRect 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 #include #include #include #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 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 , 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 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 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 - * amount * 2. 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 - , 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() {}; - /** @brief Wrap an existing interval. */ - OptInterval(Interval const &a) : boost::optional(a) {}; - /** @brief Create an interval containing a single point. */ - OptInterval(Coord u) : boost::optional(Interval(u)) {}; - /** @brief Create an interval containing a range of numbers. */ - OptInterval(Coord u, Coord v) : boost::optional(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 - 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*>(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("< - * - * 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 -/* You might try changing the above to 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 -#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 + * \brief Infinite straight line + *//* + * Authors: + * Marco Cecchetti + * Krzysztof Kosiński + * 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 - +#include #include <2geom/bezier-curve.h> // for LineSegment #include <2geom/rect.h> #include <2geom/crossing.h> #include <2geom/exception.h> - #include <2geom/ray.h> -#include - - 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 // sincos is usually only available in math.h #include @@ -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 +#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 - * Marco Cecchetti + * MenTaLguY + * Marco Cecchetti * - * 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 +#include #include #include <2geom/curve.h> #include <2geom/bezier-curve.h> -#include -#include - - -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 &a, Geom::Path &b) -{ +inline void swap(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 * @@ -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 #include - -#include <2geom/concepts.h> -#include <2geom/isnan.h> #include +#include <2geom/concepts.h> +#include <2geom/math-utils.h> +#include <2geom/sbasis.h> + namespace Geom { /** 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 + * Nathan Hurst + * Krzysztof Kosiński + * + * 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 #include #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 #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 #include #include 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 * * 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 roots(Coord v, Dim2 d) const - { - if (d < 0 || d > 1) - THROW_RANGEERROR("Ray::roots, dimension argument out of range"); - std::vector 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 roots(Coord v, Dim2 d) const { + std::vector 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 + * Krzysztof Kosiński + * 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..72b659a81 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -2,7 +2,10 @@ * \file * \brief Axis-aligned rectangle *//* - * Copyright 2007 Michael Sloan + * Authors: + * Michael Sloan + * Krzysztof Kosiński + * 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,41 @@ * MenTaLguY */ -#include <2geom/d2.h> - -#ifndef LIB2GEOM_RECT_H -#define LIB2GEOM_RECT_H +#ifndef LIB2GEOM_SEEN_RECT_H +#define LIB2GEOM_SEEN_RECT_H +#include #include <2geom/affine.h> -#include +#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 Rect; -class OptRect; - -inline Rect unify(Rect const &, Rect const &); +typedef GenericOptRect OptRect; /** * @brief Axis aligned, non-empty rectangle. * @ingroup Primitives */ -template<> -class D2 { -private: - Interval f[2]; +class Rect + : public GenericRect + , boost::multipliable< Rect, Affine > +{ + typedef GenericRect Base; public: /// @name Create rectangles. /// @{ /** @brief Create a rectangle that contains only the point at (0,0). */ - D2() { f[X] = f[Y] = Interval(); } + Rect() {} /** @brief Create a rectangle from X and Y intervals. */ - D2(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(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(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 +81,7 @@ public: * @return Rectangle that contains all points from [start, end). */ template 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. */ @@ -102,260 +93,85 @@ public: /// @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 -amount 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 -p[X] 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(*r)); } -inline Rect union_list(std::vector 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 { -public: - OptRect() : boost::optional() {}; - OptRect(Rect const &a) : boost::optional(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 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 inner; public: explicit SBasisCurve(D2 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 #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{ -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 @@ -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 -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) 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 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 +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 &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::iterator end = std::unique(splits.begin(), splits.end(), NearPredicate()); + splits.resize(end - splits.begin()); +} + +// A little sugar for appending a list to another +template +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 > mono_sections(PathVector const &ps, Dim2 d) { + std::vector > 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 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
(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 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 > split_section(boost::shared_ptr
s, PathVector const &ps, std::vector &cuts, Dim2 d) { + std::vector > 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
(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 +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 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 +std::vector deref_vector(std::vector > const &xs, unsigned from = 0) { + std::vector 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 +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 +template +struct DerefAdapter { + typedef typename boost::shared_ptr first_argument_type; + typedef typename boost::shared_ptr 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 > monoss; +std::vector > chopss; +std::vector > 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 +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 &windings, boost::shared_ptr
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; + int from_vert; + int to_vert; + Context(boost::shared_ptr
sect, int from) : section(sect), from_vert(from), to_vert(-1) {} +}; + +template +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::infinity() + +TopoGraph::TopoGraph(PathVector const &ps, Dim2 d, double t) : dim(d), tol(t) { + //s_sort = vertical section order + ContextAdapter > s_sort = DerefAdapter(SectionSorter(ps, (Dim2)(1-d), tol)); + //sweep_sort = horizontal sweep order + DerefAdapter sweep_sort = DerefAdapter(SweepSorter(d)); + //heap_sort = reverse horizontal sweep order + ReverseAdapter > heap_sort = ReverseAdapter >(sweep_sort); + //edge_sort = sorter for edges + EdgeSorter edge_sort = EdgeSorter(ps, (Dim2)(1-d), tol); + + std::vector > input_sections = mono_sections(ps, d), chops; + std::sort(input_sections.begin(), input_sections.end(), sweep_sort); + + std::vector context; + + vertices.reserve(input_sections.size()); + + //std::vector to_process; + + std::vector windings(ps.size(), 0); + for(MergeIterator > 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
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 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
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 this_splits; + for(unsigned i = 0; i < context.size(); i++) { + if(context[i].section == context[context_ix].section) continue; + + boost::shared_ptr
sec = context[i].section; + + if(!si.intersects(Interval(sec->fp[1-d], sec->tp[1-d]))) continue; + + std::vector 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
sec = context[context_ix].section; + Edge e(sec, context[context_ix].from_vert); + + std::vector::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::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
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 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
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
new_section = boost::shared_ptr
(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 > visited; + for(unsigned i = 0; i < g.size(); i++) visited.push_back(std::vector(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 > 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 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 + * Nathan Hurst + * + * 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 + +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 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 associated with this edge + unsigned other; // index of the vertex this edge points to + Edge(boost::shared_ptr
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 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) 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 vertices; + Dim2 dim; + double tol; +}; + +//TODO: convert to classes +typedef std::vector > Area; +typedef std::vector 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 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 +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 #include <2geom/forward.h> #include <2geom/affine.h> -#include 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 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 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 * Copyright 2006 Michael G. Sloan * @@ -33,6 +30,9 @@ * */ +#ifndef SEEN_LIB2GEOM_UTILS_H +#define SEEN_LIB2GEOM_UTILS_H + #include #include @@ -59,9 +59,9 @@ struct MultipliableNoncommutative : B } }; -} +} // end namespace Geom -#endif +#endif // SEEN_LIB2GEOM_UTILS_H /* Local Variables: diff --git a/src/connector-context.cpp b/src/connector-context.cpp index 251b41066..2aa9c41ee 100644 --- a/src/connector-context.cpp +++ b/src/connector-context.cpp @@ -1306,12 +1306,12 @@ cc_connector_rerouting_finish(SPConnectorContext *const cc, Geom::Point *const p if (found) { if (cc->clickedhandle == cc->endpt_handle[0]) { - cc->clickeditem->setAttribute("inkscape:connection-start", shape_label, false); - cc->clickeditem->setAttribute("inkscape:connection-start-point", cpid, false); + cc->clickeditem->setAttribute("inkscape:connection-start", shape_label, NULL); + cc->clickeditem->setAttribute("inkscape:connection-start-point", cpid, NULL); } else { - cc->clickeditem->setAttribute("inkscape:connection-end", shape_label, false); - cc->clickeditem->setAttribute("inkscape:connection-end-point", cpid, false); + cc->clickeditem->setAttribute("inkscape:connection-end", shape_label, NULL); + cc->clickeditem->setAttribute("inkscape:connection-end-point", cpid, NULL); } g_free(shape_label); } @@ -1451,23 +1451,23 @@ spcc_flush_white(SPConnectorContext *cc, SPCurve *gc) bool connection = false; cc->newconn->setAttribute( "inkscape:connector-type", - cc->isOrthogonal ? "orthogonal" : "polyline", false ); + cc->isOrthogonal ? "orthogonal" : "polyline", NULL ); cc->newconn->setAttribute( "inkscape:connector-curvature", - Glib::Ascii::dtostr(cc->curvature).c_str(), false ); + Glib::Ascii::dtostr(cc->curvature).c_str(), NULL ); if (cc->shref) { - cc->newconn->setAttribute( "inkscape:connection-start", cc->shref, false); + cc->newconn->setAttribute( "inkscape:connection-start", cc->shref, NULL); if (cc->scpid) { - cc->newconn->setAttribute( "inkscape:connection-start-point", cc->scpid, false); + cc->newconn->setAttribute( "inkscape:connection-start-point", cc->scpid, NULL); } connection = true; } if (cc->ehref) { - cc->newconn->setAttribute( "inkscape:connection-end", cc->ehref, false); + cc->newconn->setAttribute( "inkscape:connection-end", cc->ehref, NULL); if (cc->ecpid) { - cc->newconn->setAttribute( "inkscape:connection-end-point", cc->ecpid, false); + cc->newconn->setAttribute( "inkscape:connection-end-point", cc->ecpid, NULL); } connection = true; } @@ -1950,7 +1950,7 @@ void cc_selection_set_avoid(bool const set_avoid) char const *value = (set_avoid) ? "true" : NULL; if (cc_item_is_shape(item)) { - item->setAttribute("inkscape:connector-avoid", value, false); + item->setAttribute("inkscape:connector-avoid", value, NULL); item->avoidRef->handleSettingChange(); changes++; } 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-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 -#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-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index 326c37160..884e832ef 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -25,8 +25,6 @@ #include #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/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/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 2a3b525a7..62771ece2 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> namespace cola { 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 #include "gradient_projection.h" #include -#include "2geom/isnan.h" +#include <2geom/math-utils.h> #include "isinf.h" #include diff --git a/src/libnr/nr-point-fns.cpp b/src/libnr/nr-point-fns.cpp index cd6d6927b..ac58eddb7 100644 --- a/src/libnr/nr-point-fns.cpp +++ b/src/libnr/nr-point-fns.cpp @@ -1,5 +1,5 @@ #include -#include <2geom/isnan.h> +#include <2geom/math-utils.h> using NR::Point; diff --git a/src/libnr/nr-types.cpp b/src/libnr/nr-types.cpp index 0231c91d5..5da5d5cf6 100644 --- a/src/libnr/nr-types.cpp +++ b/src/libnr/nr-types.cpp @@ -3,8 +3,7 @@ */ #include - -#include "2geom/isnan.h" +#include <2geom/math-utils.h> /** Scales this vector to make it a unit vector (within rounding error). * 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/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/object-edit.cpp b/src/object-edit.cpp index 553c125a3..743ef573a 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -35,7 +35,7 @@ #include #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))) 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..3c4ccccf2 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; } diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 7e5f5f96a..424107426 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -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/spray-context.cpp b/src/spray-context.cpp index 36c135924..aa14e6ee5 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/style.cpp b/src/style.cpp index bb25a5f46..37a784e2a 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -42,7 +42,6 @@ #include "xml/repr.h" #include "xml/simple-document.h" #include "unit-constants.h" -#include "2geom/isnan.h" #include "macros.h" #include "preferences.h" diff --git a/src/tweak-context.cpp b/src/tweak-context.cpp index faa08ee91..022869c69 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/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 0d890fa86..6f3b4dcb9 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -1161,7 +1161,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; @@ -1887,7 +1887,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), -- cgit v1.2.3 From ab143333746e25648b253f13c0539adff089b1b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 24 Jun 2011 00:22:07 +0200 Subject: Remove more of libnr (bzr r10347.1.2) --- src/2geom/Makefile_insert | 2 +- src/2geom/d2-sbasis.h | 10 +- src/2geom/d2.h | 5 +- src/2geom/generic-rect.h | 31 +++- src/2geom/point-l.h | 86 --------- src/axis-manip.h | 2 +- src/box3d-context.cpp | 22 +-- src/desktop-events.cpp | 18 +- src/desktop.cpp | 1 + src/dialogs/clonetiler.cpp | 1 + src/display/canvas-axonomgrid.cpp | 25 +-- src/display/canvas-grid.cpp | 12 +- src/display/guideline.cpp | 12 +- src/display/nr-arena-glyphs.cpp | 8 +- src/display/nr-arena-group.cpp | 2 +- src/display/nr-arena-item.h | 2 + src/display/nr-arena-shape.cpp | 16 +- src/display/nr-arena-shape.h | 1 + src/display/nr-arena.cpp | 1 + src/display/nr-filter-displacement-map.cpp | 189 -------------------- src/display/nr-filter-turbulence.cpp | 1 - src/display/nr-filter-turbulence.h | 1 - src/display/nr-filter-units.cpp | 17 +- src/display/nr-filter-units.h | 2 +- src/display/nr-filter.cpp | 8 +- src/display/sp-canvas.cpp | 10 +- src/display/sp-canvas.h | 2 +- src/document.cpp | 3 +- src/draw-context.h | 2 +- src/dropper-context.cpp | 9 +- src/extension/implementation/implementation.h | 2 +- src/gradient-chemistry.cpp | 4 +- src/gradient-context.cpp | 6 +- src/graphlayout.cpp | 1 + src/helper/geom.cpp | 10 +- src/helper/geom.h | 4 +- src/helper/pixbuf-ops.cpp | 1 + src/helper/png-write.cpp | 1 + src/libnr/Makefile_insert | 13 +- src/libnr/in-svg-plane.h | 5 +- src/libnr/libnr.def | 89 ---------- src/libnr/nr-convert2geom.h | 34 +--- src/libnr/nr-coord.h | 29 --- src/libnr/nr-dim2.h | 22 --- src/libnr/nr-forward.h | 10 -- src/libnr/nr-i-coord.h | 25 --- src/libnr/nr-point-fns-test.h | 139 --------------- src/libnr/nr-point-fns.cpp | 91 ++-------- src/libnr/nr-point-fns.h | 95 +--------- src/libnr/nr-point-l.h | 103 ----------- src/libnr/nr-point-ops.h | 88 ---------- src/libnr/nr-point.h | 155 ---------------- src/libnr/nr-rect-l.cpp | 20 --- src/libnr/nr-rect-l.h | 124 +------------ src/libnr/nr-rect-ops.h | 51 ------ src/libnr/nr-rect.cpp | 198 ++------------------- src/libnr/nr-rect.h | 243 ++------------------------ src/libnr/nr-render.h | 25 --- src/libnr/nr-types-test.h | 142 --------------- src/libnr/nr-types.cpp | 67 ------- src/libnr/nr-types.h | 39 ----- src/libnr/nr-values.cpp | 9 +- src/libnr/nr-values.h | 5 +- src/libnr/nr_config.h.mingw | 12 -- src/libnr/nr_config.h.win32 | 14 -- src/livarot/Path.h | 3 +- src/livarot/PathSimplify.cpp | 1 + src/livarot/Shape.cpp | 6 +- src/livarot/Shape.h | 2 +- src/livarot/path-description.h | 2 +- src/livarot/sweep-event.h | 2 +- src/livarot/sweep-tree.h | 2 +- src/marker.cpp | 1 + src/object-edit.cpp | 4 +- src/pen-context.cpp | 3 +- src/pencil-context.cpp | 12 +- src/rect-context.cpp | 4 +- src/rect-context.h | 2 +- src/removeoverlap.cpp | 3 +- src/selection.cpp | 2 +- src/snap.cpp | 3 +- src/sp-conn-end-pair.h | 1 - src/sp-flowtext.cpp | 5 +- src/sp-image.cpp | 3 +- src/sp-item.cpp | 2 +- src/sp-mask.cpp | 3 +- src/sp-namedview.cpp | 4 +- src/sp-offset.cpp | 2 +- src/sp-root.cpp | 1 + src/sp-text.h | 1 - src/spiral-context.cpp | 8 +- src/spiral-context.h | 2 +- src/spray-context.h | 2 +- src/star-context.cpp | 6 +- src/star-context.h | 2 +- src/svg-view.cpp | 1 + src/tweak-context.h | 2 +- src/ui/cache/svg_preview_cache.cpp | 1 + src/ui/dialog/align-and-distribute.cpp | 6 +- src/ui/dialog/align-and-distribute.h | 1 - src/ui/dialog/tile.cpp | 1 + src/ui/dialog/transformation.cpp | 1 + src/ui/view/edit-widget-interface.h | 2 +- src/ui/view/view.cpp | 2 +- src/ui/widget/page-sizer.cpp | 1 + src/ui/widget/rotateable.cpp | 7 +- src/ui/widget/ruler.h | 2 +- src/unclump.cpp | 1 + src/widgets/dash-selector.cpp | 4 +- src/widgets/desktop-widget.cpp | 7 +- src/widgets/desktop-widget.h | 2 +- src/widgets/icon.cpp | 1 + src/widgets/toolbox.cpp | 8 +- 113 files changed, 284 insertions(+), 2237 deletions(-) delete mode 100644 src/2geom/point-l.h delete mode 100644 src/libnr/libnr.def delete mode 100644 src/libnr/nr-coord.h delete mode 100644 src/libnr/nr-dim2.h delete mode 100644 src/libnr/nr-i-coord.h delete mode 100644 src/libnr/nr-point-fns-test.h delete mode 100644 src/libnr/nr-point-l.h delete mode 100644 src/libnr/nr-point-ops.h delete mode 100644 src/libnr/nr-point.h delete mode 100644 src/libnr/nr-rect-ops.h delete mode 100644 src/libnr/nr-render.h delete mode 100644 src/libnr/nr-types-test.h delete mode 100644 src/libnr/nr-types.cpp delete mode 100644 src/libnr/nr-types.h delete mode 100644 src/libnr/nr_config.h.mingw delete mode 100644 src/libnr/nr_config.h.win32 (limited to 'src') diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index a668a2b3b..08bcbff45 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -77,8 +77,8 @@ 2geom/quadtree.cpp \ 2geom/quadtree.h \ 2geom/ray.h \ - 2geom/rect.h \ 2geom/rect.cpp \ + 2geom/rect.h \ 2geom/region.cpp \ 2geom/region.h \ 2geom/sbasis-2d.cpp \ diff --git a/src/2geom/d2-sbasis.h b/src/2geom/d2-sbasis.h index 95c0da4ed..e61067e1b 100644 --- a/src/2geom/d2-sbasis.h +++ b/src/2geom/d2-sbasis.h @@ -35,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 73330295b..4a4f45a63 100644 --- a/src/2geom/d2.h +++ b/src/2geom/d2.h @@ -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 #include <2geom/concepts.h> diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h index cc0d7d42e..9a839d735 100644 --- a/src/2geom/generic-rect.h +++ b/src/2geom/generic-rect.h @@ -69,7 +69,7 @@ public: /// @name Create rectangles. /// @{ /** @brief Create a rectangle that contains only the point at (0,0). */ - GenericRect() { f[X] = f[Y] = Interval(); } + 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; @@ -102,6 +102,25 @@ public: GenericRect result = GenericRect::from_range(c, c+n); return result; } + /** @brief Create rectangle from origin and dimensions. */ + static GenericRect from_xywh(C x, C y, C w, C h) { + CPoint xy(x, y); + CPoint wh(w, h); + GenericRect result(xy, xy + wh); + return result; + } + /** @brief Create rectangle from origin and dimensions. */ + static GenericRect from_xywh(CPoint const &xy, CPoint const &wh) { + GenericRect result(xy, xy + wh); + return result; + } + /** @brief Create rectangle from two points. */ + static GenericRect from_xyxy(C x0, C x1, C y0, C y1) { + CPoint p0(x0, y0); + CPoint p1(x1, y1); + GenericRect result(p0, p1); + return result; + } /// @} /// @name Inspect dimensions. @@ -183,6 +202,16 @@ public: /// @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]); 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 -#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/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 #include -#include "libnr/nr-point.h" namespace Proj { diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index 90f1707b9..fad7c0761 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 eb2b3a093..df1bf0c7a 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 f12f83ca6..181a19e1b 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -57,6 +57,7 @@ #include #include +#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 60ec4f9f7..b9e490dcf 100644 --- a/src/dialogs/clonetiler.cpp +++ b/src/dialogs/clonetiler.cpp @@ -17,6 +17,7 @@ #include #include #include +#include <2geom/transforms.h> #include "desktop.h" #include "desktop-handles.h" diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index a9893f09d..daad2d515 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 82ea036f6..52963ce6b 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -918,9 +918,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(); @@ -941,7 +941,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 { @@ -952,7 +952,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 { @@ -963,12 +963,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 dbac07596..0e20f0ddb 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(floor(b->left())); - item->bbox.y0 = static_cast(floor(b->top())); - item->bbox.x1 = static_cast(ceil (b->right())); - item->bbox.y1 = static_cast(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; diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 97f92d02d..d1e6869aa 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -176,7 +176,7 @@ 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); 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 #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..ff87b5134 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -223,10 +223,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(floor((*boundingbox)[0][0])); // Floor gives the coordinate in which the point resides - item->bbox.y0 = static_cast(floor((*boundingbox)[1][0])); - item->bbox.x1 = static_cast(ceil ((*boundingbox)[0][1])); // Ceil gives the first coordinate beyond the point - item->bbox.y1 = static_cast(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 +274,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(floor((*boundingbox)[0][0])); - shape->approx_bbox.y0 = static_cast(floor((*boundingbox)[1][0])); - shape->approx_bbox.x1 = static_cast(ceil ((*boundingbox)[0][1])); - shape->approx_bbox.y1 = static_cast(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; } 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-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(NR_PIXBLOCK_PX(pb) + (y-pb->area.y0)*pb->rs); - return rowData[x-pb->area.x0]; -} - -template -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<(round(sf * (x - xi))), - yf = static_cast(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 -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(NR_PIXBLOCK_PX(map) + (yout-map->area.y0)*map->rs); - pixel_t* outRowData = reinterpret_cast(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(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(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else if (map_premultiplied && !data_premultiplied) { - performDisplacement(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else if (data_premultiplied) { - performDisplacement(texture, map, Xchannel, Ychannel, out, scalex, scaley); - } else { - performDisplacement(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-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 55190b00c..a0997cc1b 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -238,10 +238,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.cpp b/src/display/sp-canvas.cpp index 472c9ada5..977452834 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -2306,13 +2306,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..32747e7c5 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -149,7 +149,7 @@ struct SPCanvas { 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 #include #include +#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 #include +#include <2geom/point.h> #include "event-context.h" #include -#include #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 #endif -#include -#include -#include -#include -#include +#include +#include +#include +#include <2geom/transforms.h> #include "macros.h" #include "display/canvas-bpath.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 922a9b16e..86c86d2dc 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) @@ -561,7 +561,7 @@ sp_gradient_context_root_handler(SPEventContext *event_context, GdkEvent *event) m.setup(desktop); 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 4f536beb3..41e523b86 100644 --- a/src/graphlayout.cpp +++ b/src/graphlayout.cpp @@ -19,6 +19,7 @@ #include #include #include +#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 -#include +#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 f6796f2ad..226042337 100644 --- a/src/helper/pixbuf-ops.cpp +++ b/src/helper/pixbuf-ops.cpp @@ -18,6 +18,7 @@ #include #include #include +#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 #include #include "png-write.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 -#include -#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 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 - -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 - -#include -#include -#include -#include - -#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 ac58eddb7..a2e74c112 100644 --- a/src/libnr/nr-point-fns.cpp +++ b/src/libnr/nr-point-fns.cpp @@ -1,72 +1,11 @@ -#include -#include <2geom/math-utils.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 -#include -#include +#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 -#include -#include - -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 - -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 -//#include -#include -//#include - -#include -#include -#include - -//#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..08910a1d6 100644 --- a/src/libnr/nr-rect-l.cpp +++ b/src/libnr/nr-rect-l.cpp @@ -1,23 +1,3 @@ -#include - -boost::optional NRRectL::upgrade() const { - if (nr_rect_l_test_empty_ptr(this)) { - return boost::optional(); - } else { - return NR::Rect(NR::Point(x0, y0), NR::Point(x1, y1)); - } -} - -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]))) -{ -} - -} - /* Local Variables: mode:c++ diff --git a/src/libnr/nr-rect-l.h b/src/libnr/nr-rect-l.h index 3493fa8f4..6e82bb790 100644 --- a/src/libnr/nr-rect-l.h +++ b/src/libnr/nr-rect-l.h @@ -1,132 +1,12 @@ #ifndef SEEN_NR_RECT_L_H #define SEEN_NR_RECT_L_H -#include -#include -#include -#include +#include struct NRRectL { - boost::optional upgrade() const; - NR::ICoord x0, y0, x1, y1; + gint32 x0, y0, x1, y1; }; - -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() && isEmpty(); - } - - bool intersects(const IRect &r) const { - return intersects(r) && intersects(r); - } - bool contains(const IRect &r) const { - return contains(r) && contains(r); - } - bool contains(const IPoint &p) const { - return contains(p) && contains(p); - } - - ICoord maxExtent() const { - return MAX(extent(), extent()); - } - - ICoord extent(Dim2 axis) const { - switch (axis) { - case X: return extent(); - case Y: return extent(); - }; - } - - ICoord extent(unsigned i) const throw(std::out_of_range) { - switch (i) { - case 0: return extent(); - case 1: return extent(); - 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 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 - ICoord extent() const { - return _max[axis] - _min[axis]; - } - - template - bool isEmpty() const { - return !( _min[axis] < _max[axis] ); - } - - template - bool intersects(const IRect &r) const { - return _max[axis] >= r._min[axis] && _min[axis] <= r._max[axis]; - } - - template - bool contains(const IRect &r) const { - return contains(r._min) && contains(r._max); - } - - template - 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 , - * bulia byak - * - * This code is licensed under the GNU GPL; see COPYING for more information. - */ - -#include - -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 -#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 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 NRRect::upgrade() const { - if (nr_rect_d_test_empty_ptr(this)) { - return boost::optional(); - } 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 intersection(boost::optional const & a, boost::optional const & b) { - if ( !a || !b ) { - return boost::optional(); - } 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(); - } - } - 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 * Nathan Hurst @@ -13,251 +12,33 @@ * This code is in public domain */ - #include #include +#include #include +#include <2geom/rect.h> +#include "libnr/nr-forward.h" #include "libnr/nr-values.h" -#include -#include -#include -#include -#include "libnr/nr-point-ops.h" #include "libnr/nr-macros.h" -#include -#include -#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(epsilon) || isEmpty(epsilon); - } - - bool intersects(Rect const &r) const { - return intersects(r) && intersects(r); - } - bool contains(Rect const &r) const { - return contains(r) && contains(r); - } - bool contains(Point const &p) const { - return contains(p) && contains(p); - } - - double area() const { - return extent() * extent(); - } - - double maxExtent() const { - return MAX(extent(), extent()); - } - - double extent(Dim2 const axis) const { - switch (axis) { - case X: return extent(); - case Y: return extent(); - 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(); - case 1: return extent(); - 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::infinity(); - } - - template - double extent() const { - return _max[axis] - _min[axis]; - } - - template - bool isEmpty(double epsilon) const { - return extent() < epsilon; - } - - template - bool intersects(Rect const &r) const { - return _max[axis] >= r._min[axis] && _min[axis] <= r._max[axis]; - } - - template - bool contains(Rect const &r) const { - return contains(r._min) && contains(r._max); - } - - template - bool contains(Point const &p) const { - return p[axis] >= _min[axis] && p[axis] <= _max[axis]; - } - - Point _min, _max; - - friend boost::optional intersection(boost::optional const &, boost::optional const &); - friend Rect union_bounds(Rect const &, Rect const &); -}; - -/** Returns the set of points shared by both rectangles. */ -boost::optional intersection(boost::optional const & a, boost::optional 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 const & a, Rect const &b) { - if (a) { - return union_bounds(*a, b); - } else { - return b; - } -} -inline Rect union_bounds(Rect const &a, boost::optional const & b) { - if (b) { - return union_bounds(a, *b); - } else { - return a; - } -} -inline boost::optional union_bounds(boost::optional const & a, boost::optional 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 const &rect); - operator boost::optional() const { return upgrade(); } - boost::optional 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 - * - * This code is in public domain - */ - -#include - -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 - -#include "libnr/nr-types.h" -#include "libnr/nr-point-fns.h" -#include - -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 5da5d5cf6..000000000 --- a/src/libnr/nr-types.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** \file - * Implements NR::Point::normalize() - */ - -#include -#include <2geom/math-utils.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 - * Class-ifying NRPoint, Nathan Hurst - * - * This code is in public domain - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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..5238353d4 100644 --- a/src/libnr/nr-values.cpp +++ b/src/libnr/nr-values.cpp @@ -1,7 +1,8 @@ #define __NR_VALUES_C__ -#include +#include "libnr/nr-values.h" #include "libnr/nr-rect.h" +#include "libnr/nr-rect-l.h" /* The following predefined objects are for reference @@ -10,11 +11,9 @@ 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}; /** 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 +#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/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 #include "LivarotDefs.h" #include "livarot/livarot-forward.h" -#include "libnr/nr-point.h" #include -#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 +#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 #include #include +#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 +#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/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 743ef573a..28c8d44db 100644 --- a/src/object-edit.cpp +++ b/src/object-edit.cpp @@ -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 -#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( 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 bcb1bf734..be4f1c71d 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 db7cd605b..00caf5d96 100644 --- a/src/rect-context.h +++ b/src/rect-context.h @@ -16,8 +16,8 @@ #include #include +#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 +#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 using vpsc::Rectangle; diff --git a/src/selection.cpp b/src/selection.cpp index 3c4ccccf2..3007a3d1f 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -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 f8fe8e3fa..922dfd530 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -19,6 +19,7 @@ */ #include +#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-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 #include "forward.h" -#include "libnr/nr-point.h" #include #include #include diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index d7bc0053f..9db0d29b2 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 f98a6c8e3..3f1c19295 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -25,6 +25,7 @@ #include #include #include <2geom/rect.h> +#include <2geom/transforms.h> #include #include "display/nr-arena-image.h" @@ -1497,7 +1498,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 424107426..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! } 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 #include +#include <2geom/transforms.h> #include "display/nr-arena.h" #include "display/nr-arena-group.h" -#include +#include "xml/repr.h" #include "enums.h" #include "attributes.h" diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 1feb644ad..35a159192 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -17,6 +17,7 @@ #include "config.h" #include #include +#include <2geom/transforms.h> #include "display/canvas-grid.h" #include "display/guideline.h" @@ -1099,8 +1100,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 #include +#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 754885192..a5e1fbc17 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 6d689c49c..d877e6ae4 100644 --- a/src/spiral-context.h +++ b/src/spiral-context.h @@ -18,8 +18,8 @@ #include #include #include +#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.h b/src/spray-context.h index f6d9a9c0b..fc2340b5e 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 //#include "ui/widget/spray-option.h" #include "ui/dialog/dialog.h" diff --git a/src/star-context.cpp b/src/star-context.cpp index 9f4afb94c..bc0376a20 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 b66e2dd15..c7cba2bf0 100644 --- a/src/star-context.h +++ b/src/star-context.h @@ -16,8 +16,8 @@ #include #include +#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/svg-view.cpp b/src/svg-view.cpp index b35375736..44c874150 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.h b/src/tweak-context.h index 5fbd078ef..d77605a82 100644 --- a/src/tweak-context.h +++ b/src/tweak-context.h @@ -13,7 +13,7 @@ */ #include "event-context.h" -#include +#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 fd7070bab..c631631fb 100644 --- a/src/ui/cache/svg_preview_cache.cpp +++ b/src/ui/cache/svg_preview_cache.cpp @@ -21,6 +21,7 @@ #include #include +#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 #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 #include #include -#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 //for GTK_RESPONSE* types #include #include +#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 #include +#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 +#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 672e1415b..626be7625 100644 --- a/src/ui/widget/page-sizer.cpp +++ b/src/ui/widget/page-sizer.cpp @@ -24,6 +24,7 @@ #include #include #include +#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 #include #include +#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 -#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 #include +#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 #include -#include #include #include +#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 6f3b4dcb9..797525838 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -24,8 +24,9 @@ # include "config.h" #endif -#include #include +#include +#include <2geom/rect.h> #include "box3d-context.h" #include "color-profile-fns.h" @@ -1522,7 +1523,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 +1539,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]; diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index 6c5af0aac..165367954 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -14,7 +14,6 @@ #include -#include "libnr/nr-point.h" #include "forward.h" #include "sp-object.h" #include "message.h" @@ -23,6 +22,7 @@ #include #include +#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 #include #include +#include <2geom/transforms.h> #include "path-prefix.h" #include "preferences.h" diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 01308104e..d0ff38592 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -6777,11 +6777,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 @@ -6834,7 +6834,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); -- cgit v1.2.3 From c213160c0dc2ad5807c23947ae61c8fc93f32b3e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 24 Jun 2011 00:33:00 +0200 Subject: Fix problems in GenericRect constructors (bzr r10347.1.3) --- src/2geom/generic-rect.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h index 9a839d735..d60c4bb0f 100644 --- a/src/2geom/generic-rect.h +++ b/src/2geom/generic-rect.h @@ -77,8 +77,13 @@ public: } /** @brief Create a rectangle from two points. */ GenericRect(CPoint const &a, CPoint const &b) { - f[X] = Interval(a[X], b[X]); - f[Y] = Interval(a[Y], b[Y]); + 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. @@ -114,13 +119,6 @@ public: GenericRect result(xy, xy + wh); return result; } - /** @brief Create rectangle from two points. */ - static GenericRect from_xyxy(C x0, C x1, C y0, C y1) { - CPoint p0(x0, y0); - CPoint p1(x1, y1); - GenericRect result(p0, p1); - return result; - } /// @} /// @name Inspect dimensions. -- cgit v1.2.3 From 653db8249ff01454821f2a2326317f4df9c7ab23 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 24 Jun 2011 01:00:22 +0200 Subject: Pull 2Geom revision 2013 (extra constructors for Rect). (bzr r10347.1.4) --- src/2geom/rect.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/2geom/rect.h b/src/2geom/rect.h index 72b659a81..e9f6cbeb7 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -71,6 +71,7 @@ public: Rect(Interval const &a, Interval const &b) : Base(a,b) {} /** @brief Create a rectangle from two points. */ 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. @@ -89,6 +90,14 @@ 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. -- cgit v1.2.3 From a3e406b2ceafb8fb6b44db0a7816a083d7b3c8ee Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 9 Jul 2011 02:52:06 +0200 Subject: Add SPCanvasArena caching layer. Currently breaks for clipped groups that contain filtered objects (Cairo clipping bug?) (bzr r10347.1.6) --- src/2geom/int-rect.h | 2 + src/display/canvas-arena.cpp | 154 ++++++++++++++++++++++++++++++++++++------ src/display/canvas-arena.h | 4 ++ src/display/nr-arena-item.cpp | 4 +- src/display/sp-canvas-item.h | 4 +- src/display/sp-canvas.cpp | 30 +++++++- src/libnr/nr-rect-l.cpp | 49 ++++++++++++++ src/libnr/nr-rect-l.h | 7 ++ src/libnr/nr-values.cpp | 3 +- 9 files changed, 232 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/2geom/int-rect.h b/src/2geom/int-rect.h index 27fb06dfe..a143b3ac5 100644 --- a/src/2geom/int-rect.h +++ b/src/2geom/int-rect.h @@ -32,6 +32,8 @@ #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 { 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/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 526882921..9c7af1077 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" @@ -482,7 +483,8 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // apply filter if (item->filter && filter) { - item->filter->render(item, ct, area, this_ct, &carea); + NRRectL bgarea(item->arena->canvasarena->cache_area); + item->filter->render(item, ct, &bgarea, this_ct, &carea); } if (needs_intermediate_rendering) { 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 #include #include - -#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 23c6a430e..29729ef6c 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -691,6 +691,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; @@ -734,6 +735,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; } /** @@ -877,6 +879,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. */ @@ -1218,8 +1234,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, @@ -2152,12 +2176,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 @@ -2170,7 +2199,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 } - } /** diff --git a/src/libnr/nr-rect-l.cpp b/src/libnr/nr-rect-l.cpp index 08910a1d6..1cb268266 100644 --- a/src/libnr/nr-rect-l.cpp +++ b/src/libnr/nr-rect-l.cpp @@ -1,3 +1,52 @@ +#include "libnr/nr-rect-l.h" + +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 { + x0 = G_MAXINT32; + y0 = G_MAXINT32; + x1 = G_MININT32; + y1 = G_MININT32; + } +} + +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; +} + /* Local Variables: mode:c++ diff --git a/src/libnr/nr-rect-l.h b/src/libnr/nr-rect-l.h index 6e82bb790..c4c5f5a6d 100644 --- a/src/libnr/nr-rect-l.h +++ b/src/libnr/nr-rect-l.h @@ -2,9 +2,16 @@ #define SEEN_NR_RECT_L_H #include +#include <2geom/int-rect.h> struct NRRectL { 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; }; #endif /* !SEEN_NR_RECT_L_H */ diff --git a/src/libnr/nr-values.cpp b/src/libnr/nr-values.cpp index 5238353d4..06f33b13f 100644 --- a/src/libnr/nr-values.cpp +++ b/src/libnr/nr-values.cpp @@ -9,8 +9,7 @@ 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_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). */ -- cgit v1.2.3 From f8a34926de0258e7b82ec5336aa394834f42b55b Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 10 Jul 2011 01:03:55 +0200 Subject: Redesign the rendering pipeline. Clipping paths are now rasterized. This fixes breakage related to clipped groups and correctly handles nested clipping paths. Also add the ability to use text objects as clipping paths. (bzr r10347.1.7) --- src/display/nr-arena-glyphs.cpp | 31 +++--- src/display/nr-arena-group.cpp | 1 - src/display/nr-arena-item.cpp | 206 ++++++++++++++++++++++++---------------- src/display/nr-arena-shape.cpp | 25 +++-- 4 files changed, 154 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index 0e20f0ddb..185551d31 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -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; @@ -309,9 +310,11 @@ static unsigned int nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, Geom::Affine transform = g->g_transform * group->ctm; cairo_new_path(ct); + cairo_save(ct); ink_cairo_transform(ct, transform); feed_pathvector_to_cairo (ct, *pathv); cairo_fill(ct); + cairo_restore(ct); } return item->state; @@ -352,20 +355,26 @@ 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); + + cairo_save(ct); + ink_cairo_transform(ct, ggroup->ctm); - guint ret = item->state; + 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_fill(ct); + cairo_restore(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 d1e6869aa..5f11c1a6b 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -237,7 +237,6 @@ nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) 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-item.cpp b/src/display/nr-arena-item.cpp index 9c7af1077..534591f82 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -392,119 +392,138 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area using namespace Inkscape; - // clipping and masks - unsigned int state; - - cairo_t *this_ct = ct; - NRRectL *this_area = const_cast(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(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); - } - - // 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) { - } - - Cairo::Context cct(this_ct, true); - Cairo::Context base_ct(ct); - Cairo::RefPtr 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); + /* How the rendering is done. + * + * There is one intermediate surface onto which the object is rendered. + * Clipping, masking and opacity are done with a mask. + * Here are the algorithms: + * a) no clip, no mask, no opacity: direct rendering. + * b) clip, no mask, no opacity: clipping path is rendered and used as a mask. + * c) no clip, mask, no opacity: mask is rendered, luminance is converted to alpha, + * then it is used as a mask. + * d) no clip, no mask, opacity: paint_with_alpha is used. + * e) clip, mask, no opacity: mask is rendered and its luminance is converted to alpha, + * then the clip is composited with it using the IN operator, the result is used + * as a mask. + * f) clip, no mask, opacity: clipping path is rendered with alpha corresponding + * to the opacity value and used as a mask. + * g) no clip, mask, opacity: like e), but the converted mask is composited with + * an uniform fill + * h) clip, mask, opacity: converted mask is composited with the clipping path + * rendered with alpha corresponding to the opacity using the IN operator + */ - // always clip the base context, not the one on the intermediate surface - // this is because filters must be done before clipping - if (item->clip) { - clipsave.save(); - state = nr_arena_item_invoke_clip(ct, item->clip, const_cast(area)); + // handle case a). + 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; } - base_ct.clip(); + return item->state | NR_ARENA_ITEM_STATE_RENDER; } - // render mask on the intermediate context and store it + cairo_surface_t *intermediate = cairo_surface_create_similar( + cairo_get_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); + + // now ict draws on the intermediate surface and carea is its area. + // 1. Render the mask if present. Otherwise initialize the intermediate surface to opaque. 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); + 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; + retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); + goto cleanup; } - if (needs_opacity) { - maskopacitygroup.pop_to_source(); - cct.paint_with_alpha(opacity); + ink_cairo_surface_filter(intermediate, intermediate, MaskLuminanceToAlpha()); + } else { + cairo_set_source_rgba(ict, 0,0,0,1); + cairo_paint(ict); + } + + // 2. Render clipping path and composite it with mask + if (item->clip) { + cairo_push_group_with_content(ict, CAIRO_CONTENT_ALPHA); + cairo_set_source_rgba(ict, 0,0,0,opacity); + // Since clip can be combined with opacity, the result could be incorrect + // for overlapping children. To fix this we use the SOURCE operator + // instead of the default OVER + cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); + state = nr_arena_item_invoke_clip(ict, item->clip, const_cast(area)); + cairo_pop_group_to_source(ict); + if (state & NR_ARENA_ITEM_STATE_INVALID) { + 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_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_with_content(ict, CAIRO_CONTENT_COLOR_ALPHA); + state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags); + cairo_pop_group_to_source(ict); 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) { + // TODO: creating the Cairo context here only to pass it to the filter renderer, + // which calls cairo_get_target almost immediately, is rather silly. + // See whether creating the context can be avoided. + // Could also be fixed in Cairo by fixing cairo_get_target() to return + // the intermediate surface when a group is pushed. + cairo_pattern_t *obj = cairo_get_source(ict); + cairo_surface_t *objs; + cairo_pattern_get_surface(obj, &objs); + cairo_t *tct = cairo_create(objs); + cairo_translate(tct, -carea.x0, -carea.y0); NRRectL bgarea(item->arena->canvasarena->cache_area); - item->filter->render(item, ct, &bgarea, this_ct, &carea); + item->filter->render(item, ct, &bgarea, tct, &carea); + cairo_destroy(tct); } - 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 - } else { - // opacity of non-masked objects must be rendered explicitly - if (needs_opacity) { - cairo_paint_with_alpha(ct, opacity); - } else { - cairo_paint(ct); - } - } - cairo_set_source_rgba(ct,0,0,0,0); + // 5. Render object inside the composited mask + clip + cairo_set_operator(ict, CAIRO_OPERATOR_IN); + if (needs_opacity && !item->clip) { + cairo_paint_with_alpha(ict, opacity); + } else { + cairo_paint(ict); } - return item->state | NR_ARENA_ITEM_STATE_RENDER; + // 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); + + retstate = item->state | NR_ARENA_ITEM_STATE_RENDER; + + cleanup: + cairo_destroy(ict); + cairo_surface_destroy(intermediate); + + return retstate; } unsigned int @@ -530,15 +549,34 @@ 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; + + // The item itself has a clipping path + // Render the 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); + // The source could have had opacity set, but push_group implicitly saves state + cairo_set_source_rgba(ct, 0,0,0,1); + nr_arena_item_invoke_clip(ct, item->clip, area); + } + 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))-> + 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_set_operator(ct, CAIRO_OPERATOR_SOURCE); + } - return item->state; + return retstate; } NRArenaItem * diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index ff87b5134..9bece05b5 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -396,22 +396,21 @@ 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); - - result = item->state; + return item->state; } - return result; + + // TODO: Handling of the clip-rule property / CSS attribute. + // Once the required bits are in SPStyle, this is as trivial as adding a single + // call to cairo_set_fill_rule() before cairo_fill(). + cairo_save(ct); + 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 * -- cgit v1.2.3 From 3099a49e82622b42547088666099f33d0d55b1ad Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 10 Jul 2011 05:33:59 +0200 Subject: Implement handling of the clip-rule property. Partially based on a patch by Andrew Lutomirski. Fixed bugs: - https://launchpad.net/bugs/171243 (bzr r10347.1.8) --- src/display/nr-arena-glyphs.cpp | 10 +++++++++- src/display/nr-arena-group.cpp | 14 +++++++++++++- src/display/nr-arena-shape.cpp | 12 +++++++++--- src/sp-clippath.cpp | 11 +++++++++-- src/style.cpp | 30 ++++++++++++++++++++++++++++-- src/style.h | 4 +++- 6 files changed, 71 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/display/nr-arena-glyphs.cpp b/src/display/nr-arena-glyphs.cpp index 185551d31..b76e87a78 100644 --- a/src/display/nr-arena-glyphs.cpp +++ b/src/display/nr-arena-glyphs.cpp @@ -360,6 +360,14 @@ static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, N NRArenaGroup *ggroup = NR_ARENA_GLYPHS_GROUP(item); 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) { @@ -369,9 +377,9 @@ static unsigned int nr_arena_glyphs_group_clip(cairo_t *ct, NRArenaItem *item, N cairo_save(ct); ink_cairo_transform(ct, g->g_transform); feed_pathvector_to_cairo(ct, pathv); - cairo_fill(ct); cairo_restore(ct); } + cairo_fill(ct); cairo_restore(ct); return item->state; diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 5f11c1a6b..714c4ecff 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -12,6 +12,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "display/canvas-bpath.h" #include "display/nr-arena-group.h" #include "display/nr-filter.h" #include "display/nr-filter-types.h" @@ -234,14 +235,25 @@ 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; + cairo_save(ct); + + // handle clip-rule + if (group->style) { + if (group->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); + } + } + 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; } + cairo_restore(ct); return ret; } diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 9bece05b5..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" @@ -401,10 +402,15 @@ static guint nr_arena_shape_clip(cairo_t *ct, NRArenaItem *item, NRRectL * /*are return item->state; } - // TODO: Handling of the clip-rule property / CSS attribute. - // Once the required bits are in SPStyle, this is as trivial as adding a single - // call to cairo_set_fill_rule() before cairo_fill(). 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); + } + } ink_cairo_transform(ct, shape->ctm); feed_pathvector_to_cairo(ct, shape->curve->get_pathvector()); cairo_fill(ct); 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/style.cpp b/src/style.cpp index 37a784e2a..e66c15494 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -335,6 +335,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. */ @@ -767,6 +773,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) { @@ -1020,7 +1029,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 @@ -1645,6 +1656,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 @@ -1906,7 +1922,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, @@ -2446,6 +2462,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); @@ -2592,6 +2611,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. @@ -2783,6 +2804,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; } @@ -4178,6 +4201,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 a12db388a..3ca1d4dbc 100644 --- a/src/style.h +++ b/src/style.h @@ -327,9 +327,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; -- cgit v1.2.3 From 0d0a5d5453e43fb95e7ff54a59666f72b1c3178d Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 10 Jul 2011 05:37:31 +0200 Subject: Remove irrelevant clip-rule handling bit from NRArenaGroup. (bzr r10347.1.9) --- src/display/nr-arena-group.cpp | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src') diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 714c4ecff..1a67a8404 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -237,23 +237,11 @@ nr_arena_group_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) NRArenaGroup *group = NR_ARENA_GROUP (item); unsigned int ret = item->state; - cairo_save(ct); - - // handle clip-rule - if (group->style) { - if (group->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); - } - } - 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; } - cairo_restore(ct); return ret; } -- cgit v1.2.3 From d35cc479f65a013531ca49b53af8dc9e32671c81 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Mon, 11 Jul 2011 01:05:04 +0200 Subject: Simplify rendering of masked / clipped / translucent items. Handle nested clipping paths correctly. (bzr r10347.1.10) --- src/display/nr-arena-item.cpp | 105 ++++++++++++++++++----------------------- src/display/nr-filter-slot.cpp | 2 +- src/display/nr-filter.cpp | 2 +- 3 files changed, 48 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 534591f82..f3de7a66a 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -410,26 +410,17 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area /* How the rendering is done. * - * There is one intermediate surface onto which the object is rendered. - * Clipping, masking and opacity are done with a mask. - * Here are the algorithms: - * a) no clip, no mask, no opacity: direct rendering. - * b) clip, no mask, no opacity: clipping path is rendered and used as a mask. - * c) no clip, mask, no opacity: mask is rendered, luminance is converted to alpha, - * then it is used as a mask. - * d) no clip, no mask, opacity: paint_with_alpha is used. - * e) clip, mask, no opacity: mask is rendered and its luminance is converted to alpha, - * then the clip is composited with it using the IN operator, the result is used - * as a mask. - * f) clip, no mask, opacity: clipping path is rendered with alpha corresponding - * to the opacity value and used as a mask. - * g) no clip, mask, opacity: like e), but the converted mask is composited with - * an uniform fill - * h) clip, mask, opacity: converted mask is composited with the clipping path - * rendered with alpha corresponding to the opacity using the IN operator + * 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. */ - // handle case a). + // 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) { @@ -440,82 +431,74 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area } cairo_surface_t *intermediate = cairo_surface_create_similar( - cairo_get_target(ct), CAIRO_CONTENT_COLOR_ALPHA, + 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); - // now ict draws on the intermediate surface and carea is its area. - // 1. Render the mask if present. Otherwise initialize the intermediate surface to opaque. - if (item->mask) { - state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ict, item->mask, &carea, NULL, flags); + // 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) { + state = nr_arena_item_invoke_clip(ict, item->clip, const_cast(area)); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } - ink_cairo_surface_filter(intermediate, intermediate, MaskLuminanceToAlpha()); } else { - cairo_set_source_rgba(ict, 0,0,0,1); + // 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); - // 2. Render clipping path and composite it with mask - if (item->clip) { - cairo_push_group_with_content(ict, CAIRO_CONTENT_ALPHA); - cairo_set_source_rgba(ict, 0,0,0,opacity); - // Since clip can be combined with opacity, the result could be incorrect - // for overlapping children. To fix this we use the SOURCE operator - // instead of the default OVER - cairo_set_operator(ict, CAIRO_OPERATOR_SOURCE); - state = nr_arena_item_invoke_clip(ict, item->clip, const_cast(area)); - cairo_pop_group_to_source(ict); + // 2. Render the mask if present and compose it with the clipping path + opacity. + if (item->mask) { + 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) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } + 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); } - // 3. Render object itself - cairo_push_group_with_content(ict, CAIRO_CONTENT_COLOR_ALPHA); + // 3. Render object itself. + cairo_push_group(ict); state = NR_ARENA_ITEM_VIRTUAL (item, render) (ict, item, &carea, pb, flags); - cairo_pop_group_to_source(ict); if (state & NR_ARENA_ITEM_STATE_INVALID) { retstate = (item->state |= NR_ARENA_ITEM_STATE_INVALID); goto cleanup; } - // 4. Apply filter + // 4. Apply filter. if (item->filter && filter) { - // TODO: creating the Cairo context here only to pass it to the filter renderer, - // which calls cairo_get_target almost immediately, is rather silly. - // See whether creating the context can be avoided. - // Could also be fixed in Cairo by fixing cairo_get_target() to return - // the intermediate surface when a group is pushed. - cairo_pattern_t *obj = cairo_get_source(ict); - cairo_surface_t *objs; - cairo_pattern_get_surface(obj, &objs); - cairo_t *tct = cairo_create(objs); - cairo_translate(tct, -carea.x0, -carea.y0); NRRectL bgarea(item->arena->canvasarena->cache_area); - item->filter->render(item, ct, &bgarea, tct, &carea); - cairo_destroy(tct); + 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(). } // 5. Render object inside the composited mask + clip + cairo_pop_group_to_source(ict); cairo_set_operator(ict, CAIRO_OPERATOR_IN); - if (needs_opacity && !item->clip) { - cairo_paint_with_alpha(ict, opacity); - } else { - cairo_paint(ict); - } + 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; @@ -551,14 +534,16 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) unsigned retstate = 0; - // The item itself has a clipping path - // Render the clipping path onto a temporary surface, then composite it with the item + // 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); - // The source could have had opacity set, but push_group implicitly saves state + 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); } if (item->visible && nr_rect_l_test_intersect_ptr(area, &item->bbox)) { @@ -573,7 +558,9 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) 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 retstate; 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.cpp b/src/display/nr-filter.cpp index 10b4084ed..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(item), bgct, bgarea, cairo_get_target(graphic), area, units); + FilterSlot slot(const_cast(item), bgct, bgarea, cairo_get_group_target(graphic), area, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); -- cgit v1.2.3 From d776f783e99f70029d1ec8d6c938468d7e220de0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 12 Jul 2011 03:18:44 +0200 Subject: Compute different bounding boxes in outline mode to fix partial rendering of objects where the clipping path is much larger than the base object or vice versa. Fixes LP #177687. Fixed bugs: - https://launchpad.net/bugs/177687 (bzr r10347.1.11) --- src/display/nr-arena-group.cpp | 7 +-- src/display/nr-arena-item.cpp | 115 ++++++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/display/nr-arena-group.cpp b/src/display/nr-arena-group.cpp index 1a67a8404..1d552fbc2 100644 --- a/src/display/nr-arena-group.cpp +++ b/src/display/nr-arena-group.cpp @@ -13,9 +13,11 @@ */ #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" @@ -164,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); @@ -180,7 +181,7 @@ nr_arena_group_update (NRArenaItem *item, NRRectL *area, NRGC *gc, unsigned int 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); } } diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index f3de7a66a..7e19b9f52 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -215,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), @@ -243,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; } @@ -276,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) { @@ -289,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) { @@ -299,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: @@ -350,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 @@ -389,6 +392,17 @@ 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; @@ -515,16 +529,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", @@ -533,34 +537,36 @@ nr_arena_item_invoke_clip (cairo_t *ct, NRArenaItem *item, NRRectL *area) #endif unsigned retstate = 0; - - // 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); - } + + // 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) { - retstate = ((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); } - } - - 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 retstate; @@ -624,7 +630,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 */ -- cgit v1.2.3 From 7a6b02a54a5516ff17662352903a928f5f5f7afb Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Jul 2011 23:09:35 +0200 Subject: Fix crashes during offscreen rendering, part 1 (bzr r10347.1.12) --- src/display/nr-arena-item.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/display/nr-arena-item.cpp b/src/display/nr-arena-item.cpp index 7e19b9f52..9ca5a7463 100644 --- a/src/display/nr-arena-item.cpp +++ b/src/display/nr-arena-item.cpp @@ -496,7 +496,15 @@ nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area // 4. Apply filter. if (item->filter && filter) { - NRRectL bgarea(item->arena->canvasarena->cache_area); + // 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 { + bgarea = NRRectL(item->arena->canvasarena->cache_area); + } 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() -- cgit v1.2.3 From 019aaf9cd028184da90bc8d7dd558ce14b4e7862 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 14 Jul 2011 20:55:37 +0200 Subject: Remove useless pixmap_gc variable (bzr r10347.1.14) --- src/display/sp-canvas.cpp | 27 ++++++--------------------- src/display/sp-canvas.h | 5 +---- 2 files changed, 7 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index f6446bdd7..d7f34969f 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1061,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; @@ -1121,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); } @@ -1150,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; @@ -1187,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)); } /** @@ -1205,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); } @@ -1626,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; @@ -1694,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(); } @@ -1881,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; @@ -2088,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) diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 32747e7c5..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,7 +140,7 @@ struct SPCanvas { #if ENABLE_LCMS bool enable_cms_display_adj; - Glib::ustring* cms_key; + Glib::ustring cms_key; #endif // ENABLE_LCMS bool is_scrolling; -- cgit v1.2.3 From 34551466a0ddaac96965b730f75cabb1e92ec4d3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 14 Jul 2011 20:56:10 +0200 Subject: Make cms_key in SPDesktopWidget a regular ustring rather than a pointer (bzr r10347.1.15) --- src/widgets/desktop-widget.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 075a24f82..970a094a9 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -544,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 @@ -808,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 } -- cgit v1.2.3