| 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 |  | 
|---|