summaryrefslogtreecommitdiffstats
path: root/src/2geom
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2011-08-25 19:16:02 +0000
committerKrzysztof Kosinski <tweenk.pl@gmail.com>2011-08-25 19:16:02 +0000
commit093f4174abc07b4ea523617fccdd8028f2670fea (patch)
tree5aba6cd030bc6b0dbb59ec48e32a0b0364b516bd /src/2geom
parentGerman translation update (diff)
parentReduce default rendering cache size to 64 MiB (diff)
downloadinkscape-093f4174abc07b4ea523617fccdd8028f2670fea.tar.gz
inkscape-093f4174abc07b4ea523617fccdd8028f2670fea.zip
Merge rendering cache branch (GSoC 2011)
(bzr r10579)
Diffstat (limited to 'src/2geom')
-rw-r--r--src/2geom/affine.cpp12
-rw-r--r--src/2geom/affine.h10
-rw-r--r--src/2geom/coord.h38
-rw-r--r--src/2geom/generic-interval.h8
-rw-r--r--src/2geom/generic-rect.h105
-rw-r--r--src/2geom/interval.h3
-rw-r--r--src/2geom/linear.h2
-rw-r--r--src/2geom/rect.h1
-rw-r--r--src/2geom/transforms.h30
9 files changed, 173 insertions, 36 deletions
diff --git a/src/2geom/affine.cpp b/src/2geom/affine.cpp
index 2a1f18d77..c31b9ba90 100644
--- a/src/2geom/affine.cpp
+++ b/src/2geom/affine.cpp
@@ -410,6 +410,9 @@ Affine &Affine::operator*=(Affine const &o) {
}
//TODO: What's this!?!
+/** Given a matrix m such that unit_circle = m*x, this returns the
+ * quadratic form x*A*x = 1.
+ * @relates Affine */
Affine elliptic_quadratic_form(Affine const &m) {
double od = m[0] * m[1] + m[2] * m[3];
Affine ret (m[0]*m[0] + m[1]*m[1], od,
@@ -469,6 +472,15 @@ Eigen::Eigen(double m[2][2]) {
vectors[i] = Point(0,0);
}
+/** @brief Nearness predicate for affine transforms
+ * @returns True if all entries of matrices are within eps of each other */
+bool are_near(Affine const &a, Affine const &b, Coord eps)
+{
+ return are_near(a[0], b[0], eps) && are_near(a[1], b[1], eps) &&
+ are_near(a[2], b[2], eps) && are_near(a[3], b[3], eps) &&
+ are_near(a[4], b[4], eps) && are_near(a[5], b[5], eps);
+}
+
} //namespace Geom
/*
diff --git a/src/2geom/affine.h b/src/2geom/affine.h
index d7a7a0692..22f8bd9f5 100644
--- a/src/2geom/affine.h
+++ b/src/2geom/affine.h
@@ -200,9 +200,8 @@ inline std::ostream &operator<< (std::ostream &out_file, const Geom::Affine &m)
return out_file;
}
-/** Given a matrix m such that unit_circle = m*x, this returns the
- * quadratic form x*A*x = 1.
- * @relates Affine */
+// Affine factories
+Affine from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0));
Affine elliptic_quadratic_form(Affine const &m);
/** Given a matrix (ignoring the translation) this returns the eigen
@@ -215,9 +214,6 @@ public:
Eigen(double M[2][2]);
};
-// Affine factories
-Affine from_basis(const Point x_basis, const Point y_basis, const Point offset=Point(0,0));
-
/** @brief Create an identity matrix.
* This is a convenience function identical to Affine::identity(). */
inline Affine identity() {
@@ -239,6 +235,8 @@ inline Affine Affine::identity() {
return ret; // allow NRVO
}
+bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON);
+
} // end namespace Geom
#endif // LIB2GEOM_SEEN_AFFINE_H
diff --git a/src/2geom/coord.h b/src/2geom/coord.h
index f7bf2c5d0..90e776665 100644
--- a/src/2geom/coord.h
+++ b/src/2geom/coord.h
@@ -34,6 +34,7 @@
#include <cmath>
#include <limits>
+#include <boost/operators.hpp>
#include <2geom/forward.h>
namespace Geom {
@@ -62,6 +63,9 @@ inline bool rel_error_bound(Coord a, Coord b, double eps=EPSILON) { return a <=
template <typename C>
struct CoordTraits {};
+// NOTE: operator helpers for Rect and Interval are defined here.
+// This is to avoid increasing their size through multiple inheritance.
+
template<>
struct CoordTraits<IntCoord> {
typedef IntPoint PointType;
@@ -69,6 +73,22 @@ struct CoordTraits<IntCoord> {
typedef OptIntInterval OptIntervalType;
typedef IntRect RectType;
typedef OptIntRect OptRectType;
+
+ typedef
+ boost::equality_comparable< IntervalType
+ , boost::additive< IntervalType
+ , boost::additive< IntervalType, IntCoord
+ , boost::orable< IntervalType
+ > > > >
+ IntervalOps;
+
+ typedef
+ boost::equality_comparable< RectType
+ , boost::orable< RectType
+ , boost::orable< RectType, OptRectType
+ , boost::additive< RectType, PointType
+ > > > >
+ RectOps;
};
template<>
@@ -78,6 +98,24 @@ struct CoordTraits<Coord> {
typedef OptInterval OptIntervalType;
typedef Rect RectType;
typedef OptRect OptRectType;
+
+ typedef
+ boost::equality_comparable< IntervalType
+ , boost::additive< IntervalType
+ , boost::multipliable< IntervalType
+ , boost::orable< IntervalType
+ , boost::arithmetic< IntervalType, Coord
+ > > > > >
+ IntervalOps;
+
+ typedef
+ boost::equality_comparable< RectType
+ , boost::orable< RectType
+ , boost::orable< RectType, OptRectType
+ , boost::additive< RectType, PointType
+ , boost::multipliable< RectType, Affine
+ > > > > >
+ RectOps;
};
} // end namespace Geom
diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h
index a32e97d4b..0212da676 100644
--- a/src/2geom/generic-interval.h
+++ b/src/2geom/generic-interval.h
@@ -34,7 +34,7 @@
#include <cassert>
#include <boost/none.hpp>
#include <boost/optional.hpp>
-#include <boost/operators.hpp>
+#include <2geom/coord.h>
namespace Geom {
@@ -47,11 +47,7 @@ class GenericOptInterval;
*/
template <typename C>
class GenericInterval
- : boost::equality_comparable< GenericInterval<C>
- , boost::additive< GenericInterval<C>
- , boost::additive< GenericInterval<C>, C
- , boost::orable< GenericInterval<C>
- > > > >
+ : CoordTraits<C>::IntervalOps
{
typedef GenericInterval<C> Self;
protected:
diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h
index 2db30dfa9..efe499809 100644
--- a/src/2geom/generic-rect.h
+++ b/src/2geom/generic-rect.h
@@ -42,6 +42,7 @@
#include <limits>
#include <boost/optional.hpp>
+#include <2geom/coord.h>
namespace Geom {
@@ -54,11 +55,7 @@ class GenericOptRect;
*/
template <typename C>
class GenericRect
- : boost::additive< typename CoordTraits<C>::RectType, typename CoordTraits<C>::PointType
- , boost::equality_comparable< typename CoordTraits<C>::RectType
- , boost::orable< typename CoordTraits<C>::RectType
- , boost::orable< typename CoordTraits<C>::RectType, typename CoordTraits<C>::OptRectType
- > > > >
+ : CoordTraits<C>::RectOps
{
typedef typename CoordTraits<C>::IntervalType CInterval;
typedef typename CoordTraits<C>::PointType CPoint;
@@ -131,15 +128,22 @@ public:
/// @name Inspect dimensions.
/// @{
- CInterval &operator[](unsigned i) { return f[i]; }
+ CInterval &operator[](unsigned i) { return f[i]; }
CInterval const &operator[](unsigned i) const { return f[i]; }
+ CInterval &operator[](Dim2 d) { return f[d]; }
+ CInterval const &operator[](Dim2 d) const { return f[d]; }
+ /** @brief Get the corner of the rectangle with smallest coordinate values.
+ * In 2Geom standard coordinate system, this means upper left. */
CPoint min() const { return CPoint(f[X].min(), f[Y].min()); }
+ /** @brief Get the corner of the rectangle with largest coordinate values.
+ * In 2Geom standard coordinate system, this means lower right. */
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. */
+ * Returns corners in the direction of growing angles, starting from
+ * the one given by min(). For the standard coordinate system used
+ * in 2Geom (+Y downwards), this means clockwise starting from
+ * the upper left. */
CPoint corner(unsigned i) const {
switch(i % 4) {
case 0: return CPoint(f[X].min(), f[Y].min());
@@ -196,10 +200,10 @@ public:
}
/** @brief Check whether the rectangles have any common points.
- * A non-empty rectangle will not intersect empty rectangles. */
+ * Empty rectangles will not intersect with any other rectangle. */
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. */
+ * Empty rectangles will be contained in any non-empty rectangle. */
inline bool contains(OptCRect const &r) const;
/** @brief Check whether the given point is within the rectangle. */
@@ -224,11 +228,11 @@ public:
void expandTo(CPoint const &p) {
f[X].expandTo(p[X]); f[Y].expandTo(p[Y]);
}
- /** @brief Enlarge the rectangle to contain the given rectangle. */
+ /** @brief Enlarge the rectangle to contain the argument. */
void unionWith(CRect const &b) {
f[X].unionWith(b[X]); f[Y].unionWith(b[Y]);
}
- /** @brief Enlarge the rectangle to contain the given rectangle.
+ /** @brief Enlarge the rectangle to contain the argument.
* Unioning with an empty rectangle results in no changes. */
void unionWith(OptCRect const &b);
@@ -244,7 +248,8 @@ public:
* This will expand the width by the X coordinate of the point in both directions
* and the height by Y coordinate of the point. Negative coordinate values will
* shrink the rectangle. If <code>-p[X]</code> is larger than half of the width,
- * the X interval will contain only the X coordinate of the midpoint; same for height. */
+ * 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]);
}
@@ -297,30 +302,66 @@ class GenericOptRect
typedef typename CoordTraits<C>::OptRectType OptCRect;
typedef boost::optional<CRect> Base;
public:
+ /// @name Create potentially empty rectangles.
+ /// @{
GenericOptRect() : Base() {}
GenericOptRect(GenericRect<C> const &a) : Base(CRect(a)) {}
GenericOptRect(CPoint const &a, CPoint const &b) : Base(CRect(a, b)) {}
- /**
- * Creates an empty OptRect when one of the argument intervals is empty.
- */
+ /// 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 Create a rectangle from a range of points.
+ * The resulting rectangle will contain all ponts from the range.
+ * If the range contains no points, the result will be an empty rectangle.
+ * The return type of iterators must be convertible to the corresponding
+ * point type (Point or IntPoint).
+ * @param start Beginning of the range
+ * @param end End of the range
+ * @return Rectangle that contains all points from [start, end). */
+ template <typename InputIterator>
+ static OptCRect from_range(InputIterator start, InputIterator end) {
+ OptCRect result;
+ for (; start != end; ++start) {
+ result.expandTo(*start);
+ }
+ return result;
+ }
+ /// @}
+ /// @name Check other rectangles and points for inclusion.
+ /// @{
/** @brief Check for emptiness. */
inline bool isEmpty() const { return !*this; };
-
+ /** @brief Check whether the rectangles have any common points.
+ * Empty rectangles will not intersect with any other rectangle. */
bool intersects(CRect const &r) const { return r.intersects(*this); }
+ /** @brief Check whether the rectangle includes all points in the given rectangle.
+ * Empty rectangles will be contained in any non-empty rectangle. */
bool contains(CRect const &r) const { return *this && (*this)->contains(r); }
+ /** @brief Check whether the rectangles have any common points.
+ * Empty rectangles will not intersect with any other rectangle.
+ * Two empty rectangles will not intersect each other. */
bool intersects(OptCRect const &r) const { return *this && (*this)->intersects(r); }
+ /** @brief Check whether the rectangle includes all points in the given rectangle.
+ * Empty rectangles will be contained in any non-empty rectangle.
+ * An empty rectangle will not contain other empty rectangles. */
bool contains(OptCRect const &r) const { return *this && (*this)->contains(r); }
+ /** @brief Check whether the given point is within the rectangle.
+ * An empty rectangle will not contain any points. */
bool contains(CPoint const &p) const { return *this && (*this)->contains(p); }
+ /// @}
+ /// @name Modify the potentially empty rectangle.
+ /// @{
+ /** @brief Enlarge the rectangle to contain the argument.
+ * If this rectangle is empty, after callng this method it will
+ * be equal to the argument. */
void unionWith(CRect const &b) {
if (*this) {
(*this)->unionWith(b);
@@ -328,9 +369,16 @@ public:
*this = b;
}
}
+ /** @brief Enlarge the rectangle to contain the argument.
+ * Unioning with an empty rectangle results in no changes.
+ * If this rectangle is empty, after calling this method it will
+ * be equal to the argument. */
void unionWith(OptCRect const &b) {
if (b) unionWith(*b);
}
+ /** @brief Leave only the area overlapping with the argument.
+ * If the rectangles do not have any points in common, after calling
+ * this method the rectangle will be empty. */
void intersectWith(CRect const &b) {
if (!*this) return;
OptCInterval x = (**this)[X] & b[X], y = (**this)[Y] & b[Y];
@@ -340,6 +388,9 @@ public:
*(static_cast<Base*>(this)) = boost::none;
}
}
+ /** @brief Leave only the area overlapping with the argument.
+ * If the argument is empty or the rectangles do not have any points
+ * in common, after calling this method the rectangle will be empty. */
void intersectWith(OptCRect const &b) {
if (b) {
intersectWith(*b);
@@ -347,18 +398,36 @@ public:
*(static_cast<Base*>(this)) = boost::none;
}
}
+ /** @brief Create or enlarge the rectangle to contain the given point.
+ * If the rectangle is empty, after calling this method it will be non-empty
+ * and it will contain only the given point. */
+ void expandTo(CPoint const &p) {
+ if (*this) {
+ (*this).expandTo(p);
+ } else {
+ *this = CRect(p, p);
+ }
+ }
+ /// @}
+
+ /// @name Operators
+ /// @{
+ /** @brief Union with @a b */
GenericOptRect<C> &operator|=(OptCRect const &b) {
unionWith(b);
return *this;
}
+ /** @brief Intersect with @a b */
GenericOptRect<C> &operator&=(CRect const &b) {
intersectWith(b);
return *this;
}
+ /** @brief Intersect with @a b */
GenericOptRect<C> &operator&=(OptCRect const &b) {
intersectWith(b);
return *this;
}
+ /// @}
};
template <typename C>
diff --git a/src/2geom/interval.h b/src/2geom/interval.h
index e95da4811..711eaa5e2 100644
--- a/src/2geom/interval.h
+++ b/src/2geom/interval.h
@@ -63,9 +63,6 @@ typedef GenericOptInterval<Coord> OptInterval;
*/
class Interval
: public GenericInterval<Coord>
- , boost::multipliable< Interval
- , boost::multiplicative< Interval, Coord
- > >
{
typedef GenericInterval<Coord> Base;
public:
diff --git a/src/2geom/linear.h b/src/2geom/linear.h
index df6dd9904..448ab3bb7 100644
--- a/src/2geom/linear.h
+++ b/src/2geom/linear.h
@@ -55,7 +55,7 @@ class SBasis;
class Linear{
public:
double a[2];
- Linear() {}
+ Linear() { a[0] = 0; a[1] = 0; }
Linear(double aa, double b) {a[0] = aa; a[1] = b;}
Linear(double aa) {a[0] = aa; a[1] = aa;}
diff --git a/src/2geom/rect.h b/src/2geom/rect.h
index f7d331523..b79a0a04f 100644
--- a/src/2geom/rect.h
+++ b/src/2geom/rect.h
@@ -59,7 +59,6 @@ typedef GenericOptRect<Coord> OptRect;
*/
class Rect
: public GenericRect<Coord>
- , boost::multipliable< Rect, Affine >
{
typedef GenericRect<Coord> Base;
public:
diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h
index 5627e8b6f..eaf869056 100644
--- a/src/2geom/transforms.h
+++ b/src/2geom/transforms.h
@@ -45,10 +45,11 @@ namespace Geom {
* @ingroup Concepts */
template <typename T>
struct TransformConcept {
- T t;
+ T t, t2;
Affine m;
Point p;
bool bool_;
+ Coord epsilon;
void constraints() {
m = t; //implicit conversion
m *= t;
@@ -63,6 +64,8 @@ struct TransformConcept {
bool_ = (t != t);
t = T::identity();
t = t.inverse();
+ bool_ = are_near(t, t2);
+ bool_ = are_near(t, t2, epsilon);
}
};
@@ -130,6 +133,10 @@ public:
friend class Point;
};
+inline bool are_near(Translate const &a, Translate const &b, Coord eps=EPSILON) {
+ return are_near(a[X], b[X], eps) && are_near(a[Y], b[Y], eps);
+}
+
/** @brief Scaling from the origin.
* During scaling, the point (0,0) will not move. To obtain a scale with a different
* invariant point, combine with translation to the origin and back.
@@ -164,6 +171,10 @@ public:
friend class Point;
};
+inline bool are_near(Scale const &a, Scale const &b, Coord eps=EPSILON) {
+ return are_near(a[X], b[X], eps) && are_near(a[Y], b[Y], eps);
+}
+
/** @brief Rotation around the origin.
* Combine with translations to the origin and back to get a rotation around a different point.
* @ingroup Transforms */
@@ -207,6 +218,10 @@ public:
friend class Point;
};
+inline bool are_near(Rotate const &a, Rotate const &b, Coord eps=EPSILON) {
+ return are_near(a[X], b[X], eps) && are_near(a[Y], b[Y], eps);
+}
+
/** @brief Common base for shearing transforms.
* This class is an implementation detail and should not be used directly.
* @ingroup Transforms */
@@ -241,6 +256,10 @@ public:
operator Affine() const { Affine ret(1, 0, f, 1, 0, 0); return ret; }
};
+inline bool are_near(HShear const &a, HShear const &b, Coord eps=EPSILON) {
+ return are_near(a.factor(), b.factor(), eps);
+}
+
/** @brief Vertical shearing.
* Points on the Y axis will not move. Combine with translations to get a shear
* with a different invariant line.
@@ -253,6 +272,10 @@ public:
operator Affine() const { Affine ret(1, f, 0, 1, 0, 0); return ret; }
};
+inline bool are_near(VShear const &a, VShear const &b, Coord eps=EPSILON) {
+ return are_near(a.factor(), b.factor(), eps);
+}
+
/** @brief Combination of a translation and uniform scale.
* The translation part is applied first, then the result is scaled from the new origin.
* This way when the class is used to accumulate a zoom transform, trans always points
@@ -295,6 +318,11 @@ public:
friend class Affine;
};
+inline bool are_near(Zoom const &a, Zoom const &b, Coord eps=EPSILON) {
+ return are_near(a.scale(), b.scale(), eps) &&
+ are_near(a.translation(), b.translation(), eps);
+}
+
/** @brief Specialization of exponentiation for Scale.
* @relates Scale */
template<>