sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1802074 [2/2] - in /sis/trunk: ./ 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/internal/referencin...
Date Sun, 16 Jul 2017 15:51:19 GMT
Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java?rev=1802074&r1=1802073&r2=1802074&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java [UTF-8] Sun
Jul 16 15:51:18 2017
@@ -16,39 +16,42 @@
  */
 package org.apache.sis.storage.gdal;
 
-import java.util.Date;
 import java.util.Objects;
-import javax.measure.Unit;
-import javax.measure.quantity.Angle;
-import javax.measure.quantity.Length;
-import org.opengis.metadata.extent.Extent;
+import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.ReferenceIdentifier;
+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.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.util.iso.SimpleInternationalString;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.CharSequences;
+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 ReferenceIdentifier {
     /**
      * 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.
@@ -56,7 +59,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.
@@ -67,24 +70,23 @@ 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(ReferenceIdentifier 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) {
-            throw new InvalidGeodeticParameterException(definition);
+            throw new InvalidGeodeticParameterException(Errors.format(Errors.Keys.UnparsableStringForClass_2,
+                    CoordinateReferenceSystem.class, definition));
         }
     }
 
@@ -95,13 +97,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());
         }
     }
 
@@ -110,7 +112,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);
@@ -126,19 +128,101 @@ 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 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 Proj4 definition string. This is the string given to the constructor,
+     * 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.
+     * Note that the string returned by Proj.4 contains <cite>End Of Line</cite>
characters.
+     *
+     * <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();
+    public InternationalString getDescription() {
+        String name = getName();
+        if (name != null) {
+            final StringBuilder buffer = new StringBuilder(name.length());
+            for (CharSequence line : CharSequences.splitOnEOL(getName())) {
+                line = CharSequences.trimWhitespaces(line);
+                if (buffer.length() != 0) buffer.append(' ');
+                buffer.append(line);
+            }
+            name = buffer.toString();
+            if (!name.isEmpty()) {
+               return new SimpleInternationalString(name);
+            }
+        }
+        return null;
+    }
 
     /**
      * Returns the Coordinate Reference System type.
@@ -149,7 +233,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 {
@@ -178,131 +262,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.
      *
@@ -313,29 +318,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>
@@ -350,7 +345,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)
      */
@@ -361,20 +356,40 @@ final class PJ extends PJObject implemen
      * Returns a description of the last error that occurred, or {@code null} if none.
      *
      * @return the last error that occurred, or {@code null}.
+     *
+     * @todo this method is not thread-safe. Proj.4 provides a better alternative using a
context parameter.
      */
     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/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java?rev=1802074&r1=1802073&r2=1802074&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java [UTF-8]
(original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java [UTF-8]
Sun Jul 16 15:51:18 2017
@@ -16,17 +16,40 @@
  */
 package org.apache.sis.storage.gdal;
 
+import javax.measure.Unit;
+import javax.measure.quantity.Angle;
 import org.opengis.util.FactoryException;
-import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.referencing.IdentifiedObject;
+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.referencing.IdentifiedObjects;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.internal.metadata.AxisDirections;
 import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.system.OS;
 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;
+import org.opengis.referencing.operation.Projection;
 
 
 /**
- * Bindings to the Proj4 library.
+ * Bindings to the {@literal Proj.4} library.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
@@ -36,37 +59,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,90 +86,153 @@ 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 ReferenceIdentifier crsId,
-            final ReferenceIdentifier 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) {
+            Projection c = ((ProjectedCRS) crs).getConversionFromBase();
+            datum        = ((ProjectedCRS) crs).getDatum();
+            method       = name(c.getMethod());
+            parameters   = c.getParameterValues();
+        } 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 = name(parameter.getDescriptor());
+                        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(Proj4Factory.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();
+    }
+
+    /**
+     * Returns the {@literal Proj.4} name for the given parameter,
+     * or throws an exception if the {@literal Proj.4} name is unknown.
+     */
+    private static String name(final IdentifiedObject object) throws FactoryException {
+        final String name = IdentifiedObjects.getName(object, Citations.PROJ4);
+        if (name == null) {
+            throw new FactoryException(Errors.format(Errors.Keys.CanNotSetParameterValue_1,
object.getName()));
+        }
+        return name;
+    }
+
+    /**
+     * 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.
+     *
+     * @see Proj4Factory#createCoordinateReferenceSystem(String)
+     */
+    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 Proj4Factory.INSTANCE.createCRS(definition, dimension >= 3);
+        } catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
+            throw new UnavailableFactoryException(Errors.format(Errors.Keys.NativeInterfacesNotFound_2,
OS.uname(), "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.
+     * This implementation always uses Proj.4 for performing the coordinate operations, regardless
if
+     * the given CRS were created from a Proj.4 definition string or not. This method fails
if it can
+     * not map the given CRS to Proj.4 structures.
      *
-     * @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.
+     *
+     * @see Proj4Factory#createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem)
      */
-    public static CoordinateOperation createOperation(final ReferenceIdentifier 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);
-    }
-
-    /**
-     * Returns the exception to throw when a feature is not yet supported.
-     */
-    static FactoryException unsupportedOperation() {
-        return new FactoryException("Not supported yet.");
+        ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
+        ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
+        try {
+            return Proj4Factory.INSTANCE.createOperation(sourceCRS, targetCRS);
+        } catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
+            throw new UnavailableFactoryException(Errors.format(Errors.Keys.NativeInterfacesNotFound_2,
OS.uname(), "libproj"), e);
+        }
     }
 }

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/package-info.java?rev=1802074&r1=1802073&r2=1802074&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/package-info.java
[UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/package-info.java
[UTF-8] Sun Jul 16 15:51:18 2017
@@ -16,7 +16,7 @@
  */
 
 /**
- * Referencing services as wrapper around the C/C++ <a href="http://proj.osgeo.org/">Proj4</a>
library.
+ * Referencing services as wrapper around the C/C++ <a href="http://proj.osgeo.org/">{@literal
Proj.4}</a> library.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8

Modified: sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/PJTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/PJTest.java?rev=1802074&r1=1802073&r2=1802074&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/PJTest.java [UTF-8]
(original)
+++ sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/storage/gdal/PJTest.java [UTF-8]
Sun Jul 16 15:51:18 2017
@@ -16,9 +16,9 @@
  */
 package org.apache.sis.storage.gdal;
 
+import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.TransformException;
-import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
-import org.apache.sis.measure.Units;
+import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.test.TestCase;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -37,18 +37,18 @@ import static org.junit.Assume.*;
  */
 public final strictfp class PJTest extends TestCase {
     /**
-     * If the Proj4 library has been successfully initialized, an empty string.
+     * If the {@literal Proj.4} library has been successfully initialized, an empty string.
      * Otherwise, the reason why the library is not available.
      */
     private static String status;
 
     /**
-     * Verifies if the Proj4 library is available.
+     * Verifies if the {@literal Proj.4} library is available.
      */
     @BeforeClass
     public static synchronized void verifyNativeLibraryAvailability() {
         if (status == null) try {
-            out.println("Proj.4 version: " + PJ.getVersion());
+            out.println("Proj.4 version: " + PJ.getRelease());
             status = "";
         } catch (UnsatisfiedLinkError e) {
             status = e.toString();
@@ -60,39 +60,39 @@ public final strictfp class PJTest exten
      * Ensures that the given object is the WGS84 definition.
      */
     private static void assertIsWGS84(final PJ pj) {
-        assertEquals("+proj=latlong +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0", pj.getDefinition().trim());
-        assertEquals("Lat/long (Geodetic alias)", pj.toString().trim());
+        assertEquals("Lat/long (Geodetic alias)", pj.getName().trim());
+        assertEquals("+proj=latlong +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0", pj.getCode().trim());
+        assertEquals("Proj4",            pj.getCodeSpace());
+        assertSame  (Citations.PROJ4,    pj.getAuthority());
+        assertTrue  (Character.isDigit(  pj.getVersion().codePointAt(0)));
         assertEquals(PJ.Type.GEOGRAPHIC, pj.getType());
-        assertEquals("WGS84",            pj.getName().getCode());
         assertEquals(6378137.0,          pj.getSemiMajorAxis(),         1E-9);
         assertEquals(6356752.314245179,  pj.getSemiMinorAxis(),         1E-9);
         assertEquals(298.257223563,      pj.getInverseFlattening(),     1E-9);
         assertEquals(0.0,                pj.getGreenwichLongitude(),    STRICT);
         assertEquals(1.0,                pj.getLinearUnitToMetre(true), STRICT);
-        assertSame  (Units.METRE,        pj.getAxisUnit());
-        assertFalse(pj.isSphere());
         assertArrayEquals(new char[] {'e', 'n', 'u'}, pj.getAxisDirections());
     }
 
     /**
      * Tests the creation of a simple WGS84 object.
      *
-     * @throws InvalidGeodeticParameterException if the Proj4 definition string used in this
test is invalid.
+     * @throws FactoryException if the Proj.4 definition string used in this test is invalid.
      */
     @Test
-    public void testWGS84() throws InvalidGeodeticParameterException {
-        final PJ pj = new PJ(null, "+proj=latlong +datum=WGS84");
+    public void testWGS84() throws FactoryException {
+        final PJ pj = new PJ("+proj=latlong +datum=WGS84");
         assertIsWGS84(pj);
     }
 
     /**
      * Tests the creation of the EPSG:3395 projected CRS.
      *
-     * @throws InvalidGeodeticParameterException if the Proj4 definition string used in this
test is invalid.
+     * @throws FactoryException if the Proj.4 definition string used in this test is invalid.
      */
     @Test
-    public void testEPSG3395() throws InvalidGeodeticParameterException {
-        final PJ pj = new PJ(null, "+init=epsg:3395");
+    public void testEPSG3395() throws FactoryException {
+        final PJ pj = new PJ("+init=epsg:3395");
         assertEquals(PJ.Type.PROJECTED, pj.getType());
         assertArrayEquals(new char[] {'e', 'n', 'u'}, pj.getAxisDirections());
         assertEquals(1.0, pj.getLinearUnitToMetre(true), STRICT);
@@ -100,29 +100,29 @@ public final strictfp class PJTest exten
     }
 
     /**
-     * Tests the {@link PJ#getLinearUnit(boolean)} method.
+     * Tests the {@link PJ#getLinearUnitToMetre(boolean)} method.
      *
-     * @throws InvalidGeodeticParameterException if the Proj4 definition string used in this
test is invalid.
+     * @throws FactoryException if the Proj.4 definition string used in this test is invalid.
      */
     @Test
-    public void testGetLinearUnit() throws InvalidGeodeticParameterException {
+    public void testGetLinearUnit() throws FactoryException {
         PJ pj;
-        pj = new PJ(null, "+proj=merc +to_meter=1");
-        assertSame(Units.METRE, pj.getLinearUnit(false));
-        pj = new PJ(null, "+proj=merc +to_meter=0.001");
-        assertSame(Units.KILOMETRE, pj.getLinearUnit(false));
+        pj = new PJ("+proj=merc +to_meter=1");
+        assertEquals(1, pj.getLinearUnitToMetre(false), STRICT);
+        pj = new PJ("+proj=merc +to_meter=0.001");
+        assertEquals(0.001, pj.getLinearUnitToMetre(false), STRICT);
     }
 
     /**
      * Ensures that the native code correctly detects the case of null pointers.
      * This is important in order to ensure that we don't have a JVM crash.
      *
-     * @throws InvalidGeodeticParameterException if the Proj4 definition string used in this
test is invalid.
+     * @throws FactoryException if the Proj.4 definition string used in this test is invalid.
      * @throws TransformException should never happen.
      */
     @Test
-    public void testNullPointerException() throws InvalidGeodeticParameterException, TransformException
{
-        final PJ pj = new PJ(null, "+proj=latlong +datum=WGS84");
+    public void testNullPointerException() throws FactoryException, TransformException {
+        final PJ pj = new PJ("+proj=latlong +datum=WGS84");
         try {
             pj.transform(null, 2, null, 0, 1);
             fail("Expected an exception to be thrown.");
@@ -135,12 +135,12 @@ public final strictfp class PJTest exten
      * Ensures that the native code correctly detects the case of index out of bounds.
      * This is important in order to ensure that we don't have a JVM crash.
      *
-     * @throws InvalidGeodeticParameterException if the Proj4 definition string used in this
test is invalid.
+     * @throws FactoryException if the Proj.4 definition string used in this test is invalid.
      * @throws TransformException should never happen.
      */
     @Test
-    public void testIndexOutOfBoundsException() throws InvalidGeodeticParameterException,
TransformException {
-        final PJ pj = new PJ(null, "+proj=latlong +datum=WGS84");
+    public void testIndexOutOfBoundsException() throws FactoryException, TransformException
{
+        final PJ pj = new PJ("+proj=latlong +datum=WGS84");
         try {
             pj.transform(pj, 2, new double[5], 2, 2);
             fail("Expected an exception to be thrown.");
@@ -154,12 +154,12 @@ public final strictfp class PJTest exten
      * {@link java.lang.Double#NaN} constant, because not all C/C++ compiler define
      * a {@code NAN} constant.
      *
-     * @throws InvalidGeodeticParameterException if the Proj4 definition string used in this
test is invalid.
+     * @throws FactoryException if the Proj.4 definition string used in this test is invalid.
      */
     @Test
     @SuppressWarnings("FinalizeCalledExplicitly")
-    public void testNaN() throws InvalidGeodeticParameterException {
-        final PJ pj = new PJ(null, "+proj=latlong +datum=WGS84");
+    public void testNaN() throws FactoryException {
+        final PJ pj = new PJ("+proj=latlong +datum=WGS84");
         pj.finalize();              // This cause the disposal of the internal PJ structure.
         assertNull(pj.getType());
         assertNaN(pj.getSemiMajorAxis());

Modified: sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/test/suite/GDALTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/test/suite/GDALTestSuite.java?rev=1802074&r1=1802073&r2=1802074&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/test/suite/GDALTestSuite.java
[UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/test/java/org/apache/sis/test/suite/GDALTestSuite.java
[UTF-8] Sun Jul 16 15:51:18 2017
@@ -31,7 +31,9 @@ import org.junit.runners.Suite;
  */
 @Suite.SuiteClasses({
     org.apache.sis.storage.gdal.PJTest.class,
-    org.apache.sis.storage.gdal.EPSGFactoryTest.class
+    org.apache.sis.storage.gdal.Proj4Test.class,
+    org.apache.sis.storage.gdal.Proj4ParserTest.class,
+    org.apache.sis.storage.gdal.Proj4FactoryTest.class
 })
 public final strictfp class GDALTestSuite extends TestSuite {
     /**



Mime
View raw message