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


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005:         *    (C) 2004, Institut de Recherche pour le Développement
006:         *   
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation;
010:         *    version 2.1 of the License.
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:         *    This package contains documentation from OpenGIS specifications.
018:         *    OpenGIS consortium's work is fully acknowledged here.
019:         */
020:        package org.geotools.referencing.cs;
021:
022:        // J2SE dependencies and extensions
023:        import java.util.Map;
024:        import java.util.Arrays;
025:        import java.util.HashMap;
026:        import java.util.Collections;
027:        import javax.units.SI;
028:        import javax.units.NonSI;
029:        import javax.units.Unit;
030:        import javax.units.Converter;
031:        import javax.units.ConversionException;
032:
033:        // OpenGIS dependencies
034:        import org.opengis.referencing.cs.AxisDirection;
035:        import org.opengis.referencing.cs.CoordinateSystem;
036:        import org.opengis.referencing.cs.CoordinateSystemAxis;
037:        import org.opengis.referencing.operation.Matrix;
038:        import org.opengis.geometry.MismatchedDimensionException;
039:        import org.opengis.util.InternationalString;
040:
041:        // Geotools dependencies
042:        import org.geotools.measure.Measure;
043:        import org.geotools.referencing.AbstractIdentifiedObject;
044:        import org.geotools.referencing.operation.matrix.GeneralMatrix;
045:        import org.geotools.referencing.wkt.Formatter;
046:        import org.geotools.resources.Utilities;
047:        import org.geotools.resources.i18n.Errors;
048:        import org.geotools.resources.i18n.ErrorKeys;
049:        import org.geotools.resources.i18n.Vocabulary;
050:
051:        /**
052:         * The set of coordinate system axes that spans a given coordinate space. A coordinate system (CS)
053:         * is derived from a set of (mathematical) rules for specifying how coordinates in a given space
054:         * are to be assigned to points. The coordinate values in a coordinate tuple shall be recorded in
055:         * the order in which the coordinate system axes are recorded, whenever those
056:         * coordinates use a coordinate reference system that uses this coordinate system.
057:         * <p>
058:         * This class is conceptually <cite>abstract</cite>, even if it is technically possible to
059:         * instantiate it. Typical applications should create instances of the most specific subclass with
060:         * {@code Default} prefix instead. An exception to this rule may occurs when it is not possible to
061:         * identify the exact type. For example it is not possible to infer the exact coordinate system from
062:         * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
063:         * Known Text</cite></A> is some cases (e.g. in a {@code LOCAL_CS} element). In such exceptional
064:         * situation, a plain {@code AbstractCS} object may be instantiated.
065:         *
066:         * @since 2.1
067:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/cs/AbstractCS.java $
068:         * @version $Id: AbstractCS.java 25485 2007-05-11 19:12:35Z desruisseaux $
069:         * @author Martin Desruisseaux
070:         *
071:         * @see DefaultCoordinateSystemAxis
072:         * @see javax.units.Unit
073:         * @see org.geotools.referencing.datum.AbstractDatum
074:         * @see org.geotools.referencing.crs.AbstractCRS
075:         */
076:        public class AbstractCS extends AbstractIdentifiedObject implements 
077:                CoordinateSystem {
078:            /**
079:             * Serial number for interoperability with different versions.
080:             */
081:            private static final long serialVersionUID = 6757665252533744744L;
082:
083:            /**
084:             * Base axis to use for checking directions. This is used in order to trap
085:             * inconsistency like an axis named "Northing" with South direction.
086:             */
087:            private static final DefaultCoordinateSystemAxis[] DIRECTION_CHECKS = {
088:                    DefaultCoordinateSystemAxis.NORTHING,
089:                    DefaultCoordinateSystemAxis.EASTING,
090:                    DefaultCoordinateSystemAxis.SOUTHING,
091:                    DefaultCoordinateSystemAxis.WESTING };
092:
093:            /**
094:             * The axis for this coordinate system at the specified dimension.
095:             */
096:            private final CoordinateSystemAxis[] axis;
097:
098:            /**
099:             * The unit for measuring distance in this coordinate system, or {@code null} if none.
100:             * Will be computed only when first needed.
101:             */
102:            private transient Unit distanceUnit;
103:
104:            /**
105:             * Constructs a new coordinate system with the same values than the specified one.
106:             * This copy constructor provides a way to wrap an arbitrary implementation into a
107:             * Geotools one or a user-defined one (as a subclass), usually in order to leverage
108:             * some implementation-specific API. This constructor performs a shallow copy,
109:             * i.e. the properties are not cloned.
110:             *
111:             * @since 2.2
112:             */
113:            public AbstractCS(final CoordinateSystem cs) {
114:                super (cs);
115:                if (cs instanceof  AbstractCS) {
116:                    axis = ((AbstractCS) cs).axis;
117:                } else {
118:                    axis = new CoordinateSystemAxis[cs.getDimension()];
119:                    for (int i = 0; i < axis.length; i++) {
120:                        axis[i] = cs.getAxis(i);
121:                    }
122:                }
123:            }
124:
125:            /**
126:             * Constructs a coordinate system from a name.
127:             *
128:             * @param name  The coordinate system name.
129:             * @param axis  The set of axis.
130:             */
131:            public AbstractCS(final String name,
132:                    final CoordinateSystemAxis[] axis) {
133:                this (Collections.singletonMap(NAME_KEY, name), axis);
134:            }
135:
136:            /**
137:             * Constructs a coordinate system from a set of properties. The properties map is given
138:             * unchanged to the {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map)
139:             * super-class constructor}.
140:             *
141:             * @param properties   Set of properties. Should contains at least <code>"name"</code>.
142:             * @param axis         The set of axis.
143:             */
144:            public AbstractCS(final Map properties,
145:                    final CoordinateSystemAxis[] axis) {
146:                super (properties);
147:                ensureNonNull("axis", axis);
148:                this .axis = (CoordinateSystemAxis[]) axis.clone();
149:                for (int i = 0; i < axis.length; i++) {
150:                    ensureNonNull("axis", axis, i);
151:                    final AxisDirection direction = axis[i].getDirection();
152:                    ensureNonNull("direction", direction);
153:                    /*
154:                     * Ensures that axis direction and units are compatible with the
155:                     * coordinate system to be created. For example CartesianCS will
156:                     * accepts only linear or dimensionless units.
157:                     */
158:                    if (!isCompatibleDirection(direction)) {
159:                        // TOOD: localize name()
160:                        throw new IllegalArgumentException(Errors.format(
161:                                ErrorKeys.ILLEGAL_AXIS_ORIENTATION_$2,
162:                                direction.name(), Utilities
163:                                        .getShortClassName(this )));
164:                    }
165:                    final Unit unit = axis[i].getUnit();
166:                    ensureNonNull("unit", unit);
167:                    if (!isCompatibleUnit(direction, unit)) {
168:                        throw new IllegalArgumentException(Errors.format(
169:                                ErrorKeys.INCOMPATIBLE_UNIT_$1, unit));
170:                    }
171:                    /*
172:                     * Ensures there is no axis along the same direction
173:                     * (e.g. two North axis, or an East and a West axis).
174:                     */
175:                    final AxisDirection check = direction.absolute();
176:                    if (!check.equals(AxisDirection.OTHER)) {
177:                        for (int j = i; --j >= 0;) {
178:                            if (check.equals(axis[j].getDirection().absolute())) {
179:                                // TODO: localize name()
180:                                final String nameI = axis[i].getDirection()
181:                                        .name();
182:                                final String nameJ = axis[j].getDirection()
183:                                        .name();
184:                                throw new IllegalArgumentException(Errors
185:                                        .format(ErrorKeys.COLINEAR_AXIS_$2,
186:                                                nameI, nameJ));
187:                            }
188:                        }
189:                    }
190:                    /*
191:                     * Checks for some inconsistency in naming and direction. For example if the axis
192:                     * is named "Northing", then the direction must be North. Exceptions to this rule
193:                     * are the directions along a meridian from a pole. For example a "Northing" axis
194:                     * may have a "South along 180 deg" direction.
195:                     */
196:                    final String name = axis[i].getName().getCode();
197:                    for (int j = 0; j < DIRECTION_CHECKS.length; j++) {
198:                        final DefaultCoordinateSystemAxis candidate = DIRECTION_CHECKS[j];
199:                        if (candidate.nameMatches(name)) {
200:                            final AxisDirection expected = candidate
201:                                    .getDirection();
202:                            if (!direction.equals(expected)) {
203:                                DirectionAlongMeridian m = DirectionAlongMeridian
204:                                        .parse(direction);
205:                                /*
206:                                 * Note: for the check below, maybe it would have be nice to use:
207:                                 *
208:                                 *     if (m == null || m.baseDirection.equals(expected.opposite())
209:                                 *
210:                                 * but the EPSG database contains many axis named "Northing" with
211:                                 * direction like "South along 180 deg", so it doesn't seem to be
212:                                 * considered as a contradiction...
213:                                 */
214:                                if (m == null) {
215:                                    throw new IllegalArgumentException(
216:                                            Errors
217:                                                    .format(
218:                                                            ErrorKeys.INCONSISTENT_AXIS_ORIENTATION_$2,
219:                                                            name, direction
220:                                                                    .name()));
221:                                }
222:                            }
223:                        }
224:                    }
225:                }
226:            }
227:
228:            /**
229:             * Creates a name for the predefined constants in subclasses. The name is an unlocalized String
230:             * object. However, since this method is used for creation of convenience objects only (not for
231:             * objects created from an "official" database), the "unlocalized" name is actually choosen
232:             * according the user's locale at class initialization time. The same name is also added in
233:             * a localizable form as an alias. Since the {@link #nameMatches} convenience method checks
234:             * the alias, it still possible to consider two objects are equivalent even if their names
235:             * were formatted in different locales.
236:             */
237:            static Map name(final int key) {
238:                final Map properties = new HashMap(4);
239:                final InternationalString name = Vocabulary
240:                        .formatInternational(key);
241:                properties.put(NAME_KEY, name.toString());
242:                properties.put(ALIAS_KEY, name);
243:                return properties;
244:            }
245:
246:            /**
247:             * Returns {@code true} if the specified axis direction is allowed for this coordinate
248:             * system. This method is invoked at construction time for checking argument validity.
249:             * The default implementation returns {@code true} for all axis directions. Subclasses
250:             * will overrides this method in order to put more restrictions on allowed axis directions.
251:             */
252:            protected boolean isCompatibleDirection(
253:                    final AxisDirection direction) {
254:                return true;
255:            }
256:
257:            /**
258:             * Returns {@code true} is the specified unit is legal for the specified axis direction.
259:             * This method is invoked at construction time for checking units compatibility. The default
260:             * implementation returns {@code true} in all cases. Subclasses can override this method and
261:             * check for compatibility with {@linkplain SI#METER meter} or
262:             * {@linkplain NonSI#DEGREE_ANGLE degree} units.
263:             *
264:             * @since 2.2
265:             */
266:            protected boolean isCompatibleUnit(final AxisDirection direction,
267:                    final Unit unit) {
268:                return true;
269:            }
270:
271:            /**
272:             * Returns the dimension of the coordinate system.
273:             * This is the number of axis.
274:             */
275:            public int getDimension() {
276:                return axis.length;
277:            }
278:
279:            /**
280:             * Returns the axis for this coordinate system at the specified dimension.
281:             *
282:             * @param  dimension The zero based index of axis.
283:             * @return The axis at the specified dimension.
284:             * @throws IndexOutOfBoundsException if {@code dimension} is out of bounds.
285:             */
286:            public CoordinateSystemAxis getAxis(final int dimension)
287:                    throws IndexOutOfBoundsException {
288:                return axis[dimension];
289:            }
290:
291:            /**
292:             * Returns the axis direction for the specified coordinate system.
293:             *
294:             * @param  cs The coordinate system.
295:             * @return The axis directions for the specified coordinate system.
296:             */
297:            private static AxisDirection[] getAxisDirections(
298:                    final CoordinateSystem cs) {
299:                final AxisDirection[] axis = new AxisDirection[cs
300:                        .getDimension()];
301:                for (int i = 0; i < axis.length; i++) {
302:                    axis[i] = cs.getAxis(i).getDirection();
303:                }
304:                return axis;
305:            }
306:
307:            /**
308:             * Returns an affine transform between two coordinate systems. Only units and
309:             * axis order (e.g. transforming from
310:             * ({@linkplain AxisDirection#NORTH NORTH},{@linkplain AxisDirection#WEST WEST}) to
311:             * ({@linkplain AxisDirection#EAST EAST},{@linkplain AxisDirection#NORTH NORTH}
312:             * are taken in account.
313:             *
314:             * <P><STRONG>Example:</STRONG> If coordinates in {@code sourceCS} are
315:             * (<var>x</var>,<var>y</var>) pairs in metres and coordinates in {@code targetCS}
316:             * are (-<var>y</var>,<var>x</var>) pairs in centimetres, then the transformation
317:             * can be performed as below:</P>
318:             *
319:             * <pre><blockquote>
320:             *          [-y(cm)]   [ 0  -100    0 ] [x(m)]
321:             *          [ x(cm)] = [ 100   0    0 ] [y(m)]
322:             *          [ 1    ]   [ 0     0    1 ] [1   ]
323:             * </blockquote></pre>
324:             *
325:             * @param  sourceCS The source coordinate system.
326:             * @param  targetCS The target coordinate system.
327:             * @return The conversion from {@code sourceCS} to {@code targetCS} as
328:             *         an affine transform. Only axis direction and units are taken in account.
329:             * @throws IllegalArgumentException if axis doesn't matches, or the CS doesn't have the
330:             *         same geometry.
331:             * @throws ConversionException if the unit conversion is non-linear.
332:             */
333:            public static Matrix swapAndScaleAxis(
334:                    final CoordinateSystem sourceCS,
335:                    final CoordinateSystem targetCS)
336:                    throws IllegalArgumentException, ConversionException {
337:                if (!Utilities.sameInterfaces(sourceCS.getClass(), targetCS
338:                        .getClass(), CoordinateSystem.class)) {
339:                    throw new IllegalArgumentException(
340:                            Errors
341:                                    .format(ErrorKeys.INCOMPATIBLE_COORDINATE_SYSTEM_TYPE));
342:                }
343:                final AxisDirection[] sourceAxis = getAxisDirections(sourceCS);
344:                final AxisDirection[] targetAxis = getAxisDirections(targetCS);
345:                final GeneralMatrix matrix = new GeneralMatrix(sourceAxis,
346:                        targetAxis);
347:                assert Arrays.equals(sourceAxis, targetAxis) == matrix
348:                        .isIdentity() : matrix;
349:                /*
350:                 * The previous code computed a matrix for swapping axis. Usually, this
351:                 * matrix contains only 0 and 1 values with only one "1" value by row.
352:                 * For example, the matrix operation for swapping x and y axis is:
353:                 *
354:                 *          [y]   [ 0  1  0 ] [x]
355:                 *          [x] = [ 1  0  0 ] [y]
356:                 *          [1]   [ 0  0  1 ] [1]
357:                 *
358:                 * Now, take in account units conversions. Each matrix's element (j,i)
359:                 * is multiplied by the conversion factor from sourceCS.getUnit(i) to
360:                 * targetCS.getUnit(j). This is an element-by-element multiplication,
361:                 * not a matrix multiplication. The last column is processed in a special
362:                 * way, since it contains the offset values.
363:                 */
364:                final int sourceDim = matrix.getNumCol() - 1;
365:                final int targetDim = matrix.getNumRow() - 1;
366:                assert sourceDim == sourceCS.getDimension() : sourceCS;
367:                assert targetDim == targetCS.getDimension() : targetCS;
368:                for (int j = 0; j < targetDim; j++) {
369:                    final Unit targetUnit = targetCS.getAxis(j).getUnit();
370:                    for (int i = 0; i < sourceDim; i++) {
371:                        final double element = matrix.getElement(j, i);
372:                        if (element == 0) {
373:                            // There is no dependency between source[i] and target[j]
374:                            // (i.e. axis are orthogonal).
375:                            continue;
376:                        }
377:                        final Unit sourceUnit = sourceCS.getAxis(i).getUnit();
378:                        if (Utilities.equals(sourceUnit, targetUnit)) {
379:                            // There is no units conversion to apply
380:                            // between source[i] and target[j].
381:                            continue;
382:                        }
383:                        final Converter converter = sourceUnit
384:                                .getConverterTo(targetUnit);
385:                        if (!converter.isLinear()) {
386:                            throw new ConversionException(Errors.format(
387:                                    ErrorKeys.NON_LINEAR_UNIT_CONVERSION_$2,
388:                                    sourceUnit, targetUnit));
389:                        }
390:                        final double offset = converter.convert(0);
391:                        final double scale = converter.derivative(0);
392:                        matrix.setElement(j, i, element * scale);
393:                        matrix.setElement(j, sourceDim, matrix.getElement(j,
394:                                sourceDim)
395:                                + element * offset);
396:                    }
397:                }
398:                return matrix;
399:            }
400:
401:            /**
402:             * Returns a coordinate system with "standard" axis order and units.
403:             * Most of the time, this method returns one of the predefined constants with axis in
404:             * (<var>longitude</var>,<var>latitude</var>) or (<var>X</var>,<var>Y</var>) order,
405:             * and units in degrees or metres. In some particular cases like
406:             * {@linkplain org.opengis.referencing.cs.CartesianCS Cartesian CS}, this method may
407:             * create a new instance on the fly. In every cases this method attempts to return a
408:             * <A HREF="http://en.wikipedia.org/wiki/Right_hand_rule">right-handed</A> coordinate
409:             * system, but this is not garanteed.
410:             * <p>
411:             * This method is typically used together with {@link #swapAndScaleAxis swapAndScaleAxis}
412:             * for the creation of a transformation step before some
413:             * {@linkplain org.opengis.referencing.operation.MathTransform math transform}.
414:             * Example:
415:             *
416:             * <blockquote><pre>
417:             * Matrix step1 = swapAndScaleAxis(sourceCS, standard(sourceCS));
418:             * Matrix step2 = ... some transform operating on standard axis ...
419:             * Matrix step3 = swapAndScaleAxis(standard(targetCS), targetCS);
420:             * </pre></blockquote>
421:             *
422:             * A rational for standard axis order and units is explained in the <cite>Axis units and
423:             * direction</cite> section in the {@linkplain org.geotools.referencing.operation.projection
424:             * description of map projection package}.
425:             *
426:             * @param  cs The coordinate system.
427:             * @return A constant similar to the specified {@code cs} with "standard" axis.
428:             * @throws IllegalArgumentException if the specified coordinate system is unknow to this method.
429:             *
430:             * @since 2.2
431:             */
432:            public static CoordinateSystem standard(final CoordinateSystem cs)
433:                    throws IllegalArgumentException {
434:                return PredefinedCS.standard(cs);
435:            }
436:
437:            /**
438:             * Suggests an unit for measuring distances in this coordinate system. The default
439:             * implementation scans all {@linkplain CoordinateSystemAxis#getUnit axis units},
440:             * ignoring angular ones (this also implies ignoring {@linkplain Unit#ONE dimensionless} ones).
441:             * If more than one non-angular unit is found, the default implementation returns the "largest"
442:             * one (e.g. kilometers instead of meters).
443:             *
444:             * @return Suggested distance unit.
445:             * @throws ConversionException if some non-angular units are incompatibles.
446:             */
447:            final Unit getDistanceUnit() throws ConversionException {
448:                Unit unit = distanceUnit; // Avoid the need for synchronization.
449:                if (unit == null) {
450:                    for (int i = 0; i < axis.length; i++) {
451:                        final Unit candidate = axis[i].getUnit();
452:                        if (candidate != null
453:                                && !candidate.isCompatible(SI.RADIAN)) {
454:                            // TODO: checks the unit scale type (keeps RATIO only).
455:                            if (unit != null) {
456:                                final Converter converter = candidate
457:                                        .getConverterTo(unit);
458:                                if (!converter.isLinear()) {
459:                                    // TODO: use the localization provided in 'swapAxis'. We could also
460:                                    //       do a more intelligent work by checking the unit scale type.
461:                                    throw new ConversionException(
462:                                            "Unit conversion is non-linear");
463:                                }
464:                                if (Math.abs(converter.derivative(0)) <= 1) {
465:                                    // The candidate is a "smaller" unit than the current one
466:                                    // (e.g. "m" instead of "km"). Keeps the "largest" unit.
467:                                    continue;
468:                                }
469:                            }
470:                            unit = candidate;
471:                        }
472:                    }
473:                    distanceUnit = unit;
474:                }
475:                return unit;
476:            }
477:
478:            /**
479:             * Convenience method for checking object dimension validity.
480:             *
481:             * @param  name The name of the argument to check.
482:             * @param  coordinates The coordinate array to check.
483:             * @throws MismatchedDimensionException if the coordinate doesn't have the expected dimension.
484:             */
485:            final void ensureDimensionMatch(final String name,
486:                    final double[] coordinates)
487:                    throws MismatchedDimensionException {
488:                if (coordinates.length != axis.length) {
489:                    throw new MismatchedDimensionException(Errors.format(
490:                            ErrorKeys.MISMATCHED_DIMENSION_$3, name,
491:                            new Integer(coordinates.length), new Integer(
492:                                    axis.length)));
493:                }
494:            }
495:
496:            /**
497:             * Computes the distance between two points. This method is not available for all coordinate
498:             * systems. For example, {@linkplain DefaultEllipsoidalCS ellipsoidal CS} doesn't have
499:             * suffisient information.
500:             *
501:             * @param  coord1 Coordinates of the first point.
502:             * @param  coord2 Coordinates of the second point.
503:             * @return The distance between {@code coord1} and {@code coord2}.
504:             * @throws UnsupportedOperationException if this coordinate system can't compute distances.
505:             * @throws MismatchedDimensionException if a coordinate doesn't have the expected dimension.
506:             *
507:             * @todo Provides a localized message in the exception.
508:             */
509:            public Measure distance(final double[] coord1, final double[] coord2)
510:                    throws UnsupportedOperationException,
511:                    MismatchedDimensionException {
512:                throw new UnsupportedOperationException();
513:            }
514:
515:            /**
516:             * Returns all axis in the specified unit. This method is used for implementation of
517:             * {@code usingUnit} methods in subclasses.
518:             *
519:             * @param  unit The unit for the new axis.
520:             * @return New axis using the specified unit, or {@code null} if current axis fits.
521:             * @throws IllegalArgumentException If the specified unit is incompatible with the expected one.
522:             *
523:             * @see DefaultCartesianCS#usingUnit
524:             * @see DefaultEllipsoidalCS#usingUnit
525:             */
526:            final CoordinateSystemAxis[] axisUsingUnit(final Unit unit)
527:                    throws IllegalArgumentException {
528:                CoordinateSystemAxis[] newAxis = null;
529:                for (int i = 0; i < axis.length; i++) {
530:                    CoordinateSystemAxis a = axis[i];
531:                    if (!unit.equals(a.getUnit())) {
532:                        DefaultCoordinateSystemAxis converted;
533:                        if (a instanceof  DefaultCoordinateSystemAxis) {
534:                            converted = (DefaultCoordinateSystemAxis) a;
535:                        } else {
536:                            converted = new DefaultCoordinateSystemAxis(a);
537:                            a = converted; // For detecting changes.
538:                        }
539:                        converted = converted.usingUnit(unit);
540:                        if (converted != a) {
541:                            if (newAxis == null) {
542:                                newAxis = new CoordinateSystemAxis[axis.length];
543:                                System.arraycopy(axis, 0, newAxis, 0, i);
544:                            }
545:                            newAxis[i] = converted;
546:                        }
547:                    }
548:                }
549:                return newAxis;
550:            }
551:
552:            /**
553:             * Returns every axis from the specified coordinate system as instance of
554:             * {@link DefaultCoordinateSystemAxis}. This allow usage of some methods
555:             * specific to that implementation.
556:             */
557:            private static DefaultCoordinateSystemAxis[] getDefaultAxis(
558:                    final CoordinateSystem cs) {
559:                final DefaultCoordinateSystemAxis[] axis = new DefaultCoordinateSystemAxis[cs
560:                        .getDimension()];
561:                for (int i = 0; i < axis.length; i++) {
562:                    final CoordinateSystemAxis a = cs.getAxis(i);
563:                    DefaultCoordinateSystemAxis c = DefaultCoordinateSystemAxis
564:                            .getPredefined(a);
565:                    if (c == null) {
566:                        if (a instanceof  DefaultCoordinateSystemAxis) {
567:                            c = (DefaultCoordinateSystemAxis) a;
568:                        } else {
569:                            c = new DefaultCoordinateSystemAxis(a);
570:                        }
571:                    }
572:                    axis[i] = c;
573:                }
574:                return axis;
575:            }
576:
577:            /**
578:             * Returns {@code true} if every axis in the specified {@code userCS} are colinear with axis
579:             * in this coordinate system. The comparaison is insensitive to axis order and units. What
580:             * matter is axis names (because they are fixed by ISO 19111 specification) and directions.
581:             * <p>
582:             * If this method returns {@code true}, then there is good chances that this CS can be used
583:             * together with {@code userCS} as arguments to {@link #swapAndScaleAxis swapAndScaleAxis}.
584:             * <p>
585:             * This method should not be public because current implementation is not fully consistent
586:             * for every pair of CS. It tries to check the opposite direction in addition of the usual
587:             * one, but only a few pre-defined axis declare their opposite. This method should be okay
588:             * when invoked on pre-defined CS declared in this package. {@link PredefinedCS} uses this
589:             * method only that way.
590:             */
591:            final boolean axisColinearWith(final CoordinateSystem userCS) {
592:                if (userCS.getDimension() != getDimension()) {
593:                    return false;
594:                }
595:                final DefaultCoordinateSystemAxis[] axis0 = getDefaultAxis(this );
596:                final DefaultCoordinateSystemAxis[] axis1 = getDefaultAxis(userCS);
597:                next: for (int i = 0; i < axis0.length; i++) {
598:                    final DefaultCoordinateSystemAxis direct = axis0[i];
599:                    final DefaultCoordinateSystemAxis opposite = direct
600:                            .getOpposite();
601:                    for (int j = 0; j < axis1.length; j++) {
602:                        final DefaultCoordinateSystemAxis candidate = axis1[j];
603:                        if (candidate != null) {
604:                            if (candidate.equals(direct, false, false)
605:                                    || (opposite != null && candidate.equals(
606:                                            opposite, false, false))) {
607:                                axis1[j] = null; // Flags as already compared.
608:                                continue next;
609:                            }
610:                        }
611:                    }
612:                    return false;
613:                }
614:                assert directionColinearWith(userCS);
615:                return true;
616:            }
617:
618:            /**
619:             * Compares directions only, without consideration for the axis name.
620:             */
621:            final boolean directionColinearWith(final CoordinateSystem userCS) {
622:                if (userCS.getDimension() != axis.length) {
623:                    return false;
624:                }
625:                final AxisDirection[] checks = new AxisDirection[axis.length];
626:                for (int i = 0; i < checks.length; i++) {
627:                    checks[i] = userCS.getAxis(i).getDirection().absolute();
628:                }
629:                next: for (int i = 0; i < axis.length; i++) {
630:                    final AxisDirection direction = axis[i].getDirection()
631:                            .absolute();
632:                    for (int j = 0; j < checks.length; j++) {
633:                        final AxisDirection candidate = checks[j];
634:                        if (candidate != null && candidate.equals(direction)) {
635:                            checks[j] = null; // Flags as already compared.
636:                            continue next;
637:                        }
638:                    }
639:                    return false;
640:                }
641:                return true;
642:            }
643:
644:            /**
645:             * Compares the specified object with this coordinate system for equality.
646:             *
647:             * @param  object The object to compare to {@code this}.
648:             * @param  compareMetadata {@code true} for performing a strict comparaison, or
649:             *         {@code false} for comparing only properties relevant to transformations.
650:             * @return {@code true} if both objects are equal.
651:             */
652:            public boolean equals(final AbstractIdentifiedObject object,
653:                    final boolean compareMetadata) {
654:                if (object == this ) {
655:                    return true; // Slight optimization.
656:                }
657:                if (super .equals(object, compareMetadata)) {
658:                    final AbstractCS that = (AbstractCS) object;
659:                    return equals(this .axis, that.axis, compareMetadata);
660:                }
661:                return false;
662:            }
663:
664:            /**
665:             * Returns a hash value for this coordinate system.
666:             *
667:             * @return The hash code value. This value doesn't need to be the same
668:             *         in past or future versions of this class.
669:             */
670:            public int hashCode() {
671:                int code = (int) serialVersionUID;
672:                for (int i = 0; i < axis.length; i++) {
673:                    code = code * 37 + axis[i].hashCode();
674:                }
675:                return code;
676:            }
677:
678:            /**
679:             * Format the inner part of a
680:             * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
681:             * Known Text</cite> (WKT)</A> element. Note that WKT is not yet defined for coordinate system.
682:             * Current implementation list the axis contained in this CS.
683:             *
684:             * @param  formatter The formatter to use.
685:             * @return The WKT element name. Current implementation default to the class name.
686:             */
687:            protected String formatWKT(final Formatter formatter) {
688:                for (int i = 0; i < axis.length; i++) {
689:                    formatter.append(axis[i]);
690:                }
691:                formatter.setInvalidWKT(CoordinateSystem.class);
692:                return super.formatWKT(formatter);
693:            }
694:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.