001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/graphics/displayelements/RasterDisplayElement.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    package org.deegree.graphics.displayelements;
037    
038    import java.awt.Graphics;
039    import java.awt.Graphics2D;
040    import java.awt.image.BufferedImage;
041    import java.awt.image.ConvolveOp;
042    import java.awt.image.Kernel;
043    
044    import org.deegree.framework.log.ILogger;
045    import org.deegree.framework.log.LoggerFactory;
046    import org.deegree.framework.util.Pair;
047    import org.deegree.graphics.sld.Categorize;
048    import org.deegree.graphics.sld.Interpolate;
049    import org.deegree.graphics.sld.RasterSymbolizer;
050    import org.deegree.graphics.transformation.GeoTransform;
051    import org.deegree.model.coverage.grid.GridCoverage;
052    import org.deegree.model.coverage.grid.ImageGridCoverage;
053    import org.deegree.model.spatialschema.Envelope;
054    import org.deegree.ogcwebservices.wms.operation.DimensionValues;
055    import org.deegree.ogcwebservices.wms.operation.GetMap;
056    import org.deegree.processing.raster.converter.Image2RawData;
057    
058    /**
059     *
060     *
061     *
062     * @version $Revision: 18234 $
063     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
064     * @author last edited by: $Author: apoth $
065     *
066     * @version 1.0. $Revision: 18234 $, $Date: 2009-06-23 15:40:38 +0200 (Di, 23. Jun 2009) $
067     *
068     * @since 2.0
069     */
070    public class RasterDisplayElement extends AbstractDisplayElement {
071    
072        private static final long serialVersionUID = -5195730721807600940L;
073    
074        private static ILogger LOG = LoggerFactory.getLogger( RasterDisplayElement.class );
075    
076        private RasterSymbolizer symbolizer = null;
077    
078        private GridCoverage gc = null;
079    
080        private GetMap request;
081    
082        /**
083         * Creates a new RasterDisplayElement_Impl object.
084         *
085         * @param gc
086         *            raster
087         */
088        RasterDisplayElement( GridCoverage gc ) {
089            setRaster( gc );
090            symbolizer = new RasterSymbolizer();
091        }
092    
093        /**
094         * Creates a new RasterDisplayElement_Impl object.
095         *
096         * @param gc
097         *            raster
098         * @param symbolizer
099         */
100        RasterDisplayElement( GridCoverage gc, RasterSymbolizer symbolizer ) {
101            setRaster( gc );
102            this.symbolizer = symbolizer;
103        }
104    
105        RasterDisplayElement( GridCoverage gc, RasterSymbolizer symbolizer, GetMap request ) {
106            this.request = request;
107            setRaster( gc );
108            this.symbolizer = symbolizer;
109        }
110    
111        private void paintCoverage( Graphics2D g, float[][] data, int minx, int miny, int maxx, int maxy,
112                                    BufferedImage image ) {
113            Categorize categorize = symbolizer == null ? null : symbolizer.getCategorize();
114            Interpolate interpolate = symbolizer == null ? null : symbolizer.getInterpolate();
115    
116            LOG.logDebug( categorize == null ? "Not using categorization symbolizer." : "Using categorization symbolizer." );
117            LOG.logDebug( interpolate == null ? "Not using interpolation symbolizer." : "Using interpolation symbolizer." );
118    
119            int opac = symbolizer == null ? 1 : ( (int) ( 255 * symbolizer.getOpacity() ) << 24 );
120    
121            int width = maxx - minx;
122            int height = maxy - miny;
123    
124            BufferedImage img = new BufferedImage( data[0].length, data.length, BufferedImage.TYPE_INT_ARGB );
125    
126            DimensionValues vals = request == null ? null : request.getDimElev();
127    
128            for ( int x = 0; x < data[0].length; ++x ) {
129                for ( int y = 0; y < data.length; ++y ) {
130                    float d = data[y][x];
131                    int val = 0;
132    
133                    if ( ( vals != null && vals.includesValue( d ) ) || vals == null ) {
134                        if ( categorize == null && interpolate == null ) {
135                            val = image.getRGB( x, y );
136                            val = val & 0xffffff + opac;
137                        } else if ( categorize != null ) {
138                            val = categorize.categorize( d, opac );
139                        } else if ( interpolate != null ) {
140                            val = interpolate.interpolate( d, opac );
141                        }
142                    }
143    
144                    img.setRGB( x, y, val );
145                }
146            }
147    
148            if ( symbolizer != null && symbolizer.getShaded() ) {
149                BufferedImage old = img;
150    
151                Pair<Integer, float[]> pair = symbolizer.getShadeKernel();
152                Kernel kernel = new Kernel( 3, 3, new float[] { -1, -1, -1, -1, 10, -1, -1, -1, -1 } );
153                ConvolveOp op = new ConvolveOp( kernel );
154                img = op.filter( img, null );
155                kernel = new Kernel( pair.first, pair.first, pair.second );
156                op = new ConvolveOp( kernel );
157                img = op.filter( img, null );
158    
159                // this post processing is necessary to remove pixels that were filtered out by the
160                // ELEVATION parameter
161                // value and to fix up artifacts from the shade operations above
162                for ( int y = 0; y < old.getHeight(); ++y ) {
163                    for ( int x = 0; x < old.getWidth(); ++x ) {
164                        int oldVal = old.getRGB( x, y );
165                        int newVal = img.getRGB( x, y );
166                        if ( oldVal == 0 ) {
167                            img.setRGB( x, y, 0 );
168                        } else {
169                            if ( ( newVal & 0xff000000 ) == 0 ) {
170                                img.setRGB( x, y, oldVal );
171                            } else if ( ( newVal & 0xffffff ) == 0xffffff ) {
172                                img.setRGB( x, y, oldVal );
173                            }
174                        }
175                    }
176                }
177    
178            }
179    
180            if ( symbolizer != null && symbolizer.getGamma() != 1 ) {
181                Kernel kernel = new Kernel( 1, 1, new float[] { (float) symbolizer.getGamma() } );
182                img = new ConvolveOp( kernel ).filter( img, null );
183            }
184    
185            g.drawImage( img, minx, miny, width, height, null );
186        }
187    
188        /**
189         * renders the DisplayElement to the submitted graphic context
190         *
191         */
192        public void paint( Graphics g, GeoTransform projection, double scale ) {
193            synchronized ( symbolizer ) {
194                try {
195                    if ( doesScaleConstraintApply( scale ) ) {
196                        Envelope env = gc.getEnvelope();
197                        int minx = (int) ( projection.getDestX( env.getMin().getX() ) );
198                        int maxy = (int) ( projection.getDestY( env.getMin().getY() ) );
199                        int maxx = (int) ( projection.getDestX( env.getMax().getX() ) );
200                        int miny = (int) ( projection.getDestY( env.getMax().getY() ) );
201    
202                        if ( gc instanceof ImageGridCoverage ) {
203                            ImageGridCoverage igc = (ImageGridCoverage) gc;
204                            Graphics2D g2 = (Graphics2D) g;
205                            BufferedImage image = igc.getAsImage( -1, -1 );
206    
207                            if ( symbolizer.isDefault() && ( request == null || request.getDimElev() == null ) ) {
208                                if ( symbolizer.getGamma() != 1 ) {
209                                    Kernel kernel = new Kernel( 1, 1, new float[] { (float) symbolizer.getGamma() } );
210                                    image = new ConvolveOp( kernel ).filter( image, null );
211                                }
212                                g2.drawImage( image, minx, miny, maxx - minx, maxy - miny, null );
213                            } else {
214                                if ( symbolizer.scaleValid( scale ) ) {
215                                    paintCoverage( g2, new Image2RawData( image ).parse(), minx, miny, maxx, maxy, image );
216                                }
217                            }
218                        } else {
219                            // TODO
220                            // handle other grid coverages
221                        }
222                    }
223                } catch ( Exception e ) {
224                    LOG.logError( e.getMessage(), e );
225                    throw new RuntimeException( e.getMessage(), e );
226                }
227            }
228        }
229    
230        /**
231         * returns the content of the <code>RasterDisplayElement</code>
232         *
233         * @return gird coverage
234         */
235        public GridCoverage getRaster() {
236            return gc;
237        }
238    
239        /**
240         * sets the grid coverage that represents the content of the <code>RasterDisplayElement</code>
241         *
242         * @param gc
243         *
244         */
245        public void setRaster( GridCoverage gc ) {
246            this.gc = gc;
247        }
248    
249        @Override
250        public boolean doesScaleConstraintApply( double scale ) {
251            return symbolizer.scaleValid( scale );
252        }
253    
254    }