/* 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; /** * Convenience class for linear transformations that maps an interval to another interval. * * @author Simone Giannecchini, GeoSolutions * * @source $URL$ */ public class DefaultLinearPiecewiseTransform1DElement extends DefaultPiecewiseTransform1DElement implements PiecewiseTransform1DElement { /** * UID */ private static final long serialVersionUID = 4026834241134908025L; /** * @uml.property name="outputMaximum" */ private double outputMaximum; /** * @uml.property name="outputMinimum" */ private double outputMinimum; /** * @uml.property name="outputRange" */ private Range outputRange; /** * @uml.property name="outputMinimumNaN" */ private boolean outputMinimumNaN; /** * @uml.property name="outputMaximumNaN" */ private boolean outputMaximumNaN; /** * @uml.property name="outputMinimumInfinite" */ private boolean outputMinimumInfinite; /** * @uml.property name="outputMaximumInfinite" */ private boolean outputMaximumInfinite; /** * Constructor. * * @param name for this {@link DefaultLinearPiecewiseTransform1DElement}. * @param inRange for this {@link DefaultLinearPiecewiseTransform1DElement}. * @param outRange for this {@link DefaultLinearPiecewiseTransform1DElement}. */ public DefaultLinearPiecewiseTransform1DElement(CharSequence name, Range inRange, Range outRange) { super(name, inRange); this.outputRange = RangeFactory.convertToDoubleRange(outRange); // ///////////////////////////////////////////////////////////////////// // // Checks // // ///////////////////////////////////////////////////////////////////// // // // // the output class can only be integer // // // final Class<? extends Number> type = outRange.getDataType().getClassValue(); boolean minInc = outRange.isMinIncluded(); boolean maxInc = outRange.isMaxIncluded(); outputMinimum = PiecewiseUtilities.doubleValue(type, outRange.getMin(), minInc ? 0 : +1); outputMaximum = PiecewiseUtilities.doubleValue(type, outRange.getMax(), maxInc ? 0 : -1); outputMinimumNaN = Double.isNaN(outputMinimum); outputMaximumNaN = Double.isNaN(outputMaximum); outputMinimumInfinite = Double.isInfinite(outputMinimum); outputMaximumInfinite = Double.isInfinite(outputMaximum); // // // // No open intervals for the output range // // // if (outputMinimumInfinite || outputMaximumInfinite) { throw new IllegalArgumentException("Bad range defined"); } final int compareOutBounds = PiecewiseUtilities.compare(outputMinimum, outputMaximum); // // // // the output values are correctly ordered // // // if (compareOutBounds > 0) { throw new IllegalArgumentException("Bad range defined"); } // // // // mapping NaN to a single value // // // if (isInputMaximumNaN() && isInputMinimumNaN()) if (compareOutBounds == 0) { setTransform(SingleDimensionTransformation.create(0, outputMinimum)); setInverse(SingleDimensionTransformation.create(outputMinimum, 0)); return; } else throw new IllegalArgumentException("Bad range defined"); // // // // Mapping an open interval to a single value, there is no way to map an // open interval to another interval! // // // if (isInputMaximumInfinite() || isInputMinimumInfinite()) if (compareOutBounds == 0) { setTransform(PiecewiseUtilities.createLinearTransform1D(0, outputMinimum)); setInverse(null); return; } else throw new IllegalArgumentException("Bad range defined"); final MathTransformation transform = PiecewiseUtilities.createLinearTransform1D(inRange, RangeFactory.create(outputMinimum, true, outputMaximum, true, true)); setTransform(transform); // // // // Checking the created transformation // // // assert transform instanceof SingleDimensionTransformation; assert !Double.isNaN(((SingleDimensionTransformation) transform).getScale()) && !Double.isInfinite(((SingleDimensionTransformation) transform).getScale()); // // // // Inverse // // // SingleDimensionTransformation tempTransform = (SingleDimensionTransformation) transform; final double scale = tempTransform.getScale(); if (Math.abs(scale) < 1E-6) if (PiecewiseUtilities.compare(getInputMaximum(), getInputMinimum()) == 0) setInverse(SingleDimensionTransformation.create(0, getInputMinimum())); else setInverse(null); else setInverse((MathTransformation) transform.inverseTransform()); } /** * Returns the maximum output values for this {@link DefaultLinearPiecewiseTransform1DElement} ; * * @return the maximum output values for this {@link DefaultLinearPiecewiseTransform1DElement} ; * @uml.property name="outputMaximum" */ public double getOutputMaximum() { return outputMaximum; } /** * Returns the minimum output values for this {@link DefaultLinearPiecewiseTransform1DElement} ; * * @return the minimum output values for this {@link DefaultLinearPiecewiseTransform1DElement} ; * @uml.property name="outputMinimum" */ public double getOutputMinimum() { return outputMinimum; } /** * Returns the range for the output values for this {@link DefaultLinearPiecewiseTransform1DElement} ; * * @return the range for the output values for this {@link DefaultLinearPiecewiseTransform1DElement} ; * @uml.property name="outputRange" */ public Range getOutputRange() { return outputRange; } /** * Tells me if the lower boundary of the output range is NaN * * @return <code>true</code> if the lower boundary of the output range is NaN, <code>false</code> otherwise. * @uml.property name="outputMinimumNaN" */ public boolean isOutputMinimumNaN() { return outputMinimumNaN; } /** * Tells me if the upper boundary of the output range is NaN * * @return <code>true</code> if the upper boundary of the output range is NaN, <code>false</code> otherwise. * @uml.property name="outputMaximumNaN" */ public boolean isOutputMaximumNaN() { return outputMaximumNaN; } /** * Tells me if the lower boundary of the output range is infinite * * @return <code>true</code> if the lower boundary of the output range is infinite, <code>false</code> otherwise. * @uml.property name="outputMinimumInfinite" */ public boolean isOutputMinimumInfinite() { return outputMinimumInfinite; } /** * Tells me if the upper boundary of the output range is infinite * * @return <code>true</code> if the upper boundary of the output range is infinite, <code>false</code> otherwise. * @uml.property name="outputMaximumInfinite" */ public boolean isOutputMaximumInfinite() { return outputMaximumInfinite; } /** * Retrieves the scale factor for this linear {@link PiecewiseTransform1DElement}. * * @return the scale factor for this linear {@link PiecewiseTransform1DElement}. */ public double getScale() { // get the transform at this point it is linear for sure final SingleDimensionTransformation transform = (SingleDimensionTransformation) getTransform(); return transform.getScale(); } /** * Retrieves the offset factor for this linear {@link PiecewiseTransform1DElement}. * * @return the offset factor for this linear {@link PiecewiseTransform1DElement}. */ public double getOffset() { // get the transform at this point it is linear for sure final SingleDimensionTransformation transform = (SingleDimensionTransformation) getTransform(); return transform.getOffset(); } /* * (non-Javadoc) * * @see DefaultPiecewiseTransform1DElement#toString() */ public String toString() { final StringBuilder buffer = new StringBuilder(super.toString()); buffer.append("\n").append("output range=").append(this.outputRange); return buffer.toString(); } protected Class<?> getEquivalenceClass() { return DefaultLinearPiecewiseTransform1DElement.class; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof DefaultLinearPiecewiseTransform1DElement)) return false; final DefaultLinearPiecewiseTransform1DElement that = (DefaultLinearPiecewiseTransform1DElement) obj; if (that.getEquivalenceClass() != this.getEquivalenceClass()) return false; if (!outputRange.equals(that.outputRange)) return false; if (!PiecewiseUtilities.equals(outputMaximum, that.outputMaximum)) return false; if (!PiecewiseUtilities.equals(outputMinimum, that.outputMinimum)) return false; return super.equals(obj); } @Override public int hashCode() { int hashCode = 37; hashCode = PiecewiseUtilities.hash(outputRange, hashCode); hashCode = PiecewiseUtilities.hash(outputMaximum, hashCode); hashCode = PiecewiseUtilities.hash(outputMinimum, hashCode); hashCode = PiecewiseUtilities.hash(super.hashCode(), hashCode); return hashCode; } }