/** Return true if two intervals contains the same set of points. */ @Override public boolean equals(Object that) { if (that instanceof S1Interval) { S1Interval thatInterval = (S1Interval) that; return lo() == thatInterval.lo() && hi() == thatInterval.hi(); } return false; }
/** * Return true if the length of the symmetric difference between the two intervals is at most the * given tolerance. */ public boolean approxEquals(final S1Interval y, double maxError) { if (isEmpty()) { return y.getLength() <= maxError; } if (y.isEmpty()) { return getLength() <= maxError; } return (Math.abs(Math.IEEEremainder(y.lo() - lo(), 2 * S2.M_PI)) + Math.abs(Math.IEEEremainder(y.hi() - hi(), 2 * S2.M_PI))) <= maxError; }
/** * Returns true if the interior of this interval contains the entire interval 'y'. Note that * x.InteriorContains(x) is true only when x is the empty or full interval, and * x.InteriorContains(S1Interval(p,p)) is equivalent to x.InteriorContains(p). */ public boolean interiorContains(final S1Interval y) { if (isInverted()) { if (!y.isInverted()) { return y.lo() > lo() || y.hi() < hi(); } return (y.lo() > lo() && y.hi() < hi()) || y.isEmpty(); } else { if (y.isInverted()) { return isFull() || y.isEmpty(); } return (y.lo() > lo() && y.hi() < hi()) || isFull(); } }
/** * Return the smallest interval that contains the intersection of this interval with "y". Note * that the region of intersection may consist of two disjoint intervals. */ public S1Interval intersection(final S1Interval y) { // The y.is_full() case is handled correctly in all cases by the code // below, but can follow three separate code paths depending on whether // this interval is inverted, is non-inverted but contains Pi, or neither. if (y.isEmpty()) { return empty(); } if (fastContains(y.lo())) { if (fastContains(y.hi())) { // Either this interval contains y, or the region of intersection // consists of two disjoint subintervals. In either case, we want // to return the shorter of the two original intervals. if (y.getLength() < getLength()) { return y; // is_full() code path } return this; } return new S1Interval(y.lo(), hi(), true); } if (fastContains(y.hi())) { return new S1Interval(lo(), y.hi(), true); } // This interval contains neither endpoint of y. This means that either y // contains all of this interval, or the two intervals are disjoint. if (y.fastContains(lo())) { return this; // is_empty() okay here } // assert (!intersects(y)); return empty(); }
/** * Return true if the interior of this interval contains any point of the interval 'y' (including * its boundary). Works for empty, full, and singleton intervals. */ public boolean interiorIntersects(final S1Interval y) { if (isEmpty() || y.isEmpty() || lo() == hi()) { return false; } if (isInverted()) { return y.isInverted() || y.lo() < hi() || y.hi() > lo(); } else { if (y.isInverted()) { return y.lo() < hi() || y.hi() > lo(); } return (y.lo() < hi() && y.hi() > lo()) || isFull(); } }
/** * Return true if the two intervals contain any points in common. Note that the point +/-Pi has * two representations, so the intervals [-Pi,-3] and [2,Pi] intersect, for example. */ public boolean intersects(final S1Interval y) { if (isEmpty() || y.isEmpty()) { return false; } if (isInverted()) { // Every non-empty inverted interval contains Pi. return y.isInverted() || y.lo() <= hi() || y.hi() >= lo(); } else { if (y.isInverted()) { return y.lo() <= hi() || y.hi() >= lo(); } return y.lo() <= hi() && y.hi() >= lo(); } }
/** * Return true if the interval contains the given interval 'y'. Works for empty, full, and * singleton intervals. */ public boolean contains(final S1Interval y) { // It might be helpful to compare the structure of these tests to // the simpler Contains(double) method above. if (isInverted()) { if (y.isInverted()) { return y.lo() >= lo() && y.hi() <= hi(); } return (y.lo() >= lo() || y.hi() <= hi()) && !isEmpty(); } else { if (y.isInverted()) { return isFull() || y.isEmpty(); } return y.lo() >= lo() && y.hi() <= hi(); } }
/** * Expand the interval by the minimum amount necessary so that it contains the given point "p" (an * angle in the range [-Pi, Pi]). */ public S1Interval addPoint(double p) { // assert (Math.abs(p) <= S2.M_PI); if (p == -S2.M_PI) { p = S2.M_PI; } if (fastContains(p)) { return new S1Interval(this); } if (isEmpty()) { return S1Interval.fromPoint(p); } else { // Compute distance from p to each endpoint. double dlo = positiveDistance(p, lo()); double dhi = positiveDistance(hi(), p); if (dlo < dhi) { return new S1Interval(p, hi()); } else { return new S1Interval(lo(), p); } // Adding a point can never turn a non-full interval into a full one. } }
/** Return the smallest interval that contains this interval and the given interval "y". */ public S1Interval union(final S1Interval y) { // The y.is_full() case is handled correctly in all cases by the code // below, but can follow three separate code paths depending on whether // this interval is inverted, is non-inverted but contains Pi, or neither. if (y.isEmpty()) { return this; } if (fastContains(y.lo())) { if (fastContains(y.hi())) { // Either this interval contains y, or the union of the two // intervals is the Full() interval. if (contains(y)) { return this; // is_full() code path } return full(); } return new S1Interval(lo(), y.hi(), true); } if (fastContains(y.hi())) { return new S1Interval(y.lo(), hi(), true); } // This interval contains neither endpoint of y. This means that either y // contains all of this interval, or the two intervals are disjoint. if (isEmpty() || y.fastContains(lo())) { return y; } // Check which pair of endpoints are closer together. double dlo = positiveDistance(y.hi(), lo()); double dhi = positiveDistance(hi(), y.lo()); if (dlo < dhi) { return new S1Interval(y.lo(), hi(), true); } else { return new S1Interval(lo(), y.hi(), true); } }