X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Flibnr%2Fnr-rect.h;h=46aff13f4fa938212f39df8654abeaacd1cdcaf5;hb=1c2557cd7259a8166f07b7982a44e040a44d4db1;hp=dd7caa897ea100c4a59704df33943926033ada89;hpb=8d10164b2636a9ee8b6ab5c5182143c0e50de3d4;p=inkscape.git diff --git a/src/libnr/nr-rect.h b/src/libnr/nr-rect.h index dd7caa897..46aff13f4 100644 --- a/src/libnr/nr-rect.h +++ b/src/libnr/nr-rect.h @@ -31,9 +31,10 @@ namespace NR { /** 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]. Emptiness, however, is defined - * as having zero area, meaning an empty rectangle may still contain - * points. Infinities are also permitted. */ + * 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()) {} @@ -52,9 +53,9 @@ public: /** returns the midpoint of this rect. */ Point midpoint() const; - /** does this rectangle have zero area? */ - bool isEmpty() const { - return isEmpty() || isEmpty(); + /** 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 { @@ -125,35 +126,7 @@ public: _max[NR::Y] += by; } - /** Returns the set of points shared by both rectangles. */ - static Maybe intersection(Maybe const &a, Maybe const &b); - - /** Returns the smallest rectangle that encloses both rectangles. */ - static Maybe union_bounds(Maybe const &a, Maybe const &b) - { - if (!a) { - return b; - } else if (!b) { - return a; - } else { - return union_bounds(*a, *b); - } - } - static Rect union_bounds(Maybe const &a, Rect const &b) { - if (a) { - return union_bounds(*a, b); - } else { - return b; - } - } - static Rect union_bounds(Rect const &a, Maybe const &b) { - if (b) { - return union_bounds(a, *b); - } else { - return a; - } - } - static Rect union_bounds(Rect const &a, Rect const &b); + void growBy (gdouble by); /** Scales the rect by s, with origin at 0, 0 */ inline Rect operator*(double const s) const { @@ -172,6 +145,8 @@ public: 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(); } @@ -181,9 +156,9 @@ private: return _max[axis] - _min[axis]; } - template - bool isEmpty() const { - return !( _min[axis] < _max[axis] ); + template + bool isEmpty(double epsilon) const { + return extent() < epsilon; } template @@ -203,10 +178,57 @@ private: Point _min, _max; - /* evil, but temporary */ - friend class Maybe; + friend class MaybeStorage; + friend Maybe intersection(Maybe const &, Maybe const &); + friend Rect union_bounds(Rect const &, Rect const &); }; +template <> +class MaybeStorage { +public: + MaybeStorage() : _rect(Nothing()) {} + MaybeStorage(Rect const &rect) : _rect(rect) {} + + bool is_nothing() const { + return _rect._min[X] > _rect._max[X]; + } + Rect const &value() const { return _rect; } + Rect &value() { return _rect; } + +private: + Rect _rect; +}; + +/** Returns the set of points shared by both rectangles. */ +Maybe intersection(Maybe const & a, Maybe const & b); + +/** Returns the smallest rectangle that encloses both rectangles. */ +Rect union_bounds(Rect const &a, Rect const &b); +inline Rect union_bounds(Maybe const & a, Rect const &b) { + if (a) { + return union_bounds(*a, b); + } else { + return b; + } +} +inline Rect union_bounds(Rect const &a, Maybe const & b) { + if (b) { + return union_bounds(a, *b); + } else { + return a; + } +} +inline Maybe union_bounds(Maybe const & a, Maybe 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 @@ -243,6 +265,7 @@ struct NRRect { #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. */ #define nr_rect_d_test_empty(r) ((r) && NR_RECT_DFLS_TEST_EMPTY(r)) #define nr_rect_l_test_empty(r) ((r) && NR_RECT_DFLS_TEST_EMPTY(r))