sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1789729 [4/9] - in /sis/branches/JDK9: ./ application/sis-console/ application/sis-console/src/main/java/org/apache/sis/console/ application/sis-console/src/test/java/org/apache/sis/console/ core/ core/sis-feature/src/main/java/org/apache/...
Date Fri, 31 Mar 2017 18:49:18 GMT
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/EPSGFactoryFallback.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -45,6 +45,7 @@ import org.apache.sis.util.resources.Voc
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Debug;
+import org.apache.sis.measure.Latitude;
 
 
 /**
@@ -94,8 +95,8 @@ final class EPSGFactoryFallback extends
     }
 
     /**
-     * Returns the EPSG authority with only a modification in the title of emphasing that this is a subset
-     * of EPSG dataset.
+     * Returns the EPSG authority with only a modification in the title
+     * for emphasing that this is a subset of EPSG dataset.
      */
     @Override
     public synchronized Citation getAuthority() {
@@ -138,10 +139,14 @@ final class EPSGFactoryFallback extends
                 add(codes, crs.geographic);
                 add(codes, crs.geo3D);
             }
-            if (projected && (crs.northUTM != 0 || crs.southUTM != 0)) {
-                for (int zone = crs.firstZone; zone <= crs.lastZone; zone++) {
-                    if (crs.northUTM != 0) codes.add(Integer.toString(crs.northUTM + zone));
-                    if (crs.southUTM != 0) codes.add(Integer.toString(crs.southUTM + zone));
+            if (projected) {
+                add(codes, crs.northUPS);
+                add(codes, crs.southUPS);
+                if (crs.northUTM != 0 || crs.southUTM != 0) {
+                    for (int zone = crs.firstZone; zone <= crs.lastZone; zone++) {
+                        if (crs.northUTM != 0) codes.add(Integer.toString(crs.northUTM + zone));
+                        if (crs.southUTM != 0) codes.add(Integer.toString(crs.southUTM + zone));
+                    }
                 }
             }
         }
@@ -246,13 +251,19 @@ final class EPSGFactoryFallback extends
                     final double latitude;
                     int zone;
                     if (crs.northUTM != 0 && (zone = n - crs.northUTM) >= crs.firstZone && zone <= crs.lastZone) {
-                        latitude = +1;
+                        latitude = +1;          // Any north latitude below 56°N (because of Norway exception) is okay
                     } else if (crs.southUTM != 0 && (zone = n - crs.southUTM) >= crs.firstZone && zone <= crs.lastZone) {
-                        latitude = -1;
+                        latitude = -1;          // Any south latitude above 80°S (because of UPS south case) is okay.
+                    } else if (n == crs.northUPS) {
+                        latitude = Latitude.MAX_VALUE;
+                        zone     = 30;                  // Any random UTM zone is okay.
+                    } else if (n == crs.southUPS) {
+                        latitude = Latitude.MIN_VALUE;
+                        zone     = 30;                  // Any random UTM zone is okay.
                     } else {
                         continue;
                     }
-                    return crs.UTM(latitude, TransverseMercator.centralMeridian(zone));
+                    return crs.universal(latitude, TransverseMercator.Zoner.UTM.centralMeridian(zone));
                 }
             }
             if ((kind & (DATUM | CRS)) != 0) {

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -41,12 +41,14 @@ import org.opengis.util.NoSuchIdentifier
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.metadata.AxisNames;
 import org.apache.sis.internal.referencing.provider.TransverseMercator;
+import org.apache.sis.internal.referencing.provider.PolarStereographicA;
 import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.datum.DefaultEllipsoid;
 import org.apache.sis.referencing.datum.DefaultPrimeMeridian;
 import org.apache.sis.referencing.datum.DefaultGeodeticDatum;
 import org.apache.sis.referencing.datum.DefaultVerticalDatum;
+import org.apache.sis.referencing.cs.CoordinateSystems;
 import org.apache.sis.referencing.cs.DefaultVerticalCS;
 import org.apache.sis.referencing.cs.DefaultCartesianCS;
 import org.apache.sis.referencing.cs.DefaultSphericalCS;
@@ -72,6 +74,7 @@ import static org.apache.sis.internal.me
 /**
  * Definitions of referencing objects identified by the {@link CommonCRS} enumeration values.
  * This class is used only as a fallback if the objects can not be fetched from the EPSG database.
+ * This class should not be loaded when a connection to an EPSG geodetic dataset is available.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
@@ -107,7 +110,7 @@ final class StandardDefinitions {
             map.put(IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, String.valueOf(code)));
         }
         map.put(NAME_KEY, new NamedIdentifier(Citations.EPSG, name));
-        map.put(ALIAS_KEY, alias); // May be null, which is okay.
+        map.put(ALIAS_KEY, alias);                                      // May be null, which is okay.
         if (world) {
             map.put(DOMAIN_OF_VALIDITY_KEY, Extents.WORLD);
         }
@@ -126,29 +129,31 @@ final class StandardDefinitions {
     }
 
     /**
-     * Returns the operation method for Transverse Mercator projection using the SIS factory implementation.
-     * This method restricts the factory to SIS implementation instead than arbitrary factory in order to meet
-     * the contract saying that {@link CommonCRS} methods should never fail.
+     * Creates a Universal Transverse Mercator (UTM) or a Universal Polar Stereographic (UPS) projected CRS
+     * using the Apache SIS factory implementation. This method restricts the factory to SIS implementation
+     * instead than arbitrary factory in order to meet the contract saying that {@link CommonCRS} methods
+     * should never fail.
      *
      * @param code       the EPSG code, or 0 if none.
      * @param baseCRS    the geographic CRS on which the projected CRS is based.
-     * @param latitude   a latitude in the zone of the desired projection, to be snapped to 0°.
+     * @param isUTM      {@code true} for UTM or {@code false} for UPS. Note: redundant with the given latitude.
+     * @param latitude   a latitude in the zone of the desired projection, to be snapped to 0°, 90°S or 90°N.
      * @param longitude  a longitude in the zone of the desired projection, to be snapped to UTM central meridian.
      * @param derivedCS  the projected coordinate system.
      */
-    static ProjectedCRS createUTM(final int code, final GeographicCRS baseCRS,
+    static ProjectedCRS createUniversal(final int code, final GeographicCRS baseCRS, final boolean isUTM,
             final double latitude, final double longitude, final CartesianCS derivedCS)
     {
         final OperationMethod method;
         try {
-            method = DefaultFactories.forBuildin(MathTransformFactory.class,
-                                          DefaultMathTransformFactory.class)
-                    .getOperationMethod(TransverseMercator.NAME);
+            method = DefaultFactories.forBuildin(MathTransformFactory.class, DefaultMathTransformFactory.class)
+                            .getOperationMethod(isUTM ? TransverseMercator.NAME : PolarStereographicA.NAME);
         } catch (NoSuchIdentifierException e) {
-            throw new IllegalStateException(e);     // Should not happen with SIS implementation.
+            throw new IllegalStateException(e);                     // Should not happen with SIS implementation.
         }
         final ParameterValueGroup parameters = method.getParameters().createValue();
-        String name = TransverseMercator.setParameters(parameters, true, latitude, longitude);
+        String name = isUTM ? TransverseMercator.Zoner.UTM.setParameters(parameters, latitude, longitude)
+                            : PolarStereographicA.setParameters(parameters, latitude >= 0);
         final DefaultConversion conversion = new DefaultConversion(properties(0, name, null, false), method, null, parameters);
 
         name = baseCRS.getName().getCode() + " / " + name;
@@ -165,17 +170,17 @@ final class StandardDefinitions {
      */
     static GeographicCRS createGeographicCRS(final short code, final GeodeticDatum datum, final EllipsoidalCS cs) {
         final String name;
-        String alias = null;
-        String scope = null;
+        String  alias = null;
+        String  scope = null;
         boolean world = false;
         switch (code) {
-            case 4326: name = "WGS 84"; world = true; scope = "Horizontal component of 3D system."; break;
-            case 4322: name = "WGS 72"; world = true; break;
-            case 4258: name = "ETRS89"; alias = "ETRS89-GRS80"; break;
-            case 4269: name = "NAD83";  break;
-            case 4267: name = "NAD27";  break;
-            case 4230: name = "ED50";   break;
-            case 4047: name = "Unspecified datum based upon the GRS 1980 Authalic Sphere"; world = true; break;
+            case 4326: name = "WGS 84"; world = true;           scope = "Horizontal component of 3D system."; break;
+            case 4322: name = "WGS 72"; world = true;           scope = "Horizontal component of 3D system."; break;
+            case 4258: name = "ETRS89"; alias = "ETRS89-GRS80"; scope = "Horizontal component of 3D system."; break;
+            case 4269: name = "NAD83";                          scope = "Geodetic survey.";                   break;
+            case 4267: name = "NAD27";                          scope = "Geodetic survey.";                   break;
+            case 4230: name = "ED50";                           scope = "Geodetic survey.";                   break;
+            case 4047: name = "Unspecified datum based upon the GRS 1980 Authalic Sphere"; world = true;      break;
             default:   throw new AssertionError(code);
         }
         final Map<String, Object> properties = properties(code, name, alias, world);
@@ -313,16 +318,17 @@ final class StandardDefinitions {
     @SuppressWarnings("fallthrough")
     static CoordinateSystem createCoordinateSystem(final short code) {
         final String name;
-        final int dim;                  // Number of dimension.
+        int type = 0;                   // 0= Cartesian (default), 1= Spherical, 2= Ellipsoidal
+        int dim = 2;                    // Number of dimension, default to 2.
         short axisCode;                 // Code of first axis + dim (or code after the last axis).
-        boolean isCartesian = false;
-        boolean isSpherical = false;
         switch (code) {
-            case 6422: name = "Ellipsoidal 2D"; dim = 2; axisCode = 108; break;
-            case 6423: name = "Ellipsoidal 3D"; dim = 3; axisCode = 111; break;
-            case 6404: name = "Spherical";      dim = 3; axisCode =  63; isSpherical = true; break;
-            case 6500: name = "Earth centred";  dim = 3; axisCode = 118; isCartesian = true; break;
-            case 4400: name = "Cartesian 2D";   dim = 2; axisCode =   3; isCartesian = true; break;
+            case 6422: name = "Ellipsoidal 2D"; type = 2;          axisCode =  108; break;
+            case 6423: name = "Ellipsoidal 3D"; type = 2; dim = 3; axisCode =  111; break;
+            case 6404: name = "Spherical";      type = 1; dim = 3; axisCode =   63; break;
+            case 6500: name = "Earth centred";            dim = 3; axisCode =  118; break;
+            case 4400: name = "Cartesian 2D";                      axisCode =    3; break;
+            case 1026: name = "Cartesian 2D for UPS north";        axisCode = 1067; break;
+            case 1027: name = "Cartesian 2D for UPS south";        axisCode = 1059; break;
             default:   throw new AssertionError(code);
         }
         final Map<String,?> properties = properties(code, name, null, false);
@@ -334,20 +340,13 @@ final class StandardDefinitions {
             case 1:  xAxis = createAxis(--axisCode);
             case 0:  break;
         }
-        if (isCartesian) {
-            if (zAxis != null) {
-                return new DefaultCartesianCS(properties, xAxis, yAxis, zAxis);
-            } else {
-                return new DefaultCartesianCS(properties, xAxis, yAxis);
-            }
-        } else if (isSpherical) {
-            return new DefaultSphericalCS(properties, xAxis, yAxis, zAxis);
-        } else {
-            if (zAxis != null) {
-                return new DefaultEllipsoidalCS(properties, xAxis, yAxis, zAxis);
-            } else {
-                return new DefaultEllipsoidalCS(properties, xAxis, yAxis);
-            }
+        switch (type) {
+            default: throw new AssertionError(type);
+            case 0:  return (zAxis != null) ? new DefaultCartesianCS  (properties, xAxis, yAxis, zAxis)
+                                            : new DefaultCartesianCS  (properties, xAxis, yAxis);
+            case 1:  return                   new DefaultSphericalCS  (properties, xAxis, yAxis, zAxis);
+            case 2:  return (zAxis != null) ? new DefaultEllipsoidalCS(properties, xAxis, yAxis, zAxis)
+                                            : new DefaultEllipsoidalCS(properties, xAxis, yAxis);
         }
     }
 
@@ -367,12 +366,10 @@ final class StandardDefinitions {
         switch (code) {
             case 1:    name = "Easting";
                        abrv = "E";
-                       unit = Units.METRE;
                        dir  = AxisDirection.EAST;
                        break;
             case 2:    name = "Northing";
                        abrv = "N";
-                       unit = Units.METRE;
                        dir  = AxisDirection.NORTH;
                        break;
             case 60:   name = "Spherical latitude";
@@ -393,7 +390,6 @@ final class StandardDefinitions {
                        break;
             case 62:   name = "Geocentric radius";
                        abrv = "R";                          // See HardCodedAxes.GEOCENTRIC_RADIUS in tests.
-                       unit = Units.METRE;
                        dir  = AxisDirection.UP;
                        rm   = RangeMeaning.EXACT;
                        min  = 0;
@@ -440,6 +436,23 @@ final class StandardDefinitions {
                        abrv = "Z";
                        dir  = AxisDirection.GEOCENTRIC_Z;
                        break;
+            case 1057: // Actually no axis allocated by EPSG here, but createCoordinateSystem(1027) needs this number.
+            case 1056: name = "Easting";
+                       abrv = "E";
+                       dir  = CoordinateSystems.directionAlongMeridian(AxisDirection.NORTH, 90);
+                       break;
+            case 1058: name = "Northing";
+                       abrv = "N";
+                       dir  = CoordinateSystems.directionAlongMeridian(AxisDirection.NORTH, 0);
+                       break;
+            case 1065: name = "Easting";
+                       abrv = "E";
+                       dir  = CoordinateSystems.directionAlongMeridian(AxisDirection.SOUTH, 90);
+                       break;
+            case 1066: name = "Northing";
+                       abrv = "N";
+                       dir  = CoordinateSystems.directionAlongMeridian(AxisDirection.SOUTH, 180);
+                       break;
             default:   throw new AssertionError(code);
         }
         final Map<String,Object> properties = properties(code, name, null, false);

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -169,7 +169,7 @@ public class AbstractCRS extends Abstrac
      *   </tr>
      * </table>
      *
-     * @param properties  The properties to be given to the coordinate reference system.
+     * @param properties  the properties to be given to the coordinate reference system.
      * @param cs          the coordinate system.
      */
     public AbstractCRS(final Map<String,?> properties, final CoordinateSystem cs) {

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -19,6 +19,7 @@ package org.apache.sis.referencing.cs;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.Objects;
 import javax.measure.Unit;
 import javax.measure.quantity.Angle;
 import javax.measure.UnitConverter;
@@ -45,6 +46,7 @@ import org.apache.sis.referencing.Identi
 import org.apache.sis.measure.Longitude;
 import org.apache.sis.measure.Latitude;
 import org.apache.sis.measure.Units;
+import org.apache.sis.util.Utilities;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.jaxb.Context;
@@ -69,9 +71,6 @@ import static org.apache.sis.util.collec
  */
 import static org.apache.sis.internal.referencing.NilReferencingObject.UNNAMED;
 
-// Branch-dependent imports
-import java.util.Objects;
-
 
 /**
  * Coordinate system axis name, direction, unit and range of values.
@@ -567,12 +566,13 @@ public class DefaultCoordinateSystemAxis
      * i.e. it is caller responsibility to determine if range shall be considered as metadata.
      *
      * @param  that  the axis to compare with this axis.
+     * @param  mode  whether the unit comparison is approximative or exact.
      * @param  cr    {@code true} for comparing also the range minimum and maximum values.
      * @return {@code true} if unit, direction and optionally range extremum are equal.
      */
-    private boolean equalsIgnoreMetadata(final CoordinateSystemAxis that, final boolean cr) {
-        return Objects.equals(getUnit(),      that.getUnit()) &&
-               Objects.equals(getDirection(), that.getDirection()) &&
+    private boolean equalsIgnoreMetadata(final CoordinateSystemAxis that, final ComparisonMode mode, final boolean cr) {
+        return Objects.equals(getDirection(), that.getDirection()) &&
+               Utilities.deepEquals(getUnit(), that.getUnit(), mode) &&
                (!cr || (doubleToLongBits(getMinimumValue()) == doubleToLongBits(that.getMinimumValue()) &&
                         doubleToLongBits(getMaximumValue()) == doubleToLongBits(that.getMaximumValue())));
     }
@@ -618,7 +618,7 @@ public class DefaultCoordinateSystemAxis
             }
             case BY_CONTRACT: {
                 final CoordinateSystemAxis that = (CoordinateSystemAxis) object;
-                return equalsIgnoreMetadata(that, true) &&
+                return equalsIgnoreMetadata(that, mode, true) &&
                        Objects.equals(getAbbreviation(), that.getAbbreviation()) &&
                        Objects.equals(getRangeMeaning(), that.getRangeMeaning());
             }
@@ -629,8 +629,8 @@ public class DefaultCoordinateSystemAxis
          * coordinate operation may shift some ordinate values (typically ±360° on longitudes).
          */
         final CoordinateSystemAxis that = (CoordinateSystemAxis) object;
-        if (!equalsIgnoreMetadata(that, RangeMeaning.WRAPAROUND.equals(this.getRangeMeaning()) &&
-                                        RangeMeaning.WRAPAROUND.equals(that.getRangeMeaning())))
+        if (!equalsIgnoreMetadata(that, mode, RangeMeaning.WRAPAROUND.equals(this.getRangeMeaning()) &&
+                                              RangeMeaning.WRAPAROUND.equals(that.getRangeMeaning())))
         {
             return false;
         }

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DatumShiftGrid.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DatumShiftGrid.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DatumShiftGrid.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DatumShiftGrid.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -233,9 +233,9 @@ public abstract class DatumShiftGrid<C e
     }
 
     /**
-     * Computes the conversion factors needed by {@link #interpolateAtNormalized(double, double, double[])}.
-     * This method takes only the 2 first dimensions. If a conversion factor can not be computed, then it is
-     * set to NaN.
+     * Computes the conversion factors needed by {@link #interpolateInCell(double, double, double[])}.
+     * This method takes only the 2 first dimensions. If a conversion factor can not be computed,
+     * then it is set to NaN.
      */
     @SuppressWarnings("fallthrough")
     private void computeConversionFactors() {
@@ -308,7 +308,7 @@ public abstract class DatumShiftGrid<C e
      * validity will still be accepted, but the extrapolated results may be very wrong.
      *
      * <p>The unit of measurement for the coordinate values in the returned envelope is
-     * given by {@link #getCoordinateUnit()}. The complete CRS is undefined.</p>
+     * given by {@link #getCoordinateUnit()}. The envelope CRS is undefined.</p>
      *
      * @return the domain covered by this grid.
      * @throws TransformException if an error occurred while computing the envelope.
@@ -327,6 +327,7 @@ public abstract class DatumShiftGrid<C e
      *
      * @return the unit of measurement of input values before conversion to grid indices.
      *
+     * @see #getTranslationUnit()
      * @see org.apache.sis.referencing.operation.AbstractCoordinateOperation#getInterpolationCRS()
      */
     public Unit<C> getCoordinateUnit() {
@@ -339,7 +340,7 @@ public abstract class DatumShiftGrid<C e
      * given by {@link #getCoordinateUnit()}.
      * The output points are grid indices with integer values in the center of grid cells.
      *
-     * <p>This transform is usually two-dimensional and linear, in which case conversions from (<var>x</var>,<var>y</var>)
+     * <p>This transform is usually two-dimensional, in which case conversions from (<var>x</var>,<var>y</var>)
      * coordinates to ({@code gridX}, {@code gridY}) indices can be done with the following formulas:</p>
      * <ul>
      *   <li><var>gridX</var> = (<var>x</var> - <var>x₀</var>) / <var>Δx</var></li>
@@ -416,6 +417,7 @@ public abstract class DatumShiftGrid<C e
      *
      * @return the unit of measurement of output values interpolated by {@code interpolateAt(…)}.
      *
+     * @see #getCoordinateUnit()
      * @see #interpolateAt
      */
     public Unit<T> getTranslationUnit() {
@@ -461,7 +463,7 @@ public abstract class DatumShiftGrid<C e
     /**
      * Interpolates the translation to apply for the given two-dimensional grid indices. The result is stored in
      * the given {@code vector} array, which shall have a length of at least {@link #getTranslationDimensions()}.
-     * The output unit of measurement is the same than the one documented in {@link #getCellValue}.
+     * The output unit of measurement is the same than the one documented in {@link #getCellValue(int, int, int)}.
      *
      * <div class="section">Default implementation</div>
      * The default implementation performs the following steps for each dimension <var>dim</var>,

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -17,6 +17,7 @@
 package org.apache.sis.referencing.datum;
 
 import java.util.Map;
+import java.util.Objects;
 import javax.measure.Unit;
 import javax.measure.quantity.Length;
 import javax.measure.UnitConverter;
@@ -42,6 +43,7 @@ import org.apache.sis.referencing.Abstra
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.io.wkt.Convention;
 import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.Utilities;
 import org.apache.sis.measure.Units;
 
 import static java.lang.Math.*;
@@ -49,9 +51,6 @@ import static java.lang.Double.*;
 import static org.apache.sis.util.ArgumentChecks.ensureStrictlyPositive;
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
-// Branch-dependent imports
-import java.util.Objects;
-
 
 /**
  * Geometric figure that can be used to describe the approximate shape of the earth.
@@ -717,7 +716,7 @@ public class DefaultEllipsoid extends Ab
                  */
                 final Ellipsoid that = (Ellipsoid) object;
                 final Unit<Length> unit = getAxisUnit();  // In case the user override this method.
-                if (!Objects.equals(unit, that.getAxisUnit())) {
+                if (!Utilities.deepEquals(unit, that.getAxisUnit(), mode)) {
                     return false;
                 }
                 final UnitConverter c = mode.isApproximative() ? unit.getConverterTo(Units.METRE) : null;

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -43,6 +43,7 @@ import org.opengis.referencing.cs.Cartes
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.datum.DatumFactory;
 import org.opengis.referencing.datum.EngineeringDatum;
+import org.apache.sis.internal.referencing.provider.TransverseMercator.Zoner;
 import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
 import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.metadata.iso.citation.Citations;
@@ -60,9 +61,6 @@ import org.apache.sis.util.resources.Err
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.iso.SimpleInternationalString;
 
-import static org.apache.sis.internal.referencing.provider.TransverseMercator.zone;
-import static org.apache.sis.internal.referencing.provider.TransverseMercator.centralMeridian;
-
 
 /**
  * Creates coordinate reference systems in the "{@code OGC}", "{@code CRS}" or {@code "AUTO(2)"} namespaces.
@@ -178,14 +176,18 @@ import static org.apache.sis.internal.re
  *
  * <div class="note"><b>Examples:</b>
  * {@code "AUTO2:42001,1,-100,45"} identifies a Universal Transverse Mercator (UTM) projection
- * for a zone containing the point at (45°N, 100°W).</div>
+ * for a zone containing the point at (45°N, 100°W) with axes in metres.</div>
  *
  * Codes in the {@code "AUTO"} namespace are the same than codes in the {@code "AUTO2"} namespace, except that
  * the {@linkplain org.apache.sis.measure.Units#valueOfEPSG(int) EPSG code} of the desired unit of measurement
  * was used instead than the unit factor.
  * The {@code "AUTO"} namespace was defined in the <cite>Web Map Service</cite> (WMS) 1.1.1 specification
  * while the {@code "AUTO2"} namespace is defined in WMS 1.3.0.
- * In Apache SIS implementation, the unit parameter (either as factor or as EPSG code) is optional and default to metres.
+ * In Apache SIS implementation, the unit parameter (either as factor or as EPSG code) is optional and defaults to metres.
+ *
+ * <p>In the {@code AUTO(2):42001} case, the UTM zone is calculated as specified in WMS 1.3 specification,
+ * i.e. <strong>without</strong> taking in account the Norway and Svalbard special cases and without
+ * switching to polar stereographic projections for high latitudes.</p>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.7
@@ -588,23 +590,26 @@ public class CommonAuthorityFactory exte
              * 42005: WGS 84 / Auto Mollweide         —   defined by "Central_Meridian" only.
              */
             case 42001: isUTM  = true; break;
-            case 42002: isUTM  = (latitude == 0) && (centralMeridian(zone(longitude)) == longitude); break;
-            case 42003: method = "Orthographic";       param = Constants.LATITUDE_OF_ORIGIN;         break;
-            case 42004: method = "Equirectangular";    param = Constants.STANDARD_PARALLEL_1;        break;
-            case 42005: method = "Mollweide";                                                        break;
+            case 42002: isUTM  = (latitude == 0) && (Zoner.UTM.centralMeridian(Zoner.UTM.zone(0, longitude)) == longitude); break;
+            case 42003: method = "Orthographic";       param = Constants.LATITUDE_OF_ORIGIN;  break;
+            case 42004: method = "Equirectangular";    param = Constants.STANDARD_PARALLEL_1; break;
+            case 42005: method = "Mollweide";                                                 break;
             default: throw noSuchAuthorityCode(String.valueOf(projection), code, null);
         }
         /*
          * For the (Universal) Transverse Mercator case (AUTO:42001 and 42002), we delegate to the CommonCRS
          * enumeration if possible because CommonCRS will itself delegate to the EPSG factory if possible.
+         * The Math.signum(latitude) instruction is for preventing "AUTO:42001" to handle the UTM special cases
+         * (Norway and Svalbard) or to switch on the Universal Polar Stereographic projection for high latitudes,
+         * because the WMS specification does not said that we should.
          */
         final CommonCRS datum = CommonCRS.WGS84;
-        final GeographicCRS baseCRS;
-        final ProjectedCRS crs;
-        CartesianCS cs;
+        final GeographicCRS baseCRS;                // To be set, directly or indirectly, to WGS84.geographic().
+        final ProjectedCRS crs;                     // Temporary UTM projection, for extracting other properties.
+        CartesianCS cs;                             // Coordinate system with (E,N) axes in metres.
         try {
             if (isUTM != null && isUTM) {
-                crs = datum.UTM(latitude, longitude);
+                crs = datum.universal(Math.signum(latitude), longitude);
                 if (factor == (isLegacy ? Constants.EPSG_METRE : 1)) {
                     return crs;
                 }
@@ -613,7 +618,7 @@ public class CommonAuthorityFactory exte
             } else {
                 cs = projectedCS;
                 if (cs == null) {
-                    crs = datum.UTM(latitude, longitude);
+                    crs = datum.universal(Math.signum(latitude), longitude);
                     projectedCS = cs = crs.getCoordinateSystem();
                     baseCRS = crs.getBaseCRS();
                 } else {
@@ -641,10 +646,10 @@ public class CommonAuthorityFactory exte
              */
             final GeodeticObjectBuilder builder = new GeodeticObjectBuilder();
             if (isUTM != null) {
-                if (isUTM) {
+                if (isUTM && crs != null) {
                     builder.addName(crs.getName());
                 } // else default to the conversion name, which is "Transverse Mercator".
-                builder.setTransverseMercator(isUTM, latitude, longitude);
+                builder.setTransverseMercator(isUTM ? Zoner.UTM : Zoner.ANY, latitude, longitude);
             } else {
                 builder.setConversionMethod(method)
                        .addName(PROJECTION_NAMES[projection - FIRST_PROJECTION_CODE])

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -16,189 +16,720 @@
  */
 package org.apache.sis.referencing.operation.builder;
 
+import java.util.Map;
+import java.util.Arrays;
 import java.io.IOException;
+import org.opengis.util.FactoryException;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.geometry.coordinate.Position;
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.io.TableAppender;
 import org.apache.sis.math.Line;
 import org.apache.sis.math.Plane;
+import org.apache.sis.math.Vector;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.transform.LinearTransform;
-import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Debug;
 
 
 /**
- * Creates a linear (usually affine) transform which will map approximatively the given source points to
- * the given target points. The transform coefficients are determined using a <cite>least squares</cite>
- * estimation method, with the assumption that source points are precise and all uncertainty is in the
- * target points.
+ * Creates an affine transform which will map approximatively the given source positions to the given target positions.
+ * In many cases, the <em>source</em> positions are grid indices and the <em>target</em> positions are geographic or
+ * projected coordinates, but this is not mandatory. If the source positions are known to be grid indices,
+ * then a builder created by the {@link #LinearTransformBuilder(int...)} constructor will be more efficient.
+ * Otherwise a builder created by the {@link #LinearTransformBuilder()} constructor will be able to handle
+ * randomly distributed coordinates.
  *
- * <div class="note"><b>Implementation note:</b>
- * The quantity that current implementation tries to minimize is not strictly the squared Euclidian distance.
- * The current implementation rather processes each target dimension independently, which may not give the same
- * result than if we tried to minimize the squared Euclidian distances by taking all dimensions in account together.
- * This algorithm may change in future SIS versions.
- * </div>
+ * <p>The transform coefficients are determined using a <cite>least squares</cite> estimation method,
+ * with the assumption that source positions are exact and all the uncertainty is in the target positions.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.8
  * @module
  *
+ * @see LocalizationGridBuilder
  * @see LinearTransform
  * @see Line
  * @see Plane
  */
-public class LinearTransformBuilder {
+public class LinearTransformBuilder extends TransformBuilder {
     /**
-     * The arrays of source ordinate values, for example (x[], y[]).
-     * This is {@code null} if not yet specified.
+     * Number of grid columns and rows, or {@code null} if the coordinates are not distributed on a regular grid.
+     * If the grid size is known, then the {@link #sources} coordinates do not need to be specified.
+     */
+    private final int[] gridSize;
+
+    /**
+     * The arrays of source ordinate values. Accessed with indices in that order: {@code sources[dimension][point]}.
+     * This layout allows to create only a few (typically two) large arrays instead of a multitude of small arrays.
+     * Example: {x[], y[]}.
+     *
+     * <p>In the special case where {@link #gridSize} is non-null, then this array does not need to be specified
+     * and can be {@code null}. In such case, the source coordinates are implicitly:</p>
+     *
+     * <blockquote>
+     * (0,0), (1,0), (2,0), (3,0) … ({@link #gridSize}[0]-1, 0),<br>
+     * (0,1), (1,1), (2,1), (3,1) … ({@link #gridSize}[0]-1, 1),<br>
+     * (0,2), (1,2), (2,2), (3,2) … ({@link #gridSize}[0]-1, 2),<br>
+     * (0,{@link #gridSize}[1]-1) … ({@link #gridSize}[0]-1, {@link #gridSize}[1]-1).
+     * </blockquote>
      */
     private double[][] sources;
 
     /**
-     * The arrays of target ordinate values, for example (x[], y[], z[]).
+     * The arrays of target ordinate values. Accessed with indices in that order: {@code targets[dimension][point]}.
+     * This layout allows to create only a few (typically two) large arrays instead of a multitude of small arrays.
+     * Example: {x[], y[], z[]}.
      * This is {@code null} if not yet specified.
      */
     private double[][] targets;
 
     /**
+     * The product of all {@link #gridSize} values, or 0 if none if {@link #gridSize} is null.
+     * If non-zero, then this is the length of {@link #targets} arrays to create.
+     */
+    final int gridLength;
+
+    /**
+     * Number of valid positions in the {@link #sources} or {@link #targets} arrays.
+     * Note that the "valid" positions may contain {@link Double#NaN} ordinate values.
+     * This field is only indicative if this {@code LinearTransformBuilder} instance
+     * has been created by {@link #LinearTransformBuilder(int...)}.
+     */
+    private int numPoints;
+
+    /**
      * The transform created by the last call to {@link #create()}.
+     * This is reset to {@code null} when coordinates are modified.
      */
-    private LinearTransform transform;
+    private transient LinearTransform transform;
 
     /**
      * An estimation of the Pearson correlation coefficient for each target dimension.
-     * This is {@code null} if not yet specified.
+     * This is {@code null} if not yet computed.
      */
-    private double[] correlation;
+    private transient double[] correlation;
 
     /**
-     * Creates a new linear transform builder.
+     * Creates a new linear transform builder for randomly distributed positions.
+     *
+     * <div class="note"><b>Tip:</b>
+     * if the source coordinates are grid indices, then
+     * the {@link #LinearTransformBuilder(int...)} constructor will create a more efficient builder.
+     * </div>
      */
     public LinearTransformBuilder() {
+        gridSize = null;
+        gridLength = 0;
+    }
+
+    /**
+     * Creates a new linear transform builder for source positions distributed on a regular grid.
+     * This constructor notifies {@code LinearTransformBuilder} that ordinate values of all source positions will
+     * be integers in the [0 … {@code gridSize[0]}-1] range for the first dimension (typically column indices),
+     * in the [0 … {@code gridSize[1]}-1] range for the second dimension (typically row indices), <i>etc.</i>
+     * The dimension of all source positions is the length of the given {@code gridSize} array.
+     *
+     * <p>An empty array is equivalent to invoking the no-argument constructor,
+     * i.e. no restriction is put on the source coordinates.</p>
+     *
+     * @param  gridSize  the number of integer ordinate values in each grid dimension.
+     * @throws IllegalArgumentException if a grid size is not strictly positive, or if the product
+     *         of all values (∏{@code gridSize}) is greater than {@link Integer#MAX_VALUE}.
+     *
+     * @since 0.8
+     */
+    public LinearTransformBuilder(int... gridSize) {
+        ArgumentChecks.ensureNonNull("gridSize", gridSize);
+        if (gridSize.length == 0) {
+            this.gridSize = null;
+            this.gridLength = 0;
+        } else {
+            gridSize = gridSize.clone();
+            long length = 1;
+            for (int s : gridSize) {
+                ArgumentChecks.ensureStrictlyPositive("gridSize", s);
+                length = Math.multiplyExact(length, s);
+            }
+            if (length > Integer.MAX_VALUE) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.ValueOutOfRange_4,
+                        "∏gridSize", 1, Integer.MAX_VALUE, length));
+            }
+            this.gridSize = gridSize;
+            gridLength = (int) length;
+        }
+    }
+
+    /**
+     * Returns the grid size for the given dimension. It is caller's responsibility to ensure that
+     * this method is invoked only on instances created by {@link #LinearTransformBuilder(int...)}.
+     */
+    final int gridSize(final int srcDim) {
+        return gridSize[srcDim];
+    }
+
+    /**
+     * Allocates memory for a builder created for source positions distributed on a grid.
+     * All target values need to be initialized to NaN because we can not rely on {@link #numPoints}.
+     *
+     * <p>If this builder has been created for randomly distributed source points, then the allocation
+     * should rather be performed as below:</p>
+     *
+     * {@preformat java
+     *    sources = new double[srcDim][capacity];
+     *    targets = new double[tgtDim][capacity];
+     * }
+     */
+    private void allocate(final int tgtDim) {
+        targets = new double[tgtDim][gridLength];
+        for (final double[] r : targets) {
+            Arrays.fill(r, Double.NaN);
+        }
+    }
+
+    /**
+     * Resize all the given arrays to the given capacity. This method should be invoked only for
+     * {@code LinearTransformBuilder} instances created for randomly distributed source positions.
+     */
+    private static void resize(double[][] data, final int capacity) {
+        for (int i=0; i<data.length; i++) {
+            data[i] = ArraysExt.resize(data[i], capacity);
+        }
+    }
+
+    /**
+     * Returns the offset of the given source grid coordinate, or -1 if none. The algorithm implemented in this
+     * method is inefficient, but should rarely be used. This is only a fallback when {@link #flatIndex(int[])}
+     * can not be used.
+     */
+    private int search(final int[] source) {
+        assert gridSize == null;         // This method should not be invoked for points distributed on a grid.
+search: for (int j=0; j<numPoints; j++) {
+            for (int i=0; i<source.length; i++) {
+                if (source[i] != sources[i][j]) {
+                    continue search;                            // Search another position for the same source.
+                }
+            }
+            return j;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the offset where to store a target position for the given source position in the flattened array.
+     * This method should be invoked only when this {@code LinearTransformBuilder} has been created for a grid
+     * of known size. Caller must have verified the array length before to invoke this method.
+     *
+     * @throws IllegalArgumentException if an ordinate value is illegal.
+     */
+    private int flatIndex(final int[] source) {
+        assert sources == null;               // This method should not be invoked for randomly distributed points.
+        int offset = 0;
+        for (int i = gridSize.length; i != 0;) {
+            final int size = gridSize[--i];
+            final int index = source[i];
+            if (index < 0 || index >= size) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.ValueOutOfRange_4, "source", 0, size-1, index));
+            }
+            offset = offset * size + index;
+        }
+        return offset;
     }
 
     /**
-     * Extracts the ordinate values of the given points into separated arrays, one for each dimension.
+     * Returns the index where to store a target position for the given source position in the flattened array.
+     * This method should be invoked only when this {@code LinearTransformBuilder} has been created for a grid
+     * of known size. Callers must have verified the position dimension before to invoke this method.
      *
-     * @param  points     the points from which to extract the ordinate values.
-     * @param  dimension  the expected number of dimensions.
+     * @throws IllegalArgumentException if an ordinate value is illegal.
      */
-    private static double[][] toArrays(final DirectPosition[] points, final int dimension) {
-        final int length = points.length;
-        final double[][] ordinates = new double[dimension][length];
-        for (int j=0; j<length; j++) {
-            final DirectPosition p = points[j];
-            final int d = p.getDimension();
-            if (d != dimension) {
-                throw new MismatchedDimensionException(Errors.format(
-                        Errors.Keys.MismatchedDimension_3, "points[" + j + ']', dimension, d));
+    private int flatIndex(final DirectPosition source) {
+        assert sources == null;               // This method should not be invoked for randomly distributed points.
+        int offset = 0;
+        for (int i = gridSize.length; i != 0;) {
+            final int size = gridSize[--i];
+            final double ordinate = source.getOrdinate(i);
+            final int index = (int) ordinate;
+            if (index != ordinate) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.NotAnInteger_1, ordinate));
             }
-            for (int i=0; i<dimension; i++) {
-                ordinates[i][j] = p.getOrdinate(i);
+            if (index < 0 || index >= size) {
+                throw new IllegalArgumentException(Errors.format(Errors.Keys.ValueOutOfRange_4, "source", 0, size-1, index));
             }
+            offset = offset * size + index;
         }
-        return ordinates;
+        return offset;
+    }
+
+    /**
+     * Verifies that the given number of dimensions is equal to the expected value.
+     * No verification are done if the source point is the first point of randomly distributed points.
+     */
+    private void verifySourceDimension(final int actual) {
+        final int expected;
+        if (gridSize != null) {
+            expected = gridSize.length;
+        } else if (sources != null) {
+            expected = sources.length;
+        } else {
+            return;
+        }
+        if (actual != expected) {
+            throw new MismatchedDimensionException(Errors.format(Errors.Keys.MismatchedDimension_3, "source", expected, actual));
+        }
+    }
+
+    /**
+     * Builds the exception message for an unexpected position dimension. This method assumes
+     * that positions are stored in this builder as they are read from user-provided collection.
+     */
+    private String mismatchedDimension(final String name, final int expected, final int actual) {
+        return Errors.format(Errors.Keys.MismatchedDimension_3, name + '[' + numPoints + ']', expected, actual);
+    }
+
+    /**
+     * Returns the error message to be given to {@link IllegalStateException} when there is no data.
+     */
+    private static String noData() {
+        return Errors.format(Errors.Keys.MissingValueForProperty_1, "sourceToTarget");
     }
 
     /**
-     * Sets the source points. The number of points shall be the same than the number of target points.
+     * Returns the number of dimensions in source positions.
+     *
+     * @return the dimension of source points.
+     * @throws IllegalStateException if the number of source dimensions is not yet known.
      *
-     * <p><b>Limitation:</b> in current implementation, the source points must be one or two-dimensional.
-     * This restriction may be removed in a future SIS version.</p>
+     * @see LinearTransform#getSourceDimensions()
+     *
+     * @since 0.8
+     */
+    public int getSourceDimensions() {
+        if (gridSize != null) return gridSize.length;
+        if (sources  != null) return sources.length;
+        throw new IllegalStateException(noData());
+    }
+
+    /**
+     * Returns the number of dimensions in target positions.
+     *
+     * @return the dimension of target points.
+     * @throws IllegalStateException if the number of target dimensions is not yet known.
+     *
+     * @see LinearTransform#getTargetDimensions()
+     *
+     * @since 0.8
+     */
+    public int getTargetDimensions() {
+        if (targets != null) return targets.length;
+        throw new IllegalStateException(noData());
+    }
+
+    /**
+     * Returns the direct position of the given position, or {@code null} if none.
+     */
+    private static DirectPosition position(final Position p) {
+        return (p != null) ? p.getDirectPosition() : null;
+    }
+
+    /**
+     * Sets all matching control point pairs, overwriting any previous setting. The source positions are the keys in
+     * the given map, and the target positions are the associated values in the map. The map should not contain two
+     * entries with the same source position. Coordinate reference systems are ignored.
+     * Null positions are silently ignored.
+     *
+     * <p>All source positions shall have the same number of dimensions (the <cite>source dimension</cite>),
+     * and all target positions shall have the same number of dimensions (the <cite>target dimension</cite>).
+     * However the source dimension does not need to be the same the target dimension.
+     * Apache SIS currently supports only one- or two-dimensional source positions,
+     * together with arbitrary target dimension.</p>
+     *
+     * <p>If this builder has been created with the {@link #LinearTransformBuilder(int...)} constructor,
+     * then the ordinate values of all source positions shall be integers in the [0 … {@code gridSize[0]}-1]
+     * range for the first dimension (typically column indices), in the [0 … {@code gridSize[1]}-1] range for
+     * the second dimension (typically row indices), <i>etc</i>. This constraint does not apply for builders
+     * created with the {@link #LinearTransformBuilder()} constructor.</p>
+     *
+     * @param  sourceToTarget  a map of source positions to target positions.
+     *         Source positions are assumed precise and target positions are assumed uncertain.
+     * @throws IllegalArgumentException if this builder has been {@linkplain #LinearTransformBuilder(int...)
+     *         created for a grid} but some source ordinates are not indices in that grid.
+     * @throws MismatchedDimensionException if some positions do not have the expected number of dimensions.
+     *
+     * @since 0.8
+     */
+    public void setControlPoints(final Map<? extends Position, ? extends Position> sourceToTarget)
+            throws MismatchedDimensionException
+    {
+        ArgumentChecks.ensureNonNull("sourceToTarget", sourceToTarget);
+        pendingSources = null;
+        pendingTargets = null;
+        transform   = null;
+        correlation = null;
+        sources     = null;
+        targets     = null;
+        numPoints   = 0;
+        int srcDim  = 0;
+        int tgtDim  = 0;
+        for (final Map.Entry<? extends Position, ? extends Position> entry : sourceToTarget.entrySet()) {
+            final DirectPosition src = position(entry.getKey());   if (src == null) continue;
+            final DirectPosition tgt = position(entry.getValue()); if (tgt == null) continue;
+            /*
+             * The first time that we get a non-null source and target coordinate, allocate the arrays.
+             * The sources arrays are allocated only if the source coordiantes are randomly distributed.
+             */
+            if (targets == null) {
+                tgtDim = tgt.getDimension();
+                if (tgtDim <= 0) {
+                    throw new MismatchedDimensionException(mismatchedDimension("target", 2, tgtDim));
+                }
+                if (gridSize == null) {
+                    srcDim = src.getDimension();
+                    if (srcDim <= 0) {
+                        throw new MismatchedDimensionException(mismatchedDimension("source", 2, srcDim));
+                    }
+                    final int capacity = sourceToTarget.size();
+                    sources = new double[srcDim][capacity];
+                    targets = new double[tgtDim][capacity];
+                } else {
+                    srcDim = gridSize.length;
+                    allocate(tgtDim);
+                }
+            }
+            /*
+             * Verify that the source and target coordinates have the expected number of dimensions before to store
+             * the coordinates. If the grid size is known, we do not need to store the source coordinates. Instead,
+             * we compute its index in the fixed-size target arrays.
+             */
+            int d;
+            if ((d = src.getDimension()) != srcDim) throw new MismatchedDimensionException(mismatchedDimension("source", srcDim, d));
+            if ((d = tgt.getDimension()) != tgtDim) throw new MismatchedDimensionException(mismatchedDimension("target", tgtDim, d));
+            int index;
+            if (gridSize != null) {
+                index = flatIndex(src);
+            } else {
+                index = numPoints;
+                for (int i=0; i<srcDim; i++) {
+                    sources[i][index] = src.getOrdinate(i);
+                }
+            }
+            for (int i=0; i<tgtDim; i++) {
+                targets[i][index] = tgt.getOrdinate(i);
+            }
+            numPoints++;
+        }
+    }
+
+    /**
+     * Sets a single matching control point pair. Source position is assumed precise and target position is assumed uncertain.
+     * If the given source position was already associated with another target position, then the old target position is discarded.
+     *
+     * <div class="note"><b>Performance note:</b>
+     * current implementation is efficient for builders {@linkplain #LinearTransformBuilder(int...) created for a grid}
+     * but inefficient for builders {@linkplain #LinearTransformBuilder() created for randomly distributed points}.
+     * In the later case, the {@link #setControlPoints(Map)} method is a more efficient alternative.</div>
+     *
+     * @param  source  the source coordinates. If this builder has been created with the {@link #LinearTransformBuilder(int...)} constructor,
+     *                 then for every index <var>i</var> the {@code source[i]} value shall be in the [0 … {@code gridSize[i]}-1] range inclusive.
+     *                 If this builder has been created with the {@link #LinearTransformBuilder()} constructor, then no constraint apply.
+     * @param  target  the target coordinates, assumed uncertain.
+     * @throws IllegalArgumentException if this builder has been {@linkplain #LinearTransformBuilder(int...) created for a grid}
+     *         but some source ordinates are out of index range.
+     * @throws MismatchedDimensionException if the source or target position does not have the expected number of dimensions.
+     *
+     * @since 0.8
+     */
+    public void setControlPoint(final int[] source, final double[] target) {
+        ArgumentChecks.ensureNonNull("source", source);
+        ArgumentChecks.ensureNonNull("target", target);
+        verifySourceDimension(source.length);
+        final int tgtDim = target.length;
+        if (targets != null && tgtDim != targets.length) {
+            throw new MismatchedDimensionException(Errors.format(
+                    Errors.Keys.MismatchedDimension_3, "target", targets.length, tgtDim));
+        }
+        int index;
+        if (gridSize != null) {
+            index = flatIndex(source);        // Invoked first for validating argument before to allocate arrays.
+            if (targets == null) {
+                allocate(tgtDim);
+            }
+        } else {
+            /*
+             * Case of randomly distributed points. Algorithm used below is inefficient, but Javadoc
+             * warns the user that (s)he should use setControlPoints(Map) instead in such case.
+             */
+            final int srcDim = source.length;
+            if (targets == null) {
+                targets = new double[tgtDim][20];                   // Arbitrary initial capacity of 20 points.
+                sources = new double[srcDim][20];
+            }
+            index = search(source);
+            if (index < 0) {
+                index = numPoints++;
+                if (numPoints >= targets[0].length) {
+                    final int n = Math.multiplyExact(numPoints, 2);
+                    resize(sources, n);
+                    resize(targets, n);
+                }
+            }
+            for (int i=0; i<srcDim; i++) {
+                sources[i][index] = source[i];
+            }
+        }
+        for (int i=0; i<tgtDim; i++) {
+            targets[i][index] = target[i];
+        }
+    }
+
+    /**
+     * Returns a single target coordinate for the given source coordinate, or {@code null} if none.
+     * This method can be used for retrieving points set by previous calls to
+     * {@link #setControlPoint(int[], double[])} or {@link #setControlPoints(Map)}.
+     *
+     * <div class="note"><b>Performance note:</b>
+     * current implementation is efficient for builders {@linkplain #LinearTransformBuilder(int...) created for a grid}
+     * but inefficient for builders {@linkplain #LinearTransformBuilder() created for randomly distributed points}.</div>
+     *
+     * @param  source  the source coordinates. If this builder has been created with the {@link #LinearTransformBuilder(int...)} constructor,
+     *                 then for every index <var>i</var> the {@code source[i]} value shall be in the [0 … {@code gridSize[i]}-1] range inclusive.
+     *                 If this builder has been created with the {@link #LinearTransformBuilder()} constructor, then no constraint apply.
+     * @return the target coordinates associated to the given source, or {@code null} if none.
+     * @throws IllegalArgumentException if this builder has been {@linkplain #LinearTransformBuilder(int...) created for a grid}
+     *         but some source ordinates are out of index range.
+     * @throws MismatchedDimensionException if the source position does not have the expected number of dimensions.
+     *
+     * @since 0.8
+     */
+    public double[] getControlPoint(final int[] source) {
+        processPendings();
+        ArgumentChecks.ensureNonNull("source", source);
+        verifySourceDimension(source.length);
+        if (targets == null) {
+            return null;
+        }
+        final int index;
+        if (gridSize != null) {
+            index = flatIndex(source);
+        } else {
+            index = search(source);
+            if (index < 0) {
+                return null;
+            }
+        }
+        boolean isNaN = true;
+        final double[] target = new double[targets.length];
+        for (int i=0; i<target.length; i++) {
+            isNaN &= Double.isNaN(target[i] = targets[i][index]);
+        }
+        return isNaN ? null : target;
+    }
+
+    /**
+     * More straightforward version of {@link #getControlPoint(int[])} for the case where this
+     * {@code LinearTransformBuilder} is known to have been built for grid source coordinates.
+     * This method is for {@link LocalizationGridBuilder#create()} internal usage.
+     */
+    final void getControlPoint2D(final int[] source, final double[] target) {
+        assert gridSize != null;
+        final int index = flatIndex(source);
+        final int tgtDim = targets.length;
+        for (int i=0; i<tgtDim; i++) {
+            target[i] = targets[i][index];
+        }
+    }
+
+    /**
+     * Sets the source points, overwriting any previous setting. The number of source points will need to be the same
+     * than the number of {@linkplain #setTargetPoints target points} when the {@link #create()} method will be invoked.
+     * In current Apache SIS implementation, the source points must be one or two-dimensional.
+     *
+     * <p>If this builder has been created with the {@link #LinearTransformBuilder(int, int)} constructor,
+     * then all given points must be two-dimensional and all ordinate values must be integers in the
+     * [0 … <var>width</var>-1] or [0 … <var>height</var>-1] range for the first and second dimension
+     * respectively. This constraint does not apply if this builder has been created with the
+     * {@link #LinearTransformBuilder()} constructor.</p>
+     *
+     * <p>It is caller's responsibility to ensure that no source point is duplicated.
+     * If the same source point is repeated twice, then {@code LinearTransformBuilder} behavior is undefined.</p>
      *
      * @param  points  the source points, assumed precise.
      * @throws MismatchedDimensionException if at least one point does not have the expected number of dimensions.
+     *
+     * @deprecated Replaced by {@link #setControlPoints(Map)}.
      */
+    @Deprecated
     public void setSourcePoints(final DirectPosition... points) throws MismatchedDimensionException {
         ArgumentChecks.ensureNonNull("points", points);
-        if (points.length != 0) {
-            sources = toArrays(points, points[0].getDimension() == 1 ? 1 : 2);
-        } else {
-            sources = null;
-        }
         transform   = null;
         correlation = null;
+        sources     = null;
+        targets     = null;
+        numPoints   = 0;
+        pendingSources = points.clone();
     }
 
     /**
-     * Sets the target points. The number of points shall be the same than the number of source points.
+     * Sets the target points, overwriting any previous setting. The number of target points will need to be the same
+     * than the number of {@linkplain #setSourcePoints source points} when the {@link #create()} method will be invoked.
      * Target points can have any number of dimensions (not necessarily 2), but all points shall have
      * the same number of dimensions.
      *
      * @param  points  the target points, assumed uncertain.
      * @throws MismatchedDimensionException if not all points have the same number of dimensions.
+     *
+     * @deprecated Replaced by {@link #setControlPoints(Map)}.
      */
+    @Deprecated
     public void setTargetPoints(final DirectPosition... points) throws MismatchedDimensionException {
         ArgumentChecks.ensureNonNull("points", points);
-        if (points.length != 0) {
-            targets = toArrays(points, points[0].getDimension());
-        } else {
-            targets = null;
-        }
         transform   = null;
         correlation = null;
+        sources     = null;
+        targets     = null;
+        numPoints   = 0;
+        pendingTargets = points.clone();
     }
 
-    /*
-     * No getters yet because we did not determined what they should return.
-     * Array? Collection? Map<source,target>?
-     */
+    @Deprecated
+    private transient DirectPosition[] pendingSources, pendingTargets;
+
+    @Deprecated
+    private void processPendings() {
+        if (pendingSources != null || pendingTargets != null) {
+            if (pendingSources == null || pendingTargets == null) {
+                throw new IllegalStateException(Errors.format(
+                        Errors.Keys.MissingValueForProperty_1, (pendingSources == null) ? "sources" : "targets"));
+            }
+            final int length = pendingSources.length;
+            if (pendingTargets.length != length) {
+                throw new IllegalStateException(Errors.format(Errors.Keys.MismatchedArrayLengths));
+            }
+            final Map<DirectPosition,DirectPosition> sourceToTarget = new java.util.HashMap<>(length);
+            for (int i=0; i<length; i++) {
+                sourceToTarget.put(pendingSources[i], pendingTargets[i]);
+            }
+            setControlPoints(sourceToTarget);
+        }
+    }
 
     /**
-     * Creates a linear transform approximation from the source points to the target points.
-     * This method assumes that source points are precise and all uncertainty is in the target points.
+     * Creates a linear transform approximation from the source positions to the target positions.
+     * This method assumes that source positions are precise and that all uncertainty is in the target positions.
      *
      * @return the fitted linear transform.
+     *
+     * @deprecated Replaced by {@link #create(MathTransformFactory)}.
      */
+    @Deprecated
     public LinearTransform create() {
+        try {
+            return create(null);
+        } catch (FactoryException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Creates a linear transform approximation from the source positions to the target positions.
+     * This method assumes that source positions are precise and that all uncertainty is in the target positions.
+     *
+     * @param  factory  the factory to use for creating the transform, or {@code null} for the default factory.
+     *                  The {@link MathTransformFactory#createAffineTransform(Matrix)} method of that factory
+     *                  shall return {@link LinearTransform} instances.
+     * @return the fitted linear transform.
+     * @throws FactoryException if the transform can not be created,
+     *         for example because the source or target points have not be specified.
+     *
+     * @since 0.8
+     */
+    @Override
+    @SuppressWarnings("serial")
+    public LinearTransform create(final MathTransformFactory factory) throws FactoryException {
         if (transform == null) {
+            processPendings();
             final double[][] sources = this.sources;                    // Protect from changes.
             final double[][] targets = this.targets;
-            if (sources == null || targets == null) {
-                throw new IllegalStateException(Errors.format(
-                        Errors.Keys.MissingValueForProperty_1, (sources == null) ? "sources" : "targets"));
+            if (targets == null) {
+                throw new FactoryException(noData());
             }
-            final int sourceDim = sources.length;
+            final int sourceDim = (sources != null) ? sources.length : gridSize.length;
             final int targetDim = targets.length;
             correlation = new double[targetDim];
-            final MatrixSIS matrix = Matrices.createZero(targetDim + 1, sourceDim + 1);
+            final MatrixSIS matrix = Matrices.create(targetDim + 1, sourceDim + 1,  ExtendedPrecisionMatrix.ZERO);
             matrix.setElement(targetDim, sourceDim, 1);
-            switch (sourceDim) {
-                case 1: {
-                    final Line line = new Line();
-                    for (int j=0; j < targets.length; j++) {
-                        correlation[j] = line.fit(sources[0], targets[j]);
-                        matrix.setElement(j, 0, line.slope());
-                        matrix.setElement(j, 1, line.y0());
+            for (int j=0; j < targetDim; j++) {
+                final double c;
+                switch (sourceDim) {
+                    case 1: {
+                        final int row = j;
+                        final Line line = new Line() {
+                            @Override public void setEquation(final Number slope, final Number y0) {
+                                super.setEquation(slope, y0);
+                                matrix.setNumber(row, 0, slope);    // Preserve the extended precision (double-double).
+                                matrix.setNumber(row, 1, y0);
+                            }
+                        };
+                        if (sources != null) {
+                            c = line.fit(vector(sources[0]), vector(targets[j]));
+                        } else {
+                            c = line.fit(Vector.createSequence(0, 1, gridSize[0]),
+                                         Vector.create(targets[j], false));
+                        }
+                        break;
                     }
-                    break;
-                }
-                case 2: {
-                    final Plane plan = new Plane();
-                    for (int j=0; j < targets.length; j++) {
-                        correlation[j] = plan.fit(sources[0], sources[1], targets[j]);
-                        matrix.setElement(j, 0, plan.slopeX());
-                        matrix.setElement(j, 1, plan.slopeY());
-                        matrix.setElement(j, 2, plan.z0());
+                    case 2: {
+                        final int row = j;
+                        final Plane plan = new Plane() {
+                            @Override public void setEquation(final Number sx, final Number sy, final Number z0) {
+                                super.setEquation(sx, sy, z0);
+                                matrix.setNumber(row, 0, sx);       // Preserve the extended precision (double-double).
+                                matrix.setNumber(row, 1, sy);
+                                matrix.setNumber(row, 2, z0);
+                            }
+                        };
+                        if (sources != null) {
+                            c = plan.fit(vector(sources[0]), vector(sources[1]), vector(targets[j]));
+                        } else try {
+                            c = plan.fit(gridSize[0], gridSize[1], Vector.create(targets[j], false));
+                        } catch (IllegalArgumentException e) {
+                            // This may happen if the z vector still contain some "NaN" values.
+                            throw new FactoryException(noData(), e);
+                        }
+                        break;
+                    }
+                    default: {
+                        throw new FactoryException(Errors.format(Errors.Keys.ExcessiveNumberOfDimensions_1, sourceDim));
                     }
-                    break;
                 }
-                default: throw new AssertionError(sourceDim);   // Should have been verified by setSourcePoints(…) method.
+                correlation[j] = c;
             }
-            transform = MathTransforms.linear(matrix);
+            transform = (LinearTransform) nonNull(factory).createAffineTransform(matrix);
         }
         return transform;
     }
 
     /**
+     * Wraps the given array in a vector of length {@link #numPoints}. This method should be
+     * invoked only when this builder has been created by {@link #LinearTransformBuilder()}.
+     * This can be identified by {@code sources != null} or {@code gridSize == null}.
+     */
+    private Vector vector(final double[] data) {
+        assert gridSize == null;
+        return Vector.create(data, false).subList(0, numPoints);
+    }
+
+    /**
      * Returns the correlation coefficients of the last transform created by {@link #create()},
      * or {@code null} if none. If non-null, the array length is equals to the number of target
      * dimensions.
@@ -227,13 +758,9 @@ public class LinearTransformBuilder {
             buffer.append(':').append(lineSeparator);
             final TableAppender table = new TableAppender(buffer, " ");
             table.setMultiLinesCells(true);
-            table.append(Matrices.toString(transform.getMatrix()));
-            table.nextColumn();
-            table.append(lineSeparator);
-            table.append("  ");
-            table.append(Vocabulary.format(Vocabulary.Keys.Correlation));
-            table.append(" =");
-            table.nextColumn();
+            table.append(Matrices.toString(transform.getMatrix())).nextColumn();
+            table.append(lineSeparator).append("  ")
+                 .append(Vocabulary.format(Vocabulary.Keys.Correlation)).append(" =").nextColumn();
             table.append(Matrices.create(correlation.length, 1, correlation).toString());
             try {
                 table.flush();

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -31,7 +31,7 @@
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.5
- * @since   0.5
+ * @since   0.8
  * @module
  */
 package org.apache.sis.referencing.operation.builder;

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -68,7 +68,7 @@ import org.apache.sis.internal.referenci
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.7
+ * @version 0.8
  * @module
  *
  * @see org.apache.sis.parameter.TensorParameters
@@ -203,8 +203,12 @@ public final class Matrices extends Stat
      */
     public static MatrixSIS create(final int numRow, final int numCol, final Number[] elements) {
         ArgumentChecks.ensureNonNull("elements", elements);
-        if (elements == ExtendedPrecisionMatrix.IDENTITY) { // Intentionally undocumented features.
-            return GeneralMatrix.createExtendedPrecision(numRow, numCol, true);
+        /*
+         * Below is an intantionally undocumented feature. We use those sentinel values as a way to create
+         * matrices with extended precision without exposing our double-double arithmetic in public API.
+         */
+        if (elements == ExtendedPrecisionMatrix.IDENTITY || elements == ExtendedPrecisionMatrix.ZERO) {
+            return GeneralMatrix.createExtendedPrecision(numRow, numCol, elements == ExtendedPrecisionMatrix.IDENTITY);
         }
         final GeneralMatrix matrix = GeneralMatrix.createExtendedPrecision(numRow, numCol, false);
         if (matrix.setElements(elements)) {

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -56,7 +56,7 @@ import org.apache.sis.util.resources.Err
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.7
+ * @version 0.8
  * @module
  *
  * @see Matrices
@@ -556,6 +556,46 @@ public abstract class MatrixSIS implemen
     }
 
     /**
+     * Returns a new vector which is the result of multiplying this matrix with the specified vector.
+     * In other words, returns {@code this} × {@code vector}. The length of the given vector must be
+     * equal to the number of columns in this matrix, and the length of the returned vector will be
+     * equal to the number of rows in this matrix.
+     *
+     * <div class="section">Relationship with coordinate operations</div>
+     * In the context of coordinate operations, {@code Matrix.multiply(vector)} is related to
+     * <code>{@linkplain AffineTransform#transform(double[], int, double[], int, int) AffineTransform.transform}(…)</code>
+     * except that the last {@code vector} number is implicitly 1 in {@code AffineTransform} operations.
+     * While this {@code multiply(double[])} method could be used for coordinate transformation, it is not its purpose.
+     * This method is designed for occasional uses when accuracy is more important than performance.
+     *
+     * @param  vector  the vector to multiply to this matrix.
+     * @return the result of {@code this} × {@code vector}.
+     * @throws MismatchedMatrixSizeException if the length of the given vector is not equals to the
+     *         number of columns in this matrix.
+     *
+     * @since 0.8
+     */
+    public double[] multiply(final double[] vector) {
+        final int numCol = getNumCol();
+        if (vector.length != numCol) {
+            throw new MismatchedMatrixSizeException(Errors.format(Errors.Keys.UnexpectedArrayLength_2,  numCol, vector.length));
+        }
+        final double[] target = new double[getNumRow()];
+        final DoubleDouble ele = new DoubleDouble();
+        final DoubleDouble sum = new DoubleDouble();
+        for (int j=0; j<target.length; j++) {
+            for (int i=0; i<numCol; i++) {
+                get(j, i, ele);
+                ele.multiply(vector[i]);
+                sum.add(ele);
+            }
+            target[j] = sum.value;
+            sum.clear();
+        }
+        return target;
+    }
+
+    /**
      * Returns the value of <var>U</var> which solves {@code this} × <var>U</var> = {@code matrix}.
      * This is equivalent to first computing the inverse of {@code this}, then multiplying the result
      * by the given matrix.

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/package-info.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -70,7 +70,7 @@
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 package org.apache.sis.referencing.operation.matrix;

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -720,8 +720,7 @@ public abstract class NormalizedProjecti
         /**
          * Default constructor.
          */
-        public Inverse() {
-            NormalizedProjection.this.super();
+        Inverse() {
         }
 
         /**

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -107,7 +107,6 @@ public class TransverseMercator extends
      * Work around for RFE #4093999 in Sun's bug database
      * ("Relax constraint on placement of this()/super() call in constructors").
      */
-    @SuppressWarnings("fallthrough")
     @Workaround(library="JDK", version="1.7")
     private static Initializer initializer(final OperationMethod method, final Parameters parameters) {
         final boolean isSouth = identMatch(method, "(?i).*\\bSouth\\b.*", TransverseMercatorSouth.IDENTIFIER);
@@ -126,11 +125,10 @@ public class TransverseMercator extends
     }
 
     /**
-     * Work around for RFE #4093999 in Sun's bug database
-     * ("Relax constraint on placement of this()/super() call in constructors").
+     * Creates a new Transverse Mercator projection from the given initializer.
+     * This constructor is used also by {@link ZonedGridSystem}.
      */
-    @Workaround(library="JDK", version="1.7")
-    private TransverseMercator(final Initializer initializer) {
+    TransverseMercator(final Initializer initializer) {
         super(initializer);
         final double φ0 = toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         /*
@@ -185,7 +183,7 @@ public class TransverseMercator extends
          *
          * Denormalization
          *   - Scale x and y by B.
-         *   - Subtract M0 to the northing.
+         *   - Subtract M₀ to the northing.
          *   - Multiply by the scale factor (done by the super-class constructor).
          *   - Add false easting and false northing (done by the super-class constructor).
          */

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -176,7 +176,6 @@ public abstract class AbstractMathTransf
          * Constructs an inverse math transform.
          */
         protected Inverse() {
-            AbstractMathTransform1D.this.super();
         }
 
         /**

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -339,7 +339,6 @@ public abstract class AbstractMathTransf
          * Constructs an inverse math transform.
          */
         protected Inverse() {
-            AbstractMathTransform2D.this.super();
         }
 
         /**



Mime
View raw message