001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2007, Geotools Project Managment Committee (PMC)
005: * (C) 2007, Geomatys
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.image.io.netcdf;
018:
019: import java.util.Map;
020: import java.util.Set;
021: import java.util.List;
022: import java.util.HashMap;
023: import java.util.HashSet;
024: import javax.imageio.ImageReader;
025:
026: import ucar.nc2.dataset.AxisType;
027: import ucar.nc2.dataset.CoordinateAxis;
028: import ucar.nc2.dataset.CoordinateSystem;
029: import ucar.nc2.dataset.VariableEnhanced;
030:
031: import org.geotools.image.io.GeographicImageReadParam;
032: import org.geotools.resources.i18n.ErrorKeys;
033: import org.geotools.resources.i18n.Errors;
034:
035: /**
036: * Default parameters for {@link NetcdfImageReader}.
037: *
038: * @since 2.4
039: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio-netcdf/src/main/java/org/geotools/image/io/netcdf/NetcdfReadParam.java $
040: * @version $Id: NetcdfReadParam.java 27071 2007-09-19 19:02:54Z desruisseaux $
041: * @author Martin Desruisseaux
042: */
043: public class NetcdfReadParam extends GeographicImageReadParam {
044: /**
045: * The default source band to read from the NetCDF file. Also the default indice for
046: * any additional dimension after the one assigned to bands. We use the same default
047: * for consistency, because the third dimension (typically <var>z</var>) could be
048: * selected either by {@link #setSourceBands} or by {@link #setSliceIndice}; the
049: * relevant method depends on {@link NetcdfImageReader#getBandDimension} value.
050: */
051: static final int DEFAULT_INDICE = 0;
052:
053: /**
054: * The default source bands to read from the NetCDF file.
055: * Also the default destination bands in the buffered image.
056: */
057: private static final int[] DEFAULT_BANDS = new int[] { DEFAULT_INDICE };
058:
059: /**
060: * The types of the dimension to use as image bands. If more than one type is specified,
061: * only the first dimension with a suitable type will be assigned to bands.
062: */
063: private Set/*<AxisType>*/bandDimensionTypes;
064:
065: /**
066: * For <var>n</var>-dimensional images, the indices to use for dimensions above 2.
067: * Will be created only when first needed.
068: */
069: private Map/*<AxisType,Integer>*/sliceIndices;
070:
071: /**
072: * Creates a new, initially empty, set of parameters.
073: *
074: * @param reader The reader for which this parameter block is created
075: */
076: public NetcdfReadParam(final ImageReader reader) {
077: super (reader);
078: setSourceBands(DEFAULT_BANDS);
079: setDestinationBands(DEFAULT_BANDS);
080: }
081:
082: /**
083: * Returns the dimension to assign to bands for the specified variable. The default
084: * implementation returns the last dimension corresponding to one of the types specified
085: * to {@link #setBandDimensionTypes}.
086: * <p>
087: * <b>Example:</b> For a NetCDF variable having dimensions in the
088: * (<var>t</var>,<var>z</var>,<var>y</var>,<var>x</var>) order (as in CF convention), if the
089: * {@linkplain AxisType#Height height} and {@linkplain AxisType#Pressure pressure} types have
090: * been {@linkplain #setBandDimensionTypes assigned} to bands, then this method will returns
091: * the index of the <var>z</var> dimension, i.e. {@code 1}.
092: *
093: * @param variable The variable for which we want to determine the dimension to assign to bands.
094: * @return The dimension assigned to bands, or {@code -1} if none.
095: */
096: public int getBandDimension(final VariableEnhanced variable) {
097: if (bandDimensionTypes != null) {
098: final List sys = variable.getCoordinateSystems();
099: if (sys != null) {
100: final int count = sys.size();
101: for (int i = 0; i < count; i++) {
102: final CoordinateSystem cs = (CoordinateSystem) sys
103: .get(i);
104: final List axes = cs.getCoordinateAxes();
105: if (axes != null) {
106: for (int j = axes.size(); --j >= 0;) { // Must be reverse order; see javadoc
107: final CoordinateAxis axis = (CoordinateAxis) axes
108: .get(j);
109: if (axis != null
110: && bandDimensionTypes.contains(axis
111: .getAxisType())) {
112: return j;
113: }
114: }
115: }
116: }
117: }
118: }
119: return -1;
120: }
121:
122: /**
123: * Returns the dimension assigned to bands. This method returns the values given
124: * to the last call to {@link #setBandDimensionTypes}, or {@code null} if none.
125: */
126: public AxisType[] getBandDimensionTypes() {
127: if (bandDimensionTypes == null) {
128: return null;
129: }
130: return (AxisType[]) bandDimensionTypes
131: .toArray(new AxisType[bandDimensionTypes.size()]);
132: }
133:
134: /**
135: * Assigns the dimension of the specified types to bands. For example in a NetCDF variable
136: * having (<var>t</var>,<var>y</var>,<var>x</var>) dimensions, it may be useful to treat
137: * the <var>t</var> dimension as bands. After invoking this method with the
138: * {@linkplain AxisType#Time time} value, users can select a time through the standard
139: * {@link #setSourceBands} API.
140: * <p>
141: * More than one type may be specified if they should be considered as synonymous. For example
142: * in order to assign the <var>z</var> dimension to bands, it may be necessary to specify both
143: * the {@linkplain AxisType#Height height} and {@linkplain AxisType#Pressure pressure} types.
144: *
145: * @param type The types of dimension to assign to bands.
146: *
147: * @todo Use vararg when we will be allowed to compile for J2SE 1.5.
148: */
149: public void setBandDimensionTypes(final AxisType[] types) {
150: if (types != null && types.length != 0) {
151: if (bandDimensionTypes == null) {
152: bandDimensionTypes = new HashSet/*<AxisType>*/();
153: } else {
154: bandDimensionTypes.clear();
155: }
156: for (int i = 0; i < types.length; i++) {
157: bandDimensionTypes.add(types[i]);
158: }
159: } else {
160: bandDimensionTypes = null;
161: }
162: }
163:
164: /**
165: * Returns the indice to set at the dimension of the specified axis. This is relevant only
166: * for <var>n</var>-dimensional data set where <var>n</var>>2. This method returns the
167: * last value set by {@link #setSliceIndice}.
168: *
169: * @param dimension The axis type (typically {@linkplain AxisType#Height height} or
170: * {@linkplain AxisType#Time time}).
171: * @return The indice to set at the dimension of the specified axis (0 by default).
172: */
173: public int getSliceIndice(final AxisType axis) {
174: if (sliceIndices != null) {
175: final Integer indice = (Integer) sliceIndices.get(axis);
176: if (indice != null) {
177: return indice.intValue();
178: }
179: }
180: return DEFAULT_INDICE;
181: }
182:
183: /**
184: * Sets the indice for the dimension of the specified axis. This is relevant only for
185: * <var>n</var>-dimensional data set where <var>n</var>>2. For example in 4-D data
186: * set with (<var>x</var>,<var>y</var>,<var>z</var>,<var>t</var>) axis, those indices
187: * may be used by image readers for <var>z</var> and <var>t</var> dimensions.
188: * <p>
189: * The default value is 0 for all cases. This means that for the above-cited 4-D data set,
190: * only the image at the first time (<var>t</var>=0) and first altitude (<var>z</var>=0)
191: * is selected.
192: *
193: * @param dimension The axis type (typically {@linkplain AxisType#Height height} or
194: * {@linkplain AxisType#Time time}).
195: * @param indice The indice as a positive value.
196: */
197: public void setSliceIndice(final AxisType dimension,
198: final int indice) {
199: if (indice < 0) {
200: throw new IllegalArgumentException(Errors.format(
201: ErrorKeys.ILLEGAL_ARGUMENT_$2, "indice",
202: new Integer(indice)));
203: }
204: if (indice != DEFAULT_INDICE) {
205: if (sliceIndices == null) {
206: sliceIndices = new HashMap/*<AxisType,Integer>*/();
207: }
208: sliceIndices.put(dimension, new Integer(indice));
209: } else if (sliceIndices != null) {
210: sliceIndices.remove(dimension);
211: if (sliceIndices.isEmpty()) {
212: sliceIndices = null; // hasNonNullIndices() wants that.
213: }
214: }
215: }
216:
217: /**
218: * Returns {@code true} if this set of parameters contains a least one indice
219: * defined to a value different than 0.
220: */
221: final boolean hasNonDefaultIndices() {
222: return sliceIndices != null;
223: }
224: }
|