001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/model/coverage/grid/WorldFile.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     Aennchenstraße 19
030     53177 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    package org.deegree.model.coverage.grid;
044    
045    import java.awt.image.BufferedImage;
046    import java.io.BufferedReader;
047    import java.io.File;
048    import java.io.FileReader;
049    import java.io.FileWriter;
050    import java.io.IOException;
051    import java.io.PrintWriter;
052    
053    import javax.media.jai.JAI;
054    import javax.media.jai.RenderedOp;
055    
056    import org.deegree.framework.log.ILogger;
057    import org.deegree.framework.log.LoggerFactory;
058    import org.deegree.model.spatialschema.Envelope;
059    import org.deegree.model.spatialschema.GeometryFactory;
060    
061    import com.sun.media.jai.codec.FileSeekableStream;
062    
063    /**
064     * class representation of a ESRI world file. A world file may defines bounding coordinates centered
065     * on the outter pixel (e.g. ESRI software) or outside the bounding pixels (e.g.Oracle spatial).
066     * Reading a worldfile this must be considered so the type of a worldfile must be passed. For this a
067     * <code>enum</code> named <code>TYPE</code> ist defined.
068     * 
069     * 
070     * @version $Revision: 9343 $
071     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
072     * @author last edited by: $Author: apoth $
073     * 
074     * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
075     */
076    public class WorldFile {
077    
078        private static ILogger LOG = LoggerFactory.getLogger( WorldFile.class );
079    
080        private double resx;
081    
082        private double resy;
083    
084        private double rotation1;
085    
086        private double rotation2;
087    
088        private Envelope envelope;
089    
090        /**
091         * <code>TYPE</code> enumerates the world file types.
092         * 
093         * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
094         * @author last edited by: $Author: apoth $
095         * 
096         * @version $Revision: 9343 $, $Date: 2007-12-27 14:30:32 +0100 (Do, 27 Dez 2007) $
097         */
098        public enum TYPE {
099    
100            /**
101             * Coordinates denote pixel centers.
102             */
103            CENTER,
104    
105            /**
106             * Coordinates denote outer edges.
107             */
108            OUTER
109    
110        }
111    
112        /**
113         * @return a class represention of a ESRI world file
114         * @param filename
115         *            name of the image/raster file inclusing path and extension
116         * @param type
117         * @throws IOException
118         */
119        public static WorldFile readWorldFile( String filename, TYPE type )
120                                throws IOException {
121    
122            FileSeekableStream fss = new FileSeekableStream( filename );
123            RenderedOp rop = JAI.create( "stream", fss );
124            int iw = ( (Integer) rop.getProperty( "image_width" ) ).intValue();
125            int ih = ( (Integer) rop.getProperty( "image_height" ) ).intValue();
126    
127            return readWorldFile( filename, type, iw, ih );
128    
129        }
130    
131        /**
132         * @param name
133         * @return true, if the name ends with .tfw, .wld, .jgw, .gfw, .gifw, .pgw or .pngw.
134         */
135        public static boolean hasWorldfileSuffix( String name ) {
136            String lname = name.toLowerCase();
137            return lname.endsWith( ".tfw" ) || lname.endsWith( ".wld" ) || lname.endsWith( ".jgw" )
138                   || lname.endsWith( ".gfw" ) || lname.endsWith( ".gifw" ) || lname.endsWith( ".pgw" )
139                   || lname.endsWith( ".pngw" );
140        }
141    
142        /**
143         * @return a class represention of a ESRI world file
144         * @param filename
145         *            name of the image/raster file inclusing path and extension
146         * @param type
147         * @param width
148         *            image width in pixel
149         * @param height
150         *            image height in pixel
151         * @throws IOException
152         */
153        public static WorldFile readWorldFile( String filename, TYPE type, int width, int height )
154                                throws IOException {
155            // Gets the substring beginning at the specified beginIndex (0) - the beginning index,
156            // inclusive - and extends to the character at index endIndex (position of '.') - the
157            // ending index, exclusive.
158    
159            String fname = null;
160            int pos = filename.lastIndexOf( "." );
161            filename = filename.substring( 0, pos );
162    
163            // Look for corresponding worldfiles.
164            if ( ( new File( filename + ".tfw" ) ).exists() ) {
165                fname = filename + ".tfw";
166            } else if ( ( new File( filename + ".wld" ) ).exists() ) {
167                fname = filename + ".wld";
168            } else if ( ( new File( filename + ".jgw" ) ).exists() ) {
169                fname = filename + ".jgw";
170            } else if ( ( new File( filename + ".jpgw" ) ).exists() ) {
171                fname = filename + ".jpgw";
172            } else if ( ( new File( filename + ".gfw" ) ).exists() ) {
173                fname = filename + ".gfw";
174            } else if ( ( new File( filename + ".gifw" ) ).exists() ) {
175                fname = filename + ".gifw";
176            } else if ( ( new File( filename + ".pgw" ) ).exists() ) {
177                fname = filename + ".pgw";
178            } else if ( ( new File( filename + ".pngw" ) ).exists() ) {
179                fname = filename + ".pngw";
180            } else {
181                throw new IOException( "Not a world file for: " + filename );
182            }
183    
184            // Reads character files.
185            // The constructors of this class (FileReader) assume that the default character
186            // encoding and the default byte-buffer size are appropriate.
187            // The BufferedReader reads text from a character-input stream, buffering characters
188            // so as to provide for the efficient reading of characters.
189            BufferedReader br = new BufferedReader( new FileReader( fname ) );
190            String s = null;
191            int cnt = 0;
192            double d1 = 0;
193            double d2 = 0;
194            double d3 = 0;
195            double d4 = 0;
196            double d7 = 0;
197            double d8 = 0;
198            while ( ( s = br.readLine() ) != null ) {
199                cnt++;
200                s = s.trim();
201                switch ( cnt ) {
202                case 1:
203                    // spatial resolution x direction
204                    d1 = Double.parseDouble( s.replace( ',', '.' ) );
205                    break;
206                case 2:
207                    // rotation1
208                    d7 = Double.parseDouble( s.replace( ',', '.' ) );
209                    break;
210                case 3:
211                    // rotation2
212                    d8 = Double.parseDouble( s.replace( ',', '.' ) );
213                    break;
214                case 4:
215                    // spatial resolution y direction
216                    d2 = Double.parseDouble( s.replace( ',', '.' ) );
217                    break;
218                case 5:
219                    // minimum x coordinate
220                    d3 = Double.parseDouble( s.replace( ',', '.' ) );
221                    break;
222                case 6:
223                    // maximum y coordinate
224                    d4 = Double.parseDouble( s.replace( ',', '.' ) );
225                    break;
226                }
227            }
228            br.close();
229    
230            double d5 = d3 + ( ( width - 1 ) * d1 );
231            double d6 = d4 + ( ( height - 1 ) * d2 );
232            double resx = Math.abs( d1 );
233            double resy = Math.abs( d2 );
234            double ymax = d4;
235            double ymin = d6;
236            double xmax = d5;
237            double xmin = d3;
238    
239            if ( type == TYPE.OUTER ) {
240                LOG.logDebug( xmin + " " + ymin + " " + xmax + " " + ymax );
241                xmin = xmin + resx / 2d;
242                ymin = ymin - resy / 2d;
243                xmax = xmin + resx * ( width - 1 );
244                ymax = ymin + resy * ( height - 1 );
245            }
246    
247            Envelope envelope = GeometryFactory.createEnvelope( xmin, ymin, xmax, ymax, null );
248    
249            return new WorldFile( resx, resy, d7, d8, envelope );
250        }
251    
252        /**
253         * returns a class represention of a ESRI world file
254         * 
255         * @param filename
256         *            name of the image/raster file inclusing path and extension
257         * @param type
258         *            world file type
259         * @param image
260         *            image/raster the worldfile belongs too
261         * @return a class represention of a ESRI world file
262         * @throws IOException
263         */
264        public static WorldFile readWorldFile( String filename, TYPE type, BufferedImage image )
265                                throws IOException {
266    
267            return readWorldFile( filename, type, image.getWidth(), image.getHeight() );
268        }
269    
270        /**
271         * writes a WorldFile
272         * 
273         * @param wf
274         * @param fileBaseName
275         * @throws IOException
276         */
277        public static void writeWorldFile( WorldFile wf, String fileBaseName )
278                                throws IOException {
279    
280            Envelope env = wf.envelope;
281    
282            StringBuffer sb = new StringBuffer( 200 );
283    
284            sb.append( wf.resx ).append( "\n" ).append( 0.0 ).append( "\n" ).append( 0.0 );
285            sb.append( "\n" ).append( ( -1 ) * wf.resy ).append( "\n" ).append( env.getMin().getX() );
286            sb.append( "\n" ).append( env.getMax().getY() ).append( "\n" );
287    
288            File f = new File( fileBaseName + ".wld" );
289    
290            FileWriter fw = new FileWriter( f );
291            PrintWriter pw = new PrintWriter( fw );
292    
293            pw.print( sb.toString() );
294    
295            pw.close();
296            fw.close();
297        }
298    
299        /**
300         * 
301         * @param resx
302         *            resolution x-direction
303         * @param resy
304         *            resolution y-direction (negative value)
305         * @param rotation1
306         *            first rotation parameter
307         * @param rotation2
308         *            second rotation parameter
309         * @param envelope
310         *            the envelope of the worldfile
311         */
312        public WorldFile( double resx, double resy, double rotation1, double rotation2, Envelope envelope ) {
313            this.resx = resx;
314            this.resy = resy;
315            this.rotation1 = rotation1;
316            this.rotation2 = rotation2;
317            this.envelope = envelope;
318        }
319    
320        /**
321         * returns the envelope described by a word file
322         * 
323         * @return the envelope described by a word file
324         */
325        public Envelope getEnvelope() {
326            return envelope;
327        }
328    
329        /**
330         * returns the x-resolution described by a word file
331         * 
332         * @return the x-resolution described by a word file
333         */
334        public double getResx() {
335            return resx;
336        }
337    
338        /**
339         * returns the y-resolution described by a word file
340         * 
341         * @return the y-resolution described by a word file
342         */
343        public double getResy() {
344            return resy;
345        }
346    
347        /**
348         * returns the first rotation described by a word file
349         * 
350         * @return the first rotation described by a word file
351         */
352        public double getRotation1() {
353            return rotation1;
354        }
355    
356        /**
357         * returns the second rotation described by a word file
358         * 
359         * @return the second rotation described by a word file
360         */
361        public double getRotation2() {
362            return rotation2;
363        }
364    
365        @Override
366        public String toString() {
367            StringBuffer sb = new StringBuffer( 200 );
368            sb.append( "envelope: " ).append( envelope ).append( "\n" );
369            sb.append( "resx: " ).append( resx ).append( "\n" );
370            sb.append( "resy: " ).append( resy ).append( "\n" );
371            sb.append( "rotation1: " ).append( rotation1 ).append( "\n" );
372            sb.append( "rotation2: " ).append( rotation2 );
373            return sb.toString();
374        }
375    
376    }