/* 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.piecewise; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.range.RangeFactory; /** * 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 { /** * UID */ 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().getMin().doubleValue()); } /** * 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 (!PiecewiseUtilities.equals(inputMinimum, that.inputMinimum)) return false; if (!PiecewiseUtilities.equals(inputMaximum, that.inputMaximum)) return false; if (!this.name.equals(that.name)) return false; if (!this.range.equals(that.range)) return false; return true; } protected Class<?> getEquivalenceClass() { return DefaultDomainElement1D.class; } /** * @see DomainElement1D#contains(Number) */ public boolean contains(Number value) { return range.containsN(value); } /** * @see DomainElement1D#contains(NumberRange) */ public boolean contains(Range range) { return this.range.contains(range); } /** * @see DomainElement1D#contains(double) */ public boolean contains(double value) { return (value <= inputMaximum && value >= inputMinimum) || (Double.doubleToRawLongBits(value) == Double.doubleToRawLongBits(inputMinimum)); } /** * The domain element name. * * @uml.property name="name" */ private String 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 Range 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 Range inputRange) throws IllegalArgumentException { // ///////////////////////////////////////////////////////////////////// // // Initial checks // // ///////////////////////////////////////////////////////////////////// PiecewiseUtilities.ensureNonNull("name", name); PiecewiseUtilities.ensureNonNull("range", inputRange); // ///////////////////////////////////////////////////////////////////// // // Initialise fields // // ///////////////////////////////////////////////////////////////////// this.name = name + ""; this.range = RangeFactory.convertToDoubleRange(inputRange); Class<? extends Number> type = inputRange.getDataType().getClassValue(); boolean minInc = inputRange.isMinIncluded(); boolean maxInc = inputRange.isMaxIncluded(); final double tempMin = inputRange.getMin().doubleValue(); final double tempMax = inputRange.getMax().doubleValue(); if (Double.isInfinite(tempMin)) { this.inputMinimum = tempMin; inputMinimumInf = true; } else this.inputMinimum = PiecewiseUtilities.doubleValue(type, inputRange.getMin() .doubleValue(), minInc ? 0 : +1); if (Double.isInfinite(tempMax)) { this.inputMaximum = tempMax; inputMaximumInf = true; } else this.inputMaximum = PiecewiseUtilities.doubleValue(type, inputRange.getMax() .doubleValue(), 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("Bad Range format: " + inputRange.getMin() + "/ " + inputRange.getMax()); } /** * 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 = PiecewiseUtilities.hash(name, hashCode); hashCode = PiecewiseUtilities.hash(range, hashCode); hashCode = PiecewiseUtilities.hash(inputMaximum, hashCode); hashCode = PiecewiseUtilities.hash(inputMinimum, hashCode); return hashCode; } /** * Getter method for this {@link DomainElement1D} 's name. * * @return this {@link DefaultDomainElement1D} 's name. * @uml.property name="name" */ public String 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 Range getRange() { return 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 StringBuilder buffer = new StringBuilder("Domain description:"); buffer.append("\n").append("name=").append(name); buffer.append("\n").append("input range=").append(range); return buffer.toString(); } }