Source Code Cross Referenced for GridToEnvelopeMapper.java in  » GIS » GeoTools-2.4.1 » org » geotools » referencing » operation » builder » 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.referencing.operation.builder 
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.referencing.operation.builder;
018:
019:        // J2SE dependencies
020:        import java.util.Arrays;
021:        import java.awt.image.BufferedImage; // For javadoc
022:        import java.awt.geom.AffineTransform;
023:
024:        // OpenGIS dependencies
025:        import org.opengis.coverage.grid.GridRange;
026:        import org.opengis.geometry.Envelope;
027:        import org.opengis.geometry.MismatchedDimensionException;
028:        import org.opengis.referencing.crs.CoordinateReferenceSystem;
029:        import org.opengis.referencing.cs.AxisDirection;
030:        import org.opengis.referencing.cs.CoordinateSystem;
031:        import org.opengis.referencing.datum.PixelInCell;
032:        import org.opengis.referencing.operation.MathTransform;
033:        import org.opengis.referencing.operation.Matrix;
034:
035:        // Geotools dependencies
036:        import org.geotools.referencing.operation.matrix.MatrixFactory;
037:        import org.geotools.referencing.operation.transform.ProjectiveTransform;
038:        import org.geotools.resources.Utilities;
039:        import org.geotools.resources.i18n.ErrorKeys;
040:        import org.geotools.resources.i18n.Errors;
041:
042:        /**
043:         * A helper class for building <var>n</var>-dimensional {@linkplain AffineTransform
044:         * affine transform} mapping {@linkplain GridRange grid ranges} to {@linkplain Envelope
045:         * envelopes}. The affine transform will be computed automatically from the information
046:         * specified by the {@link #setGridRange setGridRange} and {@link #setEnvelope setEnvelope}
047:         * methods, which are mandatory. All other setter methods are optional hints about the
048:         * affine transform to be created. This builder is convenient when the following conditions
049:         * are meet:
050:         * <p>
051:         * <ul>
052:         *   <li><p>Pixels coordinates (usually (<var>x</var>,<var>y</var>) integer values inside
053:         *       the rectangle specified by the grid range) are expressed in some
054:         *       {@linkplain CoordinateReferenceSystem coordinate reference system} known at compile
055:         *       time. This is often the case. For example the CRS attached to {@link BufferedImage}
056:         *       has always ({@linkplain AxisDirection#COLUMN_POSITIVE column},
057:         *       {@linkplain AxisDirection#ROW_POSITIVE row}) axis, with the origin (0,0) in the upper
058:         *       left corner, and row values increasing down.</p></li>
059:         *
060:         *   <li><p>"Real world" coordinates (inside the envelope) are expressed in arbitrary
061:         *       <em>horizontal</em> coordinate reference system. Axis directions may be
062:         *       ({@linkplain AxisDirection#NORTH North}, {@linkplain AxisDirection#WEST West}),
063:         *       or ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North}),
064:         *       <cite>etc.</cite>.</p></li>
065:         * </ul>
066:         * <p>
067:         * In such case (and assuming that the image's CRS has the same characteristics than the
068:         * {@link BufferedImage}'s CRS described above):
069:         * <p>
070:         * <ul>
071:         *   <li><p>{@link #setSwapXY swapXY} shall be set to {@code true} if the "real world" axis
072:         *       order is ({@linkplain AxisDirection#NORTH North}, {@linkplain AxisDirection#EAST East})
073:         *       instead of ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North}).
074:         *       This axis swapping is necessary for mapping the ({@linkplain AxisDirection#COLUMN_POSITIVE
075:         *       column}, {@linkplain AxisDirection#ROW_POSITIVE row}) axis order associated to the
076:         *       image CRS.</p></li>
077:         *
078:         *   <li><p>In addition, the "real world" axis directions shall be reversed (by invoking
079:         *       <code>{@linkplain #reverseAxis reverseAxis}(dimension)</code>) if their direction is
080:         *       {@link AxisDirection#WEST WEST} (<var>x</var> axis) or {@link AxisDirection#NORTH NORTH}
081:         *       (<var>y</var> axis), in order to get them oriented toward the {@link AxisDirection#EAST
082:         *       EAST} or {@link AxisDirection#SOUTH SOUTH} direction respectively. The later may seems
083:         *       unatural, but it reflects the fact that row values are increasing down in an
084:         *       {@link BufferedImage}'s CRS.</p></li>
085:         * </ul>
086:         *
087:         * @since 2.3
088:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/builder/GridToEnvelopeMapper.java $
089:         * @version $Id: GridToEnvelopeMapper.java 25778 2007-06-08 08:46:34Z desruisseaux $
090:         * @author Martin Desruisseaux
091:         */
092:        public class GridToEnvelopeMapper {
093:            /**
094:             * A bit mask for the {@link #setSwapXY swapXY} property.
095:             *
096:             * @see #isAutomatic
097:             * @see #setAutomatic
098:             */
099:            public static final int SWAP_XY = 1;
100:
101:            /**
102:             * A bit mask for the {@link #setReverseAxis reverseAxis} property.
103:             *
104:             * @see #isAutomatic
105:             * @see #setAutomatic
106:             */
107:            public static final int REVERSE_AXIS = 2;
108:
109:            /**
110:             * A combinaison of bit masks telling which property were user-defined.
111:             *
112:             * @see #isAutomatic
113:             * @see #setAutomatic
114:             */
115:            private int defined;
116:
117:            /**
118:             * The grid range, or {@code null} if not yet specified.
119:             */
120:            private GridRange gridRange;
121:
122:            /**
123:             * The envelope, or {@code null} if not yet specified.
124:             */
125:            private Envelope envelope;
126:
127:            /**
128:             * The grid type. The default value is {@link PixelInCell#CELL_CENTER}.
129:             */
130:            private PixelInCell gridType = PixelInCell.CELL_CENTER;
131:
132:            /**
133:             * {@code true} if we should swap the two first axis, {@code false} if we should
134:             * not swap and {@code null} if this state is not yet determined.
135:             */
136:            private Boolean swapXY;
137:
138:            /**
139:             * The axis to reverse, or {@code null} if none or not yet determined.
140:             */
141:            private boolean[] reverseAxis;
142:
143:            /**
144:             * The math transform, or {@code null} if not yet computed.
145:             */
146:            private MathTransform transform;
147:
148:            /**
149:             * Creates a new instance of {@code GridToEnvelopeMapper}.
150:             */
151:            public GridToEnvelopeMapper() {
152:            }
153:
154:            /**
155:             * Creates a new instance for the specified grid range and envelope.
156:             *
157:             * @param gridRange The valid coordinate range of a grid coverage.
158:             * @param userRange The corresponding coordinate range in user coordinate. This envelope must
159:             *                  contains entirely all pixels, i.e. the envelope's upper left corner must
160:             *                  coincide with the upper left corner of the first pixel and the envelope's
161:             *                  lower right corner must coincide with the lower right corner of the last
162:             *                  pixel.
163:             *
164:             * @throws MismatchedDimensionException if the grid range and the envelope doesn't have
165:             *         consistent dimensions.
166:             */
167:            public GridToEnvelopeMapper(final GridRange gridRange,
168:                    final Envelope userRange)
169:                    throws MismatchedDimensionException {
170:                ensureNonNull("gridRange", gridRange);
171:                ensureNonNull("userRange", userRange);
172:                final int gridDim = gridRange.getDimension();
173:                final int userDim = userRange.getDimension();
174:                if (userDim != gridDim) {
175:                    throw new MismatchedDimensionException(Errors.format(
176:                            ErrorKeys.MISMATCHED_DIMENSION_$2, new Integer(
177:                                    gridDim), new Integer(userDim)));
178:                }
179:                this .gridRange = gridRange;
180:                this .envelope = userRange;
181:            }
182:
183:            /**
184:             * Makes sure that an argument is non-null.
185:             */
186:            private static void ensureNonNull(final String name,
187:                    final Object object) throws IllegalArgumentException {
188:                if (object == null) {
189:                    throw new IllegalArgumentException(Errors.format(
190:                            ErrorKeys.NULL_ARGUMENT_$1, name));
191:                }
192:            }
193:
194:            /**
195:             * Makes sure that the specified objects have the same dimension.
196:             */
197:            private static void ensureDimensionMatch(final GridRange gridRange,
198:                    final Envelope envelope, final boolean checkingRange) {
199:                if (gridRange != null && envelope != null) {
200:                    final String label;
201:                    final int dim1, dim2;
202:                    if (checkingRange) {
203:                        label = "gridRange";
204:                        dim1 = gridRange.getDimension();
205:                        dim2 = envelope.getDimension();
206:                    } else {
207:                        label = "envelope";
208:                        dim1 = envelope.getDimension();
209:                        dim2 = gridRange.getDimension();
210:                    }
211:                    if (dim1 != dim2) {
212:                        throw new MismatchedDimensionException(Errors.format(
213:                                ErrorKeys.MISMATCHED_DIMENSION_$3, label,
214:                                new Integer(dim1), new Integer(dim2)));
215:                    }
216:                }
217:            }
218:
219:            /**
220:             * Flush any information cached in this object.
221:             */
222:            private void reset() {
223:                transform = null;
224:                if (isAutomatic(REVERSE_AXIS)) {
225:                    reverseAxis = null;
226:                }
227:                if (isAutomatic(SWAP_XY)) {
228:                    swapXY = null;
229:                }
230:            }
231:
232:            /**
233:             * Returns whatever the grid range maps {@linkplain PixelInCell#CELL_CENTER pixel center}
234:             * or {@linkplain PixelInCell#CELL_CORNER pixel corner}.
235:             */
236:            public PixelInCell getGridType() {
237:                return gridType;
238:            }
239:
240:            /**
241:             * Set whatever the grid range maps {@linkplain PixelInCell#CELL_CENTER pixel center}
242:             * or {@linkplain PixelInCell#CELL_CORNER pixel corner}.
243:             */
244:            public void setGridType(final PixelInCell gridType) {
245:                ensureNonNull("gridType", gridType);
246:                if (!Utilities.equals(this .gridType, gridType)) {
247:                    this .gridType = gridType;
248:                    reset();
249:                }
250:            }
251:
252:            /**
253:             * Returns the grid range.
254:             *
255:             * @throws IllegalStateException if the grid range has not yet been defined.
256:             */
257:            public GridRange getGridRange() throws IllegalStateException {
258:                if (gridRange == null) {
259:                    throw new IllegalStateException(Errors.format(
260:                            ErrorKeys.MISSING_PARAMETER_VALUE_$1, "gridRange"));
261:                }
262:                return gridRange;
263:            }
264:
265:            /**
266:             * Set the grid range.
267:             */
268:            public void setGridRange(final GridRange gridRange) {
269:                ensureNonNull("gridRange", gridRange);
270:                ensureDimensionMatch(gridRange, envelope, true);
271:                if (!Utilities.equals(this .gridRange, gridRange)) {
272:                    this .gridRange = gridRange;
273:                    reset();
274:                }
275:            }
276:
277:            /**
278:             * Returns the envelope. For performance reason, this method do not
279:             * clone the envelope. So the returned object should not be modified.
280:             *
281:             * @throws IllegalStateException if the envelope has not yet been defined.
282:             */
283:            public Envelope getEnvelope() throws IllegalStateException {
284:                if (envelope == null) {
285:                    throw new IllegalStateException(Errors.format(
286:                            ErrorKeys.MISSING_PARAMETER_VALUE_$1, "envelope"));
287:                }
288:                return envelope;
289:            }
290:
291:            /**
292:             * Set the envelope. This method do not clone the specified envelope,
293:             * so it should not be modified after this method has been invoked.
294:             */
295:            public void setEnvelope(final Envelope envelope) {
296:                ensureNonNull("envelope", envelope);
297:                ensureDimensionMatch(gridRange, envelope, false);
298:                if (!Utilities.equals(this .envelope, envelope)) {
299:                    this .envelope = envelope;
300:                    reset();
301:                }
302:            }
303:
304:            /**
305:             * Applies heuristic rules in order to determine if the two first axis should be interchanged.
306:             *
307:             * @deprecated Avoid this method as much as possible. Experience shows that this method is
308:             *             often used in a context where it should not, for example in order to select
309:             *             the coefficients to read in an affine transform.
310:             */
311:            public static boolean swapXY(final CoordinateSystem cs) {
312:                if (cs != null && cs.getDimension() >= 2) {
313:                    return AxisDirection.NORTH.equals(cs.getAxis(0)
314:                            .getDirection().absolute())
315:                            && AxisDirection.EAST.equals(cs.getAxis(1)
316:                                    .getDirection().absolute());
317:                }
318:                return false;
319:            }
320:
321:            /**
322:             * Returns {@code true} if the two first axis should be interchanged. If
323:             * <code>{@linkplain #isAutomatic isAutomatic}({@linkplain #SWAP_XY})</code>
324:             * returns {@code true} (which is the default), then this method make the
325:             * following assumptions:
326:             *
327:             * <ul>
328:             *   <li><p>Axis order in the grid range matches exactly axis order in the envelope, except
329:             *       for the special case described in the next point. In other words, if axis order in
330:             *       the underlying image is (<var>column</var>, <var>row</var>) (which is the case for
331:             *       a majority of images), then the envelope should probably have a (<var>longitude</var>,
332:             *       <var>latitude</var>) or (<var>easting</var>, <var>northing</var>) axis order.</p></li>
333:             *
334:             *   <li><p>An exception to the above rule applies for CRS using exactly the following axis
335:             *       order: ({@link AxisDirection#NORTH NORTH}|{@link AxisDirection#SOUTH SOUTH},
336:             *       {@link AxisDirection#EAST EAST}|{@link AxisDirection#WEST WEST}). An example
337:             *       of such CRS is {@code EPSG:4326}. In this particular case, this method will
338:             *       returns {@code true}, thus suggesting to interchange the
339:             *       (<var>y</var>,<var>x</var>) axis for such CRS.</p></li>
340:             * </ul>
341:             */
342:            public boolean getSwapXY() {
343:                if (swapXY == null) {
344:                    boolean value = false;
345:                    if (isAutomatic(SWAP_XY)) {
346:                        value = swapXY(getCoordinateSystem());
347:                    }
348:                    swapXY = Boolean.valueOf(value);
349:                }
350:                return swapXY.booleanValue();
351:            }
352:
353:            /**
354:             * Tells if the two first axis should be interchanged. Invoking this method force
355:             * <code>{@linkplain #isAutomatic isAutomatic}({@linkplain #SWAP_XY})</code> to
356:             * {@code false}.
357:             */
358:            public void setSwapXY(final boolean swapXY) {
359:                final Boolean newValue = Boolean.valueOf(swapXY);
360:                if (!newValue.equals(this .swapXY)) {
361:                    reset();
362:                }
363:                this .swapXY = newValue;
364:                defined |= SWAP_XY;
365:            }
366:
367:            /**
368:             * Returns which (if any) axis in <cite>user</cite> space
369:             * (not grid space) should have their direction reversed. If
370:             * <code>{@linkplain #isAutomatic isAutomatic}({@linkplain #REVERSE_AXIS})</code>
371:             * returns {@code true} (which is the default), then this method make the
372:             * following assumptions:
373:             * <p>
374:             * <ul>
375:             *   <li>Axis should be reverted if needed in order to point toward their
376:             *       "{@linkplain AxisDirection#absolute absolute}" direction.</li>
377:             *   <li>An exception to the above rule is the second axis in grid space,
378:             *       which is assumed to be the <var>y</var> axis on output device (usually
379:             *       the screen). This axis is reversed again in order to match the bottom
380:             *       direction often used with such devices.</li>
381:             * </ul>
382:             *
383:             * @return The reversal state of each axis, or {@code null} if unspecified.
384:             *         For performance reason, this method do not clone the returned array.
385:             */
386:            public boolean[] getReverseAxis() {
387:                if (reverseAxis == null) {
388:                    final CoordinateSystem cs = getCoordinateSystem();
389:                    if (cs != null) {
390:                        final int dimension = cs.getDimension();
391:                        reverseAxis = new boolean[dimension];
392:                        if (isAutomatic(REVERSE_AXIS)) {
393:                            for (int i = 0; i < dimension; i++) {
394:                                final AxisDirection direction = cs.getAxis(i)
395:                                        .getDirection();
396:                                final AxisDirection absolute = direction
397:                                        .absolute();
398:                                reverseAxis[i] = direction.equals(absolute
399:                                        .opposite());
400:                            }
401:                            if (dimension >= 2) {
402:                                final int i = getSwapXY() ? 0 : 1;
403:                                reverseAxis[i] = !reverseAxis[i];
404:                            }
405:                        }
406:                    }
407:                }
408:                return reverseAxis;
409:            }
410:
411:            /**
412:             * Set which (if any) axis in <cite>user</cite> space (not grid space)
413:             * should have their direction reversed. Invoking this method force
414:             * <code>{@linkplain #isAutomatic isAutomatic}({@linkplain #REVERSE_AXIS})</code>
415:             * to {@code false}.
416:             *
417:             * @param reverse The reversal state of each axis. A {@code null} value means to
418:             *        reverse no axis. For performance reason, this method do not clone the
419:             *        supplied array.
420:             */
421:            public void setReverseAxis(final boolean[] reverse) {
422:                if (!Arrays.equals(reverseAxis, reverse)) {
423:                    reset();
424:                }
425:                this .reverseAxis = reverse;
426:                defined |= REVERSE_AXIS;
427:            }
428:
429:            /**
430:             * Reverses a single axis in user space. Invoking this methods <var>n</var> time
431:             * is equivalent to creating a boolean {@code reverse} array of the appropriate length,
432:             * setting {@code reverse[dimension] = true} for the <var>n</var> axis to be reversed,
433:             * and invoke <code>{@linkplain #setReverseAxis setReverseAxis}(reverse)</code>.
434:             */
435:            public void reverseAxis(final int dimension) {
436:                if (reverseAxis == null) {
437:                    final int length;
438:                    if (gridRange != null) {
439:                        length = gridRange.getDimension();
440:                    } else {
441:                        ensureNonNull("envelope", envelope);
442:                        length = envelope.getDimension();
443:                    }
444:                    reverseAxis = new boolean[length];
445:                }
446:                if (!reverseAxis[dimension]) {
447:                    reset();
448:                }
449:                reverseAxis[dimension] = true;
450:                defined |= REVERSE_AXIS;
451:            }
452:
453:            /**
454:             * Returns {@code true} if all properties designed by the specified bit mask
455:             * will be computed automatically.
456:             *
457:             * @param mask Any combinaison of {@link #REVERSE_AXIS} or {@link #SWAP_XY}.
458:             */
459:            public boolean isAutomatic(final int mask) {
460:                return (defined & mask) == 0;
461:            }
462:
463:            /**
464:             * Set all properties designed by the specified bit mask as automatic. Their
465:             * value will be computed automatically by the corresponding methods (e.g.
466:             * {@link #getReverseAxis}, {@link #getSwapXY}). By default, all properties
467:             * are automatic.
468:             *
469:             * @param mask Any combinaison of {@link #REVERSE_AXIS} or {@link #SWAP_XY}.
470:             */
471:            public void setAutomatic(final int mask) {
472:                defined &= ~mask;
473:            }
474:
475:            /**
476:             * Returns the coordinate system in use with the envelope.
477:             */
478:            private CoordinateSystem getCoordinateSystem() {
479:                if (envelope != null) {
480:                    final CoordinateReferenceSystem crs;
481:                    crs = envelope.getCoordinateReferenceSystem();
482:                    if (crs != null) {
483:                        return crs.getCoordinateSystem();
484:                    }
485:                }
486:                return null;
487:            }
488:
489:            /**
490:             * Creates a math transform using the information provided by setter methods.
491:             *
492:             * @throws IllegalStateException if the grid range or the envelope were not set.
493:             */
494:            public MathTransform createTransform() throws IllegalStateException {
495:                if (transform == null) {
496:                    final GridRange gridRange = getGridRange();
497:                    final Envelope userRange = getEnvelope();
498:                    final boolean swapXY = getSwapXY();
499:                    final boolean[] reverse = getReverseAxis();
500:                    final PixelInCell gridType = getGridType();
501:                    final int dimension = gridRange.getDimension();
502:                    /*
503:                     * Setup the multi-dimensional affine transform for use with OpenGIS.
504:                     * According OpenGIS specification, transforms must map pixel center.
505:                     * This is done by adding 0.5 to grid coordinates.
506:                     */
507:                    final double translate;
508:                    if (PixelInCell.CELL_CENTER.equals(gridType)) {
509:                        translate = 0.5;
510:                    } else if (PixelInCell.CELL_CORNER.equals(gridType)) {
511:                        translate = 0.0;
512:                    } else {
513:                        throw new IllegalStateException(Errors.format(
514:                                ErrorKeys.ILLEGAL_ARGUMENT_$2, "gridType",
515:                                gridType));
516:                    }
517:                    final Matrix matrix = MatrixFactory.create(dimension + 1);
518:                    for (int i = 0; i < dimension; i++) {
519:                        // NOTE: i is a dimension in the 'gridRange' space (source coordinates).
520:                        //       j is a dimension in the 'userRange' space (target coordinates).
521:                        int j = i;
522:                        if (swapXY && j <= 1) {
523:                            j = 1 - j;
524:                        }
525:                        double scale = userRange.getLength(j)
526:                                / gridRange.getLength(i);
527:                        double offset;
528:                        if (reverse == null || j >= reverse.length
529:                                || !reverse[j]) {
530:                            offset = userRange.getMinimum(j);
531:                        } else {
532:                            scale = -scale;
533:                            offset = userRange.getMaximum(j);
534:                        }
535:                        offset -= scale * (gridRange.getLower(i) - translate);
536:                        matrix.setElement(j, j, 0.0);
537:                        matrix.setElement(j, i, scale);
538:                        matrix.setElement(j, dimension, offset);
539:                    }
540:                    transform = ProjectiveTransform.create(matrix);
541:                }
542:                return transform;
543:            }
544:
545:            /**
546:             * Returns the math transform as a two-dimensional affine transform.
547:             *
548:             * @throws IllegalStateException if the math transform is not of the appropriate type.
549:             */
550:            public AffineTransform createAffineTransform()
551:                    throws IllegalStateException {
552:                final MathTransform transform = createTransform();
553:                if (transform instanceof  AffineTransform) {
554:                    return (AffineTransform) transform;
555:                }
556:                throw new IllegalStateException(Errors
557:                        .format(ErrorKeys.NOT_AN_AFFINE_TRANSFORM));
558:            }
559:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.