/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.referencing.piecewise;
import org.geotools.renderer.i18n.ErrorKeys;
import org.geotools.renderer.i18n.Errors;
import org.geotools.util.NumberRange;
import org.geotools.util.SimpleInternationalString;
import org.geotools.util.Utilities;
import org.opengis.util.InternationalString;
/**
* This class implements the {@link DomainElement1D} interface in order to provide basic capabilities for {@link DomainElement1D} subclasses.
* @author Simone Giannecchini, GeoSolutions.
*
* @source $URL$
*/
public class DefaultDomainElement1D implements DomainElement1D {
/**
*
*/
private static final long serialVersionUID = -2520449231656622013L;
/**
* Base implementation for the {@link Comparable#compareTo(Object)} method.
* This method will work only if the provided input object is a
* {@link DefaultDomainElement1D}.
*
* <p>
* Two {@link DefaultDomainElement1D}s are compared by comparing their lower
* bounds in order to establish an order between them.
*
* @return a negative integer, zero, or a positive integer as this object is
* less than, equal to, or greater than the specified object.
*
* @throws ClassCastException
* if the specified object's type prevents it from being
* compared to this Object.
*
* @see Comparable#compareTo(Object)
* @todo we could improve this check for the specific case when the two minimums are equal
*/
public int compareTo(DomainElement1D o) {
if( o instanceof DefaultDomainElement1D)
return new Double(inputMinimum).compareTo( ((DefaultDomainElement1D)o).inputMinimum);
return new Double(inputMinimum).compareTo(o.getRange().getMinimum());
}
/**
* Implementation of {@link Object#equals(Object)} for {@link DomainElement1D}s.
*
* <p>
* Two {@link DefaultDomainElement1D}s are considered to be equal if they have
* the same inputr range and the same name.
*
* @param obj
* the reference object with which to compare.
* @return <code>true</code> if this object is the same as the obj
* argument; <code>false</code> otherwise.
* @see Object#equals(Object)
*/
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if(obj instanceof DefaultDomainElement1D)
return false;
final DefaultDomainElement1D that=(DefaultDomainElement1D) obj;
if(getEquivalenceClass()!=that.getEquivalenceClass())
return false;
if (!Utilities.equals(inputMinimum, that.inputMinimum))
return false;
if (!Utilities.equals(inputMaximum, that.inputMaximum))
return false;
if (!Utilities.equals(this.name, that.name))
return false;
if (!Utilities.equals(this.range, that.range))
return false;
return true;
}
protected Class<?> getEquivalenceClass(){
return DefaultDomainElement1D.class;
}
/**
* @see DomainElement1D#contains(Number)
*/
public boolean contains(Number value) {
return range.contains(value);
}
/**
* @see DomainElement1D#contains(NumberRange)
*/
public boolean contains(NumberRange<? extends Number> range) {
return this.range.contains(range);
}
/**
* @see DomainElement1D#contains(double)
*/
public boolean contains(double value) {
// return (value <= inputMaximum && value >= inputMinimum)
// || (Double.isNaN(value) && (Double.doubleToRawLongBits(value) ==
// Double
// .doubleToRawLongBits(inputMinimum)));
return (value <= inputMaximum && value >= inputMinimum)
|| (Double.doubleToRawLongBits(value) == Double
.doubleToRawLongBits(inputMinimum));
}
/**
* The domain element name.
* @uml.property name="name"
*/
private InternationalString name;
/**
* The minimal sample value (inclusive). This domain element is made of all values in the range {@code inputMinimum} to {@code inputMaximum} inclusive.
* @uml.property name="inputMinimum"
*/
private double inputMinimum;
/**
* The maximal sample value (inclusive). This domain element is made of all values in the range {@code inputMinimum} to {@code inputMaximum} inclusive.
* @uml.property name="inputMaximum"
*/
private double inputMaximum;
/**
* The range of values {@code [inputMinimum..maximum]} . May be computed only when first requested, or may be user-supplied .
* @uml.property name="range"
*/
private NumberRange<? extends Number> range;
/**
* Is lower input bound infinite?
*/
private boolean inputMinimumInf;
/**
* Is uper input bound infinite?
*/
private boolean inputMaximumInf;
/**
* Is upper input bound NaN?
* @uml.property name="inputMaximumNaN"
*/
private boolean inputMaximumNaN;
/**
* Is lower input bound NaN?
* @uml.property name="inputMinimumNaN"
*/
private boolean inputMinimumNaN;
private int hashCode=-1;
/**
* Abstract domain element constructor.
*
* <p>
* It builds up an {@link DefaultDomainElement1D} with the provided name and input
* range.
*
* @param name
* for this {@link DefaultDomainElement1D}.
* @param range
* for this {@link DefaultDomainElement1D}.
* @throws IllegalArgumentException
* in case one of the input arguments is invalid.
*/
public DefaultDomainElement1D(final CharSequence name,
final NumberRange<?> inputRange) throws IllegalArgumentException {
// /////////////////////////////////////////////////////////////////////
//
// Initial checks
//
// /////////////////////////////////////////////////////////////////////
PiecewiseUtilities.ensureNonNull("name", name);
PiecewiseUtilities.ensureNonNull("range", inputRange);
// /////////////////////////////////////////////////////////////////////
//
// Initialise fields
//
// /////////////////////////////////////////////////////////////////////
this.name = SimpleInternationalString.wrap(name);
this.range = inputRange;
Class<? extends Number> type = inputRange.getElementClass();
boolean minInc = inputRange.isMinIncluded();
boolean maxInc = inputRange.isMaxIncluded();
final double tempMin = inputRange.getMinimum();
final double tempMax = inputRange.getMaximum();
if (Double.isInfinite(tempMin)) {
this.inputMinimum = tempMin;
inputMinimumInf = true;
} else
this.inputMinimum = PiecewiseUtilities.doubleValue(type, inputRange
.getMinValue(), minInc ? 0 : +1);
if (Double.isInfinite(tempMax)) {
this.inputMaximum = tempMax;
inputMaximumInf = true;
} else
this.inputMaximum = PiecewiseUtilities.doubleValue(type, inputRange
.getMaxValue(), maxInc ? 0 : -1);
// /////////////////////////////////////////////////////////////////////
//
// Checks
//
// /////////////////////////////////////////////////////////////////////
// //
//
// only one input values is NaN
//
// //
inputMinimumNaN = Double.isNaN(inputMinimum);
inputMaximumNaN = Double.isNaN(inputMaximum);
if ((inputMinimumNaN && !inputMaximumNaN)
|| (!inputMinimumNaN && inputMaximumNaN))
throw new IllegalArgumentException(Errors.format(
ErrorKeys.BAD_RANGE_$2, inputRange.getMinValue(),
inputRange.getMaxValue()));
}
/**
* Returns a hash value for this domain element. This value need not remain
* consistent between different implementations of the same class.
*
*/
public int hashCode() {
if(hashCode>=0)
return hashCode;
hashCode=37;
hashCode=Utilities.hash( name,hashCode);
hashCode=Utilities.hash( range,hashCode);
hashCode=Utilities.hash( inputMaximum,hashCode);
hashCode=Utilities.hash( inputMinimum,hashCode);
return hashCode;
}
/**
* Getter method for this {@link DomainElement1D} 's name.
* @return this {@link DefaultDomainElement1D} 's name.
* @uml.property name="name"
*/
public InternationalString getName() {
return name;
}
/**
* Retrieves the upper bound of the range where this {@link DomainElement1D} is defined. <P> <strong>This is just a convenience method</strong>
* @return the upper bound of the range where this {@link DomainElement1D} is defined.
* @uml.property name="inputMaximum"
*/
public double getInputMaximum() {
return inputMaximum;
}
/**
* Tells us if the upper bound of the range where this {@link DomainElement1D} is
* defined is an infinite number
*
* <P>
* <strong>This is just a convenience method</strong>
*
* @return <code>true</code> if the upper bound of the range where this
* {@link DomainElement1D} is defined is infinite, <code>false</code>
* otherwise.
*/
public boolean isInputMaximumInfinite() {
return inputMaximumInf;
}
/**
* Tells us if the upper bound of the range where this {@link DomainElement1D} is defined is NaN. <P> <strong>This is just a convenience method</strong>
* @return <code>true</code> if the upper bound of the range where this {@link DomainElement1D} is defined is NaN, <code>false</code> otherwise.
* @uml.property name="inputMaximumNaN"
*/
public boolean isInputMaximumNaN() {
return inputMaximumNaN;
}
/**
* Retrieves the lower bound of the range where this {@link DomainElement1D} is defined. <P> <strong>This is just a convenience method</strong>
* @return the lower bound of the range where this {@link DomainElement1D} is defined.
* @uml.property name="inputMinimum"
*/
public double getInputMinimum() {
return inputMinimum;
}
/**
* Tells us if the lower bound of the range where this {@link DomainElement1D} is
* defined is an infinite number.
*
* <P>
* <strong>This is just a convenience method</strong>
*
* @return <code>true</code> if the lower bound of the range where this
* {@link DomainElement1D} is defined is infinite, <code>false</code>
* otherwise.
*/
public boolean isInputMinimumInfinite() {
return inputMinimumInf;
}
/**
* This method retrieves the input range.
* @return the input range.
* @uml.property name="range"
*/
public NumberRange<? extends Number> getRange() {
return range;
//return NumberRange.wrap(range);
}
/**
* Tells us if the lower bound of the range where this {@link DomainElement1D} is defined is NaN <P> <strong>This is just a convenience method</strong>
* @return <code>true</code> if the lower bound of the range where this {@link DomainElement1D} is defined is NaN, <code>false</code> otherwise.
* @uml.property name="inputMinimumNaN"
*/
public boolean isInputMinimumNaN() {
return inputMinimumNaN;
}
public String toString() {
final StringBuffer buffer= new StringBuffer("Domain description:");
buffer.append("\n").append("name=").append(name);
buffer.append("\n").append("input range=").append(range);
return buffer.toString();
}
}