sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1801463 [2/3] - in /sis/branches/JDK8: ide-project/NetBeans/nbproject/ storage/ storage/sis-gdal/ storage/sis-gdal/src/ storage/sis-gdal/src/main/ storage/sis-gdal/src/main/c/ storage/sis-gdal/src/main/java/ storage/sis-gdal/src/main/java/...
Date Mon, 10 Jul 2017 12:51:33 GMT
Added: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRSFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRSFactory.java?rev=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRSFactory.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRSFactory.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.util.Map;
+import javax.measure.Unit;
+import javax.measure.quantity.Angle;
+
+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.apache.sis.metadata.iso.ImmutableIdentifier;
+import org.apache.sis.util.iso.AbstractFactory;
+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}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+final class CRSFactory extends AbstractFactory implements org.opengis.referencing.crs.CRSFactory {
+    /**
+     * The unique instance.
+     */
+    static final CRSFactory INSTANCE = new CRSFactory();
+
+    /**
+     * Creates a new factory.
+     */
+    private 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.
+     */
+    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);
+        }
+    }
+
+    /**
+     * 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.
+     */
+    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);
+        }
+    }
+
+    /**
+     * 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.
+     */
+    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);
+        }
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException always thrown.
+     */
+    @Override
+    public GeocentricCRS createGeocentricCRS (Map<String,?> properties, GeodeticDatum datum, SphericalCS cs) throws FactoryException {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * 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);
+                }
+            }
+        }
+        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;
+        }
+        return crs;
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException always thrown.
+     */
+    @Override
+    public VerticalCRS createVerticalCRS(Map<String,?> properties, VerticalDatum datum, VerticalCS cs) throws FactoryException {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException always thrown.
+     */
+    @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();
+    }
+
+    /**
+     * 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();
+    }
+
+    /**
+     * 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();
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException always thrown.
+     */
+    @Override
+    public DerivedCRS createDerivedCRS(Map<String, ?> properties, CoordinateReferenceSystem baseCRS, Conversion conversionFromBase, CoordinateSystem derivedCS) throws FactoryException {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException always thrown.
+     */
+    @Override
+    public CompoundCRS createCompoundCRS(Map<String, ?> properties, CoordinateReferenceSystem... elements) throws FactoryException {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException always thrown.
+     */
+    @Override
+    public CoordinateReferenceSystem createFromXML(String xml) throws FactoryException {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * 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();
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRSFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRSFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: 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=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.util.Set;
+import java.util.Collections;
+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;
+
+
+/**
+ * A factory for {@linkplain CoordinateReferenceSystem Coordinate Reference System} objects created from EPSG codes.
+ * While this factory is primarily designed for EPSG codes, it accepts also any other codespaces supported by the
+ * Proj.4 library.
+ *
+ * <p>The main methods in this class are:</p>
+ * <ul>
+ *   <li>{@link #getAuthority()}</li>
+ *   <li>{@link #createCoordinateReferenceSystem(String)}</li>
+ * </ul>
+ *
+ * The following methods delegate to {@link #createCoordinateReferenceSystem(String)} and cast
+ * the result if possible, or throw a {@link FactoryException} otherwise.
+ * <ul>
+ *   <li>{@link #createGeographicCRS(String)}</li>
+ *   <li>{@link #createGeocentricCRS(String)}</li>
+ *   <li>{@link #createProjectedCRS(String)}</li>
+ *   <li>{@link #createObject(String)}</li>
+ * </ul>
+ *
+ * All other methods are not supported by the default implementation of this factory.
+ * However those methods will work if the {@link #createCoordinateReferenceSystem(String)}
+ * method is overridden in order to return CRS objects of the appropriate type.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+final class EPSGFactory extends AbstractFactory implements CRSAuthorityFactory {
+    /**
+     * {@code true} if the CRS created by this factory should use the axis order declared by the EPSG database.
+     */
+    private final boolean useEpsgAxisOrder;
+
+    /**
+     * The set of all EPSG codes known to Proj.4, created when first needed.
+     */
+    private Set<String> codes;
+
+    /**
+     * Creates a new coordinate operation factory. Whether the factory will follow
+     * EPSG axis order or not is specified by the given {@code useEpsgAxisOrder} argument.
+     *
+     * @param useEpsgAxisOrder {@code true} if the CRS created by this factory should
+     *        use the axis order declared by the EPSG database, or {@code false} for
+     *        the Proj.4 axis order. The default value is {@code true}.
+     */
+    private EPSGFactory(final boolean useEpsgAxisOrder) {
+        this.useEpsgAxisOrder = useEpsgAxisOrder;
+    }
+
+    /**
+     * Returns the authority for this factory, which is EPSG.
+     */
+    @Override
+    public Citation getAuthority() {
+        return useEpsgAxisOrder ? Citations.EPSG : Citations.PROJ4;
+    }
+
+    /**
+     * Returns the authority codes.
+     *
+     * @throws FactoryException if an error occurred while fetching the authority codes.
+     */
+    @Override
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
+    public synchronized Set<String> getAuthorityCodes(Class<? extends IdentifiedObject> type) throws FactoryException {
+        if (codes == null) {
+            codes = Collections.unmodifiableSet(ResourcesLoader.getAxisOrientations().keySet());
+        }
+        return codes;
+    }
+
+    /**
+     * 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.
+     *
+     * @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;
+    }
+
+    /**
+     * Creates a new CRS from the given code. If the given string is of the form {@code "AUTHORITY:CODE"},
+     * then any authority recognized by the Proj.4 library will be accepted (it doesn't need to be EPSG).
+     * If no authority is given, then {@code "EPSG:"} is assumed.
+     *
+     * @param  code  the code of the CRS object to create.
+     * @return a CRS created from the given code.
+     * @throws FactoryException if the CRS object can not be created for the given code.
+     */
+    @Override
+    public CoordinateReferenceSystem createCoordinateReferenceSystem(String code) throws FactoryException {
+        String codespace = "EPSG";
+        code = code.trim();
+        final int s = code.indexOf(':');
+        if (s >= 0) {
+            codespace = code.substring(0, s).trim();
+            code = code.substring(s+1).trim();
+        }
+        int dimension = 2;
+        final StringBuilder definition = new StringBuilder(40);
+        definition.append("+init=").append(codespace).append(':').append(code);
+        if (useEpsgAxisOrder) {
+            /*
+             * If the user asked to honor the EPSG axis definitions, get the axis orientation
+             * from the "axis-orientations.txt" file.   This may be a comma-separated list if
+             * there is also a definition for the base CRS. It may be 2 or 3 characters long.
+             * The number of characters determine the number of dimensions. However this will
+             * have to be adjusted before to be given to Proj.4 since the later expects
+             * exactly 3 characters.
+             */
+            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);
+                dimension = (end >= 0) ? end : orientation.length();
+            }
+        }
+        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);
+        }
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public GeographicCRS createGeographicCRS(String code) throws FactoryException {
+        return cast(GeographicCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public GeocentricCRS createGeocentricCRS(String code) throws FactoryException {
+        return cast(GeocentricCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public ProjectedCRS createProjectedCRS(String code) throws FactoryException {
+        return cast(ProjectedCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public CompoundCRS createCompoundCRS(String code) throws FactoryException {
+        return cast(CompoundCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public DerivedCRS createDerivedCRS(String code) throws FactoryException {
+        return cast(DerivedCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public EngineeringCRS createEngineeringCRS(String code) throws FactoryException {
+        return cast(EngineeringCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public ImageCRS createImageCRS(String code) throws FactoryException {
+        return cast(ImageCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public TemporalCRS createTemporalCRS(String code) throws FactoryException {
+        return cast(TemporalCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public VerticalCRS createVerticalCRS(String code) throws FactoryException {
+        return cast(VerticalCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public ParametricCRS createParametricCRS(String code) throws FactoryException {
+        return cast(ParametricCRS.class, code);
+    }
+
+    /**
+     * Delegates to {@link #createCoordinateReferenceSystem(String)} and casts the result.
+     *
+     * @throws FactoryException if {@code createCoordinateReferenceSystem(code)} failed.
+     */
+    @Override
+    public IdentifiedObject createObject(String code) throws FactoryException {
+        return createCoordinateReferenceSystem(code);
+    }
+
+    /**
+     * Invokes {@link #createCoordinateReferenceSystem(String)} and casts the result
+     * to the given type. If the result can not be casted, a factory exception is thrown.
+     */
+    private <T extends CoordinateReferenceSystem> T cast(final Class<T> type, final String code) throws FactoryException {
+        final CoordinateReferenceSystem crs = createCoordinateReferenceSystem(code);
+        try {
+            return type.cast(crs);
+        } catch (ClassCastException e) {
+            throw new FactoryException("The \"" + code + "\" object is not a " + type.getSimpleName(), e);
+        }
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java?rev=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.metadata.Identifier;
+import org.opengis.metadata.quality.PositionalAccuracy;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.geometry.GeneralDirectPosition;
+
+
+/**
+ * A math transform which delegate its work to the Proj4 native library.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+class Operation extends PJObject implements SingleOperation, MathTransform {
+    /**
+     * The source and target CRS.
+     */
+    final CRS source, target;
+
+    /**
+     * The inverse transform, created only when first needed.
+     */
+    private transient Operation inverse;
+
+    /**
+     * Creates a new operation for the given source and target CRS.
+     */
+    Operation(final Identifier name, final CRS source, final CRS target) {
+        super(name);
+        this.source = source;
+        this.target = target;
+    }
+
+    /**
+     * Returns the operation method.
+     *
+     * @todo Not yet implemented.
+     */
+    @Override
+    public OperationMethod getMethod() {
+        return null;
+    }
+
+    /**
+     * Returns the parameter values defining this operation.
+     *
+     * @todo Not yet implemented.
+     */
+    @Override
+    public ParameterValueGroup getParameterValues() {
+        return null;
+    }
+
+    /*
+     * Trivial methods.
+     */
+    @Override public CoordinateReferenceSystem getSourceCRS() {return source;}
+    @Override public CoordinateReferenceSystem getTargetCRS() {return target;}
+    @Override public final int     getSourceDimensions()      {return source.getDimension();}
+    @Override public final int     getTargetDimensions()      {return target.getDimension();}
+    @Override public MathTransform getMathTransform()         {return this;}
+    @Override public String        getOperationVersion()      {return PJ.getVersion();}
+    @Override
+    public Collection<PositionalAccuracy> getCoordinateOperationAccuracy() {
+        return Collections.emptySet();
+    }
+
+    /**
+     * Returns {@code true} if this transform is the identity transform. Note that a value of
+     * {@code false} does not mean that the transform is not an identity transform, since this
+     * case is a bit difficult to determine from Proj.4 API.
+     */
+    @Override
+    public boolean isIdentity() {
+        return source.pj.equals(target.pj) && source.getDimension() == target.getDimension();
+    }
+
+    /**
+     * Transforms a single coordinate point.
+     */
+    @Override
+    public DirectPosition transform(final DirectPosition ptSrc, DirectPosition ptDst)
+            throws MismatchedDimensionException, TransformException
+    {
+        final int srcDim = source.getDimension();
+        final int tgtDim = target.getDimension();
+        if (ptSrc.getDimension() != srcDim) {
+            throw new MismatchedDimensionException();
+        }
+        double[] ordinates = new double[Math.max(srcDim, tgtDim)];
+        for (int i=0; i<srcDim; i++) {
+            ordinates[i] = ptSrc.getOrdinate(i);
+        }
+        source.pj.transform(target.pj, ordinates.length, ordinates, 0, 1);
+        if (ptDst != null) {
+            if (ptDst.getDimension() != tgtDim) {
+                throw new MismatchedDimensionException();
+            }
+            for (int i=0; i<tgtDim; i++) {
+                ptDst.setOrdinate(i, ordinates[i]);
+            }
+        } else {
+            if (ordinates.length != tgtDim) {
+                ordinates = Arrays.copyOf(ordinates, tgtDim);
+            }
+            ptDst = new GeneralDirectPosition(ordinates);
+        }
+        return ptDst;
+    }
+
+    /**
+     * Transforms an array of coordinate tuples.
+     */
+    @Override
+    public void transform(final double[] srcPts, final int srcOff,
+                          final double[] dstPts, final int dstOff,
+                          final int numPts) throws TransformException
+    {
+        final int srcDim = source.getDimension();
+        final int tgtDim = target.getDimension();
+        if (srcDim == tgtDim) {
+            if (srcPts != dstPts || srcOff != dstOff) {
+                final int length = tgtDim * numPts;
+                System.arraycopy(srcPts, srcOff, dstPts, dstOff, length);
+            }
+        } else {
+            // TODO: need special check for overlapping arrays.
+            throw new TransformException("Transformation between CRS of different dimensions not yet supported.");
+        }
+        source.pj.transform(target.pj, tgtDim, dstPts, dstOff, numPts);
+    }
+
+    /**
+     * Transforms an array of coordinate tuples.
+     */
+    @Override
+    public void transform(final float[] srcPts, int srcOff,
+                          final float[] dstPts, int dstOff,
+                          int numPts) throws TransformException
+    {
+        if (numPts > 0) {
+            final int srcDim = source.getDimension();
+            final int tgtDim = target.getDimension();
+            final int dimension = Math.min(srcDim, tgtDim);
+            final int length = dimension * numPts;
+            final double[] copy = new double[length];
+            int skip = srcDim - dimension;
+            int stop = (skip == 0) ? length : dimension;
+            for (int i=0;;) {
+                copy[i] = srcPts[srcOff + i];
+                if (++i == stop) {
+                    if (i == length) break;
+                    srcOff += skip;
+                    stop += dimension;
+                }
+            }
+            source.pj.transform(target.pj, dimension, copy, 0, numPts);
+            skip = tgtDim - dimension;
+            stop = (skip == 0) ? length : dimension;
+            for (int i=0;;) {
+                dstPts[dstOff + i] = (float) copy[i];
+                if (++i == stop) {
+                    if (i == length) break;
+                    dstOff += skip;
+                    stop += dimension;
+                }
+            }
+        }
+    }
+
+    /**
+     * Transforms an array of coordinate tuples.
+     */
+    @Override
+    public void transform(final float[]  srcPts, int srcOff,
+                          final double[] dstPts, int dstOff,
+                          final int numPts) throws TransformException
+    {
+        if (numPts > 0) {
+            final int srcDim = source.getDimension();
+            final int tgtDim = target.getDimension();
+            final int dimension = Math.min(srcDim, tgtDim);
+            final int skipS  = srcDim - dimension;
+            final int skipT  = tgtDim - dimension;
+            final int length = dimension * numPts;
+            int stop = (skipS == 0 && skipT == 0) ? length : dimension;
+            if (skipT != 0) {
+                Arrays.fill(dstPts, dstOff, dstOff + tgtDim * numPts, Double.NaN);
+            }
+            for (int i=0;;) {
+                dstPts[dstOff + i] = srcPts[srcOff + i];
+                if (++i == stop) {
+                    if (i == length) break;
+                    srcOff += skipS;
+                    dstOff += skipT;
+                    stop += dimension;
+                }
+            }
+            source.pj.transform(target.pj, tgtDim, dstPts, dstOff, numPts);
+        }
+    }
+
+    /**
+     * Transforms an array of coordinate tuples.
+     */
+    @Override
+    public void transform(final double[] srcPts, int srcOff,
+                          final float[]  dstPts, int dstOff,
+                          final int numPts) throws TransformException
+    {
+        if (numPts > 0) {
+            final int srcDim = source.getDimension();
+            final int tgtDim = target.getDimension();
+            final int dimension = Math.min(srcDim, tgtDim);
+            final int length = dimension * numPts;
+            final double[] copy;
+            if (srcDim == dimension) {
+                copy = Arrays.copyOfRange(srcPts, srcOff, srcOff + length);
+            } else {
+                copy = new double[length];
+                for (int i=0; i!=length; i+=dimension) {
+                    System.arraycopy(srcPts, srcOff, copy, i, dimension);
+                    srcOff += srcDim;
+                }
+            }
+            source.pj.transform(target.pj, dimension, copy, 0, numPts);
+            final int skip = tgtDim - dimension;
+            int stop = (skip == 0) ? length : dimension;
+            for (int i=0;;) {
+                dstPts[dstOff + i] = (float) copy[i];
+                if (++i == stop) {
+                    if (i == length) break;
+                    dstOff += skip;
+                    stop += dimension;
+                }
+            }
+        }
+    }
+
+    /**
+     * The Proj4 library does not provide derivative functions.
+     */
+    @Override
+    public Matrix derivative(DirectPosition point) throws TransformException {
+        throw new TransformException("Not supported yet.");
+    }
+
+    /**
+     * Returns the inverse transform.
+     */
+    @Override
+    public synchronized MathTransform inverse() {
+        if (inverse == null) {
+            inverse = new Operation(name, target, source);
+            inverse.inverse = this;
+        }
+        return inverse;
+    }
+
+    /**
+     * A specialization of {@link Operation} for map projections.
+     */
+    static final class Projection extends Operation implements org.opengis.referencing.operation.Projection {
+        Projection(final Identifier name, final CRS.Geographic source, final CRS.Projected target) {
+            super(name, source, target);
+        }
+
+        /**
+         * Always {@code null} by definition for map projection, according ISO 19111.
+         */
+        @Override
+        public String getOperationVersion() {
+            return null;
+        }
+
+        /**
+         * Returns the source CRS, which must be geographic or {@code null}.
+         */
+        @Override
+        public final GeographicCRS getSourceCRS() {
+            return (GeographicCRS) super.getSourceCRS();
+        }
+
+        /**
+         * Returns the target CRS, which must be projected or {@code null}.
+         */
+        @Override
+        public final ProjectedCRS getTargetCRS() {
+            return (ProjectedCRS) super.getTargetCRS();
+        }
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java?rev=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.util.Map;
+import org.opengis.metadata.Identifier;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.Conversion;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.CoordinateOperationFactory;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.util.FactoryException;
+
+import org.apache.sis.util.iso.AbstractFactory;
+import org.apache.sis.metadata.iso.ImmutableIdentifier;
+
+
+/**
+ * A factory for {@linkplain CoordinateOperation Coordinate Operation} objects created from source and target CRS.
+ * Current implementation accepts only CRS objects created by a {@link Proj4}.
+ *
+ * <p>The only supported methods are:</p>
+ * <ul>
+ *   <li>{@link #createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem)}</li>
+ *   <li>{@link #createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, OperationMethod)}</li>
+ * </ul>
+ *
+ * All other methods unconditionally throw a {@link FactoryException}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+final class OperationFactory extends AbstractFactory implements CoordinateOperationFactory {
+    /**
+     * Creates a new coordinate operation factory.
+     */
+    private OperationFactory() {
+    }
+
+    /**
+     * Creates an operation for conversion or transformation between two coordinate reference systems.
+     * This given source and target CRS must be instances created by {@link Proj4} or {@link EPSGFactory}.
+     *
+     * @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 CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
+                                               final CoordinateReferenceSystem targetCRS)
+            throws FactoryException
+    {
+        Identifier id;
+        String src=null, tgt=null, space=null;
+        if ((id = sourceCRS.getName()) != null) {
+            src = id.getCode();
+            space = id.getCodeSpace();
+        }
+        if ((id = targetCRS.getName()) != null) {
+            tgt = id.getCode();
+            if (space == null) {
+                space = id.getCodeSpace();
+            }
+        }
+        id = null;
+        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);
+            id = new ImmutableIdentifier(null, space, buffer.toString());
+        }
+        try {
+            return Proj4.createOperation(id, sourceCRS, targetCRS);
+        } catch (ClassCastException e) {
+            throw new FactoryException("The CRS must be instances created by PJFactory.", e);
+        }
+    }
+
+    /**
+     * Ignores the given {@code method} argument and delegates to
+     * <code>{@linkplain #createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem)
+     * createOperation}(sourceCRS, targetCRS)</code>.
+     *
+     * @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 CoordinateOperation createOperation(final CoordinateReferenceSystem sourceCRS,
+                                               final CoordinateReferenceSystem targetCRS,
+                                               final OperationMethod method)
+            throws FactoryException
+    {
+        return createOperation(sourceCRS, targetCRS);
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException alway thrown.
+     */
+    @Override
+    public CoordinateOperation createConcatenatedOperation(Map<String,?> properties,
+            CoordinateOperation... operations) throws FactoryException
+    {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException alway thrown.
+     */
+    @Override
+    public Conversion createDefiningConversion(Map<String,?> properties,
+            OperationMethod method, ParameterValueGroup parameters) throws FactoryException
+    {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException alway thrown.
+     */
+    @Override
+    public OperationMethod createOperationMethod(Map<String,?> properties, Integer sourceDimension,
+            Integer targetDimension, ParameterDescriptorGroup parameters) throws FactoryException
+    {
+        throw Proj4.unsupportedOperation();
+    }
+
+    /**
+     * Unconditionally throws an exception, since this functionality is not supported yet.
+     *
+     * @throws FactoryException alway thrown.
+     */
+    @Override
+    public OperationMethod getOperationMethod(String name) throws FactoryException {
+        throw Proj4.unsupportedOperation();
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: 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=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,284 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.util.Objects;
+import java.lang.annotation.Native;
+import org.opengis.referencing.operation.TransformException;
+
+
+/**
+ * Wraps the <a href="http://proj.osgeo.org/">Proj4</a> {@code PJ} native data structure.
+ * Almost every methods defined in this class are native methods delegating the work to the
+ * Proj4 library. This class is the only place where such native methods are defined.
+ *
+ * <p>In the Proj4 library, the {@code PJ} structure aggregates in a single place information usually
+ * splitted in many different ISO 19111 interfaces: {@link org.opengis.referencing.datum.Ellipsoid},
+ * {@link org.opengis.referencing.datum.Datum}, {@link org.opengis.referencing.datum.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
+ */
+class PJ {
+    /**
+     * 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.
+     */
+    @Native
+    static final int DIMENSION_MAX = 100;
+
+    /**
+     * Loads the Proj4 library.
+     */
+    static {
+        System.load("libproj-binding.so");
+        init();
+    }
+
+    /**
+     * Initializes the bindings to the Proj4 library.
+     * This method needs to be invoked exactly once before any method in the {@code PJ} class.
+     */
+    private static native void init();
+
+    /**
+     * 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.
+     * 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.
+     *
+     * @param  definition  the Proj4 definition string.
+     * @throws IllegalArgumentException if the PJ structure can not be created from the given string.
+     */
+    public PJ(final String definition) throws IllegalArgumentException {
+        ptr = allocatePJ(definition);
+        if (ptr == 0) {
+            throw new IllegalArgumentException(definition);
+        }
+    }
+
+    /**
+     * Creates a new {@code PJ} structure derived from an existing {@code PJ} object.
+     * This constructor is usually for getting the
+     * {@linkplain org.opengis.referencing.crs.ProjectedCRS#getBaseCRS() base geographic CRS}
+     * from a {@linkplain org.opengis.referencing.crs.ProjectedCRS projected CRS}.
+     *
+     * @param  crs   the CRS (usually projected) from which to derive a new CRS.
+     * @param  type  the type of the new CRS. Currently, only {@link Type#GEOGRAPHIC} is supported.
+     * @throws IllegalArgumentException if the PJ structure can not be created.
+     */
+    public PJ(final PJ crs, final Type type) throws IllegalArgumentException {
+        Objects.requireNonNull(crs, "The CRS must be non-null.");
+        if (type != Type.GEOGRAPHIC) {
+            throw new IllegalArgumentException("Can not derive the " + type + " type.");
+        }
+        ptr = allocateGeoPJ(crs);
+        if (ptr == 0) {
+            throw new IllegalArgumentException(crs.getLastError());
+        }
+    }
+
+    /**
+     * Allocates a PJ native data structure and returns the pointer to it. This method should be
+     * invoked by 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.
+     * @return a pointer to the PJ native data structure, or 0 if the operation failed.
+     */
+    private static native long allocatePJ(String definition);
+
+    /**
+     * Allocates a PJ native data structure for the base geographic CRS of the given CRS, and
+     * returns the pointer to it. This method should be invoked by 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  projected  the CRS from which to derive the base geographic CRS.
+     * @return a pointer to the PJ native data structure, or 0 if the operation failed.
+     */
+    private static native long allocateGeoPJ(PJ projected);
+
+    /**
+     * Returns the version number of the Proj4 library.
+     *
+     * @return the Proj4 release string.
+     */
+    public static native String getVersion();
+
+    /**
+     * Returns the Proj4 definition string. This is the string given to the constructor,
+     * expanded with as much information as possible.
+     *
+     * @return the Proj4 definition string.
+     */
+    public native String getDefinition();
+
+    /**
+     * Returns the Coordinate Reference System type.
+     *
+     * @return the CRS type.
+     */
+    public native Type getType();
+
+    /**
+     * The coordinate reference system (CRS) type returned by {@link PJ#getType()}.
+     * In the Proj4 library, a CRS can only be geographic, geocentric or projected,
+     * without distinction between 2D and 3D CRS.
+     */
+    public enum Type {
+        /*
+         * IMPLEMENTATION NOTE: Do not rename those fields, unless you update the
+         * native C code accordingly.
+         */
+
+        /**
+         * The CRS is of type {@link org.opengis.referencing.crs.GeographicCRS}.
+         * The CRS can be two-dimensional or three-dimensional.
+         */
+        GEOGRAPHIC,
+
+        /**
+         * The CRS is of type {@link org.opengis.referencing.crs.GeocentricCRS}.
+         * The CRS can only be three-dimensional.
+         */
+        GEOCENTRIC,
+
+        /**
+         * The CRS is of type {@link org.opengis.referencing.crs.ProjectedCRS}.
+         * The CRS can be two-dimensional or three-dimensional.
+         */
+        PROJECTED
+    }
+
+    /**
+     * Returns the value stored in the {@code a_orig} PJ field.
+     *
+     * @return the axis length stored in {@code a_orig}.
+     *
+     * @see org.opengis.referencing.datum.Ellipsoid#getSemiMajorAxis()
+     */
+    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))}.
+     *
+     * @see org.opengis.referencing.datum.Ellipsoid#getSemiMinorAxis()
+     */
+    public native double getSemiMinorAxis();
+
+    /**
+     * 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 org.opengis.referencing.datum.Ellipsoid#isSphere()
+     * @see org.opengis.referencing.datum.Ellipsoid#getInverseFlattening()
+     */
+    public native double getEccentricitySquared();
+
+    /**
+     * 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.
+     *
+     * @return the axis directions.
+     *
+     * @see org.opengis.referencing.cs.CoordinateSystemAxis#getDirection()
+     */
+    public native char[] getAxisDirections();
+
+    /**
+     * Longitude of the prime meridian measured from the Greenwich meridian, positive eastward.
+     *
+     * @return the prime meridian longitude, in degrees.
+     *
+     * @see org.opengis.referencing.datum.PrimeMeridian#getGreenwichLongitude()
+     */
+    public native double getGreenwichLongitude();
+
+    /**
+     * 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.
+     */
+    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.
+     *
+     * <p>Input and output units:</p>
+     * <ul>
+     *   <li>Angular units (as in longitude and latitudes) are decimal degrees.</li>
+     *   <li>Linear units are usually metres, but this is actually projection-dependent.</li>
+     * </ul>
+     *
+     * @param  target       the target CRS.
+     * @param  dimension    the dimension of each coordinate value. Must be in the [2-{@value #DIMENSION_MAX}] range.
+     * @param  coordinates  the coordinates to transform, as a sequence of (<var>x</var>,<var>y</var>,&lt;<var>z</var>&gt;,…) tuples.
+     * @param  offset       offset of the first coordinate in the given array.
+     * @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).
+     *
+     * @see org.opengis.referencing.operation.MathTransform#transform(double[], int, double[], int, int)
+     */
+    public native void transform(PJ target, int dimension, double[] coordinates, int offset, int numPts)
+            throws TransformException;
+
+    /**
+     * Returns a description of the last error that occurred, or {@code null} if none.
+     *
+     * @return the last error that occurred, or {@code null}.
+     */
+    public native String getLastError();
+
+    /**
+     * Returns the string representation of the PJ structure.
+     *
+     * @return the string representation.
+     */
+    @Override
+    public native String toString();
+
+    /**
+     * 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).
+     * <strong>NEVER INVOKE THIS METHOD EXPLICITELY, NEVER OVERRIDE</strong>.
+     */
+    @Override
+    protected final native void finalize();
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJDatum.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJDatum.java?rev=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJDatum.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJDatum.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.util.Date;
+import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
+import javax.measure.Unit;
+import javax.measure.quantity.Angle;
+import javax.measure.quantity.Length;
+
+import org.opengis.util.GenericName;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.Identifier;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.datum.PrimeMeridian;
+
+import org.apache.sis.measure.Units;
+import org.apache.sis.internal.simple.SimpleIdentifier;
+
+import static java.lang.Math.*;
+
+
+/**
+ * Wraps the <a href="http://proj.osgeo.org/">Proj4</a> {@code PJ} native data structure in a geodetic datum.
+ * The PJ structure combines datum, ellipsoid and prime meridian information.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+final class PJDatum extends PJ implements GeodeticDatum, PrimeMeridian, Ellipsoid {
+    /**
+     * Tolerance factor for comparison of floating point numbers.
+     * Must be fine enough for distinguish {@code FOOT} from {@code FOOT_SURVEY_US}.
+     */
+    static final double EPS = 1E-7;
+
+    /**
+     * The datum or ellipsoid name, or {@code null} if none.
+     */
+    private final Identifier name;
+
+    /**
+     * The Proj4 parameters, formatted at construction time because often used.
+     */
+    private final String definition;
+
+    /**
+     * Creates a new {@code PJ} structure from the given Proj4 data.
+     *
+     * @param name        the datum identifier, or {@code null} for inferring it from the definition.
+     * @param definition  the Proj4 definition string.
+     */
+    PJDatum(Identifier name, final String definition) throws IllegalArgumentException {
+        super(definition);
+        this.definition = super.getDefinition();
+        if (name == null) {
+            final String param = getParameter("+datum=");
+            if (param != null) {
+                name = new SimpleIdentifier(null, param, false);
+            }
+        }
+        this.name = name;
+    }
+
+    /**
+     * Creates the base CRS of the given projected CRS.
+     */
+    PJDatum(final PJDatum projected) throws IllegalArgumentException {
+        super(projected, Type.GEOGRAPHIC);
+        definition = super.getDefinition();
+        name = projected.name;
+    }
+
+    /**
+     * Returns the definition cached at construction time. This avoid the need to
+     * recreate the definition from Proj.4 native definition at every method call.
+     */
+    @Override
+    public String getDefinition() {
+        return definition;
+    }
+
+    /**
+     * Returns the name given at construction time, or {@code null} if none.
+     * Note that this attribute is mandatory according ISO 19111, but this
+     * simple Proj.4 wrapper is lenient about that.
+     */
+    @Override
+    public Identifier getName() {
+        return name;
+    }
+
+    /*
+     * Various GeoAPI method having no direct mapping in the Proj4 library.
+     */
+    @Override public Collection<GenericName>  getAlias()            {return Collections.emptySet();}
+    @Override public Set<Identifier>          getIdentifiers()      {return Collections.emptySet();}
+    @Override public InternationalString      getScope()            {return null;}
+    @Override public InternationalString      getRemarks()          {return null;}
+    @Override public InternationalString      getAnchorPoint()      {return null;}
+    @Override public Date                     getRealizationEpoch() {return null;}
+    @Override public Extent                   getDomainOfValidity() {return null;}
+
+    /**
+     * Returns the ellipsoid associated with the geodetic datum.
+     */
+    @Override
+    public Ellipsoid getEllipsoid() {
+        return this;
+    }
+
+    /**
+     * Returns the prime meridian associated with the geodetic datum.
+     */
+    @Override
+    public PrimeMeridian getPrimeMeridian() {
+        return this;
+    }
+
+    /**
+     * Returns the ellipsoid axis unit, which is assumed metres in the case of the Proj4 library.
+     */
+    @Override
+    public Unit<Length> getAxisUnit() {
+        return Units.METRE;
+    }
+
+    /**
+     * Returns the linear unit for the horizontal or the vertical axes.
+     */
+    public Unit<Length> getLinearUnit(final boolean vertical) {
+        return Units.METRE.divide(getLinearUnitToMetre(vertical));
+    }
+
+    /**
+     * Returns the units of the prime meridian.
+     * All angular units are converted from radians to degrees in those wrappers.
+     */
+    @Override
+    public Unit<Angle> getAngularUnit() {
+        return Units.DEGREE;
+    }
+
+    /**
+     * Returns {@code true} unconditionally since the inverse eccentricity squared in definitive
+     * in the Proj4 library, and the eccentricity is directly related to the flattening.
+     */
+    @Override
+    public boolean isIvfDefinitive() {
+        return true;
+    }
+
+    /**
+     * Returns the inverse flattening, computed from the eccentricity.
+     */
+    @Override
+    public double getInverseFlattening() {
+        return 1 / (1 - sqrt(1 - getEccentricitySquared()));
+    }
+
+    /**
+     * Returns {@code true} if the ellipsoid is a sphere.
+     */
+    @Override
+    public boolean isSphere() {
+        return getEccentricitySquared() == 0;
+    }
+
+    /**
+     * Returns the value of the given parameter, or {@code null} if none. The given parameter key
+     * shall include the {@code '+'} prefix and {@code '='} suffix, for example {@code "+proj="}.
+     *
+     * @param  key  the parameter name.
+     * @return the parameter value.
+     */
+    final String getParameter(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 value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Throws unconditionally an exception since there is no WKt formatting provided by the Proj4 library.
+     */
+    @Override
+    public String toWKT() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJDatum.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJDatum.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: 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=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
+import org.opengis.util.GenericName;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.Identifier;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.referencing.IdentifiedObject;
+
+
+/**
+ * Base class of implementations in this Proj4 wrappers package.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+class PJObject implements IdentifiedObject {
+    /**
+     * The name of this referencing object, or {@code null} if none.
+     */
+    final Identifier name;
+
+    /**
+     * The aliases, or an empty list if none.
+     */
+    final Collection<GenericName> aliases;
+
+    /**
+     * Creates a new identified object of the given name.
+     *
+     * @param name  the name of the new object, or {@code null} if none.
+     */
+    PJObject(final Identifier name) {
+        this.name    = name;
+        this.aliases = Collections.emptyList();
+    }
+
+    /**
+     * Creates a new identified object of the given name and aliases.
+     *
+     * @param name  the name of the new object, or {@code null} if none.
+     */
+    PJObject(final Identifier name, final Collection<GenericName> aliases) {
+        this.name    = name;
+        this.aliases = aliases;
+    }
+
+    /**
+     * Creates a new identified object as a copy of the given one.
+     */
+    PJObject(final IdentifiedObject object) {
+        name    = object.getName();
+        aliases = object.getAlias();
+    }
+
+    /**
+     * 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.
+     */
+    @Override
+    public Identifier getName() {
+        return name;
+    }
+
+    /**
+     * Returns the name in a singleton set, since we don't have anything better for identifiers.
+     * The objects created by {@link Proj4} will use {@code "EPSG:xxxx"} identifiers, so this is
+     * rather the name which is quite inaccurate.
+     */
+    @Override
+    public Set<Identifier> getIdentifiers() {
+        return Collections.singleton(name);
+    }
+
+    /**
+     * Returns the aliases, or an empty set if none. The aliases are determined from
+     * the {@code "parameter-names.txt"} or {@code "projection-names.txt"} resources
+     * files.
+     */
+    @Override
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
+    public Collection<GenericName> getAlias() {
+        return aliases;
+    }
+
+    /**
+     * Returns {@code null} since we do not define any scope in our Proj4 wrappers.
+     * Note that this method is not inherited from {@link IdentifiedObject}, but is
+     * defined in sub-interfaces like {@link org.opengis.referencing.crs.SingleCRS}.
+     */
+    public InternationalString getScope() {
+        return null;
+    }
+
+    /**
+     * Returns {@code null} since we do not define any domain of validity.
+     * Note that this method is not inherited from {@link IdentifiedObject}, but is
+     * defined in sub-interfaces like {@link org.opengis.referencing.crs.SingleCRS}.
+     */
+    public Extent getDomainOfValidity() {
+        return null;
+    }
+
+    /**
+     * Returns {@code null} since there is no remarks associated with our Proj4 wrappers.
+     */
+    @Override
+    public InternationalString getRemarks() {
+        return null;
+    }
+
+    /**
+     * Throws unconditionally the exception since we do not support WKT formatting.
+     */
+    @Override
+    public String toWKT() throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns a string representation of this object, mostly for debugging purpose.
+     * This string representation may change in any future version.
+     */
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + '[' + name + ']';
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Added: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java?rev=1801463&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java (added)
+++ sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java [UTF-8] Mon Jul 10 12:51:33 2017
@@ -0,0 +1,370 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.storage.gdal;
+
+import java.net.URI;
+import java.util.Set;
+import java.util.Collection;
+import javax.measure.Unit;
+import javax.measure.IncommensurableException;
+
+import org.opengis.util.GenericName;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.Identifier;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterDirection;
+import org.opengis.parameter.InvalidParameterTypeException;
+import org.opengis.parameter.InvalidParameterValueException;
+
+import org.apache.sis.measure.Units;
+
+
+/**
+ * A relatively "simple" implementation of a parameter value for {@code double} values.
+ * In order to keep the model simpler, this parameter value is also its own descriptor.
+ * This is not quite a recommended practice (such descriptors are less suitable for use in {@link java.util.HashMap}),
+ * but allow us to keep the amount of classes smaller and closely related interfaces together.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+final class Parameter extends PJObject implements ParameterValue<Double>, ParameterDescriptor<Double>, Cloneable {
+    /**
+     * The parameter value.
+     *
+     * @see #doubleValue()
+     * @see #setValue(double)
+     */
+    private double value;
+
+    /**
+     * Creates a new parameter with the given identifier and aliases.
+     */
+    Parameter(final Identifier identifier, final Collection<GenericName> aliases) {
+        super(identifier, aliases);
+    }
+
+    /**
+     * Creates a new parameter as a copy of the given one.
+     */
+    Parameter(final ParameterValue<?> param) {
+        super(param.getDescriptor());
+        value = param.doubleValue();
+    }
+
+    /**
+     * Returns the descriptor of the parameter value, which is {@code this}.
+     */
+    @Override
+    public ParameterDescriptor<Double> getDescriptor() {
+        return this;
+    }
+
+    /**
+     * Returns {@code null}, since this simple class does not provide parameter description.
+     */
+    @Override
+    public InternationalString getDescription() {
+        return null;
+    }
+
+    /**
+     * Returns {@code this}, since this simple class is used only as input parameter.
+     */
+    @Override
+    public ParameterDirection getDirection() {
+        return ParameterDirection.IN;
+    }
+
+    /**
+     * Returns the minimum number of times that values for this parameter are required.
+     * This method returns 1, meaning that a value shall alway be supplied
+     * (the {@link #getValue()} method never return {@code null}).
+     */
+    @Override
+    public int getMinimumOccurs() {
+        return 1;
+    }
+
+    /**
+     * Returns the maximum number of times that values for this parameter can be included.
+     * This method unconditionally returns 1, which is the mandatory value for
+     * {@link ParameterValue} implementations.
+     */
+    @Override
+    public int getMaximumOccurs() {
+        return 1;
+    }
+
+    /**
+     * Unconditionally returns {@code Double.class}, which is the hard-coded type of values
+     * in this parameter implementation.
+     */
+    @Override
+    public Class<Double> getValueClass() {
+        return Double.class;
+    }
+
+    /**
+     * Returns {@code null}, since this simple class has no information about units of measurement.
+     */
+    @Override
+    public Unit<?> getUnit() {
+        return null;
+    }
+
+    /**
+     * Returns {@code null}, since this simple class has no information about the
+     * range of valid values.
+     */
+    @Override
+    public Comparable<Double> getMinimumValue() {
+        return null;
+    }
+
+    /**
+     * Returns {@code null}, since this simple class has no information about the
+     * range of valid values.
+     */
+    @Override
+    public Comparable<Double> getMaximumValue() {
+        return null;
+    }
+
+    /**
+     * Returns {@code null}, since this simple class has no information about the
+     * set of valid values.
+     */
+    @Override
+    public Set<Double> getValidValues() {
+        return null;
+    }
+
+    /**
+     * Returns {@code null}, since this simple class has no information about the default value.
+     */
+    @Override
+    public Double getDefaultValue() {
+        return null;
+    }
+
+    /**
+     * Returns the parameter {@linkplain #value} as an object.
+     */
+    @Override
+    public Double getValue() {
+        return value;
+    }
+
+    /**
+     * Returns the numeric {@linkplain #value} represented by this parameter.
+     */
+    @Override
+    public double doubleValue() {
+        return value;
+    }
+
+    /**
+     * Returns the standard unit used by Proj.4 for any value in the given unit.
+     */
+    private static Unit<?> getStandardUnit(final Unit<?> unit) {
+        if (Units.isLinear(unit))  return Units.METRE;
+        if (Units.isAngular(unit)) return Units.DEGREE;
+        if (Units.isScale(unit))   return Units.UNITY;
+        return null;
+    }
+
+    /**
+     * Returns the numeric value of the operation parameter in the specified unit of measure.
+     * This convenience method applies unit conversion from metres or decimal degrees as needed.
+     *
+     * @param  unit  the unit of measure for the value to be returned.
+     * @return the numeric value represented by this parameter after conversion to {@code unit}.
+     */
+    @Override
+    public double doubleValue(final Unit<?> unit) {
+        double c = value;
+        final Unit<?> standardUnit = getStandardUnit(unit);
+        if (standardUnit != null) try {
+            c = standardUnit.getConverterToAny(unit).convert(c);
+        } catch (IncommensurableException e) {
+            throw new IllegalArgumentException(e);              // Should never happen actually.
+        }
+        return c;
+    }
+
+    /**
+     * Creates an exception for an invalid type.
+     */
+    private InvalidParameterTypeException invalidType(final String type) {
+        return new InvalidParameterTypeException("Value " + value + " is not " + type + '.', name.getCode());
+    }
+
+    /**
+     * Returns the value as an integer if it can be casted without information lost,
+     * or throw an exception otherwise.
+     */
+    @Override
+    public int intValue() throws InvalidParameterTypeException {
+        final int r = (int) value;
+        if (r == value) {
+            return r;
+        }
+        throw invalidType("an integer");
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not a boolean.
+     */
+    @Override
+    public boolean booleanValue() throws InvalidParameterTypeException {
+        throw invalidType("a boolean");
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not a string.
+     */
+    @Override
+    public String stringValue() throws InvalidParameterTypeException {
+        throw invalidType("a string");
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not an array.
+     */
+    @Override
+    public double[] doubleValueList(final Unit<?> unit) throws IllegalArgumentException, IllegalStateException {
+        throw invalidType("an array");
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not an array.
+     */
+    @Override
+    public double[] doubleValueList() throws InvalidParameterTypeException {
+        throw invalidType("an array");
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not an array.
+     */
+    @Override
+    public int[] intValueList() throws InvalidParameterTypeException {
+        throw invalidType("an array");
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not a file.
+     */
+    @Override
+    public URI valueFile() throws InvalidParameterTypeException {
+        throw invalidType("a file");
+    }
+
+    /**
+     * Sets the parameter to the given value, after conversion to metres or decimal degrees.
+     */
+    @Override
+    public void setValue(double value, final Unit<?> unit) {
+        final Unit<?> standardUnit = getStandardUnit(unit);
+        if (standardUnit != null) try {
+            value = unit.getConverterToAny(standardUnit).convert(value);
+        } catch (IncommensurableException e) {
+            throw new IllegalArgumentException(e);              // Should never happen actually.
+        }
+        this.value = value;
+    }
+
+    /**
+     * Sets the parameter value as a floating point.
+     */
+    @Override
+    public void setValue(final double value) throws InvalidParameterValueException {
+        this.value = value;
+    }
+
+    /**
+     * Creates an exception for an invalid value.
+     */
+    private InvalidParameterValueException invalidValue(final String type, final Object value) {
+        return new InvalidParameterValueException("This parameter does not support " + type + '.', name.getCode(), value);
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not for arrays.
+     */
+    @Override
+    public void setValue(final double[] values, final Unit<?> unit) throws InvalidParameterValueException {
+        throw invalidValue("arrays", values);
+    }
+
+    /**
+     * Sets the parameter value as an integer, converted to floating point.
+     */
+    @Override
+    public void setValue(final int value) throws InvalidParameterValueException {
+        this.value = value;
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not for booleans.
+     */
+    @Override
+    public void setValue(final boolean value) throws InvalidParameterValueException {
+        throw invalidValue("booleans", value);
+    }
+
+    /**
+     * Unsupported operation, since this parameter is not for strings.
+     */
+    @Override
+    public void setValue(final Object value) throws InvalidParameterValueException {
+        throw invalidValue("strings", value);
+    }
+
+    /**
+     * Returns a new parameter with the same {@linkplain #name} than this parameter.
+     * The {@linkplain #value} is left to their default value.
+     *
+     * @see #clone()
+     */
+    @Override
+    public Parameter createValue() {
+        return new Parameter(name, aliases);
+    }
+
+    /**
+     * Returns a copy of this parameter value. This method is similar to {@link #createValue()}
+     * except that the {@linkplain #value} is initialized to the same value than the cloned parameter.
+     */
+    @Override
+    @SuppressWarnings("CloneDoesntCallSuperClone")          // Okay since this class is final.
+    public Parameter clone() {
+        return new Parameter(this);
+    }
+
+    /**
+     * Returns the string representation of this parameter value.
+     */
+    @Override
+    public String toString() {
+        return super.toString() + " = " + value;
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8



Mime
View raw message