/* * Geotools 2 - OpenSource mapping toolkit * (C) 2003, Geotools Project Management Committee (PMC) * (C) 2001, Institut de Recherche pour le Développement * * 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; either * version 2.1 of the License, or (at your option) any later version. * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * This package contains documentation from OpenGIS specifications. * OpenGIS consortium's work is fully acknowledged here. */ package org.geotools.cv; // J2SE dependencies import java.awt.image.DataBuffer; import java.awt.image.SampleModel; import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.util.Locale; import java.util.NoSuchElementException; import javax.media.jai.EnumeratedParameter; import javax.media.jai.util.Range; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Errors; import org.geotools.resources.i18n.VocabularyKeys; import org.geotools.resources.i18n.Vocabulary; import org.opengis.cv.CV_SampleDimensionType; /** * Contains information for an individual sample dimension of coverage. * This interface is applicable to any coverage type. * For grid coverages, the sample dimension refers to an individual band. * * @source $URL$ * @version $Id$ * @author OpenGIS * @author Martin Desruisseaux * * @see org.opengis.cv.CV_SampleDimensionType * * @deprecated Replaced by {@link org.opengis.coverage.SampleDimensionType} in the * org.opengis.coverage package. */ public final class SampleDimensionType extends EnumeratedParameter { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = 8172733477873830772L; /** * 1 bit integers. * * @see CV_SampleDimensionType#CV_1BIT * @see DataBuffer#TYPE_BYTE */ public static final SampleDimensionType BIT = new SampleDimensionType("BIT", CV_SampleDimensionType.CV_1BIT, DataBuffer.TYPE_BYTE, (byte)1, false, false, org.opengis.coverage.SampleDimensionType.UNSIGNED_1BIT); /** * 2 bits integers. * * @see CV_SampleDimensionType#CV_2BIT * @see DataBuffer#TYPE_BYTE */ public static final SampleDimensionType DOUBLET = new SampleDimensionType("DOUBLET", CV_SampleDimensionType.CV_2BIT, DataBuffer.TYPE_BYTE, (byte)2, false, false, org.opengis.coverage.SampleDimensionType.UNSIGNED_2BITS); /** * 4 bits integers (also called "quartet" or "half-byte"). * * @see CV_SampleDimensionType#CV_4BIT * @see DataBuffer#TYPE_BYTE */ public static final SampleDimensionType NIBBLE = new SampleDimensionType("NIBBLE", CV_SampleDimensionType.CV_4BIT, DataBuffer.TYPE_BYTE, (byte)4, false, false, org.opengis.coverage.SampleDimensionType.UNSIGNED_4BITS); /** * Unsigned 8 bits integers. * * @see CV_SampleDimensionType#CV_8BIT_U * @see DataBuffer#TYPE_BYTE */ public static final SampleDimensionType UBYTE = new SampleDimensionType("UBYTE", CV_SampleDimensionType.CV_8BIT_U, DataBuffer.TYPE_BYTE, (byte)8, false, false, org.opengis.coverage.SampleDimensionType.UNSIGNED_8BITS); /** * Signed 8 bits integers. * The equivalent Java data type is {@link DataBuffer#TYPE_BYTE}. * * @see CV_SampleDimensionType#CV_8BIT_S * @see DataBuffer#TYPE_BYTE */ public static final SampleDimensionType BYTE = new SampleDimensionType("BYTE", CV_SampleDimensionType.CV_8BIT_S, DataBuffer.TYPE_BYTE, (byte)8, true, false, org.opengis.coverage.SampleDimensionType.SIGNED_8BITS); /** * Unsigned 16 bits integers. * The equivalent Java data type is {@link DataBuffer#TYPE_USHORT}. * * @see CV_SampleDimensionType#CV_16BIT_U * @see DataBuffer#TYPE_USHORT */ public static final SampleDimensionType USHORT = new SampleDimensionType("USHORT", CV_SampleDimensionType.CV_16BIT_U, DataBuffer.TYPE_USHORT, (byte)16, false, false, org.opengis.coverage.SampleDimensionType.UNSIGNED_16BITS); /** * Signed 16 bits integers. * The equivalent Java data type is {@link DataBuffer#TYPE_SHORT}. * * @see CV_SampleDimensionType#CV_16BIT_S * @see DataBuffer#TYPE_SHORT */ public static final SampleDimensionType SHORT = new SampleDimensionType("SHORT", CV_SampleDimensionType.CV_16BIT_S, DataBuffer.TYPE_SHORT, (byte)16, true, false, org.opengis.coverage.SampleDimensionType.SIGNED_16BITS); /** * Unsigned 32 bits integers. * * @see CV_SampleDimensionType#CV_32BIT_U * @see DataBuffer#TYPE_INT */ public static final SampleDimensionType UINT = new SampleDimensionType("UINT", CV_SampleDimensionType.CV_32BIT_U, DataBuffer.TYPE_INT, (byte)32, false, false, org.opengis.coverage.SampleDimensionType.UNSIGNED_32BITS); /** * Signed 32 bits integers. * The equivalent Java data type is {@link DataBuffer#TYPE_INT}. * * @see CV_SampleDimensionType#CV_32BIT_S * @see DataBuffer#TYPE_INT */ public static final SampleDimensionType INT = new SampleDimensionType("INT", CV_SampleDimensionType.CV_32BIT_S, DataBuffer.TYPE_INT, (byte)32, true, false, org.opengis.coverage.SampleDimensionType.SIGNED_32BITS); /** * Simple precision floating point numbers. * The equivalent Java data type is {@link DataBuffer#TYPE_FLOAT}. * * @see CV_SampleDimensionType#CV_32BIT_REAL * @see DataBuffer#TYPE_FLOAT */ public static final SampleDimensionType FLOAT = new SampleDimensionType("FLOAT", CV_SampleDimensionType.CV_32BIT_REAL, DataBuffer.TYPE_FLOAT, (byte)32, true, true, org.opengis.coverage.SampleDimensionType.REAL_32BITS); /** * Double precision floating point numbers. * The equivalent Java data type is {@link DataBuffer#TYPE_DOUBLE}. * * @see CV_SampleDimensionType#CV_64BIT_REAL * @see DataBuffer#TYPE_DOUBLE */ public static final SampleDimensionType DOUBLE = new SampleDimensionType("DOUBLE", CV_SampleDimensionType.CV_64BIT_REAL, DataBuffer.TYPE_DOUBLE, (byte)64, true, true, org.opengis.coverage.SampleDimensionType.REAL_64BITS); /** * Color interpretation by value. Used to * canonicalize after deserialization. */ private static final SampleDimensionType[] ENUMS = { BIT, DOUBLET, NIBBLE, UBYTE, BYTE, USHORT, SHORT, UINT, INT, FLOAT, DOUBLE }; static { for (int i=0; itrue for signed sample type. */ private final boolean signed; /** * true for floating-point data type. */ private final boolean real; /** * The GeoAPI code. */ private final org.opengis.coverage.SampleDimensionType geoAPI; /** * Construct a new enum with the specified value. */ private SampleDimensionType(final String name, final int value, final int type, final byte size, final boolean signed, final boolean real, org.opengis.coverage.SampleDimensionType geoAPI) { super(name, value); this.type = type; this.size = size; this.signed = signed; this.real = real; this.geoAPI = geoAPI; } /** * Return the enum for the specified value. * This method is provided for compatibility with * {@link org.opengis.cv.CV_SampleDimensionType}. * * @param value The enum value. * @return The enum for the specified value. * @throws NoSuchElementException if there is no enum for the specified value. */ public static SampleDimensionType getEnum(final int value) throws NoSuchElementException { if (value>=0 && valueinclusive as well. * @return The enum for the specified range. */ static SampleDimensionType getEnum(double min, double max) { final long lgMin = (long) min; if (lgMin == min) { final long lgMax = (long) max; if (lgMax == max) { return getEnum(lgMin, lgMax); } } min = Math.abs(min); max = Math.abs(max); if (Math.min(min,max)>=Float.MIN_VALUE && Math.max(min,max)<=Float.MAX_VALUE) { return FLOAT; } return DOUBLE; } /** * Returns the enum for the smallest type capable to hold the specified range of values. * * @param min The lower value, inclusive. * @param max The upper value, inclusive as well. * @return The enum for the specified range. */ static SampleDimensionType getEnum(final long min, final long max) { if (min >= 0) { if (max < (1L << 1)) return BIT; if (max < (1L << 2)) return DOUBLET; if (max < (1L << 4)) return NIBBLE; if (max < (1L << 8)) return UBYTE; if (max < (1L << 16)) return USHORT; if (max < (1L << 32)) return UINT; } else { if (min>=Byte .MIN_VALUE && max<=Byte .MAX_VALUE) return BYTE; if (min>=Short .MIN_VALUE && max<=Short .MAX_VALUE) return SHORT; if (min>=Integer.MIN_VALUE && max<=Integer.MAX_VALUE) return INT; } return FLOAT; } /** * Return the enum for the specified sample model and band number. * If the sample model use an undefined data type, then this method * returns null. * * @param model The sample model. * @param band The band to query. * @return The enum for the specified sample model and band number. * @throws IllegalArgumentException if the band number is not in the valid range. */ public static SampleDimensionType getEnum(final SampleModel model, final int band) throws IllegalArgumentException { if (band<0 || band>=model.getNumBands()) { throw new IllegalArgumentException( Errors.format(ErrorKeys.BAD_BAND_NUMBER_$1, new Integer(band))); } boolean signed = true; switch (model.getDataType()) { case DataBuffer.TYPE_DOUBLE: return DOUBLE; case DataBuffer.TYPE_FLOAT: return FLOAT; case DataBuffer.TYPE_USHORT: signed=false; // Fall through case DataBuffer.TYPE_INT: case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_BYTE: { switch (model.getSampleSize(band)) { case 1: return BIT; case 2: return DOUBLET; case 4: return NIBBLE; case 8: return signed ? BYTE : UBYTE; case 16: return signed ? SHORT : USHORT; case 32: return signed ? INT : UINT; } } } return null; } /** * Returns this enum's name in the specified locale. If no name is available for * the specified locale, a default one will be used. For example, the localized * name for {@link #SHORT} is "16 bits unsigned integer" in English * and "Entier non-signé sur 16 bits" in French. * * @param locale The locale, or null for the default locale. * @return Enum's name in the specified locale. */ public String getName(final Locale locale) { return Vocabulary.getResources(locale).getString(VocabularyKeys.DATA_TYPE_$2, new Integer(real ? 2 : signed ? 1 : 0), new Integer(size)); } /** * Returns the {@link DataBuffer} type. This is one of the following constants: * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, * {@link DataBuffer#TYPE_SHORT}, {@link DataBuffer#TYPE_INT}, * {@link DataBuffer#TYPE_FLOAT}, {@link DataBuffer#TYPE_DOUBLE}. */ public int getDataBufferType() { return type; } /** * Returns the size in bits. The value range from 1 to 64. This is similar, but * different than {@link DataBuffer#getDataTypeSize}, which have values ranging * from 8 to 64. */ public int getSize() { return size; } /** * Returns true for signed sample type. * true is returned for {@link #BYTE}, {@link #SHORT}, * {@link #INT}, {@link #FLOAT} and {@link #DOUBLE}. */ public boolean isSigned() { return signed; } /** * Returns true for floating-point data type. * true is returned for {@link #FLOAT} and {@link #DOUBLE}. */ public boolean isFloatingPoint() { return real; } /** * Wrap the specified value into a number of this sample data type. If the * value can't fit in a {@link Number} object of this sample type, then a wider * type is choosen unless allowWidening is false. * * @param value The value to wrap in a {@link Number} object. * @param allowWidening true if this method is allowed to returns * a wider type than the usual one for this sample type. * @return The value as a {@link Number}. * @throws IllegalArgumentException if allowWidening is false * and the specified value can't fit in a {@link Number} of this * sample type. */ Number wrapSample(double value, boolean allowWidening) throws IllegalArgumentException { return wrapSample(value, getValue(), allowWidening); } /** * Wrap the specified value into a number of the specified data type. The type * must be one constant of the {@link CV_SampleDimensionType} interface. If the * value can't fit in the specified type, then a wider type is choosen unless * allowWidening is false. * * @param value The value to wrap in a {@link Number} object. * @param type A constant from the {@link CV_SampleDimensionType} interface. * @param allowWidening true if this method is allowed to returns * a wider type than the usual one for the specified type. * @return The value as a {@link Number}. * @throws IllegalArgumentException if type is not a recognized constant. * @throws IllegalArgumentException if allowWidening is false * and the specified value can't fit in the specified sample type. */ static Number wrapSample(final double value, final int type, final boolean allowWidening) throws IllegalArgumentException { switch (type) { case CV_SampleDimensionType.CV_1BIT: // Fall through case CV_SampleDimensionType.CV_2BIT: // Fall through case CV_SampleDimensionType.CV_4BIT: // Fall through case CV_SampleDimensionType.CV_8BIT_S: { final byte candidate = (byte) value; if (candidate == value) { return new Byte(candidate); } if (!allowWidening) break; // Fall through } case CV_SampleDimensionType.CV_8BIT_U: // Fall through case CV_SampleDimensionType.CV_16BIT_S: { final short candidate = (short) value; if (candidate == value) { return new Short(candidate); } if (!allowWidening) break; // Fall through } case CV_SampleDimensionType.CV_16BIT_U: // Fall through case CV_SampleDimensionType.CV_32BIT_S: { final int candidate = (int) value; if (candidate == value) { return new Integer(candidate); } if (!allowWidening) break; // Fall through } case CV_SampleDimensionType.CV_32BIT_U: { final long candidate = (long) value; if (candidate == value) { return new Long(candidate); } if (!allowWidening) break; // Fall through } case CV_SampleDimensionType.CV_32BIT_REAL: { if (!allowWidening || Math.abs(value) <= Float.MAX_VALUE) { return new Float((float) value); } // Fall through } case CV_SampleDimensionType.CV_64BIT_REAL: { return new Double(value); } default: { throw new IllegalArgumentException(String.valueOf(type)); } } throw new IllegalArgumentException(String.valueOf(value)); } /** * Use a single instance of {@link SampleDimensionType} after deserialization. * It allow client code to test enum1==enum2 instead of * enum1.equals(enum2). * * @return A single instance of this enum. * @throws ObjectStreamException is deserialization failed. */ private Object readResolve() throws ObjectStreamException { try { return getEnum(getValue()); } catch (NoSuchElementException cause) { InvalidObjectException e = new InvalidObjectException("Unknow enum"); e.initCause(cause); throw e; } } }