/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is 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.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package plotter.internal;
import java.util.Iterator;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.Map.Entry;
/**
* Set of closed ranges. (Each range contains its endpoints.)
* Behavior is undefined if NaN is used.
* This class is optimized for the common case where the set contains exactly one contiguous range.
* @author Adam Crume
*/
public class RangeSet {
/** Holds the minimum value if there is exactly one range, infinity if none, and is undefined otherwise. */
private double min = Double.POSITIVE_INFINITY;
/** Holds the maximum value if there is exactly one range, negative infinity if none, and is undefined otherwise. */
private double max = Double.NEGATIVE_INFINITY;
/** If there is more than one range, this maps the minimum to the maximum for each range. Otherwise, this is null. */
private NavigableMap<Double, Double> data;
/**
* Unions the range set with the range (min, max).
* Min and max are inclusive.
* @param min minimum endpoint of the range
* @param max maximum endpoint of the range
*/
public void add(double min, double max) {
if(data != null) {
Entry<Double, Double> e = data.floorEntry(min);
if(e != null) {
double key = e.getKey();
double value = e.getValue();
if(min <= value && max >= key) {
min = Math.min(key, min);
max = Math.max(value, max);
data.remove(key);
}
}
do {
Entry<Double, Double> e2 = data.higherEntry(min);
if(e2 == null) {
break;
}
double key = e2.getKey();
double value = e2.getValue();
if(!(min <= value && max >= key)) {
break;
}
min = Math.min(key, min);
max = Math.max(value, max);
data.remove(key);
} while(true);
if(data.isEmpty()) {
data = null;
this.min = min;
this.max = max;
} else {
data.put(min, max);
}
} else if((this.min == Double.POSITIVE_INFINITY && this.max == Double.NEGATIVE_INFINITY)
|| (min <= this.max && max >= this.min)) {
this.min = Math.min(this.min, min);
this.max = Math.max(this.max, max);
} else {
data = new TreeMap<Double, Double>();
data.put(this.min, this.max);
data.put(min, max);
}
}
/**
* Resets this to the empty set.
*/
public void clear() {
min = Double.POSITIVE_INFINITY;
max = Double.NEGATIVE_INFINITY;
data = null;
}
/**
* Returns the minimum value if there is exactly one range, infinity if none, and an unspecified value otherwise.
* @return the minimum value
*/
public double getMin() {
return min;
}
/**
* Returns the maximum value if there is exactly one range, infinity if none, and an unspecified value otherwise.
* @return the maximum value
*/
public double getMax() {
return max;
}
/**
* Returns a map of the minimum to the maximum for each range, or null if there are zero or one ranges.
* @return a map of the minimum to the maximum for each range, may be null
*/
public NavigableMap<Double, Double> getData() {
return data;
}
@Override
public String toString() {
if(data == null) {
if(min == Double.POSITIVE_INFINITY) {
return "{}";
} else {
return "{(" + min + ":" + max + ")}";
}
} else {
StringBuffer b = new StringBuffer();
b.append("{");
for(Iterator<Entry<Double, Double>> itr = data.entrySet().iterator(); itr.hasNext();) {
Entry<Double, Double> e = itr.next();
double min = e.getKey();
double max = e.getValue();
b.append("(");
b.append(min);
b.append(":");
b.append(max);
b.append(")");
if(itr.hasNext()) {
b.append(",");
}
}
b.append("}");
return b.toString();
}
}
}