sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1802029 [1/2] - in /sis/branches/JDK8: core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/ core/sis-referencing/src/main/java/org/apache/sis/referencing/op...
Date Sat, 15 Jul 2017 18:39:16 GMT
Author: desruisseaux
Date: Sat Jul 15 18:39:15 2017
New Revision: 1802029

URL: http://svn.apache.org/viewvc?rev=1802029&view=rev
Log:
Remove the CRS and CoordinateOperation wrapper around Proj.4 library. Instead, provide only a MathTransform wrapper.
The CRS and CoordinateOperation parts are better served by the Apache SIS implementation.
This allow us to simplify a little bit the "sis-gdal" module.

Added:
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Transform.java
      - copied, changed from r1802028, sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java
    sis/branches/JDK8/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/Proj4Test.java   (with props)
Removed:
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Axis.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRS.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/TransformFactory.java
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK8/storage/sis-gdal/pom.xml
    sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.c
    sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.h
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java
    sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/package-info.java
    sis/branches/JDK8/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/EPSGFactoryTest.java
    sis/branches/JDK8/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/PJTest.java
    sis/branches/JDK8/storage/sis-gdal/src/test/java/org/apache/sis/test/suite/GDALTestSuite.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -247,6 +247,21 @@ public final class AxisDirections extend
     }
 
     /**
+     * Returns {@code true} if the specified direction is cardinal direction.
+     * Cardinal directions are {@code NORTH}, {@code SOUTH}, {@code EAST} and {@code WEST}.
+     *
+     * @param  dir  the direction to test, or {@code null}.
+     * @return {@code true} if the given direction is a cardinal direction.
+     *
+     * @since 0.8
+     */
+    public static boolean isCardinal(final AxisDirection dir) {
+        if (dir == null) return false;
+        final int n  = dir.ordinal() - NORTH.ordinal();
+        return n >= 0 && n < COMPASS_COUNT && (n & 3) == 0;
+    }
+
+    /**
      * Returns {@code true} if the specified direction is an inter-cardinal direction.
      * Inter-cardinal directions are {@code NORTH_EAST}, {@code SOUTH_SOUTH_EAST}, etc.
      *

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -174,7 +174,7 @@ public final class ServicesForUtility ex
                 alternateTitle = key;
                 break;
             }
-            case "Proj4": {
+            case Constants.PROJ4: {
                 title = "Proj.4";
                 break;
             }

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -361,7 +361,7 @@ public final class Citations extends Sta
      *
      * @since 0.4
      */
-    public static final IdentifierSpace<String> PROJ4 = new CitationConstant.Authority<>("Proj4");
+    public static final IdentifierSpace<String> PROJ4 = new CitationConstant.Authority<>(Constants.PROJ4);
 
     /**
      * The authority for identifiers of objects defined by MapInfo.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -628,7 +628,7 @@ public class TransverseMercator extends
             final double tanφ = sinφ / cosφ;
             final double B    = cosφ * sinλ;
             /*
-             * Using Snyder's equation for calculating y, instead of the one used in Proj4.
+             * Using Snyder's equation for calculating y, instead of the one used in Proj.4.
              * Potential problems when y and x = 90 degrees, but behaves ok in tests.
              */
             if (dstPts != null) {

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/AxisDirectionsTest.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -110,6 +110,34 @@ public final strictfp class AxisDirectio
     }
 
     /**
+     * Tests {@link AxisDirections#isCardinal(AxisDirection)}.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testIsCardinal() {
+        assertTrue (AxisDirections.isCardinal(NORTH));
+        assertFalse(AxisDirections.isCardinal(NORTH_NORTH_EAST));
+        assertFalse(AxisDirections.isCardinal(NORTH_EAST));
+        assertFalse(AxisDirections.isCardinal(EAST_NORTH_EAST));
+        assertTrue (AxisDirections.isCardinal(EAST));
+        assertFalse(AxisDirections.isCardinal(EAST_SOUTH_EAST));
+        assertFalse(AxisDirections.isCardinal(SOUTH_EAST));
+        assertFalse(AxisDirections.isCardinal(SOUTH_SOUTH_EAST));
+        assertTrue (AxisDirections.isCardinal(SOUTH));
+        assertFalse(AxisDirections.isCardinal(SOUTH_SOUTH_WEST));
+        assertFalse(AxisDirections.isCardinal(SOUTH_WEST));
+        assertFalse(AxisDirections.isCardinal(WEST_SOUTH_WEST));
+        assertTrue (AxisDirections.isCardinal(WEST));
+        assertFalse(AxisDirections.isCardinal(WEST_NORTH_WEST));
+        assertFalse(AxisDirections.isCardinal(NORTH_WEST));
+        assertFalse(AxisDirections.isCardinal(NORTH_NORTH_WEST));
+        assertFalse(AxisDirections.isCardinal(UP));
+        assertFalse(AxisDirections.isCardinal(FUTURE));
+        assertFalse(AxisDirections.isCardinal(OTHER));
+    }
+
+    /**
      * Tests {@link AxisDirections#isIntercardinal(AxisDirection)}.
      */
     @Test

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -71,6 +71,12 @@ public final class Constants extends Sta
     public static final String SIS = "SIS";
 
     /**
+     * The {@value} code space. The project name is {@code "Proj.4"}, but this constant omits
+     * the dot because this name is used as a codes pace and we want to avoid risk of confusion.
+     */
+    public static final String PROJ4 = "Proj4";
+
+    /**
      * The {@value} code space.
      */
     public static final String CRS = "CRS";

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -906,6 +906,16 @@ public final class Errors extends Indexe
         public static final short UnsupportedArgumentValue_1 = 170;
 
         /**
+         * Axes with “{0}” direction are not supported by this operation.
+         */
+        public static final short UnsupportedAxisDirection_1 = 177;
+
+        /**
+         * The “{0}” coordinate system is not supported by this operation.
+         */
+        public static final short UnsupportedCoordinateSystem_1 = 178;
+
+        /**
          * The “{0}” datum is not supported by this operation.
          */
         public static final short UnsupportedDatum_1 = 168;

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Sat Jul 15 18:39:15 2017
@@ -196,6 +196,8 @@ UnsupportedImplementation_1       = Can
 UnsupportedInterpolation_1        = The \u201c{0}\u201d interpolation is unsupported.
 UnsupportedOperation_1            = The \u2018{0}\u2019 operation is unsupported.
 UnsupportedArgumentValue_1        = The \u201c{0}\u201d argument value is unsupported.
+UnsupportedAxisDirection_1        = Axes with \u201c{0}\u201d direction are not supported by this operation.
+UnsupportedCoordinateSystem_1     = The \u201c{0}\u201d coordinate system is not supported by this operation.
 UnsupportedDatum_1                = The \u201c{0}\u201d datum is not supported by this operation.
 UnsupportedType_1                 = The \u2018{0}\u2019 type is not supported in this context.
 ValueAlreadyDefined_1             = A value is already defined for \u201c{0}\u201d.

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Sat Jul 15 18:39:15 2017
@@ -192,6 +192,8 @@ UnsupportedImplementation_1       = Cett
 UnsupportedInterpolation_1        = L\u2019interpolation \u201c{0}\u201d n\u2019est pas support\u00e9e.
 UnsupportedOperation_1            = L\u2019op\u00e9ration \u2018{0}\u2019 n\u2019est pas support\u00e9e.
 UnsupportedArgumentValue_1        = La valeur d\u2019argument \u00ab\u202f{0}\u202f\u00bb n\u2019est pas support\u00e9e.
+UnsupportedAxisDirection_1        = Les axes de direction \u00ab\u202f{0}\u202f\u00bb ne sont pas support\u00e9s par cette op\u00e9ration.
+UnsupportedCoordinateSystem_1     = Le syst\u00e8me de coordonn\u00e9es \u00ab\u202f{0}\u202f\u00bb n\u2019est pas support\u00e9 par cette op\u00e9ration.
 UnsupportedDatum_1                = Le r\u00e9f\u00e9rentiel \u00ab\u202f{0}\u202f\u00bb n\u2019est pas support\u00e9 par cette op\u00e9ration.
 UnsupportedType_1                 = Le type \u2018{0}\u2019 n\u2019est pas support\u00e9 dans ce contexte.
 ValueAlreadyDefined_1             = Une valeur est d\u00e9j\u00e0 d\u00e9finie pour \u00ab\u202f{0}\u202f\u00bb.

Modified: sis/branches/JDK8/storage/sis-gdal/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/pom.xml?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/pom.xml (original)
+++ sis/branches/JDK8/storage/sis-gdal/pom.xml Sat Jul 15 18:39:15 2017
@@ -100,6 +100,20 @@ Referencing services from Proj4 through
       <artifactId>sis-referencing</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.sis.core</groupId>
+      <artifactId>sis-metadata</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sis.core</groupId>
+      <artifactId>sis-referencing</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>

Modified: sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.c
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.c?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.c [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.c [UTF-8] Sat Jul 15 18:39:15 2017
@@ -49,7 +49,7 @@ PJ *getPJ(JNIEnv *env, jobject object)
  * \param  class - The class from which this method has been invoked.
  * \return The Proj4 release number, or NULL.
  */
-JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getVersion
+JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getRelease
   (JNIEnv *env, jclass class)
 {
     const char *desc = pj_get_release();
@@ -99,7 +99,7 @@ JNIEXPORT jlong JNICALL Java_org_apache_
  * \param  object - The Java object wrapping the PJ structure (not allowed to be NULL).
  * \return The definition string.
  */
-JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getDefinition
+JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getCode
   (JNIEnv *env, jobject object)
 {
     PJ *pj = getPJ(env, object);
@@ -122,7 +122,7 @@ JNIEXPORT jstring JNICALL Java_org_apach
  * \param  object - The Java object wrapping the PJ structure (not allowed to be NULL).
  * \return The description associated to the PJ structure.
  */
-JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_toString
+JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getName
   (JNIEnv *env, jobject object)
 {
     PJ *pj = getPJ(env, object);

Modified: sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.h
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.h?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.h [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/c/org_apache_sis_storage_gdal_PJ.h [UTF-8] Sat Jul 15 18:39:15 2017
@@ -27,18 +27,26 @@ JNIEXPORT jlong JNICALL Java_org_apache_
 
 /*
  * Class:     org_apache_sis_storage_gdal_PJ
- * Method:    getVersion
+ * Method:    getRelease
  * Signature: ()Ljava/lang/String;
  */
-JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getVersion
+JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getRelease
   (JNIEnv *, jclass);
 
 /*
  * Class:     org_apache_sis_storage_gdal_PJ
- * Method:    getDefinition
+ * Method:    getCode
  * Signature: ()Ljava/lang/String;
  */
-JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getDefinition
+JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getCode
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_apache_sis_storage_gdal_PJ
+ * Method:    getName
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_getName
   (JNIEnv *, jobject);
 
 /*
@@ -114,14 +122,6 @@ JNIEXPORT jstring JNICALL Java_org_apach
   (JNIEnv *, jobject);
 
 /*
- * Class:     org_apache_sis_storage_gdal_PJ
- * Method:    toString
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_org_apache_sis_storage_gdal_PJ_toString
-  (JNIEnv *, jobject);
-
-/*
  * Class:     org_apache_sis_storage_gdal_PJ
  * Method:    finalize
  * Signature: ()V

Modified: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -22,13 +22,9 @@ import org.opengis.util.FactoryException
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.crs.*;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.Identifier;
 
 import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.metadata.iso.ImmutableIdentifier;
-import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.util.iso.AbstractFactory;
 
 
@@ -63,6 +59,19 @@ import org.apache.sis.util.iso.AbstractF
  */
 final class EPSGFactory extends AbstractFactory implements CRSAuthorityFactory {
     /**
+     * The {@literal Proj.4} parameter used for declaration of axis order. Proj.4 expects the axis parameter
+     * to be exactly 3 characters long, but Apache SIS accepts 2 characters as well. We relax the Proj.4 rule
+     * because we use the number of characters for determining the number of dimensions.
+     * This is okay since 1 character = 1 axis.
+     */
+    static final String AXIS_ORDER_PARAM = "+axis=";
+
+    /**
+     * The character used for separating the {@literal Proj.4} axis order declarations.
+     */
+    private static final char AXIS_ORDER_SEPARATOR = ',';
+
+    /**
      * {@code true} if the CRS created by this factory should use the axis order declared by the EPSG database.
      */
     private final boolean useEpsgAxisOrder;
@@ -107,34 +116,13 @@ final class EPSGFactory extends Abstract
     }
 
     /**
-     * Returns the name of the CRS identified by the given code. The default implementation
-     * returns a non-null value only for a few common codes.
+     * Returns the name of the CRS identified by the given code, or {@code null} if none.
      *
      * @throws FactoryException if an error occurred while fetching the description.
      */
     @Override
     public InternationalString getDescriptionText(final String code) throws FactoryException {
-        final String name = getName(code, null, false);
-        return (name != null) ? new SimpleInternationalString(code) : null;
-    }
-
-    /**
-     * Returns a hard-coded name for the given code, or {@code null} if none.
-     * Only the most frequent CRS are recognized by this method.
-     *
-     * @param isDatum  {@code false} for creating a CRS name (the usual case), or
-     *                 {@code true} for creating a datum name.
-     */
-    private static String getName(String code, final String defaultValue, final boolean isDatum) {
-        final int s = code.indexOf(':');
-        if (s<0 || code.substring(0,s).trim().equalsIgnoreCase("epsg")) try {
-            switch (Integer.parseInt(code.substring(s+1).trim())) {
-                case 4326: return isDatum ? "World Geodetic System 1984" : "WGS 84";
-            }
-        } catch (NumberFormatException e) {
-            // Ignore - this is okay for this method contract.
-        }
-        return defaultValue;
+        return null;
     }
 
     /**
@@ -169,20 +157,13 @@ final class EPSGFactory extends Abstract
              */
             String orientation = ResourcesLoader.getAxisOrientations().get(code);
             if (orientation != null) {
-                definition.append(' ').append(Proj4.AXIS_ORDER_PARAM).append(orientation);
-                final int end = orientation.indexOf(Proj4.AXIS_ORDER_SEPARATOR);
+                definition.append(' ').append(AXIS_ORDER_PARAM).append(orientation);
+                final int end = orientation.indexOf(AXIS_ORDER_SEPARATOR);
                 dimension = (end >= 0) ? end : orientation.length();
+                if (dimension == 2) definition.append('u');
             }
         }
-        final String crsName   = getName(code, code,   false);
-        final String datumName = getName(code, crsName, true);
-        final Identifier crsId = new ImmutableIdentifier(null, codespace, crsName);
-        final Identifier datumId = datumName.equals(crsName) ? crsId : new ImmutableIdentifier(null, codespace, datumName);
-        try {
-            return Proj4.createCRS(crsId, datumId, definition.toString(), dimension);
-        } catch (IllegalArgumentException e) {
-            throw new NoSuchAuthorityCodeException(e.getMessage(), codespace, code);
-        }
+        return Proj4.createCRS(definition.toString(), dimension);
     }
 
     /**

Modified: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -16,40 +16,40 @@
  */
 package org.apache.sis.storage.gdal;
 
-import java.util.Date;
 import java.util.Objects;
 import java.lang.annotation.Native;
-import javax.measure.Unit;
-import javax.measure.quantity.Angle;
-import javax.measure.quantity.Length;
 import org.opengis.metadata.Identifier;
-import org.opengis.metadata.extent.Extent;
+import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
+import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.datum.PrimeMeridian;
 import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
+import org.apache.sis.util.iso.SimpleInternationalString;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.system.OS;
-import org.apache.sis.measure.Units;
 
 
 /**
- * Wraps the <a href="http://proj.osgeo.org/">Proj4</a> {@code PJ} native data structure.
- * Many methods defined in this class are native methods delegating their work to the Proj4 library.
- * This class is the only place where such native methods are defined for Proj4 support.
+ * Wraps the <a href="http://proj.osgeo.org/">{@literal Proj.4}</a> {@code PJ} native data structure.
+ * Many methods defined in this class are native methods delegating their work to the Proj.4 library.
+ * This class is the only place where such native methods are defined for Proj.4 support.
  *
- * <p>In the Proj4 library, the {@code PJ} structure aggregates in a single place information usually
- * splitted in many different ISO 19111 interfaces: {@link Ellipsoid}, {@link GeodeticDatum}, {@link PrimeMeridian},
- * {@link org.opengis.referencing.cs.CoordinateSystem}, {@link org.opengis.referencing.crs.CoordinateReferenceSystem}
- * and their sub-interfaces. The relationship with the GeoAPI methods is indicated in the "See" tags when appropriate.</p>
+ * <p>In the Proj.4 library, the {@code PJ} structure is an aggregation of {@link GeodeticDatum},
+ * {@link Ellipsoid}, {@link PrimeMeridian}, {@link org.opengis.referencing.cs.CoordinateSystem},
+ * {@link org.opengis.referencing.crs.CoordinateReferenceSystem} and their sub-interfaces.
+ * The relationship with the GeoAPI methods is indicated in the "See" tags when appropriate.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
  * @since   0.8
  * @module
  */
-final class PJ extends PJObject implements GeodeticDatum, Ellipsoid, PrimeMeridian {
+final class PJ implements Identifier {
     /**
      * The maximal number of dimension accepted by the {@link #transform(PJ, int, double[], int, int)} method.
      * This upper limit is actually somewhat arbitrary. This limit exists mostly as a safety against potential misuse.
@@ -58,7 +58,7 @@ final class PJ extends PJObject implemen
     static final int DIMENSION_MAX = 100;
 
     /**
-     * Loads the Proj4 library.
+     * Loads the {@literal Proj.4} library.
      * This static initializer may throw a {@link UnsatisfiedLinkError} if the static library can not be loaded.
      * In such case, any future attempt to use this {@code PJ} class will cause a {@link NoClassDefFoundError}
      * as per Java language specification.
@@ -69,20 +69,18 @@ final class PJ extends PJObject implemen
 
     /**
      * The pointer to {@code PJ} structure allocated in the C/C++ heap. This value has no
-     * meaning in Java code. <strong>Do not modify</strong>, since this value is used by Proj4.
+     * meaning in Java code. <strong>Do not modify</strong>, since this value is used by Proj.4.
      * Do not rename neither, unless you update accordingly the C code in JNI wrappers.
      */
     private final long ptr;
 
     /**
-     * Creates a new {@code PJ} structure from the given Proj4 definition string.
+     * Creates a new {@code PJ} structure from the given {@literal Proj.4} definition string.
      *
-     * @param  name        the datum identifier, or {@code null} for inferring it from the definition.
-     * @param  definition  the Proj4 definition string.
+     * @param  definition  the Proj.4 definition string.
      * @throws InvalidGeodeticParameterException if the PJ structure can not be created from the given string.
      */
-    public PJ(Identifier name, final String definition) throws InvalidGeodeticParameterException {
-        super(name != null ? name : identifier(definition, "+datum="));
+    public PJ(final String definition) throws InvalidGeodeticParameterException {
         Objects.requireNonNull(definition);
         ptr = allocatePJ(definition);
         if (ptr == 0) {
@@ -97,13 +95,13 @@ final class PJ extends PJObject implemen
      * from a {@linkplain org.opengis.referencing.crs.ProjectedCRS projected CRS}.
      *
      * @param  crs   the CRS (usually projected) from which to derive a new CRS.
-     * @throws IllegalArgumentException if the PJ structure can not be created.
+     * @throws FactoryException if the PJ structure can not be created.
      */
-    public PJ(final PJ crs) throws IllegalArgumentException {
-        super(identifier(crs.getDefinition(), "+datum="));
+    public PJ(final PJ crs) throws FactoryException {
+        Objects.requireNonNull(crs);
         ptr = allocateGeoPJ(crs);
         if (ptr == 0) {
-            throw new IllegalArgumentException(crs.getLastError());
+            throw new FactoryException(crs.getLastError());
         }
     }
 
@@ -112,7 +110,7 @@ final class PJ extends PJObject implemen
      * the constructor only, and the return value <strong>must</strong> be assigned to the {@link #ptr} field.
      * The allocated structure is released by the {@link #finalize()} method.
      *
-     * @param  definition  the Proj4 definition string.
+     * @param  definition  the Proj.4 definition string.
      * @return a pointer to the PJ native data structure, or 0 if the operation failed.
      */
     private static native long allocatePJ(String definition);
@@ -128,19 +126,89 @@ final class PJ extends PJObject implemen
     private static native long allocateGeoPJ(PJ projected);
 
     /**
-     * Returns the version number of the Proj4 library.
+     * Returns the project responsible for maintenance of the namespace.
      *
-     * @return the Proj4 release string.
+     * @see #getCodeSpace()
      */
-    public static native String getVersion();
+    @Override
+    public Citation getAuthority() {
+        return Citations.PROJ4;
+    }
 
     /**
-     * Returns the Proj4 definition string. This is the string given to the constructor,
+     * Returns the version identifier for the namespace, as specified by the code authority.
+     * This method* parses the Proj.4 release string (for example <cite>"Rel. 4.9.3, 15 August 2016"</cite>)
+     * for extracting the version number ("4.9.3" in above example).
+     *
+     * @see Proj4#version()
+     */
+    @Override
+    public String getVersion() {
+        String rel = getRelease();
+        if (rel != null) {
+            int start = -1;
+            final int length = rel.length();
+            for (int c, i=0; i < length; i += Character.charCount(c)) {
+                c = rel.codePointAt(i);
+                if (Character.isDigit(c)) {
+                    if (start < 0) start = i;
+                } else if (c != '.' && start >= 0) {
+                    return rel.substring(start, i);
+                }
+            }
+        }
+        return rel;
+    }
+
+    /**
+     * Returns the version number of the {@literal Proj.4} library.
+     *
+     * @return the Proj.4 release string.
+     *
+     * @see #getVersion()
+     * @see Proj4#version()
+     */
+    static native String getRelease();
+
+    /**
+     * Returns the namespace in which the code is valid.
+     *
+     * @see #getAuthority()
+     * @see #getCode()
+     */
+    @Override
+    public String getCodeSpace() {
+        return Constants.PROJ4;
+    }
+
+    /**
+     * Returns the {@literal Proj.4} definition string. This is the string given to the constructor,
      * expanded with as much information as possible.
      *
-     * @return the Proj4 definition string.
+     * <div class="note"><b>Example:</b> "+proj=latlong +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"</div>
+     *
+     * @return the Proj.4 definition string.
+     */
+    @Override
+    public native String getCode();
+
+    /**
+     * Returns the string representation of the PJ structure.
+     *
+     * <div class="note"><b>Example:</b> "Lat/long (Geodetic alias)"</div>
+     */
+    native String getName();
+
+    /**
+     * Returns the string representation of the PJ structure.
+     *
+     * @return the string representation, or {@code null} if none.
      */
-    public native String getDefinition();
+    @Override
+    public InternationalString getDescription() {
+        final String name = getName();
+        return (name != null) ? new SimpleInternationalString(getName()) : null;
+    }
 
     /**
      * Returns the Coordinate Reference System type.
@@ -151,7 +219,7 @@ final class PJ extends PJObject implemen
 
     /**
      * The coordinate reference system (CRS) type returned by {@link PJ#getType()}.
-     * In the Proj4 library, a CRS can only be geographic, geocentric or projected,
+     * In the Proj.4 library, a CRS can only be geographic, geocentric or projected,
      * without distinction between 2D and 3D CRS.
      */
     enum Type {
@@ -180,131 +248,52 @@ final class PJ extends PJObject implemen
     }
 
     /**
-     * Returns the ellipsoid associated with this geodetic datum.
-     * In Proj4 implementation, the datum and its ellipsoid are represented by the same {@code PJ} object.
-     */
-    @Override
-    public Ellipsoid getEllipsoid() {
-        return this;
-    }
-
-    /**
-     * Returns {@code true} if the ellipsoid is a sphere.
-     */
-    @Override
-    public boolean isSphere() {
-        return getEccentricitySquared() == 0;
-    }
-
-    /**
-     * Returns {@code true} unconditionally since the inverse eccentricity squared in definitive
-     * in the Proj4 library, and the eccentricity is directly related to the flattening.
+     * Returns the square of the ellipsoid eccentricity (ε²). The eccentricity is related to axis length
+     * by ε=√(1-(<var>b</var>/<var>a</var>)²). The eccentricity of a sphere is zero.
+     *
+     * @return the eccentricity.
+     *
+     * @see Ellipsoid#isSphere()
+     * @see Ellipsoid#getInverseFlattening()
      */
-    @Override
-    public boolean isIvfDefinitive() {
-        return true;
-    }
+    public native double getEccentricitySquared();
 
     /**
      * Returns the inverse flattening, computed from the eccentricity.
+     * The inverse flattening factor of a sphere is infinity.
      */
-    @Override
     public double getInverseFlattening() {
         return 1 / (1 - Math.sqrt(1 - getEccentricitySquared()));
     }
 
     /**
-     * Returns the square of the ellipsoid eccentricity (ε²). The eccentricity is related to axis length
-     * by ε=√(1-(<var>b</var>/<var>a</var>)²). The eccentricity of a sphere is zero.
-     *
-     * @return the eccentricity.
-     *
-     * @see #isSphere()
-     * @see #getInverseFlattening()
-     */
-    public native double getEccentricitySquared();
-
-    /**
      * Returns the value stored in the {@code a_orig} PJ field.
      *
      * @return the axis length stored in {@code a_orig}.
+     *
+     * @see Ellipsoid#getSemiMajorAxis()
      */
-    @Override
     public native double getSemiMajorAxis();
 
     /**
      * Returns the value computed from PJ fields by {@code √((a_orig)² × (1 - es_orig))}.
      *
      * @return the axis length computed by {@code √((a_orig)² × (1 - es_orig))}.
-     */
-    @Override
-    public native double getSemiMinorAxis();
-
-    /**
-     * Returns the ellipsoid axis unit, which is assumed metres in the case of the Proj4 library.
-     * Not to be confused with the {@linkplain #getLinearUnit(boolean) coordinate system axis unit}.
-     */
-    @Override
-    public Unit<Length> getAxisUnit() {
-        return Units.METRE;
-    }
-
-    /**
-     * Returns the prime meridian associated with this geodetic datum.
-     * In Proj4 implementation, the datum and its prime meridian are represented by the same {@code PJ} object.
-     */
-    @Override
-    public PrimeMeridian getPrimeMeridian() {
-        return this;
-    }
-
-    /**
-     * Returns the units of the prime meridian.
-     * All angular units are converted from radians to degrees in the JNI code.
      *
-     * @see #getLinearUnit(boolean)
+     * @see Ellipsoid#getSemiMinorAxis()
      */
-    @Override
-    public Unit<Angle> getAngularUnit() {
-        return Units.DEGREE;
-    }
+    public native double getSemiMinorAxis();
 
     /**
      * Longitude of the prime meridian measured from the Greenwich meridian, positive eastward.
      *
      * @return the prime meridian longitude, in degrees.
+     *
+     * @see PrimeMeridian#getGreenwichLongitude()
      */
-    @Override
     public native double getGreenwichLongitude();
 
     /**
-     * Returns a description of the relationship used to anchor the coordinate system to the Earth.
-     * Current implementation returns {@code null}.
-     */
-    @Override
-    public InternationalString getAnchorPoint() {
-        return null;
-    }
-
-    /**
-     * Returns the time after which this datum definition is valid.
-     * Current implementation returns {@code null}.
-     */
-    @Override
-    public Date getRealizationEpoch() {
-        return null;
-    }
-
-    /**
-     * Returns the area or region or timeframe in which this datum is valid.
-     * Current implementation returns {@code null}.
-     */
-    @Override
-    public Extent getDomainOfValidity() {
-        return null;
-    }
-
-    /**
      * Returns an array of character indicating the direction of each axis. Directions are
      * characters like {@code 'e'} for East, {@code 'n'} for North and {@code 'u'} for Up.
      *
@@ -315,29 +304,19 @@ final class PJ extends PJObject implemen
     public native char[] getAxisDirections();
 
     /**
-     * Returns the linear unit for the horizontal or the vertical coordinate system axes.
-     * Not to be confused with the {@linkplain #getAxisUnit() ellipsoid axis unit}.
-     *
-     * @see #getAngularUnit()
-     */
-    public Unit<Length> getLinearUnit(final boolean vertical) {
-        return Units.METRE.divide(getLinearUnitToMetre(vertical));
-    }
-
-    /**
      * Returns the conversion factor from the linear units to metres.
      *
      * @param  vertical {@code false} for the conversion factor of horizontal axes,
      *         or {@code true} for the conversion factor of the vertical axis.
      * @return the conversion factor to metres for the given axis.
      */
-    native double getLinearUnitToMetre(boolean vertical);
+    public native double getLinearUnitToMetre(boolean vertical);
 
     /**
-     * Transforms in-place the coordinates in the given array. The coordinates array shall contain
-     * (<var>x</var>,<var>y</var>,<var>z</var>,…) tuples, where the <var>z</var> and
-     * following dimensions are optional. Note that any dimension after the <var>z</var> value
-     * are ignored.
+     * Transforms in-place the coordinates in the given array.
+     * The coordinates array shall contain (<var>x</var>,<var>y</var>,<var>z</var>,…) tuples,
+     * where the <var>z</var> and any additional dimensions are optional.
+     * Note that any dimension after the <var>z</var> value are ignored.
      *
      * <p>Input and output units:</p>
      * <ul>
@@ -352,7 +331,7 @@ final class PJ extends PJObject implemen
      * @param  numPts       number of points to transform.
      * @throws NullPointerException if the {@code target} or {@code coordinates} argument is null.
      * @throws IndexOutOfBoundsException if the {@code offset} or {@code numPts} arguments are invalid.
-     * @throws TransformException if the operation failed for an other reason (provided by Proj4).
+     * @throws TransformException if the operation failed for another reason (provided by Proj.4).
      *
      * @see org.opengis.referencing.operation.MathTransform#transform(double[], int, double[], int, int)
      */
@@ -367,16 +346,34 @@ final class PJ extends PJObject implemen
     native String getLastError();
 
     /**
+     * Returns a hash code value for this {@literal Proj.4} object.
+     */
+    @Override
+    public int hashCode() {
+        return ~getCode().hashCode();
+    }
+
+    /**
+     * Compares this identifier with the given object for equality.
+     */
+    @Override
+    public boolean equals(final Object other) {
+        return (other instanceof PJ) && getCode().equals(((PJ) other).getCode());
+    }
+
+    /**
      * Returns the string representation of the PJ structure.
      *
      * @return the string representation.
      */
     @Override
-    public native String toString();
+    public String toString() {
+        return IdentifiedObjects.toString(this);
+    }
 
     /**
-     * Deallocates the native PJ data structure. This method can be invoked only by the garbage
-     * collector, and must be invoked exactly once (no more, no less).
+     * Deallocates the native PJ data structure.
+     * It is okay if this method is invoked more than once.
      */
     @Override
     @SuppressWarnings("FinalizeDeclaration")

Modified: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -24,11 +24,10 @@ import org.opengis.util.InternationalStr
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.referencing.IdentifiedObject;
-import org.apache.sis.internal.simple.SimpleIdentifier;
 
 
 /**
- * Base class of implementations in this Proj4 wrappers package.
+ * Base class of implementations in this {@literal Proj.4} wrappers package.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
@@ -75,29 +74,6 @@ class PJObject implements IdentifiedObje
     }
 
     /**
-     * Returns the value of the given parameter as an identifier, or {@code null} if none.
-     * The given parameter key shall include the {@code '+'} prefix and {@code '='} suffix,
-     * for example {@code "+proj="}. This is a helper method for providing the {@code name}
-     * argument in constructors.
-     *
-     * @param  definition  the Proj.4 definition string to parse.
-     * @param  key         the parameter name.
-     * @return the parameter value as an identifier.
-     */
-    static Identifier identifier(final String definition, final String key) {
-        int i = definition.indexOf(key);
-        if (i >= 0) {
-            i += key.length();
-            final int stop = definition.indexOf(' ', i);
-            String value = (stop >= 0) ? definition.substring(i, stop) : definition.substring(i);
-            if (!(value = value.trim()).isEmpty()) {
-                return new SimpleIdentifier(null, value, false);
-            }
-        }
-        return null;
-    }
-
-    /**
      * Returns the name of this referencing object, or {@code null} if none.
      * Note that this attribute is mandatory according ISO 19111, but this
      * simple Proj.4 wrapper is lenient about that.
@@ -129,7 +105,7 @@ class PJObject implements IdentifiedObje
     }
 
     /**
-     * Returns {@code null} since we do not define any scope in our Proj4 wrappers.
+     * Returns {@code null} since we do not define any scope in our {@literal Proj.4} wrappers.
      * Note that this method is not inherited from {@link IdentifiedObject}, but is
      * defined in sub-interfaces like {@link org.opengis.referencing.crs.SingleCRS}.
      */
@@ -147,7 +123,7 @@ class PJObject implements IdentifiedObje
     }
 
     /**
-     * Returns {@code null} since there is no remarks associated with our Proj4 wrappers.
+     * Returns {@code null} since there is no remarks associated with our {@literal Proj.4} wrappers.
      */
     @Override
     public InternationalString getRemarks() {

Modified: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -16,17 +16,35 @@
  */
 package org.apache.sis.storage.gdal;
 
-import org.opengis.metadata.Identifier;
+import javax.measure.Unit;
+import javax.measure.quantity.Angle;
 import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.referencing.crs.GeodeticCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.datum.PrimeMeridian;
 import org.opengis.referencing.operation.CoordinateOperation;
+import org.apache.sis.referencing.factory.UnavailableFactoryException;
+import org.apache.sis.internal.metadata.AxisDirections;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Static;
+import org.apache.sis.measure.Units;
 
 
 /**
- * Bindings to the Proj4 library.
+ * Bindings to the {@literal Proj.4} library.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
@@ -36,37 +54,22 @@ import org.apache.sis.util.Static;
  */
 public final class Proj4 extends Static {
     /**
-     * The Proj4 parameter used for declaration of axis order. This parameter is handled in a special way
-     * by the factories: it be a comma-separated list of axis order definitions, in which case the second
-     * value is used as the axis order of the {@link org.opengis.referencing.crs.ProjectedCRS#getBaseCRS()}.
-     *
-     * <p>An other departure from Proj.4 is that Proj.4 expect the axis parameter to be exactly
-     * 3 characters long, which our code accepts 2 characters as well. We relax the Proj.4
-     * rule because we use the number of characters for determining the number of dimensions.
-     * This is okay since 1 character = 1 axis.</p>
-     */
-    static final String AXIS_ORDER_PARAM = "+axis=";
-
-    /**
-     * The character used for separating the Proj4 axis order declarations.
-     */
-    static final char AXIS_ORDER_SEPARATOR = ',';
-
-    /**
      * Do not allow instantiation of this class.
      */
     private Proj4() {
     }
 
     /**
-     * Returns the version number of the Proj4 library.
+     * Returns the version number of the {@literal Proj.4} library.
      * Returns {@code null} if Proj.4 is not installed on the current system.
      *
-     * @return the Proj4 release string, or {@code null} if no installation has been found.
+     * <div class="note"><b>Example:</b> Rel. 4.9.3, 15 August 2016</div>
+     *
+     * @return the Proj.4 release string, or {@code null} if no installation has been found.
      */
-    public static String getVersion() {
+    public static String version() {
         try {
-            return PJ.getVersion();
+            return PJ.getRelease();
         } catch (UnsatisfiedLinkError e) {
             // Thrown the first time that we try to use the library.
             Logging.unexpectedException(Logging.getLogger(Modules.GDAL), Proj4.class, "version", e);
@@ -78,84 +81,136 @@ public final class Proj4 extends Static
     }
 
     /**
-     * Creates a new CRS from the given Proj4 definition string. The CRS can have an arbitrary number of dimensions
-     * in the [2-100] range. However Proj.4 will handle at most the 3 first dimensions. All supplemental dimensions
-     * will be simply copied unchanged by {@link org.opengis.referencing.operation.MathTransform} implementations.
+     * Infers a {@literal Proj.4} definition from the given projected, geographic or geocentric coordinate reference system.
+     * This method does not need the Proj.4 native library; it can be used in a pure Java application.
      *
-     * @param  crsId       the name of the CRS to create, or {@code null} if none.
-     * @param  datumId     the name of the datum to create, or {@code null} if none.
-     * @param  definition  the Proj.4 definition string.
-     * @param  dimension   the number of dimension of the CRS to create.
-     * @return a CRS created from the given definition string and number of dimension.
-     * @throws NullPointerException if the definition string is {@code null}.
-     * @throws FactoryException if one of the given argument has an invalid value.
-     */
-    public static CoordinateReferenceSystem createCRS(final Identifier crsId,
-            final Identifier datumId, String definition, final int dimension)
-            throws FactoryException
-    {
-        if ((definition = definition.trim()).isEmpty()) {
-            throw new IllegalArgumentException("The definition must be non-empty.");
-        }
-        if (dimension < 2 || dimension > PJ.DIMENSION_MAX) {
-            throw new IllegalArgumentException("Illegal number of dimensions: " + dimension);
+     * @param  crs  the coordinate reference system for which to create a Proj.4 definition.
+     * @return the definition of the given CRS in a Proj.4 format.
+     * @throws FactoryException if the Proj.4 definition string can not be created from the given CRS.
+     */
+    public static String definition(final CoordinateReferenceSystem crs) throws FactoryException {
+        final String method;
+        final GeodeticDatum datum;
+        final ParameterValueGroup parameters;
+        final CoordinateSystem cs = crs.getCoordinateSystem();
+        if (crs instanceof GeodeticCRS) {
+            if (cs instanceof EllipsoidalCS) {
+                method = "latlon";
+            } else if (cs instanceof CartesianCS) {
+                method = "geocent";
+            } else {
+                throw new FactoryException(Errors.format(Errors.Keys.UnsupportedCoordinateSystem_1, cs.getClass()));
+            }
+            datum      = ((GeodeticCRS) crs).getDatum();
+            parameters = null;
+        } else if (crs instanceof ProjectedCRS) {
+            datum      = ((ProjectedCRS) crs).getDatum();
+            parameters = ((ProjectedCRS) crs).getConversionFromBase().getParameterValues();
+            method     = ResourcesLoader.getProjName(parameters, false).substring(1);
+        } else {
+            throw new FactoryException(Errors.format(Errors.Keys.UnsupportedType_1, crs.getClass()));
         }
         /*
-         * Custom parsing of the "+axis=" parameter.
-         * This code may modify the definition string.
+         * Append the map projection parameters. Those parameters may include axis lengths (a and b),
+         * but not necessarily. If axis lengths are specified, then we will ignore the Ellipsoid instance
+         * associated to the CRS.
          */
-        String orientation = null;
-        int beginParam = definition.indexOf(AXIS_ORDER_PARAM);
-        if (beginParam >= 0) {
-            beginParam += AXIS_ORDER_PARAM.length();
-            final int length = definition.length();
-            while (beginParam < length) {                                   // Skip whitespaces.
-                final int c = definition.codePointAt(beginParam);
-                if (!Character.isWhitespace(c)) break;
-                beginParam += Character.charCount(c);
+        final StringBuilder definition = new StringBuilder(100);
+        definition.append("+proj=").append(method);
+        boolean hasSemiMajor = false;
+        boolean hasSemiMinor = false;
+        if (parameters != null) {
+            for (final GeneralParameterValue parameter : parameters.values()) {
+                if (parameter instanceof ParameterValue) {
+                    final Object value = ((ParameterValue) parameter).getValue();
+                    if (value != null) {
+                        final String pn = ResourcesLoader.getProjName(parameter, true);
+                        if (pn.equals("+a")) hasSemiMajor = true;
+                        if (pn.equals("+b")) hasSemiMinor = true;
+                        definition.append(' ').append(pn).append('=').append(value);
+                    }
+                }
             }
-            final StringBuilder modified = new StringBuilder(definition.length());
-            modified.append(definition, 0, beginParam);
-            int endParam = CRS.Projected.findWordEnd(definition, beginParam);
-            orientation = definition.substring(beginParam, endParam);
-            modified.append(CRS.Projected.ensure3D(orientation));
-            if (endParam < length && definition.charAt(endParam) == AXIS_ORDER_SEPARATOR) {
-                endParam = CRS.Projected.findWordEnd(definition, endParam+1);
-                orientation = definition.substring(beginParam, endParam);
+        }
+        /*
+         * Append datum information: axis lengths if they were not part of the parameters, then prime meridian.
+         */
+        final Ellipsoid ellipsoid = datum.getEllipsoid();
+        if (!hasSemiMajor) definition.append(" +a=").append(ellipsoid.getSemiMajorAxis());
+        if (!hasSemiMinor) definition.append(" +b=").append(ellipsoid.getSemiMinorAxis());
+        final PrimeMeridian pm = datum.getPrimeMeridian();
+        if (pm != null) {
+            double lon = pm.getGreenwichLongitude();
+            final Unit<Angle> unit = pm.getAngularUnit();
+            if (unit != null) {
+                lon = unit.getConverterTo(Units.DEGREE).convert(lon);
             }
-            modified.append(definition, endParam, length);
-            definition = modified.toString();
+            definition.append(" +pm=").append(lon);
         }
         /*
-         * Create the Proj.4 wrapper.
+         * Appends axis directions. This method always format a vertical direction (up or down)
+         * even if the coordinate system is two-dimensional, because Proj.4 seems to require it.
          */
-        final PJ datum = new PJ(datumId, definition);
-        final PJ.Type type = datum.getType();
-        final CoordinateReferenceSystem crs;
-        switch (type) {
-            case GEOCENTRIC: crs = new CRS.Geocentric(crsId, datum, dimension); break;
-            case GEOGRAPHIC: crs = new CRS.Geographic(crsId, datum, dimension); break;
-            case PROJECTED:  crs = new CRS.Projected (crsId, datum, dimension, orientation); break;
-            default: throw new UnsupportedOperationException("Unknown CRS type: " + type);
+        definition.append(' ').append(EPSGFactory.AXIS_ORDER_PARAM);
+        final int dimension = Math.min(cs.getDimension(), 3);
+        boolean hasVertical = false;
+        for (int i=0; i<dimension; i++) {
+            final AxisDirection dir = cs.getAxis(i).getDirection();
+            if (!AxisDirections.isCardinal(dir)) {
+                if (!AxisDirections.isVertical(dir)) {
+                    throw new FactoryException(Errors.format(Errors.Keys.UnsupportedAxisDirection_1, dir));
+                }
+                hasVertical = true;
+            }
+            definition.appendCodePoint(Character.toLowerCase(dir.name().codePointAt(0)));
+        }
+        if (!hasVertical && dimension < 3) {
+            definition.append('u');                    // Add a UP direction if not already present.
+        }
+        return definition.toString();
+    }
+
+    /**
+     * Creates a new CRS from the given {@literal Proj.4} definition string.
+     *
+     * @param  definition  the Proj.4 definition string.
+     * @param  dimension   the number of dimension of the CRS to create (2 or 3).
+     * @return a CRS created from the given definition string and number of dimensions.
+     * @throws NullPointerException if the definition string is {@code null}.
+     * @throws FactoryException if one of the given argument has an invalid value.
+     */
+    public static CoordinateReferenceSystem createCRS(String definition, final int dimension) throws FactoryException {
+        definition = definition.trim();
+        ArgumentChecks.ensureNonEmpty(definition, definition);
+        ArgumentChecks.ensureBetween("dimension", 2, 3, dimension);
+        try {
+            return ReferencingFactory.INSTANCE.createCRS(definition, dimension >= 3);
+        } catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
+            throw new UnavailableFactoryException(Errors.format(Errors.Keys.NativeInterfacesNotFound_2,
+                    System.getProperty("os.name"), "libproj"), e);
         }
-        return crs;
     }
 
     /**
      * Creates an operation for conversion or transformation between two coordinate reference systems.
-     * This given source and target CRS must be instances created by this factory.
      *
-     * @param  identifier  the name of the operation to create, or {@code null} if none.
      * @param  sourceCRS   the source coordinate reference system.
      * @param  targetCRS   the target coordinate reference system.
      * @return a coordinate operation for transforming coordinates from the given source CRS to the given target CRS.
-     * @throws ClassCastException if the given CRS are not instances created by this class.
+     * @throws FactoryException if an error occurred while creating the coordinate operation.
      */
-    public static CoordinateOperation createOperation(final Identifier identifier,
-            final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS)
-            throws ClassCastException
+    public static CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
+                                                      final CoordinateReferenceSystem targetCRS)
+            throws FactoryException
     {
-        return new Operation(identifier, (CRS) sourceCRS, (CRS) targetCRS);
+        ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
+        ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
+        try {
+            return ReferencingFactory.INSTANCE.createOperation(sourceCRS, targetCRS);
+        } catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
+            throw new UnavailableFactoryException(Errors.format(Errors.Keys.NativeInterfacesNotFound_2,
+                    System.getProperty("os.name"), "libproj"), e);
+        }
     }
 
     /**

Modified: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java?rev=1802029&r1=1802028&r2=1802029&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java [UTF-8] Sat Jul 15 18:39:15 2017
@@ -17,310 +17,289 @@
 package org.apache.sis.storage.gdal;
 
 import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
 import javax.measure.Unit;
-import javax.measure.quantity.Angle;
-
+import org.opengis.util.FactoryException;
+import org.opengis.metadata.Identifier;
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
 import org.opengis.referencing.datum.*;
-import org.opengis.referencing.operation.*;
-import org.opengis.util.FactoryException;
-import org.opengis.metadata.Identifier;
-import org.opengis.parameter.ParameterValue;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.parameter.GeneralParameterValue;
-
+import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
+import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.metadata.AxisDirections;
+import org.apache.sis.internal.util.Constants;
+import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
+import org.apache.sis.util.collection.WeakValueHashMap;
+import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.iso.AbstractFactory;
+import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.measure.Units;
 
 
 /**
- * A factory for {@linkplain CoordinateReferenceSystem Coordinate Reference System} objects
- * created from property maps.
- *
- * <p>The supported methods in this class are:</p>
- *
- * <ul>
- *   <li>{@link #createGeocentricCRS(Map, GeodeticDatum, CartesianCS)}</li>
- *   <li>{@link #createGeographicCRS(Map, GeodeticDatum, EllipsoidalCS)}</li>
- *   <li>{@link #createProjectedCRS(Map, GeographicCRS, Conversion, CartesianCS)}</li>
- * </ul>
- *
- * All other methods throw a {@link FactoryException}.
+ * Creates Coordinate Reference System instances form {@link PJ} objects.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
  * @since   0.8
  * @module
  */
-final class ReferencingFactory extends AbstractFactory implements CRSFactory {
+final class ReferencingFactory extends AbstractFactory {
     /**
-     * The unique instance.
+     * The default factory instance.
      */
     static final ReferencingFactory INSTANCE = new ReferencingFactory();
 
     /**
-     * Creates a new factory.
+     * The factory for coordinate reference system objects.
      */
-    private ReferencingFactory() {
-    }
+    private final CRSFactory crsFactory;
 
     /**
-     * Appends the prime meridian to the given definition string buffer.
-     *
-     * @param def  the definition string buffer.
-     * @param pm   the prime meridian, or {@code null} if none.
+     * The factory for coordinate system objects.
      */
-    private static void appendPrimeMeridian(final StringBuilder def, final PrimeMeridian pm) {
-        if (pm != null) {
-            double lon = pm.getGreenwichLongitude();
-            final Unit<Angle> unit = pm.getAngularUnit();
-            if (unit != null) {
-                lon = unit.getConverterTo(Units.DEGREE).convert(lon);
-            }
-            def.append(" +pm=").append(lon);
-        }
-    }
+    private final CSFactory csFactory;
 
     /**
-     * Appends the axis directions in the given definition string buffer.
-     *
-     * @param  def        the definition string buffer.
-     * @param  cs         the coordinate system.
-     * @param  dimension  the number of dimension to format (may be lower than the CS dimension).
-     * @throws FactoryException if an axis direction is not supported.
+     * The factory for datum objects.
      */
-    private static void appendAxisDirections(final StringBuilder def, final CoordinateSystem cs,
-            final int dimension) throws FactoryException
-    {
-        for (int i=0; i<dimension; i++) {
-            final AxisDirection dir = cs.getAxis(i).getDirection();
-            final char c;
-                 if (dir == AxisDirection.EAST ) c = 'e';
-            else if (dir == AxisDirection.WEST ) c = 'w';
-            else if (dir == AxisDirection.NORTH) c = 'n';
-            else if (dir == AxisDirection.SOUTH) c = 's';
-            else if (dir == AxisDirection.UP   ) c = 'u';
-            else if (dir == AxisDirection.DOWN ) c = 'd';
-            else throw new FactoryException("Unsupported axis direction: " + dir);
-            def.append(c);
-        }
-    }
+    private final DatumFactory datumFactory;
 
     /**
-     * Creates a geographic or geocentric coordinate reference system.
-     *
-     * @param  type        {@code "latlon"} or {@code "geocent"}.
-     * @param  properties  name to give to the new object.
-     * @param  datum       geodetic datum to use in created CRS.
-     * @param  cs          the ellipsoidal coordinate system for the created CRS.
-     * @return the coordinate reference system for the given properties.
-     * @throws FactoryException if the object creation failed.
+     * Poll of identifiers created by this factory.
      */
-    private CoordinateReferenceSystem createGeodeticCRS(final String type, final Map<String,?> properties,
-            final GeodeticDatum datum, final CoordinateSystem cs) throws FactoryException
-    {
-        final int           dimension  = cs.getDimension();
-        final Identifier    name       = new ImmutableIdentifier(properties);
-        final Ellipsoid     ellipsoid  = datum.getEllipsoid();
-        final StringBuilder definition = new StringBuilder(100);
-        definition.append("+proj=").append(type)
-                .append(" +a=").append(ellipsoid.getSemiMajorAxis())
-                .append(" +b=").append(ellipsoid.getSemiMinorAxis());
-        appendPrimeMeridian(definition, datum.getPrimeMeridian());
-        appendAxisDirections(definition.append(' ').append(Proj4.AXIS_ORDER_PARAM), cs, Math.min(dimension, 3));
-        try {
-            return Proj4.createCRS(name, datum.getName(), definition.toString(), dimension);
-        } catch (IllegalArgumentException e) {
-            throw new FactoryException(e.getMessage(), e);
-        }
-    }
+    private final Map<String,Identifier> identifiers;
 
     /**
-     * Creates a geographic coordinate reference system.
-     * It can be <var>Latitude</var>/<var>Longitude</var> or <var>Longitude</var>/<var>Latitude</var>.
-     *
-     * @param  properties  name to give to the new object.
-     * @param  datum       geodetic datum to use in created CRS.
-     * @param  cs          the ellipsoidal coordinate system for the created CRS.
-     * @return the coordinate reference system for the given properties.
-     * @throws FactoryException if the object creation failed.
-     */
-    @Override
-    public GeographicCRS createGeographicCRS(final Map<String,?> properties,
-            final GeodeticDatum datum, final EllipsoidalCS cs) throws FactoryException
-    {
-        return (GeographicCRS) createGeodeticCRS("latlon", properties, datum, cs);
-    }
-
-    /**
-     * Creates a geocentric coordinate reference system.
-     *
-     * @param  properties  name to give to the new object.
-     * @param  datum       geodetic datum to use in created CRS.
-     * @param  cs          the coordinate system for the created CRS.
-     * @return the coordinate reference system for the given properties.
-     * @throws FactoryException if the object creation failed.
-     */
-    @Override
-    public GeocentricCRS createGeocentricCRS(final Map<String,?> properties,
-            final GeodeticDatum datum, final CartesianCS cs) throws FactoryException
-    {
-        return (GeocentricCRS) createGeodeticCRS("geocent", properties, datum, cs);
-    }
+     * Pool of {@literal Proj.4} objects created so far. The keys are the Proj.4 definition strings.
+     * The same {@link PJ} instance may appear more than once if various definition strings resulted
+     * in the same Proj.4 object.
+     */
+    private final WeakValueHashMap<String,PJ> pool;
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
+     * Creates a new factory.
      */
-    @Override
-    public GeocentricCRS createGeocentricCRS (Map<String,?> properties, GeodeticDatum datum, SphericalCS cs) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+    private ReferencingFactory() {
+        crsFactory   = DefaultFactories.forBuildin(CRSFactory.class);
+        csFactory    = DefaultFactories.forBuildin(CSFactory.class);
+        datumFactory = DefaultFactories.forBuildin(DatumFactory.class);
+        identifiers  = new HashMap<>();
+        pool         = new WeakValueHashMap<>(String.class);
     }
 
     /**
-     * Creates a projected coordinate reference system from a defining conversion.
-     * The projection and parameter names in the {@code conversionFromBase} can be
-     * Proj.4 names, OGC names, EPSG names or GeoTIFF names.
-     *
-     * @param  properties          name to give to the new object.
-     * @param  baseCRS             geographic coordinate reference system to base the projection on.
-     * @param  conversionFromBase  the defining conversion.
-     * @param  derivedCS           the coordinate system for the projected CRS.
-     * @return the coordinate reference system for the given properties.
-     * @throws FactoryException if the object creation failed.
-     */
-    @Override
-    public ProjectedCRS createProjectedCRS(final Map<String,?> properties, final GeographicCRS baseCRS,
-            final Conversion conversionFromBase, final CartesianCS derivedCS) throws FactoryException
-    {
-        final int                 dimension  = derivedCS.getDimension();
-        final Identifier          name       = new ImmutableIdentifier(properties);
-        final EllipsoidalCS       baseCS     = baseCRS.getCoordinateSystem();
-        final GeodeticDatum       datum      = baseCRS.getDatum();
-        final Ellipsoid           ellipsoid  = datum.getEllipsoid();
-        final ParameterValueGroup parameters = conversionFromBase.getParameterValues();
-        final StringBuilder       definition = new StringBuilder(200);
-        definition.append("+proj=").append(ResourcesLoader.getProjName(parameters, false).substring(1));
-        boolean hasSemiMajor = false;
-        boolean hasSemiMinor = false;
-        for (final GeneralParameterValue parameter : parameters.values()) {
-            if (parameter instanceof ParameterValue) {
-                final Object value = ((ParameterValue) parameter).getValue();
-                if (value != null) {
-                    final String pn = ResourcesLoader.getProjName(parameter, true);
-                    if (pn.equals("+a")) hasSemiMajor = true;
-                    if (pn.equals("+b")) hasSemiMinor = true;
-                    definition.append(' ').append(pn).append('=').append(value);
-                }
+     * Returns the value of the given parameter as an identifier, or {@code null} if none.
+     * The given parameter key shall include the {@code '+'} prefix and {@code '='} suffix,
+     * for example {@code "+proj="}. This is a helper method for providing the {@code name}
+     * property value in constructors.
+     *
+     * @param  definition  the Proj.4 definition string to parse.
+     * @param  keyword     the parameter name.
+     * @return the parameter value as an identifier.
+     */
+    private Map<String,Identifier> identifier(final String definition, final String keyword) {
+        String value = "";
+        if (keyword != null) {
+            int i = definition.indexOf(keyword);
+            if (i >= 0) {
+                i += keyword.length();
+                final int stop = definition.indexOf(' ', i);
+                value = (stop >= 0) ? definition.substring(i, stop) : definition.substring(i);
+                value = value.trim();
             }
         }
-        if (!hasSemiMajor) definition.append(" +a=").append(ellipsoid.getSemiMajorAxis());
-        if (!hasSemiMinor) definition.append(" +b=").append(ellipsoid.getSemiMinorAxis());
-        appendPrimeMeridian (definition, datum.getPrimeMeridian());
-        appendAxisDirections(definition.append(' ').append(Proj4.AXIS_ORDER_PARAM), derivedCS, Math.min(dimension, 3));
-        appendAxisDirections(definition.append(Proj4.AXIS_ORDER_SEPARATOR), baseCS, Math.min(baseCS.getDimension(), 3));
-        final CRS.Projected crs;
-        try {
-            crs = (CRS.Projected) Proj4.createCRS(name, datum.getName(), definition.toString(), dimension);
-        } catch (IllegalArgumentException e) {
-            throw new FactoryException(e.getMessage(), e);
-        }
-        if (baseCRS instanceof CRS.Geographic) {
-            crs.baseCRS = (CRS.Geographic) baseCRS;
+        if (value.isEmpty()) {
+            value = "Unnamed";
         }
-        return crs;
+        return identifier(value);
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
+     * Returns the identifier for the given code in {@literal Proj.4} namespace.
      */
-    @Override
-    public VerticalCRS createVerticalCRS(Map<String,?> properties, VerticalDatum datum, VerticalCS cs) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+    private Map<String,Identifier> identifier(final String code) {
+        Identifier id = identifiers.computeIfAbsent(code, (k) -> {
+            short i18n = 0;
+            if (k.equalsIgnoreCase("Unnamed")) i18n = Vocabulary.Keys.Unnamed;
+            if (k.equalsIgnoreCase("Unknown")) i18n = Vocabulary.Keys.Unknown;
+            return new ImmutableIdentifier(Citations.PROJ4, Constants.PROJ4, k, null,
+                    (i18n != 0) ? Vocabulary.formatInternational(i18n) : null);
+        });
+        return Collections.singletonMap(IdentifiedObject.NAME_KEY, id);
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
+     * Creates a geodetic datum from the given {@literal Proj.4} wrapper.
      *
-     * @throws FactoryException always thrown.
+     * @param  pj  the Proj.4 object to wrap.
      */
-    @Override
-    public TemporalCRS createTemporalCRS(Map<String, ?> properties, TemporalDatum datum, TimeCS cs) throws FactoryException {
-        throw Proj4.unsupportedOperation();
-    }
-
-    /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
-     */
-    @Override
-    public ParametricCRS createParametricCRS(Map<String, ?> properties, ParametricDatum datum, ParametricCS cs) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+    private GeodeticDatum createDatum(final PJ pj) throws FactoryException {
+        final PrimeMeridian pm;
+        final double greenwichLongitude = pj.getGreenwichLongitude();
+        if (greenwichLongitude == 0) {
+            pm = CommonCRS.WGS84.datum().getPrimeMeridian();
+        } else {
+            pm = datumFactory.createPrimeMeridian(identifier("Unnamed"), greenwichLongitude, Units.DEGREE);
+        }
+        final String definition = pj.getCode();
+        return datumFactory.createGeodeticDatum(identifier(definition, "+datum="),
+               datumFactory.createEllipsoid    (identifier(definition, "+ellps="),
+                    pj.getSemiMajorAxis(), pj.getSemiMinorAxis(), Units.METRE), pm);
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
-     */
-    @Override
-    public ImageCRS createImageCRS(Map<String, ?> properties, ImageDatum datum, AffineCS cs) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+     * Creates a coordinate reference system from the given {@literal Proj.4} wrapper.
+     * The given {@code pj} will be stored as the CRS identifier.
+     *
+     * @param  pj          the Proj.4 object to wrap.
+     * @param  withHeight  whether to include a height axis.
+     */
+    private CoordinateReferenceSystem createCRS(final PJ pj, final boolean withHeight) throws FactoryException {
+        final PJ.Type type = pj.getType();
+        final boolean geographic = PJ.Type.GEOGRAPHIC.equals(type);
+        final char[] dir = pj.getAxisDirections();
+        final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[withHeight ? dir.length : 2];
+        for (int i=0; i<axes.length; i++) {
+            final char d = Character.toLowerCase(dir[i]);
+            char abbreviation = Character.toUpperCase(d);
+            boolean vertical = false;
+            final AxisDirection c;
+            final String name;
+            switch (d) {
+                case 'e': c = AxisDirection.EAST;  name = geographic ? "Geodetic longitude" : "Easting";  break;
+                case 'w': c = AxisDirection.WEST;  name = geographic ? "Geodetic longitude" : "Westing";  break;
+                case 'n': c = AxisDirection.NORTH; name = geographic ? "Geodetic latitude"  : "Northing"; break;
+                case 's': c = AxisDirection.SOUTH; name = geographic ? "Geodetic latitude"  : "Southing"; break;
+                case 'u': c = AxisDirection.UP;    name = "Height";  vertical = true; abbreviation = 'h'; break;
+                case 'd': c = AxisDirection.DOWN;  name = "Depth";   vertical = true; break;
+                default:  c = AxisDirection.OTHER; name = "Unknown"; break;
+            }
+            if (geographic && AxisDirections.isCardinal(c)) {
+                abbreviation = (d == 'e' || d == 'w') ? 'λ' : 'φ';
+            }
+            final Unit<?> unit = (vertical || !geographic) ? Units.METRE.divide(pj.getLinearUnitToMetre(vertical)) : Units.DEGREE;
+            axes[i] = csFactory.createCoordinateSystemAxis(identifier(name), String.valueOf(abbreviation).intern(), c, unit);
+        }
+        /*
+         * At this point we got the coordinate system axes. Now create the CRS. The given Proj.4 object
+         * will be stored as the CRS identifier for allowing OperationFactory to get it back before to
+         * attempt to create a new one for a given CRS.
+         */
+        final Map<String,Identifier> csName = identifier("Unnamed");
+        final Map<String,Identifier> name = new HashMap<>(identifier(pj.getName()));
+        name.put(CoordinateReferenceSystem.IDENTIFIERS_KEY, pj);
+        switch (type) {
+            case GEOGRAPHIC: {
+                return crsFactory.createGeographicCRS(name, createDatum(pj), withHeight ?
+                        csFactory.createEllipsoidalCS(csName, axes[0], axes[1], axes[2]) :
+                        csFactory.createEllipsoidalCS(csName, axes[0], axes[1]));
+            }
+            case GEOCENTRIC: {
+                return crsFactory.createGeocentricCRS(name, createDatum(pj),
+                        csFactory.createCartesianCS(csName, axes[0], axes[1], axes[2]));
+            }
+            case PROJECTED: {
+                final CoordinateReferenceSystem base = createCRS(unique(new PJ(pj)), withHeight);
+                final Conversion fromBase = null;   // TODO
+                return crsFactory.createProjectedCRS(name, (GeographicCRS) base, fromBase, withHeight ?
+                        csFactory.createCartesianCS(csName, axes[0], axes[1], axes[2]) :
+                        csFactory.createCartesianCS(csName, axes[0], axes[1]));
+            }
+            default: {
+                throw new FactoryException(Errors.format(Errors.Keys.UnknownEnumValue_2, type, PJ.Type.class));
+            }
+        }
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
-     */
-    @Override
-    public EngineeringCRS createEngineeringCRS(Map<String, ?> properties, EngineeringDatum datum, CoordinateSystem cs) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+     * Gets the {@literal Proj.4} object from the given coordinate reference system. If an existing {@code PJ}
+     * instance is found, returns it. Otherwise creates a new {@code PJ} instance from a Proj.4 definition
+     * inferred from the given CRS. This method is the converse of {@link #createCRS(PJ, boolean)}.
+     */
+    private PJ unwrapOrCreate(final CoordinateReferenceSystem crs) throws FactoryException {
+        for (final Identifier id : crs.getIdentifiers()) {
+            if (id instanceof PJ) {
+                return (PJ) id;
+            }
+        }
+        return unique(new PJ(Proj4.definition(crs)));
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
+     * Returns a unique instance of the given {@literal Proj.4} object.
      */
-    @Override
-    public DerivedCRS createDerivedCRS(Map<String, ?> properties, CoordinateReferenceSystem baseCRS, Conversion conversionFromBase, CoordinateSystem derivedCS) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+    @SuppressWarnings("FinalizeCalledExplicitly")
+    private PJ unique(PJ pj) {
+        final PJ existing = pool.putIfAbsent(pj.getCode(), pj);
+        if (existing != null) {
+            pj.finalize();          // Release Proj.4 resources.
+            return existing;
+        }
+        return pj;
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
+     * Creates a coordinate reference system from the given {@literal Proj.4} definition string.
      *
-     * @throws FactoryException always thrown.
+     * @param  definition  the Proj.4 definition.
+     * @param  withHeight  whether to include a height axis.
      */
-    @Override
-    public CompoundCRS createCompoundCRS(Map<String, ?> properties, CoordinateReferenceSystem... elements) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+    public CoordinateReferenceSystem createCRS(final String definition, final boolean withHeight) throws FactoryException {
+        PJ pj = pool.get(definition);
+        if (pj == null) {
+            pj = unique(new PJ(definition));
+            pool.putIfAbsent(definition, pj);
+        }
+        return createCRS(pj, withHeight);
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
+     * Creates an operation for conversion or transformation between two coordinate reference systems.
      *
-     * @throws FactoryException always thrown.
+     * @param  sourceCRS  the source coordinate reference system.
+     * @param  targetCRS  the target coordinate reference system.
+     * @return a coordinate operation for transforming coordinates from the given source CRS to the given target CRS.
+     * @throws FactoryException if the given CRS are not instances recognized by this class.
      */
-    @Override
-    public CoordinateReferenceSystem createFromXML(String xml) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+    public CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
+                                               final CoordinateReferenceSystem targetCRS)
+            throws FactoryException
+    {
+        Identifier id;
+        String src = null, tgt = null, name = "Unnamed";
+        if ((id = sourceCRS.getName()) != null) src = id.getCode();
+        if ((id = targetCRS.getName()) != null) tgt = id.getCode();
+        if (src != null || tgt != null) {
+            final StringBuilder buffer = new StringBuilder();
+            if (src != null) buffer.append("From ").append(src);
+            if (tgt != null) buffer.append(buffer.length() == 0 ? "To " : " to ").append(tgt);
+            name = buffer.toString();
+        }
+        final Transform tr = new Transform(unwrapOrCreate(sourceCRS), is3D("sourceCRS", sourceCRS),
+                                           unwrapOrCreate(targetCRS), is3D("targetCRS", targetCRS));
+        /*
+         * TODO: should create a more specific coordinate operation.
+         */
+        return new AbstractCoordinateOperation(identifier(name), sourceCRS, targetCRS, null, tr);
     }
 
     /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
-     */
-    @Override
-    public CoordinateReferenceSystem createFromWKT(String wkt) throws FactoryException {
-        throw Proj4.unsupportedOperation();
+     * Returns whether the given CRS is three-dimensional.
+     * Thrown an exception if the number of dimension is unsupported.
+     */
+    private static boolean is3D(final String arg, final CoordinateReferenceSystem crs) throws FactoryException {
+        final int dim = crs.getCoordinateSystem().getDimension();
+        final boolean is3D = (dim >= 3);
+        if (dim < 2 || dim > 3) {
+            throw new FactoryException(Errors.format(Errors.Keys.MismatchedDimension_3, arg, is3D ? 3 : 2, dim));
+        }
+        return is3D;
     }
 }



Mime
View raw message