Code

8f7a0b2a167bf9e40cb9b81635757a657941d920
[inkscape.git] / src / 2geom / interval.h
1 /**
2  * \file
3  * \brief  Simple closed interval class
4  *
5  * Copyright 2007 Michael Sloan <mgsloan@gmail.com>
6  *
7  * Original Rect/Range code by:
8  *   Lauris Kaplinski <lauris@kaplinski.com>
9  *   Nathan Hurst <njh@mail.csse.monash.edu.au>
10  *   bulia byak <buliabyak@users.sf.net>
11  *   MenTaLguY <mental@rydia.net>
12  * 
13  * This library is free software; you can redistribute it and/or
14  * modify it either under the terms of the GNU Lesser General Public
15  * License version 2.1 as published by the Free Software Foundation
16  * (the "LGPL") or, at your option, under the terms of the Mozilla
17  * Public License Version 1.1 (the "MPL"). If you do not alter this
18  * notice, a recipient may use your version of this file under either
19  * the MPL or the LGPL.
20  *
21  * You should have received a copy of the LGPL along with this library
22  * in the file COPYING-LGPL-2.1; if not, output to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  * You should have received a copy of the MPL along with this library
25  * in the file COPYING-MPL-1.1
26  *
27  * The contents of this file are subject to the Mozilla Public License
28  * Version 1.1 (the "License"); you may not use this file except in
29  * compliance with the License. You may obtain a copy of the License at
30  * http://www.mozilla.org/MPL/
31  *
32  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
33  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
34  * the specific language governing rights and limitations.
35  *
36  */
37 #ifndef SEEN_INTERVAL_H
38 #define SEEN_INTERVAL_H
40 #include <assert.h>
41 #include <2geom/coord.h>
43 #include <boost/optional/optional.hpp>
45 namespace Geom {
47 /* Although an Interval where _b[0] > _b[1] is considered empty, for proper functioning of other methods,
48  * a proper empty Interval is [+infinity, -infinity]. Then, expandTo(p) will set the interval to [p,p].
49  */
50 class Interval {
51 private:
52     Coord _b[2];
54 public:
55     // The default constructor creates an empty interval, that ranges from +infinity to -infinity.
56     // Doing an expandTo(p) on this empty interval will correctly set the whole interval to [p,p].
57     explicit Interval() { _b[0] = +infinity();  _b[1] = -infinity(); }
58     explicit Interval(Coord u) { _b[0] = _b[1] = u; }
59     /* When creating an Interval using the constructor specifying the exact range, the created interval
60      * will be [u,v] when u<=v ; and will be [v,u] when v < u !!!
61      */
62     Interval(Coord u, Coord v) {
63         if(u < v) {
64             _b[0] = u; _b[1] = v;
65         } else {
66             _b[0] = v; _b[1] = u;
67         }
68     }
69     
70     double operator[](unsigned i) const {
71         assert(i < 2);
72         return _b[i];
73     }
74     inline double& operator[](unsigned i) { return _b[i]; }  //Trust the user...
75     
76     inline Coord min() const { return _b[0]; }
77     inline Coord max() const { return _b[1]; }
78     inline Coord extent() const { return _b[1] - _b[0]; }
79     inline Coord middle() const { return (_b[1] + _b[0]) * 0.5; }
80     
81     inline bool isEmpty() const { return _b[0] > _b[1]; }
82     inline bool contains(Coord val) const { return _b[0] <= val && val <= _b[1]; }
83     bool contains(const Interval & val) const { return _b[0] <= val._b[0] && val._b[1] <= _b[1]; }
84     bool intersects(const Interval & val) const {
85         return contains(val._b[0]) || contains(val._b[1]) || val.contains(*this);
86     }
87     
88     inline bool operator==(Interval other) const { return _b[0] == other._b[0] && _b[1] == other._b[1]; }
89     inline bool operator!=(Interval other) const { return _b[0] != other._b[0] || _b[1] != other._b[1]; }
90     
91     //IMPL: OffsetableConcept
92     //TODO: rename output_type to something else in the concept
93     typedef Coord output_type;
94     inline Interval operator+(Coord amnt) {
95         return Interval(_b[0] + amnt, _b[1] + amnt);
96     }
97     inline Interval operator-(Coord amnt) {
98         return Interval(_b[0] - amnt, _b[1] - amnt);
99     }
100     inline Interval operator+=(Coord amnt) {
101         _b[0] += amnt; _b[1] += amnt;
102         return *this;
103     }
104     inline Interval operator-=(Coord amnt) {
105         _b[0] -= amnt; _b[1] -= amnt;
106         return *this;
107     }
108     
109     //IMPL: ScalableConcept
110     inline Interval operator-() const { return Interval(*this); }
111     inline Interval operator*(Coord s) const { return Interval(_b[0]*s, _b[1]*s); }
112     inline Interval operator/(Coord s) const { return Interval(_b[0]/s, _b[1]/s); }
113     Interval operator*=(Coord s) {
114         if(s < 0) {
115             Coord temp = _b[0];
116             _b[0] = _b[1]*s;
117             _b[1] = temp*s;
118         } else {
119             _b[0] *= s;
120             _b[1] *= s;
121         }
122         return *this;
123     }
124     Interval operator/=(Coord s) {
125         //TODO: what about s=0?
126         if(s < 0) {
127             Coord temp = _b[0];
128             _b[0] = _b[1]/s;
129             _b[1] = temp/s;
130         } else {
131             _b[0] /= s;
132             _b[1] /= s;
133         }
134         return *this;
135     }
136     
137     //TODO: NaN handleage for the next two?
138     //TODO: Evaluate if wrap behaviour is proper.
139     //If val > max, then rather than becoming a min==max range, it 'wraps' over
140     void setMin(Coord val) {
141         if(val > _b[1]) {
142             _b[0] = _b[1];
143             _b[1] = val;
144         } else {
145             _b[0] = val;
146         }
147     }
148     //If val < min, then rather than becoming a min==max range, it 'wraps' over
149     void setMax(Coord val) {
150         if(val < _b[0]) {
151             _b[1] = _b[0];
152             _b[0] = val;
153         } else {
154             _b[1] = val;
155         }
156     }
157     
158     inline void extendTo(Coord val) {
159        if(val < _b[0]) _b[0] = val;
160        if(val > _b[1]) _b[1] = val;  //no else, as we want to handle NaN
161     }
162     
163     static Interval fromArray(const Coord* c, int n) {
164         assert(n > 0);
165         Interval result(c[0]);
166         for(int i = 1; i < n; i++) result.extendTo(c[i]);
167         return result;
168     }
169     
170     inline void expandBy(double amnt) {
171         _b[0] -= amnt;
172         _b[1] += amnt;
173     }
174     
175     inline void unionWith(const Interval & a) {
176         if(a._b[0] < _b[0]) _b[0] = a._b[0];
177         if(a._b[1] > _b[1]) _b[1] = a._b[1];
178     }
179 };
181 //IMPL: AddableConcept
182 inline Interval operator+(const Interval & a, const Interval & b) {
183     return Interval(a.min() + b.min(), a.max() + b.max());
185 inline Interval operator-(const Interval & a, const Interval & b) {
186     return Interval(a.min() - b.max(), a.max() - b.min());
188 inline Interval operator+=(Interval & a, const Interval & b) { a = a + b; return a; }
189 inline Interval operator-=(Interval & a, const Interval & b) { a = a - b; return a; }
191 //There might be impls of this based off sign checks
192 inline Interval operator*(const Interval & a, const Interval & b) {
193     Interval res(a.min() * b.min());
194     res.extendTo(a.min() * b.max());
195     res.extendTo(a.max() * b.min());
196     res.extendTo(a.max() * b.max());
197     return res;
199 inline Interval operator*=(Interval & a, const Interval & b) { a = a * b; return a; }
201 /* reinstate if useful (doesn't do the proper thing for 0 inclusion)
202 inline Interval operator/(const Interval & a, const Interval & b) {
203     Interval res(a.min() / b.min());
204     res.extendTo(a.min() / b.max());
205     res.extendTo(a.max() / b.min());
206     res.extendTo(a.max() / b.max());
207     return res;
209 inline Interval operator/=(Interval & a, const Interval & b) { a = a / b; return a; }
210 */
212 // 'union' conflicts with C keyword
213 inline Interval unify(const Interval & a, const Interval & b) {
214     return Interval(std::min(a.min(), b.min()),
215                     std::max(a.max(), b.max()));
217 inline boost::optional<Interval> intersect(const Interval & a, const Interval & b) {
218     Coord u = std::max(a.min(), b.min()),
219           v = std::min(a.max(), b.max());
220     //technically >= might be incorrect, but singulars suck
221     return u >= v ? boost::optional<Interval>()
222                   : boost::optional<Interval>(Interval(u, v));
226 #endif //SEEN_INTERVAL_H
228 /*
229   Local Variables:
230   mode:c++
231   c-file-style:"stroustrup"
232   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
233   indent-tabs-mode:nil
234   fill-column:99
235   End:
236 */
237 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :