Source Code Cross Referenced for GridGeometry2D.java in  » GIS » GeoTools-2.4.1 » org » geotools » coverage » grid » 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.grid 
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) 2001, 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.grid;
018:
019:        // J2SE dependencies
020:        import java.awt.Rectangle;
021:        import java.awt.geom.AffineTransform;
022:        import java.awt.geom.Point2D;
023:        import java.awt.geom.Rectangle2D;
024:        import java.awt.image.BufferedImage;
025:        import java.awt.image.RenderedImage;
026:        import java.util.Map;
027:        import java.util.HashMap;
028:        import java.util.Locale;
029:
030:        // OpenGIS dependencies
031:        import org.opengis.coverage.CannotEvaluateException;
032:        import org.opengis.coverage.grid.GridRange;
033:        import org.opengis.metadata.spatial.PixelOrientation;
034:        import org.opengis.referencing.FactoryException;
035:        import org.opengis.referencing.cs.CoordinateSystem;
036:        import org.opengis.referencing.operation.Matrix;
037:        import org.opengis.referencing.operation.MathTransform;
038:        import org.opengis.referencing.operation.MathTransform2D;
039:        import org.opengis.referencing.operation.NoninvertibleTransformException;
040:        import org.opengis.referencing.operation.TransformException;
041:        import org.opengis.referencing.crs.CoordinateReferenceSystem;
042:        import org.opengis.geometry.Envelope;
043:        import org.opengis.geometry.MismatchedDimensionException;
044:
045:        // Geotools dependencies
046:        import org.geotools.geometry.Envelope2D;
047:        import org.geotools.referencing.factory.FactoryGroup;
048:        import org.geotools.referencing.operation.matrix.MatrixFactory;
049:        import org.geotools.referencing.operation.transform.DimensionFilter;
050:        import org.geotools.referencing.operation.transform.ProjectiveTransform;
051:        import org.geotools.referencing.operation.transform.ConcatenatedTransform;
052:        import org.geotools.resources.Utilities;
053:        import org.geotools.resources.i18n.Errors;
054:        import org.geotools.resources.i18n.ErrorKeys;
055:
056:        /**
057:         * Describes the valid range of grid coordinates and the math transform, in the special case
058:         * where only 2 dimensions are in use. By "in use", we means dimension with more than 1 pixel.
059:         * For example a grid size of 512×512×1 pixels can be represented by this
060:         * {@code GridGeometry2D} class (some peoples said 2.5D) because a two-dimensional grid
061:         * coordinate is enough for referencing a pixel without ambiguity. But a grid size of
062:         * 512×512×2 pixels can not be represented by this {@code GridGeometry2D},
063:         * because a three-dimensional coordinate is mandatory for referencing a pixel without
064:         * ambiguity.
065:         *
066:         * @since 2.1
067:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/coverage/grid/GridGeometry2D.java $
068:         * @version $Id: GridGeometry2D.java 27070 2007-09-19 16:14:49Z desruisseaux $
069:         * @author Martin Desruisseaux
070:         */
071:        public class GridGeometry2D extends GeneralGridGeometry {
072:            /**
073:             * Serial number for interoperability with different versions.
074:             */
075:            private static final long serialVersionUID = -3989363771504614419L;
076:
077:            /**
078:             * Helpers methods for 2D CRS creation. Will be constructed only when first needed.
079:             */
080:            private static FactoryGroup FACTORY_GROUP;
081:
082:            /**
083:             * The offset for various pixel orientations. Keys must be upper-case names.
084:             *
085:             * @todo Uncomment the additional enums if we add those code lists to GeoAPI.
086:             */
087:            private static Map/*<PixelOrientation, Point2D.Double>*/ORIENTATIONS = new HashMap(
088:                    8);
089:            static {
090:                ORIENTATIONS.put(PixelOrientation.CENTER, new Point2D.Double(
091:                        0.0, 0.0));
092:                ORIENTATIONS.put(PixelOrientation.UPPER_LEFT,
093:                        new Point2D.Double(-0.5, -0.5));
094:                ORIENTATIONS.put(PixelOrientation.UPPER_RIGHT,
095:                        new Point2D.Double(0.5, -0.5));
096:                ORIENTATIONS.put(PixelOrientation.LOWER_LEFT,
097:                        new Point2D.Double(-0.5, 0.5));
098:                ORIENTATIONS.put(PixelOrientation.LOWER_RIGHT,
099:                        new Point2D.Double(0.5, 0.5));
100:                //      ORIENTATIONS.put(PixelOrientation.LEFT,        new Point2D.Double(-0.5,  0.0));
101:                //      ORIENTATIONS.put(PixelOrientation.RIGHT,       new Point2D.Double( 0.5,  0.0));
102:                //      ORIENTATIONS.put(PixelOrientation.UPPER,       new Point2D.Double( 0.0, -0.5));
103:                //      ORIENTATIONS.put(PixelOrientation.LOWER,       new Point2D.Double( 0.0,  0.5));
104:            }
105:
106:            /**
107:             * The two-dimensional part of the coordinate reference system.
108:             * This is usually (but not always) identical to {@link #getCoordinateReferenceSystem}.
109:             */
110:            private final CoordinateReferenceSystem crs2D;
111:
112:            /**
113:             * The first ({@code gridDimensionX}) and second ({@code gridDimensionY}) dimensions of
114:             * {@linkplain #getGridRange grid range} with {@linkplain GridRange#getLength length}
115:             * greater than 1. Those (<var>x</var>, <var>y</var>) dimensions are usually 0 and 1
116:             * respectively.
117:             */
118:            public final int gridDimensionX, gridDimensionY;
119:
120:            /**
121:             * The ({@link #gridDimensionX}, {@link #gridDimensionY}) dimensions in the envelope space.
122:             * They are the (<var>x</var>, <var>y</var>) dimensions after the
123:             * {@linkplain #getGridToCoordinateSystem grid to CRS} transform.
124:             * Those dimensions are usually 0 and 1 respectively.
125:             */
126:            public final int axisDimensionX, axisDimensionY;
127:
128:            /**
129:             * A math transform mapping only the two first dimensions of {@link #gridToCRS gridToCRS}.
130:             */
131:            private final MathTransform2D gridToCRS2D;
132:
133:            /**
134:             * The inverse of {@code gridToCRS2D}.
135:             */
136:            private final MathTransform2D gridFromCRS2D;
137:
138:            /**
139:             * Constructs a new grid geometry identical to the specified one except for the CRS.
140:             * Note that this constructor just defines the CRS; it does <strong>not</strong> reproject
141:             * the envelope. For this reason, this constructor should not be public. It is for internal
142:             * use by {@link GridCoverageFactory} only.
143:             */
144:            GridGeometry2D(final GridGeometry2D gm,
145:                    final CoordinateReferenceSystem crs) {
146:                super (gm, crs);
147:                gridDimensionX = gm.gridDimensionX;
148:                gridDimensionY = gm.gridDimensionY;
149:                axisDimensionX = gm.axisDimensionX;
150:                axisDimensionY = gm.axisDimensionY;
151:                gridFromCRS2D = gm.gridFromCRS2D;
152:                gridToCRS2D = gm.gridToCRS2D;
153:                crs2D = createCRS2D();
154:            }
155:
156:            /**
157:             * Constructs a new grid geometry from a math transform. The arguments are passed unchanged
158:             * to the {@linkplain GeneralGridGeometry#GeneralGridGeometry(GridRange, MathTransform,
159:             * CoordinateReferenceSystem) super-class constructor}. However, they must obey to one
160:             * additional constraint: only two dimensions in the grid range can have a
161:             * {@linkplain GridRange#getLength length} larger than 1.
162:             *
163:             * @param  gridRange The valid coordinate range of a grid coverage, or {@code null} if none.
164:             *         The lowest valid grid coordinate is zero for {@link BufferedImage}, but may
165:             *         be non-zero for arbitrary {@link RenderedImage}. A grid with 512 cells can have a
166:             *         minimum coordinate of 0 and maximum of 512, with 511 as the highest valid index.
167:             * @param  gridToCRS The math transform which allows for the transformations
168:             *         from grid coordinates (pixel's <em>center</em>) to real world earth coordinates.
169:             * @param  crs The coordinate reference system for the "real world" coordinates, or {@code null}
170:             *         if unknown. This CRS is given to the {@linkplain #getEnvelope envelope}.
171:             *
172:             * @throws MismatchedDimensionException if the math transform and the CRS doesn't have
173:             *         consistent dimensions.
174:             * @throws IllegalArgumentException if {@code gridRange} has more than 2 dimensions with
175:             *         a {@linkplain GridRange#getLength length} larger than 1, or if the math transform
176:             *         can't transform coordinates in the domain of the specified grid range.
177:             *
178:             * @see RenderedImage#getMinX
179:             * @see RenderedImage#getMinY
180:             * @see RenderedImage#getWidth
181:             * @see RenderedImage#getHeight
182:             *
183:             * @since 2.2
184:             */
185:            public GridGeometry2D(final GridRange gridRange,
186:                    final MathTransform gridToCRS,
187:                    final CoordinateReferenceSystem crs)
188:                    throws IllegalArgumentException,
189:                    MismatchedDimensionException {
190:                super (gridRange, gridToCRS, crs);
191:                final int[] dimensions;
192:                dimensions = new int[4];
193:                gridToCRS2D = getMathTransform2D(gridToCRS, gridRange,
194:                        dimensions);
195:                gridFromCRS2D = inverse(gridToCRS2D);
196:                gridDimensionX = dimensions[0];
197:                gridDimensionY = dimensions[1];
198:                axisDimensionX = dimensions[2];
199:                axisDimensionY = dimensions[3];
200:                crs2D = createCRS2D();
201:            }
202:
203:            /**
204:             * Constructs a new grid geometry from an envelope. This constructors applies the same heuristic
205:             * rules than the {@linkplain GeneralGridGeometry#GeneralGridGeometry(GridRange,Envelope)
206:             * super-class constructor}. However, they must obey to one additional constraint: only two
207:             * dimensions in the grid range can have a {@linkplain GridRange#getLength length} larger than
208:             * 1.
209:             *
210:             * @param gridRange The valid coordinate range of a grid coverage.
211:             * @param userRange The corresponding coordinate range in user coordinate.
212:             *
213:             * @throws IllegalArgumentException if {@code gridRange} has more than 2 dimensions with
214:             *         a {@linkplain GridRange#getLength length} larger than 1.
215:             * @throws MismatchedDimensionException if the grid range and the CRS doesn't have
216:             *         consistent dimensions.
217:             *
218:             * @since 2.2
219:             */
220:            public GridGeometry2D(final GridRange gridRange,
221:                    final Envelope userRange) throws IllegalArgumentException,
222:                    MismatchedDimensionException {
223:                this (gridRange, userRange, null, false, true);
224:            }
225:
226:            /**
227:             * Constructs a new grid geometry from an envelope. The argument are passed unchanged to the
228:             * {@linkplain GeneralGridGeometry#GeneralGridGeometry(GridRange,Envelope,boolean[],boolean)
229:             * super-class constructor}. However, they must obey to one additional constraint:
230:             * only two dimensions in the grid range can have a {@linkplain GridRange#getLength length}
231:             * larger than 1.
232:             *
233:             * @param gridRange The valid coordinate range of a grid coverage.
234:             * @param userRange The corresponding coordinate range in user coordinate.
235:             * @param reverse   Tells for each axis in <cite>user</cite> space whatever or not its
236:             *                  direction should be reversed. A {@code null} value reverse no axis.
237:             * @param swapXY    If {@code true}, then the two first axis will be interchanged.
238:             *
239:             * @throws IllegalArgumentException if {@code gridRange} has more than 2 dimensions with
240:             *         a {@linkplain GridRange#getLength length} larger than 1.
241:             * @throws MismatchedDimensionException if the grid range and the CRS doesn't have
242:             *         consistent dimensions.
243:             *
244:             * @since 2.2
245:             */
246:            public GridGeometry2D(final GridRange gridRange,
247:                    final Envelope userRange, final boolean[] reverse,
248:                    final boolean swapXY) throws IllegalArgumentException,
249:                    MismatchedDimensionException {
250:                this (gridRange, userRange, reverse, swapXY, false);
251:            }
252:
253:            /**
254:             * Implementation of heuristic constructors.
255:             */
256:            private GridGeometry2D(final GridRange gridRange,
257:                    final Envelope userRange, final boolean[] reverse,
258:                    final boolean swapXY, final boolean automatic)
259:                    throws IllegalArgumentException,
260:                    MismatchedDimensionException {
261:                super (gridRange, userRange, reverse, swapXY, automatic);
262:                final int[] dimensions;
263:                dimensions = new int[4];
264:                gridToCRS2D = getMathTransform2D(gridToCRS, gridRange,
265:                        dimensions);
266:                gridFromCRS2D = inverse(gridToCRS2D);
267:                gridDimensionX = dimensions[0];
268:                gridDimensionY = dimensions[1];
269:                axisDimensionX = dimensions[2];
270:                axisDimensionY = dimensions[3];
271:                crs2D = createCRS2D();
272:            }
273:
274:            /**
275:             * Constructs a new two-dimensional grid geometry. A math transform will be computed
276:             * automatically with an inverted <var>y</var> axis (i.e. {@code gridRange} and
277:             * {@code userRange} are assumed to have <var>y</var> axis in opposite direction).
278:             *
279:             * @param gridRange The valid coordinate range of a grid coverage.
280:             *                  Increasing <var>x</var> values goes right and
281:             *                  increasing <var>y</var> values goes <strong>down</strong>.
282:             * @param userRange The corresponding coordinate range in user coordinate.
283:             *                  Increasing <var>x</var> values goes right and
284:             *                  increasing <var>y</var> values goes <strong>up</strong>.
285:             *                  This rectangle must contains entirely all pixels, i.e.
286:             *                  the rectangle's upper left corner must coincide with
287:             *                  the upper left corner of the first pixel and the rectangle's
288:             *                  lower right corner must coincide with the lower right corner
289:             *                  of the last pixel.
290:             */
291:            public GridGeometry2D(final Rectangle gridRange,
292:                    final Rectangle2D userRange) {
293:                this (new GeneralGridRange(gridRange), getMathTransform(
294:                        gridRange, userRange), (CoordinateReferenceSystem) null);
295:            }
296:
297:            /**
298:             * Workaround for RFE #4093999 ("Relax constraint on placement of this()/super()
299:             * call in constructors").
300:             */
301:            private static MathTransform getMathTransform(
302:                    final Rectangle gridRange, final Rectangle2D userRange) {
303:                final double scaleX = userRange.getWidth()
304:                        / gridRange.getWidth();
305:                final double scaleY = userRange.getHeight()
306:                        / gridRange.getHeight();
307:                final double transX = userRange.getMinX() - gridRange.x
308:                        * scaleX;
309:                final double transY = userRange.getMaxY() + gridRange.y
310:                        * scaleY;
311:                final AffineTransform tr = new AffineTransform(scaleX, 0, 0,
312:                        -scaleY, transX, transY);
313:                tr.translate(0.5, 0.5); // Maps to pixel center
314:                return ProjectiveTransform.create(tr);
315:            }
316:
317:            /**
318:             * Returns the math transform for two dimensions of the specified transform.
319:             *
320:             * @param  gridRange The grid range.
321:             * @param  transform The transform.
322:             * @param  axis An array of length 4 initialized to 0. This is the array where to store
323:             *         {@link #axisDimensionX} and {@link #axisDimensionY} values. This argument is
324:             *         actually a workaround for a Java language limitation (no multiple return values).
325:             *         If we could, we should returns directly the {@code dimensions} array computed in
326:             *         the body of this method.
327:             * @return The {@link MathTransform2D} part of {@code transform}.
328:             * @throws IllegalArgumentException if the 2D part is not separable.
329:             */
330:            private static MathTransform2D getMathTransform2D(
331:                    final MathTransform transform, final GridRange gridRange,
332:                    final int[] axis) throws IllegalArgumentException {
333:                axis[1] = axis[3] = 1;
334:                if (transform == null || transform instanceof  MathTransform2D) {
335:                    return (MathTransform2D) transform;
336:                }
337:                /*
338:                 * Finds the axis for the two dimensional parts. We infer them from the grid range.
339:                 * If no grid range were specified, then we assume that they are the 2 first dimensions.
340:                 */
341:                final DimensionFilter filter = new DimensionFilter();
342:                if (gridRange != null) {
343:                    final int dimension = gridRange.getDimension();
344:                    for (int i = 0; i < dimension; i++) {
345:                        if (gridRange.getLength(i) > 1) {
346:                            filter.addSourceDimension(i);
347:                        }
348:                    }
349:                } else {
350:                    filter.addSourceDimensionRange(0, 2);
351:                }
352:                Exception cause = null;
353:                int[] dimensions = filter.getSourceDimensions();
354:                /*
355:                 * Select a math transform that operate only on the two dimensions choosen above.
356:                 * If such a math transform doesn't have exactly 2 output dimensions, then select
357:                 * the same output dimensions than the input ones.
358:                 */
359:                MathTransform candidate;
360:                if (dimensions.length == 2) {
361:                    System.arraycopy(dimensions, 0, axis, 0, 2);
362:                    try {
363:                        candidate = filter.separate(transform);
364:                        if (candidate.getTargetDimensions() != 2) {
365:                            filter.clear();
366:                            filter.addSourceDimensions(dimensions);
367:                            filter.addTargetDimensions(dimensions);
368:                            candidate = filter.separate(transform);
369:                        }
370:                        dimensions = filter.getTargetDimensions();
371:                        System.arraycopy(dimensions, 0, axis, 2, 2);
372:                        try {
373:                            return (MathTransform2D) candidate;
374:                        } catch (ClassCastException exception) {
375:                            cause = exception;
376:                        }
377:                    } catch (FactoryException exception) {
378:                        cause = exception;
379:                    }
380:                }
381:                IllegalArgumentException e = new IllegalArgumentException(
382:                        Errors.format(ErrorKeys.NO_TRANSFORM2D_AVAILABLE));
383:                e.initCause(cause); // TODO: Move in constructor's argument when we
384:                throw e; //       will be allowed to compile for J2SE 1.5.
385:            }
386:
387:            /**
388:             * Inverses the specified math transform. This method is invoked by constructors only. It wraps
389:             * {@link NoninvertibleTransformException} into {@link IllegalArgumentException}, since failures
390:             * to inverse a transform are caused by an illegal user-supplied transform.
391:             *
392:             * @throws IllegalArgumentException if the transform is non-invertible.
393:             */
394:            private static MathTransform2D inverse(
395:                    final MathTransform2D gridToCRS2D)
396:                    throws IllegalArgumentException {
397:                if (gridToCRS2D == null) {
398:                    return null;
399:                } else
400:                    try {
401:                        return (MathTransform2D) gridToCRS2D.inverse();
402:                    } catch (NoninvertibleTransformException exception) {
403:                        final IllegalArgumentException e;
404:                        e = new IllegalArgumentException(Errors.format(
405:                                ErrorKeys.BAD_TRANSFORM_$1, Utilities
406:                                        .getShortClassName(gridToCRS2D)));
407:                        e.initCause(exception); // TODO: move into contructor call with J2SE 1.5.
408:                        throw e;
409:                    }
410:            }
411:
412:            /**
413:             * Constructs the two-dimensional CRS. This is usually identical to the user-supplied CRS.
414:             * However, the user is allowed to specify a wider CRS (for example a 3D one which includes
415:             * a time axis), in which case we infer which axis apply to the 2D image, and constructs a
416:             * 2D CRS with only those axis.
417:             *
418:             * @return The coordinate reference system, or {@code null} if none.
419:             */
420:            private CoordinateReferenceSystem createCRS2D() {
421:                if (!super .isDefined(CRS)) {
422:                    return null;
423:                }
424:                final CoordinateReferenceSystem crs = super 
425:                        .getCoordinateReferenceSystem();
426:                if (FACTORY_GROUP == null) {
427:                    FACTORY_GROUP = FactoryGroup.createInstance(null);
428:                    // No need to synchronize: this is not a big deal
429:                    // if two FactoryGroup instances are created.
430:                }
431:                final CoordinateReferenceSystem crs2D;
432:                try {
433:                    crs2D = FACTORY_GROUP.separate(crs, new int[] {
434:                            axisDimensionX, axisDimensionY });
435:                } catch (FactoryException exception) {
436:                    final InvalidGridGeometryException e = new InvalidGridGeometryException(
437:                            Errors.format(ErrorKeys.ILLEGAL_ARGUMENT_$2, "crs",
438:                                    crs.getName()));
439:                    e.initCause(exception); // TODO: inline in the constructor with J2SE 1.5.
440:                    throw e;
441:                }
442:                assert crs2D.getCoordinateSystem().getDimension() == 2 : crs2D;
443:                return crs2D;
444:            }
445:
446:            /**
447:             * Returns the two-dimensional part of this grid geometry CRS. This is usually (but not
448:             * always) identical to the {@linkplain #getCoordinateReferenceSystem full CRS}.
449:             *
450:             * @return The coordinate reference system (never {@code null}).
451:             * @throws InvalidGridGeometryException if this grid geometry has no CRS (i.e.
452:             *         <code>{@linkplain #isDefined isDefined}({@linkplain #CRS CRS})</code>
453:             *         returned {@code false}).
454:             *
455:             * @see #getCoordinateReferenceSystem
456:             *
457:             * @since 2.2
458:             */
459:            public CoordinateReferenceSystem getCoordinateReferenceSystem2D()
460:                    throws InvalidGridGeometryException {
461:                if (crs2D != null) {
462:                    assert isDefined(CRS);
463:                    return crs2D;
464:                }
465:                assert !isDefined(CRS);
466:                throw new InvalidGridGeometryException(Errors
467:                        .format(ErrorKeys.UNSPECIFIED_CRS));
468:            }
469:
470:            /**
471:             * Returns the two-dimensional bounding box for the coverage domain in coordinate reference
472:             * system coordinates. If the coverage envelope has more than two dimensions, only the
473:             * dimensions used in the underlying rendered image are returned.
474:             *
475:             * @return The bounding box in "real world" coordinates (never {@code null}).
476:             * @throws InvalidGridGeometryException if this grid geometry has no envelope (i.e.
477:             *         <code>{@linkplain #isDefined isDefined}({@linkplain #ENVELOPE ENVELOPE})</code>
478:             *         returned {@code false}).
479:             *
480:             * @see #getEnvelope
481:             */
482:            public Envelope2D getEnvelope2D()
483:                    throws InvalidGridGeometryException {
484:                if (envelope != null && !envelope.isNull()) {
485:                    assert isDefined(ENVELOPE);
486:                    return new Envelope2D(crs2D, envelope
487:                            .getMinimum(axisDimensionX), envelope
488:                            .getMinimum(axisDimensionY), envelope
489:                            .getLength(axisDimensionX), envelope
490:                            .getLength(axisDimensionY));
491:                }
492:                assert !isDefined(ENVELOPE);
493:                throw new InvalidGridGeometryException(
494:                        Errors
495:                                .format(gridToCRS == null ? ErrorKeys.UNSPECIFIED_TRANSFORM
496:                                        : ErrorKeys.UNSPECIFIED_IMAGE_SIZE));
497:            }
498:
499:            /**
500:             * Returns the two-dimensional part of the {@linkplain #getGridRange grid range}
501:             * as a rectangle.
502:             *
503:             * @return The grid range (never {@code null}).
504:             * @throws InvalidGridGeometryException if this grid geometry has no grid range (i.e.
505:             *         <code>{@linkplain #isDefined isDefined}({@linkplain #GRID_RANGE GRID_RANGE})</code>
506:             *         returned {@code false}).
507:             *
508:             * @see #getGridRange
509:             * @see RenderedImage#getMinX
510:             * @see RenderedImage#getMinY
511:             * @see RenderedImage#getWidth
512:             * @see RenderedImage#getHeight
513:             */
514:            public Rectangle getGridRange2D()
515:                    throws InvalidGridGeometryException {
516:                if (gridRange != null) {
517:                    assert isDefined(GRID_RANGE);
518:                    return new Rectangle(gridRange.getLower(gridDimensionX),
519:                            gridRange.getLower(gridDimensionY), gridRange
520:                                    .getLength(gridDimensionX), gridRange
521:                                    .getLength(gridDimensionY));
522:                }
523:                assert !isDefined(GRID_RANGE);
524:                throw new InvalidGridGeometryException(Errors
525:                        .format(ErrorKeys.UNSPECIFIED_IMAGE_SIZE));
526:            }
527:
528:            /**
529:             * @deprecated Renamed as {@link #getGridToCRS2D()}.
530:             */
531:            public MathTransform2D getGridToCoordinateSystem2D()
532:                    throws InvalidGridGeometryException {
533:                return getGridToCRS2D();
534:            }
535:
536:            /**
537:             * Returns a math transform for the two dimensional part. This is a convenience method for
538:             * working on horizontal data while ignoring vertical or temporal dimensions.
539:             *
540:             * @return The transform which allows for the transformations from grid coordinates
541:             *         to real world earth coordinates, operating only on two dimensions.
542:             *         The returned transform is often an instance of {@link AffineTransform}, which
543:             *         make it convenient for interoperability with Java2D.
544:             * @throws InvalidGridGeometryException if a two-dimensional transform is not available
545:             *         for this grid geometry.
546:             *
547:             * @see #getGridToCRS
548:             *
549:             * @since 2.3
550:             */
551:            public MathTransform2D getGridToCRS2D()
552:                    throws InvalidGridGeometryException {
553:                if (gridToCRS2D != null) {
554:                    return gridToCRS2D;
555:                }
556:                throw new InvalidGridGeometryException(Errors
557:                        .format(ErrorKeys.NO_TRANSFORM2D_AVAILABLE));
558:            }
559:
560:            /**
561:             * Returns a math transform for the two dimensional part. This method is similar
562:             * to {@link #getGridToCRS2D()} except that the transform may maps a pixel corner
563:             * instead of pixel center.
564:             *
565:             * @param  orientation The pixel part to map. The default value is
566:             *         {@link PixelOrientation#CENTER CENTER}.
567:             * @return The transform which allows for the transformations from grid coordinates
568:             *         to real world earth coordinates.
569:             * @throws InvalidGridGeometryException if a two-dimensional transform is not available
570:             *         for this grid geometry.
571:             *
572:             * @since 2.3
573:             */
574:            public MathTransform2D getGridToCRS2D(
575:                    final PixelOrientation orientation) {
576:                final int xdim = (gridDimensionX < gridDimensionY) ? 0 : 1;
577:                return (MathTransform2D) translate(getGridToCRS2D(),
578:                        orientation, xdim, xdim ^ 1);
579:            }
580:
581:            /**
582:             * Returns a math transform mapping the specified pixel part.
583:             *
584:             * @param  orientation The pixel part to map. The default value is
585:             *         {@link PixelOrientation#CENTER CENTER}.
586:             * @return The transform which allows for the transformations from grid coordinates
587:             *         to real world earth coordinates.
588:             * @throws InvalidGridGeometryException if a transform is not available
589:             *         for this grid geometry.
590:             *
591:             * @since 2.3
592:             */
593:            public MathTransform getGridToCRS(final PixelOrientation orientation) {
594:                return translate(getGridToCRS(), orientation, gridDimensionX,
595:                        gridDimensionY);
596:            }
597:
598:            /**
599:             * Translates the specified math transform according the specified pixel orientation.
600:             * The {@code gridToCRS} math transform is assumed maps the pixel centers.
601:             */
602:            private static MathTransform translate(
603:                    final MathTransform gridToCRS,
604:                    final PixelOrientation orientation,
605:                    final int gridDimensionX, final int gridDimensionY) {
606:                if (PixelOrientation.CENTER.equals(orientation)) {
607:                    return gridToCRS;
608:                }
609:                final Point2D.Double offset = getDirectPixelTranslation(orientation);
610:                final int dimension = gridToCRS.getSourceDimensions();
611:                final Matrix matrix = MatrixFactory.create(dimension + 1);
612:                matrix.setElement(gridDimensionX, dimension, offset.x);
613:                matrix.setElement(gridDimensionY, dimension, offset.y);
614:                return ConcatenatedTransform.create(ProjectiveTransform
615:                        .create(matrix), gridToCRS);
616:            }
617:
618:            /**
619:             * Like {@link #getPixelTranslation} but without cloning the returned value.
620:             */
621:            private static Point2D.Double getDirectPixelTranslation(
622:                    final PixelOrientation orientation)
623:                    throws IllegalArgumentException {
624:                final Point2D.Double offset = (Point2D.Double) ORIENTATIONS
625:                        .get(orientation);
626:                if (offset == null) {
627:                    throw new IllegalArgumentException(Errors.format(
628:                            ErrorKeys.ILLEGAL_ARGUMENT_$2, "orientation",
629:                            orientation));
630:                }
631:                return offset;
632:            }
633:
634:            /**
635:             * Returns the specified position relative to the pixel center.
636:             * This method returns a value from the following table:
637:             * <p>
638:             * <table>
639:             *   <tr><th>Pixel orientation</th>                               <th>  x </th><th>  y </th></tr>
640:             *   <tr><td>{@link PixelOrientation#CENTER      CENTER}</td>     <td> 0.0</td><td> 0.0</td></tr>
641:             *   <tr><td>{@link PixelOrientation#UPPER_LEFT  UPPER_LEFT}</td> <td>-0.5</td><td>-0.5</td></tr>
642:             *   <tr><td>{@link PixelOrientation#UPPER_RIGHT UPPER_RIGHT}</td><td>+0.5</td><td>-0.5</td></tr>
643:             *   <tr><td>{@link PixelOrientation#LOWER_LEFT  LOWER_LEFT}</td> <td>-0.5</td><td>+0.5</td></tr>
644:             *   <tr><td>{@link PixelOrientation#LOWER_RIGHT LOWER_RIGHT}</td><td>+0.5</td><td>+0.5</td></tr>
645:             * </table>
646:             *
647:             * @param  orientation The pixel orientation.
648:             * @return The position relative to the pixel center.
649:             * @throws IllegalArgumentException if the specified orientation is not known.
650:             * @since 2.4
651:             */
652:            public static Point2D getPixelTranslation(
653:                    final PixelOrientation orientation)
654:                    throws IllegalArgumentException {
655:                return (Point2D) getDirectPixelTranslation(orientation).clone();
656:            }
657:
658:            /**
659:             * Transforms a point using the inverse of {@link #getGridToCRS2D()}.
660:             *
661:             * @param  point The point in logical coordinate system.
662:             * @return A new point in the grid coordinate system.
663:             * @throws InvalidGridGeometryException if a two-dimensional inverse
664:             *         transform is not available for this grid geometry.
665:             * @throws CannotEvaluateException if the transformation failed.
666:             */
667:            final Point2D inverseTransform(final Point2D point)
668:                    throws InvalidGridGeometryException {
669:                if (gridFromCRS2D != null) {
670:                    try {
671:                        return gridFromCRS2D.transform(point, null);
672:                    } catch (TransformException exception) {
673:                        throw new CannotEvaluateException(Errors.format(
674:                                ErrorKeys.CANT_EVALUATE_$1,
675:                                AbstractGridCoverage.toString(point, Locale
676:                                        .getDefault()), exception));
677:                    }
678:                }
679:                throw new InvalidGridGeometryException(Errors
680:                        .format(ErrorKeys.NO_TRANSFORM2D_AVAILABLE));
681:            }
682:
683:            /**
684:             * Returns the pixel coordinate of a rectangle containing the
685:             * specified geographic area. If the rectangle can't be computed,
686:             * then this method returns {@code null}.
687:             */
688:            final Rectangle inverseTransform(Rectangle2D bounds) {
689:                if (bounds != null && gridFromCRS2D != null) {
690:                    try {
691:                        bounds = org.geotools.referencing.CRS.transform(
692:                                gridFromCRS2D, bounds, null);
693:                        final int xmin = (int) Math
694:                                .floor(bounds.getMinX() - 0.5);
695:                        final int ymin = (int) Math
696:                                .floor(bounds.getMinY() - 0.5);
697:                        final int xmax = (int) Math
698:                                .ceil(bounds.getMaxX() - 0.5);
699:                        final int ymax = (int) Math
700:                                .ceil(bounds.getMaxY() - 0.5);
701:                        return new Rectangle(xmin, ymin, xmax - xmin, ymax
702:                                - ymin);
703:                    } catch (TransformException exception) {
704:                        // Ignore, since this method is invoked from 'GridCoverage.prefetch' only.
705:                        // It doesn't matter if the transformation failed; 'prefetch' is just a hint.
706:                    }
707:                }
708:                return null;
709:            }
710:
711:            /**
712:             * Compares the specified object with this grid geometry for equality.
713:             */
714:            public boolean equals(final Object object) {
715:                if (super .equals(object)) {
716:                    final GridGeometry2D that = (GridGeometry2D) object;
717:                    return this .gridDimensionX == that.gridDimensionX
718:                            && this .gridDimensionY == that.gridDimensionY
719:                            && this .axisDimensionX == that.axisDimensionX
720:                            && this .axisDimensionY == that.axisDimensionY;
721:                }
722:                return false;
723:            }
724:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.