Code

563c8a05869713e5f3c62af4619876736f39f304
[inkscape.git] / src / 2geom / rect.h
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(); }
66     
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     }
93         
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(); }
99     
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     }
139     
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]));
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     }
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;
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>();
180 inline
181 double distanceSq( Point const& p, Rect const& rect )
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;
203 /**
204  * Returns the smallest distance between p and rect.
205  */
206 inline 
207 double distance( Point const& p, Rect const& rect )
209     return std::sqrt(distanceSq(p, rect));
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 :