001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.gce.geotiff;
017:
018: import java.awt.geom.AffineTransform;
019: import java.io.File;
020: import java.io.FilenameFilter;
021: import java.io.IOException;
022: import java.text.ParseException;
023: import java.util.logging.Logger;
024:
025: import javax.media.jai.JAI;
026: import javax.media.jai.TileCache;
027:
028: import junit.framework.TestCase;
029: import junit.textui.TestRunner;
030:
031: import org.geotools.coverage.grid.GridCoverage2D;
032: import org.geotools.coverage.grid.GridGeometry2D;
033: import org.geotools.coverage.grid.io.AbstractGridFormat;
034: import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
035: import org.geotools.coverage.grid.io.imageio.IIOMetadataDumper;
036: import org.geotools.coverage.processing.AbstractProcessor;
037: import org.geotools.coverage.processing.DefaultProcessor;
038: import org.geotools.geometry.GeneralEnvelope;
039: import org.geotools.referencing.CRS;
040: import org.geotools.referencing.operation.matrix.XAffineTransform;
041: import org.geotools.resources.CRSUtilities;
042: import org.geotools.test.TestData;
043: import org.opengis.coverage.grid.GridCoverageReader;
044: import org.opengis.coverage.grid.GridCoverageWriter;
045: import org.opengis.coverage.grid.GridRange;
046: import org.opengis.parameter.GeneralParameterValue;
047: import org.opengis.parameter.ParameterValueGroup;
048: import org.opengis.referencing.FactoryException;
049: import org.opengis.referencing.crs.CoordinateReferenceSystem;
050: import org.opengis.referencing.crs.ProjectedCRS;
051: import org.opengis.referencing.datum.PixelInCell;
052: import org.opengis.referencing.operation.MathTransform;
053: import org.opengis.referencing.operation.TransformException;
054:
055: /**
056: * @author Simone Giannecchini
057: *
058: * @source $URL:
059: * http://svn.geotools.org/geotools/trunk/gt/plugin/geotiff/test/org/geotools/gce/geotiff/GeoTiffVisualizationTest.java $
060: */
061: public class GeoTiffWriterTest extends TestCase {
062: private static final Logger logger = org.geotools.util.logging.Logging
063: .getLogger(GeoTiffWriterTest.class.toString());
064:
065: /**
066: *
067: */
068: public GeoTiffWriterTest() {
069: super ("Writer Test!");
070: // TODO Auto-generated constructor stub
071: }
072:
073: /**
074: * @param args
075: */
076: public static void main(String[] args) {
077: TestRunner.run(GeoTiffWriterTest.class);
078:
079: }
080:
081: /*
082: * @see TestCase#setUp()
083: */
084: protected void setUp() throws Exception {
085: super .setUp();
086: final JAI jaiDef = JAI.getDefaultInstance();
087:
088: // using a big tile cache
089: final TileCache cache = jaiDef.getTileCache();
090: cache.setMemoryCapacity(64 * 1024 * 1024);
091: cache.setMemoryThreshold(0.75f);
092:
093: }
094:
095: /**
096: * Testing {@link GeoTiffWriter} capapbilities.
097: *
098: * @throws IllegalArgumentException
099: * @throws IOException
100: * @throws UnsupportedOperationException
101: * @throws ParseException
102: * @throws FactoryException
103: */
104: public void testWriter() throws IllegalArgumentException,
105: IOException, UnsupportedOperationException, ParseException,
106: FactoryException {
107:
108: // /////////////////////////////////////////////////////////////////////
109: //
110: //
111: // PREPARATION
112: //
113: //
114: // /////////////////////////////////////////////////////////////////////
115: final File readdir = TestData.file(GeoTiffWriterTest.class, "");
116: final File writedir = new File(new StringBuffer(readdir
117: .getAbsolutePath()).append("/testWriter/").toString());
118: writedir.mkdir();
119: final File files[] = readdir.listFiles(new FilenameFilter() {
120:
121: public boolean accept(File dir, String name) {
122: // are they tiff?
123: if (!name.endsWith("tif") && !name.endsWith("tiff"))
124: return false;
125:
126: // are they geotiff?
127: return new GeoTiffFormat().accepts(new File(
128: new StringBuffer(dir.getAbsolutePath()).append(
129: File.separatorChar).append(name)
130: .toString()));
131:
132: }
133: });
134: final int numFiles = files.length;
135:
136: // /////////////////////////////////////////////////////////////////////
137: //
138: //
139: // FORMAT AND READER
140: //
141: // Creatin format and other objects we need in the further steps of this
142: // test.
143: //
144: //
145: // /////////////////////////////////////////////////////////////////////
146: final GeoTiffFormat format = new GeoTiffFormat();
147: final GeoTiffWriteParams wp = new GeoTiffWriteParams();
148: // wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
149: // wp.setCompressionType("ZLib");
150: // wp.setCompressionQuality(0.75F);
151: wp.setTilingMode(GeoToolsWriteParams.MODE_EXPLICIT);
152: wp.setTiling(256, 256);
153: final ParameterValueGroup params = format.getWriteParameters();
154: params.parameter(
155: AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName()
156: .toString()).setValue(wp);
157:
158: for (int i = 0; i < numFiles; i++) {
159:
160: // /////////////////////////////////////////////////////////////////////
161: //
162: //
163: // READER
164: //
165: //
166: // /////////////////////////////////////////////////////////////////////
167: if (TestData.isInteractiveTest())
168: logger.info(files[i].getAbsolutePath());
169:
170: // getting a reader
171: GeoTiffReader reader = new GeoTiffReader(files[i], null);
172: // dumping metadata
173: IIOMetadataDumper metadataDumper = new IIOMetadataDumper(
174: ((GeoTiffReader) reader).getMetadata()
175: .getRootNode());
176: if (TestData.isInteractiveTest()) {
177: logger.info(metadataDumper.getMetadata());
178: } else
179: metadataDumper.getMetadata();
180:
181: if (reader != null) {
182:
183: // /////////////////////////////////////////////////////////////////////
184: //
185: //
186: // COVERAGE
187: //
188: //
189: // /////////////////////////////////////////////////////////////////////
190: GridCoverage2D gc = (GridCoverage2D) reader.read(null);
191: if (TestData.isInteractiveTest()) {
192: logger.info(new StringBuffer("Coverage before: ")
193: .append("\n").append(
194: gc.getCoordinateReferenceSystem()
195: .toWKT()).append(
196: gc.getEnvelope().toString())
197: .toString());
198: }
199: if (gc != null) {
200: // /////////////////////////////////////////////////////////////////////
201: //
202: //
203: // WRITING
204: //
205: //
206: // /////////////////////////////////////////////////////////////////////
207: GeneralEnvelope sourceEnv = (GeneralEnvelope) gc
208: .getEnvelope();
209: CoordinateReferenceSystem sourceCRS = gc
210: .getCoordinateReferenceSystem2D();
211: final File writeFile = new File(new StringBuffer(
212: writedir.getAbsolutePath()).append(
213: File.separatorChar).append(
214: gc.getName().toString()).append(".tiff")
215: .toString());
216: GridCoverageWriter writer = format
217: .getWriter(writeFile);
218: writer.write(gc, (GeneralParameterValue[]) params
219: .values().toArray(
220: new GeneralParameterValue[1]));
221:
222: // /////////////////////////////////////////////////////////////////////
223: //
224: //
225: // READING BACK
226: //
227: //
228: // /////////////////////////////////////////////////////////////////////
229: reader = new GeoTiffReader(writeFile, null);
230: metadataDumper = new IIOMetadataDumper(
231: ((GeoTiffReader) reader).getMetadata()
232: .getRootNode());
233: if (TestData.isInteractiveTest()) {
234: logger.info(metadataDumper.getMetadata());
235: } else
236: metadataDumper.getMetadata();
237: gc = (GridCoverage2D) reader.read(null);
238: CoordinateReferenceSystem targetCRS = gc
239: .getCoordinateReferenceSystem2D();
240: GeneralEnvelope targetEnv = (GeneralEnvelope) gc
241: .getEnvelope();
242: MathTransform tr = CRS.findMathTransform(targetCRS,
243: sourceCRS, true);
244:
245: // TODO: THE TEST BELOW IS TEMPORARILY DISABLED.
246: // The sourceCRS is constructed in a strange way.
247: // It declares "m" units, but the map projection
248: // is concatenated with a conversion from metres
249: // to feet.
250: if (false)
251: assertTrue(
252: "Source and Target coordinate reference systems do not match:"
253: + "\n\nSource CRS =\n"
254: + sourceCRS
255: + "\n\nTarget CRS =\n"
256: + targetCRS
257: + "\n\nSource projection =\n"
258: + getConversionFromBase(sourceCRS)
259: + "\n\nTarget projection =\n"
260: + getConversionFromBase(targetCRS)
261: + "\n\nInverse transform =\n"
262: + tr, CRS.equalsIgnoreMetadata(
263: targetCRS, sourceCRS)
264: || tr.isIdentity());
265: assertTrue(
266: "Source and Target envelopes do not match",
267: checkEnvelopes(sourceEnv, targetEnv, gc));
268:
269: if (TestData.isInteractiveTest()) {
270: logger
271: .info(new StringBuffer(
272: "Coverage after: ")
273: .append("\n")
274: .append(
275: gc
276: .getCoordinateReferenceSystem()
277: .toWKT())
278: .append(
279: gc.getEnvelope()
280: .toString())
281: .toString());
282: if (TestData.isInteractiveTest())
283: gc.show();
284: else
285: gc.getRenderedImage().getData();
286:
287: }
288:
289: }
290:
291: }
292:
293: }
294: }
295:
296: private static MathTransform getConversionFromBase(
297: CoordinateReferenceSystem crs) {
298: return (crs instanceof ProjectedCRS) ? ((ProjectedCRS) crs)
299: .getConversionFromBase().getMathTransform() : null;
300: }
301:
302: /**
303: * Checks two envelopes for equality ignoring their CRSs.
304: * @param sourceEnv first {@link GeneralEnvelope} to check.
305: * @param targetEnv secondo {@link GeneralEnvelope} to check.
306: * @param gc the source {@link GridCoverage2D}.
307: * @return false if they are reasonably equal, false otherwise.
308: */
309: private boolean checkEnvelopes(GeneralEnvelope sourceEnv,
310: GeneralEnvelope targetEnv, GridCoverage2D gc) {
311: final int dimension = sourceEnv.getDimension();
312: if (sourceEnv.getDimension() != targetEnv.getDimension()) {
313: return false;
314: }
315: AffineTransform mathTransformation = (AffineTransform) ((GridGeometry2D) gc
316: .getGridGeometry()).getGridToCRS2D();
317: double epsilon;
318: for (int i = 0; i < dimension; i++) {
319: epsilon = i == 0 ? XAffineTransform
320: .getScaleX0(mathTransformation) : XAffineTransform
321: .getScaleY0(mathTransformation);
322: // Comparaison below uses '!' in order to catch NaN values.
323: if (!(Math.abs(sourceEnv.getMinimum(i)
324: - targetEnv.getMinimum(i)) <= epsilon && Math
325: .abs(sourceEnv.getMaximum(i)
326: - targetEnv.getMaximum(i)) <= epsilon)) {
327: return false;
328: }
329: }
330: return true;
331: }
332:
333: /**
334: * Testing {@link GeoTiffWriter} capabilities to write a cropped coverage.
335: *
336: * @throws IllegalArgumentException
337: * @throws IOException
338: * @throws UnsupportedOperationException
339: * @throws ParseException
340: * @throws FactoryException
341: * @throws TransformException
342: */
343: public void testWriteCroppedCoverage()
344: throws IllegalArgumentException, IOException,
345: UnsupportedOperationException, ParseException,
346: FactoryException, TransformException {
347:
348: // /////////////////////////////////////////////////////////////////////
349: //
350: //
351: // READ
352: //
353: //
354: // /////////////////////////////////////////////////////////////////////
355: // /////////////////////////////////////////////////////////////////////
356: //
357: // Look for the original coverage that wew want to crop.
358: //
359: // /////////////////////////////////////////////////////////////////////
360: final File readdir = TestData.file(GeoTiffWriterTest.class, "");
361: final File writedir = new File(new StringBuffer(readdir
362: .getAbsolutePath()).append("/testWriter/").toString());
363: writedir.mkdir();
364: final File tiff = new File(readdir, "latlon.tiff");
365: assert tiff.exists() && tiff.canRead() && tiff.isFile();
366: if (TestData.isInteractiveTest())
367: logger.info(tiff.getAbsolutePath());
368:
369: // /////////////////////////////////////////////////////////////////////
370: //
371: // Create format and reader
372: //
373: // /////////////////////////////////////////////////////////////////////
374: final GeoTiffFormat format = new GeoTiffFormat();
375: // getting a reader
376: GridCoverageReader reader = format.getReader(tiff);
377: assertNotNull(reader);
378:
379: // /////////////////////////////////////////////////////////////////////
380: //
381: // Play with metadata
382: //
383: // /////////////////////////////////////////////////////////////////////
384: IIOMetadataDumper metadataDumper = new IIOMetadataDumper(
385: ((GeoTiffReader) reader).getMetadata().getRootNode());
386: if (TestData.isInteractiveTest()) {
387: logger.info(metadataDumper.getMetadata());
388: } else
389: metadataDumper.getMetadata();
390:
391: // /////////////////////////////////////////////////////////////////////
392: //
393: // Read the original coverage.
394: //
395: // /////////////////////////////////////////////////////////////////////
396: GridCoverage2D gc = (GridCoverage2D) reader.read(null);
397: if (TestData.isInteractiveTest()) {
398: logger.info(new StringBuffer("Coverage before: ").append(
399: "\n").append(
400: gc.getCoordinateReferenceSystem().toWKT()).append(
401: gc.getEnvelope().toString()).toString());
402: }
403: final CoordinateReferenceSystem sourceCRS = gc
404: .getCoordinateReferenceSystem2D();
405: final GeneralEnvelope sourceEnvelope = (GeneralEnvelope) gc
406: .getEnvelope();
407: final GridGeometry2D sourcedGG = (GridGeometry2D) gc
408: .getGridGeometry();
409: final MathTransform sourceG2W = sourcedGG
410: .getGridToCRS(PixelInCell.CELL_CENTER);
411:
412: // /////////////////////////////////////////////////////////////////////
413: //
414: //
415: // CROP
416: //
417: //
418: // /////////////////////////////////////////////////////////////////////
419:
420: // /////////////////////////////////////////////////////////////////////
421: //
422: // Crop the original coverage.
423: //
424: // /////////////////////////////////////////////////////////////////////
425: double xc = sourceEnvelope.getCenter(0);
426: double yc = sourceEnvelope.getCenter(1);
427: double xl = sourceEnvelope.getLength(0);
428: double yl = sourceEnvelope.getLength(1);
429: final GeneralEnvelope cropEnvelope = new GeneralEnvelope(
430: new double[] { xc - xl / 4.0, yc - yl / 4.0 },
431: new double[] { xc + xl / 4.0, yc + yl / 4.0 });
432: final AbstractProcessor processor = new DefaultProcessor(null);
433: final ParameterValueGroup param = processor.getOperation(
434: "CoverageCrop").getParameters();
435: param.parameter("Source").setValue(gc);
436: param.parameter("Envelope").setValue(cropEnvelope);
437: final GridCoverage2D cropped = (GridCoverage2D) processor
438: .doOperation(param);
439:
440: // /////////////////////////////////////////////////////////////////////
441: //
442: // Check that we got everything correctly after the crop.
443: //
444: // /////////////////////////////////////////////////////////////////////
445: // checking the ranges of the output image.
446: final GridGeometry2D croppedGG = (GridGeometry2D) cropped
447: .getGridGeometry();
448: final GridRange croppedGR = croppedGG.getGridRange();
449: final MathTransform croppedG2W = croppedGG
450: .getGridToCRS(PixelInCell.CELL_CENTER);
451: final GeneralEnvelope croppedEnvelope = (GeneralEnvelope) cropped
452: .getEnvelope();
453: assertTrue("min x do not match after crop", 30 == croppedGR
454: .getLower(0));
455: assertTrue("min y do not match after crop", 30 == croppedGR
456: .getLower(1));
457: assertTrue("max x do not match after crop", 90 == croppedGR
458: .getUpper(0));
459: assertTrue("max y do not match after crop", 91 == croppedGR
460: .getUpper(1));
461: // check that the affine transform are the same thing
462: assertTrue(
463: "The Grdi2World tranformations of the original and the cropped covearage do not match",
464: sourceG2W.equals(croppedG2W));
465: // check that the envelope is correct
466: final GeneralEnvelope expectedEnvelope = new GeneralEnvelope(
467: croppedGR, PixelInCell.CELL_CENTER, croppedG2W, cropped
468: .getCoordinateReferenceSystem2D());
469:
470: assertTrue(
471: "Expected envelope is different from the computed one",
472: expectedEnvelope
473: .equals(
474: croppedEnvelope,
475: XAffineTransform
476: .getScale((AffineTransform) croppedG2W) / 2.0,
477: false));
478:
479: // /////////////////////////////////////////////////////////////////////
480: //
481: //
482: // WRITING AND TESTING
483: //
484: //
485: // /////////////////////////////////////////////////////////////////////
486: final File writeFile = new File(new StringBuffer(writedir
487: .getAbsolutePath()).append(File.separatorChar).append(
488: cropped.getName().toString()).append(".tiff")
489: .toString());
490: final GridCoverageWriter writer = format.getWriter(writeFile);
491: // /////////////////////////////////////////////////////////////////////
492: //
493: // Create the writing params
494: //
495: // /////////////////////////////////////////////////////////////////////
496: final GeoTiffWriteParams wp = new GeoTiffWriteParams();
497: wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
498: wp.setCompressionType("LZW");
499: wp.setCompressionQuality(0.75F);
500: final ParameterValueGroup params = format.getWriteParameters();
501: params.parameter(
502: AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName()
503: .toString()).setValue(wp);
504: writer.write(cropped, (GeneralParameterValue[]) params.values()
505: .toArray(new GeneralParameterValue[1]));
506:
507: reader = new GeoTiffReader(writeFile, null);
508: gc = (GridCoverage2D) reader.read(null);
509: final CoordinateReferenceSystem targetCRS = gc
510: .getCoordinateReferenceSystem2D();
511: assertTrue(
512: "Source and Target coordinate reference systems do not match",
513: CRSUtilities.equalsIgnoreMetadata(sourceCRS, targetCRS));
514: assertEquals("Read-back and Cropped envelopes do not match",
515: cropped.getEnvelope(), croppedEnvelope);
516:
517: if (TestData.isInteractiveTest()) {
518: logger.info(new StringBuffer("Coverage after: ").append(
519: "\n").append(
520: gc.getCoordinateReferenceSystem().toWKT()).append(
521: gc.getEnvelope().toString()).toString());
522: if (TestData.isInteractiveTest())
523: gc.show();
524: else
525: gc.getRenderedImage().getData();
526:
527: }
528: }
529: }
|