001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/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: 9787 $
071: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
072: * @author last edited by: $Author: otonnhofer $
073: *
074: * @version $Revision: 9787 $, $Date: 2008-01-28 06:54:23 -0800 (Mon, 28 Jan 2008) $
075: */
076: public class WorldFile {
077:
078: private static ILogger LOG = LoggerFactory
079: .getLogger(WorldFile.class);
080:
081: private double resx;
082:
083: private double resy;
084:
085: private double rotation1;
086:
087: private double rotation2;
088:
089: private Envelope envelope;
090:
091: /**
092: * <code>TYPE</code> enumerates the world file types.
093: *
094: * @author <a href="mailto:schmitz@lat-lon.de">Andreas Schmitz</a>
095: * @author last edited by: $Author: otonnhofer $
096: *
097: * @version $Revision: 9787 $, $Date: 2008-01-28 06:54:23 -0800 (Mon, 28 Jan 2008) $
098: */
099: public enum TYPE {
100:
101: /**
102: * Coordinates denote pixel centers.
103: */
104: CENTER,
105:
106: /**
107: * Coordinates denote outer edges.
108: */
109: OUTER
110:
111: }
112:
113: /**
114: * @return a class represention of a ESRI world file
115: * @param filename
116: * name of the image/raster file inclusing path and extension
117: * @param type
118: * @throws IOException
119: */
120: public static WorldFile readWorldFile(String filename, TYPE type)
121: throws IOException {
122:
123: FileSeekableStream fss = new FileSeekableStream(filename);
124: RenderedOp rop = JAI.create("stream", fss);
125: int iw = ((Integer) rop.getProperty("image_width")).intValue();
126: int ih = ((Integer) rop.getProperty("image_height")).intValue();
127:
128: return readWorldFile(filename, type, iw, ih);
129:
130: }
131:
132: /**
133: * @param name
134: * @return true, if the name ends with .tfw, .wld, .jgw, .gfw, .gifw, .pgw or .pngw.
135: */
136: public static boolean hasWorldfileSuffix(String name) {
137: String lname = name.toLowerCase();
138: return lname.endsWith(".tfw") || lname.endsWith(".wld")
139: || lname.endsWith(".jgw") || lname.endsWith(".gfw")
140: || lname.endsWith(".gifw") || lname.endsWith(".pgw")
141: || lname.endsWith(".pngw");
142: }
143:
144: /**
145: * @return a class represention of a ESRI world file
146: * @param filename
147: * name of the image/raster file inclusing path and extension
148: * @param type
149: * @param width
150: * image width in pixel
151: * @param height
152: * image height in pixel
153: * @throws IOException
154: */
155: public static WorldFile readWorldFile(String filename, TYPE type,
156: int width, int height) throws IOException {
157: // Gets the substring beginning at the specified beginIndex (0) - the beginning index,
158: // inclusive - and extends to the character at index endIndex (position of '.') - the
159: // ending index, exclusive.
160:
161: String fname = null;
162: int pos = filename.lastIndexOf(".");
163: filename = filename.substring(0, pos);
164:
165: // Look for corresponding worldfiles.
166: if ((new File(filename + ".tfw")).exists()) {
167: fname = filename + ".tfw";
168: } else if ((new File(filename + ".wld")).exists()) {
169: fname = filename + ".wld";
170: } else if ((new File(filename + ".jgw")).exists()) {
171: fname = filename + ".jgw";
172: } else if ((new File(filename + ".jpgw")).exists()) {
173: fname = filename + ".jpgw";
174: } else if ((new File(filename + ".gfw")).exists()) {
175: fname = filename + ".gfw";
176: } else if ((new File(filename + ".gifw")).exists()) {
177: fname = filename + ".gifw";
178: } else if ((new File(filename + ".pgw")).exists()) {
179: fname = filename + ".pgw";
180: } else if ((new File(filename + ".pngw")).exists()) {
181: fname = filename + ".pngw";
182: } else {
183: throw new IOException("Not a world file for: " + filename);
184: }
185:
186: // Reads character files.
187: // The constructors of this class (FileReader) assume that the default character
188: // encoding and the default byte-buffer size are appropriate.
189: // The BufferedReader reads text from a character-input stream, buffering characters
190: // so as to provide for the efficient reading of characters.
191: BufferedReader br = new BufferedReader(new FileReader(fname));
192: String s = null;
193: int cnt = 0;
194: double d1 = 0;
195: double d2 = 0;
196: double d3 = 0;
197: double d4 = 0;
198: double d7 = 0;
199: double d8 = 0;
200: while ((s = br.readLine()) != null) {
201: cnt++;
202: s = s.trim();
203: switch (cnt) {
204: case 1:
205: // spatial resolution x direction
206: d1 = Double.parseDouble(s.replace(',', '.'));
207: break;
208: case 2:
209: // rotation1
210: d7 = Double.parseDouble(s.replace(',', '.'));
211: break;
212: case 3:
213: // rotation2
214: d8 = Double.parseDouble(s.replace(',', '.'));
215: break;
216: case 4:
217: // spatial resolution y direction
218: d2 = Double.parseDouble(s.replace(',', '.'));
219: break;
220: case 5:
221: // minimum x coordinate
222: d3 = Double.parseDouble(s.replace(',', '.'));
223: break;
224: case 6:
225: // maximum y coordinate
226: d4 = Double.parseDouble(s.replace(',', '.'));
227: break;
228: }
229: }
230: br.close();
231:
232: double d5 = d3 + ((width - 1) * d1);
233: double d6 = d4 + ((height - 1) * d2);
234: double resx = Math.abs(d1);
235: double resy = Math.abs(d2);
236: double ymax = d4;
237: double ymin = d6;
238: double xmax = d5;
239: double xmin = d3;
240:
241: if (type == TYPE.OUTER) {
242: LOG.logDebug(xmin + " " + ymin + " " + xmax + " " + ymax);
243: xmin = xmin + resx / 2d;
244: ymin = ymin - resy / 2d;
245: xmax = xmin + resx * (width - 1);
246: ymax = ymin + resy * (height - 1);
247: }
248:
249: Envelope envelope = GeometryFactory.createEnvelope(xmin, ymin,
250: xmax, ymax, null);
251:
252: return new WorldFile(resx, resy, d7, d8, envelope);
253: }
254:
255: /**
256: * returns a class represention of a ESRI world file
257: *
258: * @param filename
259: * name of the image/raster file inclusing path and extension
260: * @param type
261: * world file type
262: * @param image
263: * image/raster the worldfile belongs too
264: * @return a class represention of a ESRI world file
265: * @throws IOException
266: */
267: public static WorldFile readWorldFile(String filename, TYPE type,
268: BufferedImage image) throws IOException {
269:
270: return readWorldFile(filename, type, image.getWidth(), image
271: .getHeight());
272: }
273:
274: /**
275: * writes a WorldFile
276: *
277: * @param wf
278: * @param fileBaseName
279: * @throws IOException
280: */
281: public static void writeWorldFile(WorldFile wf, String fileBaseName)
282: throws IOException {
283:
284: Envelope env = wf.envelope;
285:
286: StringBuffer sb = new StringBuffer(200);
287:
288: sb.append(wf.resx).append("\n").append(0.0).append("\n")
289: .append(0.0);
290: sb.append("\n").append((-1) * wf.resy).append("\n").append(
291: env.getMin().getX());
292: sb.append("\n").append(env.getMax().getY()).append("\n");
293:
294: File f = new File(fileBaseName + ".wld");
295:
296: FileWriter fw = new FileWriter(f);
297: PrintWriter pw = new PrintWriter(fw);
298:
299: pw.print(sb.toString());
300:
301: pw.close();
302: fw.close();
303: }
304:
305: /**
306: * Create a new WorldFile with an envelope that spans from the center of the corner pixels.
307: *
308: * @param resx
309: * resolution x-direction
310: * @param resy
311: * resolution y-direction (negative value)
312: * @param rotation1
313: * first rotation parameter
314: * @param rotation2
315: * second rotation parameter
316: * @param envelope
317: * the envelope of the worldfile
318: */
319: public WorldFile(double resx, double resy, double rotation1,
320: double rotation2, Envelope envelope) {
321: this .resx = resx;
322: this .resy = resy;
323: this .rotation1 = rotation1;
324: this .rotation2 = rotation2;
325: this .envelope = envelope;
326: }
327:
328: /**
329: * Create a new WorldFile with an envelope.
330: *
331: * @param resx
332: * resolution x-direction
333: * @param resy
334: * resolution y-direction (negative value)
335: * @param rotation1
336: * first rotation parameter
337: * @param rotation2
338: * second rotation parameter
339: * @param envelope
340: * the envelope of the worldfile
341: * @param type
342: * whether the envelope spans from the center or from the outer bounds
343: * of the corner pixels
344: */
345: public WorldFile(double resx, double resy, double rotation1,
346: double rotation2, Envelope envelope, TYPE type) {
347: this .resx = resx;
348: this .resy = resy;
349: this .rotation1 = rotation1;
350: this .rotation2 = rotation2;
351: if (type == TYPE.CENTER) {
352: this .envelope = envelope;
353: } else { // convert to internal TYPE.CENTER format
354: this .envelope = GeometryFactory.createEnvelope(envelope
355: .getMin().getX()
356: + resx / 2, envelope.getMin().getY() + resy / 2,
357: envelope.getMax().getX() - resx / 2, envelope
358: .getMax().getY()
359: - resy / 2, envelope.getCoordinateSystem());
360: }
361: }
362:
363: /**
364: * returns the envelope described by a word file.
365: * The envelope spans the center coordinates of the corner pixels.
366: *
367: * @return the envelope described by a word file
368: */
369: public Envelope getEnvelope() {
370: return envelope;
371: }
372:
373: /**
374: * returns the envelope described by a word file
375: *
376: * @param envType
377: * whether the result envelope should span from the center or from the outer bounds
378: * of the corner pixels
379: * @return the envelope described by a word file
380: */
381: public Envelope getEnvelope(TYPE envType) {
382: if (envType == TYPE.CENTER) {
383: return envelope;
384: } else { // convert from internal TYPE.CENTER format to TYPE.OUTER
385: return GeometryFactory.createEnvelope(envelope.getMin()
386: .getX()
387: - resx / 2, envelope.getMin().getY() - resy / 2,
388: envelope.getMax().getX() + resx / 2, envelope
389: .getMax().getY()
390: + resy / 2, envelope.getCoordinateSystem());
391: }
392: }
393:
394: /**
395: * returns the x-resolution described by a word file
396: *
397: * @return the x-resolution described by a word file
398: */
399: public double getResx() {
400: return resx;
401: }
402:
403: /**
404: * returns the y-resolution described by a word file
405: *
406: * @return the y-resolution described by a word file
407: */
408: public double getResy() {
409: return resy;
410: }
411:
412: /**
413: * returns the first rotation described by a word file
414: *
415: * @return the first rotation described by a word file
416: */
417: public double getRotation1() {
418: return rotation1;
419: }
420:
421: /**
422: * returns the second rotation described by a word file
423: *
424: * @return the second rotation described by a word file
425: */
426: public double getRotation2() {
427: return rotation2;
428: }
429:
430: @Override
431: public String toString() {
432: StringBuffer sb = new StringBuffer(200);
433: sb.append("envelope: ").append(envelope).append("\n");
434: sb.append("resx: ").append(resx).append("\n");
435: sb.append("resy: ").append(resy).append("\n");
436: sb.append("rotation1: ").append(rotation1).append("\n");
437: sb.append("rotation2: ").append(rotation2);
438: return sb.toString();
439: }
440:
441: }
|