Source Code Cross Referenced for ConcatenatedTransform.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:        package org.geotools.referencing.operation.transform;
019:
020:        // J2SE dependencies
021:        import java.awt.geom.AffineTransform;
022:        import java.awt.geom.Point2D;
023:        import java.io.Serializable;
024:
025:        // OpenGIS dependencies
026:        import org.opengis.parameter.ParameterValueGroup;
027:        import org.opengis.referencing.operation.MathTransform;
028:        import org.opengis.referencing.operation.MathTransform1D;
029:        import org.opengis.referencing.operation.MathTransform2D;
030:        import org.opengis.referencing.operation.Matrix;
031:        import org.opengis.referencing.operation.NoninvertibleTransformException;
032:        import org.opengis.referencing.operation.TransformException;
033:        import org.opengis.geometry.DirectPosition;
034:
035:        // Geotools dependencies
036:        import org.geotools.geometry.GeneralDirectPosition;
037:        import org.geotools.referencing.operation.matrix.XMatrix;
038:        import org.geotools.referencing.operation.matrix.Matrix3;
039:        import org.geotools.referencing.operation.matrix.GeneralMatrix;
040:        import org.geotools.referencing.operation.LinearTransform;
041:        import org.geotools.referencing.wkt.Formatter;
042:        import org.geotools.resources.Utilities;
043:        import org.geotools.resources.i18n.Errors;
044:        import org.geotools.resources.i18n.ErrorKeys;
045:
046:        /**
047:         * Base class for concatenated transform. Concatenated transforms are
048:         * serializable if all their step transforms are serializables.
049:         *
050:         * @since 2.0
051:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/operation/transform/ConcatenatedTransform.java $
052:         * @version $Id: ConcatenatedTransform.java 24925 2007-03-27 20:12:08Z jgarnett $
053:         * @author Martin Desruisseaux
054:         */
055:        public class ConcatenatedTransform extends AbstractMathTransform
056:                implements  Serializable {
057:            /**
058:             * Serial number for interoperability with different versions.
059:             */
060:            private static final long serialVersionUID = 5772066656987558634L;
061:
062:            /**
063:             * Small number for floating point comparaisons.
064:             */
065:            private static final double EPSILON = 1E-10;
066:
067:            /**
068:             * The first math transform.
069:             */
070:            public final MathTransform transform1;
071:
072:            /**
073:             * The second math transform.
074:             */
075:            public final MathTransform transform2;
076:
077:            /**
078:             * The inverse transform. This field will be computed only when needed.
079:             * But it is serialized in order to avoid rounding error if the inverse
080:             * transform is serialized instead of the original one.
081:             */
082:            private ConcatenatedTransform inverse;
083:
084:            /**
085:             * Constructs a concatenated transform. This constructor is for subclasses only. To
086:             * create a concatenated transform, use the factory method {@link #create} instead.
087:             *
088:             * @param transform1 The first math transform.
089:             * @param transform2 The second math transform.
090:             */
091:            protected ConcatenatedTransform(final MathTransform transform1,
092:                    final MathTransform transform2) {
093:                this .transform1 = transform1;
094:                this .transform2 = transform2;
095:                if (!isValid()) {
096:                    throw new IllegalArgumentException(Errors.format(
097:                            ErrorKeys.CANT_CONCATENATE_TRANSFORMS_$2,
098:                            getName(transform1), getName(transform2)));
099:                }
100:            }
101:
102:            /**
103:             * Returns the underlying matrix for the specified transform,
104:             * or {@code null} if the matrix is unavailable.
105:             */
106:            private static XMatrix getMatrix(final MathTransform transform) {
107:                if (transform instanceof  LinearTransform) {
108:                    return toXMatrix(((LinearTransform) transform).getMatrix());
109:                }
110:                if (transform instanceof  AffineTransform) {
111:                    return new Matrix3((AffineTransform) transform);
112:                }
113:                return null;
114:            }
115:
116:            /**
117:             * Tests if one math transform is the inverse of the other. This implementation
118:             * can't detect every case. It just detect the case when {@code tr2} is an
119:             * instance of {@link AbstractMathTransform.Inverse}.
120:             *
121:             * @todo We could make this test more general (just compare with tr2.inverse(),
122:             *       no matter if it is an instance of AbstractMathTransform.Inverse or not,
123:             *       and catch the exception if one is thrown). Would it be too expensive to
124:             *       create inconditionnaly the inverse transform?
125:             */
126:            private static boolean areInverse(final MathTransform tr1,
127:                    final MathTransform tr2) {
128:                if (tr2 instanceof  AbstractMathTransform.Inverse) {
129:                    return tr1.equals(((AbstractMathTransform.Inverse) tr2)
130:                            .inverse());
131:                }
132:                return false;
133:            }
134:
135:            /**
136:             * Constructs a concatenated transform.  This factory method checks for step transforms
137:             * dimension. The returned transform will implements {@link MathTransform2D} if source and
138:             * target dimensions are equal to 2.  Likewise, it will implements {@link MathTransform1D}
139:             * if source and target dimensions are equal to 1.  {@link MathTransform} implementations
140:             * are available in two version: direct and non-direct. The "non-direct" version use an
141:             * intermediate buffer when performing transformations; they are slower and consume more
142:             * memory. They are used only as a fallback when a "direct" version can't be created.
143:             *
144:             * @param tr1 The first math transform.
145:             * @param tr2 The second math transform.
146:             * @return    The concatenated transform.
147:             *
148:             * @todo We could add one more optimisation: if one transform is a matrix and the
149:             *       other transform is a PassThroughTransform, and if the matrix as 0 elements
150:             *       for all rows matching the PassThrough sub-transform, then we can get ride
151:             *       of the whole PassThroughTransform object.
152:             */
153:            public static MathTransform create(MathTransform tr1,
154:                    MathTransform tr2) {
155:                final int dim1 = tr1.getTargetDimensions();
156:                final int dim2 = tr2.getSourceDimensions();
157:                if (dim1 != dim2) {
158:                    throw new IllegalArgumentException(Errors.format(
159:                            ErrorKeys.CANT_CONCATENATE_TRANSFORMS_$2,
160:                            getName(tr1), getName(tr2))
161:                            + ' '
162:                            + Errors.format(ErrorKeys.MISMATCHED_DIMENSION_$2,
163:                                    new Integer(dim1), new Integer(dim2)));
164:                }
165:                if (tr1.isIdentity())
166:                    return tr2;
167:                if (tr2.isIdentity())
168:                    return tr1;
169:
170:                // If both transforms use matrix, then we can create
171:                // a single transform using the concatenated matrix.
172:                final XMatrix matrix1 = getMatrix(tr1);
173:                if (matrix1 != null) {
174:                    final XMatrix matrix2 = getMatrix(tr2);
175:                    if (matrix2 != null) {
176:                        // Compute "matrix = matrix2 * matrix1". Reuse an existing matrix object
177:                        // if possible, which is always the case when both matrix are square.
178:                        final int numRow = matrix2.getNumRow();
179:                        final int numCol = matrix1.getNumCol();
180:                        final XMatrix matrix;
181:                        if (numCol == matrix2.getNumCol()) {
182:                            matrix = matrix2;
183:                            matrix2.multiply(matrix1);
184:                        } else {
185:                            final GeneralMatrix m = new GeneralMatrix(numRow,
186:                                    numCol);
187:                            m.mul(toGMatrix(matrix2), toGMatrix(matrix1));
188:                            matrix = m;
189:                        }
190:                        if (matrix.isIdentity(EPSILON)) {
191:                            matrix.setIdentity();
192:                        }
193:                        // May not be really affine, but work anyway...
194:                        // This call will detect and optimize the special
195:                        // case where an 'AffineTransform' can be used.
196:                        return ProjectiveTransform.create(matrix);
197:                    }
198:                }
199:
200:                // If one transform is the inverse of the
201:                // other, returns the identity transform.
202:                if (areInverse(tr1, tr2) || areInverse(tr2, tr1)) {
203:                    assert tr1.getSourceDimensions() == tr2
204:                            .getTargetDimensions();
205:                    assert tr1.getTargetDimensions() == tr2
206:                            .getSourceDimensions();
207:                    return IdentityTransform.create(tr1.getSourceDimensions());
208:                }
209:
210:                // If one or both math transform are instance of ConcatenatedTransform,
211:                // then maybe it is possible to efficiently concatenate tr1 or tr2 with
212:                // one of step transforms. Try that...
213:                if (tr1 instanceof  ConcatenatedTransform) {
214:                    final ConcatenatedTransform ctr = (ConcatenatedTransform) tr1;
215:                    tr1 = ctr.transform1;
216:                    tr2 = create(ctr.transform2, tr2);
217:                }
218:                if (tr2 instanceof  ConcatenatedTransform) {
219:                    final ConcatenatedTransform ctr = (ConcatenatedTransform) tr2;
220:                    tr1 = create(tr1, ctr.transform1);
221:                    tr2 = ctr.transform2;
222:                }
223:                // Tests again, because one of the 'create' methods
224:                // above may have returned an identity transform.
225:                if (tr1.isIdentity())
226:                    return tr2;
227:                if (tr2.isIdentity())
228:                    return tr1;
229:
230:                // Before to create a general ConcatenatedTransform object, give a
231:                // chance to AbstractMathTransform to returns an optimized object.
232:                if (tr1 instanceof  AbstractMathTransform) {
233:                    final MathTransform optimized = ((AbstractMathTransform) tr1)
234:                            .concatenate(tr2, false);
235:                    if (optimized != null) {
236:                        return optimized;
237:                    }
238:                }
239:                if (tr2 instanceof  AbstractMathTransform) {
240:                    final MathTransform optimized = ((AbstractMathTransform) tr2)
241:                            .concatenate(tr1, true);
242:                    if (optimized != null) {
243:                        return optimized;
244:                    }
245:                }
246:                // Can't avoid the creation of a ConcatenatedTransform object.
247:                // Check for the type to create (1D, 2D, general case...)
248:                return createConcatenatedTransform(tr1, tr2);
249:            }
250:
251:            /**
252:             * Continue the construction started by {@link #create}. The construction step is available
253:             * separatly for testing purpose (in a JUnit test), and for {@link #inverse()} implementation.
254:             */
255:            static ConcatenatedTransform createConcatenatedTransform(
256:                    final MathTransform tr1, final MathTransform tr2) {
257:                final int dimSource = tr1.getSourceDimensions();
258:                final int dimTarget = tr2.getTargetDimensions();
259:                //
260:                // Check if the result need to be a MathTransform1D.
261:                //
262:                if (dimSource == 1 && dimTarget == 1) {
263:                    if (tr1 instanceof  MathTransform1D
264:                            && tr2 instanceof  MathTransform1D) {
265:                        return new ConcatenatedTransformDirect1D(
266:                                (MathTransform1D) tr1, (MathTransform1D) tr2);
267:                    } else {
268:                        return new ConcatenatedTransform1D(tr1, tr2);
269:                    }
270:                } else
271:                //
272:                // Check if the result need to be a MathTransform2D.
273:                //
274:                if (dimSource == 2 && dimTarget == 2) {
275:                    if (tr1 instanceof  MathTransform2D
276:                            && tr2 instanceof  MathTransform2D) {
277:                        return new ConcatenatedTransformDirect2D(
278:                                (MathTransform2D) tr1, (MathTransform2D) tr2);
279:                    } else {
280:                        return new ConcatenatedTransform2D(tr1, tr2);
281:                    }
282:                } else
283:                //
284:                // Check for the general case.
285:                //
286:                if (dimSource == tr1.getTargetDimensions()
287:                        && tr2.getSourceDimensions() == dimTarget) {
288:                    return new ConcatenatedTransformDirect(tr1, tr2);
289:                } else {
290:                    return new ConcatenatedTransform(tr1, tr2);
291:                }
292:            }
293:
294:            /**
295:             * Returns a name for the specified math transform.
296:             */
297:            private static final String getName(final MathTransform transform) {
298:                if (transform instanceof  AbstractMathTransform) {
299:                    ParameterValueGroup params = ((AbstractMathTransform) transform)
300:                            .getParameterValues();
301:                    if (params != null) {
302:                        String name = params.getDescriptor().getName()
303:                                .getCode();
304:                        if (name != null && (name = name.trim()).length() != 0) {
305:                            return name;
306:                        }
307:                    }
308:                }
309:                return Utilities.getShortClassName(transform);
310:            }
311:
312:            /**
313:             * Check if transforms are compatibles. The default
314:             * implementation check if transfert dimension match.
315:             */
316:            boolean isValid() {
317:                return transform1.getTargetDimensions() == transform2
318:                        .getSourceDimensions();
319:            }
320:
321:            /**
322:             * Gets the dimension of input points.
323:             */
324:            public final int getSourceDimensions() {
325:                return transform1.getSourceDimensions();
326:            }
327:
328:            /**
329:             * Gets the dimension of output points.
330:             */
331:            public final int getTargetDimensions() {
332:                return transform2.getTargetDimensions();
333:            }
334:
335:            /**
336:             * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.
337:             */
338:            public DirectPosition transform(final DirectPosition ptSrc,
339:                    DirectPosition ptDst) throws TransformException {
340:                assert isValid();
341:                //  Note: If we know that the transfert dimension is the same than source
342:                //        and target dimension, then we don't need to use an intermediate
343:                //        point. This optimization is done in ConcatenatedTransformDirect.
344:                return transform2.transform(transform1.transform(ptSrc, null),
345:                        ptDst);
346:            }
347:
348:            /**
349:             * Transforms a list of coordinate point ordinal values.
350:             */
351:            public void transform(final double[] srcPts, final int srcOff,
352:                    final double[] dstPts, final int dstOff, final int numPts)
353:                    throws TransformException {
354:                assert isValid();
355:                //  Note: If we know that the transfert dimension is the same than source
356:                //        and target dimension, then we don't need to use an intermediate
357:                //        buffer. This optimization is done in ConcatenatedTransformDirect.
358:                final double[] tmp = new double[numPts
359:                        * transform1.getTargetDimensions()];
360:                transform1.transform(srcPts, srcOff, tmp, 0, numPts);
361:                transform2.transform(tmp, 0, dstPts, dstOff, numPts);
362:            }
363:
364:            /**
365:             * Transforms a list of coordinate point ordinal values.
366:             */
367:            public void transform(final float[] srcPts, final int srcOff,
368:                    final float[] dstPts, final int dstOff, final int numPts)
369:                    throws TransformException {
370:                assert isValid();
371:                //  Note: If we know that the transfert dimension is the same than source
372:                //        and target dimension, then we don't need to use an intermediate
373:                //        buffer. This optimization is done in ConcatenatedTransformDirect.
374:                final float[] tmp = new float[numPts
375:                        * transform1.getTargetDimensions()];
376:                transform1.transform(srcPts, srcOff, tmp, 0, numPts);
377:                transform2.transform(tmp, 0, dstPts, dstOff, numPts);
378:            }
379:
380:            /**
381:             * Creates the inverse transform of this object.
382:             */
383:            public synchronized final MathTransform inverse()
384:                    throws NoninvertibleTransformException {
385:                assert isValid();
386:                if (inverse == null) {
387:                    inverse = createConcatenatedTransform(transform2.inverse(),
388:                            transform1.inverse());
389:                    inverse.inverse = this ;
390:                }
391:                return inverse;
392:            }
393:
394:            /**
395:             * Gets the derivative of this transform at a point. This method delegates to the
396:             * {@link #derivative(DirectPosition)} method because the transformation steps
397:             * {@link #transform1} and {@link #transform2} may not be instances of
398:             * {@link MathTransform2D}.
399:             *
400:             * @param  point The coordinate point where to evaluate the derivative.
401:             * @return The derivative at the specified point as a 2×2 matrix.
402:             * @throws TransformException if the derivative can't be evaluated at the specified point.
403:             */
404:            public Matrix derivative(final Point2D point)
405:                    throws TransformException {
406:                return derivative(new GeneralDirectPosition(point));
407:            }
408:
409:            /**
410:             * Gets the derivative of this transform at a point.
411:             *
412:             * @param  point The coordinate point where to evaluate the derivative.
413:             * @return The derivative at the specified point (never {@code null}).
414:             * @throws TransformException if the derivative can't be evaluated at the specified point.
415:             */
416:            public Matrix derivative(final DirectPosition point)
417:                    throws TransformException {
418:                final Matrix matrix1 = transform1.derivative(point);
419:                final Matrix matrix2 = transform2.derivative(transform1
420:                        .transform(point, null));
421:                // Compute "matrix = matrix2 * matrix1". Reuse an existing matrix object
422:                // if possible, which is always the case when both matrix are square.
423:                final int numRow = matrix2.getNumRow();
424:                final int numCol = matrix1.getNumCol();
425:                final XMatrix matrix;
426:                if (numCol == matrix2.getNumCol()) {
427:                    matrix = toXMatrix(matrix2);
428:                    matrix.multiply(matrix1);
429:                } else {
430:                    final GeneralMatrix m = new GeneralMatrix(numRow, numCol);
431:                    m.mul(toGMatrix(matrix2), toGMatrix(matrix1));
432:                    matrix = m;
433:                }
434:                return matrix;
435:            }
436:
437:            /**
438:             * Tests whether this transform does not move any points.
439:             * Default implementation check if the two transforms are
440:             * identity. 
441:             */
442:            public final boolean isIdentity() {
443:                return transform1.isIdentity() && transform2.isIdentity();
444:            }
445:
446:            /**
447:             * Returns a hash value for this transform.
448:             */
449:            public final int hashCode() {
450:                return transform1.hashCode() + 37 * transform2.hashCode();
451:            }
452:
453:            /**
454:             * Compares the specified object with
455:             * this math transform for equality.
456:             */
457:            public final boolean equals(final Object object) {
458:                if (object == this ) {
459:                    // Slight optimization
460:                    return true;
461:                }
462:                if (super .equals(object)) {
463:                    final ConcatenatedTransform that = (ConcatenatedTransform) object;
464:                    return Utilities.equals(this .transform1, that.transform1)
465:                            && Utilities.equals(this .transform2,
466:                                    that.transform2);
467:                }
468:                return false;
469:            }
470:
471:            /**
472:             * Format the inner part of a
473:             * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
474:             * Known Text</cite> (WKT)</A> element.
475:             *
476:             * @param  formatter The formatter to use.
477:             * @return The WKT element name.
478:             */
479:            protected String formatWKT(final Formatter formatter) {
480:                addWKT(formatter, transform1);
481:                addWKT(formatter, transform2);
482:                return "CONCAT_MT";
483:            }
484:
485:            /**
486:             * Append to a string buffer the WKT for the specified math transform.
487:             */
488:            private static void addWKT(final Formatter formatter,
489:                    final MathTransform transform) {
490:                if (transform instanceof  ConcatenatedTransform) {
491:                    final ConcatenatedTransform concat = (ConcatenatedTransform) transform;
492:                    addWKT(formatter, concat.transform1);
493:                    addWKT(formatter, concat.transform2);
494:                } else {
495:                    formatter.append(transform);
496:                }
497:            }
498:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.