001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/coverage/AbstractCoverage.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.model.coverage;
045    
046    import java.awt.image.renderable.RenderableImage;
047    import java.io.Serializable;
048    import java.util.ArrayList;
049    import java.util.List;
050    
051    import org.deegree.datatypes.CodeList;
052    import org.deegree.model.crs.CRSFactory;
053    import org.deegree.model.crs.CoordinateSystem;
054    import org.deegree.model.metadata.iso19115.Keywords;
055    import org.deegree.model.spatialschema.Envelope;
056    import org.deegree.model.spatialschema.Position;
057    import org.deegree.ogcwebservices.wcs.describecoverage.AxisDescription;
058    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering;
059    import org.opengis.pt.PT_CoordinatePoint;
060    import org.opengis.pt.PT_Envelope;
061    
062    /**
063     * Provides access to an OpenGIS coverage. The essential property of coverage is to be able to
064     * generate a value for any point within its domain. How coverage is represented internally is not a
065     * concern.
066     * 
067     * For example consider the following different internal representations of coverage:<br>
068     * <OL>
069     * <li>A coverage may be represented by a set of polygons which exhaustively tile a plane (that is
070     * each point on the plane falls in precisely one polygon). The value returned by the coverage for a
071     * point is the value of an attribute of the polygon that contains the point.</li>
072     * <li>A coverage may be represented by a grid of values. The value returned by the coverage for a
073     * point is that of the grid value whose location is nearest the point.</li>
074     * <li>Coverage may be represented by a mathematical function. The value returned by the coverage
075     * for a point is just the return value of the function when supplied the coordinates of the point
076     * as arguments.</li>
077     * <li>Coverage may be represented by combination of these. For example, coverage may be
078     * represented by a combination of mathematical functions valid over a set of polynomials.</LI>
079     * </OL>
080     * 
081     * A coverage has a corresponding {@link SampleDimension} for each sample dimension in the coverage.
082     * 
083     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
084     * @author last edited by: $Author: apoth $
085     * 
086     * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
087     */
088    public abstract class AbstractCoverage implements Coverage, Serializable {
089    
090        protected CoverageOffering coverageOffering = null;
091    
092        private CoordinateSystem crs = null;
093    
094        private PT_Envelope envelope = null;
095    
096        protected int numSources = 0;
097    
098        protected Coverage[] sources = null;
099    
100        private String[] dimensionNames = null;
101    
102        /**
103         * @param coverageOffering
104         * @param env
105         */
106        public AbstractCoverage( CoverageOffering coverageOffering, Envelope env ) {
107            this( coverageOffering, env, null );
108        }
109    
110        /**
111         * @param coverageOffering
112         * @param env
113         * @param sources
114         */
115        public AbstractCoverage( CoverageOffering coverageOffering, Envelope env, Coverage[] sources ) {
116            this.coverageOffering = coverageOffering;
117            this.sources = sources;
118            if ( sources != null ) {
119                numSources = sources.length;
120            }
121            // set coverage envelope
122            Position min = env.getMin();
123            Position max = env.getMax();
124            PT_CoordinatePoint minCP = new PT_CoordinatePoint( min.getX(), min.getY() );
125            PT_CoordinatePoint maxCP = new PT_CoordinatePoint( max.getX(), max.getY() );
126            envelope = new PT_Envelope();
127            envelope.minCP = minCP;
128            envelope.maxCP = maxCP;
129    
130            if ( coverageOffering != null ) {
131                // set coordinate system
132                try {
133                    CodeList[] cl = coverageOffering.getSupportedCRSs().getNativeSRSs();
134                    String code = cl[cl.length - 1].getCodes()[0];
135                    crs = CRSFactory.create( code );
136                } catch ( Exception e ) {
137                    e.printStackTrace();
138                }
139                buildDimensionNames();
140            }
141        }
142    
143        /**
144         * 
145         * @param coverageOffering
146         * @param env
147         * @param sources
148         * @param crs
149         */
150        public AbstractCoverage( CoverageOffering coverageOffering, Envelope env, Coverage[] sources, CoordinateSystem crs ) {
151            this.coverageOffering = coverageOffering;
152            this.sources = sources;
153            if ( sources != null ) {
154                numSources = sources.length;
155            }
156            // set coverage envelope
157            Position min = env.getMin();
158            Position max = env.getMax();
159            PT_CoordinatePoint minCP = new PT_CoordinatePoint( min.getX(), min.getY() );
160            PT_CoordinatePoint maxCP = new PT_CoordinatePoint( max.getX(), max.getY() );
161            envelope = new PT_Envelope();
162            envelope.minCP = minCP;
163            envelope.maxCP = maxCP;
164    
165            this.crs = crs;
166            if ( coverageOffering != null ) {
167                buildDimensionNames();
168            }
169        }
170    
171        /**
172         * private method to build the dimension names from the coverage axises (x, y, [z]) and the
173         * available ranges
174         */
175        private void buildDimensionNames() {
176            AxisDescription[] axisDescription = coverageOffering.getRangeSet().getAxisDescription();
177            dimensionNames = new String[axisDescription.length + envelope.maxCP.ord.length];
178            int k = 0;
179            dimensionNames[k++] = "X";
180            dimensionNames[k++] = "Y";
181            if ( envelope.maxCP.ord.length == 3 ) {
182                dimensionNames[k++] = "Z";
183            }
184            for ( int i = 0; i < axisDescription.length; i++ ) {
185                dimensionNames[k++] = axisDescription[i].getName();
186            }
187        }
188    
189        /**
190         * Specifies the coordinate reference system used when accessing a coverage or grid coverage
191         * with the <code>evaluate(...)</code> methods. It is also the coordinate reference system of
192         * the coordinates used with the math transform gridToCoordinateSystem}).
193         * 
194         * This coordinate reference system is usually different than coordinate system of the grid.
195         * Grid coverage can be accessed (re-projected) with new coordinate reference system with the
196         * {@link "org.opengis.coverage.processing.GridCoverageProcessor"} component. In this case, a
197         * new instance of a grid coverage is created. <br>
198         * <br>
199         * Note: If a coverage does not have an associated coordinate reference system, the returned
200         * value will be <code>null</code>. attribute should also be <code>null</code> if the
201         * coordinate reference system is <code>null</code>.
202         * 
203         * @return The coordinate reference system used when accessing a coverage or grid coverage with
204         *         the <code>evaluate(...)</code> methods, or <code>null</code>.
205         */
206        public CoordinateSystem getCoordinateReferenceSystem() {
207            return crs;
208        }
209    
210        /**
211         * The bounding box for the coverage domain in
212         * {@linkplain #getCoordinateReferenceSystem coordinate reference system} coordinates. For grid
213         * coverages, the grid cells are centered on each grid coordinate. The envelope for a 2-D grid
214         * coverage includes the following corner positions.
215         * 
216         * <blockquote>
217         * 
218         * <pre>
219         *   (Minimum row - 0.5, Minimum column - 0.5) for the minimum coordinates
220         *   (Maximum row - 0.5, Maximum column - 0.5) for the maximum coordinates
221         * </pre>
222         * 
223         * </blockquote>
224         * 
225         * If a grid coverage does not have any associated coordinate reference system, the minimum and
226         * maximum coordinate points for the envelope will be empty sequences.
227         * 
228         * @return The bounding box for the coverage domain in coordinate system coordinates.
229         */
230        public PT_Envelope getEnvelope() {
231            return envelope;
232        }
233    
234        /**
235         * The names of each dimension in the coverage. Typically these names are <var>x</var>, <var>y</var>,
236         * <var>z</var> and <var>t</var>. The number of items in the sequence is the number of
237         * dimensions in the coverage. Grid coverages are typically 2D (<var>x</var>, <var>y</var>)
238         * while other coverages may be 3D (<var>x</var>, <var>y</var>, <var>z</var>) or 4D (<var>x</var>,
239         * <var>y</var>, <var>z</var>, <var>t</var>). The number of dimensions of the coverage is the
240         * number of entries in the list of dimension names.
241         * 
242         * @return The names of each dimension in the coverage.
243         */
244        public String[] getDimensionNames() {
245            return dimensionNames;
246        }
247    
248        /**
249         * Retrieve sample dimension information for the coverage. For a grid coverage a sample
250         * dimension is a band. The sample dimension information include such things as description,
251         * data type of the value (bit, byte, integer...), the no data values, minimum and maximum
252         * values and a color table if one is associated with the dimension. A coverage must have at
253         * least one sample dimension.
254         * 
255         * @param index
256         *            Index for sample dimension to retrieve. Indices are numbered 0 to (<var>{@linkplain #getNumSampleDimensions n}</var>-1).
257         * @return Sample dimension information for the coverage.
258         * @throws IndexOutOfBoundsException
259         *             if <code>index</code> is out of bounds.
260         */
261        public SampleDimension getSampleDimension( int index )
262                                throws IndexOutOfBoundsException {
263            return null;
264        }
265    
266        /**
267         * Number of grid coverages which the grid coverage was derived from. This implementation
268         * specification does not include interfaces for creating collections of coverages therefore
269         * this value will usually be one indicating an adapted grid coverage, or zero indicating a raw
270         * grid coverage.
271         * 
272         * @return The number of grid coverages which the grid coverage was derived from.
273         */
274        public int getNumSources() {
275            return 0;
276        }
277    
278        /**
279         * Returns the source data for a coverage. This is intended to allow applications to establish
280         * what <code>Coverage</code>s will be affected when others are updated, as well as to trace
281         * back to the "raw data".
282         * 
283         * @param sourceDataIndex
284         *            Source coverage index. Indexes start at 0.
285         * @return The source data for a coverage.
286         * @throws IndexOutOfBoundsException
287         *             if <code>sourceDataIndex</code> is out of bounds.
288         * 
289         * @see #getNumSources
290         * @see "org.opengis.coverage.grid.GridCoverage#getSource"
291         */
292        public Coverage getSource( int sourceDataIndex )
293                                throws IndexOutOfBoundsException {
294            if ( sources != null && sources.length >= sourceDataIndex - 1 ) {
295                return sources[sourceDataIndex];
296            }
297            return null;
298        }
299    
300        /**
301         * List of metadata keywords for a coverage. If no metadata is available, the sequence will be
302         * empty.
303         * 
304         * @return the list of metadata keywords for a coverage.
305         * 
306         * @see #getMetadataValue
307         * @see javax.media.jai.PropertySource#getPropertyNames()
308         */
309        public String[] getMetadataNames() {
310            String[] keyw = new String[0];
311            Keywords[] keywords = coverageOffering.getKeywords();
312            if ( keywords != null ) {
313                List<String> list = new ArrayList<String>( 100 );
314                for ( int i = 0; i < keywords.length; i++ ) {
315                    String[] kw = keywords[i].getKeywords();
316                    for ( int k = 0; k < kw.length; k++ ) {
317                        list.add( kw[k] );
318                    }
319                }
320                keyw = list.toArray( new String[list.size()] );
321            }
322            return keyw;
323        }
324    
325        /**
326         * Retrieve the metadata value for a given metadata name.
327         * 
328         * @param name
329         *            Metadata keyword for which to retrieve data.
330         * @return the metadata value for a given metadata name.
331         * @throws MetadataNameNotFoundException
332         *             if there is no value for the specified metadata name.
333         * 
334         * @see #getMetadataNames
335         * @see javax.media.jai.PropertySource#getProperty
336         */
337        public String getMetadataValue( String name )
338                                throws MetadataNameNotFoundException {
339            return null;
340        }
341    
342        /**
343         * Returns 2D view of this coverage as a renderable image. This optional operation allows
344         * interoperability with <A HREF="http://java.sun.com/products/java-media/2D/">Java2D</A>. If
345         * this coverage is a {@link "org.opengis.coverage.grid.GridCoverage"} backed by a
346         * {@link java.awt.image.RenderedImage}, the underlying image can be obtained with:
347         * 
348         * <code>getRenderableImage(0,1).{@linkplain RenderableImage#createDefaultRendering()
349         * createDefaultRendering()}</code>
350         * 
351         * @param xAxis
352         *            Dimension to use for the <var>x</var> axis.
353         * @param yAxis
354         *            Dimension to use for the <var>y</var> axis.
355         * @return A 2D view of this coverage as a renderable image.
356         * @throws UnsupportedOperationException
357         *             if this optional operation is not supported.
358         * @throws IndexOutOfBoundsException
359         *             if <code>xAxis</code> or <code>yAxis</code> is out of bounds.
360         */
361        public abstract RenderableImage getRenderableImage( int xAxis, int yAxis )
362                                throws UnsupportedOperationException, IndexOutOfBoundsException;
363    
364        /**
365         * returns the {@link CoverageOffering} describing a coverage
366         * 
367         * @see CoverageOffering
368         * @return the CoverageOffering describing a coverage
369         */
370        public CoverageOffering getCoverageOffering() {
371            return coverageOffering;
372        }
373    
374    }