001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.mappaint; 003 004/** 005 * An interval of the form "lower < x <= upper" where 0 <= lower < upper. 006 * (upper can be Double.POSITIVE_INFINITY) 007 * immutable class 008 */ 009public class Range { 010 private final double lower; 011 private final double upper; 012 013 public static final Range ZERO_TO_INFINITY = new Range(0.0, Double.POSITIVE_INFINITY); 014 015 /** 016 * Constructs a new {@code Range}. 017 * @param lower Lower bound. Must be positive or zero 018 * @param upper Upper bound 019 * @throws IllegalArgumentException if the range is invalid ({@code lower < 0 || lower >= upper}) 020 */ 021 public Range(double lower, double upper) { 022 if (lower < 0 || lower >= upper) 023 throw new IllegalArgumentException("Invalid range: "+lower+'-'+upper); 024 this.lower = lower; 025 this.upper = upper; 026 } 027 028 public boolean contains(double x) { 029 return lower < x && x <= upper; 030 } 031 032 /** 033 * provides the intersection of 2 overlapping ranges 034 * @param a first range 035 * @param b second range 036 * @return intersection of {@code a} and {@code b} 037 */ 038 public static Range cut(Range a, Range b) { 039 if (b.lower >= a.upper || b.upper <= a.lower) 040 throw new IllegalArgumentException("Ranges do not overlap: "+a+" - "+b); 041 return new Range(Math.max(a.lower, b.lower), Math.min(a.upper, b.upper)); 042 } 043 044 /** 045 * under the premise, that x is within this range, 046 * and not within the other range, it shrinks this range in a way 047 * to exclude the other range, but still contain x. 048 * 049 * x | 050 * 051 * this (------------------------------] 052 * 053 * other (-------] or 054 * (-----------------] 055 * 056 * result (----------------] 057 * @param x value 058 * @param other other range 059 * @return reduced range 060 */ 061 public Range reduceAround(double x, Range other) { 062 if (!contains(x)) 063 throw new IllegalArgumentException(x+" is not inside "+this); 064 if (other.contains(x)) 065 throw new IllegalArgumentException(x+" is inside "+other); 066 067 if (x < other.lower && other.lower < upper) 068 return new Range(lower, other.lower); 069 070 if (this.lower < other.upper && other.upper < x) 071 return new Range(other.upper, this.upper); 072 073 return this; 074 } 075 076 public double getLower() { 077 return lower; 078 } 079 080 public double getUpper() { 081 return upper; 082 } 083 084 @Override 085 public String toString() { 086 return String.format("|s%s-%s", lower, upper); 087 } 088 089 @Override 090 public boolean equals(Object o) { 091 if (this == o) return true; 092 if (o == null || getClass() != o.getClass()) return false; 093 094 Range range = (Range) o; 095 096 if (Double.compare(range.lower, lower) != 0) return false; 097 if (Double.compare(range.upper, upper) != 0) return false; 098 099 return true; 100 } 101 102 @Override 103 public int hashCode() { 104 int result; 105 long temp; 106 temp = Double.doubleToLongBits(lower); 107 result = (int) (temp ^ (temp >>> 32)); 108 temp = Double.doubleToLongBits(upper); 109 result = 31 * result + (int) (temp ^ (temp >>> 32)); 110 return result; 111 } 112}