Source Code Cross Referenced for GridCoverageRenderer.java in  » GIS » GeoTools-2.4.1 » org » geotools » renderer » lite » gridcoverage2d » 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.renderer.lite.gridcoverage2d 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *    GeoTools - OpenSource mapping toolkit
0003:         *    http://geotools.org
0004:         *    (C) 2004-2006, Geotools Project Managment Committee (PMC)
0005:         *
0006:         *    This library is free software; you can redistribute it and/or
0007:         *    modify it under the terms of the GNU Lesser General Public
0008:         *    License as published by the Free Software Foundation; either
0009:         *    version 2.1 of the License, or (at your option) any later version.
0010:         *
0011:         *    This library is distributed in the hope that it will be useful,
0012:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014:         *    Lesser General Public License for more details.
0015:         */
0016:        package org.geotools.renderer.lite.gridcoverage2d;
0017:
0018:        // J2SE dependencies
0019:        import java.awt.AlphaComposite;
0020:        import java.awt.Color;
0021:        import java.awt.Composite;
0022:        import java.awt.Graphics2D;
0023:        import java.awt.Rectangle;
0024:        import java.awt.RenderingHints;
0025:        import java.awt.geom.AffineTransform;
0026:        import java.awt.geom.NoninvertibleTransformException;
0027:        import java.awt.image.BufferedImage;
0028:        import java.awt.image.RenderedImage;
0029:        import java.awt.image.renderable.RenderableImage;
0030:        import java.io.File;
0031:        import java.io.IOException;
0032:        import java.util.HashMap;
0033:        import java.util.logging.Level;
0034:        import java.util.logging.Logger;
0035:
0036:        import javax.imageio.ImageIO;
0037:        import javax.media.jai.BorderExtender;
0038:        import javax.media.jai.Interpolation;
0039:        import javax.media.jai.InterpolationBilinear;
0040:        import javax.media.jai.InterpolationNearest;
0041:        import javax.media.jai.JAI;
0042:
0043:        import org.geotools.coverage.grid.GeneralGridRange;
0044:        import org.geotools.coverage.grid.GridCoverage2D;
0045:        import org.geotools.coverage.grid.GridGeometry2D;
0046:        import org.geotools.coverage.processing.DefaultProcessor;
0047:        import org.geotools.coverage.processing.operation.Crop;
0048:        import org.geotools.coverage.processing.operation.FilteredSubsample;
0049:        import org.geotools.coverage.processing.operation.Resample;
0050:        import org.geotools.coverage.processing.operation.Scale;
0051:        import org.geotools.factory.Hints;
0052:        import org.geotools.geometry.GeneralEnvelope;
0053:        import org.geotools.geometry.jts.ReferencedEnvelope;
0054:        import org.geotools.referencing.CRS;
0055:        import org.geotools.referencing.operation.builder.GridToEnvelopeMapper;
0056:        import org.geotools.referencing.operation.matrix.XAffineTransform;
0057:        import org.geotools.renderer.lite.StreamingRenderer;
0058:        import org.geotools.resources.CRSUtilities;
0059:        import org.geotools.resources.image.CoverageUtilities;
0060:        import org.geotools.resources.image.ImageUtilities;
0061:        import org.geotools.styling.RasterSymbolizer;
0062:        import org.geotools.styling.SLD;
0063:        import org.opengis.coverage.grid.GridCoverage;
0064:        import org.opengis.filter.expression.Literal;
0065:        import org.opengis.parameter.ParameterValueGroup;
0066:        import org.opengis.referencing.FactoryException;
0067:        import org.opengis.referencing.crs.CoordinateReferenceSystem;
0068:        import org.opengis.referencing.datum.PixelInCell;
0069:        import org.opengis.referencing.operation.MathTransform;
0070:        import org.opengis.referencing.operation.TransformException;
0071:
0072:        import com.vividsolutions.jts.geom.Envelope;
0073:
0074:        /**
0075:         * A helper class for rendering {@link GridCoverage} objects. Support for grid
0076:         * coverage SLD stylers is still limited.
0077:         * 
0078:         * @author Simone Giannecchini
0079:         * @author Andrea Aime
0080:         * @author Alessio Fabiani
0081:         * @source $URL:
0082:         *         http://svn.geotools.org/geotools/trunk/gt/module/render/src/org/geotools/renderer/lite/GridCoverageRenderer.java $
0083:         * @version $Id: GridCoverageRenderer.java 18352 2006-03-01 06:13:42Z
0084:         *          desruisseaux $
0085:         * 
0086:         * @task Add support for SLD styles
0087:         */
0088:        public final class GridCoverageRenderer {
0089:            /**
0090:             * This variable is use for testing purposes in order to force this
0091:             * {@link GridCoverageRenderer} to dump images at various steps on the disk.
0092:             */
0093:            private final static boolean DEBUG = Boolean
0094:                    .getBoolean("org.geotools.renderer.lite.gridcoverage2d.debug");
0095:
0096:            protected static final double EPS = 1E-6;
0097:
0098:            private static String debugDir;
0099:            static {
0100:                if (DEBUG) {
0101:                    final File tempDir = new File(System
0102:                            .getProperty("java.io.tmpdir"));
0103:                    if (!tempDir.exists() || !tempDir.canWrite()) {
0104:                        System.out
0105:                                .println("Unable to create debug dir, exiting application!!!");
0106:                        System.exit(1);
0107:                        debugDir = null;
0108:                    } else
0109:                        debugDir = tempDir.getAbsolutePath();
0110:                }
0111:
0112:            }
0113:
0114:            /** Cached factory for the {@link Scale} operation. */
0115:            private final static Scale scaleFactory = new Scale();
0116:
0117:            /** Cached factory for the {@link FilteredSubsample} operation. */
0118:            private final static FilteredSubsample filteredSubsampleFactory = new FilteredSubsample();
0119:
0120:            /** Cached factory for the {@link Crop} operation. */
0121:            private final static Crop coverageCropFactory = new Crop();
0122:
0123:            /** Logger. */
0124:            private static final Logger LOGGER = org.geotools.util.logging.Logging
0125:                    .getLogger("org.geotools.rendering");
0126:
0127:            static {
0128:
0129:                // ///////////////////////////////////////////////////////////////////
0130:                //
0131:                // Caching parameters for performing the various operations.
0132:                //	
0133:                // ///////////////////////////////////////////////////////////////////
0134:                final DefaultProcessor processor = new DefaultProcessor(
0135:                        CoverageUtilities.LENIENT_HINT);
0136:                resampleParams = processor.getOperation("Resample")
0137:                        .getParameters();
0138:                scaleParams = processor.getOperation("Scale").getParameters();
0139:                cropParams = processor.getOperation("CoverageCrop")
0140:                        .getParameters();
0141:                filteredSubsampleParams = processor.getOperation(
0142:                        "FilteredSubsample").getParameters();
0143:            }
0144:
0145:            /** The Display (User defined) CRS * */
0146:            private final CoordinateReferenceSystem destinationCRS;
0147:
0148:            /** Area we want to draw. */
0149:            private final GeneralEnvelope destinationEnvelope;
0150:
0151:            /** Size of the area we want to draw in pixels. */
0152:            private final Rectangle destinationSize;
0153:
0154:            private final GridToEnvelopeMapper gridToEnvelopeMapper;
0155:
0156:            private final AffineTransform finalGridToWorld;
0157:
0158:            private final AffineTransform finalWorldToGrid;
0159:
0160:            private final Hints hints = new Hints(new HashMap(5));
0161:
0162:            /** Parameters used to control the {@link Resample} operation. */
0163:            private final static ParameterValueGroup resampleParams;
0164:
0165:            /** Parameters used to control the {@link Scale} operation. */
0166:            private final static ParameterValueGroup scaleParams;
0167:
0168:            /** Parameters used to control the {@link Crop} operation. */
0169:            private static ParameterValueGroup cropParams;
0170:
0171:            /** Parameters used to control the {@link FilteredSubsample} operation. */
0172:            private final static ParameterValueGroup filteredSubsampleParams;
0173:
0174:            /** Parameters used to control the {@link Scale} operation. */
0175:            private static final Resample resampleFactory = new Resample();
0176:
0177:            /**
0178:             * Tolerance for NOT drawing a coverage.
0179:             * 
0180:             * If after a scaling a coverage has all dimensions smaller than
0181:             * {@link GridCoverageRenderer#MIN_DIM_TOLERANCE} we just do not draw it.
0182:             */
0183:            private static final int MIN_DIM_TOLERANCE = 2;
0184:
0185:            /**
0186:             * Creates a new {@link GridCoverageRenderer} object.
0187:             * 
0188:             * @param destinationCRS
0189:             *            the CRS of the {@link GridCoverage2D} to render.
0190:             * @param envelope
0191:             *            delineating the area to be rendered.
0192:             * @param screenSize
0193:             *            at which we want to rendere the source {@link GridCoverage2D}.
0194:             * @throws TransformException
0195:             * @throws NoninvertibleTransformException
0196:             * 
0197:             */
0198:            public GridCoverageRenderer(
0199:                    final CoordinateReferenceSystem destinationCRS,
0200:                    final Envelope envelope, Rectangle screenSize)
0201:                    throws TransformException, NoninvertibleTransformException {
0202:
0203:                this (destinationCRS, envelope, screenSize, null);
0204:
0205:            }
0206:
0207:            /**
0208:             * Creates a new {@link GridCoverageRenderer} object.
0209:             * 
0210:             * @param destinationCRS
0211:             *            the CRS of the {@link GridCoverage2D} to render.
0212:             * @param envelope
0213:             *            delineating the area to be rendered.
0214:             * @param screenSize
0215:             *            at which we want to rendere the source {@link GridCoverage2D}.
0216:             * @param java2dHints
0217:             *            to control this rendering process.
0218:             * 
0219:             * @throws TransformException
0220:             * @throws NoninvertibleTransformException
0221:             */
0222:            public GridCoverageRenderer(
0223:                    final CoordinateReferenceSystem destinationCRS,
0224:                    final Envelope envelope, Rectangle screenSize,
0225:                    RenderingHints java2dHints) throws TransformException,
0226:                    NoninvertibleTransformException {
0227:
0228:                // ///////////////////////////////////////////////////////////////////
0229:                //
0230:                // Initialize this renderer
0231:                //
0232:                // ///////////////////////////////////////////////////////////////////
0233:                this .destinationSize = screenSize;
0234:                this .destinationCRS = CRSUtilities.getCRS2D(destinationCRS);
0235:                gridToEnvelopeMapper = new GridToEnvelopeMapper();
0236:                gridToEnvelopeMapper.setGridType(PixelInCell.CELL_CORNER);
0237:                gridToEnvelopeMapper.setGridRange(new GeneralGridRange(
0238:                        destinationSize));
0239:                destinationEnvelope = new GeneralEnvelope(
0240:                        new ReferencedEnvelope(envelope, destinationCRS));
0241:                // ///////////////////////////////////////////////////////////////////
0242:                //
0243:                // FINAL DRAWING DIMENSIONS AND RESOLUTION
0244:                // I am here getting the final drawing dimensions (on the device) and
0245:                // the resolution for this rendererbut in the CRS of the source coverage
0246:                // since I am going to compare this info with the same info for the
0247:                // source coverage.
0248:                //
0249:                // ///////////////////////////////////////////////////////////////////
0250:                gridToEnvelopeMapper.setEnvelope(destinationEnvelope);
0251:                finalGridToWorld = new AffineTransform(gridToEnvelopeMapper
0252:                        .createAffineTransform());
0253:                finalWorldToGrid = finalGridToWorld.createInverse();
0254:
0255:                // ///////////////////////////////////////////////////////////////////
0256:                //
0257:                // HINTS
0258:                //
0259:                // ///////////////////////////////////////////////////////////////////
0260:                if (java2dHints != null)
0261:                    this .hints.add(java2dHints);
0262:                // this prevents users from overriding leninet hint
0263:                this .hints.add(CoverageUtilities.LENIENT_HINT);
0264:                this .hints.add(ImageUtilities.DONT_REPLACE_INDEX_COLOR_MODEL);
0265:
0266:            }
0267:
0268:            /**
0269:             * Paint this grid coverage. The caller must ensure that
0270:             * <code>graphics</code> has an affine transform mapping "real world"
0271:             * coordinates in the coordinate system given by {@link
0272:             * #getCoordinateSystem}.
0273:             * 
0274:             * @param graphics
0275:             *            the {@link Graphics2D} context in which to paint.
0276:             * @param metaBufferedEnvelope 
0277:             * @throws FactoryException
0278:             * @throws TransformException
0279:             * @throws NoninvertibleTransformException
0280:             * @throws Exception
0281:             * @throws UnsupportedOperationException
0282:             *             if the transformation from grid to coordinate system in the
0283:             *             GridCoverage is not an AffineTransform
0284:             */
0285:            public void paint(final Graphics2D graphics,
0286:                    final GridCoverage2D gridCoverage,
0287:                    final RasterSymbolizer symbolizer) throws FactoryException,
0288:                    TransformException, NoninvertibleTransformException {
0289:                //		METABUFFER SUPPORT	
0290:                //		public void paint(final Graphics2D graphics,
0291:                //		final GridCoverage2D gridCoverage, final RasterSymbolizer symbolizer,
0292:                //		GeneralEnvelope metaBufferedEnvelope)
0293:                //		throws FactoryException, TransformException,
0294:                //		NoninvertibleTransformException {
0295:
0296:                // ///////////////////////////////////////////////////////////////////
0297:                //
0298:                // Getting information about the source coverage like the source CRS,
0299:                // the source envelope and the source geometry.
0300:                //
0301:                // ///////////////////////////////////////////////////////////////////
0302:                if (LOGGER.isLoggable(Level.FINE))
0303:                    LOGGER.fine(new StringBuffer("Drawing coverage ").append(
0304:                            gridCoverage.toString()).toString());
0305:                final CoordinateReferenceSystem sourceCoverageCRS = gridCoverage
0306:                        .getCoordinateReferenceSystem2D();
0307:                final GridGeometry2D sourceCoverageGG = (GridGeometry2D) gridCoverage
0308:                        .getGridGeometry();
0309:                final GeneralGridRange sourceRange = (GeneralGridRange) sourceCoverageGG
0310:                        .getGridRange();
0311:                final GeneralEnvelope sourceCoverageEnvelope = (GeneralEnvelope) gridCoverage
0312:                        .getEnvelope();
0313:
0314:                // ///////////////////////////////////////////////////////////////////
0315:                //
0316:                // GET THE CRS MAPPING
0317:                //
0318:                // This step I instantiate the MathTransform for going from the source
0319:                // crs to the desination crs.
0320:                //
0321:                // ///////////////////////////////////////////////////////////////////
0322:                // math transform from source to target crs
0323:                final MathTransform sourceCRSToDestinationCRSTransformation = StreamingRenderer
0324:                        .getMathTransform(sourceCoverageCRS, destinationCRS);
0325:                final MathTransform destinationCRSToSourceCRSTransformation = sourceCRSToDestinationCRSTransformation
0326:                        .inverse();
0327:                final boolean doReprojection = !sourceCRSToDestinationCRSTransformation
0328:                        .isIdentity();
0329:                if (LOGGER.isLoggable(Level.FINE))
0330:                    LOGGER.fine(new StringBuffer(
0331:                            "Transforming coverage envelope with transform ")
0332:                            .append(
0333:                                    destinationCRSToSourceCRSTransformation
0334:                                            .toWKT()).toString());
0335:
0336:                // //
0337:                //
0338:                // Do we need reprojection?
0339:                //
0340:                // //
0341:                GeneralEnvelope croppedDestinationEnvelope = null;
0342:                if (doReprojection) {
0343:                    // //
0344:                    //
0345:                    // Let's crop the destination envelope with respect to the source
0346:                    // coverage envelope in order to do resampling if needed.
0347:                    //
0348:                    // //
0349:                    // create a new envelope
0350:                    croppedDestinationEnvelope = new GeneralEnvelope(
0351:                            destinationEnvelope);
0352:                    croppedDestinationEnvelope
0353:                            .setCoordinateReferenceSystem(destinationCRS);
0354:
0355:                    //
0356:                    // transform the source coverage envelope to the destination
0357:                    // coordinate reference system for cropping the destination envelope
0358:                    final GeneralEnvelope transformedSourceCoverageEnvelope = CRS
0359:                            .transform(sourceCRSToDestinationCRSTransformation,
0360:                                    sourceCoverageEnvelope);
0361:                    transformedSourceCoverageEnvelope
0362:                            .setCoordinateReferenceSystem(destinationCRS);
0363:                    croppedDestinationEnvelope
0364:                            .intersect(transformedSourceCoverageEnvelope);
0365:
0366:                }
0367:
0368:                final Interpolation interpolation = (Interpolation) hints
0369:                        .get(JAI.KEY_INTERPOLATION);
0370:                if (LOGGER.isLoggable(Level.FINE))
0371:                    LOGGER.fine(new StringBuffer("Using interpolation ")
0372:                            .append(interpolation).toString());
0373:
0374:                final GridCoverage2D preSymbolizer;
0375:                if (!isScaleTranslate(gridCoverage.getGridGeometry()
0376:                        .getGridToCRS())) {
0377:                    /////////////////////////////////////////////////////////////////////
0378:                    //
0379:                    // REPROJECT to the requested crs.
0380:                    //
0381:                    //
0382:                    // ///////////////////////////////////////////////////////////////////
0383:                    if (doReprojection) {
0384:                        preSymbolizer = resample(
0385:                                gridCoverage,
0386:                                destinationCRS,
0387:                                interpolation == null ? new InterpolationBilinear()
0388:                                        : interpolation,
0389:                                croppedDestinationEnvelope);
0390:                        if (LOGGER.isLoggable(Level.FINE))
0391:                            LOGGER
0392:                                    .fine(new StringBuffer(
0393:                                            "Reprojecting to crs ").append(
0394:                                            destinationCRS.toWKT()).toString());
0395:                        if (DEBUG) {
0396:                            try {
0397:                                ImageIO.write(preSymbolizer.geophysics(false)
0398:                                        .getRenderedImage(), "tiff", new File(
0399:                                        debugDir, "reprojected.tiff"));
0400:                            } catch (IOException e) {
0401:
0402:                                e.printStackTrace();
0403:                            }
0404:                        }
0405:                    } else
0406:                        preSymbolizer = gridCoverage;
0407:
0408:                } else {
0409:                    // /////////////////////////////////////////////////////////////////
0410:                    //
0411:                    // CROP
0412:                    // This step I aim to crop the area of the coverage we want to serve.
0413:                    // I know that drawRenderedImage takes already into account tiling but
0414:                    // there is reprojection in between and I do not want end up
0415:                    // reprojecting 2 Giga of image for using 1 Kb.
0416:                    //
0417:                    // First I need to convert the source envelope into the destination crs.
0418:                    //
0419:                    // /////////////////////////////////////////////////////////////////
0420:                    // //
0421:                    //
0422:                    // This is the destination envelope in the coverage crs which is going
0423:                    // to be used for getting the crop area to crop the source coverage
0424:                    //
0425:                    // //
0426:                    final GeneralEnvelope destinationEnvelopeInSourceGCCRS = doReprojection ? CRS
0427:                            .transform(destinationCRSToSourceCRSTransformation,
0428:                                    destinationEnvelope)
0429:                            : new GeneralEnvelope(destinationEnvelope);
0430:                    destinationEnvelopeInSourceGCCRS
0431:                            .setCoordinateReferenceSystem(sourceCoverageCRS);
0432:                    final GridCoverage2D croppedGridCoverage = getCroppedCoverage(
0433:                            gridCoverage, destinationEnvelopeInSourceGCCRS,
0434:                            sourceCoverageCRS);
0435:                    if (croppedGridCoverage == null) {
0436:                        // nothing to render, the AOI does not overlap
0437:                        if (LOGGER.isLoggable(Level.FINE))
0438:                            LOGGER
0439:                                    .fine(new StringBuffer(
0440:                                            "Skipping current coverage because cropped to an empty area")
0441:                                            .toString());
0442:                        return;
0443:                    }
0444:                    if (DEBUG) {
0445:                        try {
0446:                            ImageIO.write(croppedGridCoverage.geophysics(false)
0447:                                    .getRenderedImage(), "tiff", new File(
0448:                                    debugDir, "cropped.tiff"));
0449:                        } catch (IOException e1) {
0450:                            // TODO Auto-generated catch block
0451:                            e1.printStackTrace();
0452:                        }
0453:                    }
0454:
0455:                    // ///////////////////////////////////////////////////////////////////
0456:                    //
0457:                    // DRAWING DIMENSIONS AND RESOLUTION
0458:                    // I am here getting the final drawing dimensions (on the device) and
0459:                    // the resolution for this renderer but in the CRS of the source
0460:                    // coverage
0461:                    // since I am going to compare this info with the same info for the
0462:                    // source coverage. The objective is to come up with the needed scale
0463:                    // factors for the original coverage in order to decide how to proceed.
0464:                    // Options are first scale then reproject or the opposite.
0465:                    //
0466:                    // In case we need to upsample the coverage first we reproject and then
0467:                    // we upsample otherwise we do the opposite in order
0468:                    //
0469:                    // ///////////////////////////////////////////////////////////////////
0470:                    AffineTransform finalGridToWorldInGCCRS;
0471:                    if (!sourceCRSToDestinationCRSTransformation.isIdentity()) {
0472:                        assert new GeneralGridRange(destinationSize)
0473:                                .equals(gridToEnvelopeMapper.getGridRange());
0474:                        gridToEnvelopeMapper
0475:                                .setEnvelope(destinationEnvelopeInSourceGCCRS);
0476:                        finalGridToWorldInGCCRS = new AffineTransform(
0477:                                gridToEnvelopeMapper.createAffineTransform());
0478:                    } else {
0479:                        finalGridToWorldInGCCRS = new AffineTransform(
0480:                                finalGridToWorld);
0481:                    }
0482:
0483:                    // ///////////////////////////////////////////////////////////////////
0484:                    //
0485:                    // SCALE and REPROJECT in the best order.
0486:                    // Let me now scale down or up to the EXACT needed SPATIAL resolution.
0487:                    // This step does not prevent from having loaded an overview of the
0488:                    // original image based on the requested scale but it complements it.
0489:                    //
0490:                    // ///////////////////////////////////////////////////////////////////
0491:                    // //
0492:                    //
0493:                    // First step is computing the needed resolution levels for this
0494:                    // coverage in its original crs to see the scale factors.
0495:                    //
0496:                    // //
0497:                    final AffineTransform croppedCoverageGridToWorldTransformations = (AffineTransform) ((GridGeometry2D) croppedGridCoverage
0498:                            .getGridGeometry()).getGridToCRS2D();
0499:                    final boolean sourceGCHasLonFirst = (XAffineTransform
0500:                            .getSwapXY(croppedCoverageGridToWorldTransformations) != -1);
0501:                    final boolean destinationHasLonFirst = (XAffineTransform
0502:                            .getSwapXY(finalGridToWorldInGCCRS) != -1);
0503:                    final double actualScaleX = sourceGCHasLonFirst ? croppedCoverageGridToWorldTransformations
0504:                            .getScaleX()
0505:                            : croppedCoverageGridToWorldTransformations
0506:                                    .getShearY();
0507:                    final double actualScaleY = sourceGCHasLonFirst ? croppedCoverageGridToWorldTransformations
0508:                            .getScaleY()
0509:                            : croppedCoverageGridToWorldTransformations
0510:                                    .getShearX();
0511:                    final double scaleX = actualScaleX
0512:                            / (destinationHasLonFirst ? finalGridToWorldInGCCRS
0513:                                    .getScaleX() : finalGridToWorldInGCCRS
0514:                                    .getShearY());
0515:                    final double scaleY = actualScaleY
0516:                            / (destinationHasLonFirst ? finalGridToWorldInGCCRS
0517:                                    .getScaleY() : finalGridToWorldInGCCRS
0518:                                    .getShearX());
0519:                    if (LOGGER.isLoggable(Level.FINE))
0520:                        LOGGER.fine(new StringBuffer("Scale factors are ")
0521:                                .append(scaleX).append(" ").append(scaleY)
0522:                                .toString());
0523:                    final int actualW = sourceRange.getLength(0);
0524:                    final int actualH = sourceRange.getLength(1);
0525:                    if (Math.round(actualW * scaleX) < MIN_DIM_TOLERANCE
0526:                            && Math.round(actualH * scaleY) < MIN_DIM_TOLERANCE) {
0527:                        if (LOGGER.isLoggable(Level.FINE))
0528:                            LOGGER
0529:                                    .fine(new StringBuffer(
0530:                                            "Skipping the actual coverage because one of the final dimension is null")
0531:                                            .toString());
0532:                        return;
0533:                    }
0534:
0535:                    // //
0536:                    //
0537:                    // Now if we are upsampling first reproject then scale else first scale
0538:                    // then reproject.
0539:                    //
0540:                    // //
0541:                    if (scaleX * scaleY <= 1.0) {
0542:                        int scaleXInt = (int) Math.floor(1 / scaleX);
0543:                        scaleXInt = scaleXInt == 0 ? 1 : scaleXInt;
0544:                        int scaleYInt = (int) Math.floor(1 / scaleY);
0545:                        scaleYInt = scaleYInt == 0 ? 1 : scaleYInt;
0546:
0547:                        // ///////////////////////////////////////////////////////////////////
0548:                        //
0549:                        // SCALE DOWN to the needed resolution
0550:                        //
0551:                        // ///////////////////////////////////////////////////////////////////
0552:                        // //
0553:                        //
0554:                        // first step for down sampling is filtered subsample which is fast.
0555:                        // 
0556:                        // //
0557:                        if (LOGGER.isLoggable(Level.FINE))
0558:                            LOGGER.fine(new StringBuffer(
0559:                                    "Filtered subsample with factors ").append(
0560:                                    scaleXInt).append(scaleYInt).toString());
0561:                        final GridCoverage2D preScaledGridCoverage = filteredSubsample(
0562:                                croppedGridCoverage,
0563:                                scaleXInt,
0564:                                scaleYInt,
0565:                                new InterpolationNearest(),
0566:                                BorderExtender
0567:                                        .createInstance(BorderExtender.BORDER_COPY));
0568:                        if (DEBUG) {
0569:                            try {
0570:                                ImageIO.write(preScaledGridCoverage.geophysics(
0571:                                        false).getRenderedImage(), "tiff",
0572:                                        new File(debugDir, "prescaled.tiff"));
0573:                            } catch (IOException e) {
0574:                                // TODO Auto-generated catch block
0575:                                e.printStackTrace();
0576:                            }
0577:                        }
0578:                        // //
0579:                        //
0580:                        // Second step is scale
0581:                        //
0582:                        // //
0583:                        if (LOGGER.isLoggable(Level.FINE))
0584:                            LOGGER.fine(new StringBuffer(
0585:                                    "Scale down with factors ").append(
0586:                                    scaleX * scaleXInt).append(
0587:                                    scaleY * scaleYInt).toString());
0588:                        final GridCoverage2D scaledGridCoverage;
0589:                        if (scaleX * scaleXInt == 1.0
0590:                                && scaleY * scaleYInt == 1.0)
0591:                            scaledGridCoverage = preScaledGridCoverage;
0592:                        else
0593:                            scaledGridCoverage = scale(
0594:                                    scaleX * scaleXInt,
0595:                                    scaleY * scaleYInt,
0596:                                    0f,
0597:                                    0f,
0598:                                    interpolation == null ? new InterpolationBilinear()
0599:                                            : interpolation,
0600:                                    BorderExtender
0601:                                            .createInstance(BorderExtender.BORDER_COPY),
0602:                                    preScaledGridCoverage);
0603:
0604:                        if (DEBUG) {
0605:                            try {
0606:                                ImageIO.write(scaledGridCoverage.geophysics(
0607:                                        false).getRenderedImage(), "tiff",
0608:                                        new File(debugDir, "scaled.tiff"));
0609:                            } catch (IOException e) {
0610:
0611:                                e.printStackTrace();
0612:                            }
0613:                        }
0614:
0615:                        // ///////////////////////////////////////////////////////////////////
0616:                        //
0617:                        // REPROJECT to the requested crs.
0618:                        //
0619:                        //
0620:                        // ///////////////////////////////////////////////////////////////////
0621:                        if (doReprojection) {
0622:                            preSymbolizer = resample(
0623:                                    scaledGridCoverage,
0624:                                    destinationCRS,
0625:                                    interpolation == null ? new InterpolationBilinear()
0626:                                            : interpolation,
0627:                                    croppedDestinationEnvelope);
0628:                            if (LOGGER.isLoggable(Level.FINE))
0629:                                LOGGER.fine(new StringBuffer(
0630:                                        "Reprojecting to crs ").append(
0631:                                        destinationCRS.toWKT()).toString());
0632:                            if (DEBUG) {
0633:                                try {
0634:                                    ImageIO.write(preSymbolizer.geophysics(
0635:                                            false).getRenderedImage(), "tiff",
0636:                                            new File(debugDir,
0637:                                                    "reprojected.tiff"));
0638:                                } catch (IOException e) {
0639:
0640:                                    e.printStackTrace();
0641:                                }
0642:                            }
0643:                        } else
0644:                            preSymbolizer = scaledGridCoverage;
0645:
0646:                    } else {
0647:
0648:                        // ///////////////////////////////////////////////////////////////////
0649:                        //
0650:                        // REPROJECT to the requested crs
0651:                        //
0652:                        //
0653:                        // ///////////////////////////////////////////////////////////////////
0654:                        final GridCoverage2D reprojectedCoverage;
0655:                        if (doReprojection) {
0656:                            reprojectedCoverage = resample(
0657:                                    croppedGridCoverage,
0658:                                    destinationCRS,
0659:                                    interpolation == null ? new InterpolationBilinear()
0660:                                            : interpolation,
0661:                                    croppedDestinationEnvelope);
0662:                            if (LOGGER.isLoggable(Level.FINE))
0663:                                LOGGER.fine(new StringBuffer(
0664:                                        "Reprojecting to crs ").append(
0665:                                        destinationCRS.toWKT()).toString());
0666:                        } else
0667:                            reprojectedCoverage = croppedGridCoverage;
0668:
0669:                        if (DEBUG) {
0670:                            try {
0671:                                ImageIO.write(reprojectedCoverage.geophysics(
0672:                                        false).getRenderedImage(), "tiff",
0673:                                        new File("c:/reprojected.tiff"));
0674:                            } catch (IOException e) {
0675:
0676:                                e.printStackTrace();
0677:                            }
0678:                        }
0679:                        // ///////////////////////////////////////////////////////////////////
0680:                        //
0681:                        // SCALE UP to the needed resolution
0682:                        //
0683:                        // ///////////////////////////////////////////////////////////////////
0684:                        if (LOGGER.isLoggable(Level.FINE))
0685:                            LOGGER.fine(new StringBuffer(
0686:                                    "Scale up with factors ").append(scaleX)
0687:                                    .append(scaleY).toString());
0688:                        preSymbolizer = (GridCoverage2D) scale(
0689:                                scaleX,
0690:                                scaleY,
0691:                                0f,
0692:                                0f,
0693:                                interpolation == null ? new InterpolationBilinear()
0694:                                        : interpolation,
0695:                                BorderExtender
0696:                                        .createInstance(BorderExtender.BORDER_COPY),
0697:                                reprojectedCoverage);
0698:                        if (DEBUG) {
0699:                            try {
0700:                                ImageIO.write(preSymbolizer.geophysics(false)
0701:                                        .getRenderedImage(), "tiff", new File(
0702:                                        debugDir, "scaleup.tiff"));
0703:                            } catch (IOException e) {
0704:
0705:                                e.printStackTrace();
0706:                            }
0707:                        }
0708:
0709:                    }
0710:                }
0711:
0712:                if (DEBUG) {
0713:
0714:                    try {
0715:                        ImageIO.write(preSymbolizer.geophysics(false)
0716:                                .getRenderedImage(), "tiff", new File(debugDir,
0717:                                "preSymbolizer.tiff"));
0718:                    } catch (IOException e) {
0719:                        // TODO Auto-generated catch block
0720:                        e.printStackTrace();
0721:                    }
0722:                }
0723:
0724:                // ///////////////////////////////////////////////////////////////////
0725:                //
0726:                // RECOLOR
0727:                //
0728:                //
0729:                // ///////////////////////////////////////////////////////////////////
0730:                if (LOGGER.isLoggable(Level.FINE))
0731:                    LOGGER.fine(new StringBuffer("Raster Symbolizer ")
0732:                            .toString());
0733:                final RasterSymbolizerSupport rsp = new RasterSymbolizerSupport(
0734:                        symbolizer);
0735:                final GridCoverage2D recoloredGridCoverage = (GridCoverage2D) rsp
0736:                        .recolorCoverage(preSymbolizer);
0737:                final RenderedImage finalImage = recoloredGridCoverage
0738:                        .geophysics(false).getRenderedImage();
0739:
0740:                // ///////////////////////////////////////////////////////////////////
0741:                //
0742:                // DRAW ME
0743:                // I need the grid to world transform for drawing this grid coverage to
0744:                // the display
0745:                //
0746:                // ///////////////////////////////////////////////////////////////////
0747:                final AffineTransform finalGCgridToWorld = new AffineTransform(
0748:                        (AffineTransform) ((GridGeometry2D) recoloredGridCoverage
0749:                                .getGridGeometry()).getGridToCRS2D());
0750:                if (!(finalGCgridToWorld instanceof  AffineTransform)) {
0751:                    throw new UnsupportedOperationException(
0752:                            "Non-affine transformations not yet implemented"); // TODO
0753:                }
0754:
0755:                // //
0756:                //
0757:                // I need to translate half of a pixel since in wms 1.1.1 the envelope
0758:                // map to the corners of the raster space not to the center of the
0759:                // pixels.
0760:                //
0761:                // //
0762:                finalGCgridToWorld.translate(-0.5, -0.5); // Map to upper-left corner.
0763:
0764:                // //
0765:                //
0766:                // I am going to concatenate the final world to grid transform for the
0767:                // screen area with the grid to world transform of the input coverage.
0768:                //
0769:                // This way i right away position the coverage at the right place in the
0770:                // area of interest for the device.
0771:                //
0772:                // //
0773:                final AffineTransform clonedFinalWorldToGrid = (AffineTransform) finalWorldToGrid
0774:                        .clone();
0775:                clonedFinalWorldToGrid.concatenate(finalGCgridToWorld);
0776:                if (LOGGER.isLoggable(Level.FINE))
0777:                    LOGGER.fine(new StringBuffer("clonedFinalWorldToGrid ")
0778:                            .append(clonedFinalWorldToGrid.toString())
0779:                            .toString());
0780:
0781:                // it should be a simple translation TODO check
0782:                final RenderingHints oldHints = graphics.getRenderingHints();
0783:                graphics.setRenderingHints(this .hints);
0784:
0785:                // //
0786:                // Opacity
0787:                // //
0788:                final float alpha = rsp.getOpacity();
0789:                final Composite oldAlphaComposite = graphics.getComposite();
0790:                graphics.setComposite(AlphaComposite.getInstance(
0791:                        AlphaComposite.SRC_OVER, alpha));
0792:                try {
0793:                    // //
0794:                    // Drawing the Image
0795:                    // //
0796:                    graphics.drawRenderedImage(finalImage,
0797:                            clonedFinalWorldToGrid);
0798:                } catch (Throwable t) {
0799:                    try {
0800:                        if (DEBUG) {
0801:                            try {
0802:                                ImageIO.write(finalImage, "tiff", new File(
0803:                                        debugDir, "final0.tiff"));
0804:                            } catch (IOException e) {
0805:
0806:                                e.printStackTrace();
0807:                            }
0808:                        }
0809:                        // /////////////////////////////////////////////////////////////
0810:                        // this is a workaround for a bug in Java2D
0811:                        // (see bug 4723021
0812:                        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4723021).
0813:                        //
0814:                        // AffineTransformOp.filter throws a
0815:                        // java.awt.image.ImagingOpException: Unable to tranform src
0816:                        // image when a PixelInterleavedSampleModel is used.
0817:                        //
0818:                        // CUSTOMER WORKAROUND :
0819:                        // draw the BufferedImage into a buffered image of type ARGB
0820:                        // then perform the affine transform. THIS OPERATION WASTES
0821:                        // RESOURCES BY PERFORMING AN ALLOCATION OF MEMORY AND A COPY ON
0822:                        // LARGE IMAGES.
0823:                        // /////////////////////////////////////////////////////////////
0824:                        final BufferedImage buf = new BufferedImage(
0825:                                (int) finalImage.getWidth(), (int) finalImage
0826:                                        .getHeight(),
0827:                                BufferedImage.TYPE_4BYTE_ABGR);
0828:                        final Graphics2D g = (Graphics2D) buf.getGraphics();
0829:                        g.drawRenderedImage(finalImage, AffineTransform
0830:                                .getScaleInstance(1, 1));
0831:                        g.dispose();
0832:                        if (DEBUG) {
0833:                            try {
0834:                                ImageIO.write(buf, "tiff", new File(debugDir,
0835:                                        "final1.tiff"));
0836:                            } catch (IOException e1) {
0837:
0838:                            }
0839:                        }
0840:
0841:                        graphics.drawImage(buf, clonedFinalWorldToGrid, null);
0842:                        buf.flush();
0843:
0844:                    } catch (Throwable t1) {
0845:                        // if fthe workaround fails again, there is really nothing to do
0846:                        // :-(
0847:                        LOGGER.log(Level.WARNING, t1.getLocalizedMessage(), t1);
0848:                    }
0849:                }
0850:
0851:                // ///////////////////////////////////////////////////////////////////
0852:                //
0853:                // Restore old elements
0854:                //
0855:                // ///////////////////////////////////////////////////////////////////
0856:                graphics.setComposite(oldAlphaComposite);
0857:                graphics.setRenderingHints(oldHints);
0858:
0859:            }
0860:
0861:            /**
0862:             * Scaling the input coverage using the provided parameters.
0863:             * 
0864:             * @param scaleX
0865:             * @param scaleY
0866:             * @param xTrans
0867:             * @param yTrans
0868:             * @param interpolation
0869:             * @param be
0870:             * @param gc
0871:             * @return
0872:             */
0873:            private GridCoverage2D scale(final double scaleX,
0874:                    final double scaleY, float xTrans, float yTrans,
0875:                    final Interpolation interpolation, final BorderExtender be,
0876:                    final GridCoverage2D gc) {
0877:
0878:                final ParameterValueGroup param = (ParameterValueGroup) scaleParams
0879:                        .clone();
0880:                param.parameter("source").setValue(gc);
0881:                param.parameter("xScale").setValue(new Float(scaleX));
0882:                param.parameter("yScale").setValue(new Float(scaleY));
0883:                param.parameter("xTrans").setValue(new Float(xTrans));
0884:                param.parameter("yTrans").setValue(new Float(yTrans));
0885:                param.parameter("Interpolation").setValue(interpolation);
0886:                param.parameter("BorderExtender").setValue(be);
0887:                return (GridCoverage2D) scaleFactory.doOperation(param, hints);
0888:
0889:            }
0890:
0891:            /**
0892:             * Reprojecting the input coverage using the provided parameters.
0893:             * 
0894:             * @param gc
0895:             * @param crs
0896:             * @param interpolation
0897:             * @return
0898:             */
0899:            private GridCoverage2D resample(final GridCoverage2D gc,
0900:                    CoordinateReferenceSystem crs,
0901:                    final Interpolation interpolation,
0902:                    final GeneralEnvelope destinationEnvelope) {
0903:                // paranoiac check
0904:                assert CRS.equalsIgnoreMetadata(destinationEnvelope
0905:                        .getCoordinateReferenceSystem(), crs);
0906:
0907:                final ParameterValueGroup param = (ParameterValueGroup) resampleParams
0908:                        .clone();
0909:                param.parameter("source").setValue(gc);
0910:                param.parameter("CoordinateReferenceSystem").setValue(crs);
0911:                param.parameter("GridGeometry").setValue(
0912:                        new GridGeometry2D(gc.getGridGeometry().getGridRange(),
0913:                                destinationEnvelope));
0914:                param.parameter("InterpolationType").setValue(interpolation);
0915:                return (GridCoverage2D) resampleFactory.doOperation(param,
0916:                        hints);
0917:
0918:            }
0919:
0920:            /**
0921:             * Subsampling the provided {@link GridCoverage2D} with the provided
0922:             * parameters.
0923:             * 
0924:             * @param gc
0925:             * @param scaleXInt
0926:             * @param scaleYInt
0927:             * @param interpolation
0928:             * @param be
0929:             * @return
0930:             */
0931:            private GridCoverage2D filteredSubsample(final GridCoverage2D gc,
0932:                    int scaleXInt, int scaleYInt,
0933:                    final Interpolation interpolation, final BorderExtender be) {
0934:                final GridCoverage2D preScaledGridCoverage;
0935:                if (scaleXInt == 1 && scaleYInt == 1)
0936:                    preScaledGridCoverage = gc;
0937:                else {
0938:
0939:                    final ParameterValueGroup param = (ParameterValueGroup) filteredSubsampleParams
0940:                            .clone();
0941:                    param.parameter("source").setValue(gc);
0942:                    param.parameter("scaleX").setValue(new Integer(scaleXInt));
0943:                    param.parameter("scaleY").setValue(new Integer(scaleYInt));
0944:                    if (hints.get(JAI.KEY_INTERPOLATION) != null
0945:                            && hints.get(JAI.KEY_INTERPOLATION).equals(
0946:                                    new InterpolationNearest()))
0947:                        param.parameter("qsFilterArray").setValue(
0948:                                new float[] { 1.0F });
0949:                    else
0950:                        param.parameter("qsFilterArray").setValue(
0951:                                new float[] { 0.5F, 1.0F / 3.0F, 0.0F,
0952:                                        -1.0F / 12.0F });
0953:                    param.parameter("Interpolation").setValue(interpolation);
0954:                    if (!(interpolation instanceof  InterpolationNearest))
0955:                        param.parameter("BorderExtender").setValue(be);
0956:                    preScaledGridCoverage = (GridCoverage2D) filteredSubsampleFactory
0957:                            .doOperation(param, hints);
0958:
0959:                }
0960:                return preScaledGridCoverage;
0961:            }
0962:
0963:            /**
0964:             * Cropping the provided coverage to the requested geographic area.
0965:             * 
0966:             * @param gc
0967:             * @param envelope
0968:             * @param crs
0969:             * @return
0970:             */
0971:            private GridCoverage2D getCroppedCoverage(GridCoverage2D gc,
0972:                    GeneralEnvelope envelope, CoordinateReferenceSystem crs) {
0973:                final GeneralEnvelope oldEnvelope = (GeneralEnvelope) gc
0974:                        .getEnvelope();
0975:                // intersect the envelopes in order to prepare for crooping the coverage
0976:                // down to the neded resolution
0977:                final GeneralEnvelope intersectionEnvelope = new GeneralEnvelope(
0978:                        envelope);
0979:                intersectionEnvelope.setCoordinateReferenceSystem(crs);
0980:                intersectionEnvelope.intersect((GeneralEnvelope) oldEnvelope);
0981:
0982:                // Do we have something to show? After the crop I could get a null
0983:                // coverage which would mean nothing to show.
0984:                if (intersectionEnvelope.isEmpty())
0985:                    return null;
0986:
0987:                // crop
0988:                final ParameterValueGroup param = (ParameterValueGroup) cropParams
0989:                        .clone();
0990:                param.parameter("source").setValue(gc);
0991:                param.parameter("ConserveEnvelope").setValue(Boolean.TRUE);
0992:                param.parameter("Envelope").setValue(intersectionEnvelope);
0993:                return (GridCoverage2D) coverageCropFactory.doOperation(param,
0994:                        hints);
0995:
0996:            }
0997:
0998:            /**
0999:             * Checks the transformation is a pure scale/translate instance (using a tolerance)
1000:             * @param transform
1001:             * @return
1002:             */
1003:            private boolean isScaleTranslate(MathTransform transform) {
1004:                if (!(transform instanceof  AffineTransform))
1005:                    return false;
1006:                final AffineTransform at = new AffineTransform(
1007:                        (AffineTransform) transform);
1008:                XAffineTransform.round(at, EPS);
1009:                final double rotation = XAffineTransform.getRotation(at);
1010:                final boolean retVal = (Math.abs(rotation) == 0);
1011:                return retVal;
1012:            }
1013:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.