001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/coverage/AbstractCoverage.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree
005     Copyright (C) 2001-2007 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: fitzke@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: 7842 $, $Date: 2007-07-25 09:44:14 +0200 (Mi, 25 Jul 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,
151                                 CoordinateSystem crs ) {
152            this.coverageOffering = coverageOffering;
153            this.sources = sources;
154            if ( sources != null ) {
155                numSources = sources.length;
156            }
157            // set coverage envelope
158            Position min = env.getMin();
159            Position max = env.getMax();
160            PT_CoordinatePoint minCP = new PT_CoordinatePoint( min.getX(), min.getY() );
161            PT_CoordinatePoint maxCP = new PT_CoordinatePoint( max.getX(), max.getY() );
162            envelope = new PT_Envelope();
163            envelope.minCP = minCP;
164            envelope.maxCP = maxCP;
165    
166            this.crs = crs;
167            if ( coverageOffering != null ) {
168                buildDimensionNames();
169            }
170        }
171    
172        /**
173         * private method to build the dimension names from the coverage axises (x, y, [z]) and the
174         * available ranges
175         */
176        private void buildDimensionNames() {
177            AxisDescription[] axisDescription = coverageOffering.getRangeSet().getAxisDescription();
178            dimensionNames = new String[axisDescription.length + envelope.maxCP.ord.length];
179            int k = 0;
180            dimensionNames[k++] = "X";
181            dimensionNames[k++] = "Y";
182            if ( envelope.maxCP.ord.length == 3 ) {
183                dimensionNames[k++] = "Z";
184            }
185            for ( int i = 0; i < axisDescription.length; i++ ) {
186                dimensionNames[k++] = axisDescription[i].getName();
187            }
188        }
189    
190        /**
191         * Specifies the coordinate reference system used when accessing a coverage or grid coverage
192         * with the <code>evaluate(...)</code> methods. It is also the coordinate reference system of
193         * the coordinates used with the math transform gridToCoordinateSystem}).
194         * 
195         * This coordinate reference system is usually different than coordinate system of the grid.
196         * Grid coverage can be accessed (re-projected) with new coordinate reference system with the
197         * {@link "org.opengis.coverage.processing.GridCoverageProcessor"} component. In this case, a
198         * new instance of a grid coverage is created. <br>
199         * <br>
200         * Note: If a coverage does not have an associated coordinate reference system, the returned
201         * value will be <code>null</code>. attribute should also be <code>null</code> if the
202         * coordinate reference system is <code>null</code>.
203         * 
204         * @return The coordinate reference system used when accessing a coverage or grid coverage with
205         *         the <code>evaluate(...)</code> methods, or <code>null</code>.
206         */
207        public CoordinateSystem getCoordinateReferenceSystem() {
208            return crs;
209        }
210    
211        /**
212         * The bounding box for the coverage domain in
213         * {@linkplain #getCoordinateReferenceSystem coordinate reference system} coordinates. For grid
214         * coverages, the grid cells are centered on each grid coordinate. The envelope for a 2-D grid
215         * coverage includes the following corner positions.
216         * 
217         * <blockquote>
218         * 
219         * <pre>
220         *   (Minimum row - 0.5, Minimum column - 0.5) for the minimum coordinates
221         *   (Maximum row - 0.5, Maximum column - 0.5) for the maximum coordinates
222         * </pre>
223         * 
224         * </blockquote>
225         * 
226         * If a grid coverage does not have any associated coordinate reference system, the minimum and
227         * maximum coordinate points for the envelope will be empty sequences.
228         * 
229         * @return The bounding box for the coverage domain in coordinate system coordinates.
230         */
231        public PT_Envelope getEnvelope() {
232            return envelope;
233        }
234    
235        /**
236         * The names of each dimension in the coverage. Typically these names are <var>x</var>, <var>y</var>,
237         * <var>z</var> and <var>t</var>. The number of items in the sequence is the number of
238         * dimensions in the coverage. Grid coverages are typically 2D (<var>x</var>, <var>y</var>)
239         * while other coverages may be 3D (<var>x</var>, <var>y</var>, <var>z</var>) or 4D (<var>x</var>,
240         * <var>y</var>, <var>z</var>, <var>t</var>). The number of dimensions of the coverage is the
241         * number of entries in the list of dimension names.
242         * 
243         * @return The names of each dimension in the coverage.
244         */
245        public String[] getDimensionNames() {
246            return dimensionNames;
247        }
248    
249        /**
250         * Retrieve sample dimension information for the coverage. For a grid coverage a sample
251         * dimension is a band. The sample dimension information include such things as description,
252         * data type of the value (bit, byte, integer...), the no data values, minimum and maximum
253         * values and a color table if one is associated with the dimension. A coverage must have at
254         * least one sample dimension.
255         * 
256         * @param index
257         *            Index for sample dimension to retrieve. Indices are numbered 0 to (<var>{@linkplain #getNumSampleDimensions n}</var>-1).
258         * @return Sample dimension information for the coverage.
259         * @throws IndexOutOfBoundsException
260         *             if <code>index</code> is out of bounds.
261         */
262        public SampleDimension getSampleDimension( int index )
263                                throws IndexOutOfBoundsException {
264            return null;
265        }
266    
267        /**
268         * Number of grid coverages which the grid coverage was derived from. This implementation
269         * specification does not include interfaces for creating collections of coverages therefore
270         * this value will usually be one indicating an adapted grid coverage, or zero indicating a raw
271         * grid coverage.
272         * 
273         * @return The number of grid coverages which the grid coverage was derived from.
274         */
275        public int getNumSources() {
276            return 0;
277        }
278    
279        /**
280         * Returns the source data for a coverage. This is intended to allow applications to establish
281         * what <code>Coverage</code>s will be affected when others are updated, as well as to trace
282         * back to the "raw data".
283         * 
284         * @param sourceDataIndex
285         *            Source coverage index. Indexes start at 0.
286         * @return The source data for a coverage.
287         * @throws IndexOutOfBoundsException
288         *             if <code>sourceDataIndex</code> is out of bounds.
289         * 
290         * @see #getNumSources
291         * @see "org.opengis.coverage.grid.GridCoverage#getSource"
292         */
293        public Coverage getSource( int sourceDataIndex )
294                                throws IndexOutOfBoundsException {
295            if ( sources != null && sources.length >= sourceDataIndex - 1 ) {
296                return sources[sourceDataIndex];
297            }
298            return null;
299        }
300    
301        /**
302         * List of metadata keywords for a coverage. If no metadata is available, the sequence will be
303         * empty.
304         * 
305         * @return the list of metadata keywords for a coverage.
306         * 
307         * @see #getMetadataValue
308         * @see javax.media.jai.PropertySource#getPropertyNames()
309         */
310        public String[] getMetadataNames() {
311            String[] keyw = new String[0];
312            Keywords[] keywords = coverageOffering.getKeywords();
313            if ( keywords != null ) {
314                List<String> list = new ArrayList<String>( 100 );
315                for ( int i = 0; i < keywords.length; i++ ) {
316                    String[] kw = keywords[i].getKeywords();
317                    for ( int k = 0; k < kw.length; k++ ) {
318                        list.add( kw[k] );
319                    }
320                }
321                keyw = list.toArray( new String[list.size()] );
322            }
323            return keyw;
324        }
325    
326        /**
327         * Retrieve the metadata value for a given metadata name.
328         * 
329         * @param name
330         *            Metadata keyword for which to retrieve data.
331         * @return the metadata value for a given metadata name.
332         * @throws MetadataNameNotFoundException
333         *             if there is no value for the specified metadata name.
334         * 
335         * @see #getMetadataNames
336         * @see javax.media.jai.PropertySource#getProperty
337         */
338        public String getMetadataValue( String name )
339                                throws MetadataNameNotFoundException {
340            return null;
341        }
342    
343        
344        /**
345         * Returns 2D view of this coverage as a renderable image. This optional operation allows
346         * interoperability with <A HREF="http://java.sun.com/products/java-media/2D/">Java2D</A>. If
347         * this coverage is a {@link "org.opengis.coverage.grid.GridCoverage"} backed by a
348         * {@link java.awt.image.RenderedImage}, the underlying image can be obtained with:
349         * 
350         * <code>getRenderableImage(0,1).{@linkplain RenderableImage#createDefaultRendering()
351         * createDefaultRendering()}</code>
352         * 
353         * @param xAxis
354         *            Dimension to use for the <var>x</var> axis.
355         * @param yAxis
356         *            Dimension to use for the <var>y</var> axis.
357         * @return A 2D view of this coverage as a renderable image.
358         * @throws UnsupportedOperationException
359         *             if this optional operation is not supported.
360         * @throws IndexOutOfBoundsException
361         *             if <code>xAxis</code> or <code>yAxis</code> is out of bounds.
362         */
363        public abstract RenderableImage getRenderableImage( int xAxis, int yAxis )
364                                throws UnsupportedOperationException, IndexOutOfBoundsException;
365    
366        /**
367         * returns the {@link CoverageOffering} describing a coverage
368         * 
369         * @see CoverageOffering
370         * @return the CoverageOffering describing a coverage
371         */
372        public CoverageOffering getCoverageOffering() {
373            return coverageOffering;
374        }
375    
376    }