/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 GeoSolutions
* 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 it.geosolutions.jaiext.range;
import it.geosolutions.jaiext.utilities.ImageUtilities;
/**
* This class is a subclass of the {@link Range} class handling float data.
*/
public class RangeFloat extends Range {
public static RangeFloat FULL_RANGE = new RangeFloat(Float.NEGATIVE_INFINITY, true,
Float.POSITIVE_INFINITY, true, true);
/** Minimum range bound */
private final float minValue;
/** Maximum range bound */
private final float maxValue;
/** If the Range is degenerated and it is a NaN value, then this value is taken as an Integer */
private final int intValue;
/** Boolean indicating if the maximum bound is included */
private final boolean isPoint;
/** Boolean indicating the presence of No Data, only used for degenerated Range(single-point) */
private final boolean isNaN;
/** Boolean indicating if No Data in should be considered always inside or outside the Range (only for non-degenerated Ranges) */
private final boolean nanIncluded;
RangeFloat(float minValue, boolean minIncluded, float maxValue, boolean maxIncluded,boolean nanIncluded) {
super(minIncluded, maxIncluded);
// If one of the 2 bound values is NaN an exception is thrown
if (Float.isNaN(minValue) && !Float.isNaN(maxValue) || !Float.isNaN(minValue) && Float.isNaN(maxValue)) {
throw new UnsupportedOperationException(
"NaN values can only be set inside a single-point Range");
}else if (minValue < maxValue) {
this.minValue = minValue;
this.maxValue = maxValue;
this.isPoint = false;
this.isNaN = false;
this.intValue=0;
this.nanIncluded=nanIncluded;
} else if (minValue > maxValue) {
this.minValue = maxValue;
this.maxValue = minValue;
this.isPoint = false;
this.isNaN = false;
this.intValue=0;
this.nanIncluded=nanIncluded;
} else {
this.minValue = minValue;
this.maxValue = minValue;
this.isPoint = true;
this.nanIncluded=false;
if (Float.isNaN(minValue)) {
this.isNaN = true;
this.intValue=Float.floatToIntBits(minValue);
} else {
this.isNaN = false;
this.intValue=0;
}
if (!minIncluded && !maxIncluded) {
throw new IllegalArgumentException(
"Cannot create a single-point range without minimum and maximum "
+ "bounds included");
} else {
setMaxIncluded(true);
setMinIncluded(true);
}
}
}
@Override
public boolean contains(float value) {
if (isPoint) {
if (isNaN) {
int valueInt = Float.floatToIntBits(value);
return valueInt == intValue;
} else {
return this.minValue == value;
}
} else if(nanIncluded){
final boolean lower;
final boolean upper;
if (isMinIncluded()) {
lower = value < minValue;
} else {
lower = value <= minValue;
}
if (isMaxIncluded()) {
upper = value > maxValue;
} else {
upper = value >= maxValue;
}
return !lower && !upper;
}else{
final boolean notLower;
final boolean notUpper;
if (isMinIncluded()) {
notLower = value >= minValue;
} else {
notLower = value > minValue;
}
if (isMaxIncluded()) {
notUpper = value <= maxValue;
} else {
notUpper = value < maxValue;
}
return notLower && notUpper;
}
}
@Override
public DataType getDataType() {
return DataType.FLOAT;
}
@Override
public boolean isPoint() {
return isPoint;
}
@Override
public Number getMax() {
return maxValue;
}
@Override
public Number getMin() {
return minValue;
}
public Number getMax(boolean isMaxIncluded) {
float value = maxValue;
if (isMaxIncluded != isMaxIncluded()) {
value = (float) ImageUtilities.rool(getDataType().getClassValue(), value, isMaxIncluded ? -1 : +1);
}
return value;
}
public Number getMin(boolean isMinIncluded) {
float value = minValue;
if (isMinIncluded != isMinIncluded()) {
value = (float) ImageUtilities.rool(getDataType().getClassValue(), value, isMinIncluded ? -1 : +1);
}
return value;
}
public boolean isNanIncluded() {
return nanIncluded;
}
public boolean isNaN(){
return isNaN;
}
public Range union(Range other) {
if(this.contains(other)){
return this;
} else if(other.contains(this)){
return other;
}
float min2 = other.getMin().floatValue();
float max2 = other.getMax().floatValue();
float finalMin = minValue;
float finalMax = maxValue;
boolean minIncluded = isMinIncluded();
boolean maxIncluded = isMaxIncluded();
if(min2 < minValue){
finalMin = min2;
minIncluded = other.isMinIncluded();
} else if(min2 == minValue){
minIncluded |= other.isMinIncluded();
}
if(max2 > maxValue){
finalMax = max2;
maxIncluded = other.isMaxIncluded();
} else if(max2 == maxValue){
maxIncluded |= other.isMaxIncluded();
}
boolean isNaNIncluded = this.isNaN() || other.isNaN() || this.isNanIncluded() || other.isNanIncluded();
return new RangeFloat(finalMin, minIncluded, finalMax, maxIncluded, isNaNIncluded);
}
@Override
public Range intersection(Range other) {
if (other.getDataType() == getDataType()) {
if (other.contains(this)) {
return this;
} else if (this.contains(other)) {
return other;
}
}
float minOther = other.getMin().floatValue();
float maxOther = other.getMax().floatValue();
float finalMin = minValue;
float finalMax = maxValue;
boolean minIncluded = isMinIncluded();
boolean maxIncluded = isMaxIncluded();
if (minOther > minValue) {
finalMin = minOther;
minIncluded = other.isMinIncluded();
} else if (minOther == minValue) {
minIncluded &= other.isMinIncluded();
}
if (maxOther < maxValue) {
finalMax = maxOther;
maxIncluded = other.isMaxIncluded();
} else if (maxOther == maxValue) {
maxIncluded &= other.isMaxIncluded();
}
if (finalMax < finalMin || (finalMax == finalMin && !minIncluded && !maxIncluded)) {
return null;
}
boolean isNaNIncluded = this.isNaN() && other.isNaN() && this.isNanIncluded()
&& other.isNanIncluded();
return new RangeFloat(finalMin, minIncluded, finalMax, maxIncluded, isNaNIncluded);
}
}