Source Code Cross Referenced for LocalizationGridTransform2D.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:         *   
005:         *   (C) 2003-2006, Geotools Project Managment Committee (PMC)
006:         *   (C) 2002, Institut de Recherche pour le Développement
007:         *
008:         *    This library is free software; you can redistribute it and/or
009:         *    modify it under the terms of the GNU Lesser General Public
010:         *    License as published by the Free Software Foundation; either
011:         *    version 2.1 of the License, or (at your option) any later version.
012:         *
013:         *    This library is distributed in the hope that it will be useful,
014:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
015:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
016:         *    Lesser General Public License for more details.
017:         */
018:        package org.geotools.referencing.operation.builder;
019:
020:        // J2SE dependencies
021:        import java.awt.Point;
022:        import java.awt.geom.AffineTransform;
023:        import java.awt.geom.NoninvertibleTransformException;
024:        import java.awt.geom.Point2D;
025:        import java.io.IOException;
026:        import java.io.ObjectInputStream;
027:        import java.io.Serializable;
028:        import java.util.Arrays;
029:
030:        // OpenGIS dependencies
031:        import org.opengis.parameter.ParameterValue;
032:        import org.opengis.parameter.ParameterValueGroup;
033:        import org.opengis.parameter.ParameterDescriptor;
034:        import org.opengis.parameter.ParameterDescriptorGroup;
035:        import org.opengis.parameter.ParameterNotFoundException;
036:        import org.opengis.referencing.FactoryException;
037:        import org.opengis.referencing.operation.MathTransform;
038:        import org.opengis.referencing.operation.MathTransform2D;
039:        import org.opengis.referencing.operation.Matrix;
040:        import org.opengis.referencing.operation.Transformation;
041:        import org.opengis.referencing.operation.TransformException;
042:
043:        // Geotools dependencies
044:        import org.geotools.metadata.iso.citation.Citations;
045:        import org.geotools.parameter.Parameter;
046:        import org.geotools.parameter.ParameterGroup;
047:        import org.geotools.referencing.NamedIdentifier;
048:        import org.geotools.referencing.operation.MathTransformProvider;
049:        import org.geotools.referencing.operation.matrix.Matrix2;
050:        import org.geotools.referencing.operation.transform.AbstractMathTransform;
051:        import org.geotools.util.logging.Logging;
052:        import org.geotools.resources.Utilities;
053:        import org.geotools.resources.i18n.Errors;
054:        import org.geotools.resources.i18n.ErrorKeys;
055:
056:        /**
057:         * Transform a set of coordinate points using a grid of localization.
058:         * Input coordinates are index in this two-dimensional array.
059:         * Those input coordinates (or index) should be in the range
060:         *
061:         * <code>x</sub>input</sub>&nbsp;=&nbsp;[0..width-1]</code> and
062:         * <code>y</sub>input</sub>&nbsp;=&nbsp;[0..height-1]</code> inclusive,
063:         *
064:         * where {@code width} and {@code height} are the number of columns and
065:         * rows in the grid of localization. Output coordinates are the values stored in
066:         * the grid of localization at the specified index. If input coordinates (index)
067:         * are non-integer values, then output coordinates are interpolated using a bilinear
068:         * interpolation. If input coordinates are outside the grid range, then output
069:         * coordinates are extrapolated.
070:         *
071:         * @since 2.0
072:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/builder/LocalizationGridTransform2D.java $
073:         * @version $Id: LocalizationGridTransform2D.java 29101 2008-02-06 12:11:19Z desruisseaux $
074:         * @author Remi Eve
075:         * @author Martin Desruisseaux
076:         *
077:         * @todo This class should extends {@link WarpTransform2D} and constructs a
078:         *       {@link javax.media.jai.WarpGrid} the first time the {@link WarpTransform2D#getWarp()}
079:         *       method is invoked (GEOT-522).
080:         */
081:        final class LocalizationGridTransform2D extends AbstractMathTransform
082:                implements  MathTransform2D, Serializable {
083:            /**
084:             * Serial number for interoperability with different versions.
085:             */
086:            private static final long serialVersionUID = 1067560328828441295L;
087:
088:            /**
089:             * Maximal number of iterations to try before to fail
090:             * during an inverse transformation.
091:             */
092:            private static final int MAX_ITER = 40;
093:
094:            /**
095:             * Set to {@code true} for a conservative (and maybe slower) algorithm
096:             * in {@link #inverseTransform}.
097:             */
098:            private static final boolean CONSERVATIVE = true;
099:
100:            /**
101:             * Set to {@code true} for forcing {@link #inverseTransform} to returns
102:             * a value instead of throwing an exception if the transform do not converge.
103:             * This is a temporary flag until we find why the inverse transform fails to
104:             * converge in some case.
105:             */
106:            private static final boolean MASK_NON_CONVERGENCE;
107:            static {
108:                String property;
109:                try {
110:                    property = System.getProperty(
111:                            "org.geotools.referencing.forceConvergence",
112:                            "false");
113:                } catch (SecurityException exception) {
114:                    // We are running in an applet.
115:                    property = "false";
116:                }
117:                MASK_NON_CONVERGENCE = property.equalsIgnoreCase("true");
118:            }
119:
120:            /**
121:             * <var>x</var> (usually longitude) offset relative to an entry.
122:             * Points are stored in {@link #grid} as {@code (x,y)} pairs.
123:             */
124:            static final int X_OFFSET = 0;
125:
126:            /**
127:             * <var>y</var> (usually latitude) offset relative to an entry.
128:             * Points are stored in {@link #grid} as {@code (x,y)} pairs.
129:             */
130:            static final int Y_OFFSET = 1;
131:
132:            /**
133:             * Length of an entry in the {@link #grid} array. This lenght
134:             * is equals to the dimension of output coordinate points.
135:             */
136:            static final int CP_LENGTH = 2;
137:
138:            /**
139:             * Number of grid's columns.
140:             */
141:            private final int width;
142:
143:            /**
144:             * Number of grid's rows.
145:             */
146:            private final int height;
147:
148:            /**
149:             * Grid of coordinate points.
150:             * Points are stored as {@code (x,y)} pairs.
151:             */
152:            private final double[] grid;
153:
154:            /**
155:             * A global affine transform for the whole grid.
156:             */
157:            private final AffineTransform global;
158:
159:            /**
160:             * The inverse math transform. Will be constructed only when first requested.
161:             */
162:            private transient MathTransform inverse;
163:
164:            /**
165:             * Constructs a localization grid using the specified data.
166:             *
167:             * @param width  Number of grid's columns.
168:             * @param height Number of grid's rows.
169:             * @param grid   The localization grid as an array of {@code (x,y)} coordinates.
170:             *               This array is not cloned; this is the caller's responsability to ensure
171:             *               that it will not be modified as long as this transformation is strongly
172:             *               reachable.
173:             * @param global A global affine transform for the whole grid.
174:             */
175:            protected LocalizationGridTransform2D(final int width,
176:                    final int height, final double[] grid,
177:                    final AffineTransform global) {
178:                this .width = width;
179:                this .height = height;
180:                this .grid = grid;
181:                this .global = global;
182:            }
183:
184:            /**
185:             * Returns the parameter descriptors for this math transform.
186:             */
187:            public ParameterDescriptorGroup getParameterDescriptors() {
188:                return Provider.PARAMETERS;
189:            }
190:
191:            /**
192:             * Returns the dimension of input points.
193:             */
194:            public int getSourceDimensions() {
195:                return 2;
196:            }
197:
198:            /**
199:             * Returns the dimension of output points.
200:             */
201:            public int getTargetDimensions() {
202:                return 2;
203:            }
204:
205:            /**
206:             * Tests if this transform is the identity transform.
207:             */
208:            public boolean isIdentity() {
209:                return false;
210:            }
211:
212:            /**
213:             * Gets the derivative of this transform at a point.
214:             */
215:            public Matrix derivative(final Point2D point) {
216:                final AffineTransform tr = new AffineTransform();
217:                getAffineTransform(point.getX(), point.getY(), tr);
218:                return new Matrix2(tr.getScaleX(), tr.getShearX(), tr
219:                        .getShearY(), tr.getScaleY());
220:            }
221:
222:            /** 
223:             * Transforme des coordonnées sources (généralement des index de pixels) en coordonnées
224:             * destinations (généralement des degrés de longitude et latitude). Les transformations
225:             * feront intervenir des interpolations linéaires si les coordonnées sources ne sont pas
226:             * entières.
227:             *
228:             * @param  srcPts  Points d'entrée.
229:             * @param  srcOff  Index du premier point d'entrée à transformer.
230:             * @param  dstPts  Points de sortie.
231:             * @param  dstOff  Index du premier point de sortie.
232:             * @param  numPts  Nombre de points à transformer.
233:             */
234:            public void transform(final float[] srcPts, int srcOff,
235:                    final float[] dstPts, int dstOff, int numPts) {
236:                transform(srcPts, null, srcOff, dstPts, null, dstOff, numPts);
237:            }
238:
239:            /** 
240:             * Transforme des coordonnées sources (généralement des index de pixels) en coordonnées
241:             * destinations (généralement des degrés de longitude et latitude). Les transformations
242:             * feront intervenir des interpolations linéaires si les coordonnées sources ne sont pas
243:             * entières.
244:             *
245:             * @param  srcPts  Points d'entrée.
246:             * @param  srcOff  Index du premier point d'entrée à transformer.
247:             * @param  dstPts  Points de sortie.
248:             * @param  dstOff  Index du premier point de sortie.
249:             * @param  numPts  Nombre de points à transformer.
250:             */
251:            public void transform(final double[] srcPts, int srcOff,
252:                    final double[] dstPts, int dstOff, int numPts) {
253:                transform(null, srcPts, srcOff, null, dstPts, dstOff, numPts);
254:            }
255:
256:            /**
257:             * Implementation of direct transformation.
258:             */
259:            private void transform(final float[] srcPts1,
260:                    final double[] srcPts2, int srcOff, final float[] dstPts1,
261:                    final double[] dstPts2, int dstOff, int numPts) {
262:                final int minCol = 0;
263:                final int minRow = 0;
264:                final int maxCol = width - 2;
265:                final int maxRow = height - 2;
266:                int postIncrement = 0;
267:                if (srcOff < dstOff) {
268:                    if ((srcPts2 != null) ? srcPts2 == dstPts2
269:                            : srcPts1 == dstPts1) {
270:                        srcOff += (numPts - 1) * 2;
271:                        dstOff += (numPts - 1) * 2;
272:                        postIncrement = -4;
273:                    }
274:                }
275:                while (--numPts >= 0) {
276:                    final double xi, yi;
277:                    if (srcPts2 != null) {
278:                        xi = srcPts2[srcOff++];
279:                        yi = srcPts2[srcOff++];
280:                    } else {
281:                        xi = srcPts1[srcOff++];
282:                        yi = srcPts1[srcOff++];
283:                    }
284:                    final int col = Math
285:                            .max(Math.min((int) xi, maxCol), minCol);
286:                    final int row = Math
287:                            .max(Math.min((int) yi, maxRow), minRow);
288:                    final int offset00 = (col + row * width) * CP_LENGTH;
289:                    final int offset01 = offset00 + CP_LENGTH * width; // Une ligne plus bas
290:                    final int offset10 = offset00 + CP_LENGTH; // Une colonne à droite
291:                    final int offset11 = offset01 + CP_LENGTH; // Une colonne à droite, une ligne plus bas
292:                    /*
293:                     * Interpole les coordonnées de destination        [00]--.(x0,y0)----[10]
294:                     * sur la ligne courante (x0,y0)  ainsi que         |                  |
295:                     * sur la ligne suivante (x1,y1).   Exemple         |    .(x,y)        |
296:                     * ci-contre:  les coordonnées sources sont         |                  |
297:                     * entre crochets, et les coordonnées de la        [01]--.(x1,y1)----[11]
298:                     * sortie (à calculer) sont entre parenthèses.
299:                     */
300:                    final double x0 = linearInterpolation(col + 0,
301:                            grid[offset00 + X_OFFSET], col + 1, grid[offset10
302:                                    + X_OFFSET], xi);
303:                    final double y0 = linearInterpolation(col + 0,
304:                            grid[offset00 + Y_OFFSET], col + 1, grid[offset10
305:                                    + Y_OFFSET], xi);
306:                    final double x1 = linearInterpolation(col + 0,
307:                            grid[offset01 + X_OFFSET], col + 1, grid[offset11
308:                                    + X_OFFSET], xi);
309:                    final double y1 = linearInterpolation(col + 0,
310:                            grid[offset01 + Y_OFFSET], col + 1, grid[offset11
311:                                    + Y_OFFSET], xi);
312:                    /*
313:                     * Interpole maintenant les coordonnées (x,y) entre les deux lignes.
314:                     */
315:                    final double xf = linearInterpolation(row, x0, row + 1, x1,
316:                            yi);
317:                    final double yf = linearInterpolation(row, y0, row + 1, y1,
318:                            yi);
319:                    if (dstPts2 != null) {
320:                        dstPts2[dstOff++] = xf;
321:                        dstPts2[dstOff++] = yf;
322:                    } else {
323:                        dstPts1[dstOff++] = (float) xf;
324:                        dstPts1[dstOff++] = (float) yf;
325:                    }
326:                    srcOff += postIncrement;
327:                    dstOff += postIncrement;
328:                    if (false) {
329:                        final java.io.PrintStream out = System.out;
330:                        out.print("TD  ==> xi : ");
331:                        out.print(xi);
332:                        out.print(" / yi : ");
333:                        out.print(yi);
334:                        out.print("  --->  xo : ");
335:                        out.print(xf);
336:                        out.print(" / yo : ");
337:                        out.println(yf);
338:                    }
339:                }
340:            }
341:
342:            /**
343:             * Interpole/extrapole entre deux points.
344:             *
345:             * @param   x1  Coordonnee <var>x</var> du premier point.
346:             * @param   y1  Coordonnee <var>y</var> du premier point.
347:             * @param   x2  Coordonnee <var>x</var> du second point.
348:             * @param   y2  Coordonnee <var>y</var> du second point.
349:             * @param   x   Position <var>x</var> à laquelle calculer la valeur de <var>y</var>.
350:             * @return      La valeur <var>y</var> interpolée entre les deux points.
351:             */
352:            private static double linearInterpolation(final double x1,
353:                    final double y1, final double x2, final double y2,
354:                    final double x) {
355:                return y1 + (y2 - y1) / (x2 - x1) * (x - x1);
356:            }
357:
358:            /**
359:             * Retourne une approximation de la transformation affine à la position indiquée.
360:             *
361:             * @param  col  Coordonnee <var>x</var> du point.
362:             * @param  row  Coordonnee <var>y</var> du point.
363:             * @param dest  Matrice dans laquelle écrire la transformation affine.
364:             */
365:            private void getAffineTransform(double x, double y,
366:                    final AffineTransform dest) {
367:                int col = (int) x;
368:                int row = (int) y;
369:                if (col > width - 2)
370:                    col = width - 2;
371:                if (row > height - 2)
372:                    row = height - 2;
373:                if (col < 0)
374:                    col = 0;
375:                if (row < 0)
376:                    row = 0;
377:                final int sgnCol;
378:                final int sgnRow;
379:                if (x - col > 0.5) {
380:                    sgnCol = -1;
381:                    col++;
382:                } else
383:                    sgnCol = +1;
384:                if (y - row > 0.5) {
385:                    sgnRow = -1;
386:                    row++;
387:                } else
388:                    sgnRow = +1;
389:                /*
390:                 * Le calcul de la transformation affine  comprend 6        P00------P10
391:                 * inconnues. Sa solution recquiert donc 6 équations.        |        |
392:                 * Nous les obtenons en utilisant 3 points,   chaque         |        |
393:                 * points ayant 2 coordonnées. Voir exemple ci-contre:      P01----(ignoré)
394:                 */
395:                final int offset00 = (col + row * width) * CP_LENGTH;
396:                final int offset01 = offset00 + sgnRow * CP_LENGTH * width;
397:                final int offset10 = offset00 + sgnCol * CP_LENGTH;
398:                x = grid[offset00 + X_OFFSET];
399:                y = grid[offset00 + Y_OFFSET];
400:                final double dxCol = (grid[offset10 + X_OFFSET] - x) * sgnCol;
401:                final double dyCol = (grid[offset10 + Y_OFFSET] - y) * sgnCol;
402:                final double dxRow = (grid[offset01 + X_OFFSET] - x) * sgnRow;
403:                final double dyRow = (grid[offset01 + Y_OFFSET] - y) * sgnRow;
404:                dest.setTransform(dxCol, dyCol, dxRow, dyRow, x - dxCol * col
405:                        - dxRow * row, y - dyCol * col - dyRow * row);
406:                /*
407:                 * Si l'on transforme les 3 points qui ont servit à déterminer la transformation
408:                 * affine, on devrait obtenir un résultat identique (aux erreurs d'arrondissement
409:                 * près) peu importe que l'on utilise la transformation affine ou la grille de
410:                 * localisation.
411:                 */
412:                assert distance(new Point(col, row), dest) < 1E-5;
413:                assert distance(new Point(col + sgnCol, row), dest) < 1E-5;
414:                assert distance(new Point(col, row + sgnRow), dest) < 1E-5;
415:            }
416:
417:            /**
418:             * Transform a point using the localization grid, transform it back using the inverse
419:             * of the specified affine transform, and returns the distance between the source and
420:             * the resulting point. This is used for assertions only.
421:             *
422:             * @param  index The source point to test.
423:             * @param  tr The affine transform to test.
424:             * @return The distance in grid coordinate. Should be close to 0.
425:             */
426:            private double distance(final Point2D index,
427:                    final AffineTransform tr) {
428:                try {
429:                    Point2D geoCoord = transform(index, null);
430:                    geoCoord = tr.inverseTransform(geoCoord, geoCoord);
431:                    return geoCoord.distance(index);
432:                } catch (TransformException exception) {
433:                    // Should not happen
434:                    throw new AssertionError(exception);
435:                } catch (NoninvertibleTransformException exception) {
436:                    // Not impossible. What should we do? Open question...
437:                    throw new AssertionError(exception);
438:                }
439:            }
440:
441:            /**
442:             * Apply the inverse transform to a set of points. More specifically, this method transform
443:             * "real world" coordinates to grid coordinates. This method use an iterative algorithm for
444:             * that purpose. A {@link TransformException} is thrown in the computation do not converge.
445:             * The algorithm applied by this method and its callers is:
446:             *
447:             * <ul>
448:             *   <li>Transform the first point using a "global" affine transform (i.e. the affine
449:             *       transformed computed using the "least squares" method in LocalizationGrid).
450:             *       Other points will be transformed using the last successful affine transform,
451:             *       since we assume that the points to transform are close to each other.</li>
452:             *
453:             *   <li>Next, compute a local affine transform and use if for transforming the point
454:             *       again. Recompute again the local affine transform and continue until the cell
455:             *       (x0,y0) doesn't change.</li>
456:             * </ul>
457:             *
458:             * @param source The "real world" coordinate to transform.
459:             * @param target A pre-allocated destination point. <strong>This point
460:             *               can't be the same than {@code source}!<strong>
461:             * @param tr In input, the affine transform to use for the first step.
462:             *        In output, the last affine transform used for the transformation.
463:             *
464:             */
465:            final void inverseTransform(final Point2D source,
466:                    final Point2D.Double target, final AffineTransform tr)
467:                    throws TransformException {
468:                if (CONSERVATIVE) {
469:                    // In an optimal approach, we should reuse the same affine transform than the one used
470:                    // in the last transformation, since it is likely to converge faster for a point close
471:                    // to the previous one. However, it may lead to strange and hard to predict
472:                    // discontinuity in transformations.
473:                    tr.setTransform(global);
474:                }
475:                try {
476:                    tr.inverseTransform(source, target);
477:                    int previousX = (int) target.x;
478:                    int previousY = (int) target.y;
479:                    for (int iter = 0; iter < MAX_ITER; iter++) {
480:                        getAffineTransform(target.x, target.y, tr);
481:                        tr.inverseTransform(source, target);
482:                        final int ix = (int) target.x;
483:                        final int iy = (int) target.y;
484:                        if (previousX == ix && previousY == iy) {
485:                            // Computation converged.
486:                            if (target.x >= 0 && target.x < width
487:                                    && target.y >= 0 && target.y < height) {
488:                                // Point is inside the grid. Check the precision.
489:                                assert transform(target, null).distanceSq(
490:                                        source) < 1E-3 : target;
491:                            } else {
492:                                // Point is outside the grid. Use the global transform for uniformity.
493:                                inverseTransform(source, target);
494:                            }
495:                            return;
496:                        }
497:                        previousX = ix;
498:                        previousY = iy;
499:                    }
500:                    /*
501:                     * No convergence found in the "ordinary" loop. The following code checks if
502:                     * we are stuck in a never-ending loop. If yes, then it will try to minimize
503:                     * the following function:
504:                     *
505:                     *     {@code transform(target).distance(source)}.
506:                     */
507:                    final int x0 = previousX;
508:                    final int y0 = previousY;
509:                    global.inverseTransform(source, target);
510:                    double x, y;
511:                    double bestX = x = target.x;
512:                    double bestY = y = target.y;
513:                    double minSq = Double.POSITIVE_INFINITY;
514:                    for (int iter = 1 - MAX_ITER; iter < MAX_ITER; iter++) {
515:                        previousX = (int) x;
516:                        previousY = (int) y;
517:                        getAffineTransform(x, y, tr);
518:                        tr.inverseTransform(source, target);
519:                        x = target.x;
520:                        y = target.y;
521:                        final int ix = (int) x;
522:                        final int iy = (int) y;
523:                        if (previousX == ix && previousY == iy) {
524:                            // Computation converged.
525:                            assert iter >= 0;
526:                            if (x >= 0 && x < width && y >= 0 && y < height) {
527:                                // Point is inside the grid. Check the precision.
528:                                assert transform(target, null).distanceSq(
529:                                        source) < 1E-3 : target;
530:                            } else {
531:                                // Point is outside the grid. Use the global transform for uniformity.
532:                                inverseTransform(source, target);
533:                            }
534:                            return;
535:                        }
536:                        if (iter == 0) {
537:                            assert x0 == ix && y0 == iy;
538:                        } else if (x0 == ix && y0 == iy) {
539:                            // Loop detected.
540:                            if (bestX >= 0 && bestX < width && bestY >= 0
541:                                    && bestY < height) {
542:                                target.x = bestX;
543:                                target.y = bestY;
544:                            } else {
545:                                inverseTransform(source, target);
546:                            }
547:                            return;
548:                        }
549:                        transform(target, target);
550:                        final double distanceSq = target.distanceSq(source);
551:                        if (distanceSq < minSq) {
552:                            minSq = distanceSq;
553:                            bestX = x;
554:                            bestY = y;
555:                        }
556:                    }
557:                    /*
558:                     * The transformation didn't converge, and no loop has been found.
559:                     * If the following block is enabled (true), then the best point
560:                     * will be returned. It may not be the best approach since we don't
561:                     * know if this point is valid. Otherwise, an exception is thrown.
562:                     */
563:                    if (MASK_NON_CONVERGENCE) {
564:                        Logging.getLogger("org.geotools.gc").fine(
565:                                "No convergence");
566:                        if (bestX >= 0 && bestX < width && bestY >= 0
567:                                && bestY < height) {
568:                            target.x = bestX;
569:                            target.y = bestY;
570:                        } else {
571:                            inverseTransform(source, target);
572:                        }
573:                        return;
574:                    }
575:                } catch (NoninvertibleTransformException exception) {
576:                    final TransformException e;
577:                    e = new TransformException(Errors
578:                            .format(ErrorKeys.NONINVERTIBLE_TRANSFORM));
579:                    e.initCause(exception);
580:                    throw e;
581:                }
582:                throw new TransformException(Errors
583:                        .format(ErrorKeys.NO_CONVERGENCE));
584:            }
585:
586:            /**
587:             * Inverse transforms a point using the {@link #global} affine transform, and
588:             * make sure that the result point is outside the grid. This method is used
589:             * for the transformation of a point which shouldn't be found in the grid.
590:             *
591:             * @param  source The source coordinate point.
592:             * @param  target The target coordinate point (should not be {@code null}).
593:             * @throws NoninvertibleTransformException if the transform is non-invertible.
594:             *
595:             * @todo Current implementation project an inside point on the nearest border.
596:             *       Could we do something better?
597:             */
598:            private void inverseTransform(final Point2D source,
599:                    final Point2D.Double target)
600:                    throws NoninvertibleTransformException {
601:                if (global.inverseTransform(source, target) != target) {
602:                    throw new AssertionError(); // Should not happen.
603:                }
604:                double x = target.x;
605:                double y = target.y;
606:                if (x >= 0 && x < width && y >= 0 && y < height) {
607:                    // Project on the nearest border. TODO: Could we do something better here?
608:                    x -= 0.5 * width;
609:                    y -= 0.5 * height;
610:                    if (Math.abs(x) < Math.abs(y)) {
611:                        target.x = x > 0 ? width : -1;
612:                    } else {
613:                        target.y = y > 0 ? height : -1;
614:                    }
615:                }
616:            }
617:
618:            /** 
619:             * Returns the inverse transform.
620:             */
621:            public MathTransform inverse() {
622:                if (inverse == null) {
623:                    inverse = new Inverse();
624:                }
625:                return inverse;
626:            }
627:
628:            /**
629:             * The inverse transform. This inner class is the inverse of the enclosing math transform.
630:             *
631:             * @version $Id: LocalizationGridTransform2D.java 29101 2008-02-06 12:11:19Z desruisseaux $
632:             * @author Martin Desruisseaux
633:             */
634:            private final class Inverse extends AbstractMathTransform.Inverse
635:                    implements  MathTransform2D, Serializable {
636:                /**
637:                 * Serial number for interoperability with different versions.
638:                 */
639:                private static final long serialVersionUID = 4876426825123740986L;
640:
641:                /**
642:                 * Default constructor.
643:                 */
644:                public Inverse() {
645:                    LocalizationGridTransform2D.this .super ();
646:                }
647:
648:                /**
649:                 * Transform a "real world" coordinate into a grid coordinate.
650:                 */
651:                public Point2D transform(final Point2D ptSrc,
652:                        final Point2D ptDst) throws TransformException {
653:                    final AffineTransform tr = new AffineTransform(global);
654:                    if (ptDst == null) {
655:                        final Point2D.Double target = new Point2D.Double();
656:                        inverseTransform(ptSrc, target, tr);
657:                        return target;
658:                    }
659:                    if (ptDst != ptSrc && (ptDst instanceof  Point2D.Double)) {
660:                        inverseTransform(ptSrc, (Point2D.Double) ptDst, tr);
661:                        return ptDst;
662:                    }
663:                    final Point2D.Double target = new Point2D.Double();
664:                    inverseTransform(ptSrc, target, tr);
665:                    ptDst.setLocation(target);
666:                    return ptDst;
667:                }
668:
669:                /**
670:                 * Apply the inverse transform to a set of points. More specifically, this method transform
671:                 * "real world" coordinates to grid coordinates. This method use an iterative algorithm for
672:                 * that purpose. A {@link TransformException} is thrown in the computation do not converge.
673:                 *
674:                 * @param srcPts the array containing the source point coordinates.
675:                 * @param srcOff the offset to the first point to be transformed in the source array.
676:                 * @param dstPts the array into which the transformed point coordinates are returned.
677:                 *               May be the same than {@code srcPts}.
678:                 * @param dstOff the offset to the location of the first transformed
679:                 *               point that is stored in the destination array.
680:                 * @param numPts the number of point objects to be transformed.
681:                 * @throws TransformException if a point can't be transformed.
682:                 */
683:                public void transform(final float[] srcPts, int srcOff,
684:                        final float[] dstPts, int dstOff, int numPts)
685:                        throws TransformException {
686:                    int postIncrement = 0;
687:                    if (srcPts == dstPts && srcOff < dstOff) {
688:                        srcOff += (numPts - 1) * 2;
689:                        dstOff += (numPts - 1) * 2;
690:                        postIncrement = -4;
691:                    }
692:                    final Point2D.Double source = new Point2D.Double();
693:                    final Point2D.Double target = new Point2D.Double();
694:                    final AffineTransform tr = new AffineTransform(global);
695:                    while (--numPts >= 0) {
696:                        source.x = srcPts[srcOff++];
697:                        source.y = srcPts[srcOff++];
698:                        inverseTransform(source, target, tr);
699:                        dstPts[dstOff++] = (float) target.x;
700:                        dstPts[dstOff++] = (float) target.y;
701:                        srcOff += postIncrement;
702:                        dstOff += postIncrement;
703:                    }
704:                }
705:
706:                /**
707:                 * Apply the inverse transform to a set of points. More specifically, this method transform
708:                 * "real world" coordinates to grid coordinates. This method use an iterative algorithm for
709:                 * that purpose. A {@link TransformException} is thrown in the computation do not converge.
710:                 *
711:                 * @param srcPts the array containing the source point coordinates.
712:                 * @param srcOff the offset to the first point to be transformed in the source array.
713:                 * @param dstPts the array into which the transformed point coordinates are returned.
714:                 *               May be the same than {@code srcPts}.
715:                 * @param dstOff the offset to the location of the first transformed
716:                 *               point that is stored in the destination array.
717:                 * @param numPts the number of point objects to be transformed.
718:                 * @throws TransformException if a point can't be transformed.
719:                 */
720:                public void transform(final double[] srcPts, int srcOff,
721:                        final double[] dstPts, int dstOff, int numPts)
722:                        throws TransformException {
723:                    int postIncrement = 0;
724:                    if (srcPts == dstPts && srcOff < dstOff) {
725:                        srcOff += (numPts - 1) * 2;
726:                        dstOff += (numPts - 1) * 2;
727:                        postIncrement = -4;
728:                    }
729:                    final Point2D.Double source = new Point2D.Double();
730:                    final Point2D.Double target = new Point2D.Double();
731:                    final AffineTransform tr = new AffineTransform(global);
732:                    while (--numPts >= 0) {
733:                        source.x = srcPts[srcOff++];
734:                        source.y = srcPts[srcOff++];
735:                        inverseTransform(source, target, tr);
736:                        dstPts[dstOff++] = target.x;
737:                        dstPts[dstOff++] = target.y;
738:                        srcOff += postIncrement;
739:                        dstOff += postIncrement;
740:                    }
741:                }
742:
743:                /**
744:                 * Restore reference to this object after deserialization.
745:                 */
746:                private void readObject(ObjectInputStream in)
747:                        throws IOException, ClassNotFoundException {
748:                    in.defaultReadObject();
749:                    LocalizationGridTransform2D.this .inverse = this ;
750:                }
751:            }
752:
753:            /**
754:             * Returns a hash value for this transform.
755:             */
756:            public int hashCode() {
757:                return (int) serialVersionUID ^ super .hashCode()
758:                        ^ global.hashCode();
759:            }
760:
761:            /**
762:             * Compare this transform with the specified object for equality.
763:             */
764:            public boolean equals(final Object object) {
765:                if (super .equals(object)) {
766:                    final LocalizationGridTransform2D that = (LocalizationGridTransform2D) object;
767:                    return this .width == that.width
768:                            && this .height == that.height
769:                            && Utilities.equals(this .global, that.global)
770:                            && Arrays.equals(this .grid, that.grid);
771:                }
772:                return false;
773:            }
774:
775:            /**
776:             * The provider for the {@link LocalizationGridTransform2D}.
777:             *
778:             * @version $Id: LocalizationGridTransform2D.java 29101 2008-02-06 12:11:19Z desruisseaux $
779:             * @author Martin Desruisseaux
780:             *
781:             * @todo Not yet fully implemented. Once it is implemented, we need to add a
782:             *       getParameterValues() method in LocalizationGridTransform2D.
783:             */
784:            private static class Provider extends MathTransformProvider {
785:                /** Serial number for interoperability with different versions. */
786:                private static final long serialVersionUID = -8263439392080019340L;
787:
788:                /**
789:                 * The parameters group.
790:                 */
791:                static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(
792:                        new NamedIdentifier[] { new NamedIdentifier(
793:                                Citations.GEOTOOLS, "WarpPolynomial") },
794:                        new ParameterDescriptor[] {});
795:
796:                /**
797:                 * Create a provider for warp transforms.
798:                 */
799:                public Provider() {
800:                    super (2, 2, PARAMETERS);
801:                }
802:
803:                /**
804:                 * Returns the operation type.
805:                 */
806:                public Class getOperationType() {
807:                    return Transformation.class;
808:                }
809:
810:                /**
811:                 * Creates a warp transform from the specified group of parameter values.
812:                 *
813:                 * @param  values The group of parameter values.
814:                 * @return The created math transform.
815:                 * @throws ParameterNotFoundException if a required parameter was not found.
816:                 */
817:                protected MathTransform createMathTransform(
818:                        final ParameterValueGroup values)
819:                        throws ParameterNotFoundException, FactoryException {
820:                    throw new FactoryException("Not yet implemented");
821:                }
822:            }
823:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.