You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
6.0 KiB
237 lines
6.0 KiB
/*
|
|
* Copyright 2005 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.google.common.geometry;
|
|
|
|
/**
|
|
* An R1Interval represents a closed, bounded interval on the real line. It is
|
|
* capable of representing the empty interval (containing no points) and
|
|
* zero-length intervals (containing a single point).
|
|
*
|
|
*/
|
|
|
|
public final strictfp class R1Interval {
|
|
|
|
private final double lo;
|
|
private final double hi;
|
|
|
|
/** Interval constructor. If lo > hi, the interval is empty. */
|
|
public R1Interval(double lo, double hi) {
|
|
this.lo = lo;
|
|
this.hi = hi;
|
|
}
|
|
|
|
/**
|
|
* Returns an empty interval. (Any interval where lo > hi is considered
|
|
* empty.)
|
|
*/
|
|
public static R1Interval empty() {
|
|
return new R1Interval(1, 0);
|
|
}
|
|
|
|
/**
|
|
* Convenience method to construct an interval containing a single point.
|
|
*/
|
|
public static R1Interval fromPoint(double p) {
|
|
return new R1Interval(p, p);
|
|
}
|
|
|
|
/**
|
|
* Convenience method to construct the minimal interval containing the two
|
|
* given points. This is equivalent to starting with an empty interval and
|
|
* calling AddPoint() twice, but it is more efficient.
|
|
*/
|
|
public static R1Interval fromPointPair(double p1, double p2) {
|
|
if (p1 <= p2) {
|
|
return new R1Interval(p1, p2);
|
|
} else {
|
|
return new R1Interval(p2, p1);
|
|
}
|
|
}
|
|
|
|
public double lo() {
|
|
return lo;
|
|
}
|
|
|
|
public double hi() {
|
|
return hi;
|
|
}
|
|
|
|
/**
|
|
* Return true if the interval is empty, i.e. it contains no points.
|
|
*/
|
|
public boolean isEmpty() {
|
|
return lo() > hi();
|
|
}
|
|
|
|
/**
|
|
* Return the center of the interval. For empty intervals, the result is
|
|
* arbitrary.
|
|
*/
|
|
public double getCenter() {
|
|
return 0.5 * (lo() + hi());
|
|
}
|
|
|
|
/**
|
|
* Return the length of the interval. The length of an empty interval is
|
|
* negative.
|
|
*/
|
|
public double getLength() {
|
|
return hi() - lo();
|
|
}
|
|
|
|
public boolean contains(double p) {
|
|
return p >= lo() && p <= hi();
|
|
}
|
|
|
|
public boolean interiorContains(double p) {
|
|
return p > lo() && p < hi();
|
|
}
|
|
|
|
/** Return true if this interval contains the interval 'y'. */
|
|
public boolean contains(R1Interval y) {
|
|
if (y.isEmpty()) {
|
|
return true;
|
|
}
|
|
return y.lo() >= lo() && y.hi() <= hi();
|
|
}
|
|
|
|
/**
|
|
* Return true if the interior of this interval contains the entire interval
|
|
* 'y' (including its boundary).
|
|
*/
|
|
public boolean interiorContains(R1Interval y) {
|
|
if (y.isEmpty()) {
|
|
return true;
|
|
}
|
|
return y.lo() > lo() && y.hi() < hi();
|
|
}
|
|
|
|
/**
|
|
* Return true if this interval intersects the given interval, i.e. if they
|
|
* have any points in common.
|
|
*/
|
|
public boolean intersects(R1Interval y) {
|
|
if (lo() <= y.lo()) {
|
|
return y.lo() <= hi() && y.lo() <= y.hi();
|
|
} else {
|
|
return lo() <= y.hi() && lo() <= hi();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return true if the interior of this interval intersects any point of the
|
|
* given interval (including its boundary).
|
|
*/
|
|
public boolean interiorIntersects(R1Interval y) {
|
|
return y.lo() < hi() && lo() < y.hi() && lo() < hi() && y.lo() <= y.hi();
|
|
}
|
|
|
|
/** Expand the interval so that it contains the given point "p". */
|
|
public R1Interval addPoint(double p) {
|
|
if (isEmpty()) {
|
|
return R1Interval.fromPoint(p);
|
|
} else if (p < lo()) {
|
|
return new R1Interval(p, hi());
|
|
} else if (p > hi()) {
|
|
return new R1Interval(lo(), p);
|
|
} else {
|
|
return new R1Interval(lo(), hi());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return an interval that contains all points with a distance "radius" of a
|
|
* point in this interval. Note that the expansion of an empty interval is
|
|
* always empty.
|
|
*/
|
|
public R1Interval expanded(double radius) {
|
|
// assert (radius >= 0);
|
|
if (isEmpty()) {
|
|
return this;
|
|
}
|
|
return new R1Interval(lo() - radius, hi() + radius);
|
|
}
|
|
|
|
/**
|
|
* Return the smallest interval that contains this interval and the given
|
|
* interval "y".
|
|
*/
|
|
public R1Interval union(R1Interval y) {
|
|
if (isEmpty()) {
|
|
return y;
|
|
}
|
|
if (y.isEmpty()) {
|
|
return this;
|
|
}
|
|
return new R1Interval(Math.min(lo(), y.lo()), Math.max(hi(), y.hi()));
|
|
}
|
|
|
|
/**
|
|
* Return the intersection of this interval with the given interval. Empty
|
|
* intervals do not need to be special-cased.
|
|
*/
|
|
public R1Interval intersection(R1Interval y) {
|
|
return new R1Interval(Math.max(lo(), y.lo()), Math.min(hi(), y.hi()));
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object that) {
|
|
if (that instanceof R1Interval) {
|
|
R1Interval y = (R1Interval) that;
|
|
// Return true if two intervals contain the same set of points.
|
|
return (lo() == y.lo() && hi() == y.hi()) || (isEmpty() && y.isEmpty());
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
if (isEmpty()) {
|
|
return 17;
|
|
}
|
|
|
|
long value = 17;
|
|
value = 37 * value + Double.doubleToLongBits(lo);
|
|
value = 37 * value + Double.doubleToLongBits(hi);
|
|
return (int) (value ^ (value >>> 32));
|
|
}
|
|
|
|
public boolean approxEquals(R1Interval y) {
|
|
return approxEquals(y, 1e-15);
|
|
}
|
|
|
|
/**
|
|
* Return true if length of the symmetric difference between the two intervals
|
|
* is at most the given tolerance.
|
|
*
|
|
*/
|
|
public boolean approxEquals(R1Interval y, double maxError) {
|
|
if (isEmpty()) {
|
|
return y.getLength() <= maxError;
|
|
}
|
|
if (y.isEmpty()) {
|
|
return getLength() <= maxError;
|
|
}
|
|
return Math.abs(y.lo() - lo()) + Math.abs(y.hi() - hi()) <= maxError;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "[" + lo() + ", " + hi() + "]";
|
|
}
|
|
}
|