Source Code Cross Referenced for Resampler2D.java in  » GIS » GeoTools-2.4.1 » org » geotools » coverage » processing » operation » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.coverage.processing.operation 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2002, Institut de Recherche pour le Développement
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.coverage.processing.operation;
018:
019:        // J2SE dependencies
020:        import java.awt.RenderingHints;
021:        import java.awt.geom.AffineTransform;
022:        import java.awt.image.renderable.ParameterBlock;
023:        import java.util.List;
024:        import java.util.Locale;
025:        import java.util.logging.Level;
026:        import java.util.logging.LogRecord;
027:
028:        import javax.media.jai.ImageLayout;
029:        import javax.media.jai.Interpolation;
030:        import javax.media.jai.JAI;
031:        import javax.media.jai.PlanarImage;
032:        import javax.media.jai.RenderedOp;
033:        import javax.media.jai.Warp;
034:
035:        import org.geotools.coverage.GridSampleDimension;
036:        import org.geotools.coverage.grid.GeneralGridRange;
037:        import org.geotools.coverage.grid.GridCoverage2D;
038:        import org.geotools.coverage.grid.GridGeometry2D;
039:        import org.geotools.coverage.processing.AbstractProcessor;
040:        import org.geotools.coverage.processing.CannotReprojectException;
041:        import org.geotools.factory.Hints;
042:        import org.geotools.geometry.GeneralEnvelope;
043:        import org.geotools.image.ImageWorker;
044:        import org.geotools.referencing.CRS;
045:        import org.geotools.referencing.ReferencingFactoryFinder;
046:        import org.geotools.referencing.operation.matrix.XAffineTransform;
047:        import org.geotools.referencing.operation.transform.DimensionFilter;
048:        import org.geotools.referencing.operation.transform.IdentityTransform;
049:        import org.geotools.referencing.operation.transform.WarpTransform2D;
050:        import org.geotools.resources.XArray;
051:        import org.geotools.resources.coverage.CoverageUtilities;
052:        import org.geotools.resources.i18n.ErrorKeys;
053:        import org.geotools.resources.i18n.Errors;
054:        import org.geotools.resources.i18n.Logging;
055:        import org.geotools.resources.i18n.LoggingKeys;
056:        import org.geotools.resources.image.ImageUtilities;
057:        import org.opengis.coverage.grid.GridRange;
058:        import org.opengis.referencing.FactoryException;
059:        import org.opengis.referencing.crs.CoordinateReferenceSystem;
060:        import org.opengis.referencing.operation.CoordinateOperationFactory;
061:        import org.opengis.referencing.operation.MathTransform;
062:        import org.opengis.referencing.operation.MathTransform2D;
063:        import org.opengis.referencing.operation.MathTransformFactory;
064:        import org.opengis.referencing.operation.TransformException;
065:        import org.opengis.geometry.Envelope;
066:
067:        /**
068:         * Implementation of the {@link Resample} operation. This implementation is provided as a
069:         * separated class for two purpose: avoid loading this code before needed and provide some
070:         * way to check if a grid coverages is a result of a resample operation.
071:         *
072:         * @since 2.2
073:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/coverage/processing/operation/Resampler2D.java $
074:         * @version $Id: Resampler2D.java 28130 2007-11-29 11:26:25Z afabiani $
075:         * @author Martin Desruisseaux
076:         */
077:        final class Resampler2D extends GridCoverage2D {
078:            /**
079:             * The logging level for defails about resampling operation applied.
080:             */
081:            private static final Level LOGGING_LEVEL = Level.FINE;
082:
083:            /**
084:             * Constructs a new grid coverage for the specified grid geometry.
085:             *
086:             * @param source   The source for this grid coverage.
087:             * @param image    The image.
088:             * @param geometry The grid geometry (including the new CRS).
089:             */
090:            private Resampler2D(final GridCoverage2D source,
091:                    final PlanarImage image, final GridGeometry2D geometry,
092:                    GridSampleDimension[] sampleDimensions) {
093:                super (source.getName(), image, geometry, sampleDimensions,
094:                        new GridCoverage2D[] { source }, null);
095:            }
096:
097:            /**
098:             * Creates a new coverage with a different coordinate reference reference system. If a
099:             * grid geometry is supplied, only its {@linkplain GridGeometry2D#getRange grid range}
100:             * and {@linkplain GridGeometry2D#getGridToCoordinateSystem grid to CRS} transform are
101:             * taken in account.
102:             *
103:             * @param sourceCoverage The source grid coverage.
104:             * @param targetCRS      Coordinate reference system for the new grid coverage, or {@code null}.
105:             * @param targetGG       The target grid geometry, or {@code null} for default.
106:             * @param interpolation  The interpolation to use.
107:             * @param hints          The rendering hints. This is usually provided by
108:             *                       {@link AbstractProcessor}. This method will looks for
109:             *                       {@link Hints#COORDINATE_OPERATION_FACTORY} and
110:             *                       {@link Hints#JAI_INSTANCE} keys.
111:             * @return The new grid coverage, or {@code sourceCoverage} if no resampling was needed.
112:             * @throws FactoryException if a transformation step can't be created.
113:             * @throws TransformException if a transformation failed.
114:             */
115:            public static GridCoverage2D reproject(
116:                    GridCoverage2D sourceCoverage,
117:                    CoordinateReferenceSystem targetCRS,
118:                    GridGeometry2D targetGG, final Interpolation interpolation,
119:                    final Hints hints) throws FactoryException,
120:                    TransformException {
121:                /*
122:                 * Grid range and "grid to CRS" transform are the only grid geometry informations used
123:                 * by this method. If they are not available, this is equivalent to not providing grid
124:                 * geometry at all. Set to null, since null value is what the remaining code will check
125:                 * for.
126:                 */
127:                if (targetGG != null) {
128:                    if (!targetGG.isDefined(GridGeometry2D.GRID_RANGE)
129:                            && !targetGG.isDefined(GridGeometry2D.GRID_TO_CRS)) {
130:                        targetGG = null;
131:                    }
132:                }
133:                final boolean automaticGG = (targetGG == null);
134:                final boolean automaticGR = automaticGG
135:                        || !targetGG.isDefined(GridGeometry2D.GRID_RANGE);
136:                /*
137:                 * If the source coverage is already the result of a previous "Resample" operation,
138:                 * go up in the chain and check if a previously computed image could fits (i.e. the
139:                 * requested resampling may be the inverse of a previous resampling). This method
140:                 * may stop immediately if a suitable image is found. Otherwise, we will resample
141:                 * the original image instead of the user-supplied one, in order to reduce the amount
142:                 * of intermediate steps (and maybe give a chance to the garbage collector to collect
143:                 * the user-supplied image).
144:                 */
145:                boolean sameGG, sameCRS;
146:                GridGeometry2D sourceGG;
147:                CoordinateReferenceSystem sourceCRS;
148:                while (true) {
149:                    sourceGG = (GridGeometry2D) sourceCoverage
150:                            .getGridGeometry(); // TODO: remove cast with J2SE 1.5.
151:                    sourceCRS = sourceCoverage.getCoordinateReferenceSystem();
152:                    if (targetCRS == null) {
153:                        targetCRS = sourceCRS;
154:                    }
155:                    sameGG = (targetGG == null || equivalent(targetGG, sourceGG));
156:                    sameCRS = CRS.equalsIgnoreMetadata(targetCRS, sourceCRS);
157:                    if (sameGG && sameCRS) {
158:                        return sourceCoverage;
159:                    }
160:                    if (sourceCoverage instanceof  Resampler2D) {
161:                        final List sources = sourceCoverage.getSources();
162:                        if (sources.size() != 1) {
163:                            // Should not happen, but test anyway.
164:                            throw new AssertionError(sources);
165:                        }
166:                        sourceCoverage = (GridCoverage2D) sources.get(0);
167:                        continue;
168:                    }
169:                    break;
170:                }
171:                /*
172:                 * Preparing the source image
173:                 */
174:                PlanarImage sourceImage = PlanarImage
175:                        .wrapRenderedImage(sourceCoverage.getRenderedImage());
176:                // 0==nothing changes, 1==index color expanded,
177:                // 2==taken geophysics, 3==taken non-geophysics
178:                final int actionTaken = CoverageUtilities
179:                        .prepareSourcesForGCOperation(sourceCoverage,
180:                                interpolation, false, hints);
181:                ParameterBlock paramBlk = new ParameterBlock();
182:                switch (actionTaken) {
183:                case 1: {
184:                    sourceImage = new ImageWorker(sourceImage)
185:                            .forceComponentColorModel().getPlanarImage();
186:                    break;
187:                }
188:                case 2: {
189:                    // in this case we need to go back the geophysics view of the
190:                    // source coverage
191:                    sourceCoverage = sourceCoverage.geophysics(true);
192:                    sourceImage = PlanarImage.wrapRenderedImage(sourceCoverage
193:                            .getRenderedImage());
194:                    break;
195:                }
196:                case 3: {
197:                    sourceCoverage = sourceCoverage.geophysics(false);
198:                    break;
199:                }
200:                }
201:                paramBlk.addSource(sourceImage);
202:                /*
203:                 * Hints management
204:                 */
205:                RenderingHints targetHints = ImageUtilities
206:                        .getRenderingHints(sourceImage);
207:                if (targetHints == null) {
208:                    targetHints = new RenderingHints(hints);
209:                } else if (hints != null) {
210:                    targetHints.add(hints);
211:                }
212:                /*
213:                 * The source coverage is now selected and will not change anymore. Gets
214:                 * the JAI instance and factories to use from the rendering hints.
215:                 */
216:                final JAI processor;
217:                if (true) {
218:                    final Object property = (hints != null) ? hints
219:                            .get(Hints.JAI_INSTANCE) : null;
220:                    if (property instanceof  JAI) {
221:                        processor = (JAI) property;
222:                    } else {
223:                        processor = JAI.getDefaultInstance();
224:                    }
225:                }
226:                final CoordinateOperationFactory factory = ReferencingFactoryFinder
227:                        .getCoordinateOperationFactory(hints);
228:                final MathTransformFactory mtFactory = ReferencingFactoryFinder
229:                        .getMathTransformFactory(hints);
230:                /*
231:                 * Computes the INVERSE of the math transform from [Source Grid] to [Target Grid].
232:                 * The transform will be computed using the following path:
233:                 *
234:                 *      Target Grid --> Target CRS --> Source CRS --> Source Grid
235:                 *                   ^              ^              ^
236:                 *                 step 1         step 2         step 3
237:                 *
238:                 * If source and target CRS are equal, a shorter path is used. This special
239:                 * case is needed because 'sourceCRS' and 'targetCRS' may be null.
240:                 *
241:                 *      Target Grid --> Common CRS --> Source Grid
242:                 *                   ^              ^
243:                 *                 step 1         step 3
244:                 */
245:                final MathTransform step1, step2, step3, allSteps, allSteps2D;
246:                if (sameCRS) {
247:                    /*
248:                     * Note: targetGG should not be null, otherwise the code that computed 'sameCRS'
249:                     *       should have already detected that this resample is not doing anything.
250:                     */
251:                    if (!targetGG.isDefined(GridGeometry2D.GRID_TO_CRS)) {
252:                        step1 = sourceGG.getGridToCRS(); // Really sourceGG, not targetGG
253:                        step2 = IdentityTransform.create(step1
254:                                .getTargetDimensions());
255:                        step3 = step1.inverse();
256:                        allSteps = IdentityTransform.create(step1
257:                                .getSourceDimensions());
258:                        targetGG = new GridGeometry2D(targetGG.getGridRange(),
259:                                step1, targetCRS);
260:                    } else {
261:                        step1 = targetGG.getGridToCRS();
262:                        step2 = IdentityTransform.create(step1
263:                                .getTargetDimensions());
264:                        step3 = sourceGG.getGridToCRS().inverse();
265:                        allSteps = mtFactory.createConcatenatedTransform(step1,
266:                                step3);
267:                        if (!targetGG.isDefined(GridGeometry2D.GRID_RANGE)) {
268:                            /*
269:                             * If the target grid range was not explicitely specified, a grid range will be
270:                             * automatically computed in such a way that it will maps to the same envelope
271:                             * (at least approximatively).
272:                             */
273:                            Envelope gridRange;
274:                            gridRange = toEnvelope(sourceGG.getGridRange());
275:                            gridRange = CRS.transform(allSteps.inverse(),
276:                                    gridRange);
277:                            targetGG = new GridGeometry2D(new GeneralGridRange(
278:                                    gridRange), step1, targetCRS);
279:                        }
280:                    }
281:                } else {
282:                    if (sourceCRS == null) {
283:                        throw new CannotReprojectException(Errors
284:                                .format(ErrorKeys.UNSPECIFIED_CRS));
285:                    }
286:                    final Envelope sourceEnvelope;
287:                    final GeneralEnvelope targetEnvelope;
288:                    step2 = factory.createOperation(targetCRS, sourceCRS)
289:                            .getMathTransform();
290:                    step3 = sourceGG.getGridToCRS().inverse();
291:                    sourceEnvelope = sourceCoverage.getEnvelope();
292:                    targetEnvelope = CRS.transform(step2.inverse(),
293:                            sourceEnvelope);
294:                    targetEnvelope.setCoordinateReferenceSystem(targetCRS);
295:                    /*
296:                     * If the target GridGeometry is incomplete, provides default
297:                     * values for the missing fields. Three cases may occurs:
298:                     *
299:                     * - User provided no GridGeometry at all. Then, constructs an image of the same size
300:                     *   than the source image and set an envelope big enough to contains the projected
301:                     *   coordinates. The transform will derivate from the grid range and the envelope.
302:                     *
303:                     * - User provided only a grid range.  Then, set an envelope big enough to contains
304:                     *   the projected coordinates. The transform will derivate from the grid range and
305:                     *   the envelope.
306:                     *
307:                     * - User provided only a "grid to coordinate system" transform. Then, transform the
308:                     *   projected envelope to "grid units" using the specified transform,  and create a
309:                     *   grid range big enough to hold the result.
310:                     */
311:                    if (targetGG == null) {
312:                        targetGG = new GridGeometry2D(sourceGG.getGridRange(),
313:                                targetEnvelope);
314:                        step1 = targetGG.getGridToCRS();
315:                    } else if (!targetGG.isDefined(GridGeometry2D.GRID_TO_CRS)) {
316:                        targetGG = new GridGeometry2D(targetGG.getGridRange(),
317:                                targetEnvelope);
318:                        step1 = targetGG.getGridToCRS();
319:                    } else {
320:                        step1 = targetGG.getGridToCRS();
321:                        if (!targetGG.isDefined(GridGeometry2D.GRID_RANGE)) {
322:                            final GeneralEnvelope gridRange;
323:                            gridRange = CRS.transform(step1.inverse(),
324:                                    targetEnvelope);
325:                            for (int i = gridRange.getDimension(); --i >= 0;) {
326:                                /*
327:                                 * According OpenGIS specification, GridGeometry maps pixel's center.
328:                                 * But the bounding box was for all pixels, not pixel's centers. Offset
329:                                 * by 0.5 (use +0.5 for maximum too, not -0.5, since maximum is exclusive).
330:                                 */
331:                                gridRange.setRange(i,
332:                                        gridRange.getMinimum(i) + 0.5,
333:                                        gridRange.getMaximum(i) + 0.5);
334:                            }
335:                            targetGG = new GridGeometry2D(new GeneralGridRange(
336:                                    gridRange), step1, targetCRS);
337:                        }
338:                    }
339:                    /*
340:                     * Computes the final transform.
341:                     */
342:                    if (step1.equals(step3.inverse())) {
343:                        allSteps = step2;
344:                    } else {
345:                        allSteps = mtFactory.createConcatenatedTransform(
346:                                mtFactory.createConcatenatedTransform(step1,
347:                                        step2), step3);
348:                    }
349:                }
350:                allSteps2D = getMathTransform2D(allSteps, mtFactory, targetGG);
351:                if (!(allSteps2D instanceof  MathTransform2D)) {
352:                    // Should not happen with Geotools implementations. May happen
353:                    // with some external implementations, but should stay unusual.
354:                    throw new TransformException(Errors
355:                            .format(ErrorKeys.NO_TRANSFORM2D_AVAILABLE));
356:                }
357:                /*
358:                 * Prepare the parameter block for the image to be created. Prepare also
359:                 * rendering hints, which contains mostly indications about tiles layout.
360:                 * The xmin, xmax, ymin and ymax bounds are relative to the target image.
361:                 */
362:                //      final PlanarImage sourceImage =
363:                final GridRange targetGR = targetGG.getGridRange();
364:                final int xAxis = targetGG.gridDimensionX;
365:                final int yAxis = targetGG.gridDimensionY;
366:                final int xmin = targetGR.getLower(xAxis);
367:                final int xmax = targetGR.getUpper(xAxis);
368:                final int ymin = targetGR.getLower(yAxis);
369:                final int ymax = targetGR.getUpper(yAxis);
370:                final GridRange sourceGR = sourceGG.getGridRange();
371:                final int xminS = sourceGR.getLower(xAxis);
372:                final int xmaxS = sourceGR.getUpper(xAxis);
373:                final int yminS = sourceGR.getLower(yAxis);
374:                final int ymaxS = sourceGR.getUpper(yAxis);
375:                ImageLayout layout = (ImageLayout) targetHints
376:                        .get(JAI.KEY_IMAGE_LAYOUT);
377:                if (layout != null) {
378:                    layout = (ImageLayout) layout.clone();
379:                } else {
380:                    layout = new ImageLayout(sourceImage);
381:                    layout.unsetImageBounds();
382:                    layout.unsetTileLayout();
383:                    // At this point, only the color model and sample model are left valids.
384:                }
385:                if ((layout.getValidMask() & (ImageLayout.MIN_X_MASK
386:                        | ImageLayout.MIN_Y_MASK | ImageLayout.WIDTH_MASK | ImageLayout.HEIGHT_MASK)) == 0) {
387:                    layout.setMinX(targetGR.getLower(xAxis));
388:                    layout.setMinY(targetGR.getLower(yAxis));
389:                    layout.setWidth(targetGR.getLength(xAxis));
390:                    layout.setHeight(targetGR.getLength(yAxis));
391:                }
392:                if ((layout.getValidMask() & (ImageLayout.TILE_WIDTH_MASK
393:                        | ImageLayout.TILE_HEIGHT_MASK
394:                        | ImageLayout.TILE_GRID_X_OFFSET_MASK | ImageLayout.TILE_GRID_Y_OFFSET_MASK)) == 0) {
395:                    layout.setTileGridXOffset(layout.getMinX(sourceImage));
396:                    layout.setTileGridYOffset(layout.getMinY(sourceImage));
397:                    final int width = layout.getWidth(sourceImage);
398:                    final int height = layout.getHeight(sourceImage);
399:                    if (layout.getTileWidth(sourceImage) > width)
400:                        layout.setTileWidth(width);
401:                    if (layout.getTileHeight(sourceImage) > height)
402:                        layout.setTileHeight(height);
403:                }
404:                targetHints.put(JAI.KEY_IMAGE_LAYOUT, layout);
405:                // it is crucial to correctly manage the Hints to control the
406:                // replacement of IndexColorModel. It is worth to point out that setting
407:                // the JAI.KEY_REPLACE_INDEX_COLOR_MODEL hint to true is not enough to
408:                // force the operators to do an expansion.
409:                // If we explicitly provide an ImageLayout built with the source image
410:                // where the CM and the SM are valid. those will be employed overriding
411:                // a the possibility to expand the color model.
412:                if (actionTaken != 1) {
413:                    targetHints
414:                            .add(ImageUtilities.DONT_REPLACE_INDEX_COLOR_MODEL);
415:                } else {
416:                    targetHints.add(ImageUtilities.REPLACE_INDEX_COLOR_MODEL);
417:                    layout.unsetValid(ImageLayout.COLOR_MODEL_MASK);
418:                    layout.unsetValid(ImageLayout.SAMPLE_MODEL_MASK);
419:                }
420:                /*
421:                 * If the user requests a new grid geometry with the same coordinate reference system,
422:                 * and if the grid geometry is equivalents to a simple extraction of a sub-area, then
423:                 * delegates the work to a "Crop" operation.
424:                 */
425:                String operation = null;
426:                if (((allSteps instanceof  AffineTransform) && XAffineTransform
427:                        .isIdentity((AffineTransform) allSteps, 10E-2))
428:                        || allSteps.isIdentity()) {
429:                    if (xmin > xminS && xmax < xmaxS && ymin > yminS
430:                            && ymax < ymaxS) {
431:                        operation = "Crop";
432:                        paramBlk = paramBlk.add((float) (xmin)).add(
433:                                (float) (ymin)).add((float) (xmax - xmin)).add(
434:                                (float) (ymax - ymin));
435:                    } else if (xmin == xminS && xmax == xmaxS && ymin == yminS
436:                            && ymax == ymaxS) {
437:                        // Optimization in case we have nothing to do, not even a crop.
438:                        GridCoverage2D targetCoverage = new Resampler2D(
439:                                sourceCoverage, sourceImage, targetGG,
440:                                actionTaken == 1 ? null : sourceCoverage
441:                                        .getSampleDimensions());
442:                        switch (actionTaken) {
443:                        case 3:
444:                            targetCoverage = targetCoverage.geophysics(true);
445:                            break;
446:                        case 2:
447:                            targetCoverage = targetCoverage.geophysics(false);
448:                            break;
449:                        }
450:                        return targetCoverage;
451:                    }
452:                }
453:                /*
454:                 * Special case for the affine transform. Try to use the JAI "Affine" operation instead of
455:                 * the more general "Warp" one. JAI provides native acceleration for the affine operation.
456:                 * NOTE: "Affine", "Scale", "Translate", "Rotate" and similar operations ignore the 'xmin',
457:                 * 'ymin', 'width' and 'height' image layout. Consequently, we can't use this operation if
458:                 * the user provided explicitely a grid range.
459:                 *
460:                 * Note: if the user didn't specified any grid geometry, then a yet cheaper approach is to
461:                 *       just update the 'gridToCRS' value. We returns a grid coverage wrapping the SOURCE
462:                 *       image with the updated grid geometry.
463:                 */
464:                double[] background = null;
465:                if (operation == null) {
466:                    if (allSteps instanceof  AffineTransform
467:                            && (automaticGG || automaticGR)) {
468:                        if (automaticGG) {
469:                            background = null;// we won't use it
470:                            // Cheapest approach: just update 'gridToCRS'.
471:                            GridCoverage2D targetCoverage;
472:                            MathTransform mtr;
473:                            mtr = sourceGG.getGridToCRS();
474:                            mtr = mtFactory.createConcatenatedTransform(mtr,
475:                                    step2.inverse());
476:                            targetGG = new GridGeometry2D(sourceGG
477:                                    .getGridRange(), mtr, targetCRS);
478:                            /*
479:                             * Note: do NOT use the "GridGeometry2D(sourceGridRange,
480:                             * targetEnvelope)" constructor in the above line. We must
481:                             * give a MathTransform argument to the constructor, not an
482:                             * Envelope, because the later infer a MathTransform using
483:                             * heuristic rules. Only the constructor with a
484:                             * MathTransform argument is fully accurate.
485:                             */
486:                            targetCoverage = new Resampler2D(sourceCoverage,
487:                                    sourceImage, targetGG,
488:                                    actionTaken == 1 ? null : sourceCoverage
489:                                            .getSampleDimensions());
490:                            switch (actionTaken) {
491:                            case 3:
492:                                targetCoverage = targetCoverage
493:                                        .geophysics(true);
494:                                break;
495:                            case 2:
496:                                targetCoverage = targetCoverage
497:                                        .geophysics(false);
498:                                break;
499:                            }
500:                            return targetCoverage;
501:                        }
502:                        // More general approach: apply the affine transform.
503:                        if (automaticGR) {
504:                            operation = "Affine";
505:                            // prepare the values for the background
506:                            background = CoverageUtilities
507:                                    .getBackgroundValues(sourceCoverage);
508:                            final AffineTransform affine = (AffineTransform) allSteps
509:                                    .inverse();
510:                            paramBlk = paramBlk.add(affine).add(interpolation)
511:                                    .add(background);
512:                        }
513:                    } else {
514:                        /*
515:                         * General case: construct the warp transform.
516:                         */
517:                        operation = "Warp";
518:                        final Warp warp = WarpTransform2D.getWarp(
519:                                sourceCoverage.getName(),
520:                                (MathTransform2D) allSteps2D);
521:                        // prepare the values for the background
522:                        background = CoverageUtilities
523:                                .getBackgroundValues(sourceCoverage);
524:                        paramBlk = paramBlk.add(warp).add(interpolation).add(
525:                                background);
526:                    }
527:                }
528:                final RenderedOp targetImage = processor.createNS(operation,
529:                        paramBlk, targetHints);
530:                final Locale locale = sourceCoverage.getLocale(); // For logging purpose.
531:                /*
532:                 * The JAI operation sometime returns an image with a bounding box different than what we
533:                 * expected. This is true especially for the "Affine" operation: the JAI documentation said
534:                 * explicitly that xmin, ymin, width and height image layout hints are ignored for this one.
535:                 * As a safety, we check the bounding box in any case. If it doesn't matches, then we will
536:                 * reconstruct the target grid geometry.
537:                 */
538:                final int[] lower = targetGR.getLower().getCoordinateValues();
539:                final int[] upper = targetGR.getUpper().getCoordinateValues();
540:                lower[xAxis] = targetImage.getMinX();
541:                lower[yAxis] = targetImage.getMinY();
542:                upper[xAxis] = targetImage.getMaxX();
543:                upper[yAxis] = targetImage.getMaxY();
544:                final GridRange actualGR = new GeneralGridRange(lower, upper);
545:                if (!targetGR.equals(actualGR)) {
546:                    MathTransform gridToCRS = targetGG.getGridToCRS();
547:                    targetGG = new GridGeometry2D(actualGR, gridToCRS,
548:                            targetCRS);
549:                    if (!automaticGR) {
550:                        log(Logging.getResources(locale).getLogRecord(
551:                                Level.WARNING,
552:                                LoggingKeys.ADJUSTED_GRID_GEOMETRY_$1,
553:                                sourceCoverage.getName().toString(locale)));
554:                    }
555:                }
556:                /*
557:                 * Constructs the final grid coverage, then log a message as in the following example:
558:                 *
559:                 *     Resampled coverage "Foo" from coordinate system "myCS" (for an image of size
560:                 *     1000x1500) to coordinate system "WGS84" (image size 1000x1500). JAI operation
561:                 *     is "Warp" with "Nearest" interpolation on geophysics pixels values. Background
562:                 *     value is 255.
563:                 */
564:                GridCoverage2D targetCoverage = new Resampler2D(sourceCoverage,
565:                        targetImage, targetGG, actionTaken == 1 ? null
566:                                : sourceCoverage.getSampleDimensions());
567:                switch (actionTaken) {
568:                case 3:
569:                    targetCoverage = targetCoverage.geophysics(true);
570:                    break;
571:                case 2:
572:                    targetCoverage = targetCoverage.geophysics(false);
573:                    break;
574:                }
575:                assert CRS.equalsIgnoreMetadata(targetCoverage
576:                        .getCoordinateReferenceSystem(), targetCRS) : targetGG;
577:                assert ((GridGeometry2D) targetCoverage.getGridGeometry())
578:                        .getGridRange2D().equals(targetImage.getBounds()) : targetGG;
579:                if (AbstractProcessor.LOGGER.isLoggable(LOGGING_LEVEL)) {
580:                    log(Logging
581:                            .getResources(locale)
582:                            .getLogRecord(
583:                                    LOGGING_LEVEL,
584:                                    LoggingKeys.APPLIED_RESAMPLE_$11,
585:                                    new Object[] {
586:                                            /*  {0} */sourceCoverage.getName()
587:                                                    .toString(locale),
588:                                            /*  {1} */sourceCoverage
589:                                                    .getCoordinateReferenceSystem()
590:                                                    .getName().getCode(),
591:                                            /*  {2} */new Integer(sourceImage
592:                                                    .getWidth()),
593:                                            /*  {3} */new Integer(sourceImage
594:                                                    .getHeight()),
595:                                            /*  {4} */targetCoverage
596:                                                    .getCoordinateReferenceSystem()
597:                                                    .getName().getCode(),
598:                                            /*  {5} */new Integer(targetImage
599:                                                    .getWidth()),
600:                                            /*  {6} */new Integer(targetImage
601:                                                    .getHeight()),
602:                                            /*  {7} */targetImage
603:                                                    .getOperationName(),
604:                                            /*  {8} */new Integer(
605:                                                    sourceCoverage == sourceCoverage
606:                                                            .geophysics(true) ? 1
607:                                                            : 0),
608:                                            /*  {9} */ImageUtilities
609:                                                    .getInterpolationName(interpolation),
610:                                            /* {10} */(background != null) ? background.length == 1 ? (Double
611:                                                    .isNaN(background[0]) ? (Object) "NaN"
612:                                                    : (Object) new Double(
613:                                                            background[0]))
614:                                                    : (Object) XArray.toString(
615:                                                            background, locale)
616:                                                    : "No background used" }));
617:                }
618:                return targetCoverage;
619:            }
620:
621:            /**
622:             * Returns the math transform for the two specified dimensions of the specified transform.
623:             *
624:             * @param  transform The transform.
625:             * @param  mtFactory The factory to use for extracting the sub-transform.
626:             * @param  sourceGG  The grid geometry which is the source of the <strong>transform</strong>.
627:             *                   This is {@code targetGG} in the {@link #reproject} method, because the
628:             *                   later computes a transform from target to source grid geometry.
629:             * @return The {@link MathTransform2D} part of {@code transform}.
630:             * @throws FactoryException If {@code transform} is not separable.
631:             */
632:            private static MathTransform2D getMathTransform2D(
633:                    final MathTransform transform,
634:                    final MathTransformFactory mtFactory,
635:                    final GridGeometry2D sourceGG) throws FactoryException {
636:                final DimensionFilter filter = new DimensionFilter(mtFactory);
637:                filter.addSourceDimension(sourceGG.axisDimensionX);
638:                filter.addSourceDimension(sourceGG.axisDimensionY);
639:                MathTransform candidate = filter.separate(transform);
640:                if (candidate instanceof  MathTransform2D) {
641:                    return (MathTransform2D) candidate;
642:                }
643:                filter.addTargetDimension(sourceGG.axisDimensionX);
644:                filter.addTargetDimension(sourceGG.axisDimensionY);
645:                candidate = filter.separate(transform);
646:                if (candidate instanceof  MathTransform2D) {
647:                    return (MathTransform2D) candidate;
648:                }
649:                throw new FactoryException(Errors
650:                        .format(ErrorKeys.NO_TRANSFORM2D_AVAILABLE));
651:            }
652:
653:            /**
654:             * Checks if two geometries are equal, ignoring unspecified fields. If one or both
655:             * geometries has no "gridToCRS" transform, then this properties is not taken in account.
656:             * Same apply for the grid range.
657:             *
658:             * @param  range1 The first range.
659:             * @param  range2 The second range.
660:             * @return {@code true} if the two geometries are equal, ignoring unspecified fields.
661:             */
662:            private static boolean equivalent(final GridGeometry2D geom1,
663:                    final GridGeometry2D geom2) {
664:                if (geom1.equals(geom2)) {
665:                    return true;
666:                }
667:                if (geom1.isDefined(GridGeometry2D.GRID_RANGE)
668:                        && geom2.isDefined(GridGeometry2D.GRID_RANGE)) {
669:                    if (!geom1.getGridRange().equals(geom2.getGridRange())) {
670:                        return false;
671:                    }
672:                }
673:                if (geom1.isDefined(GridGeometry2D.GRID_TO_CRS)
674:                        && geom2.isDefined(GridGeometry2D.GRID_TO_CRS)) {
675:                    if (!geom1.getGridToCRS().equals(geom2.getGridToCRS())) {
676:                        return false;
677:                    }
678:                }
679:                return true;
680:            }
681:
682:            /**
683:             * Cast the specified grid range into an envelope. This is used before to transform
684:             * the envelope using {@link CTSUtilities#transform(MathTransform, Envelope)}.
685:             */
686:            private static Envelope toEnvelope(final GridRange gridRange) {
687:                final int dimension = gridRange.getDimension();
688:                final double[] lower = new double[dimension];
689:                final double[] upper = new double[dimension];
690:                for (int i = 0; i < dimension; i++) {
691:                    lower[i] = gridRange.getLower(i);
692:                    upper[i] = gridRange.getUpper(i);
693:                }
694:                return new GeneralEnvelope(lower, upper);
695:            }
696:
697:            /**
698:             * Log a message.
699:             */
700:            static void log(final LogRecord record) {
701:                record.setSourceClassName("Resample");
702:                record.setSourceMethodName("doOperation");
703:                AbstractProcessor.LOGGER.log(record);
704:            }
705:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.