summaryrefslogtreecommitdiffstats
path: root/src/2geom
diff options
context:
space:
mode:
Diffstat (limited to 'src/2geom')
-rw-r--r--src/2geom/affine.cpp60
-rw-r--r--src/2geom/coord.h42
-rw-r--r--src/2geom/forward.h4
-rw-r--r--src/2geom/generic-interval.h31
-rw-r--r--src/2geom/generic-rect.h36
-rw-r--r--src/2geom/interval.h43
-rw-r--r--src/2geom/linear.h2
-rw-r--r--src/2geom/rect.h42
8 files changed, 182 insertions, 78 deletions
diff --git a/src/2geom/affine.cpp b/src/2geom/affine.cpp
index c31b9ba90..1be5d9fe8 100644
--- a/src/2geom/affine.cpp
+++ b/src/2geom/affine.cpp
@@ -144,6 +144,7 @@ bool Affine::isNonzeroTranslation(Coord eps) const {
0 & b & 0 \\
0 & 0 & 1 \end{array}\right]\f$. */
bool Affine::isScale(Coord eps) const {
+ if (isSingular(eps)) return false;
return are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
}
@@ -156,6 +157,7 @@ bool Affine::isScale(Coord eps) const {
0 & b & 0 \\
0 & 0 & 1 \end{array}\right]\f$ and \f$a, b \neq 1\f$. */
bool Affine::isNonzeroScale(Coord eps) const {
+ if (isSingular(eps)) return false;
return (!are_near(_c[0], 1.0, eps) || !are_near(_c[3], 1.0, eps)) && //NOTE: these are the diags, and the next line opposite diags
are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
@@ -165,11 +167,12 @@ bool Affine::isNonzeroScale(Coord eps) const {
* @param eps Numerical tolerance
* @return True iff the matrix is of the form
* \f$\left[\begin{array}{ccc}
- a & 0 & 0 \\
- 0 & a & 0 \\
- 0 & 0 & 1 \end{array}\right]\f$. */
+ a_1 & 0 & 0 \\
+ 0 & a_2 & 0 \\
+ 0 & 0 & 1 \end{array}\right]\f$ where \f$|a_1| = |a_2|\f$. */
bool Affine::isUniformScale(Coord eps) const {
- return are_near(_c[0], _c[3], eps) &&
+ if (isSingular(eps)) return false;
+ return are_near(fabs(_c[0]), fabs(_c[3]), eps) &&
are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
}
@@ -178,11 +181,16 @@ bool Affine::isUniformScale(Coord eps) const {
* @param eps Numerical tolerance
* @return True iff the matrix is of the form
* \f$\left[\begin{array}{ccc}
- a & 0 & 0 \\
- 0 & a & 0 \\
- 0 & 0 & 1 \end{array}\right]\f$ and \f$a \neq 1\f$. */
+ a_1 & 0 & 0 \\
+ 0 & a_2 & 0 \\
+ 0 & 0 & 1 \end{array}\right]\f$ where \f$|a_1| = |a_2|\f$
+ * and \f$a_1, a_2 \neq 1\f$. */
bool Affine::isNonzeroUniformScale(Coord eps) const {
- return !are_near(_c[0], 1.0, eps) && are_near(_c[0], _c[3], eps) &&
+ if (isSingular(eps)) return false;
+ // we need to test both c0 and c3 to handle the case of flips,
+ // which should be treated as nonzero uniform scales
+ return !(are_near(_c[0], 1.0, eps) && are_near(_c[3], 1.0, eps)) &&
+ are_near(fabs(_c[0]), fabs(_c[3]), eps) &&
are_near(_c[1], 0.0, eps) && are_near(_c[2], 0.0, eps) &&
are_near(_c[4], 0.0, eps) && are_near(_c[5], 0.0, eps);
}
@@ -266,15 +274,17 @@ bool Affine::isNonzeroVShear(Coord eps) const {
}
/** @brief Check whether this matrix represents zooming.
- * Zooming is any combination of translation and uniform scaling. It preserves angles, ratios
- * of distances between arbitrary points and unit vectors of line segments.
+ * Zooming is any combination of translation and uniform non-flipping scaling.
+ * It preserves angles, ratios of distances between arbitrary points
+ * and unit vectors of line segments.
* @param eps Numerical tolerance
- * @return True iff the matrix is of the form
+ * @return True iff the matrix is invertible and of the form
* \f$\left[\begin{array}{ccc}
a & 0 & 0 \\
0 & a & 0 \\
b & c & 1 \end{array}\right]\f$. */
bool Affine::isZoom(Coord eps) const {
+ if (isSingular(eps)) return false;
return are_near(_c[0], _c[3], eps) && are_near(_c[1], 0, eps) && are_near(_c[2], 0, eps);
}
@@ -290,30 +300,42 @@ bool Affine::preservesArea(Coord eps) const
}
/** @brief Check whether the transformation preserves angles between lines.
- * This means that the transformation can be any combination of translation, uniform scaling
- * and rotation.
+ * This means that the transformation can be any combination of translation, uniform scaling,
+ * rotation and flipping.
* @param eps Numerical tolerance
* @return True iff the matrix is of the form
* \f$\left[\begin{array}{ccc}
- a & b & 0 \\
- -b & a & 0 \\
- c & d & 1 \end{array}\right]\f$. */
+ a & b & 0 \\
+ -b & a & 0 \\
+ c & d & 1 \end{array}\right]\f$ or
+ \f$\left[\begin{array}{ccc}
+ -a & b & 0 \\
+ b & a & 0 \\
+ c & d & 1 \end{array}\right]\f$. */
bool Affine::preservesAngles(Coord eps) const
{
- return are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps);
+ if (isSingular(eps)) return false;
+ return (are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps)) ||
+ (are_near(_c[0], -_c[3], eps) && are_near(_c[1], _c[2], eps));
}
/** @brief Check whether the transformation preserves distances between points.
- * This means that the transformation can be any combination of translation and rotation.
+ * This means that the transformation can be any combination of translation,
+ * rotation and flipping.
* @param eps Numerical tolerance
* @return True iff the matrix is of the form
* \f$\left[\begin{array}{ccc}
a & b & 0 \\
-b & a & 0 \\
+ c & d & 1 \end{array}\right]\f$ or
+ \f$\left[\begin{array}{ccc}
+ -a & b & 0 \\
+ b & a & 0 \\
c & d & 1 \end{array}\right]\f$ and \f$a^2 + b^2 = 1\f$. */
bool Affine::preservesDistances(Coord eps) const
{
- return are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps) &&
+ return ((are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps)) ||
+ (are_near(_c[0], -_c[3], eps) && are_near(_c[1], _c[2], eps))) &&
are_near(_c[0] * _c[0] + _c[1] * _c[1], 1.0, eps);
}
diff --git a/src/2geom/coord.h b/src/2geom/coord.h
index 90e776665..78a852f32 100644
--- a/src/2geom/coord.h
+++ b/src/2geom/coord.h
@@ -75,18 +75,18 @@ struct CoordTraits<IntCoord> {
typedef OptIntRect OptRectType;
typedef
- boost::equality_comparable< IntervalType
- , boost::additive< IntervalType
- , boost::additive< IntervalType, IntCoord
- , boost::orable< IntervalType
+ boost::equality_comparable< IntInterval
+ , boost::additive< IntInterval
+ , boost::additive< IntInterval, IntCoord
+ , boost::orable< IntInterval
> > > >
IntervalOps;
typedef
- boost::equality_comparable< RectType
- , boost::orable< RectType
- , boost::orable< RectType, OptRectType
- , boost::additive< RectType, PointType
+ boost::equality_comparable< IntRect
+ , boost::orable< IntRect
+ , boost::orable< IntRect, OptIntRect
+ , boost::additive< IntRect, IntPoint
> > > >
RectOps;
};
@@ -100,21 +100,23 @@ struct CoordTraits<Coord> {
typedef OptRect OptRectType;
typedef
- boost::equality_comparable< IntervalType
- , boost::additive< IntervalType
- , boost::multipliable< IntervalType
- , boost::orable< IntervalType
- , boost::arithmetic< IntervalType, Coord
- > > > > >
+ boost::equality_comparable< Interval
+ , boost::equality_comparable< Interval, IntInterval
+ , boost::additive< Interval
+ , boost::multipliable< Interval
+ , boost::orable< Interval
+ , boost::arithmetic< Interval, Coord
+ > > > > > >
IntervalOps;
typedef
- boost::equality_comparable< RectType
- , boost::orable< RectType
- , boost::orable< RectType, OptRectType
- , boost::additive< RectType, PointType
- , boost::multipliable< RectType, Affine
- > > > > >
+ boost::equality_comparable< Rect
+ , boost::equality_comparable< Rect, IntRect
+ , boost::orable< Rect
+ , boost::orable< Rect, OptRect
+ , boost::additive< Rect, Point
+ , boost::multipliable< Rect, Affine
+ > > > > > >
RectOps;
};
diff --git a/src/2geom/forward.h b/src/2geom/forward.h
index 0dbd9fa94..70cac1f7d 100644
--- a/src/2geom/forward.h
+++ b/src/2geom/forward.h
@@ -49,13 +49,13 @@ class Ray;
template <typename> class GenericInterval;
template <typename> class GenericOptInterval;
class Interval;
-typedef GenericOptInterval<Coord> OptInterval;
+class OptInterval;
typedef GenericInterval<IntCoord> IntInterval;
typedef GenericOptInterval<IntCoord> OptIntInterval;
template <typename> class GenericRect;
template <typename> class GenericOptRect;
class Rect;
-typedef GenericOptRect<Coord> OptRect;
+class OptRect;
typedef GenericRect<IntCoord> IntRect;
typedef GenericOptRect<IntCoord> OptIntRect;
diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h
index 0212da676..87d3be2c1 100644
--- a/src/2geom/generic-interval.h
+++ b/src/2geom/generic-interval.h
@@ -49,6 +49,7 @@ template <typename C>
class GenericInterval
: CoordTraits<C>::IntervalOps
{
+ typedef typename CoordTraits<C>::IntervalType CInterval;
typedef GenericInterval<C> Self;
protected:
C _b[2];
@@ -76,15 +77,15 @@ public:
* @param end End of the range
* @return Interval that contains all values from [start, end). */
template <typename InputIterator>
- static Self from_range(InputIterator start, InputIterator end) {
+ static CInterval from_range(InputIterator start, InputIterator end) {
assert(start != end);
- Self result(*start++);
+ CInterval 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);
+ static CInterval from_array(C const *c, unsigned n) {
+ CInterval result = from_range(c, c+n);
return result;
}
/// @}
@@ -94,7 +95,7 @@ public:
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; }
+ C middle() const { return (max() + min()) / 2; }
bool isSingular() const { return min() == max(); }
/// @}
@@ -105,11 +106,11 @@ public:
return min() <= val && val <= max();
}
/** @brief Check whether the interval includes the given interval. */
- bool contains(Self const &val) const {
+ bool contains(CInterval const &val) const {
return min() <= val.min() && val.max() <= max();
}
/** @brief Check whether the intervals have any common elements. */
- bool intersects(Self const &val) const {
+ bool intersects(CInterval const &val) const {
return contains(val.min()) || contains(val.max()) || val.contains(*this);
}
/// @}
@@ -159,7 +160,7 @@ public:
* 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) {
+ void unionWith(CInterval const &a) {
if(a._b[0] < _b[0]) _b[0] = a._b[0];
if(a._b[1] > _b[1]) _b[1] = a._b[1];
}
@@ -187,7 +188,7 @@ public:
/** @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) {
+ Self &operator+=(CInterval const &o) {
_b[0] += o._b[0];
_b[1] += o._b[1];
return *this;
@@ -196,7 +197,7 @@ public:
* 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) {
+ Self &operator-=(CInterval const &o) {
// equal to *this += -o
_b[0] -= o._b[1];
_b[1] -= o._b[0];
@@ -205,12 +206,12 @@ public:
/** @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) {
+ Self &operator|=(CInterval const &o) {
unionWith(o);
return *this;
}
/** @brief Test for interval equality. */
- bool operator==(Self const &other) const {
+ bool operator==(CInterval const &other) const {
return min() == other.min() && max() == other.max();
}
/// @}
@@ -230,15 +231,15 @@ inline GenericInterval<C> unify(GenericInterval<C> const &a, GenericInterval<C>
template <typename C>
class GenericOptInterval
: public boost::optional<typename CoordTraits<C>::IntervalType>
- , boost::orable< GenericOptInterval<C>, typename CoordTraits<C>::OptIntervalType
- , boost::andable< GenericOptInterval<C>, typename CoordTraits<C>::OptIntervalType
+ , boost::orable< GenericOptInterval<C>
+ , boost::andable< GenericOptInterval<C>
> >
{
typedef typename CoordTraits<C>::IntervalType CInterval;
typedef typename CoordTraits<C>::OptIntervalType OptCInterval;
typedef boost::optional<CInterval> Base;
public:
- /// @name Create optionally empty intervals of integers.
+ /// @name Create optionally empty intervals.
/// @{
/** @brief Create an empty interval. */
GenericOptInterval() : Base() {}
diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h
index efe499809..719b37385 100644
--- a/src/2geom/generic-rect.h
+++ b/src/2geom/generic-rect.h
@@ -135,10 +135,10 @@ public:
/** @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()); }
+ CPoint min() const { CPoint p(f[X].min(), f[Y].min()); return p; }
/** @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()); }
+ CPoint max() const { CPoint p(f[X].max(), f[Y].max()); return p; }
/** @brief Return the n-th corner of the rectangle.
* Returns corners in the direction of growing angles, starting from
* the one given by min(). For the standard coordinate system used
@@ -242,7 +242,15 @@ public:
* 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);
+ expandBy(amount, amount);
+ }
+ /** @brief Expand the rectangle in both directions.
+ * Note that this is different from scaling. Negative values wil shrink the
+ * rectangle. If <code>-x</code> is larger than
+ * half of the width, the X interval will contain only the X coordinate
+ * of the midpoint; same for height. */
+ void expandBy(C x, C y) {
+ f[X].expandBy(x); f[Y].expandBy(y);
}
/** @brief Expand the rectangle by the coordinates of the given point.
* This will expand the width by the X coordinate of the point in both directions
@@ -250,8 +258,8 @@ public:
* shrink the rectangle. If <code>-p[X]</code> is larger than half of the width,
* the X interval will contain only the X coordinate of the midpoint;
* same for height. */
- void expandBy(CPoint const &p) {
- f[X].expandBy(p[X]); f[Y].expandBy(p[Y]);
+ void expandBy(CPoint const &p) {
+ expandBy(p[X], p[Y]);
}
/// @}
@@ -279,7 +287,7 @@ public:
return *this;
}
/** @brief Test for equality of rectangles. */
- bool operator==(GenericRect<C> const &o) const { return f[X] == o[X] && f[Y] == o[Y]; }
+ bool operator==(CRect const &o) const { return f[X] == o[X] && f[Y] == o[Y]; }
/// @}
};
@@ -290,10 +298,12 @@ public:
template <typename C>
class GenericOptRect
: public boost::optional<typename CoordTraits<C>::RectType>
+ , boost::equality_comparable< typename CoordTraits<C>::OptRectType
+ , boost::equality_comparable< typename CoordTraits<C>::OptRectType, typename CoordTraits<C>::RectType
, boost::orable< typename CoordTraits<C>::OptRectType
, boost::andable< typename CoordTraits<C>::OptRectType
, boost::andable< typename CoordTraits<C>::OptRectType, typename CoordTraits<C>::RectType
- > > >
+ > > > > >
{
typedef typename CoordTraits<C>::IntervalType CInterval;
typedef typename CoordTraits<C>::OptIntervalType OptCInterval;
@@ -307,6 +317,7 @@ public:
GenericOptRect() : Base() {}
GenericOptRect(GenericRect<C> const &a) : Base(CRect(a)) {}
GenericOptRect(CPoint const &a, CPoint const &b) : Base(CRect(a, b)) {}
+ GenericOptRect(C x0, C y0, C x1, C y1) : Base(CRect(x0, y0, x1, y1)) {}
/// 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) {
@@ -314,6 +325,7 @@ public:
}
// 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.
@@ -427,6 +439,16 @@ public:
intersectWith(b);
return *this;
}
+ /** @brief Test for equality.
+ * All empty rectangles are equal. */
+ bool operator==(OptCRect const &other) const {
+ if (!*this != !other) return false;
+ return *this ? (**this == *other) : true;
+ }
+ bool operator==(CRect const &other) const {
+ if (!*this) return false;
+ return **this == other;
+ }
/// @}
};
diff --git a/src/2geom/interval.h b/src/2geom/interval.h
index 711eaa5e2..b1fac04d9 100644
--- a/src/2geom/interval.h
+++ b/src/2geom/interval.h
@@ -47,12 +47,6 @@
namespace Geom {
-/**
- * @brief Range of real numbers that can be empty.
- * @ingroup Primitives
- */
-typedef GenericOptInterval<Coord> OptInterval;
-
/**
* @brief Range of real numbers that is never empty.
*
@@ -128,8 +122,6 @@ public:
/// @name Operators
/// @{
- inline operator OptInterval() { return OptInterval(*this); }
-
// IMPL: ScalableConcept
/** @brief Scale an interval */
Interval &operator*=(Coord s) {
@@ -158,6 +150,12 @@ public:
expandTo(mx * o.max());
return *this;
}
+ bool operator==(IntInterval const &ii) const {
+ return min() == Coord(ii.min()) && max() == Coord(ii.max());
+ }
+ bool operator==(Interval const &other) const {
+ return Base::operator==(other);
+ }
/// @}
/// @name Rounding to integer values
@@ -177,6 +175,35 @@ public:
/// @}
};
+/**
+ * @brief Range of real numbers that can be empty.
+ * @ingroup Primitives
+ */
+class OptInterval
+ : public GenericOptInterval<Coord>
+{
+ typedef GenericOptInterval<Coord> Base;
+public:
+ /// @name Create optionally empty intervals.
+ /// @{
+ /** @brief Create an empty interval. */
+ OptInterval() : Base() {}
+ /** @brief Wrap an existing interval. */
+ OptInterval(Interval const &a) : Base(a) {}
+ /** @brief Create an interval containing a single point. */
+ OptInterval(Coord u) : Base(u) {}
+ /** @brief Create an interval containing a range of numbers. */
+ OptInterval(Coord u, Coord v) : Base(u,v) {}
+ OptInterval(Base const &b) : Base(b) {}
+
+ /** @brief Promote from IntInterval. */
+ OptInterval(IntInterval const &i) : Base(Interval(i)) {}
+ /** @brief Promote from OptIntInterval. */
+ OptInterval(OptIntInterval const &i) : Base() {
+ if (i) *this = Interval(*i);
+ }
+};
+
// functions required for Python bindings
inline Interval unify(Interval const &a, Interval const &b)
{
diff --git a/src/2geom/linear.h b/src/2geom/linear.h
index 448ab3bb7..df6dd9904 100644
--- a/src/2geom/linear.h
+++ b/src/2geom/linear.h
@@ -55,7 +55,7 @@ class SBasis;
class Linear{
public:
double a[2];
- Linear() { a[0] = 0; a[1] = 0; }
+ Linear() {}
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 b79a0a04f..2516bcfa6 100644
--- a/src/2geom/rect.h
+++ b/src/2geom/rect.h
@@ -48,12 +48,6 @@
namespace Geom {
/**
- * @brief Axis-aligned rectangle that can be empty.
- * @ingroup Primitives
- */
-typedef GenericOptRect<Coord> OptRect;
-
-/**
* @brief Axis aligned, non-empty rectangle.
* @ingroup Primitives
*/
@@ -118,9 +112,45 @@ public:
/// @name Operators
/// @{
Rect &operator*=(Affine const &m);
+ bool operator==(IntRect const &ir) const {
+ return f[X] == ir[X] && f[Y] == ir[Y];
+ }
+ bool operator==(Rect const &other) const {
+ return Base::operator==(other);
+ }
/// @}
};
+/**
+ * @brief Axis-aligned rectangle that can be empty.
+ * @ingroup Primitives
+ */
+class OptRect
+ : public GenericOptRect<Coord>
+{
+ typedef GenericOptRect<Coord> Base;
+public:
+ OptRect() : Base() {}
+ OptRect(Rect const &a) : Base(a) {}
+ OptRect(Point const &a, Point const &b) : Base(a, b) {}
+ OptRect(Coord x0, Coord y0, Coord x1, Coord y1) : Base(x0, y0, x1, y1) {}
+ OptRect(OptInterval const &x_int, OptInterval const &y_int) : Base(x_int, y_int) {}
+ OptRect(Base const &b) : Base(b) {}
+
+ OptRect(IntRect const &r) : Base(Rect(r)) {}
+ OptRect(OptIntRect const &r) : Base() {
+ if (r) *this = Rect(*r);
+ }
+ // actually, the only reason we have this class, instead of typedefing
+ // to GenericOptRect<Coord>, are the above constructors
+ bool operator==(OptRect const &other) const {
+ return Base::operator==(other);
+ }
+ bool operator==(Rect const &other) const {
+ return Base::operator==(other);
+ }
+};
+
Coord distanceSq(Point const &p, Rect const &rect);
Coord distance(Point const &p, Rect const &rect);