Source Code Cross Referenced for AbstractMathTransform.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) 2003-2006, Geotools Project Managment Committee (PMC)
006:         *   (C) 2001, 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:         *    This package contains documentation from OpenGIS specifications.
019:         *    OpenGIS consortium's work is fully acknowledged here.
020:         */
021:        package org.geotools.referencing.operation.transform;
022:
023:        // J2SE and vecmath dependencies
024:        import java.io.Serializable;
025:        import java.awt.Shape;
026:        import java.awt.geom.Point2D;
027:        import java.awt.geom.GeneralPath;
028:        import java.awt.geom.PathIterator;
029:        import java.awt.geom.AffineTransform;
030:        import java.awt.geom.IllegalPathStateException;
031:        import javax.vecmath.SingularMatrixException;
032:        import javax.units.NonSI;
033:        import javax.units.SI;
034:
035:        // OpenGIS dependencies
036:        import org.opengis.referencing.operation.Matrix;
037:        import org.opengis.referencing.operation.MathTransform;
038:        import org.opengis.referencing.operation.MathTransform1D;
039:        import org.opengis.referencing.operation.MathTransform2D;
040:        import org.opengis.referencing.operation.Operation;
041:        import org.opengis.referencing.operation.OperationMethod;
042:        import org.opengis.referencing.operation.TransformException;
043:        import org.opengis.referencing.operation.NoninvertibleTransformException;
044:        import org.opengis.geometry.MismatchedDimensionException;
045:        import org.opengis.geometry.DirectPosition;
046:        import org.opengis.parameter.InvalidParameterValueException;
047:        import org.opengis.parameter.ParameterDescriptorGroup;
048:        import org.opengis.parameter.ParameterValueGroup;
049:
050:        // Geotools dependencies
051:        import org.geotools.referencing.wkt.Formatter;
052:        import org.geotools.referencing.wkt.Formattable;
053:        import org.geotools.referencing.operation.matrix.XMatrix;
054:        import org.geotools.referencing.operation.matrix.Matrix1;
055:        import org.geotools.referencing.operation.matrix.GeneralMatrix;
056:        import org.geotools.referencing.operation.matrix.MatrixFactory;
057:        import org.geotools.geometry.GeneralDirectPosition;
058:        import org.geotools.resources.geometry.ShapeUtilities;
059:        import org.geotools.resources.Utilities;
060:        import org.geotools.resources.i18n.Errors;
061:        import org.geotools.resources.i18n.ErrorKeys;
062:
063:        /**
064:         * Provides a default implementation for most methods required by the
065:         * {@link MathTransform} interface. {@code AbstractMathTransform}
066:         * provides a convenient base class from which other transform classes
067:         * can be easily derived. In addition, {@code AbstractMathTransform}
068:         * implements methods required by the {@link MathTransform2D} interface,
069:         * but <strong>does not</strong> implements {@code MathTransform2D}.
070:         * Subclasses must declare <code>implements&nbsp;MathTransform2D</code>
071:         * themself if they know to maps two-dimensional coordinate systems.
072:         *
073:         * @since 2.0
074:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/transform/AbstractMathTransform.java $
075:         * @version $Id: AbstractMathTransform.java 24925 2007-03-27 20:12:08Z jgarnett $
076:         * @author Martin Desruisseaux
077:         *
078:         * @tutorial http://docs.codehaus.org/display/GEOTOOLS/Coordinate+Transformation+Parameters
079:         */
080:        public abstract class AbstractMathTransform extends Formattable
081:                implements  MathTransform {
082:            /**
083:             * Constructs a math transform.
084:             */
085:            protected AbstractMathTransform() {
086:            }
087:
088:            /**
089:             * Gets the dimension of input points.
090:             */
091:            public abstract int getSourceDimensions();
092:
093:            /**
094:             * Gets the dimension of output points.
095:             */
096:            public abstract int getTargetDimensions();
097:
098:            /**
099:             * Returns the parameter descriptors for this math transform, or {@code null} if unknow.
100:             * This method is similar to {@link OperationMethod#getParameters}, except that
101:             * {@code MathTransform} returns parameters in standard units (usually
102:             * {@linkplain SI#METER meters} or {@linkplain NonSI#DEGREE_ANGLE decimal degrees}).
103:             *
104:             * @return The parameter descriptors for this math transform, or {@code null}.
105:             *
106:             * @see OperationMethod#getParameters
107:             */
108:            public ParameterDescriptorGroup getParameterDescriptors() {
109:                return null;
110:            }
111:
112:            /**
113:             * Returns the parameter values for this math transform, or {@code null} if unknow.
114:             * This method is similar to {@link Operation#getParameterValues}, except that
115:             * {@code MathTransform} returns parameters in standard units (usually
116:             * {@linkplain SI#METER meters} or {@linkplain NonSI#DEGREE_ANGLE decimal degrees}).
117:             * Since this method returns a copy of the parameter values, any change to a value
118:             * will have no effect on this math transform.
119:             *
120:             * @return A copy of the parameter values for this math transform, or {@code null}.
121:             *
122:             * @see Operation#getParameterValues
123:             */
124:            public ParameterValueGroup getParameterValues() {
125:                return null;
126:            }
127:
128:            /**
129:             * Tests whether this transform does not move any points.
130:             * The default implementation always returns {@code false}.
131:             */
132:            public boolean isIdentity() {
133:                return false;
134:            }
135:
136:            /**
137:             * Constructs an error message for the {@link MismatchedDimensionException}.
138:             *
139:             * @param argument  The argument name with the wrong number of dimensions.
140:             * @param dimension The wrong dimension.
141:             * @param expected  The expected dimension.
142:             */
143:            private static String constructMessage(final String argument,
144:                    final int dimension, final int expected) {
145:                return Errors
146:                        .format(ErrorKeys.MISMATCHED_DIMENSION_$3, argument,
147:                                new Integer(dimension), new Integer(expected));
148:            }
149:
150:            /**
151:             * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
152:             * The default implementation invokes {@link #transform(double[],int,double[],int,int)}
153:             * using a temporary array of doubles.
154:             *
155:             * @param ptSrc the specified coordinate point to be transformed.
156:             * @param ptDst the specified coordinate point that stores the result of transforming
157:             *              {@code ptSrc}, or {@code null}.
158:             * @return      the coordinate point after transforming {@code ptSrc} and storing the result in
159:             *              {@code ptDst}.
160:             * @throws MismatchedDimensionException if this transform doesn't map two-dimensional
161:             *         coordinate systems.
162:             * @throws TransformException if the point can't be transformed.
163:             *
164:             * @see MathTransform2D#transform(Point2D,Point2D)
165:             */
166:            public Point2D transform(final Point2D ptSrc, final Point2D ptDst)
167:                    throws TransformException {
168:                int dim;
169:                if ((dim = getSourceDimensions()) != 2) {
170:                    throw new MismatchedDimensionException(constructMessage(
171:                            "ptSrc", 2, dim));
172:                }
173:                if ((dim = getTargetDimensions()) != 2) {
174:                    throw new MismatchedDimensionException(constructMessage(
175:                            "ptDst", 2, dim));
176:                }
177:                final double[] ord = new double[] { ptSrc.getX(), ptSrc.getY() };
178:                this .transform(ord, 0, ord, 0, 1);
179:                if (ptDst != null) {
180:                    ptDst.setLocation(ord[0], ord[1]);
181:                    return ptDst;
182:                } else {
183:                    return new Point2D.Double(ord[0], ord[1]);
184:                }
185:            }
186:
187:            /**
188:             * Transforms the specified {@code ptSrc} and stores the result
189:             * in {@code ptDst}. The default implementation invokes
190:             * {@link #transform(double[],int,double[],int,int)}.
191:             */
192:            public DirectPosition transform(final DirectPosition ptSrc,
193:                    DirectPosition ptDst) throws TransformException {
194:                int dimPoint = ptSrc.getDimension();
195:                final int dimSource = getSourceDimensions();
196:                final int dimTarget = getTargetDimensions();
197:                if (dimPoint != dimSource) {
198:                    throw new MismatchedDimensionException(constructMessage(
199:                            "ptSrc", dimPoint, dimSource));
200:                }
201:                if (ptDst != null) {
202:                    dimPoint = ptDst.getDimension();
203:                    if (dimPoint != dimTarget) {
204:                        throw new MismatchedDimensionException(
205:                                constructMessage("ptDst", dimPoint, dimTarget));
206:                    }
207:                    /*
208:                     * Transforms the coordinates using a temporary 'double[]' buffer,
209:                     * and copy the transformation result in the destination position.
210:                     */
211:                    final double[] array;
212:                    if (dimSource >= dimTarget) {
213:                        array = ptSrc.getCoordinates();
214:                    } else {
215:                        array = new double[dimTarget];
216:                        for (int i = dimSource; --i >= 0;) {
217:                            array[i] = ptSrc.getOrdinate(i);
218:                        }
219:                    }
220:                    transform(array, 0, array, 0, 1);
221:                    for (int i = dimTarget; --i >= 0;) {
222:                        ptDst.setOrdinate(i, array[i]);
223:                    }
224:                } else {
225:                    /*
226:                     * Destination not set.  We are going to create the destination here.  Since we know
227:                     * that the destination will be the Geotools implementation, write directly into the
228:                     * 'ordinates' array.
229:                     */
230:                    final GeneralDirectPosition destination;
231:                    ptDst = destination = new GeneralDirectPosition(dimTarget);
232:                    final double[] source;
233:                    if (dimSource <= dimTarget) {
234:                        source = destination.ordinates;
235:                        for (int i = dimSource; --i >= 0;) {
236:                            source[i] = ptSrc.getOrdinate(i);
237:                        }
238:                    } else {
239:                        source = ptSrc.getCoordinates();
240:                    }
241:                    transform(source, 0, destination.ordinates, 0, 1);
242:                }
243:                return ptDst;
244:            }
245:
246:            /**
247:             * Transforms a list of coordinate point ordinal values. The default implementation
248:             * invokes {@link #transform(double[],int,double[],int,int)} using a temporary array
249:             * of doubles.
250:             */
251:            public void transform(final float[] srcPts, final int srcOff,
252:                    final float[] dstPts, final int dstOff, final int numPts)
253:                    throws TransformException {
254:                final int dimSource = getSourceDimensions();
255:                final int dimTarget = getTargetDimensions();
256:                final double[] tmpPts = new double[numPts
257:                        * Math.max(dimSource, dimTarget)];
258:                for (int i = numPts * dimSource; --i >= 0;) {
259:                    tmpPts[i] = srcPts[srcOff + i];
260:                }
261:                transform(tmpPts, 0, tmpPts, 0, numPts);
262:                for (int i = numPts * dimTarget; --i >= 0;) {
263:                    dstPts[dstOff + i] = (float) tmpPts[i];
264:                }
265:            }
266:
267:            /**
268:             * Transform the specified shape. The default implementation computes
269:             * quadratic curves using three points for each shape segments.
270:             *
271:             * @param  shape Shape to transform.
272:             * @return Transformed shape, or {@code shape} if this transform is the identity transform.
273:             * @throws IllegalStateException if this transform doesn't map 2D coordinate systems.
274:             * @throws TransformException if a transform failed.
275:             *
276:             * @see MathTransform2D#createTransformedShape(Shape)
277:             */
278:            public Shape createTransformedShape(final Shape shape)
279:                    throws TransformException {
280:                return isIdentity() ? shape : createTransformedShape(shape,
281:                        null, null, ShapeUtilities.PARALLEL);
282:            }
283:
284:            /**
285:             * Transforms a geometric shape. This method always copy transformed coordinates in a new
286:             * object. The new object is usually a {@link GeneralPath}, but may also be a {@link Line2D}
287:             * or a {@link QuadCurve2D} if such simplification is possible.
288:             *
289:             * @param  shape         The geometric shape to transform.
290:             * @param  preTransform  An optional affine transform to apply <em>before</em> the
291:             *                       transformation using {@code this}, or {@code null} if none.
292:             * @param  postTransform An optional affine transform to apply <em>after</em> the transformation
293:             *                       using {@code this}, or {@code null} if none.
294:             * @param orientation    Base line of quadratic curves. Must be
295:             *                       {@link ShapeUtilities#HORIZONTAL} or {@link ShapeUtilities#PARALLEL}).
296:             *
297:             * @return The transformed geometric shape.
298:             * @throws MismatchedDimensionException if this transform doesn't is not two-dimensional.
299:             * @throws TransformException If a transformation failed.
300:             */
301:            final Shape createTransformedShape(final Shape shape,
302:                    final AffineTransform preTransform,
303:                    final AffineTransform postTransform, final int orientation)
304:                    throws TransformException {
305:                int dim;
306:                if ((dim = getSourceDimensions()) != 2
307:                        || (dim = getTargetDimensions()) != 2) {
308:                    throw new MismatchedDimensionException(constructMessage(
309:                            "shape", 2, dim));
310:                }
311:                final PathIterator it = shape.getPathIterator(preTransform);
312:                final GeneralPath path = new GeneralPath(it.getWindingRule());
313:                final Point2D.Float ctrl = new Point2D.Float();
314:                final double[] buffer = new double[6];
315:
316:                double ax = 0, ay = 0; // Coordinate of the last point before transform.
317:                double px = 0, py = 0; // Coordinate of the last point after  transform.
318:                for (; !it.isDone(); it.next()) {
319:                    switch (it.currentSegment(buffer)) {
320:                    default: {
321:                        throw new IllegalPathStateException();
322:                    }
323:                    case PathIterator.SEG_CLOSE: {
324:                        /*
325:                         * Closes the geometric shape and continues the loop. We use the 'continue'
326:                         * instruction here instead of 'break' because we don't want to execute the
327:                         * code after the switch (addition of transformed points into the path - there
328:                         * is no such point in a SEG_CLOSE).
329:                         */
330:                        path.closePath();
331:                        continue;
332:                    }
333:                    case PathIterator.SEG_MOVETO: {
334:                        /*
335:                         * Transforms the single point and adds it to the path. We use the 'continue'
336:                         * instruction here instead of 'break' because we don't want to execute the
337:                         * code after the switch (addition of a line or a curve - there is no such
338:                         * curve to add here; we are just moving the cursor).
339:                         */
340:                        ax = buffer[0];
341:                        ay = buffer[1];
342:                        transform(buffer, 0, buffer, 0, 1);
343:                        px = buffer[0];
344:                        py = buffer[1];
345:                        path.moveTo((float) px, (float) py);
346:                        continue;
347:                    }
348:                    case PathIterator.SEG_LINETO: {
349:                        /*
350:                         * Inserts a new control point at 'buffer[0,1]'. This control point will
351:                         * be initialised with coordinates in the middle of the straight line:
352:                         *
353:                         *  x = 0.5*(x1+x2)
354:                         *  y = 0.5*(y1+y2)
355:                         *
356:                         * This point will be transformed after the 'switch', which is why we use
357:                         * the 'break' statement here instead of 'continue' as in previous case.
358:                         */
359:                        buffer[0] = 0.5 * (ax + (ax = buffer[0]));
360:                        buffer[1] = 0.5 * (ay + (ay = buffer[1]));
361:                        buffer[2] = ax;
362:                        buffer[3] = ay;
363:                        break;
364:                    }
365:                    case PathIterator.SEG_QUADTO: {
366:                        /*
367:                         * Replaces the control point in 'buffer[0,1]' by a new control point lying
368:                         * on the quadratic curve. Coordinates for a point in the middle of the curve
369:                         * can be computed with:
370:                         *
371:                         *  x = 0.5*(ctrlx + 0.5*(x1+x2))
372:                         *  y = 0.5*(ctrly + 0.5*(y1+y2))
373:                         *
374:                         * There is no need to keep the old control point because it was not lying
375:                         * on the curve.
376:                         */
377:                        buffer[0] = 0.5 * (buffer[0] + 0.5 * (ax + (ax = buffer[2])));
378:                        buffer[1] = 0.5 * (buffer[1] + 0.5 * (ay + (ay = buffer[3])));
379:                        break;
380:                    }
381:                    case PathIterator.SEG_CUBICTO: {
382:                        /*
383:                         * Replaces the control point in 'buffer[0,1]' by a new control point lying
384:                         * on the cubic curve. Coordinates for a point in the middle of the curve
385:                         * can be computed with:
386:                         *
387:                         *  x = 0.25*(1.5*(ctrlx1+ctrlx2) + 0.5*(x1+x2));
388:                         *  y = 0.25*(1.5*(ctrly1+ctrly2) + 0.5*(y1+y2));
389:                         *
390:                         * There is no need to keep the old control point because it was not lying
391:                         * on the curve.
392:                         *
393:                         * NOTE: Le point calculé est bien sur la courbe, mais n'est pas
394:                         *       nécessairement représentatif. Cet algorithme remplace les
395:                         *       deux points de contrôles par un seul, ce qui se traduit par
396:                         *       une perte de souplesse qui peut donner de mauvais résultats
397:                         *       si la courbe cubique était bien tordue. Projeter une courbe
398:                         *       cubique ne me semble pas être un problème simple, mais ce
399:                         *       cas devrait être assez rare. Il se produira le plus souvent
400:                         *       si on essaye de projeter un cercle ou une ellipse, auxquels
401:                         *       cas l'algorithme actuel donnera quand même des résultats
402:                         *       tolérables.
403:                         */
404:                        buffer[0] = 0.25 * (1.5 * (buffer[0] + buffer[2]) + 0.5 * (ax + (ax = buffer[4])));
405:                        buffer[1] = 0.25 * (1.5 * (buffer[1] + buffer[3]) + 0.5 * (ay + (ay = buffer[5])));
406:                        buffer[2] = ax;
407:                        buffer[3] = ay;
408:                        break;
409:                    }
410:                    }
411:                    /*
412:                     * Applies the transform on the point in the buffer, and append the transformed points
413:                     * to the general path. Try to add them as a quadratic line, or as a straight line if
414:                     * the computed control point is colinear with the starting and ending points.
415:                     */
416:                    transform(buffer, 0, buffer, 0, 2);
417:                    final Point2D ctrlPoint = ShapeUtilities
418:                            .parabolicControlPoint(px, py, buffer[0],
419:                                    buffer[1], buffer[2], buffer[3],
420:                                    orientation, ctrl);
421:                    px = buffer[2];
422:                    py = buffer[3];
423:                    if (ctrlPoint != null) {
424:                        assert ctrl == ctrlPoint;
425:                        path.quadTo(ctrl.x, ctrl.y, (float) px, (float) py);
426:                    } else {
427:                        path.lineTo((float) px, (float) py);
428:                    }
429:                }
430:                /*
431:                 * La projection de la forme géométrique est terminée. Applique
432:                 * une transformation affine si c'était demandée, puis retourne
433:                 * une version si possible simplifiée de la forme géométrique.
434:                 */
435:                if (postTransform != null) {
436:                    path.transform(postTransform);
437:                }
438:                return ShapeUtilities.toPrimitive(path);
439:            }
440:
441:            /**
442:             * Gets the derivative of this transform at a point. The default implementation always
443:             * throw an exception. Subclasses that implement the {@link MathTransform2D} interface
444:             * should override this method. Other subclasses should override
445:             * {@link #derivative(DirectPosition)} instead.
446:             *
447:             * @param  point The coordinate point where to evaluate the derivative.
448:             * @return The derivative at the specified point as a 2&times;2 matrix.
449:             * @throws MismatchedDimensionException if the input dimension is not 2.
450:             * @throws TransformException if the derivative can't be evaluated at the specified point.
451:             *
452:             * @see MathTransform2D#derivative(Point2D)
453:             */
454:            public Matrix derivative(final Point2D point)
455:                    throws TransformException {
456:                final int dimSource = getSourceDimensions();
457:                if (dimSource != 2) {
458:                    throw new MismatchedDimensionException(constructMessage(
459:                            "point", 2, dimSource));
460:                }
461:                throw new TransformException(Errors
462:                        .format(ErrorKeys.CANT_COMPUTE_DERIVATIVE));
463:            }
464:
465:            /**
466:             * Gets the derivative of this transform at a point. The default implementation
467:             * ensure that {@code point} has a valid dimension. Next, it try to delegate
468:             * the work to an other method:
469:             *
470:             * <ul>
471:             *   <li>If the input dimension is 2, then this method delegates the work to
472:             *       {@link #derivative(Point2D)}.</li>
473:             *   <li>If this object is an instance of {@link MathTransform1D}, then this
474:             *       method delegates the work to {@link MathTransform1D#derivative(double)
475:             *       derivative(double)}.</li>
476:             * </ul>
477:             *
478:             * Otherwise, a {@link TransformException} is thrown.
479:             *
480:             * @param  point The coordinate point where to evaluate the derivative.
481:             * @return The derivative at the specified point (never {@code null}).
482:             * @throws NullPointerException if the derivative dependents on coordinate
483:             *         and {@code point} is {@code null}.
484:             * @throws MismatchedDimensionException if {@code point} doesn't have
485:             *         the expected dimension.
486:             * @throws TransformException if the derivative can't be evaluated at the
487:             *         specified point.
488:             */
489:            public Matrix derivative(final DirectPosition point)
490:                    throws TransformException {
491:                final int dimSource = getSourceDimensions();
492:                if (point == null) {
493:                    if (dimSource == 2) {
494:                        return derivative((Point2D) null);
495:                    }
496:                } else {
497:                    final int dimPoint = point.getDimension();
498:                    if (dimPoint != dimSource) {
499:                        throw new MismatchedDimensionException(
500:                                constructMessage("point", dimPoint, dimSource));
501:                    }
502:                    if (dimSource == 2) {
503:                        if (point instanceof  Point2D) {
504:                            return derivative((Point2D) point);
505:                        }
506:                        return derivative(new Point2D.Double(point
507:                                .getOrdinate(0), point.getOrdinate(1)));
508:                    }
509:                    if (this  instanceof  MathTransform1D) {
510:                        return new Matrix1(((MathTransform1D) this )
511:                                .derivative(point.getOrdinate(0)));
512:                    }
513:                }
514:                throw new TransformException(Errors
515:                        .format(ErrorKeys.CANT_COMPUTE_DERIVATIVE));
516:            }
517:
518:            /**
519:             * Creates the inverse transform of this object.
520:             * The default implementation returns {@code this} if this transform is an identity
521:             * transform, and throws a {@link NoninvertibleTransformException} otherwise. Subclasses
522:             * should override this method.
523:             */
524:            public MathTransform inverse()
525:                    throws NoninvertibleTransformException {
526:                if (isIdentity()) {
527:                    return this ;
528:                }
529:                throw new NoninvertibleTransformException(Errors
530:                        .format(ErrorKeys.NONINVERTIBLE_TRANSFORM));
531:            }
532:
533:            /**
534:             * Concatenates in an optimized way a {@link MathTransform} {@code other} to this
535:             * {@code MathTransform}. A new math transform is created to perform the combined
536:             * transformation. The {@code applyOtherFirst} value determine the transformation
537:             * order as bellow:
538:             *
539:             * <ul>
540:             *   <li>If {@code applyOtherFirst} is {@code true}, then transforming a point
541:             *       <var>p</var> by the combined transform is equivalent to first transforming
542:             *       <var>p</var> by {@code other} and then transforming the result by the
543:             *       original transform {@code this}.</li>
544:             *   <li>If {@code applyOtherFirst} is {@code false}, then transforming a point
545:             *       <var>p</var> by the combined transform is equivalent to first transforming
546:             *       <var>p</var> by the original transform {@code this} and then transforming
547:             *       the result by {@code other}.</li>
548:             * </ul>
549:             *
550:             * If no special optimization is available for the combined transform, then this method
551:             * returns {@code null}.  In the later case, the concatenation will be prepared by
552:             * {@link DefaultMathTransformFactory} using a generic {@link ConcatenatedTransform}.
553:             *
554:             * The default implementation always returns {@code null}. This method is ought to be
555:             * overridden by subclasses capable of concatenating some combinaison of transforms in a
556:             * special way. Examples are {@link ExponentialTransform1D} and {@link LogarithmicTransform1D}.
557:             *
558:             * @param  other The math transform to apply.
559:             * @param  applyOtherFirst {@code true} if the transformation order is {@code other}
560:             *         followed by {@code this}, or {@code false} if the transformation order is
561:             *         {@code this} followed by {@code other}.
562:             * @return The combined math transform, or {@code null} if no optimized combined
563:             *         transform is available.
564:             */
565:            MathTransform concatenate(final MathTransform other,
566:                    final boolean applyOtherFirst) {
567:                return null;
568:            }
569:
570:            /**
571:             * Returns a hash value for this transform.
572:             */
573:            public int hashCode() {
574:                return getSourceDimensions() + 37 * getTargetDimensions();
575:            }
576:
577:            /**
578:             * Compares the specified object with this math transform for equality.
579:             * The default implementation checks if {@code object} is an instance
580:             * of the same class than {@code this} and use the same parameter descriptor.
581:             * Subclasses should override this method in order to compare internal fields.
582:             */
583:            public boolean equals(final Object object) {
584:                // Do not check 'object==this' here, since this
585:                // optimization is usually done in subclasses.
586:                if (object != null && getClass().equals(object.getClass())) {
587:                    final AbstractMathTransform that = (AbstractMathTransform) object;
588:                    return Utilities.equals(this .getParameterDescriptors(),
589:                            that.getParameterDescriptors());
590:                }
591:                return false;
592:            }
593:
594:            /**
595:             * Format the inner part of a
596:             * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
597:             * Known Text</cite> (WKT)</A> element. The default implementation formats all parameter values
598:             * returned by {@link #getParameterValues}. The parameter group name is used as the math
599:             * transform name.
600:             *
601:             * @param  formatter The formatter to use.
602:             * @return The WKT element name, which is {@code "PARAM_MT"} in the default implementation.
603:             */
604:            protected String formatWKT(final Formatter formatter) {
605:                final ParameterValueGroup parameters = getParameterValues();
606:                if (parameters != null) {
607:                    formatter.append(formatter.getName(parameters
608:                            .getDescriptor()));
609:                    formatter.append(parameters);
610:                }
611:                return "PARAM_MT";
612:            }
613:
614:            /**
615:             * Makes sure that an argument is non-null. This is a
616:             * convenience method for subclass constructors.
617:             *
618:             * @param  name   Argument name.
619:             * @param  object User argument.
620:             * @throws InvalidParameterValueException if {@code object} is null.
621:             */
622:            protected static void ensureNonNull(final String name,
623:                    final Object object) throws IllegalArgumentException {
624:                if (object == null) {
625:                    throw new InvalidParameterValueException(Errors.format(
626:                            ErrorKeys.NULL_ARGUMENT_$1, name), name, object);
627:                }
628:            }
629:
630:            /**
631:             * Checks if source coordinates need to be copied before to apply the transformation.
632:             * This convenience method is provided for {@code transform(...)} method implementation.
633:             * This method make the following assumptions:
634:             * <BR><BR>
635:             * <UL>
636:             *   <LI>Coordinates will be iterated from lower index to upper index.</LI>
637:             *   <LI>Coordinates are read and writen in shrunk. For example (longitude,latitude,height)
638:             *       values for one coordinate are read together, and the transformed (x,y,z) values are
639:             *       written together only after.</LI>
640:             * </UL>
641:             * <BR><BR>
642:             * However, this method does not assumes that source and target dimension are the same (in the
643:             * special case where source and target dimension are always the same, a simplier and more
644:             * efficient check is possible). The following example prepares a transformation from 2
645:             * dimensional points to three dimensional points:
646:             * <BR><BR>
647:             * <blockquote><pre>
648:             * public void transform(double[] srcPts, int srcOff,
649:             *                       double[] dstPts, int dstOff, int numPts)
650:             * {
651:             *     if (srcPts==dstPts && <strong>needCopy</strong>(srcOff, 2, dstOff, 3, numPts) {
652:             *         final double[] old = srcPts;
653:             *         srcPts = new double[numPts*2];
654:             *         System.arraycopy(old, srcOff, srcPts, 0, srcPts.length);
655:             *         srcOff = 0;
656:             *     }
657:             * }</pre><blockquote>
658:             */
659:            protected static boolean needCopy(final int srcOff,
660:                    final int dimSource, final int dstOff, final int dimTarget,
661:                    final int numPts) {
662:                if (numPts <= 1 || (srcOff >= dstOff && dimSource >= dimTarget)) {
663:                    /*
664:                     * Source coordinates are stored after target coordinates. If implementation
665:                     * read coordinates from lower index to upper index, then the destination will
666:                     * not overwrite the source coordinates, even if there is an overlaps.
667:                     */
668:                    return false;
669:                }
670:                return srcOff < dstOff + numPts * dimTarget
671:                        && dstOff < srcOff + numPts * dimSource;
672:            }
673:
674:            /**
675:             * Ensures that the specified longitude stay within &plusmn;&pi; radians. This method
676:             * is typically invoked after geographic coordinates are transformed. This method may add
677:             * or substract some amount of 2&pi; radians to <var>x</var>.
678:             *
679:             * @param  x The longitude in radians.
680:             * @return The longitude in the range &plusmn;&pi; radians.
681:             */
682:            protected static double rollLongitude(final double x) {
683:                return x - (2 * Math.PI) * Math.floor(x / (2 * Math.PI) + 0.5);
684:            }
685:
686:            /**
687:             * Wraps the specified matrix in a Geotools implementation of {@link Matrix}. If {@code matrix}
688:             * is already an instance of {@code XMatrix}, then it is returned unchanged. Otherwise, all
689:             * elements are copied in a new {@code XMatrix} object.
690:             */
691:            static XMatrix toXMatrix(final Matrix matrix) {
692:                if (matrix instanceof  XMatrix) {
693:                    return (XMatrix) matrix;
694:                }
695:                return MatrixFactory.create(matrix);
696:            }
697:
698:            /**
699:             * Wraps the specified matrix in a Geotools implementation of {@link Matrix}. If {@code matrix}
700:             * is already an instance of {@code GeneralMatrix}, then it is returned unchanged. Otherwise,
701:             * all elements are copied in a new {@code GeneralMatrix} object.
702:             * <p>
703:             * Before to use this method, check if a {@link XMatrix} (to be obtained with {@link #toXMatrix})
704:             * would be suffisient. Use this method only if a {@code GeneralMatrix} is really necessary.
705:             */
706:            static GeneralMatrix toGMatrix(final Matrix matrix) {
707:                if (matrix instanceof  GeneralMatrix) {
708:                    return (GeneralMatrix) matrix;
709:                } else {
710:                    return new GeneralMatrix(matrix);
711:                }
712:            }
713:
714:            /**
715:             * Inverts the specified matrix in place. If the matrix can't be inverted (for example
716:             * because of a {@link SingularMatrixException}), then the exception is wrapped into a
717:             * {@link NoninvertibleTransformException}.
718:             */
719:            static Matrix invert(final Matrix matrix)
720:                    throws NoninvertibleTransformException {
721:                try {
722:                    final XMatrix m = toXMatrix(matrix);
723:                    m.invert();
724:                    return m;
725:                } catch (SingularMatrixException exception) {
726:                    NoninvertibleTransformException e = new NoninvertibleTransformException(
727:                            Errors.format(ErrorKeys.NONINVERTIBLE_TRANSFORM));
728:                    e.initCause(exception);
729:                    throw e;
730:                }
731:            }
732:
733:            /**
734:             * Default implementation for inverse math transform. This inner class is the inverse
735:             * of the enclosing {@link MathTransform}. It is serializable only if the enclosing
736:             * math transform is also serializable.
737:             *
738:             * @since 2.0
739:             * @version $Id: AbstractMathTransform.java 24925 2007-03-27 20:12:08Z jgarnett $
740:             * @author Martin Desruisseaux
741:             */
742:            protected abstract class Inverse extends AbstractMathTransform
743:                    implements  Serializable {
744:                /**
745:                 * Serial number for interoperability with different versions. This serial number is
746:                 * especilly important for inner classes, since the default {@code serialVersionUID}
747:                 * computation will not produce consistent results across implementations of different
748:                 * Java compiler. This is because different compilers may generate different names for
749:                 * synthetic members used in the implementation of inner classes. See:
750:                 *
751:                 * http://developer.java.sun.com/developer/bugParade/bugs/4211550.html
752:                 */
753:                private static final long serialVersionUID = 3528274816628012283L;
754:
755:                /**
756:                 * Constructs an inverse math transform.
757:                 */
758:                protected Inverse() {
759:                }
760:
761:                /**
762:                 * Gets the dimension of input points. The default
763:                 * implementation returns the dimension of output
764:                 * points of the enclosing math transform.
765:                 */
766:                public int getSourceDimensions() {
767:                    return AbstractMathTransform.this .getTargetDimensions();
768:                }
769:
770:                /**
771:                 * Gets the dimension of output points. The default
772:                 * implementation returns the dimension of input
773:                 * points of the enclosing math transform.
774:                 */
775:                public int getTargetDimensions() {
776:                    return AbstractMathTransform.this .getSourceDimensions();
777:                }
778:
779:                /**
780:                 * Gets the derivative of this transform at a point. The default
781:                 * implementation compute the inverse of the matrix returned by
782:                 * the enclosing math transform.
783:                 */
784:                public Matrix derivative(final Point2D point)
785:                        throws TransformException {
786:                    return invert(AbstractMathTransform.this .derivative(this 
787:                            .transform(point, null)));
788:                }
789:
790:                /**
791:                 * Gets the derivative of this transform at a point. The default
792:                 * implementation compute the inverse of the matrix returned by
793:                 * the enclosing math transform.
794:                 */
795:                public Matrix derivative(final DirectPosition point)
796:                        throws TransformException {
797:                    return invert(AbstractMathTransform.this .derivative(this 
798:                            .transform(point, null)));
799:                }
800:
801:                /**
802:                 * Returns the inverse of this math transform, which is the enclosing math transform.
803:                 * This method is declared final because some implementation assume that the inverse
804:                 * of {@code this} is always {@code AbstractMathTransform.this}.
805:                 */
806:                public final MathTransform inverse() {
807:                    return AbstractMathTransform.this ;
808:                }
809:
810:                /**
811:                 * Tests whether this transform does not move any points.
812:                 * The default implementation delegate this tests to the
813:                 * enclosing math transform.
814:                 */
815:                public boolean isIdentity() {
816:                    return AbstractMathTransform.this .isIdentity();
817:                }
818:
819:                /**
820:                 * Returns a hash code value for this math transform.
821:                 */
822:                public int hashCode() {
823:                    return ~AbstractMathTransform.this .hashCode();
824:                }
825:
826:                /**
827:                 * Compares the specified object with this inverse math transform for equality.
828:                 * The default implementation tests if {@code object} in an instance of the same
829:                 * class than {@code this}, and then test their enclosing math transforms.
830:                 */
831:                public boolean equals(final Object object) {
832:                    if (object == this ) {
833:                        // Slight optimization
834:                        return true;
835:                    }
836:                    if (object instanceof  Inverse) {
837:                        final Inverse that = (Inverse) object;
838:                        return Utilities.equals(this .inverse(), that.inverse());
839:                    } else {
840:                        return false;
841:                    }
842:                }
843:
844:                /**
845:                 * Format the inner part of a
846:                 * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
847:                 * Known Text</cite> (WKT)</A> element. If this inverse math transform
848:                 * has any parameter values, then this method format the WKT as in the
849:                 * {@linkplain AbstractMathTransform#formatWKT super-class method}. Otherwise
850:                 * this method format the math transform as an <code>"INVERSE_MT"</code> entity.
851:                 *
852:                 * @param  formatter The formatter to use.
853:                 * @return The WKT element name, which is <code>"PARAM_MT"</code> or
854:                 *         <code>"INVERSE_MT"</code> in the default implementation.
855:                 */
856:                protected String formatWKT(final Formatter formatter) {
857:                    final ParameterValueGroup parameters = getParameterValues();
858:                    if (parameters != null) {
859:                        formatter.append(formatter.getName(parameters
860:                                .getDescriptor()));
861:                        formatter.append(parameters);
862:                        return "PARAM_MT";
863:                    } else {
864:                        formatter
865:                                .append((Formattable) AbstractMathTransform.this );
866:                        return "INVERSE_MT";
867:                    }
868:                }
869:            }
870:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.