Source Code Cross Referenced for WarpTransform2D.java in  » GIS » GeoTools-2.4.1 » org » geotools » referencing » operation » transform » 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.transform 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *   
005:         *   (C) 2005-2006, Geotools Project Managment Committee (PMC)
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.transform;
018:
019:        // J2SE dependencies and extensions
020:        import java.awt.geom.Point2D;
021:        import java.awt.geom.Rectangle2D;
022:        import java.io.Serializable;
023:        import javax.units.Unit;
024:
025:        // JAI dependencies
026:        import javax.media.jai.Warp;
027:        import javax.media.jai.WarpAffine;
028:        import javax.media.jai.WarpQuadratic;
029:        import javax.media.jai.WarpCubic;
030:        import javax.media.jai.WarpPolynomial;
031:        import javax.media.jai.WarpGeneralPolynomial;
032:
033:        // OpenGIS dependencies
034:        import org.opengis.util.InternationalString;
035:        import org.opengis.parameter.ParameterValue;
036:        import org.opengis.parameter.ParameterValueGroup;
037:        import org.opengis.parameter.ParameterDescriptor;
038:        import org.opengis.parameter.ParameterDescriptorGroup;
039:        import org.opengis.parameter.ParameterNotFoundException;
040:        import org.opengis.referencing.operation.MathTransform;
041:        import org.opengis.referencing.operation.MathTransform2D;
042:        import org.opengis.referencing.operation.NoninvertibleTransformException;
043:        import org.opengis.referencing.operation.Transformation;
044:
045:        // Geotools dependencies
046:        import org.geotools.resources.Utilities;
047:        import org.geotools.referencing.NamedIdentifier;
048:        import org.geotools.referencing.operation.MathTransformProvider;
049:        import org.geotools.metadata.iso.citation.Citations;
050:        import org.geotools.parameter.DefaultParameterDescriptor;
051:        import org.geotools.parameter.ParameterGroup;
052:        import org.geotools.parameter.Parameter;
053:        import org.geotools.resources.XArray;
054:        import org.geotools.resources.i18n.Vocabulary;
055:        import org.geotools.resources.i18n.VocabularyKeys;
056:
057:        /**
058:         * Wraps an arbitrary {@link Warp} object as a {@linkplain MathTransform2D two-dimensional transform}.
059:         * Calls to {@linkplain #transform(float[],int,float[],int,int) transform} methods are forwarded to
060:         * the {@link Warp#warpPoint(int,int,float[]) warpPoint} method, or something equivalent. This
061:         * implies that source coordinates may be rounded to nearest integers before the transformation
062:         * is applied.
063:         * <p>
064:         * This transform is typically used with {@linkplain org.geotools.coverage.processing.operation.Resample
065:         * grid coverage "Resample" operation} for reprojecting an image. Source and destination coordinates
066:         * are usually pixel coordinates in source and target image, which is why this transform may use
067:         * integer arithmetic.
068:         * <p>
069:         * This math transform can be created alone (by invoking its public constructors directly), or it
070:         * can be created by a factory like {@link LocalizationGrid}.
071:         * <p>
072:         * For more information on image warp, see
073:         * <A HREF="http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/Geom-image-manip.doc.html">Geometric
074:         * Image Manipulation</A> in the <cite>Programming in Java Advanced Imaging</cite> guide.
075:         *
076:         * @since 2.1
077:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/transform/WarpTransform2D.java $
078:         * @version $Id: WarpTransform2D.java 29101 2008-02-06 12:11:19Z desruisseaux $
079:         * @author Martin Desruisseaux
080:         * @author Alessio Fabiani
081:         *
082:         * @see LocalizationGrid#getPolynomialTransform(int)
083:         * @see Warp
084:         * @see javax.media.jai.WarpOpImage
085:         * @see javax.media.jai.operator.WarpDescriptor
086:         */
087:        public class WarpTransform2D extends AbstractMathTransform implements 
088:                MathTransform2D, Serializable {
089:            /**
090:             * Serial number for interoperability with different versions.
091:             */
092:            private static final long serialVersionUID = -7949539694656719923L;
093:
094:            /**
095:             * The maximal polynomial degree allowed.
096:             *
097:             * @since 2.4
098:             */
099:            public static final int MAX_DEGREE = 7;
100:
101:            /**
102:             * The warp object. Transformations will be applied using the
103:             * {@link Warp#warpPoint(int,int,float[]) warpPoint} method or something equivalent.
104:             */
105:            private final Warp warp;
106:
107:            /**
108:             * The inverse math transform.
109:             */
110:            private final WarpTransform2D inverse;
111:
112:            /**
113:             * Constructs a warp transform that approximatively maps the given source coordinates to the
114:             * given destination coordinates. The transformation is performed using some polynomial warp
115:             * with the degree supplied in argument. The number of points required for each degree of warp
116:             * are as follows:
117:             * <p>
118:             * <table>
119:             * <tr><th>Degree of Warp</th><th>Number of Points</th></tr>
120:             * <tr><td>1</td><td>3</td></tr>
121:             * <tr><td>2</td><td>6</td></tr>
122:             * <tr><td>3</td><td>10</td></tr>
123:             * <tr><td>4</td><td>15</td></tr>
124:             * <tr><td>5</td><td>21</td></tr>
125:             * <tr><td>6</td><td>28</td></tr>
126:             * <tr><td>7</td><td>36</td></tr>
127:             * </table>
128:             *
129:             * @param srcCoords Source coordinates.
130:             * @param dstCoords Destination coordinates.
131:             * @param degree    The desired degree of the warp polynomials.
132:             */
133:            public WarpTransform2D(final Point2D[] srcCoords,
134:                    final Point2D[] dstCoords, final int degree) {
135:                this (null, srcCoords, 0, null, dstCoords, 0, Math.min(
136:                        srcCoords.length, dstCoords.length), degree);
137:            }
138:
139:            /**
140:             * Constructs a warp transform that approximatively maps the given source coordinates to the
141:             * given destination coordinates. The transformation is performed using some polynomial warp
142:             * with the degree supplied in argument.
143:             *
144:             * @param srcBounds Bounding box of source coordinates, or {@code null} if unknow.
145:             * @param srcCoords Source coordinates.
146:             * @param srcOffset The inital entry of {@code srcCoords} to be used.
147:             * @param dstBounds Bounding box of destination coordinates, or {@code null} if unknow.
148:             * @param dstCoords Destination coordinates.
149:             * @param dstOffset The inital entry of {@code destCoords} to be used.
150:             * @param numCoords The number of coordinates from {@code srcCoords} and {@code destCoords}
151:             *                  to be used.
152:             * @param degree    The desired degree of the warp polynomials.
153:             */
154:            public WarpTransform2D(final Rectangle2D srcBounds,
155:                    final Point2D[] srcCoords, final int srcOffset,
156:                    final Rectangle2D dstBounds, final Point2D[] dstCoords,
157:                    final int dstOffset, final int numCoords, final int degree) {
158:                this (srcBounds, toFloat(srcCoords, srcOffset, numCoords), 0,
159:                        dstBounds, toFloat(dstCoords, dstOffset, numCoords), 0,
160:                        numCoords, degree, false);
161:            }
162:
163:            /**
164:             * Converts an array of points into an array of floats.
165:             * This is used internally for the above constructor only.
166:             */
167:            private static float[] toFloat(final Point2D[] points, int offset,
168:                    final int numCoords) {
169:                final float[] array = new float[numCoords * 2];
170:                for (int i = 0; i < array.length;) {
171:                    final Point2D point = points[offset++];
172:                    array[i++] = (float) point.getX();
173:                    array[i++] = (float) point.getY();
174:                }
175:                return array;
176:            }
177:
178:            /**
179:             * Constructs a warp transform that approximatively maps the given source coordinates to the
180:             * given destination coordinates. The transformation is performed using some polynomial warp
181:             * with the degree supplied in argument.
182:             *
183:             * @param srcBounds Bounding box of source coordinates, or {@code null} if unknow.
184:             * @param srcCoords Source coordinates with <var>x</var> and <var>y</var> alternating.
185:             * @param srcOffset The inital entry of {@code srcCoords} to be used.
186:             * @param dstBounds Bounding box of destination coordinates, or {@code null} if unknow.
187:             * @param dstCoords Destination coordinates with <var>x</var> and <var>y</var> alternating.
188:             * @param dstOffset The inital entry of {@code destCoords} to be used.
189:             * @param numCoords The number of coordinates from {@code srcCoords} and {@code destCoords}
190:             *                  to be used.
191:             * @param degree    The desired degree of the warp polynomials.
192:             */
193:            public WarpTransform2D(final Rectangle2D srcBounds,
194:                    final float[] srcCoords, final int srcOffset,
195:                    final Rectangle2D dstBounds, final float[] dstCoords,
196:                    final int dstOffset, final int numCoords, final int degree) {
197:                this (srcBounds, srcCoords, srcOffset, dstBounds, dstCoords,
198:                        dstOffset, numCoords, degree, true);
199:            }
200:
201:            /**
202:             * Work around for a bug in WarpPolynomial.createWarp(...). This constructor should move in
203:             * the one above when the {@code cloneCoords} argument will no longer be needed (after the
204:             * JAI bug get fixed).
205:             */
206:            private WarpTransform2D(final Rectangle2D srcBounds,
207:                    float[] srcCoords, int srcOffset,
208:                    final Rectangle2D dstBounds, float[] dstCoords,
209:                    int dstOffset, final int numCoords, final int degree,
210:                    boolean cloneCoords) {
211:                final float preScaleX, preScaleY, postScaleX, postScaleY;
212:                if (srcBounds != null) {
213:                    preScaleX = (float) srcBounds.getWidth();
214:                    preScaleY = (float) srcBounds.getHeight();
215:                } else {
216:                    preScaleX = getWidth(srcCoords, srcOffset, numCoords);
217:                    preScaleY = getWidth(srcCoords, srcOffset + 1, numCoords);
218:                }
219:                if (dstBounds != null) {
220:                    postScaleX = (float) dstBounds.getWidth();
221:                    postScaleY = (float) dstBounds.getHeight();
222:                } else {
223:                    postScaleX = getWidth(dstCoords, dstOffset, numCoords);
224:                    postScaleY = getWidth(dstCoords, dstOffset + 1, numCoords);
225:                }
226:                /*
227:                 * Workaround for a bug in WarpPolynomial.create(...): the later scale coordinates
228:                 * according the scale values, but the 'preScale' and 'postScale' are interchanged.
229:                 * When JAI bug will be fixed, delete all the following block until the next comment.
230:                 */
231:                final double scaleX = preScaleX / postScaleX;
232:                final double scaleY = preScaleY / postScaleY;
233:                if (scaleX != 1 || scaleY != 1) {
234:                    final int n = numCoords * 2;
235:                    if (cloneCoords) {
236:                        float[] o;
237:                        o = srcCoords;
238:                        srcCoords = new float[n];
239:                        System.arraycopy(o, srcOffset, srcCoords, 0, n);
240:                        srcOffset = 0;
241:                        o = dstCoords;
242:                        dstCoords = new float[n];
243:                        System.arraycopy(o, dstOffset, dstCoords, 0, n);
244:                        dstOffset = 0;
245:                    }
246:                    for (int i = 0; i < n;) {
247:                        srcCoords[srcOffset + i] /= scaleX;
248:                        dstCoords[dstOffset + i++] *= scaleX;
249:                        srcCoords[srcOffset + i] /= scaleY;
250:                        dstCoords[dstOffset + i++] *= scaleY;
251:                    }
252:                }
253:                /*
254:                 * Note: Warp semantic (transforms coordinates from destination to source) is the
255:                 *       opposite of MathTransform semantic (transforms coordinates from source to
256:                 *       destination). We have to interchange source and destination arrays for the
257:                 *       direct transform.
258:                 */
259:                warp = WarpPolynomial.createWarp(dstCoords, dstOffset,
260:                        srcCoords, srcOffset, numCoords, 1 / preScaleX,
261:                        1 / preScaleY, postScaleX, postScaleY, degree);
262:                inverse = new WarpTransform2D(WarpPolynomial.createWarp(
263:                        srcCoords, srcOffset, dstCoords, dstOffset, numCoords,
264:                        1 / postScaleX, 1 / postScaleY, preScaleX, preScaleY,
265:                        degree), this );
266:            }
267:
268:            /**
269:             * Returns the maximum minus the minimum ordinate int the specifie array.
270:             * This is used internally for the above constructor only.
271:             */
272:            private static float getWidth(final float[] array, int offset,
273:                    int num) {
274:                float min = Float.POSITIVE_INFINITY;
275:                float max = Float.NEGATIVE_INFINITY;
276:                while (--num >= 0) {
277:                    float value = array[offset];
278:                    if (value < min)
279:                        min = value;
280:                    if (value > max)
281:                        max = value;
282:                    offset += 2;
283:                }
284:                return max - min;
285:            }
286:
287:            /**
288:             * Constructs a transform using the specified warp object. Transformations will be applied
289:             * using the {@link Warp#warpPoint(int,int,float[]) warpPoint} method or something equivalent.
290:             *
291:             * @param warp    The image warp to wrap into a math transform.
292:             * @param inverse An image warp to uses for the {@linkplain #inverse inverse transform},
293:             *                or {@code null} in none.
294:             */
295:            protected WarpTransform2D(final Warp warp, final Warp inverse) {
296:                ensureNonNull("warp", warp);
297:                this .warp = warp;
298:                this .inverse = (inverse != null) ? new WarpTransform2D(inverse,
299:                        this ) : null;
300:            }
301:
302:            /**
303:             * Constructs a transform using the specified warp object. This private constructor is used
304:             * for the construction of {@link #inverse} transform only.
305:             */
306:            private WarpTransform2D(final Warp warp,
307:                    final WarpTransform2D inverse) {
308:                this .warp = warp;
309:                this .inverse = inverse;
310:            }
311:
312:            /**
313:             * Returns a transform using the specified warp object. Transformations will be applied
314:             * using the {@link Warp#warpPoint(int,int,float[]) warpPoint} method or something equivalent.
315:             *
316:             * @param warp The image warp to wrap into a math transform.
317:             */
318:            public static MathTransform2D create(final Warp warp) {
319:                if (warp instanceof  WarpAdapter) {
320:                    return ((WarpAdapter) warp).getTransform();
321:                }
322:                return new WarpTransform2D(warp, (Warp) null);
323:            }
324:
325:            /**
326:             * Returns a {@linkplain Warp image warp} for the specified transform. The
327:             * {@link Warp#warpPoint(int,int,float[]) Warp.warpPoint} method transforms coordinates from
328:             * source to target CRS. Note that JAI's {@linkplain javax.media.jai.operator.WarpDescriptor
329:             * warp operation} needs a warp object with the opposite semantic (i.e. the image warp must
330:             * transforms coordinates from target to source CRS). Consequently, consider invoking
331:             * {@code getWarp(transform.inverse())} if the warp object is going to be used in an
332:             * image reprojection.
333:             *
334:             * @param name The image or {@linkplain org.geotools.coverage.grid.GridCoverage2D coverage}
335:             *        name, or {@code null} in unknow. Used only for formatting error message if some
336:             *        {@link org.opengis.referencing.operation.TransformException} are thrown by the
337:             *        supplied transform.
338:             * @param transform The transform to returns as an image warp.
339:             *
340:             * @todo We should check for {@link ConcatenatedTransform}. If we detect that a
341:             * {@code WarpTransform2D} is concatenated with {@code AffineTransform} only, and if the
342:             * {@code AffineTransform} has scale factors only, then we can ommit the {@code AffineTransform}
343:             * and merge the scale factors with {@link WarpPolynomial} preScaleX, preScaleY, postScaleX and
344:             * postScaleY. Additionnaly, the translation term for the post-AffineTransform may also be
345:             * merged with the first coefficients of WarpPolynomial.xCoeffs and yCoeffs. See GEOT-521.
346:             */
347:            public static Warp getWarp(CharSequence name,
348:                    final MathTransform2D transform) {
349:                if (transform instanceof  WarpTransform2D) {
350:                    return ((WarpTransform2D) transform).getWarp();
351:                }
352:                if (name == null) {
353:                    name = Vocabulary
354:                            .formatInternational(VocabularyKeys.UNKNOW);
355:                }
356:                return new WarpAdapter(name, transform);
357:            }
358:
359:            /**
360:             * Returns {@linkplain Warp image warp} wrapped by this transform. The
361:             * {@link Warp#warpPoint(int,int,float[]) Warp.warpPoint} method transforms coordinates from
362:             * source to target CRS. Note that JAI's {@linkplain javax.media.jai.operator.WarpDescriptor
363:             * warp operation} needs a warp object with the opposite semantic (i.e. the image warp must
364:             * transforms coordinates from target to source CRS). Consequently, consider invoking
365:             * <code>{@linkplain #inverse}.getWarp()</code> if the warp object is going to be used in an
366:             * image reprojection.
367:             */
368:            public Warp getWarp() {
369:                return warp;
370:            }
371:
372:            /**
373:             * Returns the parameter descriptors for this math transform.
374:             */
375:            public ParameterDescriptorGroup getParameterDescriptors() {
376:                if (warp instanceof  WarpPolynomial) {
377:                    return Provider.PARAMETERS;
378:                } else {
379:                    return super .getParameterDescriptors();
380:                }
381:            }
382:
383:            /**
384:             * Returns the parameter values for this math transform.
385:             */
386:            public ParameterValueGroup getParameterValues() {
387:                if (warp instanceof  WarpPolynomial) {
388:                    final WarpPolynomial poly = (WarpPolynomial) warp;
389:                    final ParameterValue[] p = new ParameterValue[7];
390:                    int c = 0;
391:                    p[c++] = new Parameter(Provider.DEGREE, new Integer(poly
392:                            .getDegree()));
393:                    p[c++] = new Parameter(Provider.X_COEFFS, poly.getXCoeffs());
394:                    p[c++] = new Parameter(Provider.Y_COEFFS, poly.getYCoeffs());
395:                    float s;
396:                    if ((s = poly.getPreScaleX()) != 1)
397:                        p[c++] = new Parameter(Provider.PRE_SCALE_X, new Float(
398:                                s));
399:                    if ((s = poly.getPreScaleY()) != 1)
400:                        p[c++] = new Parameter(Provider.PRE_SCALE_Y, new Float(
401:                                s));
402:                    if ((s = poly.getPostScaleX()) != 1)
403:                        p[c++] = new Parameter(Provider.POST_SCALE_X,
404:                                new Float(s));
405:                    if ((s = poly.getPostScaleY()) != 1)
406:                        p[c++] = new Parameter(Provider.POST_SCALE_Y,
407:                                new Float(s));
408:                    return new ParameterGroup(getParameterDescriptors(),
409:                            (ParameterValue[]) XArray.resize(p, c));
410:                } else {
411:                    return super .getParameterValues();
412:                }
413:            }
414:
415:            /**
416:             * Returns the dimension of input points.
417:             */
418:            public int getSourceDimensions() {
419:                return 2;
420:            }
421:
422:            /**
423:             * Returns the dimension of output points.
424:             */
425:            public int getTargetDimensions() {
426:                return 2;
427:            }
428:
429:            /**
430:             * Tests if this transform is the identity transform.
431:             */
432:            public boolean isIdentity() {
433:                return false;
434:            }
435:
436:            /**
437:             * Transforms source coordinates (usually pixel indices) into destination coordinates
438:             * (usually "real world" coordinates).
439:             *
440:             * @param ptSrc the specified coordinate point to be transformed.
441:             * @param ptDst the specified coordinate point that stores the result of transforming
442:             *              {@code ptSrc}, or {@code null}.
443:             * @return the coordinate point after transforming {@code ptSrc} and storing the result in
444:             *         {@code ptDst}.
445:             */
446:            public Point2D transform(Point2D ptSrc, Point2D ptDst) {
447:                /*
448:                 * We have to copy the coordinate in a temporary point object because we don't know
449:                 * neither the ptSrc or ptDst type. Since mapDestPoint returns a clone of the point
450:                 * given in argument,  giving ptSrc directly would result in a lost of precision if
451:                 * its type is java.awt.Point (for example), even if ptDst had a greater precision.
452:                 *
453:                 * There is also an other reason for creating a temporary object:
454:                 * JAI's Warp is designed for mapping pixel coordinates in J2SE's image. In JAI, pixel
455:                 * coordinates map by definition to the pixel's upper left corner. But for interpolation
456:                 * purpose, JAI needs to map pixel's center. This introduce a shift of 0.5, which is
457:                 * documented (for example) in WarpAffine.mapDestPoint(Point2D).
458:                 */
459:                ptSrc = new PointDouble(ptSrc.getX() - 0.5, ptSrc.getY() - 0.5);
460:                final Point2D result = warp.mapDestPoint(ptSrc);
461:                result.setLocation(result.getX() + 0.5, result.getY() + 0.5);
462:                if (ptDst == null) {
463:                    // Do not returns 'result' directly, since it has tricked 'clone()' method.
464:                    ptDst = new Point2D.Float();
465:                }
466:                ptDst.setLocation(result);
467:                return ptDst;
468:            }
469:
470:            /**
471:             * Transforms source coordinates (usually pixel indices) into destination coordinates
472:             * (usually "real world" coordinates).
473:             */
474:            public void transform(final float[] srcPts, int srcOff,
475:                    final float[] dstPts, int dstOff, int numPts) {
476:                final int postIncrement;
477:                if (srcPts == dstPts && srcOff < dstOff) {
478:                    srcOff += (numPts - 1) * 2;
479:                    dstOff += (numPts - 1) * 2;
480:                    postIncrement = -4;
481:                } else {
482:                    postIncrement = 0;
483:                }
484:                final Point2D.Float ptSrc = new PointFloat();
485:                final float[] ptDst = new float[2];
486:                while (--numPts >= 0) {
487:                    ptSrc.x = srcPts[srcOff++] - 0.5f; // See the comment in transform(Point2D...)
488:                    ptSrc.y = srcPts[srcOff++] - 0.5f; // for an explanation about the 0.5 shift.
489:                    final Point2D result = warp.mapDestPoint(ptSrc);
490:                    dstPts[dstOff++] = (float) (result.getX() + 0.5);
491:                    dstPts[dstOff++] = (float) (result.getY() + 0.5);
492:                    dstOff += postIncrement;
493:                }
494:            }
495:
496:            /**
497:             * Transforms source coordinates (usually pixel indices) into destination coordinates
498:             * (usually "real world" coordinates).
499:             */
500:            public void transform(final double[] srcPts, int srcOff,
501:                    final double[] dstPts, int dstOff, int numPts) {
502:                final int postIncrement;
503:                if (srcPts == dstPts && srcOff < dstOff) {
504:                    srcOff += (numPts - 1) * 2;
505:                    dstOff += (numPts - 1) * 2;
506:                    postIncrement = -4;
507:                } else {
508:                    postIncrement = 0;
509:                }
510:                final Point2D.Double ptSrc = new PointDouble();
511:                final float[] ptDst = new float[2];
512:                while (--numPts >= 0) {
513:                    ptSrc.x = srcPts[srcOff++] - 0.5; // See the comment in transform(Point2D...)
514:                    ptSrc.y = srcPts[srcOff++] - 0.5; // for an explanation about the 0.5 shift.
515:                    final Point2D result = warp.mapDestPoint(ptSrc);
516:                    dstPts[dstOff++] = result.getX() + 0.5;
517:                    dstPts[dstOff++] = result.getY() + 0.5;
518:                    dstOff += postIncrement;
519:                }
520:            }
521:
522:            /**
523:             * Returns the inverse transform.
524:             *
525:             * @throws NoninvertibleTransformException if no inverse warp were specified at construction time.
526:             */
527:            public MathTransform inverse()
528:                    throws NoninvertibleTransformException {
529:                if (inverse != null) {
530:                    return inverse;
531:                } else {
532:                    return super .inverse();
533:                }
534:            }
535:
536:            /**
537:             * Returns a hash value for this transform.
538:             */
539:            public int hashCode() {
540:                return (int) serialVersionUID ^ super .hashCode()
541:                        ^ warp.hashCode();
542:            }
543:
544:            /**
545:             * Compares this transform with the specified object for equality.
546:             */
547:            public boolean equals(final Object object) {
548:                if (super .equals(object)) {
549:                    final WarpTransform2D that = (WarpTransform2D) object;
550:                    return Utilities.equals(this .warp, that.warp);
551:                }
552:                return false;
553:            }
554:
555:            /**
556:             * A {@code Point2D.Float} that returns itself when {@link #clone} is invoked.
557:             * This trick is used for avoiding the creation of thousands of temporary objects
558:             * when transforming an array of points using {@link Warp#mapDestPoint}.
559:             */
560:            private static final class PointFloat extends Point2D.Float {
561:                public Object clone() {
562:                    return this ;
563:                }
564:            }
565:
566:            /**
567:             * A {@code Point2D.Double} that returns itself when {@link #clone} is invoked.
568:             * This trick is used for avoiding the creation of thousands of temporary objects
569:             * when transforming an array of points using {@link Warp#mapDestPoint}.
570:             */
571:            private static final class PointDouble extends Point2D.Double {
572:                public PointDouble() {
573:                    super ();
574:                }
575:
576:                public PointDouble(double x, double y) {
577:                    super (x, y);
578:                }
579:
580:                public Object clone() {
581:                    return this ;
582:                }
583:            }
584:
585:            /**
586:             * The provider for the {@link WarpTransform2D}. This provider constructs a JAI
587:             * {@linkplain WarpPolynomial image warp} from a set of polynomial coefficients,
588:             * and wrap it in a {@link WarpTransform2D} object.
589:             *
590:             * @version $Id: WarpTransform2D.java 29101 2008-02-06 12:11:19Z desruisseaux $
591:             * @author Martin Desruisseaux
592:             */
593:            public static class Provider extends MathTransformProvider {
594:                /** Serial number for interoperability with different versions. */
595:                private static final long serialVersionUID = -7949539694656719923L;
596:
597:                /** Descriptor for the "{@link WarpPolynomial#getDegree degree}" parameter value. */
598:                public static final ParameterDescriptor DEGREE = new DefaultParameterDescriptor(
599:                        "degree", 2, 1, MAX_DEGREE);
600:
601:                /** Descriptor for the "{@link WarpPolynomial#getXCoeffs xCoeffs}" parameter value. */
602:                public static final ParameterDescriptor X_COEFFS = new DefaultParameterDescriptor(
603:                        "xCoeffs", float[].class, null, null);
604:
605:                /** Descriptor for the "{@link WarpPolynomial#getYCoeffs yCoeffs}" parameter value. */
606:                public static final ParameterDescriptor Y_COEFFS = new DefaultParameterDescriptor(
607:                        "yCoeffs", float[].class, null, null);
608:
609:                /** Descriptor for the "{@link WarpPolynomial#getPreScaleX preScaleX}" parameter value. */
610:                public static final ParameterDescriptor PRE_SCALE_X;
611:
612:                /** Descriptor for the "{@link WarpPolynomial#getPreScaleY preScaleY}" parameter value. */
613:                public static final ParameterDescriptor PRE_SCALE_Y;
614:
615:                /** Descriptor for the "{@link WarpPolynomial#getPostScaleX postScaleX}" parameter value. */
616:                public static final ParameterDescriptor POST_SCALE_X;
617:
618:                /** Descriptor for the "{@link WarpPolynomial#getPostScaleY postScaleY}" parameter value. */
619:                public static final ParameterDescriptor POST_SCALE_Y;
620:                static {
621:                    final Float ONE = new Float(1);
622:                    PRE_SCALE_X = new DefaultParameterDescriptor("preScaleX",
623:                            null, ONE, false);
624:                    PRE_SCALE_Y = new DefaultParameterDescriptor("preScaleY",
625:                            null, ONE, false);
626:                    POST_SCALE_X = new DefaultParameterDescriptor("postScaleX",
627:                            null, ONE, false);
628:                    POST_SCALE_Y = new DefaultParameterDescriptor("postScaleY",
629:                            null, ONE, false);
630:                }
631:
632:                /**
633:                 * The parameters group.
634:                 */
635:                static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup(
636:                        new NamedIdentifier[] { new NamedIdentifier(
637:                                Citations.GEOTOOLS, "WarpPolynomial") },
638:                        new ParameterDescriptor[] { DEGREE, X_COEFFS, Y_COEFFS,
639:                                PRE_SCALE_X, PRE_SCALE_Y, POST_SCALE_X,
640:                                POST_SCALE_Y });
641:
642:                /**
643:                 * Create a provider for warp transforms.
644:                 */
645:                public Provider() {
646:                    super (2, 2, PARAMETERS);
647:                }
648:
649:                /**
650:                 * Returns the operation type.
651:                 */
652:                public Class getOperationType() {
653:                    return Transformation.class;
654:                }
655:
656:                /**
657:                 * Creates a warp transform from the specified group of parameter values.
658:                 *
659:                 * @param  values The group of parameter values.
660:                 * @return The created math transform.
661:                 * @throws ParameterNotFoundException if a required parameter was not found.
662:                 */
663:                protected MathTransform createMathTransform(
664:                        final ParameterValueGroup values)
665:                        throws ParameterNotFoundException {
666:                    final int degree = intValue(DEGREE, values);
667:                    final float[] xCoeffs = (float[]) value(X_COEFFS, values);
668:                    final float[] yCoeffs = (float[]) value(Y_COEFFS, values);
669:                    final float preScaleX = scale(PRE_SCALE_X, values);
670:                    final float preScaleY = scale(PRE_SCALE_Y, values);
671:                    final float postScaleX = scale(POST_SCALE_X, values);
672:                    final float postScaleY = scale(POST_SCALE_Y, values);
673:                    final Warp warp;
674:                    switch (degree) {
675:                    case 1:
676:                        warp = new WarpAffine(xCoeffs, yCoeffs, preScaleX,
677:                                preScaleY, postScaleX, postScaleY);
678:                        break;
679:                    case 2:
680:                        warp = new WarpQuadratic(xCoeffs, yCoeffs, preScaleX,
681:                                preScaleY, postScaleX, postScaleY);
682:                        break;
683:                    case 3:
684:                        warp = new WarpCubic(xCoeffs, yCoeffs, preScaleX,
685:                                preScaleY, postScaleX, postScaleY);
686:                        break;
687:                    default:
688:                        warp = new WarpGeneralPolynomial(xCoeffs, yCoeffs,
689:                                preScaleX, preScaleY, postScaleX, postScaleY);
690:                        break;
691:                    }
692:                    return new WarpTransform2D(warp, (Warp) null);
693:                }
694:
695:                /**
696:                 * Returns the parameter value for the specified operation parameter.
697:                 *
698:                 * @param  param The parameter to look for.
699:                 * @param  group The parameter value group to search into.
700:                 * @return The requested parameter value, or {@code 1} if none.
701:                 */
702:                private static float scale(final ParameterDescriptor param,
703:                        final ParameterValueGroup group)
704:                        throws ParameterNotFoundException {
705:                    final Object value = value(param, group);
706:                    return (value != null) ? ((Number) value).floatValue() : 1;
707:                }
708:            }
709:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.