563c8a05869713e5f3c62af4619876736f39f304
1 /**
2 * \file
3 * \brief D2<Interval> specialization to Rect
4 */
5 /*
6 * Copyright 2007 Michael Sloan <mgsloan@gmail.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it either under the terms of the GNU Lesser General Public
10 * License version 2.1 as published by the Free Software Foundation
11 * (the "LGPL") or, at your option, under the terms of the Mozilla
12 * Public License Version 1.1 (the "MPL"). If you do not alter this
13 * notice, a recipient may use your version of this file under either
14 * the MPL or the LGPL.
15 *
16 * You should have received a copy of the LGPL along with this library
17 * in the file COPYING-LGPL-2.1; if not, output to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
21 *
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.1 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
26 *
27 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 * the specific language governing rights and limitations.
30 *
31 */
33 /* Authors of original rect class:
34 * Lauris Kaplinski <lauris@kaplinski.com>
35 * Nathan Hurst <njh@mail.csse.monash.edu.au>
36 * bulia byak <buliabyak@users.sf.net>
37 * MenTaLguY <mental@rydia.net>
38 */
40 #include <2geom/d2.h>
42 #ifndef _2GEOM_RECT
43 #define _2GEOM_RECT
45 #include <2geom/matrix.h>
46 #include <boost/optional/optional.hpp>
48 namespace Geom {
49 /** D2<Interval> specialization to Rect */
50 typedef D2<Interval> Rect;
52 Rect unify(const Rect &, const Rect &);
53 /**
54 * %Rect class.
55 * The Rect class is actually a specialisation of D2<Interval>.
56 *
57 */
58 template<>
59 class D2<Interval> {
60 private:
61 Interval f[2];
62 public:
63 /* The default constructor creates an empty rect, constructed of two empty Intervals. (users rely on this!)
64 */
65 D2<Interval>() { f[X] = f[Y] = Interval(); }
67 D2<Interval>(Interval const &a, Interval const &b) {
68 f[X] = a;
69 f[Y] = b;
70 }
72 D2<Interval>(Point const & a, Point const & b) {
73 f[X] = Interval(a[X], b[X]);
74 f[Y] = Interval(a[Y], b[Y]);
75 }
77 inline Interval& operator[](unsigned i) { return f[i]; }
78 inline Interval const & operator[](unsigned i) const { return f[i]; }
80 inline Point min() const { return Point(f[X].min(), f[Y].min()); }
81 inline Point max() const { return Point(f[X].max(), f[Y].max()); }
83 /** Returns the four corners of the rectangle in positive order
84 * (clockwise if +Y is up, anticlockwise if +Y is down) */
85 Point corner(unsigned i) const {
86 switch(i % 4) {
87 case 0: return Point(f[X].min(), f[Y].min());
88 case 1: return Point(f[X].max(), f[Y].min());
89 case 2: return Point(f[X].max(), f[Y].max());
90 default: return Point(f[X].min(), f[Y].max());
91 }
92 }
94 //We should probably remove these - they're coord sys gnostic
95 inline double top() const { return f[Y].min(); }
96 inline double bottom() const { return f[Y].max(); }
97 inline double left() const { return f[X].min(); }
98 inline double right() const { return f[X].max(); }
100 inline double width() const { return f[X].extent(); }
101 inline double height() const { return f[Y].extent(); }
103 /** Returns a vector from min to max. */
104 inline Point dimensions() const { return Point(f[X].extent(), f[Y].extent()); }
105 inline Point midpoint() const { return Point(f[X].middle(), f[Y].middle()); }
107 /**
108 * Compute the area of this rectangle. Note that a zero area rectangle is not necessarily empty - just as the interval [0,0] contains one point, the rectangle [0,0] x [0,0] contains 1 point and no area.
109 */
110 inline double area() const { return f[X].extent() * f[Y].extent(); }
111 inline double maxExtent() const { return std::max(f[X].extent(), f[Y].extent()); }
113 inline bool isEmpty() const {
114 return f[X].isEmpty() || f[Y].isEmpty();
115 }
116 inline bool intersects(Rect const &r) const {
117 return f[X].intersects(r[X]) && f[Y].intersects(r[Y]);
118 }
119 inline bool contains(Rect const &r) const {
120 return f[X].contains(r[X]) && f[Y].contains(r[Y]);
121 }
122 inline bool contains(Point const &p) const {
123 return f[X].contains(p[X]) && f[Y].contains(p[Y]);
124 }
126 inline void expandTo(Point p) {
127 f[X].extendTo(p[X]); f[Y].extendTo(p[Y]);
128 }
129 inline void unionWith(Rect const &b) {
130 f[X].unionWith(b[X]); f[Y].unionWith(b[Y]);
131 }
133 inline void expandBy(double amnt) {
134 f[X].expandBy(amnt); f[Y].expandBy(amnt);
135 }
136 inline void expandBy(Point const p) {
137 f[X].expandBy(p[X]); f[Y].expandBy(p[Y]);
138 }
140 /** Transforms the rect by m. Note that it gives correct results only for scales and translates,
141 in the case of rotations, the area of the rect will grow as it cannot rotate. */
142 inline Rect operator*(Matrix const m) const {
143 return unify(Rect(corner(0) * m, corner(2) * m),
144 Rect(corner(1) * m, corner(3) * m));
145 }
146 };
148 inline Rect unify(Rect const & a, Rect const & b) {
149 return Rect(unify(a[X], b[X]), unify(a[Y], b[Y]));
150 }
152 /**
153 * Returns the smallest rectangle that encloses both rectangles.
154 * An empty argument is assumed to be an empty rectangle
155 */
156 inline boost::optional<Rect> unify(boost::optional<Rect> const & a, boost::optional<Rect> const & b) {
157 if (!a) {
158 return b;
159 } else if (!b) {
160 return a;
161 } else {
162 return unify(*a, *b);
163 }
164 }
166 inline Rect union_list(std::vector<Rect> const &r) {
167 if(r.empty()) return Rect(Interval(0,0), Interval(0,0));
168 Rect ret = r[0];
169 for(unsigned i = 1; i < r.size(); i++)
170 ret.unionWith(r[i]);
171 return ret;
172 }
174 inline boost::optional<Rect> intersect(Rect const & a, Rect const & b) {
175 boost::optional<Interval> x = intersect(a[X], b[X]);
176 boost::optional<Interval> y = intersect(a[Y], b[Y]);
177 return x && y ? boost::optional<Rect>(Rect(*x, *y)) : boost::optional<Rect>();
178 }
180 inline
181 double distanceSq( Point const& p, Rect const& rect )
182 {
183 double dx = 0, dy = 0;
184 if ( p[X] < rect.left() )
185 {
186 dx = p[X] - rect.left();
187 }
188 else if ( p[X] > rect.right() )
189 {
190 dx = rect.right() - p[X];
191 }
192 if ( p[Y] < rect.top() )
193 {
194 dy = rect.top() - p[Y];
195 }
196 else if ( p[Y] > rect.bottom() )
197 {
198 dy = p[Y] - rect.bottom();
199 }
200 return dx*dx + dy*dy;
201 }
203 /**
204 * Returns the smallest distance between p and rect.
205 */
206 inline
207 double distance( Point const& p, Rect const& rect )
208 {
209 return std::sqrt(distanceSq(p, rect));
210 }
213 } // end namespace Geom
215 #endif //_2GEOM_RECT
217 /*
218 Local Variables:
219 mode:c++
220 c-file-style:"stroustrup"
221 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
222 indent-tabs-mode:nil
223 fill-column:99
224 End:
225 */
226 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :