1 | // Copyright 2005 Google Inc. All Rights Reserved. |
2 | |
3 | #ifndef UTIL_GEOMETRY_S1INTERVAL_H_ |
4 | #define UTIL_GEOMETRY_S1INTERVAL_H_ |
5 | |
6 | #include <iostream> |
7 | using std::ostream; |
8 | using std::cout; |
9 | using std::endl; |
10 | |
11 | #include <math.h> |
12 | #include "base/basictypes.h" |
13 | #include "base/logging.h" |
14 | #include "util/math/vector2-inl.h" |
15 | |
16 | // An S1Interval represents a closed interval on a unit circle (also known |
17 | // as a 1-dimensional sphere). It is capable of representing the empty |
18 | // interval (containing no points), the full interval (containing all |
19 | // points), and zero-length intervals (containing a single point). |
20 | // |
21 | // Points are represented by the angle they make with the positive x-axis in |
22 | // the range [-Pi, Pi]. An interval is represented by its lower and upper |
23 | // bounds (both inclusive, since the interval is closed). The lower bound may |
24 | // be greater than the upper bound, in which case the interval is "inverted" |
25 | // (i.e. it passes through the point (-1, 0)). |
26 | // |
27 | // Note that the point (-1, 0) has two valid representations, Pi and -Pi. |
28 | // The normalized representation of this point internally is Pi, so that |
29 | // endpoints of normal intervals are in the range (-Pi, Pi]. However, we |
30 | // take advantage of the point -Pi to construct two special intervals: |
31 | // the Full() interval is [-Pi, Pi], and the Empty() interval is [Pi, -Pi]. |
32 | // |
33 | // This class is intended to be copied by value as desired. It uses |
34 | // the default copy constructor and assignment operator. |
35 | class S1Interval { |
36 | public: |
37 | // Constructor. Both endpoints must be in the range -Pi to Pi inclusive. |
38 | // The value -Pi is converted internally to Pi except for the Full() |
39 | // and Empty() intervals. |
40 | inline S1Interval(double lo, double hi); |
41 | |
42 | // The default constructor creates an empty interval. |
43 | // |
44 | // Note: Don't construct an interval using the default constructor and |
45 | // set_lo()/set_hi(). If you need to set both endpoints, use the |
46 | // constructor above: |
47 | // |
48 | // lng_bounds_ = S1Interval(lng_lo, lng_hi); |
49 | inline S1Interval(); |
50 | |
51 | // Returns the empty interval. |
52 | static inline S1Interval Empty(); |
53 | |
54 | // Returns the full interval. |
55 | static inline S1Interval Full(); |
56 | |
57 | // Convenience method to construct an interval containing a single point. |
58 | static S1Interval FromPoint(double p); |
59 | |
60 | // Convenience method to construct the minimal interval containing |
61 | // the two given points. This is equivalent to starting with an empty |
62 | // interval and calling AddPoint() twice, but it is more efficient. |
63 | static S1Interval FromPointPair(double p1, double p2); |
64 | |
65 | double lo() const { return bounds_[0]; } |
66 | double hi() const { return bounds_[1]; } |
67 | double bound(int i) const { return bounds_[i]; } |
68 | Vector2_d const& bounds() const { return bounds_; } |
69 | |
70 | // Methods to modify one endpoint of an existing S1Interval. Requires that |
71 | // the resulting S1Interval is valid. This implies you cannot call this |
72 | // method on an Empty() or Full() interval, since these intervals do not |
73 | // have any endpoints. |
74 | // |
75 | // Do not use these methods if you want to replace both endpoints of the |
76 | // interval; use a constructor instead. For example: |
77 | // |
78 | // *lng_bounds = S1Interval(lng_lo, lng_hi); |
79 | void set_lo(double p) { bounds_[0] = p; DCHECK(is_valid()); } |
80 | void set_hi(double p) { bounds_[1] = p; DCHECK(is_valid()); } |
81 | |
82 | // An interval is valid if neither bound exceeds Pi in absolute value, |
83 | // and the value -Pi appears only in the Empty() and Full() intervals. |
84 | inline bool is_valid() const; |
85 | |
86 | // Return true if the interval contains all points on the unit circle. |
87 | bool is_full() const { return hi() - lo() == 2 * M_PI; } |
88 | |
89 | // Return true if the interval is empty, i.e. it contains no points. |
90 | bool is_empty() const { return lo() - hi() == 2 * M_PI; } |
91 | |
92 | // Return true if lo() > hi(). (This is true for empty intervals.) |
93 | bool is_inverted() const { return lo() > hi(); } |
94 | |
95 | // Return the midpoint of the interval. For full and empty intervals, |
96 | // the result is arbitrary. |
97 | double GetCenter() const; |
98 | |
99 | // Return the length of the interval. The length of an empty interval |
100 | // is negative. |
101 | double GetLength() const; |
102 | |
103 | // Return the complement of the interior of the interval. An interval and |
104 | // its complement have the same boundary but do not share any interior |
105 | // values. The complement operator is not a bijection, since the complement |
106 | // of a singleton interval (containing a single value) is the same as the |
107 | // complement of an empty interval. |
108 | S1Interval Complement() const; |
109 | |
110 | // Return the midpoint of the complement of the interval. For full and empty |
111 | // intervals, the result is arbitrary. For a singleton interval (containing a |
112 | // single point), the result is its antipodal point on S1. |
113 | double GetComplementCenter() const; |
114 | |
115 | // Return true if the interval (which is closed) contains the point 'p'. |
116 | bool Contains(double p) const; |
117 | |
118 | // Return true if the interior of the interval contains the point 'p'. |
119 | bool InteriorContains(double p) const; |
120 | |
121 | // Return true if the interval contains the given interval 'y'. |
122 | // Works for empty, full, and singleton intervals. |
123 | bool Contains(S1Interval const& y) const; |
124 | |
125 | // Returns true if the interior of this interval contains the entire |
126 | // interval 'y'. Note that x.InteriorContains(x) is true only when |
127 | // x is the empty or full interval, and x.InteriorContains(S1Interval(p,p)) |
128 | // is equivalent to x.InteriorContains(p). |
129 | bool InteriorContains(S1Interval const& y) const; |
130 | |
131 | // Return true if the two intervals contain any points in common. |
132 | // Note that the point +/-Pi has two representations, so the intervals |
133 | // [-Pi,-3] and [2,Pi] intersect, for example. |
134 | bool Intersects(S1Interval const& y) const; |
135 | |
136 | // Return true if the interior of this interval contains any point of the |
137 | // interval 'y' (including its boundary). Works for empty, full, and |
138 | // singleton intervals. |
139 | bool InteriorIntersects(S1Interval const& y) const; |
140 | |
141 | // Return the Hausdorff distance to the given interval 'y'. For two |
142 | // S1Intervals x and y, this distance is defined by |
143 | // h(x, y) = max_{p in x} min_{q in y} d(p, q), |
144 | // where d(.,.) is measured along S1. |
145 | double GetDirectedHausdorffDistance(S1Interval const& y) const; |
146 | |
147 | // Expand the interval by the minimum amount necessary so that it |
148 | // contains the given point "p" (an angle in the range [-Pi, Pi]). |
149 | void AddPoint(double p); |
150 | |
151 | // Return an interval that contains all points with a distance "radius" of a |
152 | // point in this interval. Note that the expansion of an empty interval is |
153 | // always empty. The radius must be non-negative. |
154 | S1Interval Expanded(double radius) const; |
155 | |
156 | // Return the smallest interval that contains this interval and the |
157 | // given interval "y". |
158 | S1Interval Union(S1Interval const& y) const; |
159 | |
160 | // Return the smallest interval that contains the intersection of this |
161 | // interval with "y". Note that the region of intersection may |
162 | // consist of two disjoint intervals. |
163 | S1Interval Intersection(S1Interval const& y) const; |
164 | |
165 | // Return true if two intervals contains the same set of points. |
166 | inline bool operator==(S1Interval const& y) const; |
167 | |
168 | // Return true if the length of the symmetric difference between the two |
169 | // intervals is at most the given tolerance. |
170 | bool ApproxEquals(S1Interval const& y, double max_error = 1e-15) const; |
171 | |
172 | private: |
173 | enum ArgsChecked { ARGS_CHECKED }; |
174 | |
175 | // Internal constructor that assumes that both arguments are in the |
176 | // correct range, i.e. normalization from -Pi to Pi is already done. |
177 | inline S1Interval(double lo, double hi, ArgsChecked dummy); |
178 | |
179 | // Return true if the interval (which is closed) contains the point 'p'. |
180 | // Skips the normalization of 'p' from -Pi to Pi. |
181 | bool FastContains(double p) const; |
182 | |
183 | Vector2_d bounds_; |
184 | }; |
185 | DECLARE_POD(S1Interval); |
186 | |
187 | inline S1Interval::S1Interval(double lo, double hi) : bounds_(lo, hi) { |
188 | if (lo == -M_PI && hi != M_PI) set_lo(M_PI); |
189 | if (hi == -M_PI && lo != M_PI) set_hi(M_PI); |
190 | DCHECK(is_valid()); |
191 | } |
192 | |
193 | inline S1Interval::S1Interval(double lo, double hi, ArgsChecked dummy) |
194 | : bounds_(lo, hi) { |
195 | DCHECK(is_valid()); |
196 | } |
197 | |
198 | inline S1Interval::S1Interval() : bounds_(M_PI, -M_PI) { |
199 | } |
200 | |
201 | inline S1Interval S1Interval::Empty() { |
202 | return S1Interval(); |
203 | } |
204 | |
205 | inline S1Interval S1Interval::Full() { |
206 | return S1Interval(-M_PI, M_PI, ARGS_CHECKED); |
207 | } |
208 | |
209 | inline bool S1Interval::is_valid() const { |
210 | return (fabs(lo()) <= M_PI && fabs(hi()) <= M_PI && |
211 | !(lo() == -M_PI && hi() != M_PI) && |
212 | !(hi() == -M_PI && lo() != M_PI)); |
213 | } |
214 | |
215 | inline bool S1Interval::operator==(S1Interval const& y) const { |
216 | return lo() == y.lo() && hi() == y.hi(); |
217 | } |
218 | |
219 | inline ostream& operator<<(ostream& os, S1Interval const& x) { |
220 | return os << "[" << x.lo() << ", " << x.hi() << "]" ; |
221 | } |
222 | |
223 | #endif // UTIL_GEOMETRY_S1INTERVAL_H_ |
224 | |