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


0001:        /*
0002:         *    GeoTools - OpenSource mapping toolkit
0003:         *    http://geotools.org
0004:         *    (C) 2005-2006, GeoTools Project Managment Committee (PMC)
0005:         *   
0006:         *    This library is free software; you can redistribute it and/or
0007:         *    modify it under the terms of the GNU Lesser General Public
0008:         *    License as published by the Free Software Foundation;
0009:         *    version 2.1 of the License.
0010:         *
0011:         *    This library is distributed in the hope that it will be useful,
0012:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014:         *    Lesser General Public License for more details.
0015:         */
0016:        package org.geotools.referencing;
0017:
0018:        // J2SE dependencies
0019:        import java.util.Set;
0020:        import java.util.Map;
0021:        import java.util.List;
0022:        import java.util.HashSet;
0023:        import java.util.Iterator;
0024:        import java.util.Collections;
0025:        import java.util.NoSuchElementException;
0026:        import java.awt.geom.Rectangle2D;
0027:        import java.awt.geom.Point2D;
0028:        import javax.swing.event.ChangeEvent;
0029:        import javax.swing.event.ChangeListener;
0030:
0031:        // OpenGIS dependencies
0032:        import org.opengis.metadata.Identifier;
0033:        import org.opengis.metadata.extent.Extent;
0034:        import org.opengis.metadata.extent.BoundingPolygon;
0035:        import org.opengis.metadata.extent.GeographicExtent;
0036:        import org.opengis.metadata.extent.GeographicBoundingBox;
0037:        import org.opengis.referencing.*;
0038:        import org.opengis.referencing.crs.*;
0039:        import org.opengis.referencing.datum.*;
0040:        import org.opengis.referencing.operation.*;
0041:        import org.opengis.referencing.cs.CoordinateSystem;
0042:        import org.opengis.referencing.cs.CoordinateSystemAxis;
0043:        import org.opengis.referencing.operation.CoordinateOperation;
0044:        import org.opengis.referencing.operation.CoordinateOperationFactory;
0045:        import org.opengis.referencing.operation.MathTransform;
0046:        import org.opengis.referencing.operation.TransformException;
0047:        import org.opengis.geometry.Envelope;
0048:        import org.opengis.geometry.DirectPosition;
0049:        import org.opengis.geometry.MismatchedDimensionException;
0050:        import org.opengis.geometry.MismatchedReferenceSystemException;
0051:
0052:        // Geotools dependencies
0053:        import org.geotools.factory.GeoTools;
0054:        import org.geotools.factory.Hints;
0055:        import org.geotools.factory.Factory;
0056:        import org.geotools.factory.FactoryNotFoundException;
0057:        import org.geotools.factory.FactoryRegistryException;
0058:        import org.geotools.geometry.Envelope2D;
0059:        import org.geotools.geometry.GeneralEnvelope;
0060:        import org.geotools.geometry.GeneralDirectPosition;
0061:        import org.geotools.metadata.iso.extent.GeographicBoundingBoxImpl;
0062:        import org.geotools.referencing.crs.DefaultGeographicCRS;
0063:        import org.geotools.referencing.factory.AbstractAuthorityFactory;
0064:        import org.geotools.referencing.factory.IdentifiedObjectFinder;
0065:        import org.geotools.referencing.operation.transform.IdentityTransform;
0066:        import org.geotools.resources.geometry.XRectangle2D;
0067:        import org.geotools.resources.CRSUtilities;
0068:        import org.geotools.resources.i18n.Errors;
0069:        import org.geotools.resources.i18n.ErrorKeys;
0070:        import org.geotools.util.Version;
0071:        import org.geotools.util.logging.Logging;
0072:        import org.geotools.util.UnsupportedImplementationException;
0073:
0074:        /**
0075:         * Simple utility class for making use of the {@linkplain CoordinateReferenceSystem
0076:         * coordinate reference system} and associated {@linkplain org.opengis.referencing.Factory}
0077:         * implementations. This utility class is made up of static final functions. This class is
0078:         * not a factory or a builder. It makes use of the GeoAPI factory interfaces provided by
0079:         * {@link ReferencingFactoryFinder}.
0080:         * <p>
0081:         * The following methods may be added in a future version:
0082:         * <ul>
0083:         *   <li>{@code CoordinateReferenceSystem parseXML(String)}</li>
0084:         * </ul>
0085:         *
0086:         * @since 2.1
0087:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/CRS.java $
0088:         * @version $Id: CRS.java 29058 2008-02-03 17:47:07Z desruisseaux $
0089:         * @author Jody Garnett (Refractions Research)
0090:         * @author Martin Desruisseaux
0091:         * @author Andrea Aime
0092:         *
0093:         * @tutorial http://docs.codehaus.org/display/GEOTOOLS/Coordinate+Transformation+Services+for+Geotools+2.1
0094:         */
0095:        public final class CRS {
0096:            /**
0097:             * The logger name to use for logging messages in this class.
0098:             */
0099:            private static final String LOGGER = "org.geotools.referencing";
0100:
0101:            /**
0102:             * A factory for CRS creation with (<var>latitude</var>, <var>longitude</var>) axis order
0103:             * (unless otherwise specified in system property). Will be created only when first needed.
0104:             */
0105:            private static CRSAuthorityFactory defaultFactory;
0106:
0107:            /**
0108:             * A factory for CRS creation with (<var>longitude</var>, <var>latitude</var>) axis order.
0109:             * Will be created only when first needed.
0110:             */
0111:            private static CRSAuthorityFactory xyFactory;
0112:
0113:            /**
0114:             * A factory for default (non-lenient) operations.
0115:             */
0116:            private static CoordinateOperationFactory strictFactory;
0117:
0118:            /**
0119:             * A factory for default lenient operations.
0120:             */
0121:            private static CoordinateOperationFactory lenientFactory;
0122:
0123:            static {
0124:                GeoTools.addChangeListener(new ChangeListener() {
0125:                    // Automatically invoked when the system-wide configuration changed.
0126:                    public void stateChanged(ChangeEvent e) {
0127:                        synchronized (CRS.class) {
0128:                            defaultFactory = null;
0129:                            xyFactory = null;
0130:                            strictFactory = null;
0131:                            lenientFactory = null;
0132:                        }
0133:                    }
0134:                });
0135:            }
0136:
0137:            /**
0138:             * Do not allow instantiation of this class.
0139:             */
0140:            private CRS() {
0141:            }
0142:
0143:            //////////////////////////////////////////////////////////////
0144:            ////                                                      ////
0145:            ////        FACTORIES, CRS CREATION AND INSPECTION        ////
0146:            ////                                                      ////
0147:            //////////////////////////////////////////////////////////////
0148:
0149:            /**
0150:             * Returns the CRS authority factory used by the {@link #decode(String,boolean) decode} methods.
0151:             * This factory is {@linkplain org.geotools.referencing.factory.BufferedAuthorityFactory buffered},
0152:             * scans over {@linkplain org.geotools.referencing.factory.AllAuthoritiesFactory all factories} and
0153:             * uses additional factories as {@linkplain org.geotools.referencing.factory.FallbackAuthorityFactory
0154:             * fallbacks} if there is more than one {@linkplain ReferencingFactoryFinder#getCRSAuthorityFactories
0155:             * registered factory} for the same authority.
0156:             * <p>
0157:             * This factory can be used as a kind of <cite>system-wide</cite> factory for all authorities.
0158:             * However for more determinist behavior, consider using a more specific factory (as returned
0159:             * by {@link ReferencingFactoryFinder#getCRSAuthorityFactory} when the authority in known.
0160:             *
0161:             * @param  longitudeFirst {@code true} if axis order should be forced to
0162:             *         (<var>longitude</var>,<var>latitude</var>). Note that {@code false} means
0163:             *         "<cite>use default</cite>", <strong>not</strong> "<cite>latitude first</cite>".
0164:             * @return The CRS authority factory.
0165:             * @throws FactoryRegistryException if the factory can't be created.
0166:             *
0167:             * @since 2.3
0168:             */
0169:            public static synchronized CRSAuthorityFactory getAuthorityFactory(
0170:                    final boolean longitudeFirst)
0171:                    throws FactoryRegistryException {
0172:                CRSAuthorityFactory factory = (longitudeFirst) ? xyFactory
0173:                        : defaultFactory;
0174:                if (factory == null)
0175:                    try {
0176:                        factory = new DefaultAuthorityFactory(longitudeFirst);
0177:                        if (longitudeFirst) {
0178:                            xyFactory = factory;
0179:                        } else {
0180:                            defaultFactory = factory;
0181:                        }
0182:                    } catch (NoSuchElementException exception) {
0183:                        // No factory registered in FactoryFinder.
0184:                        throw new FactoryNotFoundException(null, exception);
0185:                    }
0186:                return factory;
0187:            }
0188:
0189:            /**
0190:             * Returns the coordinate operation factory used by
0191:             * {@link #findMathTransform(CoordinateReferenceSystem, CoordinateReferenceSystem)
0192:             * findMathTransform} convenience methods.
0193:             *
0194:             * @param lenient {@code true} if the coordinate operations should be created
0195:             *        even when there is no information available for a datum shift.
0196:             *
0197:             * @since 2.4
0198:             */
0199:            public static synchronized CoordinateOperationFactory getCoordinateOperationFactory(
0200:                    final boolean lenient) {
0201:                CoordinateOperationFactory factory = (lenient) ? lenientFactory
0202:                        : strictFactory;
0203:                if (factory == null) {
0204:                    final Hints hints = GeoTools.getDefaultHints();
0205:                    if (lenient) {
0206:                        hints.put(Hints.LENIENT_DATUM_SHIFT, Boolean.TRUE);
0207:                    }
0208:                    factory = ReferencingFactoryFinder
0209:                            .getCoordinateOperationFactory(hints);
0210:                    if (lenient) {
0211:                        lenientFactory = factory;
0212:                    } else {
0213:                        strictFactory = factory;
0214:                    }
0215:                }
0216:                return factory;
0217:            }
0218:
0219:            /**
0220:             * Returns the version number of the specified authority database, or {@code null} if
0221:             * not available.
0222:             *
0223:             * @param  authority The authority name (typically {@code "EPSG"}).
0224:             * @return The version number of the authority database, or {@code null} if unknown.
0225:             * @throws FactoryRegistryException if no {@link CRSAuthorityFactory} implementation
0226:             *         was found for the specified authority.
0227:             *
0228:             * @since 2.4
0229:             */
0230:            public static Version getVersion(final String authority)
0231:                    throws FactoryRegistryException {
0232:                Object factory = ReferencingFactoryFinder
0233:                        .getCRSAuthorityFactory(authority, null);
0234:                final Set guard = new HashSet(); // Safety against never-ending recursivity.
0235:                while (factory instanceof  Factory && guard.add(factory)) {
0236:                    final Map hints = ((Factory) factory)
0237:                            .getImplementationHints();
0238:                    final Object version = hints.get(Hints.VERSION);
0239:                    if (version instanceof  Version) {
0240:                        return (Version) version;
0241:                    }
0242:                    factory = hints.get(Hints.CRS_AUTHORITY_FACTORY);
0243:                }
0244:                return null;
0245:            }
0246:
0247:            /**
0248:             * Get the list of the codes that are supported by the given authority. For example
0249:             * {@code getSupportedCodes("EPSG")} may returns {@code "EPSG:2000"}, {@code "EPSG:2001"},
0250:             * {@code "EPSG:2002"}, <cite>etc</cite>. It may also returns {@code "2000"}, {@code "2001"},
0251:             * {@code "2002"}, <cite>etc.</cite> without the {@code "EPSG:"} prefix. Whatever the authority
0252:             * name is prefixed or not is factory implementation dependent.
0253:             * <p>
0254:             * If there is more than one factory for the given authority, then this method merges the
0255:             * code set of all of them. If a factory fails to provide a set of supported code, then
0256:             * this particular factory is ignored. Please be aware of the following potential issues:
0257:             * <p>
0258:             * <ul>
0259:             *   <li>If there is more than one EPSG databases (for example an 
0260:             *       {@linkplain org.geotools.referencing.factory.epsg.AccessDataSource Access} and a
0261:             *       {@linkplain org.geotools.referencing.factory.epsg.PostgreDataSource PostgreSQL} ones),
0262:             *       then this method will connect to all of them even if their content are identical.</li>
0263:             *
0264:             *   <li>If two factories format their codes differently (e.g. {@code "4326"} and
0265:             *       {@code "EPSG:4326"}), then the returned set will contain a lot of synonymous
0266:             *       codes.</li>
0267:             *
0268:             *   <li>For any code <var>c</var> in the returned set, there is no warranty that
0269:             *       <code>{@linkplain #decode decode}(c)</code> will use the same authority
0270:             *       factory than the one that formatted <var>c</var>.</li>
0271:             *   
0272:             *   <li>This method doesn't report connection problems since it doesn't throw any exception.
0273:             *       {@link FactoryException}s are logged as warnings and otherwise ignored.</li>
0274:             * </ul>
0275:             * <p>
0276:             * If a more determinist behavior is wanted, consider the code below instead.
0277:             * The following code exploit only one factory, the "preferred" one.
0278:             *
0279:             * <blockquote><code>
0280:             * {@linkplain CRSAuthorityFactory} factory = FactoryFinder.{@linkplain
0281:             * ReferencingFactoryFinder#getCRSAuthorityFactory getCRSAuthorityFactory}(authority, null);<br>
0282:             * Set&lt;String&gt; codes = factory.{@linkplain CRSAuthorityFactory#getAuthorityCodes
0283:             * getAuthorityCodes}(CoordinateReferenceSystem.class);<br>
0284:             * String code = <cite>...choose a code here...</cite><br>
0285:             * {@linkplain CoordinateReferenceSystem} crs = factory.createCoordinateReferenceSystem(code);
0286:             * </code></blockquote>
0287:             *
0288:             * @param  authority The authority name (for example {@code "EPSG"}).
0289:             * @return The set of supported codes. May be empty, but never null.
0290:             */
0291:            public static Set/*<String>*/getSupportedCodes(
0292:                    final String authority) {
0293:                return DefaultAuthorityFactory.getSupportedCodes(authority);
0294:            }
0295:
0296:            /**
0297:             * Returns the set of the authority identifiers supported by registered authority factories.
0298:             * This method search only for {@linkplain CRSAuthorityFactory CRS authority factories}.
0299:             *
0300:             * @param  returnAliases If {@code true}, the set will contain all identifiers for each
0301:             *         authority. If {@code false}, only the first one
0302:             * @return The set of supported authorities. May be empty, but never null.
0303:             *
0304:             * @since 2.3.1
0305:             */
0306:            public static Set/*<String>*/getSupportedAuthorities(
0307:                    final boolean returnAliases) {
0308:                return DefaultAuthorityFactory
0309:                        .getSupportedAuthorities(returnAliases);
0310:            }
0311:
0312:            /**
0313:             * Return a Coordinate Reference System for the specified code.
0314:             * Note that the code needs to mention the authority. Examples:
0315:             *
0316:             * <blockquote><pre>
0317:             * EPSG:1234
0318:             * AUTO:42001, ..., ..., ...
0319:             * </pre></blockquote>
0320:             *
0321:             * If there is more than one factory implementation for the same authority, then all additional
0322:             * factories are {@linkplain org.geotools.referencing.factory.FallbackAuthorityFactory fallbacks}
0323:             * to be used only when the first acceptable factory failed to create the requested CRS object.
0324:             * <p>
0325:             * CRS objects created by previous calls to this method are
0326:             * {@linkplain org.geotools.referencing.factory.BufferedAuthorityFactory cached in a buffer}
0327:             * using {@linkplain java.lang.ref.WeakReference weak references}. Subsequent calls to this
0328:             * method with the same authority code should be fast, unless the CRS object has been garbage
0329:             * collected.
0330:             *
0331:             * @param  code The Coordinate Reference System authority code.
0332:             * @return The Coordinate Reference System for the provided code.
0333:             * @throws NoSuchAuthorityCodeException If the code could not be understood.
0334:             * @throws FactoryException if the CRS creation failed for an other reason.
0335:             *
0336:             * @see #getSupportedCodes
0337:             * @see org.geotools.referencing.factory.AllAuthoritiesFactory#createCoordinateReferenceSystem
0338:             */
0339:            public static CoordinateReferenceSystem decode(final String code)
0340:                    throws NoSuchAuthorityCodeException, FactoryException {
0341:                /*
0342:                 * Do not use Boolean.getBoolean(GeoTools.FORCE_LONGITUDE_FIRST_AXIS_ORDER).
0343:                 * The boolean argument should be 'false', which means "use system default"
0344:                 * (not "latitude first").
0345:                 */
0346:                return decode(code, false);
0347:            }
0348:
0349:            /**
0350:             * Return a Coordinate Reference System for the specified code, maybe forcing the axis order
0351:             * to (<var>longitude</var>, <var>latitude</var>). The {@code code} argument value is parsed
0352:             * as in "<code>{@linkplain #decode(String) decode}(code)</code>". The {@code longitudeFirst}
0353:             * argument value controls the hints to be given to the {@linkplain ReferencingFactoryFinder
0354:             * factory finder} as in the following pseudo-code:
0355:             * <p>
0356:             * <blockquote><pre>
0357:             * if (longitudeFirst) {
0358:             *     hints.put({@linkplain Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER}, {@linkplain Boolean#TRUE});
0359:             * } else {
0360:             *     // Do not set the FORCE_LONGITUDE_FIRST_AXIS_ORDER hint to FALSE.
0361:             *     // Left it unset, which means "use system default".
0362:             * }
0363:             * </pre></blockquote>
0364:             *
0365:             * The following table compare this method {@code longitudeFirst} argument with the
0366:             * hint meaning:
0367:             * <p>
0368:             * <table border='1'>
0369:             * <tr>
0370:             *   <th>This method argument</th>
0371:             *   <th>{@linkplain Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER Hint} value</th>
0372:             *   <th>Meaning</th>
0373:             * </tr>
0374:             * <tr>
0375:             *   <td>{@code true}</td>
0376:             *   <td>{@link Boolean#TRUE TRUE}</td>
0377:             *   <td>All coordinate reference systems are forced to
0378:             *       (<var>longitude</var>, <var>latitude</var>) axis order.</td>
0379:             * </tr>
0380:             * <tr>
0381:             *   <td>{@code false}</td>
0382:             *   <td>{@code null}</td>
0383:             *   <td>Coordinate reference systems may or may not be forced to
0384:             *       (<var>longitude</var>, <var>latitude</var>) axis order. The behavior depends on user
0385:             *       setting, for example the value of the <code>{@value
0386:             *       org.geotools.referencing.factory.epsg.LongitudeFirstFactory#SYSTEM_DEFAULT_KEY}</code>
0387:             *       system property.</td>
0388:             * </tr>
0389:             * <tr>
0390:             *   <td></td>
0391:             *   <td>{@link Boolean#FALSE FALSE}</td>
0392:             *   <td>Forcing (<var>longitude</var>, <var>latitude</var>) axis order is not allowed,
0393:             *       no matter the value of the <code>{@value
0394:             *       org.geotools.referencing.factory.epsg.LongitudeFirstFactory#SYSTEM_DEFAULT_KEY}</code>
0395:             *       system property.</td>
0396:             * </tr>
0397:             * </table>
0398:             *
0399:             * @param  code The Coordinate Reference System authority code.
0400:             * @param  longitudeFirst {@code true} if axis order should be forced to
0401:             *         (<var>longitude</var>, <var>latitude</var>). Note that {@code false} means
0402:             *         "<cite>use default</cite>", <strong>not</strong> "<cite>latitude first</cite>".
0403:             * @return The Coordinate Reference System for the provided code.
0404:             * @throws NoSuchAuthorityCodeException If the code could not be understood.
0405:             * @throws FactoryException if the CRS creation failed for an other reason.
0406:             *
0407:             * @see #getSupportedCodes
0408:             * @see Hints#FORCE_LONGITUDE_FIRST_AXIS_ORDER
0409:             *
0410:             * @since 2.3
0411:             */
0412:            public static CoordinateReferenceSystem decode(String code,
0413:                    final boolean longitudeFirst)
0414:                    throws NoSuchAuthorityCodeException, FactoryException {
0415:                // @deprecated: 'toUpperCase()' is required only for epsg-wkt.
0416:                // Remove after we deleted the epsg-wkt module.
0417:                code = code.trim().toUpperCase();
0418:                return getAuthorityFactory(longitudeFirst)
0419:                        .createCoordinateReferenceSystem(code);
0420:            }
0421:
0422:            /**
0423:             * Parses a
0424:             * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
0425:             * Known Text</cite></A> (WKT) into a CRS object. This convenience method is a
0426:             * shorthand for the following:
0427:             *
0428:             * <blockquote><code>
0429:             * FactoryFinder.{@linkplain ReferencingFactoryFinder#getCRSFactory getCRSFactory}(null).{@linkplain
0430:             * org.opengis.referencing.crs.CRSFactory#createFromWKT createFromWKT}(wkt);
0431:             * </code></blockquote>
0432:             */
0433:            public static CoordinateReferenceSystem parseWKT(final String wkt)
0434:                    throws FactoryException {
0435:                return ReferencingFactoryFinder.getCRSFactory(null)
0436:                        .createFromWKT(wkt);
0437:            }
0438:
0439:            /**
0440:             * Returns the valid area bounding box for the specified coordinate reference system, or
0441:             * {@code null} if unknown. This method search in the metadata informations associated with
0442:             * the given CRS. The returned envelope is expressed in terms of the specified CRS.
0443:             *
0444:             * @param  crs The coordinate reference system, or {@code null}.
0445:             * @return The envelope in terms of the specified CRS, or {@code null} if none.
0446:             *
0447:             * @since 2.2
0448:             */
0449:            public static Envelope getEnvelope(CoordinateReferenceSystem crs) {
0450:                Envelope envelope = getGeographicEnvelope(crs);
0451:                if (envelope != null) {
0452:                    final CoordinateReferenceSystem sourceCRS = envelope
0453:                            .getCoordinateReferenceSystem();
0454:                    if (sourceCRS != null)
0455:                        try {
0456:                            crs = CRSUtilities.getCRS2D(crs);
0457:                            if (!equalsIgnoreMetadata(sourceCRS, crs)) {
0458:                                final GeneralEnvelope e;
0459:                                e = transform(findMathTransform(sourceCRS, crs,
0460:                                        true), envelope);
0461:                                e.setCoordinateReferenceSystem(crs);
0462:                                envelope = e;
0463:                            }
0464:                        } catch (FactoryException exception) {
0465:                            /*
0466:                             * No transformation path was found for the specified CRS. Logs a warning and
0467:                             * returns null, since it is a legal return value according this method contract.
0468:                             */
0469:                            envelope = null;
0470:                            unexpectedException("getEnvelope", exception);
0471:                        } catch (TransformException exception) {
0472:                            /*
0473:                             * The envelope is probably outside the range of validity for this CRS.
0474:                             * It should not occurs, since the envelope is supposed to describe the
0475:                             * CRS area of validity. Logs a warning and returns null, since it is a
0476:                             * legal return value according this method contract.
0477:                             */
0478:                            envelope = null;
0479:                            unexpectedException("getEnvelope", exception);
0480:                        }
0481:                }
0482:                return envelope;
0483:            }
0484:
0485:            /**
0486:             * Returns the valid area bounding box for the specified coordinate reference system, or
0487:             * {@code null} if unknown. This method search in the metadata informations associated with
0488:             * the given CRS. The returned envelope is always expressed in terms of the
0489:             * {@linkplain DefaultGeographicCRS#WGS_84 WGS 84} CRS.
0490:             *
0491:             * @param  crs The coordinate reference system, or {@code null}.
0492:             * @return The envelope, or {@code null} if none.
0493:             */
0494:            private static Envelope getGeographicEnvelope(
0495:                    final CoordinateReferenceSystem crs) {
0496:                GeneralEnvelope envelope = null;
0497:                if (crs != null) {
0498:                    final Extent validArea = crs.getValidArea();
0499:                    if (validArea != null) {
0500:                        for (final Iterator it = validArea
0501:                                .getGeographicElements().iterator(); it
0502:                                .hasNext();) {
0503:                            final GeographicExtent geo = (GeographicExtent) it
0504:                                    .next();
0505:                            final GeneralEnvelope candidate;
0506:                            if (geo instanceof  GeographicBoundingBox) {
0507:                                final GeographicBoundingBox bounds = (GeographicBoundingBox) geo;
0508:                                final Boolean inclusion = bounds.getInclusion();
0509:                                if (inclusion == null) {
0510:                                    // Status unknow; ignore this bounding box.
0511:                                    continue;
0512:                                }
0513:                                if (!inclusion.booleanValue()) {
0514:                                    // TODO: we could uses Envelope.substract if such
0515:                                    //       a method is defined in a future version.
0516:                                    continue;
0517:                                }
0518:                                candidate = new GeneralEnvelope(
0519:                                        new double[] {
0520:                                                bounds.getWestBoundLongitude(),
0521:                                                bounds.getSouthBoundLatitude() },
0522:                                        new double[] {
0523:                                                bounds.getEastBoundLongitude(),
0524:                                                bounds.getNorthBoundLatitude() });
0525:                                candidate
0526:                                        .setCoordinateReferenceSystem(DefaultGeographicCRS.WGS84);
0527:                            } else if (geo instanceof  BoundingPolygon) {
0528:                                // TODO: iterates through all polygons and invoke Polygon.getEnvelope();
0529:                                continue;
0530:                            } else {
0531:                                continue;
0532:                            }
0533:                            if (envelope == null) {
0534:                                envelope = candidate;
0535:                            } else {
0536:                                envelope.add(candidate);
0537:                            }
0538:                        }
0539:                    }
0540:                }
0541:                return envelope;
0542:            }
0543:
0544:            /**
0545:             * Returns the valid geographic area for the specified coordinate reference system, or
0546:             * {@code null} if unknown. This method search in the metadata informations associated
0547:             * with the given CRS.
0548:             *
0549:             * @param  crs The coordinate reference system, or {@code null}.
0550:             * @return The geographic area, or {@code null} if none.
0551:             *
0552:             * @since 2.3
0553:             */
0554:            public static GeographicBoundingBox getGeographicBoundingBox(
0555:                    final CoordinateReferenceSystem crs) {
0556:                final Envelope envelope = getGeographicEnvelope(crs);
0557:                if (envelope != null)
0558:                    try {
0559:                        return new GeographicBoundingBoxImpl(envelope);
0560:                    } catch (TransformException exception) {
0561:                        /*
0562:                         * Should not occurs, since envelopes are usually already in geographic coordinates.
0563:                         * If it occurs anyway, returns null since it is allowed by this method contract.
0564:                         */
0565:                        unexpectedException("getGeographicBoundingBox",
0566:                                exception);
0567:                    }
0568:                return null;
0569:            }
0570:
0571:            /**
0572:             * Returns the first horizontal coordinate reference system found in the given CRS,
0573:             * or {@code null} if there is none. A horizontal CRS is usually a two-dimensional
0574:             * {@linkplain GeographicCRS geographic} or {@linkplain ProjectedCRS projected} CRS.
0575:             *
0576:             * @since 2.4
0577:             */
0578:            public static SingleCRS getHorizontalCRS(
0579:                    final CoordinateReferenceSystem crs) {
0580:                if (crs instanceof  SingleCRS
0581:                        && crs.getCoordinateSystem().getDimension() == 2) {
0582:                    CoordinateReferenceSystem base = crs;
0583:                    while (base instanceof  GeneralDerivedCRS) {
0584:                        base = ((GeneralDerivedCRS) base).getBaseCRS();
0585:                    }
0586:                    // No need to test for ProjectedCRS, since the code above unwrap it.
0587:                    if (base instanceof  GeographicCRS) {
0588:                        return (SingleCRS) crs; // Really returns 'crs', not 'base'.
0589:                    }
0590:                }
0591:                if (crs instanceof  CompoundCRS) {
0592:                    final List/*<CoordinateReferenceSystem>*/c = ((CompoundCRS) crs)
0593:                            .getCoordinateReferenceSystems();
0594:                    for (final Iterator it = c.iterator(); it.hasNext();) {
0595:                        final SingleCRS candidate = getHorizontalCRS((CoordinateReferenceSystem) it
0596:                                .next());
0597:                        if (candidate != null) {
0598:                            return candidate;
0599:                        }
0600:                    }
0601:                }
0602:                return null;
0603:            }
0604:
0605:            /**
0606:             * Returns the first projected coordinate reference system found in a the given CRS,
0607:             * or {@code null} if there is none.
0608:             *
0609:             * @since 2.4
0610:             */
0611:            public static ProjectedCRS getProjectedCRS(
0612:                    final CoordinateReferenceSystem crs) {
0613:                if (crs instanceof  ProjectedCRS) {
0614:                    return (ProjectedCRS) crs;
0615:                }
0616:                if (crs instanceof  CompoundCRS) {
0617:                    final List/*<CoordinateReferenceSystem>*/c = ((CompoundCRS) crs)
0618:                            .getCoordinateReferenceSystems();
0619:                    for (final Iterator it = c.iterator(); it.hasNext();) {
0620:                        final ProjectedCRS candidate = getProjectedCRS((CoordinateReferenceSystem) it
0621:                                .next());
0622:                        if (candidate != null) {
0623:                            return candidate;
0624:                        }
0625:                    }
0626:                }
0627:                return null;
0628:            }
0629:
0630:            /**
0631:             * Returns the first vertical coordinate reference system found in a the given CRS,
0632:             * or {@code null} if there is none.
0633:             *
0634:             * @since 2.4
0635:             */
0636:            public static VerticalCRS getVerticalCRS(
0637:                    final CoordinateReferenceSystem crs) {
0638:                if (crs instanceof  VerticalCRS) {
0639:                    return (VerticalCRS) crs;
0640:                }
0641:                if (crs instanceof  CompoundCRS) {
0642:                    final List/*<CoordinateReferenceSystem>*/c = ((CompoundCRS) crs)
0643:                            .getCoordinateReferenceSystems();
0644:                    for (final Iterator it = c.iterator(); it.hasNext();) {
0645:                        final VerticalCRS candidate = getVerticalCRS((CoordinateReferenceSystem) it
0646:                                .next());
0647:                        if (candidate != null) {
0648:                            return candidate;
0649:                        }
0650:                    }
0651:                }
0652:                return null;
0653:            }
0654:
0655:            /**
0656:             * Returns the first temporal coordinate reference system found in the given CRS,
0657:             * or {@code null} if there is none.
0658:             *
0659:             * @since 2.4
0660:             */
0661:            public static TemporalCRS getTemporalCRS(
0662:                    final CoordinateReferenceSystem crs) {
0663:                if (crs instanceof  TemporalCRS) {
0664:                    return (TemporalCRS) crs;
0665:                }
0666:                if (crs instanceof  CompoundCRS) {
0667:                    final List/*<CoordinateReferenceSystem>*/c = ((CompoundCRS) crs)
0668:                            .getCoordinateReferenceSystems();
0669:                    for (final Iterator it = c.iterator(); it.hasNext();) {
0670:                        final TemporalCRS candidate = getTemporalCRS((CoordinateReferenceSystem) it
0671:                                .next());
0672:                        if (candidate != null) {
0673:                            return candidate;
0674:                        }
0675:                    }
0676:                }
0677:                return null;
0678:            }
0679:
0680:            /**
0681:             * Returns the first ellipsoid found in a coordinate reference system,
0682:             * or {@code null} if there is none.
0683:             *
0684:             * @since 2.4
0685:             */
0686:            public static Ellipsoid getEllipsoid(
0687:                    final CoordinateReferenceSystem crs) {
0688:                final Datum datum = CRSUtilities.getDatum(crs);
0689:                if (datum instanceof  GeodeticDatum) {
0690:                    return ((GeodeticDatum) datum).getEllipsoid();
0691:                }
0692:                if (crs instanceof  CompoundCRS) {
0693:                    final List/*<CoordinateReferenceSystem>*/c = ((CompoundCRS) crs)
0694:                            .getCoordinateReferenceSystems();
0695:                    for (final Iterator it = c.iterator(); it.hasNext();) {
0696:                        final Ellipsoid candidate = getEllipsoid((CoordinateReferenceSystem) it
0697:                                .next());
0698:                        if (candidate != null) {
0699:                            return candidate;
0700:                        }
0701:                    }
0702:                }
0703:                return null;
0704:            }
0705:
0706:            /**
0707:             * Compares the specified objects for equality. If both objects are Geotools
0708:             * implementations of class {@link AbstractIdentifiedObject}, then this method
0709:             * will ignore the metadata during the comparaison.
0710:             *
0711:             * @param  object1 The first object to compare (may be null).
0712:             * @param  object2 The second object to compare (may be null).
0713:             * @return {@code true} if both objects are equals.
0714:             *
0715:             * @since 2.2
0716:             */
0717:            public static boolean equalsIgnoreMetadata(final Object object1,
0718:                    final Object object2) {
0719:                if (object1 == object2) {
0720:                    return true;
0721:                }
0722:                if (object1 instanceof  AbstractIdentifiedObject
0723:                        && object2 instanceof  AbstractIdentifiedObject) {
0724:                    return ((AbstractIdentifiedObject) object1).equals(
0725:                            ((AbstractIdentifiedObject) object2), false);
0726:                }
0727:                return object1 != null && object1.equals(object2);
0728:            }
0729:
0730:            /**
0731:             * Looks up an identifier for the specified object. This method searchs in registered factories
0732:             * for an object {@linkplain #equalsIgnoreMetadata equals, ignoring metadata}, to the specified
0733:             * object. If such object is found, then its identifier is returned. Otherwise this method
0734:             * returns {@code null}.
0735:             * <p>
0736:             * This convenience method delegates its work to {@link IdentifiedObjectFinder}. Consider using
0737:             * the later if more control are wanted, for example if the search shall be performed only on
0738:             * some {@linkplain AuthorityFactory authority factories} instead of all registered onez, or
0739:             * if the full {@linkplain IdentifiedObject identified object} is wanted instead of only its
0740:             * identifier.
0741:             * 
0742:             * @param  object The object (usually a {@linkplain CoordinateReferenceSystem coordinate
0743:             *         reference system}) looked up.
0744:             * @param  fullScan If {@code true}, an exhaustive full scan against all registered objects
0745:             *         will be performed (may be slow). Otherwise only a fast lookup based on embedded
0746:             *         identifiers and names will be performed.
0747:             * @return The identifier, or {@code null} if not found.
0748:             * @throws FactoryException if an unexpected failure occured during the search.
0749:             *
0750:             * @see AbstractAuthorityFactory#getIdentifiedObjectFinder
0751:             * @see IdentifiedObjectFinder#find
0752:             *
0753:             * @since 2.4
0754:             */
0755:            public static String lookupIdentifier(
0756:                    final IdentifiedObject object, final boolean fullScan)
0757:                    throws FactoryException {
0758:                /*
0759:                 * We perform the search using the 'xyFactory' because our implementation of
0760:                 * IdentifiedObjectFinder should be able to inspect both the (x,y) and (y,x)
0761:                 * axis order using this factory.
0762:                 */
0763:                final AbstractAuthorityFactory xyFactory = (AbstractAuthorityFactory) getAuthorityFactory(true);
0764:                final IdentifiedObjectFinder finder = xyFactory
0765:                        .getIdentifiedObjectFinder(object.getClass());
0766:                finder.setFullScanAllowed(fullScan);
0767:                return finder.findIdentifier(object);
0768:            }
0769:
0770:            /**
0771:             * Looks up an identifier for the specified coordinate reference system.
0772:             * 
0773:             * @param crs the coordinate reference system looked up.
0774:             * @param authorities the authority that we should look up the identifier into. 
0775:             *         If {@code null} the search will to be performed against all authorities.
0776:             * @param fullScan if {@code true}, an exhaustive full scan against all registered CRS
0777:             *         will be performed (may be slow). Otherwise only a fast lookup based on embedded
0778:             *         identifiers and names will be performed.
0779:             * @return The identifier, or {@code null} if not found.
0780:             *
0781:             * @since 2.3.1
0782:             *
0783:             * @deprecated Replaced by {@link #lookupIdentifier(IdentifiedObject, boolean)},
0784:             *             which should be faster since it tries to leverage database index.
0785:             */
0786:            public static String lookupIdentifier(
0787:                    final CoordinateReferenceSystem crs,
0788:                    Set/*<String>*/authorities, final boolean fullScan) {
0789:                // gather the authorities we're considering
0790:                if (authorities == null) {
0791:                    authorities = getSupportedAuthorities(false);
0792:                }
0793:                // first check if one of the identifiers can be used to spot directly
0794:                // a CRS (and check it's actually equal to one in the db)
0795:                for (Iterator it = crs.getIdentifiers().iterator(); it
0796:                        .hasNext();) {
0797:                    final Identifier id = (Identifier) it.next();
0798:                    final CoordinateReferenceSystem candidate;
0799:                    try {
0800:                        candidate = CRS.decode(id.toString());
0801:                    } catch (FactoryException e) {
0802:                        // the identifier was not recognized, no problem, let's go on
0803:                        continue;
0804:                    }
0805:                    if (equalsIgnoreMetadata(candidate, crs)) {
0806:                        String identifier = getSRSFromCRS(candidate,
0807:                                authorities);
0808:                        if (identifier != null) {
0809:                            return identifier;
0810:                        }
0811:                    }
0812:                }
0813:
0814:                // try a quick name lookup
0815:                try {
0816:                    CoordinateReferenceSystem candidate = CRS.decode(crs
0817:                            .getName().toString());
0818:                    if (equalsIgnoreMetadata(candidate, crs)) {
0819:                        String identifier = getSRSFromCRS(candidate,
0820:                                authorities);
0821:                        if (identifier != null) {
0822:                            return identifier;
0823:                        }
0824:                    }
0825:                } catch (Exception e) {
0826:                    // the name was not recognized, no problem, let's go on
0827:                }
0828:
0829:                // here we exhausted the quick paths, bail out if the user does not want a full scan
0830:                if (!fullScan) {
0831:                    return null;
0832:                }
0833:                // a direct lookup did not work, let's try a full scan of known CRS then
0834:                // TODO: implement a smarter method in the actual EPSG authorities, which may
0835:                // well be this same loop if they do have no other search capabilities
0836:                for (Iterator itAuth = authorities.iterator(); itAuth.hasNext();) {
0837:                    String authority = (String) itAuth.next();
0838:                    Set codes = CRS.getSupportedCodes(authority);
0839:                    for (Iterator itCodes = codes.iterator(); itCodes.hasNext();) {
0840:                        String code = (String) itCodes.next();
0841:                        try {
0842:                            final CoordinateReferenceSystem candidate;
0843:                            if (code.indexOf(':') == -1) {
0844:                                candidate = CRS.decode(authority + ':' + code);
0845:                            } else {
0846:                                candidate = CRS.decode(code);
0847:                            }
0848:                            if (CRS.equalsIgnoreMetadata(candidate, crs)) {
0849:                                return getSRSFromCRS(candidate, Collections
0850:                                        .singleton(authority));
0851:                            }
0852:                        } catch (Exception e) {
0853:                            // some CRS cannot be decoded properly
0854:                        }
0855:                    }
0856:                }
0857:                return null;
0858:            }
0859:
0860:            /**
0861:             * Scans the identifiers list looking for an EPSG id
0862:             *
0863:             * @deprecated Used by deprecated methods only.
0864:             */
0865:            private static String getSRSFromCRS(
0866:                    final CoordinateReferenceSystem crs, final Set authorities) {
0867:                for (Iterator itAuth = authorities.iterator(); itAuth.hasNext();) {
0868:                    final String authority = (String) itAuth.next();
0869:                    final String prefix = authority + ":";
0870:                    for (Iterator itIdent = crs.getIdentifiers().iterator(); itIdent
0871:                            .hasNext();) {
0872:                        NamedIdentifier id = (NamedIdentifier) itIdent.next();
0873:                        String idName = id.toString();
0874:                        if (idName.startsWith(prefix))
0875:                            return idName;
0876:                    }
0877:                }
0878:                return null;
0879:            }
0880:
0881:            /////////////////////////////////////////////////
0882:            ////                                         ////
0883:            ////          COORDINATE OPERATIONS          ////
0884:            ////                                         ////
0885:            /////////////////////////////////////////////////
0886:
0887:            /**
0888:             * Grab a transform between two Coordinate Reference Systems. This convenience method is a
0889:             * shorthand for the following:
0890:             *
0891:             * <blockquote><code>FactoryFinder.{@linkplain ReferencingFactoryFinder#getCoordinateOperationFactory
0892:             * getCoordinateOperationFactory}(null).{@linkplain CoordinateOperationFactory#createOperation
0893:             * createOperation}(sourceCRS, targetCRS).{@linkplain CoordinateOperation#getMathTransform
0894:             * getMathTransform}();</code></blockquote>
0895:             *
0896:             * Note that some metadata like {@linkplain CoordinateOperation#getPositionalAccuracy
0897:             * positional accuracy} are lost by this method. If those metadata are wanted, use the
0898:             * {@linkplain CoordinateOperationFactory coordinate operation factory} directly.
0899:             * <p>
0900:             * Sample use:
0901:             * <blockquote><code>
0902:             * {@linkplain MathTransform} transform = CRS.findMathTransform(
0903:             * CRS.{@linkplain #decode decode}("EPSG:42102"),
0904:             * CRS.{@linkplain #decode decode}("EPSG:4326") );
0905:             * </blockquote></code>
0906:             * 
0907:             * @param  sourceCRS The source CRS.
0908:             * @param  targetCRS The target CRS.
0909:             * @return The math transform from {@code sourceCRS} to {@code targetCRS}.
0910:             * @throws FactoryException If no math transform can be created for the specified source and
0911:             *         target CRS.
0912:             */
0913:            public static MathTransform findMathTransform(
0914:                    final CoordinateReferenceSystem sourceCRS,
0915:                    final CoordinateReferenceSystem targetCRS)
0916:                    throws FactoryException {
0917:                return findMathTransform(sourceCRS, targetCRS, false);
0918:            }
0919:
0920:            /**
0921:             * Grab a transform between two Coordinate Reference Systems. This method is similar to
0922:             * <code>{@linkplain #findMathTransform(CoordinateReferenceSystem, CoordinateReferenceSystem)
0923:             * findMathTransform}(sourceCRS, targetCRS)</code>, except that it can optionally tolerate
0924:             * <cite>lenient datum shift</cite>. If the {@code lenient} argument is {@code true},
0925:             * then this method will not throw a "<cite>Bursa-Wolf parameters required</cite>"
0926:             * exception during datum shifts if the Bursa-Wolf paramaters are not specified.
0927:             * Instead it will assume a no datum shift.
0928:             * 
0929:             * @param  sourceCRS The source CRS.
0930:             * @param  targetCRS The target CRS.
0931:             * @param  lenient {@code true} if the math transform should be created even when there is
0932:             *         no information available for a datum shift. The default value is {@code false}.
0933:             * @return The math transform from {@code sourceCRS} to {@code targetCRS}.
0934:             * @throws FactoryException If no math transform can be created for the specified source and
0935:             *         target CRS.
0936:             *
0937:             * @see Hints#LENIENT_DATUM_SHIFT
0938:             */
0939:            public static MathTransform findMathTransform(
0940:                    final CoordinateReferenceSystem sourceCRS,
0941:                    final CoordinateReferenceSystem targetCRS, boolean lenient)
0942:                    throws FactoryException {
0943:                if (equalsIgnoreMetadata(sourceCRS, targetCRS)) {
0944:                    // Slight optimization in order to avoid the overhead of loading the full referencing engine.
0945:                    return IdentityTransform.create(sourceCRS
0946:                            .getCoordinateSystem().getDimension());
0947:                }
0948:                return getCoordinateOperationFactory(lenient).createOperation(
0949:                        sourceCRS, targetCRS).getMathTransform();
0950:            }
0951:
0952:            /**
0953:             * Transforms an envelope using the given {@linkplain MathTransform math transform}.
0954:             * The transformation is only approximative. Note that the returned envelope may not
0955:             * have the same number of dimensions than the original envelope.
0956:             * <p>
0957:             * Note that this method can not handle the case where the envelope contains the North or
0958:             * South pole, or when it cross the &plusmn;180� longitude, because {@linkplain MathTransform
0959:             * math transforms} do not carry suffisient informations. For a more robust envelope
0960:             * transformation, use {@link #transform(CoordinateOperation, Envelope)} instead.
0961:             *
0962:             * @param  transform The transform to use.
0963:             * @param  envelope Envelope to transform, or {@code null}. This envelope will not be modified.
0964:             * @return The transformed envelope, or {@code null} if {@code envelope} was null.
0965:             * @throws TransformException if a transform failed.
0966:             *
0967:             * @since 2.4
0968:             */
0969:            public static GeneralEnvelope transform(
0970:                    final MathTransform transform, final Envelope envelope)
0971:                    throws TransformException {
0972:                return transform(transform, envelope, null);
0973:            }
0974:
0975:            /**
0976:             * Implementation of {@link #transform(MathTransform, Envelope)} with the opportunity to
0977:             * save the projected center coordinate. If {@code targetPt} is non-null, then this method
0978:             * will set it to the center of the source envelope projected to the target CRS.
0979:             */
0980:            private static GeneralEnvelope transform(
0981:                    final MathTransform transform, final Envelope envelope,
0982:                    GeneralDirectPosition targetPt) throws TransformException {
0983:                if (envelope == null) {
0984:                    return null;
0985:                }
0986:                if (transform.isIdentity()) {
0987:                    /*
0988:                     * Slight optimisation: Just copy the envelope. Note that we need to set the CRS
0989:                     * to null because we don't know what the target CRS was supposed to be. Even if
0990:                     * an identity transform often imply that the target CRS is the same one than the
0991:                     * source CRS, it is not always the case. The metadata may be differents, or the
0992:                     * transform may be a datum shift without Bursa-Wolf parameters, etc.
0993:                     */
0994:                    final GeneralEnvelope e = new GeneralEnvelope(envelope);
0995:                    e.setCoordinateReferenceSystem(null);
0996:                    return e;
0997:                }
0998:                /*
0999:                 * Checks argument validity: envelope and math transform dimensions must be consistent.
1000:                 */
1001:                final int sourceDim = transform.getSourceDimensions();
1002:                if (envelope.getDimension() != sourceDim) {
1003:                    throw new MismatchedDimensionException(Errors.format(
1004:                            ErrorKeys.MISMATCHED_DIMENSION_$2, new Integer(
1005:                                    sourceDim), new Integer(envelope
1006:                                    .getDimension())));
1007:                }
1008:                int coordinateNumber = 0;
1009:                GeneralEnvelope transformed = null;
1010:                if (targetPt == null) {
1011:                    targetPt = new GeneralDirectPosition(transform
1012:                            .getTargetDimensions());
1013:                }
1014:                /*
1015:                 * Before to run the loops, we must initialize the coordinates to the minimal values.
1016:                 * This coordinates will be updated in the 'switch' statement inside the 'while' loop.
1017:                 */
1018:                final GeneralDirectPosition sourcePt = new GeneralDirectPosition(
1019:                        sourceDim);
1020:                for (int i = sourceDim; --i >= 0;) {
1021:                    sourcePt.setOrdinate(i, envelope.getMinimum(i));
1022:                }
1023:                loop: while (true) {
1024:                    /*
1025:                     * Transform a point and add the transformed point to the destination envelope.
1026:                     * Note that the very last point to be projected must be the envelope center.
1027:                     */
1028:                    if (targetPt != transform.transform(sourcePt, targetPt)) {
1029:                        throw new UnsupportedImplementationException(transform
1030:                                .getClass());
1031:                    }
1032:                    if (transformed != null) {
1033:                        transformed.add(targetPt);
1034:                    } else {
1035:                        transformed = new GeneralEnvelope(targetPt, targetPt);
1036:                    }
1037:                    /*
1038:                     * Get the next point's coordinates.  The 'coordinateNumber' variable should
1039:                     * be seen as a number in base 3 where the number of digits is equals to the
1040:                     * number of dimensions. For example, a 4-D space would have numbers ranging
1041:                     * from "0000" to "2222" (numbers in base 3). The digits are then translated
1042:                     * into minimal, central or maximal ordinates. The outer loop stops when the
1043:                     * counter roll back to "0000".  Note that 'targetPt' must keep the value of
1044:                     * the last projected point, which must be the envelope center identified by
1045:                     * "2222" in the 4-D case.
1046:                     */
1047:                    int n = ++coordinateNumber;
1048:                    for (int i = sourceDim; --i >= 0;) {
1049:                        switch (n % 3) {
1050:                        case 0:
1051:                            sourcePt.setOrdinate(i, envelope.getMinimum(i));
1052:                            n /= 3;
1053:                            break;
1054:                        case 1:
1055:                            sourcePt.setOrdinate(i, envelope.getMaximum(i));
1056:                            continue loop;
1057:                        case 2:
1058:                            sourcePt.setOrdinate(i, envelope.getCenter(i));
1059:                            continue loop;
1060:                        default:
1061:                            throw new AssertionError(n); // Should never happen
1062:                        }
1063:                    }
1064:                    break;
1065:                }
1066:                return transformed;
1067:            }
1068:
1069:            /**
1070:             * Transforms an envelope using the given {@linkplain CoordinateOperation coordinate pperation}.
1071:             * The transformation is only approximative. Note that the returned envelope may not have the
1072:             * same number of dimensions than the original envelope.
1073:             * <p>
1074:             * This method can handle the case where the envelope contains the North or South pole,
1075:             * or when it cross the &plusmn;180� longitude.
1076:             *
1077:             * @param  operation The operation to use. Source and target dimension must be 2.
1078:             * @param  envelope Envelope to transform, or {@code null}. This envelope will not be modified.
1079:             * @return The transformed envelope, or {@code null} if {@code envelope} was null.
1080:             * @throws TransformException if a transform failed.
1081:             *
1082:             * @since 2.4
1083:             */
1084:            public static GeneralEnvelope transform(
1085:                    final CoordinateOperation operation, final Envelope envelope)
1086:                    throws TransformException {
1087:                if (envelope == null) {
1088:                    return null;
1089:                }
1090:                final CoordinateReferenceSystem sourceCRS = operation
1091:                        .getSourceCRS();
1092:                if (sourceCRS != null) {
1093:                    final CoordinateReferenceSystem crs = envelope
1094:                            .getCoordinateReferenceSystem();
1095:                    if (crs != null && !equalsIgnoreMetadata(crs, sourceCRS)) {
1096:                        throw new MismatchedReferenceSystemException(
1097:                                Errors
1098:                                        .format(ErrorKeys.MISMATCHED_COORDINATE_REFERENCE_SYSTEM));
1099:                    }
1100:                }
1101:                MathTransform mt = operation.getMathTransform();
1102:                final GeneralDirectPosition centerPt = new GeneralDirectPosition(
1103:                        mt.getTargetDimensions());
1104:                final GeneralEnvelope transformed = transform(mt, envelope,
1105:                        centerPt);
1106:                final CoordinateReferenceSystem targetCRS = operation
1107:                        .getTargetCRS();
1108:                if (targetCRS == null) {
1109:                    return transformed;
1110:                }
1111:                transformed.setCoordinateReferenceSystem(targetCRS);
1112:                final CoordinateSystem targetCS = targetCRS
1113:                        .getCoordinateSystem();
1114:                if (targetCS == null) {
1115:                    // It should be an error, but we keep this method tolerant.
1116:                    return transformed;
1117:                }
1118:                /*
1119:                 * Checks for singularity points. For example the south pole is a singularity point in
1120:                 * geographic CRS because we reach the maximal value allowed on one particular geographic
1121:                 * axis, namely latitude. This point is not a singularity in the stereographic projection,
1122:                 * where axis extends toward infinity in all directions (mathematically) and south pole
1123:                 * has nothing special apart being the origin (0,0).
1124:                 *
1125:                 * Algorithm:
1126:                 *
1127:                 * 1) Inspect the target axis, looking if there is any bounds. If bounds are found, get
1128:                 *    the coordinates of singularity points and project them from target to source CRS.
1129:                 *
1130:                 *    Example: if the transformed envelope above is (80�S to 85�S, 10�W to 50�W), and if
1131:                 *             target axis inspection reveal us that the latitude in target CRS is bounded
1132:                 *             at 90�S, then project (90�S,30�W) to source CRS. Note that the longitude is
1133:                 *             set to the the center of the envelope longitude range (more on this later).
1134:                 *
1135:                 * 2) If the singularity point computed above is inside the source envelope, add that
1136:                 *    point to the target (transformed) envelope.
1137:                 *
1138:                 * Note: We could choose to project the (-180, -90), (180, -90), (-180, 90), (180, 90)
1139:                 * points, or the (-180, centerY), (180, centerY), (centerX, -90), (centerX, 90) points
1140:                 * where (centerX, centerY) are transformed from the source envelope center. It make
1141:                 * no difference for polar projections because the longitude is irrelevant at pole, but
1142:                 * may make a difference for the 180� longitude bounds.  Consider a Mercator projection
1143:                 * where the transformed envelope is between 20�N and 40�N. If we try to project (-180,90),
1144:                 * we will get a TransformException because the Mercator projection is not supported at
1145:                 * pole. If we try to project (-180, 30) instead, we will get a valid point. If this point
1146:                 * is inside the source envelope because the later overlaps the 180� longitude, then the
1147:                 * transformed envelope will be expanded to the full (-180 to 180) range. This is quite
1148:                 * large, but at least it is correct (while the envelope without expansion is not).
1149:                 */
1150:                GeneralEnvelope generalEnvelope = null;
1151:                DirectPosition sourcePt = null;
1152:                DirectPosition targetPt = null;
1153:                final int dimension = targetCS.getDimension();
1154:                for (int i = 0; i < dimension; i++) {
1155:                    final CoordinateSystemAxis axis = targetCS.getAxis(i);
1156:                    boolean testMax = false; // Tells if we are testing the minimal or maximal value.
1157:                    do {
1158:                        final double extremum = testMax ? axis
1159:                                .getMaximumValue() : axis.getMinimumValue();
1160:                        if (Double.isInfinite(extremum)
1161:                                || Double.isNaN(extremum)) {
1162:                            /*
1163:                             * The axis is unbounded. It should always be the case when the target CRS is
1164:                             * a map projection, in which case this loop will finish soon and this method
1165:                             * will do nothing more (no object instantiated, no MathTransform inversed...)
1166:                             */
1167:                            continue;
1168:                        }
1169:                        if (targetPt == null) {
1170:                            try {
1171:                                mt = mt.inverse();
1172:                            } catch (NoninvertibleTransformException exception) {
1173:                                /*
1174:                                 * If the transform is non invertible, this method can't do anything. This
1175:                                 * is not a fatal error because the envelope has already be transformed by
1176:                                 * the caller. We lost the check for singularity points performed by this
1177:                                 * method, but it make no difference in the common case where the source
1178:                                 * envelope didn't contains any of those points.
1179:                                 *
1180:                                 * Note that this exception is normal if target dimension is smaller than
1181:                                 * source dimension, since the math transform can not reconstituate the
1182:                                 * lost dimensions. So we don't log any warning in this case.
1183:                                 */
1184:                                if (dimension >= mt.getSourceDimensions()) {
1185:                                    unexpectedException("transform", exception);
1186:                                }
1187:                                return transformed;
1188:                            }
1189:                            targetPt = new GeneralDirectPosition(mt
1190:                                    .getSourceDimensions());
1191:                            for (int j = 0; j < dimension; j++) {
1192:                                targetPt
1193:                                        .setOrdinate(j, centerPt.getOrdinate(j));
1194:                            }
1195:                            // TODO: avoid the hack below if we provide a contains(DirectPosition)
1196:                            //       method in GeoAPI Envelope interface.
1197:                            if (envelope instanceof  GeneralEnvelope) {
1198:                                generalEnvelope = (GeneralEnvelope) envelope;
1199:                            } else {
1200:                                generalEnvelope = new GeneralEnvelope(envelope);
1201:                            }
1202:                        }
1203:                        targetPt.setOrdinate(i, extremum);
1204:                        try {
1205:                            sourcePt = mt.transform(targetPt, sourcePt);
1206:                        } catch (TransformException e) {
1207:                            /*
1208:                             * This exception may be normal. For example we are sure to get this exception
1209:                             * when trying to project the latitude extremums with a cylindrical Mercator
1210:                             * projection. Do not log any message and try the other points.
1211:                             */
1212:                            continue;
1213:                        }
1214:                        if (generalEnvelope.contains(sourcePt)) {
1215:                            transformed.add(targetPt);
1216:                        }
1217:                    } while ((testMax = !testMax) == true);
1218:                    if (targetPt != null) {
1219:                        targetPt.setOrdinate(i, centerPt.getOrdinate(i));
1220:                    }
1221:                }
1222:                return transformed;
1223:            }
1224:
1225:            /**
1226:             * Transforms a rectangular envelope using the given {@linkplain MathTransform math transform}.
1227:             * The transformation is only approximative. Invoking this method is equivalent to invoking the
1228:             * following:
1229:             * <p>
1230:             * <pre>transform(transform, new GeneralEnvelope(envelope)).toRectangle2D()</pre>
1231:             * <p>
1232:             * Note that this method can not handle the case where the rectangle contains the North or
1233:             * South pole, or when it cross the &plusmn;180� longitude, because {@linkplain MathTransform
1234:             * math transforms} do not carry suffisient informations. For a more robust rectangle
1235:             * transformation, use {@link #transform(CoordinateOperation, Rectangle2D, Rectangle2D)}
1236:             * instead.
1237:             *
1238:             * @param  transform   The transform to use. Source and target dimension must be 2.
1239:             * @param  envelope    The rectangle to transform (may be {@code null}).
1240:             * @param  destination The destination rectangle (may be {@code envelope}).
1241:             *         If {@code null}, a new rectangle will be created and returned.
1242:             * @return {@code destination}, or a new rectangle if {@code destination} was non-null
1243:             *         and {@code envelope} was null.
1244:             * @throws TransformException if a transform failed.
1245:             *
1246:             * @since 2.4
1247:             */
1248:            public static Rectangle2D transform(
1249:                    final MathTransform2D transform,
1250:                    final Rectangle2D envelope, Rectangle2D destination)
1251:                    throws TransformException {
1252:                return transform(transform, envelope, destination,
1253:                        new Point2D.Double());
1254:            }
1255:
1256:            /**
1257:             * Implementation of {@link #transform(MathTransform, Rectangle2D, Rectangle2D)} with the
1258:             * opportunity to save the projected center coordinate. This method sets {@code point} to
1259:             * the center of the source envelope projected to the target CRS.
1260:             */
1261:            private static Rectangle2D transform(
1262:                    final MathTransform2D transform,
1263:                    final Rectangle2D envelope, Rectangle2D destination,
1264:                    final Point2D.Double point) throws TransformException {
1265:                if (envelope == null) {
1266:                    return null;
1267:                }
1268:                double xmin = Double.POSITIVE_INFINITY;
1269:                double ymin = Double.POSITIVE_INFINITY;
1270:                double xmax = Double.NEGATIVE_INFINITY;
1271:                double ymax = Double.NEGATIVE_INFINITY;
1272:                for (int i = 0; i <= 8; i++) {
1273:                    /*
1274:                     *   (0)----(5)----(1)
1275:                     *    |             |
1276:                     *   (4)    (8)    (7)
1277:                     *    |             |
1278:                     *   (2)----(6)----(3)
1279:                     *
1280:                     * (note: center must be last)
1281:                     */
1282:                    point.x = (i & 1) == 0 ? envelope.getMinX() : envelope
1283:                            .getMaxX();
1284:                    point.y = (i & 2) == 0 ? envelope.getMinY() : envelope
1285:                            .getMaxY();
1286:                    switch (i) {
1287:                    case 5: // fall through
1288:                    case 6:
1289:                        point.x = envelope.getCenterX();
1290:                        break;
1291:                    case 8:
1292:                        point.x = envelope.getCenterX(); // fall through
1293:                    case 7: // fall through
1294:                    case 4:
1295:                        point.y = envelope.getCenterY();
1296:                        break;
1297:                    }
1298:                    if (point != transform.transform(point, point)) {
1299:                        throw new UnsupportedImplementationException(transform
1300:                                .getClass());
1301:                    }
1302:                    if (point.x < xmin)
1303:                        xmin = point.x;
1304:                    if (point.x > xmax)
1305:                        xmax = point.x;
1306:                    if (point.y < ymin)
1307:                        ymin = point.y;
1308:                    if (point.y > ymax)
1309:                        ymax = point.y;
1310:                }
1311:                if (destination != null) {
1312:                    destination.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
1313:                } else {
1314:                    destination = XRectangle2D.createFromExtremums(xmin, ymin,
1315:                            xmax, ymax);
1316:                }
1317:                // Attempt the 'equalsEpsilon' assertion only if source and destination are not same.
1318:                assert (destination == envelope)
1319:                        || XRectangle2D.equalsEpsilon(destination, transform(
1320:                                transform, new Envelope2D(null, envelope))
1321:                                .toRectangle2D()) : destination;
1322:                return destination;
1323:            }
1324:
1325:            /**
1326:             * Transforms a rectangular envelope using the given {@linkplain CoordinateOperation coordinate
1327:             * operation}. The transformation is only approximative. Invoking this method is equivalent to
1328:             * invoking the following:
1329:             * <p>
1330:             * <pre>transform(operation, new GeneralEnvelope(envelope)).toRectangle2D()</pre>
1331:             * <p>
1332:             * This method can handle the case where the rectangle contains the North or South pole,
1333:             * or when it cross the &plusmn;180� longitude.
1334:             *
1335:             * @param  operation The operation to use. Source and target dimension must be 2.
1336:             * @param  envelope The rectangle to transform (may be {@code null}).
1337:             * @param  destination The destination rectangle (may be {@code envelope}).
1338:             *         If {@code null}, a new rectangle will be created and returned.
1339:             * @return {@code destination}, or a new rectangle if {@code destination} was non-null
1340:             *         and {@code envelope} was null.
1341:             * @throws TransformException if a transform failed.
1342:             *
1343:             * @since 2.4
1344:             */
1345:            public static Rectangle2D transform(
1346:                    final CoordinateOperation operation,
1347:                    final Rectangle2D envelope, Rectangle2D destination)
1348:                    throws TransformException {
1349:                if (envelope == null) {
1350:                    return null;
1351:                }
1352:                final MathTransform transform = operation.getMathTransform();
1353:                if (!(transform instanceof  MathTransform2D)) {
1354:                    throw new MismatchedDimensionException(Errors
1355:                            .format(ErrorKeys.NO_TRANSFORM2D_AVAILABLE));
1356:                }
1357:                MathTransform2D mt = (MathTransform2D) transform;
1358:                final Point2D.Double center = new Point2D.Double();
1359:                destination = transform(mt, envelope, destination, center);
1360:                final CoordinateReferenceSystem targetCRS = operation
1361:                        .getTargetCRS();
1362:                if (targetCRS == null) {
1363:                    return destination;
1364:                }
1365:                final CoordinateSystem targetCS = targetCRS
1366:                        .getCoordinateSystem();
1367:                if (targetCS == null || targetCS.getDimension() != 2) {
1368:                    // It should be an error, but we keep this method tolerant.
1369:                    return destination;
1370:                }
1371:                /*
1372:                 * Checks for singularity points. See the transform(CoordinateOperation, Envelope)
1373:                 * method for comments about the algorithm. The code below is the same algorithm
1374:                 * adapted for the 2D case and the related objects (Point2D, Rectangle2D, etc.).
1375:                 */
1376:                Point2D sourcePt = null;
1377:                Point2D targetPt = null;
1378:                for (int flag = 0; flag < 4; flag++) { // 2 dimensions and 2 extremums compacted in a flag.
1379:                    final int i = flag >> 1; // The dimension index being examined.
1380:                    final CoordinateSystemAxis axis = targetCS.getAxis(i);
1381:                    final double extremum = (flag & 1) == 0 ? axis
1382:                            .getMinimumValue() : axis.getMaximumValue();
1383:                    if (Double.isInfinite(extremum) || Double.isNaN(extremum)) {
1384:                        continue;
1385:                    }
1386:                    if (targetPt == null) {
1387:                        try {
1388:                            // TODO: remove the cast when we will be allowed to compile for J2SE 1.5.
1389:                            mt = (MathTransform2D) mt.inverse();
1390:                        } catch (NoninvertibleTransformException exception) {
1391:                            unexpectedException("transform", exception);
1392:                            return destination;
1393:                        }
1394:                        targetPt = new Point2D.Double();
1395:                    }
1396:                    switch (i) {
1397:                    case 0:
1398:                        targetPt.setLocation(extremum, center.y);
1399:                        break;
1400:                    case 1:
1401:                        targetPt.setLocation(center.x, extremum);
1402:                        break;
1403:                    default:
1404:                        throw new AssertionError(flag);
1405:                    }
1406:                    try {
1407:                        sourcePt = mt.transform(targetPt, sourcePt);
1408:                    } catch (TransformException e) {
1409:                        // Do not log; this exception is often expected here.
1410:                        continue;
1411:                    }
1412:                    if (envelope.contains(sourcePt)) {
1413:                        destination.add(targetPt);
1414:                    }
1415:                }
1416:                // Attempt the 'equalsEpsilon' assertion only if source and destination are not same.
1417:                assert (destination == envelope)
1418:                        || XRectangle2D.equalsEpsilon(destination, transform(
1419:                                operation, new GeneralEnvelope(envelope))
1420:                                .toRectangle2D()) : destination;
1421:                return destination;
1422:            }
1423:
1424:            /**
1425:             * Invoked when an unexpected exception occured. Those exceptions must be non-fatal,
1426:             * i.e. the caller <strong>must</strong> have a raisonable fallback (otherwise it
1427:             * should propagate the exception).
1428:             */
1429:            static void unexpectedException(final String methodName,
1430:                    final Exception exception) {
1431:                Logging.unexpectedException(LOGGER, CRS.class, methodName,
1432:                        exception);
1433:            }
1434:
1435:            /**
1436:             * Prints to the {@linkplain System#out standard output stream} some information about
1437:             * {@linkplain CoordinateReferenceSystem coordinate reference systems} specified by their
1438:             * authority codes. This method can be invoked from the command line in order to test the
1439:             * {@linkplain #getAuthorityFactory authority factory} content for some specific CRS.
1440:             * <p>
1441:             * By default, this method prints all enumerated objects as <cite>Well Known Text</cite>.
1442:             * However this method can prints different kind of information if an option such as
1443:             * {@code -factories}, {@code -codes} or {@code -bursawolfs} is provided.
1444:             * <p>
1445:             * <b>Usage:</b> {@code java org.geotools.referencing.CRS [options] [codes]}<br>
1446:             * <b>Options:</b>
1447:             *
1448:             * <blockquote>
1449:             *   <p><b>{@code -authority}=<var>name</var></b><br>
1450:             *       Uses the specified authority factory, for example {@code "EPSG"}. The authority
1451:             *       name can be any of the authorities listed by the {@code -factories} option. If
1452:             *       this option is not specified, then the default is all factories.</p>
1453:             *
1454:             *   <p><b>{@code -bursawolfs} <var>codes</var></b><br>
1455:             *       Lists the Bursa-Wolf parameters for the specified CRS ou datum objects. For some
1456:             *       transformations, there is more than one set of Bursa-Wolf parameters available.
1457:             *       The standard <cite>Well Known Text</cite> format prints only what look like the
1458:             *       "main" one. This option display all Bursa-Wolf parameters in a table for a given
1459:             *       object.</p>
1460:             *
1461:             *   <p><b>{@code -codes}</b><br>
1462:             *       Lists all available authority codes. Use the {@code -authority} option if the
1463:             *       list should be restricted to a single authority.</p>
1464:             *
1465:             *   <p><b>{@code -colors}</b><br>
1466:             *       Enable syntax coloring on <A HREF="http://en.wikipedia.org/wiki/ANSI_escape_code">ANSI
1467:             *       X3.64</A> compatible (aka ECMA-48 and ISO/IEC 6429) terminal. This option tries to
1468:             *       highlight most of the elements relevant to the {@link #equalsIgnoreMetadata
1469:             *       equalsIgnoreMetadata} method, with the addition of Bursa-Wolf parameters.</p>
1470:             *
1471:             *   <p><b>{@code -encoding}=<var>charset</var></b><br>
1472:             *       Sets the console encoding for this application output. This value has no impact
1473:             *       on data, but may improve the output quality. This is not needed on Linux terminal
1474:             *       using UTF-8 encoding (tip: the <cite>terminus font</cite> gives good results).
1475:             *       Windows users may need to set this encoding to the value returned by the
1476:             *       {@code chcp} command line. This parameter need to be specified only once.</p>
1477:             *
1478:             *   <p><b>{@code -dependencies}</b><br>
1479:             *       Lists authority factory dependencies as a tree.</p>
1480:             *
1481:             *   <p><b>{@code -factories}</b><br>
1482:             *       Lists all availables CRS authority factories.</p>
1483:             *
1484:             *   <p><b>{@code -forcexy}</b><br>
1485:             *       Force "longitude first" axis order.</p>
1486:             *
1487:             *   <p><b>{@code -help}</b><br>
1488:             *       Prints the list of options.</p>
1489:             *
1490:             *   <p><b>{@code -locale}=<var>name</var></b><br>
1491:             *       Formats texts in the specified {@linkplain java.util.Locale locale}.</p>
1492:             *
1493:             *   <p><b>{@code -operations} <var>sourceCRS</var> <var>targetCRS</var></b><br>
1494:             *       Prints all available coordinate operations between a pair of CRS. This option
1495:             *       prints only the operations explicitly defined in a database like EPSG. There
1496:             *       is sometime many such operations, and sometime none (in which case this option
1497:             *       prints nothing - it doesn't try to find an operation by itself).</p>
1498:             *
1499:             *   <p><b>{@code -transform} <var>sourceCRS</var> <var>targetCRS</var></b><br>
1500:             *       Prints the preferred math transform between a pair of CRS. At the difference of
1501:             *       the {@code "-operations"} option, this option pick up only one operation (usually
1502:             *       the most accurate one), inferring it if none were explicitly specified in the
1503:             *       database.</p>
1504:             * </blockquote>
1505:             *
1506:             * <strong>Examples</strong> (assuming that {@code "CRS"} is a shortcut for 
1507:             * {@code "java org.geotools.referencing.CRS"}):
1508:             *
1509:             * <blockquote>
1510:             *   <p><b>{@code CRS EPSG:4181 EPSG:4326 CRS:84 AUTO:42001,30,0}</b><br>
1511:             *       Prints the "Luxembourg 1930" CRS, the "WGS 84" CRS (from EPSG database),
1512:             *       the ""WGS84" CRS (from the <cite>Web Map Service</cite> specification) and a UTM
1513:             *       projection in WKT format.</p>
1514:             *
1515:             *   <p><b>{@code CRS -authority=EPSG 4181 4326}</b><br>
1516:             *       Prints the "Luxembourg 1930" and "WGS 84" CRS, looking only in the EPSG
1517:             *       database (so there is no need to prefix the codes with {@code "EPSG"}).</p>
1518:             *
1519:             *   <p><b>{@code CRS -colors EPSG:7411}</b><br>
1520:             *       Prints the "NTF (Paris) / Lambert zone II + NGF Lallemand" CRS with syntax
1521:             *       coloring enabled.</p>
1522:             *
1523:             *   <p><b>{@code CRS -bursawolfs EPSG:4230}</b><br>
1524:             *       Prints three set of Bursa-Wolf parameters for a CRS based on
1525:             *       "European Datum 1950".</p>
1526:             *
1527:             *   <p><b>{@code CRS -authority=EPSG -operations 4230 4326}</b><br>
1528:             *       Prints all operations declared in the EPSG database from "ED50" to "WGS 84"
1529:             *       geographic CRS. Note that for this particular pair of CRS, there is close
1530:             *       to 40 operations declared in the EPSG database. This method prints only the
1531:             *       ones that Geotools can handle.</p>
1532:             *
1533:             *   <p><b>{@code CRS -transform EPSG:4230 EPSG:4326}</b><br>
1534:             *       Prints the math transform that Geotools would use by default for coordinate
1535:             *       transformation from "ED50" to "WGS 84".</p>
1536:             * </blockquote>
1537:             *
1538:             * @param args Options and list of object codes to display.
1539:             *
1540:             * @since 2.4
1541:             */
1542:            public static void main(final String[] args) {
1543:                Command.execute(args);
1544:            }
1545:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.