001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/coverage/grid/ShortGridCoverage.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     Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: klaus.greve@uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.model.coverage.grid;
045    
046    import java.awt.Rectangle;
047    import java.awt.color.ColorSpace;
048    import java.awt.image.BandedSampleModel;
049    import java.awt.image.BufferedImage;
050    import java.awt.image.ComponentColorModel;
051    import java.awt.image.DataBuffer;
052    import java.awt.image.DataBufferShort;
053    import java.awt.image.Raster;
054    import java.awt.image.SampleModel;
055    import java.awt.image.WritableRaster;
056    import java.awt.image.renderable.RenderableImage;
057    import java.util.Hashtable;
058    
059    import org.deegree.model.spatialschema.Envelope;
060    import org.deegree.model.spatialschema.GeometryFactory;
061    import org.deegree.ogcwebservices.wcs.describecoverage.CoverageOffering;
062    import org.deegree.processing.raster.converter.RawData2Image;
063    import org.opengis.pt.PT_Envelope;
064    
065    /**
066     * GridCoverage implementation for holding grids stored in a raw byte matrix (byte[][]) or in a set
067     * of <tt>ByteGridCoverage</tt>s
068     * 
069     * @version $Revision: 7842 $
070     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
071     * @author last edited by: $Author: apoth $
072     * 
073     * @version $Revision: 7842 $, $Date: 2007-07-25 09:44:14 +0200 (Mi, 25 Jul 2007) $
074     */
075    public class ShortGridCoverage extends AbstractGridCoverage {
076    
077        private static final long serialVersionUID = -2073045348804541362L;
078    
079        private short[][][] data = null;
080           
081    
082        /**
083         * @param coverageOffering
084         * @param envelope
085         * @param data
086         */
087        public ShortGridCoverage( CoverageOffering coverageOffering, Envelope envelope, short[][][] data ) {
088            this( coverageOffering, envelope, false, data );
089        }
090    
091        /**
092         * @param coverageOffering
093         * @param envelope
094         * @param isEditable
095         * @param data
096         */
097        public ShortGridCoverage( CoverageOffering coverageOffering, Envelope envelope,
098                                  boolean isEditable, short[][][] data ) {
099            super( coverageOffering, envelope, isEditable );
100            this.data = data;
101        }
102    
103        /**
104         * @param coverageOffering
105         * @param envelope
106         * @param sources
107         */
108        public ShortGridCoverage( CoverageOffering coverageOffering, Envelope envelope,
109                                  ShortGridCoverage[] sources ) {
110            super( coverageOffering, envelope, sources );
111        }
112    
113        /**
114         * The number of sample dimensions in the coverage. For grid coverages, a sample dimension is a
115         * band.
116         * 
117         * @return The number of sample dimensions in the coverage.
118         * @UML mandatory numSampleDimensions
119         */
120        public int getNumSampleDimensions() {
121            if ( data != null ) {
122                return data.length;
123            }
124            return sources[0].getNumSampleDimensions();
125        }
126       
127     
128        /**
129         * Returns 2D view of this coverage as a renderable image. This optional operation allows
130         * interoperability with <A HREF="http://java.sun.com/products/java-media/2D/">Java2D</A>. If
131         * this coverage is a {@link "org.opengis.coverage.grid.GridCoverage"} backed by a
132         * {@link java.awt.image.RenderedImage}, the underlying image can be obtained with:
133         * 
134         * <code>getRenderableImage(0,1).{@linkplain RenderableImage#createDefaultRendering()
135         * createDefaultRendering()}</code>
136         * 
137         * @param xAxis
138         *            Dimension to use for the <var>x</var> axis.
139         * @param yAxis
140         *            Dimension to use for the <var>y</var> axis.
141         * @return A 2D view of this coverage as a renderable image.
142         * @throws UnsupportedOperationException
143         *             if this optional operation is not supported.
144         * @throws IndexOutOfBoundsException
145         *             if <code>xAxis</code> or <code>yAxis</code> is out of bounds.
146         */
147        public RenderableImage getRenderableImage( int xAxis, int yAxis )
148                                throws UnsupportedOperationException, IndexOutOfBoundsException {
149            if ( data != null ) {
150    
151                return null;
152            }
153            // TODO if multi images -> sources.length > 0
154            return null;
155        }
156    
157        /**
158         * this is a deegree convenience method which returns the source image of an
159         * <tt>ImageGridCoverage</tt>. In procipal the same can be done with the
160         * getRenderableImage(int xAxis, int yAxis) method. but creating a <tt>RenderableImage</tt>
161         * image is very slow. I xAxis or yAxis <= 0 then the size of the returned image will be
162         * calculated from the source images of the coverage.
163         * 
164         * @param xAxis
165         *            Dimension to use for the <var>x</var> axis.
166         * @param yAxis
167         *            Dimension to use for the <var>y</var> axis.
168         * @return the source image of an <tt>ImageGridCoverage</tt>.
169         */
170        public BufferedImage getAsImage( int xAxis, int yAxis ) {
171    
172            if ( xAxis <= 0 || yAxis <= 0 ) {
173                // get default size if passed target size is <= 0
174                Rectangle rect = calculateOriginalSize();
175                xAxis = rect.width;
176                yAxis = rect.height;
177            }
178            BufferedImage bi = null;
179            if ( data != null ) {
180    
181                bi = createBufferedImage( data[0][0].length, data[0].length );
182                // total number of fields for one band; it is assumed that each
183                // band has the same number of fiels
184                int numOfFields = data[0].length * data[0][0].length;
185                short[][] bb = new short[data.length][];
186                for ( int z = 0; z < data.length; z++ ) {
187                    bb[z] = new short[numOfFields];
188                }
189                int c = 0;
190                for ( int i = 0; i < data[0].length; i++ ) {
191                    for ( int j = 0; j < data[0][i].length; j++ ) {
192                        for ( int z = 0; z < data.length; z++ ) {
193                            bb[z][c] = data[z][i][j];
194                        }
195                        c++;
196                    }
197                }
198                DataBuffer db = new DataBufferShort( bb, numOfFields );
199                SampleModel sm = new BandedSampleModel( DataBuffer.TYPE_USHORT, data[0][0].length,
200                                                        data[0].length, data.length );
201                Raster raster = Raster.createWritableRaster( sm, db, null );
202                bi.setData( raster );
203            } else {
204                bi = createBufferedImage( xAxis, yAxis );
205                int targetPs = bi.getColorModel().getPixelSize();
206                float[][] data = null;
207                if ( targetPs == 16 ) {
208                    // do not use image api if target bitDepth = 16
209                    data = new float[bi.getHeight()][bi.getWidth()];
210                }
211                // it's a complex ImageGridCoverage made up of different
212                // source coverages
213                for ( int i = 0; i < sources.length; i++ ) {
214                    PT_Envelope env = sources[i].getEnvelope();
215                    Envelope sourceEnv = GeometryFactory.createEnvelope( env.minCP.ord[0],
216                                                                         env.minCP.ord[1],
217                                                                         env.maxCP.ord[0],
218                                                                         env.maxCP.ord[1], null );
219                    env = this.getEnvelope();
220                    Envelope targetEnv = GeometryFactory.createEnvelope( env.minCP.ord[0],
221                                                                         env.minCP.ord[1],
222                                                                         env.maxCP.ord[0],
223                                                                         env.maxCP.ord[1], null );
224               
225                    BufferedImage sourceImg = ( (AbstractGridCoverage) sources[i] ).getAsImage( -1, -1 );
226                    bi = paintImage( bi, data, targetEnv, sourceImg, sourceEnv );
227                }
228                if ( targetPs == 16 ) {
229                    bi = RawData2Image.rawData2Image( data, false, scaleFactor, offset );
230                }
231            }
232            
233    
234            return bi;
235        }
236    
237        /**
238         * 
239         * @param xAxis
240         * @param yAxis
241         * @return
242         */
243        private BufferedImage createBufferedImage( int xAxis, int yAxis ) {
244            BufferedImage bi = null;
245            int sampleDim = getNumSampleDimensions();
246            switch ( sampleDim ) {
247            case 1: {
248                ColorSpace cs = ColorSpace.getInstance( ColorSpace.CS_GRAY );
249                ComponentColorModel ccm = new ComponentColorModel( cs, null, false, false,
250                                                                   BufferedImage.OPAQUE,
251                                                                   DataBuffer.TYPE_USHORT );
252                WritableRaster wr = ccm.createCompatibleWritableRaster( xAxis, yAxis );
253    
254                bi = new BufferedImage( ccm, wr, false, new Hashtable() );
255            }
256            }
257            return bi;
258        }
259    
260        /**
261         * calculates the original size of a gridcoverage based on its resolution and the envelope(s) of
262         * its source(s).
263         * 
264         * @return
265         */
266        private Rectangle calculateOriginalSize() {
267         
268            if ( data != null ) {
269                return new Rectangle( data[0][0].length, data[0].length );
270            }
271            BufferedImage bi = ( (ShortGridCoverage) sources[0] ).getAsImage( -1, -1 );
272            PT_Envelope env = sources[0].getEnvelope();
273            double dx = ( env.maxCP.ord[0] - env.minCP.ord[0] ) / bi.getWidth();
274            double dy = ( env.maxCP.ord[1] - env.minCP.ord[1] ) / bi.getHeight();
275    
276            env = this.getEnvelope();
277            int w = (int) Math.round( ( env.maxCP.ord[0] - env.minCP.ord[0] ) / dx );
278            int h = (int) Math.round( ( env.maxCP.ord[1] - env.minCP.ord[1] ) / dy );
279            return new Rectangle( w, h );
280        }
281    }