001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/model/coverage/AbstractCoverage.java $
002    /*----------------------------------------------------------------------------
003     This file originated as a part of GeoAPI.
004    
005     GeoAPI is free software. GeoAPI may be used, modified and
006     redistributed by anyone for any purpose requring only maintaining the
007     copyright and license terms on the source code and derivative files.
008     See the OGC legal page for details.
009    
010     The copyright to the GeoAPI interfaces is held by the Open Geospatial
011     Consortium, see http://www.opengeospatial.org/ogc/legal
012    ----------------------------------------------------------------------------*/
013    package org.deegree.model.coverage;
014    
015    import java.awt.image.renderable.RenderableImage;
016    import java.io.Serializable;
017    import java.util.ArrayList;
018    import java.util.List;
019    
020    import org.deegree.datatypes.CodeList;
021    import org.deegree.model.crs.CRSFactory;
022    import org.deegree.model.crs.CoordinateSystem;
023    import org.deegree.model.metadata.iso19115.Keywords;
024    import org.deegree.model.spatialschema.Envelope;
025    import org.deegree.ogcwebservices.wcs.describecoverage.AxisDescription;
026    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering;
027    
028    /**
029     * Provides access to an OpenGIS coverage. The essential property of coverage is to be able to generate a value for any
030     * point within its domain. How coverage is represented internally is not a concern.
031     *
032     * For example consider the following different internal representations of coverage:<br>
033     * <OL>
034     * <li>A coverage may be represented by a set of polygons which exhaustively tile a plane (that is each point on the
035     * plane falls in precisely one polygon). The value returned by the coverage for a point is the value of an attribute of
036     * the polygon that contains the point.</li>
037     * <li>A coverage may be represented by a grid of values. The value returned by the coverage for a point is that of the
038     * grid value whose location is nearest the point.</li>
039     * <li>Coverage may be represented by a mathematical function. The value returned by the coverage for a point is just
040     * the return value of the function when supplied the coordinates of the point as arguments.</li>
041     * <li>Coverage may be represented by combination of these. For example, coverage may be represented by a combination of
042     * mathematical functions valid over a set of polynomials.</LI>
043     * </OL>
044     *
045     * A coverage has a corresponding {@link SampleDimension} for each sample dimension in the coverage.
046     *
047     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
048     * @author last edited by: $Author: mschneider $
049     *
050     * @version $Revision: 20326 $, $Date: 2009-10-22 18:41:56 +0200 (Do, 22. Okt 2009) $
051     */
052    public abstract class AbstractCoverage implements Coverage, Serializable {
053    
054        private static final long serialVersionUID = 1839111189194771556L;
055    
056        protected CoverageOffering coverageOffering = null;
057    
058        private CoordinateSystem crs = null;
059    
060        private Envelope envelope = null;
061    
062        protected int numSources = 0;
063    
064        protected Coverage[] sources = null;
065    
066        private String[] dimensionNames = null;
067    
068        /**
069         * @param coverageOffering
070         * @param env
071         */
072        public AbstractCoverage( CoverageOffering coverageOffering, Envelope env ) {
073            this( coverageOffering, env, null );
074        }
075    
076        /**
077         * @param coverageOffering
078         * @param env
079         * @param sources
080         */
081        public AbstractCoverage( CoverageOffering coverageOffering, Envelope env, Coverage[] sources ) {
082            this.coverageOffering = coverageOffering;
083            this.sources = sources;
084            if ( sources != null ) {
085                numSources = sources.length;
086            }
087            // set coverage envelope
088            envelope = env;
089    
090            if ( coverageOffering != null ) {
091                // set coordinate system
092                try {
093                    CodeList[] cl = coverageOffering.getSupportedCRSs().getNativeSRSs();
094                    String code = cl[cl.length - 1].getCodes()[0];
095                    crs = CRSFactory.create( code );
096                } catch ( Exception e ) {
097                    e.printStackTrace();
098                }
099                buildDimensionNames();
100            }
101        }
102    
103        /**
104         *
105         * @param coverageOffering
106         * @param env
107         * @param sources
108         * @param crs
109         */
110        public AbstractCoverage( CoverageOffering coverageOffering, Envelope env, Coverage[] sources, CoordinateSystem crs ) {
111            this.coverageOffering = coverageOffering;
112            this.sources = sources;
113            if ( sources != null ) {
114                numSources = sources.length;
115            }
116            // set coverage envelope
117            envelope = env;
118    
119            this.crs = crs;
120            if ( coverageOffering != null ) {
121                buildDimensionNames();
122            }
123        }
124    
125        /**
126         * private method to build the dimension names from the coverage axises (x, y, [z]) and the available ranges
127         */
128        private void buildDimensionNames() {
129            AxisDescription[] axisDescription = coverageOffering.getRangeSet().getAxisDescription();
130            dimensionNames = new String[axisDescription.length + envelope.getMax().getCoordinateDimension()];
131            int k = 0;
132            dimensionNames[k++] = "X";
133            dimensionNames[k++] = "Y";
134            if ( envelope.getMax().getCoordinateDimension() == 3 ) {
135                dimensionNames[k++] = "Z";
136            }
137            for ( int i = 0; i < axisDescription.length; i++ ) {
138                dimensionNames[k++] = axisDescription[i].getName();
139            }
140        }
141    
142        /**
143         * Specifies the coordinate reference system used when accessing a coverage or grid coverage with the
144         * <code>evaluate(...)</code> methods. It is also the coordinate reference system of the coordinates used with the
145         * math transform gridToCoordinateSystem}).
146         *
147         * This coordinate reference system is usually different than coordinate system of the grid. Grid coverage can be
148         * accessed (re-projected) with new coordinate reference system with the
149         * {@link "org.opengis.coverage.processing.GridCoverageProcessor"} component. In this case, a new instance of a grid
150         * coverage is created. <br>
151         * <br>
152         * Note: If a coverage does not have an associated coordinate reference system, the returned value will be
153         * <code>null</code>. attribute should also be <code>null</code> if the coordinate reference system is
154         * <code>null</code>.
155         *
156         * @return The coordinate reference system used when accessing a coverage or grid coverage with the
157         *         <code>evaluate(...)</code> methods, or <code>null</code>.
158         */
159        public CoordinateSystem getCoordinateReferenceSystem() {
160            return crs;
161        }
162    
163        /**
164         * The bounding box for the coverage domain in {@linkplain #getCoordinateReferenceSystem coordinate reference
165         * system} coordinates. For grid coverages, the grid cells are centered on each grid coordinate. The envelope for a
166         * 2-D grid coverage includes the following corner positions.
167         *
168         * <blockquote>
169         *
170         * <pre>
171         *   (Minimum row - 0.5, Minimum column - 0.5) for the minimum coordinates
172         *   (Maximum row - 0.5, Maximum column - 0.5) for the maximum coordinates
173         * </pre>
174         *
175         * </blockquote>
176         *
177         * If a grid coverage does not have any associated coordinate reference system, the minimum and maximum coordinate
178         * points for the envelope will be empty sequences.
179         *
180         * @return The bounding box for the coverage domain in coordinate system coordinates.
181         */
182        public Envelope getEnvelope() {
183            return envelope;
184        }
185    
186        /**
187         * The names of each dimension in the coverage. Typically these names are <var>x</var>, <var>y</var>, <var>z</var>
188         * and <var>t</var>. The number of items in the sequence is the number of dimensions in the coverage. Grid coverages
189         * are typically 2D (<var>x</var>, <var>y</var>) while other coverages may be 3D (<var>x</var>, <var>y</var>,
190         * <var>z</var>) or 4D (<var>x</var>, <var>y</var>, <var>z</var>, <var>t</var>). The number of dimensions of the
191         * coverage is the number of entries in the list of dimension names.
192         *
193         * @return The names of each dimension in the coverage.
194         */
195        public String[] getDimensionNames() {
196            return dimensionNames;
197        }
198    
199        /**
200         * Retrieve sample dimension information for the coverage. For a grid coverage a sample dimension is a band. The
201         * sample dimension information include such things as description, data type of the value (bit, byte, integer...),
202         * the no data values, minimum and maximum values and a color table if one is associated with the dimension. A
203         * coverage must have at least one sample dimension.
204         *
205         * @param index
206         *            Index for sample dimension to retrieve. Indices are numbered 0 to (<var>n</var>-1).
207         * @return Sample dimension information for the coverage, currently always null
208         * @throws IndexOutOfBoundsException
209         *             if <code>index</code> is out of bounds.
210         */
211        public SampleDimension getSampleDimension( int index )
212                                throws IndexOutOfBoundsException {
213            return null;
214        }
215    
216        /**
217         * Number of grid coverages which the grid coverage was derived from. This implementation specification does not
218         * include interfaces for creating collections of coverages therefore this value will usually be one indicating an
219         * adapted grid coverage, or zero indicating a raw grid coverage.
220         *
221         * @return The number of grid coverages which the grid coverage was derived from.
222         */
223        public int getNumSources() {
224            return 0;
225        }
226    
227        /**
228         * Returns the source data for a coverage. This is intended to allow applications to establish what
229         * <code>Coverage</code>s will be affected when others are updated, as well as to trace back to the "raw data".
230         *
231         * @param sourceDataIndex
232         *            Source coverage index. Indexes start at 0.
233         * @return The source data for a coverage.
234         * @throws IndexOutOfBoundsException
235         *             if <code>sourceDataIndex</code> is out of bounds.
236         *
237         * @see #getNumSources
238         * @see "org.opengis.coverage.grid.GridCoverage#getSource"
239         */
240        public Coverage getSource( int sourceDataIndex )
241                                throws IndexOutOfBoundsException {
242            if ( sources != null && sources.length >= sourceDataIndex - 1 ) {
243                return sources[sourceDataIndex];
244            }
245            return null;
246        }
247    
248        /**
249         * List of metadata keywords for a coverage. If no metadata is available, the sequence will be empty.
250         *
251         * @return the list of metadata keywords for a coverage.
252         *
253         * @see #getMetadataValue
254         * @see javax.media.jai.PropertySource#getPropertyNames()
255         */
256        public String[] getMetadataNames() {
257            String[] keyw = new String[0];
258            Keywords[] keywords = coverageOffering.getKeywords();
259            if ( keywords != null ) {
260                List<String> list = new ArrayList<String>( 100 );
261                for ( int i = 0; i < keywords.length; i++ ) {
262                    String[] kw = keywords[i].getKeywords();
263                    for ( int k = 0; k < kw.length; k++ ) {
264                        list.add( kw[k] );
265                    }
266                }
267                keyw = list.toArray( new String[list.size()] );
268            }
269            return keyw;
270        }
271    
272        /**
273         * Retrieve the metadata value for a given metadata name.
274         *
275         * @param name
276         *            Metadata keyword for which to retrieve data.
277         * @return the metadata value for a given metadata name.
278         * @throws MetadataNameNotFoundException
279         *             if there is no value for the specified metadata name.
280         *
281         * @see #getMetadataNames
282         * @see javax.media.jai.PropertySource#getProperty
283         */
284        public String getMetadataValue( String name )
285                                throws MetadataNameNotFoundException {
286            return null;
287        }
288    
289        /**
290         * Returns 2D view of this coverage as a renderable image. This optional operation allows interoperability with <A
291         * HREF="http://java.sun.com/products/java-media/2D/">Java2D</A>. If this coverage is a
292         * {@link "org.opengis.coverage.grid.GridCoverage"} backed by a {@link java.awt.image.RenderedImage}, the underlying
293         * image can be obtained with:
294         *
295         * <code>getRenderableImage(0,1).{@linkplain RenderableImage#createDefaultRendering()
296         * createDefaultRendering()}</code>
297         *
298         * @param xAxis
299         *            Dimension to use for the <var>x</var> axis.
300         * @param yAxis
301         *            Dimension to use for the <var>y</var> axis.
302         * @return A 2D view of this coverage as a renderable image.
303         * @throws UnsupportedOperationException
304         *             if this optional operation is not supported.
305         * @throws IndexOutOfBoundsException
306         *             if <code>xAxis</code> or <code>yAxis</code> is out of bounds.
307         */
308        public abstract RenderableImage getRenderableImage( int xAxis, int yAxis )
309                                throws UnsupportedOperationException, IndexOutOfBoundsException;
310    
311        /**
312         * returns the {@link CoverageOffering} describing a coverage
313         *
314         * @see CoverageOffering
315         * @return the CoverageOffering describing a coverage
316         */
317        public CoverageOffering getCoverageOffering() {
318            return coverageOffering;
319        }
320    
321    }