/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2010-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2010-2012, Geomatys
*
* 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.geotoolkit.referencing.cs;
import java.util.Set;
import java.util.Arrays;
import java.util.Collection;
import java.io.Serializable;
import javax.measure.Unit;
import org.opengis.util.GenericName;
import org.opengis.util.InternationalString;
import org.opengis.metadata.Identifier;
import org.opengis.referencing.cs.RangeMeaning;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.geotoolkit.lang.Decorator;
import org.apache.sis.measure.NumberRange;
/**
* A default implementation of {@link DiscreteCoordinateSystemAxis}. This implementation wraps
* an existing axis and adds discrete ordinate values. While not mandatory, the ordinates values
* are better to be in strictly increasing or decreasing order (this is not verified).
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.20
*
* @since 3.15
* @module
*/
@Decorator(CoordinateSystemAxis.class)
final class DiscreteAxis implements CoordinateSystemAxis, DiscreteCoordinateSystemAxis<Double>, Serializable {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 7456302077762863016L;
/**
* The axis on which to delegates every method calls.
*/
protected final CoordinateSystemAxis axis;
/**
* The ordinate values. <strong>Do not modify the ordinate values</strong>.
*/
final double[] ordinates;
/**
* Constructs a new coordinate system axis which delegates every method calls to
* the given axis.
*
* @param axis The coordinate system axis to wrap.
* @param ordinates The ordinate values. This array is <strong>not</strong> cloned.
*/
DiscreteAxis(final CoordinateSystemAxis axis, final double... ordinates) {
this.axis = axis;
this.ordinates = ordinates;
}
/**
* Returns the name of the wrapped axis.
*/
@Override
public Identifier getName() {
return axis.getName();
}
/**
* Returns the alias of the wrapped axis.
*/
@Override
public Collection<GenericName> getAlias() {
return axis.getAlias();
}
/**
* Returns the identifiers of the wrapped axis.
*/
@Override
public Set<Identifier> getIdentifiers() {
return axis.getIdentifiers();
}
/**
* The abbreviation used by the wrapped axis.
*/
@Override
public String getAbbreviation() {
return axis.getAbbreviation();
}
/**
* Returns the direction of the wrapped axis.
*/
@Override
public AxisDirection getDirection() {
return axis.getDirection();
}
/**
* Returns the range meaning of the wrapped axis. Note that this is not related
* to {@link #getOrdinateRangeAt(int)}.
*/
@Override
public RangeMeaning getRangeMeaning() {
return axis.getRangeMeaning();
}
/**
* Returns the unit of the wrapped axis.
*/
@Override
public Unit<?> getUnit() {
return axis.getUnit();
}
/**
* Returns the minimal value of the wrapped axis.
*/
@Override
public double getMinimumValue() {
return axis.getMinimumValue();
}
/**
* Returns the maximal value of the wrapped axis.
*/
@Override
public synchronized double getMaximumValue() {
return axis.getMaximumValue();
}
/**
* Returns the number of ordinate values.
*/
@Override
public int length() {
return ordinates.length;
}
/**
* Returns the type of ordinate values.
*
* @since 3.20
*/
@Override
public Class<Double> getElementType() {
return Double.class;
}
/**
* Returns the ordinate value at the given index.
*/
@Override
public Double getOrdinateAt(final int index) throws IndexOutOfBoundsException {
return ordinates[index];
}
/**
* Returns the range at the given index.
*/
@Override
public NumberRange<Double> getOrdinateRangeAt(final int index) throws IndexOutOfBoundsException {
if (ordinates.length < 2) {
throw new UnsupportedOperationException();
}
final double value = ordinates[index];
final int lower = (index == 0) ? 0 : index-1;
final int upper = Math.min(ordinates.length-1, index+1);
double min = value - 0.5*(ordinates[lower + 1] - ordinates[lower]);
double max = value + 0.5*(ordinates[upper] - ordinates[upper - 1]);
final boolean decreasing = (min > max);
if (decreasing) {
final double tmp = min;
min = max;
max = tmp;
}
return NumberRange.create(min, !decreasing, max, decreasing);
}
/**
* Returns the remarks of the wrapped axis.
*/
@Override
public InternationalString getRemarks() {
return axis.getRemarks();
}
/**
* Returns the WKT formatted by the wrapped axis. We can delegates directly to
* the wrapped array because the ordinate values are not part of WKT formatting.
*/
@Override
public String toWKT() throws UnsupportedOperationException {
return axis.toWKT();
}
/**
* Returns the string representation of the wrapped axis.
* This is usually the same than the WKT representation.
*/
@Override
public String toString() {
return axis.toString();
}
/**
* Returns a hash code value for this axis.
*/
@Override
public int hashCode() {
return axis.hashCode() + 31 * Arrays.hashCode(ordinates);
}
/**
* Compares this axis with the given object for equality.
*
* @param other The object to compare with this axis for equality.
*/
@Override
public boolean equals(final Object other) {
if (other instanceof DiscreteAxis) {
final DiscreteAxis that = (DiscreteAxis) other;
return axis.equals(that.axis) && Arrays.equals(ordinates, that.ordinates);
}
return false;
}
}