• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2005 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.common.geometry;
17 
18 /**
19  * An R1Interval represents a closed, bounded interval on the real line. It is
20  * capable of representing the empty interval (containing no points) and
21  * zero-length intervals (containing a single point).
22  *
23  */
24 
25 public final strictfp class R1Interval {
26 
27   private final double lo;
28   private final double hi;
29 
30   /** Interval constructor. If lo > hi, the interval is empty. */
R1Interval(double lo, double hi)31   public R1Interval(double lo, double hi) {
32     this.lo = lo;
33     this.hi = hi;
34   }
35 
36   /**
37    * Returns an empty interval. (Any interval where lo > hi is considered
38    * empty.)
39    */
empty()40   public static R1Interval empty() {
41     return new R1Interval(1, 0);
42   }
43 
44   /**
45    * Convenience method to construct an interval containing a single point.
46    */
fromPoint(double p)47   public static R1Interval fromPoint(double p) {
48     return new R1Interval(p, p);
49   }
50 
51   /**
52    * Convenience method to construct the minimal interval containing the two
53    * given points. This is equivalent to starting with an empty interval and
54    * calling AddPoint() twice, but it is more efficient.
55    */
fromPointPair(double p1, double p2)56   public static R1Interval fromPointPair(double p1, double p2) {
57     if (p1 <= p2) {
58       return new R1Interval(p1, p2);
59     } else {
60       return new R1Interval(p2, p1);
61     }
62   }
63 
lo()64   public double lo() {
65     return lo;
66   }
67 
hi()68   public double hi() {
69     return hi;
70   }
71 
72   /**
73    * Return true if the interval is empty, i.e. it contains no points.
74    */
isEmpty()75   public boolean isEmpty() {
76     return lo() > hi();
77   }
78 
79   /**
80    * Return the center of the interval. For empty intervals, the result is
81    * arbitrary.
82    */
getCenter()83   public double getCenter() {
84     return 0.5 * (lo() + hi());
85   }
86 
87   /**
88    * Return the length of the interval. The length of an empty interval is
89    * negative.
90    */
getLength()91   public double getLength() {
92     return hi() - lo();
93   }
94 
contains(double p)95   public boolean contains(double p) {
96     return p >= lo() && p <= hi();
97   }
98 
interiorContains(double p)99   public boolean interiorContains(double p) {
100     return p > lo() && p < hi();
101   }
102 
103   /** Return true if this interval contains the interval 'y'. */
contains(R1Interval y)104   public boolean contains(R1Interval y) {
105     if (y.isEmpty()) {
106       return true;
107     }
108     return y.lo() >= lo() && y.hi() <= hi();
109   }
110 
111   /**
112    * Return true if the interior of this interval contains the entire interval
113    * 'y' (including its boundary).
114    */
interiorContains(R1Interval y)115   public boolean interiorContains(R1Interval y) {
116     if (y.isEmpty()) {
117       return true;
118     }
119     return y.lo() > lo() && y.hi() < hi();
120   }
121 
122   /**
123    * Return true if this interval intersects the given interval, i.e. if they
124    * have any points in common.
125    */
intersects(R1Interval y)126   public boolean intersects(R1Interval y) {
127     if (lo() <= y.lo()) {
128       return y.lo() <= hi() && y.lo() <= y.hi();
129     } else {
130       return lo() <= y.hi() && lo() <= hi();
131     }
132   }
133 
134   /**
135    * Return true if the interior of this interval intersects any point of the
136    * given interval (including its boundary).
137    */
interiorIntersects(R1Interval y)138   public boolean interiorIntersects(R1Interval y) {
139     return y.lo() < hi() && lo() < y.hi() && lo() < hi() && y.lo() <= y.hi();
140   }
141 
142   /** Expand the interval so that it contains the given point "p". */
addPoint(double p)143   public R1Interval addPoint(double p) {
144     if (isEmpty()) {
145       return R1Interval.fromPoint(p);
146     } else if (p < lo()) {
147       return new R1Interval(p, hi());
148     } else if (p > hi()) {
149       return new R1Interval(lo(), p);
150     } else {
151       return new R1Interval(lo(), hi());
152     }
153   }
154 
155   /**
156    * Return an interval that contains all points with a distance "radius" of a
157    * point in this interval. Note that the expansion of an empty interval is
158    * always empty.
159    */
expanded(double radius)160   public R1Interval expanded(double radius) {
161     // assert (radius >= 0);
162     if (isEmpty()) {
163       return this;
164     }
165     return new R1Interval(lo() - radius, hi() + radius);
166   }
167 
168   /**
169    * Return the smallest interval that contains this interval and the given
170    * interval "y".
171    */
union(R1Interval y)172   public R1Interval union(R1Interval y) {
173     if (isEmpty()) {
174       return y;
175     }
176     if (y.isEmpty()) {
177       return this;
178     }
179     return new R1Interval(Math.min(lo(), y.lo()), Math.max(hi(), y.hi()));
180   }
181 
182   /**
183    * Return the intersection of this interval with the given interval. Empty
184    * intervals do not need to be special-cased.
185    */
intersection(R1Interval y)186   public R1Interval intersection(R1Interval y) {
187     return new R1Interval(Math.max(lo(), y.lo()), Math.min(hi(), y.hi()));
188   }
189 
190   @Override
equals(Object that)191   public boolean equals(Object that) {
192     if (that instanceof R1Interval) {
193       R1Interval y = (R1Interval) that;
194       // Return true if two intervals contain the same set of points.
195       return (lo() == y.lo() && hi() == y.hi()) || (isEmpty() && y.isEmpty());
196 
197     }
198     return false;
199   }
200 
201   @Override
hashCode()202   public int hashCode() {
203     if (isEmpty()) {
204       return 17;
205     }
206 
207     long value = 17;
208     value = 37 * value + Double.doubleToLongBits(lo);
209     value = 37 * value + Double.doubleToLongBits(hi);
210     return (int) (value ^ (value >>> 32));
211   }
212 
approxEquals(R1Interval y)213   public boolean approxEquals(R1Interval y) {
214     return approxEquals(y, 1e-15);
215   }
216 
217   /**
218    * Return true if length of the symmetric difference between the two intervals
219    * is at most the given tolerance.
220    *
221    */
approxEquals(R1Interval y, double maxError)222   public boolean approxEquals(R1Interval y, double maxError) {
223     if (isEmpty()) {
224       return y.getLength() <= maxError;
225     }
226     if (y.isEmpty()) {
227       return getLength() <= maxError;
228     }
229     return Math.abs(y.lo() - lo()) + Math.abs(y.hi() - hi()) <= maxError;
230   }
231 
232   @Override
toString()233   public String toString() {
234     return "[" + lo() + ", " + hi() + "]";
235   }
236 }
237