Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercatorSouth.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercatorSouth.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercatorSouth.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercatorSouth.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -62,17 +62,17 @@ public final class TransverseMercatorSou .setRemarks(Messages.formatInternational(Messages.Keys.MisnamedParameter_1, "False southing"))); PARAMETERS = builder - .addIdentifier(IDENTIFIER) - .addName( "Transverse Mercator (South Orientated)") - .addName(Citations.OGC, "Transverse_Mercator_South_Orientated") - .addName(Citations.GEOTIFF, "CT_TransvMercator_SouthOriented") - .addIdentifier(Citations.GEOTIFF, "27") - .createGroupForMapProjection( - TransverseMercator.LATITUDE_OF_ORIGIN, - TransverseMercator.LONGITUDE_OF_ORIGIN, - TransverseMercator.SCALE_FACTOR, - LambertConformalWest.FALSE_WESTING, - falseSouthing); + .addIdentifier(IDENTIFIER) + .addName( "Transverse Mercator (South Orientated)") + .addName(Citations.OGC, "Transverse_Mercator_South_Orientated") + .addName(Citations.GEOTIFF, "CT_TransvMercator_SouthOriented") + .addIdentifier(Citations.GEOTIFF, "27") + .createGroupForMapProjection( + TransverseMercator.LATITUDE_OF_ORIGIN, + TransverseMercator.LONGITUDE_OF_ORIGIN, + TransverseMercator.SCALE_FACTOR, + LambertConformalWest.FALSE_WESTING, + falseSouthing); } /**
Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -148,7 +148,7 @@ public class DefaultParameterDescriptorG * </tr> * </table> * - * @param properties The properties to be given to the identified object. + * @param properties The properties to be given to the new parameter group. * @param minimumOccurs The {@linkplain #getMinimumOccurs() minimum number of times} that values * for this parameter group are required, or 0 if no restriction. * @param maximumOccurs The {@linkplain #getMaximumOccurs() maximum number of times} that values @@ -167,12 +167,39 @@ public class DefaultParameterDescriptorG } /** + * Constructs a group with the same parameters than another group. This is a convenience constructor for + * operations that expect the same parameters than another operation, but perform a different process. + * + * <div class="note"><b>Example:</b> + * the various <cite>"Coordinate Frame Rotation"</cite> variants (EPSG codes 1032, 1038 and 9607) + * expect the same parameters than their <cite>"Position Vector transformation"</cite> counterpart + * (EPSG codes 1033, 1037 and 9606) but perform the rotation in the opposite direction.</div> + * + * @param properties The properties to be given to the new parameter group. + * @param parameters The existing group from which to copy the {@linkplain #descriptors() parameter descriptors}. + * + * @since 0.7 + */ + public DefaultParameterDescriptorGroup(final Map<String,?> properties, final ParameterDescriptorGroup parameters) { + super(properties, parameters.getMinimumOccurs(), parameters.getMaximumOccurs()); + descriptors = parameters.descriptors(); // We will share the same instance if it is safe. + if (!(parameters instanceof DefaultParameterDescriptorGroup) + || ((DefaultParameterDescriptorGroup) parameters).descriptors != descriptors) + { + // Note sure where the list come from, we are better to copy its content. + final GeneralParameterDescriptor[] p = descriptors.toArray(new GeneralParameterDescriptor[descriptors.size()]); + verifyNames(properties, p); + descriptors = asList(p); + } + } + + /** * Creates a mandatory parameter group without cloning the given array. This constructor shall * be used only when we know that the given array is already a copy of the user-provided array. */ DefaultParameterDescriptorGroup(final Map<String,?> properties, final GeneralParameterDescriptor[] parameters) { super(properties, 1, 1); - verifyNames(properties, parameters.clone()); + verifyNames(properties, parameters); descriptors = asList(parameters); } Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -957,9 +957,14 @@ public class DefaultParameterValue<T> ex * is identical in both units (typically the 0 value). */ if (!ignoreUnits && !Double.isNaN(value)) { + // Test equivalent to unit.equals(contextualUnit) but more aggressive. ignoreUnits = Numerics.equals(value, doubleValue(contextualUnit)); } - if (!ignoreUnits || !convention.isSimplified() || !hasContextualUnit(formatter)) { + if (ignoreUnits && convention != Convention.INTERNAL) { + // One last check about if we are really allowed to ignore units. + ignoreUnits = convention.isSimplified() && hasContextualUnit(formatter); + } + if (!ignoreUnits) { if (!isWKT1) { formatter.append(unit); } else if (!ignoreUnits) { Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -38,7 +38,6 @@ import org.apache.sis.util.LenientCompar import org.apache.sis.util.ComparisonMode; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.ArgumentChecks; -import org.apache.sis.util.Debug; import static org.apache.sis.util.Utilities.deepEquals; import static org.apache.sis.referencing.IdentifiedObjects.isHeuristicMatchForName; @@ -473,31 +472,6 @@ public class DefaultParameterValueGroup return copy; } - /** - * Returns a string representation of this group. - * The default implementation delegates to {@link ParameterFormat}. - * - * <p>This method is for information purpose only and may change in future SIS version.</p> - */ - @Debug - @Override - public String toString() { - return ParameterFormat.sharedFormat(this); - } - - /** - * Prints a string representation of this group to the {@linkplain System#out standard output stream}. - * If a {@linkplain java.io.Console console} is attached to the running JVM (i.e. if the application - * is run from the command-line and the output is not redirected to a file) and if Apache SIS thinks - * that the console supports the ANSI escape codes (a.k.a. X3.64), then a syntax coloring will be applied. - * - * <p>This is a convenience method for debugging purpose and for console applications.</p> - */ - @Debug - public void print() { - ParameterFormat.print(this); - } - Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -368,6 +368,31 @@ public class ParameterBuilder extends Bu } /** + * Creates a descriptor group with the same parameters than another group. This is a convenience constructor + * for operations that expect the same parameters than another operation, but perform a different process. + * + * <div class="note"><b>Example:</b> + * the various <cite>"Coordinate Frame Rotation"</cite> variants (EPSG codes 1032, 1038 and 9607) + * expect the same parameters than their <cite>"Position Vector transformation"</cite> counterpart + * (EPSG codes 1033, 1037 and 9606) but perform the rotation in the opposite direction.</div> + * + * @param parameters The existing group from which to copy the parameters. + * @return The parameter descriptor group. + * + * @since 0.7 + */ + public ParameterDescriptorGroup createGroupWithSameParameters(final ParameterDescriptorGroup parameters) { + final ParameterDescriptorGroup group; + onCreate(false); + try { + group = new DefaultParameterDescriptorGroup(properties, parameters); + } finally { + onCreate(true); + } + return group; + } + + /** * Creates a descriptor group for a map projection. This method automatically adds mandatory parameters * for the <cite>semi-major</cite> and <cite>semi-minor axis length</cite>. Those parameters are usually * not explicitely included in parameter definitions since the axis lengths can be inferred from the Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -34,6 +34,7 @@ import org.apache.sis.referencing.Identi import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.ObjectConverters; import org.apache.sis.util.resources.Errors; +import org.apache.sis.util.Debug; import static org.apache.sis.referencing.IdentifiedObjects.isHeuristicMatchForName; @@ -111,7 +112,7 @@ import org.apache.sis.internal.jdk8.JDK8 * * @author Martin Desruisseaux (Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module */ @XmlTransient @@ -760,4 +761,33 @@ public abstract class Parameters impleme throw new IndexOutOfBoundsException(name); } } + + /** + * Returns a string representation of this group. + * The default implementation delegates to {@link ParameterFormat}. + * + * <p>This method is for information purpose only and may change in future SIS version.</p> + * + * @since 0.7 + */ + @Debug + @Override + public String toString() { + return ParameterFormat.sharedFormat(this); + } + + /** + * Prints a string representation of this group to the {@linkplain System#out standard output stream}. + * If a {@linkplain java.io.Console console} is attached to the running JVM (i.e. if the application + * is run from the command-line and the output is not redirected to a file) and if Apache SIS thinks + * that the console supports the ANSI escape codes (a.k.a. X3.64), then a syntax coloring will be applied. + * + * <p>This is a convenience method for debugging purpose and for console applications.</p> + * + * @since 0.7 + */ + @Debug + public void print() { + ParameterFormat.print(this); + } } Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -31,6 +31,7 @@ import org.opengis.metadata.Identifier; import org.opengis.referencing.datum.Ellipsoid; import org.apache.sis.geometry.DirectPosition2D; import org.apache.sis.internal.util.Numerics; +import org.apache.sis.internal.util.DoubleDouble; import org.apache.sis.internal.jaxb.gml.Measure; import org.apache.sis.internal.jaxb.referencing.SecondDefiningParameter; import org.apache.sis.internal.referencing.ReferencingUtilities; @@ -399,15 +400,76 @@ public class DefaultEllipsoid extends Ab } /** - * The ratio of the distance between the center and a focus of the ellipse - * to the length of its semi-major axis. The eccentricity can alternately be - * computed from the equation: <code>e = sqrt(2f - f²)</code>. + * The ratio of the distance between the center and a focus of the ellipse to the length of its semi-major axis. + * The eccentricity can alternately be computed from the equation: ℯ = √(2f - f²) where <var>f</var> is the + * flattening factor (not inverse). * - * @return The eccentricity of this ellipsoid. + * @return ℯ, the eccentricity of this ellipsoid. */ public double getEccentricity() { - final double f = 1 - getSemiMinorAxis() / getSemiMajorAxis(); - return sqrt(2*f - f*f); + final DoubleDouble e = eccentricitySquared(); + e.sqrt(); + return e.value; + } + + /** + * Returns the square of the {@link #getEccentricity() eccentricity} value. + * + * <div class="note"><b>Purpose:</b> + * this convenience method is provided because ℯ² is frequently used in coordinate operations, + * actually more often than ℯ. This convenience method avoids the cost of computing the square + * root when not needed.</div> + * + * @return ℯ², the square of the eccentricity value. + * + * @since 0.7 + */ + public double getEccentricitySquared() { + return eccentricitySquared().value; + } + + /** + * Computes the square of the eccentricity value with ℯ² = 2f - f². + * + * <div class="note"><b>Implementation note:</b> + * we use the flattening factor for this computation because the inverse flattening factor is usually the + * second defining parameter. But even if the second defining parameter of this ellipsoid was rather the + * semi-minor axis, the fact that we use double-double arithmetic should give the same result anyway.</div> + */ + private DoubleDouble eccentricitySquared() { + final DoubleDouble f = flattening(this); + final DoubleDouble eccentricitySquared = new DoubleDouble(f); + eccentricitySquared.multiply(2, 0); + f.square(); + eccentricitySquared.subtract(f); + return eccentricitySquared; + } + + /** + * Computes the flattening factor (not inverse) of the given ellipsoid. + * This method chooses the formula depending on whether the defining parameter is the inverse flattening factor + * or the semi-minor axis length. The defining parameters are presumed fully accurate in base 10 (even if this + * is of course not possible in the reality), because those parameters are definitions given by authorities. + * + * <div class="note"><b>Analogy:</b> + * the conversion factor from inches to centimetres is 2.54 <em>by definition</em>. Even if we could find a more + * accurate value matching historical measurements, the 2.54 value is the internationally agreed value for all + * conversions. This value is (by convention) defined in base 10 and has no exact {@code double} representation. + * </div> + */ + private static DoubleDouble flattening(final Ellipsoid e) { + final DoubleDouble f; + if (e.isIvfDefinitive()) { + f = new DoubleDouble(e.getInverseFlattening()); // Presumed accurate in base 10 (not 2) by definition. + f.inverseDivide(1, 0); + } else { + f = new DoubleDouble(e.getSemiMajorAxis()); // Presumed accurate in base 10 (not 2) by definition. + final double value = f.value; + final double error = f.error; + f.subtract(e.getSemiMinorAxis()); // Presumed accurate in base 10 (not 2) by definition. + f.divide(value, error); + } + return f; } /** @@ -553,6 +615,47 @@ public class DefaultEllipsoid extends Ab } /** + * Returns the difference between the semi-major axis length of two ellipsoids. + * If the two ellipsoid does not use the same unit of measurement, than the axis + * length of the other ellipsoid is converted into the units of this ellipsoid axis. + * + * <div class="note"><b>Example:</b> + * {@code WGS84.semiMajorAxisDifference(ED50)} returns 251 metres. This information is a parameter of + * {@linkplain org.apache.sis.referencing.operation.transform.MolodenskyTransform Molodensky transformations}.</div> + * + * @param other The other ellipsoid from which to get semi-major axis length difference. + * @return (<var>other</var> ellipsoid semi-major axis) - (<var>this</var> ellipsoid semi-major axis). + * + * @since 0.7 + */ + public double semiMajorAxisDifference(final Ellipsoid other) { + double semiMajor = other.getSemiMajorAxis(); + semiMajor = other.getAxisUnit().getConverterTo(getAxisUnit()).convert(semiMajor); // Often a no-op. + final DoubleDouble a = new DoubleDouble(semiMajor); // Presumed accurate in base 10 if no unit conversion. + a.subtract(getSemiMajorAxis()); // Presumed accurate in base 10 (not 2) by definition. + return a.value; + } + + /** + * Returns the difference between the flattening factor of two ellipsoids. + * This method returns 0 if the two ellipsoids are equal. + * + * <div class="note"><b>Example:</b> + * {@code WGS84.flatteningDifference(ED50)} returns approximatively 1.41927E-05. This information is a parameter of + * {@linkplain org.apache.sis.referencing.operation.transform.MolodenskyTransform Molodensky transformations}.</div> + * + * @param other The other ellipsoid from which to get flattening difference. + * @return (<var>other</var> ellipsoid flattening) - (<var>this</var> ellipsoid flattening). + * + * @since 0.7 + */ + public double flatteningDifference(final Ellipsoid other) { + final DoubleDouble f = flattening(other); + f.subtract(flattening(this)); + return f.value; + } + + /** * Compares this ellipsoid with the specified object for equality. * * @param object The object to compare to {@code this}. Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/Sphere.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/Sphere.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/Sphere.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/Sphere.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -20,6 +20,7 @@ import java.util.Map; import javax.measure.unit.Unit; import javax.measure.quantity.Length; import javax.xml.bind.annotation.XmlTransient; +import org.opengis.referencing.datum.Ellipsoid; import static java.lang.Math.*; @@ -35,7 +36,7 @@ import static java.lang.Math.*; * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module */ @XmlTransient @@ -82,6 +83,22 @@ final class Sphere extends DefaultEllips } /** + * Eccentricity of a sphere is always zero. + */ + @Override + public double getEccentricitySquared() { + return 0; + } + + /** + * Returns the flattening factor of the other ellipsoid, since the flattening factor of {@code this} is zero. + */ + @Override + public double flatteningDifference(final Ellipsoid other) { + return 1 / other.getInverseFlattening(); + } + + /** * Returns the orthodromic distance between two geographic coordinates. * The orthodromic distance is the shortest distance between two points * on a sphere's surface. The orthodromic path is always on a great circle. Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -377,8 +377,8 @@ public final class Matrices extends Stat * </ul> * * <div class="note"><b>Example:</b> - * It is legal to transform from (<i>easting</i>, <i>northing</i>, <i>up</i>) to - * (<i>easting</i>, <i>northing</i>) - this is the first above case, but illegal + * it is legal to transform from (<i>easting</i>, <i>northing</i>, <i>up</i>) to + * (<i>easting</i>, <i>northing</i>) — this is the first above case — but illegal * to transform (<i>easting</i>, <i>northing</i>) to (<i>easting</i>, <i>up</i>).</div> * * <div class="section">Example</div> @@ -487,7 +487,7 @@ public final class Matrices extends Stat /** * Creates a matrix for a transform that keep only a subset of source ordinate values. - * The matrix size will be ({@code selectedDimensions.length}+1) × ({@code sourceDimensions}+1). + * The matrix size will be ({@code selectedDimensions.length} + 1) × ({@code sourceDimensions} + 1). * The matrix will contain only zero elements, except for the following cells which will contain 1: * * <ul> @@ -541,7 +541,7 @@ public final class Matrices extends Stat } /** - * Creates a matrix which converts a subset of ordinates with another matrix. + * Creates a matrix which converts a subset of ordinates using the transform given by another matrix. * For example giving (<var>latitude</var>, <var>longitude</var>, <var>height</var>) coordinates, * a pass through operation can convert the height values from feet to metres without affecting * the (<var>latitude</var>, <var>longitude</var>) values. @@ -650,6 +650,75 @@ public final class Matrices extends Stat } /** + * Returns a new matrix with the same elements than the given matrix except for the specified rows. + * This method is useful for removing a range of <em>target</em> dimensions in an affine transform. + * + * @param matrix The matrix where to remove rows, or {@code null}. + * @param lower Index of the first row to remove (inclusive). + * @param upper Index after the last row to remove (exclusive). + * @return A copy of the given matrix with the specified rows removed, + * or {@code null} if the given matrix was null. + * + * @since 0.7 + */ + public static Matrix removeRows(final Matrix matrix, final int lower, final int upper) { + if (matrix == null) { + return null; + } + final int numRow = matrix.getNumRow(); + final int numCol = matrix.getNumCol(); + ArgumentChecks.ensureValidIndexRange(numRow, lower, upper); + final Matrix reduced = createZero(numRow - (upper - lower), numCol); + int dest = 0; + for (int j=0; j<numRow; j++) { + if (j == lower) { + j = upper; + if (j == numRow) break; + } + for (int i=0; i<numCol; i++) { + reduced.setElement(dest, i, matrix.getElement(j, i)); + } + dest++; + } + return reduced; + } + + /** + * Returns a new matrix with the same elements than the given matrix except for the specified columns. + * This method is useful for removing a range of <em>source</em> dimensions in an affine transform. + * Coordinates will be converted as if the values in the removed dimensions were zeros. + * + * @param matrix The matrix where to remove columns, or {@code null}. + * @param lower Index of the first column to remove (inclusive). + * @param upper Index after the last column to remove (exclusive). + * @return A copy of the given matrix with the specified columns removed, + * or {@code null} if the given matrix was null. + * + * @since 0.7 + */ + public static Matrix removeColumns(final Matrix matrix, final int lower, final int upper) { + if (matrix == null) { + return null; + } + final int numRow = matrix.getNumRow(); + final int numCol = matrix.getNumCol(); + ArgumentChecks.ensureValidIndexRange(numCol, lower, upper); + final Matrix reduced = createZero(numRow, numCol - (upper - lower)); + int dest = 0; + for (int i=0; i<numCol; i++) { + if (i == lower) { + i = upper; + if (i == numCol) break; + } + for (int j=0; j<numRow; j++) { + reduced.setElement(j, dest, matrix.getElement(j, i)); + } + dest++; + } + return reduced; + } + + /** * Creates a new matrix which is a copy of the given matrix. * * <div class="note"><b>Implementation note:</b> Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/UnmodifiableMatrix.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -126,6 +126,7 @@ final class UnmodifiableMatrix extends M * Returns a copy of this matrix that users can modify. */ @Override + @SuppressWarnings("CloneDoesntCallSuperClone") public MatrixSIS clone() { return castOrCopy(matrix.clone()); } Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -100,7 +100,7 @@ abstract class ConformalProjection exten static final boolean ALLOW_TRIGONOMETRIC_IDENTITIES = true; /** - * The threshold value of {@link #excentricity} at which we consider the accuracy of the + * The threshold value of {@link #eccentricity} at which we consider the accuracy of the * series expansion insufficient. This threshold is determined empirically with the help * of the {@code MercatorMethodComparison} class in the test directory. * We choose the value where: @@ -110,20 +110,22 @@ abstract class ConformalProjection exten * <li>the maximal error of series expansion become greater than {@link NormalizedProjection#ANGULAR_TOLERANCE}.</li> * </ul> */ - static final double EXCENTRICITY_THRESHOLD = 0.16; + static final double ECCENTRICITY_THRESHOLD = 0.16; /** - * {@code true} if the {@link #excentricity} value is greater than or equals to {@link #EXCENTRICITY_THRESHOLD}, + * {@code true} if the {@link #eccentricity} value is greater than or equals to {@link #ECCENTRICITY_THRESHOLD}, * in which case the {@link #φ(double)} method will need to use an iterative method. * * <p><strong>Consider this field as final!</strong> - * It is not final only for the purpose of {@link #readObject(ObjectInputStream)}.</p> + * It is not final only for the purpose of {@link #readObject(ObjectInputStream)}. + * This field is not serialized because its value may depend on the version of this + * {@code ConformalProjection} class.</p> */ private transient boolean useIterations; /** * Coefficients in the series expansion of the inverse projection, - * depending only on {@linkplain #excentricity excentricity} value. + * depending only on {@linkplain #eccentricity eccentricity} value. * The series expansion is of the following form, where f(θ) is typically sin(θ): * * <blockquote>ci₂⋅f(2θ) + ci₄⋅f(4θ) + ci₆⋅f(6θ) + ci₈⋅f(8θ)</blockquote> @@ -152,18 +154,18 @@ abstract class ConformalProjection exten } /** - * Computes the coefficients in the series expansions from the {@link #excentricitySquared} value. + * Computes the coefficients in the series expansions from the {@link #eccentricitySquared} value. * This method shall be invoked after {@code ConformalProjection} construction or deserialization. */ void computeCoefficients() { - useIterations = (excentricity >= EXCENTRICITY_THRESHOLD); - final double e2 = excentricitySquared; + useIterations = (eccentricity >= ECCENTRICITY_THRESHOLD); + final double e2 = eccentricitySquared; final double e4 = e2 * e2; final double e6 = e2 * e4; final double e8 = e4 * e4; /* * For each line below, add the smallest values first in order to reduce rounding errors. - * The smallest values are the one using the excentricity raised to the highest power. + * The smallest values are the one using the eccentricity raised to the highest power. */ ci2 = 13/ 360.* e8 + 1/ 12.* e6 + 5/24.* e4 + e2/2; ci4 = 811/ 11520.* e8 + 29/240.* e6 + 7/48.* e4; @@ -222,7 +224,7 @@ abstract class ConformalProjection exten * * <b>Note:</b> §1.3.3 in Geomatics Guidance Note number 7 part 2 (April 2015) uses a series expansion * while USGS used an iterative method. The series expansion is twice faster than the iterative method - * for the same precision, but this precision is achieved "only" for relatively small excentricity like + * for the same precision, but this precision is achieved "only" for relatively small eccentricity like * the Earth's one. See the {@code MercatorMethodComparison} class in the test package for more discussion. * * @param expOfSouthing The <em>reciprocal</em> of the value returned by {@link #expOfNorthing}. @@ -235,7 +237,7 @@ abstract class ConformalProjection exten final double φ(final double expOfSouthing) throws ProjectionException { /* * Get a first approximation of φ from Snyder (7-11). The result below would be exact if the - * ellipsoid was actually a sphere. But if the excentricity is different than 0, then we will + * ellipsoid was actually a sphere. But if the eccentricity is different than 0, then we will * need to add a correction. * * Note that the φ value computed by the line below is called χ in EPSG guide. @@ -273,23 +275,20 @@ abstract class ConformalProjection exten } /* * We should never reach this point for map projections on Earth. But if the ellipsoid is for some - * other planet having a high excentricity, then the above series expansion may not be sufficient. + * other planet having a high eccentricity, then the above series expansion may not be sufficient. * Try to improve by iteratively solving equation (7-9) from Snyder. However instead than using * Snyder (7-11) as the starting point, we take the result of above calculation as the initial φ. * Assuming that it is closer to the real φ value, this save us some iteration loops and usually * gives us more accurate results (according MercatorMethodComparison tests). */ - final double hℯ = 0.5 * excentricity; - for (int i=0; i<MAXIMUM_ITERATIONS; i++) { - final double ℯsinφ = excentricity * sin(φ); - double ε = abs(φ - (φ = PI/2 - 2*atan(expOfSouthing * pow((1 - ℯsinφ)/(1 + ℯsinφ), hℯ)))); - if (ε <= ITERATION_TOLERANCE) { + final double hℯ = 0.5 * eccentricity; + for (int it=0; it<MAXIMUM_ITERATIONS; it++) { + final double ℯsinφ = eccentricity * sin(φ); + final double Δφ = φ - (φ = PI/2 - 2*atan(expOfSouthing * pow((1 - ℯsinφ)/(1 + ℯsinφ), hℯ))); + if (!(abs(Δφ) > ITERATION_TOLERANCE)) { // Use '!' for accepting NaN. return φ; } } - if (Double.isNaN(expOfSouthing)) { - return Double.NaN; - } throw new ProjectionException(Errors.Keys.NoConvergence); } @@ -345,7 +344,7 @@ abstract class ConformalProjection exten * </ul> * * @param φ The latitude in radians. - * @param ℯsinφ The sine of the φ argument multiplied by {@link #excentricity}. + * @param ℯsinφ The sine of the φ argument multiplied by {@link #eccentricity}. * @return {@code Math.exp} of the Mercator projection of the given latitude. * * @see #φ(double) @@ -359,7 +358,7 @@ abstract class ConformalProjection exten * favorises slightly the North hemisphere (but the differences are very small). In Apache SIS, * we handle that by changing the sign of some terms in the (de)normalisation matrices. */ - return tan(PI/4 + 0.5*φ) * pow((1 - ℯsinφ) / (1 + ℯsinφ), 0.5*excentricity); + return tan(PI/4 + 0.5*φ) * pow((1 - ℯsinφ) / (1 + ℯsinφ), 0.5*eccentricity); } /** @@ -377,7 +376,7 @@ abstract class ConformalProjection exten * @see #φ(double) */ final double dy_dφ(final double sinφ, final double cosφ) { - return (1 / cosφ) - excentricitySquared * cosφ / (1 - excentricitySquared * (sinφ*sinφ)); + return (1 / cosφ) - eccentricitySquared * cosφ / (1 - eccentricitySquared * (sinφ*sinφ)); } /** Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -42,7 +42,7 @@ import static org.apache.sis.internal.ut * * <ul> * <li>To convert degrees to radians, than back to degrees and find the original value.</li> - * <li>To convert axis length (optionally with flattening factor) to excentricity, then back + * <li>To convert axis length (optionally with flattening factor) to eccentricity, then back * to axis length and find the original value.</li> * </ul> * @@ -75,8 +75,8 @@ final class Initializer { final Parameters parameters; /** - * The square of excentricity: ℯ² = (a²-b²)/a² where - * <var>ℯ</var> is the {@linkplain #excentricity excentricity}, + * The square of eccentricity: ℯ² = (a²-b²)/a² where + * <var>ℯ</var> is the {@linkplain #eccentricity eccentricity}, * <var>a</var> is the <cite>semi-major</cite> axis length and * <var>b</var> is the <cite>semi-minor</cite> axis length. * @@ -85,7 +85,7 @@ final class Initializer { * {@code double} parameter value without rounding errors. This wish usually do not apply to other internal * {@link NormalizedProjection} parameters.</p> */ - final DoubleDouble excentricitySquared; + final DoubleDouble eccentricitySquared; /** * Map projection variant. This is a convenience field left at @@ -130,7 +130,7 @@ final class Initializer { final double fn = getAndStore(roles.get(ParameterRole.FALSE_NORTHING)) - getAndStore(roles.get(ParameterRole.FALSE_SOUTHING)); - excentricitySquared = new DoubleDouble(); + eccentricitySquared = new DoubleDouble(); DoubleDouble k = new DoubleDouble(a); // The value by which to multiply all results of normalized projection. if (a != b) { /* @@ -161,16 +161,16 @@ final class Initializer { if (isIvfDefinitive) { final DoubleDouble f = new DoubleDouble(parameters.parameter(Constants.INVERSE_FLATTENING).doubleValue()); f.inverseDivide(1,0); - excentricitySquared.setFrom(f); - excentricitySquared.multiply(2,0); + eccentricitySquared.setFrom(f); + eccentricitySquared.multiply(2,0); f.square(); - excentricitySquared.subtract(f); + eccentricitySquared.subtract(f); } else { final DoubleDouble rs = new DoubleDouble(b); rs.divide(k); // rs = b/a rs.square(); - excentricitySquared.value = 1; - excentricitySquared.subtract(rs); + eccentricitySquared.value = 1; + eccentricitySquared.subtract(rs); } final ParameterDescriptor<? extends Number> radius = roles.get(ParameterRole.LATITUDE_OF_CONFORMAL_SPHERE_RADIUS); if (radius != null) { @@ -188,7 +188,7 @@ final class Initializer { * Equivalent Java code: * * final double sinφ = sin(toRadians(parameters.doubleValue(radius))); - * k = b / (1 - excentricitySquared * (sinφ*sinφ)); + * k = b / (1 - eccentricitySquared * (sinφ*sinφ)); */ k = rν2(sin(toRadians(parameters.doubleValue(radius)))); k.inverseDivide(b, 0); @@ -208,7 +208,7 @@ final class Initializer { * in the (de)normalization matrices. */ context.normalizeGeographicInputs(λ0); - final MatrixSIS denormalize = context.getMatrix(false); + final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION); denormalize.convertAfter(0, k, new DoubleDouble(fe)); denormalize.convertAfter(1, k, new DoubleDouble(fn)); } @@ -255,11 +255,11 @@ final class Initializer { /** * Returns {@code b/a} where {@code a} is the semi-major axis length and {@code b} the semi-minor axis length. - * We retrieve this value from the excentricity with {@code b/a = sqrt(1-ℯ²)}. + * We retrieve this value from the eccentricity with {@code b/a = sqrt(1-ℯ²)}. */ final DoubleDouble axisLengthRatio() { final DoubleDouble b = new DoubleDouble(1,0); - b.subtract(excentricitySquared); + b.subtract(eccentricitySquared); b.sqrt(); return b; } @@ -291,11 +291,11 @@ final class Initializer { */ private DoubleDouble rν2(final double sinφ) { if (DoubleDouble.DISABLED) { - return verbatim(1 - excentricitySquared.value * (sinφ*sinφ)); + return verbatim(1 - eccentricitySquared.value * (sinφ*sinφ)); } final DoubleDouble t = verbatim(sinφ); t.square(); - t.multiply(excentricitySquared); + t.multiply(eccentricitySquared); // Compute 1 - ℯ²⋅sin²φ. Since ℯ²⋅sin²φ may be small, // this is where double-double arithmetic has more value. @@ -320,7 +320,7 @@ final class Initializer { */ final double radiusOfConformalSphere(final double sinφ) { final DoubleDouble Rc = verbatim(1); - Rc.subtract(excentricitySquared); // 1 - ℯ² + Rc.subtract(eccentricitySquared); // 1 - ℯ² Rc.sqrt(); // √(1 - ℯ²) Rc.divide(rν2(sinφ)); // √(1 - ℯ²) / (1 - ℯ²sin²φ) return Rc.value; Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -27,6 +27,7 @@ import org.apache.sis.measure.Latitude; import org.apache.sis.parameter.Parameters; import org.apache.sis.referencing.operation.matrix.Matrix2; import org.apache.sis.referencing.operation.matrix.MatrixSIS; +import org.apache.sis.referencing.operation.transform.ContextualParameters; import org.apache.sis.internal.referencing.provider.LambertConformal1SP; import org.apache.sis.internal.referencing.provider.LambertConformal2SP; import org.apache.sis.internal.referencing.provider.LambertConformalWest; @@ -261,13 +262,13 @@ public class LambertConicConformal exten φ2 = toRadians(φ2); /* * Compute constants. We do not need to use special formulas for the spherical case below, - * since rν(sinφ) = 1 and expOfNorthing(φ) = tan(π/4 + φ/2) when the excentricity is zero. + * since rν(sinφ) = 1 and expOfNorthing(φ) = tan(π/4 + φ/2) when the eccentricity is zero. * However we need special formulas for φ1 ≈ φ2 in the calculation of n, otherwise we got * a 0/0 indetermination. */ final double sinφ1 = sin(φ1); final double m1 = initializer.scaleAtφ(sinφ1, cos(φ1)); - final double t1 = expOfNorthing(φ1, excentricity*sinφ1); + final double t1 = expOfNorthing(φ1, eccentricity*sinφ1); /* * Compute n = (ln m₁ – ln m₂) / (ln t₁ – ln t₂), which we rewrite as ln(m₁/m₂) / ln(t₁/t₂) * for reducing the amount of calls to the logarithmic function. Note that this equation @@ -276,7 +277,7 @@ public class LambertConicConformal exten if (abs(φ1 - φ2) >= ANGULAR_TOLERANCE) { // Should be 'true' for 2SP case. final double sinφ2 = sin(φ2); final double m2 = initializer.scaleAtφ(sinφ2, cos(φ2)); - final double t2 = expOfNorthing(φ2, excentricity*sinφ2); + final double t2 = expOfNorthing(φ2, eccentricity*sinφ2); n = log(m1/m2) / log(t1/t2); // Tend toward 0/0 if φ1 ≈ φ2. } else { n = -sinφ1; @@ -305,7 +306,7 @@ public class LambertConicConformal exten DoubleDouble rF = null; if (φ0 != copySign(PI/2, -n)) { // For reducing the rounding error documented in expOfNorthing(+π/2). rF = new DoubleDouble(F); - rF.multiply(pow(expOfNorthing(φ0, excentricity*sin(φ0)), n), 0); + rF.multiply(pow(expOfNorthing(φ0, eccentricity*sin(φ0)), n), 0); } /* * At this point, all parameters have been processed. Now store @@ -332,8 +333,8 @@ public class LambertConicConformal exten } else { sλ.negate(); } - final MatrixSIS normalize = context.getMatrix(true); - final MatrixSIS denormalize = context.getMatrix(false); + final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION); + final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION); normalize .convertAfter(0, sλ, (initializer.variant == BELGIUM) ? belgeA() : null); normalize .convertAfter(1, sφ, null); denormalize.convertBefore(0, F, null); F.negate(); @@ -381,7 +382,7 @@ public class LambertConicConformal exten @Override public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException { LambertConicConformal kernel = this; - if (excentricity == 0) { + if (eccentricity == 0) { kernel = new Spherical(this); } return context.completeTransform(factory, kernel); @@ -414,7 +415,7 @@ public class LambertConicConformal exten final double ρ; // EPSG guide uses "r", but we keep the symbol from Snyder p. 108 for consistency with PolarStereographic. if (absφ < PI/2) { sinφ = sin(φ); - ρ = pow(expOfNorthing(φ, excentricity*sinφ), n); + ρ = pow(expOfNorthing(φ, eccentricity*sinφ), n); } else if (absφ < PI/2 + ANGULAR_TOLERANCE) { sinφ = 1; ρ = (φ*n >= 0) ? POSITIVE_INFINITY : 0; Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -30,8 +30,9 @@ import org.apache.sis.internal.referenci import org.apache.sis.internal.referencing.provider.RegionalMercator; import org.apache.sis.internal.referencing.provider.PseudoMercator; import org.apache.sis.internal.util.DoubleDouble; -import org.apache.sis.referencing.operation.matrix.MatrixSIS; import org.apache.sis.referencing.operation.matrix.Matrix2; +import org.apache.sis.referencing.operation.matrix.MatrixSIS; +import org.apache.sis.referencing.operation.transform.ContextualParameters; import org.apache.sis.parameter.Parameters; import org.apache.sis.util.Workaround; @@ -242,8 +243,8 @@ public class Mercator extends ConformalP * simple as possible, we increase the chances of efficient concatenation of an inverse with a forward * projection. */ - final MatrixSIS normalize = context.getMatrix(true); - final MatrixSIS denormalize = context.getMatrix(false); + final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION); + final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION); denormalize.convertBefore(0, k0, null); denormalize.convertBefore(1, k0, null); if (λ0 != 0) { @@ -257,7 +258,7 @@ public class Mercator extends ConformalP denormalize.convertBefore(0, null, offset); } if (φ0 != 0) { - denormalize.convertBefore(1, null, verbatim(-log(expOfNorthing(φ0, excentricity * sin(φ0))))); + denormalize.convertBefore(1, null, verbatim(-log(expOfNorthing(φ0, eccentricity * sin(φ0))))); } if (variant == MILLER) { normalize .convertBefore(1, 0.80, null); @@ -316,7 +317,7 @@ public class Mercator extends ConformalP @Override public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException { Mercator kernel = this; - if ((variant & SPHERICAL) != 0 || excentricity == 0) { + if ((variant & SPHERICAL) != 0 || eccentricity == 0) { kernel = new Spherical(this); } return context.completeTransform(factory, kernel); @@ -352,7 +353,7 @@ public class Mercator extends ConformalP // about why we perform explicit checks for the pole cases. final double a = abs(φ); if (a < PI/2) { - y = log(expOfNorthing(φ, excentricity * sinφ)); // Snyder (7-7) + y = log(expOfNorthing(φ, eccentricity * sinφ)); // Snyder (7-7) } else { y = copySign(a <= (PI/2 + ANGULAR_TOLERANCE) ? POSITIVE_INFINITY : NaN, φ); } @@ -393,7 +394,7 @@ public class Mercator extends ConformalP final double a = abs(φ); final double y; if (a < PI/2) { - y = log(expOfNorthing(φ, excentricity * sin(φ))); + y = log(expOfNorthing(φ, eccentricity * sin(φ))); } else { y = copySign(a <= (PI/2 + ANGULAR_TOLERANCE) ? POSITIVE_INFINITY : NaN, φ); } Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -44,9 +44,9 @@ import org.apache.sis.referencing.operat import org.apache.sis.referencing.operation.transform.ContextualParameters; import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory; import org.apache.sis.referencing.operation.transform.MathTransformProvider; +import org.apache.sis.internal.referencing.provider.MapProjection; import org.apache.sis.internal.metadata.ReferencingServices; import org.apache.sis.internal.referencing.Formulas; -import org.apache.sis.internal.util.CollectionsExt; import org.apache.sis.internal.util.Constants; import org.apache.sis.internal.util.Utilities; import org.apache.sis.internal.util.Numerics; @@ -162,14 +162,14 @@ public abstract class NormalizedProjecti /** * Maximum number of iterations for iterative computations. * The iterative methods used in subclasses should converge quickly (in 3 or 4 iterations) - * when used for a planet with an excentricity similar to Earth. But we allow a high limit - * in case someone uses SIS for some planet with higher excentricity. + * when used for a planet with an eccentricity similar to Earth. But we allow a high limit + * in case someone uses SIS for some planet with higher eccentricity. */ - static final int MAXIMUM_ITERATIONS = 15; + static final int MAXIMUM_ITERATIONS = Formulas.MAXIMUM_ITERATIONS; /** * The internal parameter descriptors. Keys are implementation classes. Values are parameter descriptor groups - * containing at least a parameter for the {@link #excentricity} value, and optionally other internal parameter + * containing at least a parameter for the {@link #eccentricity} value, and optionally other internal parameter * added by some subclasses. * * <p>Entries are created only when first needed. Those descriptors are usually never created since they are @@ -188,27 +188,33 @@ public abstract class NormalizedProjecti final ContextualParameters context; /** - * Ellipsoid excentricity, equals to <code>sqrt({@linkplain #excentricitySquared})</code>. + * Ellipsoid eccentricity, equals to <code>sqrt({@linkplain #eccentricitySquared})</code>. * Value 0 means that the ellipsoid is spherical. */ - protected final double excentricity; + protected final double eccentricity; /** - * The square of excentricity: ℯ² = (a²-b²)/a² where - * <var>ℯ</var> is the {@linkplain #excentricity excentricity}, + * The square of eccentricity: ℯ² = (a²-b²)/a² where + * <var>ℯ</var> is the {@linkplain #eccentricity eccentricity}, * <var>a</var> is the <cite>semi-major</cite> axis length and * <var>b</var> is the <cite>semi-minor</cite> axis length. */ - protected final double excentricitySquared; + protected final double eccentricitySquared; /** * The inverse of this map projection. + * + * <div class="note"><b>Note:</b> + * creation of this object is not deferred to the first call to the {@link #inverse()} method because this + * object is lightweight and typically needed soon anyway (may be as soon as {@code ConcatenatedTransform} + * construction time). In addition this field is part of serialization form in order to preserve the + * references graph.</div> */ private final MathTransform2D inverse; /** * Maps the parameters to be used for initializing {@link NormalizedProjection} and its - * {@linkplain ContextualParameters#getMatrix(boolean) normalization / denormalization} matrices. + * {@linkplain ContextualParameters#getMatrix normalization / denormalization} matrices. * This is an enumeration of parameters found in almost every map projections, but under different names. * This enumeration allows {@code NormalizedProjection} subclasses to specify which parameter names, ranges * and default values should be used by the @@ -227,7 +233,7 @@ public abstract class NormalizedProjecti protected static enum ParameterRole { /** * Maps the <cite>semi-major axis length</cite> parameter (symbol: <var>a</var>). - * This value is used for computing {@link NormalizedProjection#excentricity}, + * This value is used for computing {@link NormalizedProjection#eccentricity}, * and is also a multiplication factor for the denormalization matrix. * * <p>Unless specified otherwise, this is always mapped to a parameter named {@code "semi_major"}. @@ -237,7 +243,7 @@ public abstract class NormalizedProjecti /** * Maps the <cite>semi-minor axis length</cite> parameter (symbol: <var>b</var>). - * This value is used for computing {@link NormalizedProjection#excentricity}. + * This value is used for computing {@link NormalizedProjection#eccentricity}. * * <p>Unless specified otherwise, this is always mapped to a parameter named {@code "semi_minor"}. * {@code NormalizedProjection} subclasses typically do not need to provide a value for this key.</p> @@ -414,8 +420,8 @@ public abstract class NormalizedProjecti */ NormalizedProjection(final Initializer initializer) { context = initializer.context; - excentricitySquared = initializer.excentricitySquared.value; - excentricity = sqrt(excentricitySquared); // DoubleDouble.sqrt() does not make any difference here. + eccentricitySquared = initializer.eccentricitySquared.value; + eccentricity = sqrt(eccentricitySquared); // DoubleDouble.sqrt() does not make any difference here. inverse = new Inverse(); } @@ -427,8 +433,8 @@ public abstract class NormalizedProjecti */ NormalizedProjection(final NormalizedProjection other) { context = other.context; - excentricity = other.excentricity; - excentricitySquared = other.excentricitySquared; + eccentricity = other.eccentricity; + eccentricitySquared = other.eccentricitySquared; inverse = new Inverse(); } @@ -540,10 +546,10 @@ public abstract class NormalizedProjecti /** * Returns a copy of non-linear internal parameter values of this {@code NormalizedProjection}. - * The returned group contained at least the {@link #excentricity} parameter value. + * The returned group contains at least the {@link #eccentricity} parameter value. * Some subclasses add more non-linear parameters, but most of them do not because many parameters * like the <cite>scale factor</cite> or the <cite>false easting/northing</cite> are handled by the - * {@linkplain ContextualParameters#getMatrix(boolean) (de)normalization affine transforms} instead. + * {@linkplain ContextualParameters#getMatrix (de)normalization affine transforms} instead. * * <div class="note"><b>Note:</b> * This method is mostly for {@linkplain org.apache.sis.io.wkt.Convention#INTERNAL debugging purposes} @@ -557,7 +563,7 @@ public abstract class NormalizedProjecti @Override public ParameterValueGroup getParameterValues() { final ParameterValueGroup group = getParameterDescriptors().createValue(); - group.parameter("excentricity").setValue(excentricity); + group.parameter("eccentricity").setValue(eccentricity); final String[] names = getInternalParameterNames(); final double[] values = getInternalParameterValues(); for (int i=0; i<names.length; i++) { @@ -568,7 +574,7 @@ public abstract class NormalizedProjecti /** * Returns a description of the non-linear internal parameters of this {@code NormalizedProjection}. - * The returned group contained at least a descriptor for the {@link #excentricity} parameter. + * The returned group contains at least a descriptor for the {@link #eccentricity} parameter. * Subclasses may add more parameters. * * <p>This method is for inspecting the parameter values of this non-linear kernel only, @@ -590,23 +596,13 @@ public abstract class NormalizedProjecti if (group == null) { final ParameterBuilder builder = new ParameterBuilder().setRequired(true); if (Utilities.isSIS(type)) { - builder.setCodeSpace(Citations.SIS, "SIS"); + builder.setCodeSpace(Citations.SIS, Constants.SIS); } final String[] names = getInternalParameterNames(); final ParameterDescriptor<?>[] parameters = new ParameterDescriptor<?>[names.length + 1]; - for (int i=0; i<parameters.length; i++) { - final ParameterDescriptor<?> p; - if (i == 0) { - final ParameterDescriptorGroup existing = CollectionsExt.first(DESCRIPTORS.values()); - if (existing != null) { - p = (ParameterDescriptor<?>) existing.descriptor("excentricity"); - } else { - p = builder.addName(Citations.SIS, "excentricity").createBounded(0, 1, Double.NaN, null); - } - } else { - p = builder.addName(names[i-1]).create(Double.class, null); - } - parameters[i] = p; + parameters[0] = MapProjection.ECCENTRICITY; + for (int i=1; i<parameters.length; i++) { + parameters[i] = builder.addName(names[i-1]).create(Double.class, null); } group = builder.addName(CharSequences.camelCaseToSentence(type.getSimpleName())).createGroup(1, 1, parameters); DESCRIPTORS.put(type, group); @@ -616,7 +612,7 @@ public abstract class NormalizedProjecti } /** - * Returns the names of any additional internal parameters (other than {@link #excentricity}) + * Returns the names of any additional internal parameters (other than {@link #eccentricity}) * that this projection has. The length of this array must be the same than the length of the * {@link #getInternalParameterValues()} array, if the later is non-null. */ @@ -625,7 +621,7 @@ public abstract class NormalizedProjecti } /** - * Returns the values of any additional internal parameters (other than {@link #excentricity}) that + * Returns the values of any additional internal parameters (other than {@link #eccentricity}) that * this projection has. Those values are also compared by {@link #equals(Object, ComparisonMode)}. */ double[] getInternalParameterValues() { @@ -761,7 +757,7 @@ public abstract class NormalizedProjecti */ @Override protected int computeHashCode() { - long c = Double.doubleToLongBits(excentricity); + long c = Double.doubleToLongBits(eccentricity); final double[] parameters = getInternalParameterValues(); if (parameters != null) { for (int i=0; i<parameters.length; i++) { @@ -773,7 +769,7 @@ public abstract class NormalizedProjecti /** * Compares the given object with this transform for equivalence. The default implementation checks if - * {@code object} is an instance of the same class than {@code this}, then compares the excentricity. + * {@code object} is an instance of the same class than {@code this}, then compares the eccentricity. * * <p>If this method returns {@code true}, then for any given identical source position, the two compared map * projections shall compute the same target position. Many of the {@linkplain #getContextualParameters() @@ -808,23 +804,23 @@ public abstract class NormalizedProjecti if (!Objects.equals(context, that.context)) { return false; } - // Fall through for comparing the excentricity. + // Fall through for comparing the eccentricity. } case IGNORE_METADATA: { /* - * There is no need to compare both 'excentricity' and 'excentricitySquared' since the former - * is computed from the later. We are better to compare 'excentricitySquared' since it is the + * There is no need to compare both 'eccentricity' and 'eccentricitySquared' since the former + * is computed from the later. We are better to compare 'eccentricitySquared' since it is the * original value from which the other value is derived. */ - if (!Numerics.equals(excentricitySquared, that.excentricitySquared)) { + if (!Numerics.equals(eccentricitySquared, that.eccentricitySquared)) { return false; } break; } default: { /* - * We want to compare the excentricity with a tolerance threshold corresponding approximatively - * to an error of 1 cm on Earth. The excentricity for an ellipsoid of semi-major axis a=1 is: + * We want to compare the eccentricity with a tolerance threshold corresponding approximatively + * to an error of 1 cm on Earth. The eccentricity for an ellipsoid of semi-major axis a=1 is: * * ℯ² = 1 - b² * @@ -842,12 +838,12 @@ public abstract class NormalizedProjecti * ε′ ≈ ε⋅(ℯ - 1/ℯ) * * Note that ε′ is negative for ℯ < 1 so we actually need to compute ε⋅(1/ℯ - ℯ) instead. - * The result is less than 2E-8 for the excentricity of the Earth. + * The result is less than 2E-8 for the eccentricity of the Earth. */ - final double e = max(excentricity, that.excentricity); - if (!Numerics.epsilonEqual(excentricity, that.excentricity, ANGULAR_TOLERANCE * (1/e - e))) { + final double e = max(eccentricity, that.eccentricity); + if (!Numerics.epsilonEqual(eccentricity, that.eccentricity, ANGULAR_TOLERANCE * (1/e - e))) { assert (mode != ComparisonMode.DEBUG) : Numerics.messageForDifference( - "excentricity", excentricity, that.excentricity); + "eccentricity", eccentricity, that.eccentricity); return false; } break; Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -26,6 +26,7 @@ import org.opengis.util.FactoryException import org.apache.sis.parameter.Parameters; import org.apache.sis.referencing.operation.matrix.Matrix2; import org.apache.sis.referencing.operation.matrix.MatrixSIS; +import org.apache.sis.referencing.operation.transform.ContextualParameters; import org.apache.sis.internal.referencing.provider.PolarStereographicA; import org.apache.sis.internal.referencing.Formulas; import org.apache.sis.util.resources.Errors; @@ -125,14 +126,14 @@ public class ObliqueStereographic extend super(initializer); final double φ0 = toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN)); final double sinφ0 = sin(φ0); - final double ℯsinφ0 = excentricity * sinφ0; - n = sqrt(1 + ((excentricitySquared * pow(cos(φ0), 4)) / (1 - excentricitySquared))); + final double ℯsinφ0 = eccentricity * sinφ0; + n = sqrt(1 + ((eccentricitySquared * pow(cos(φ0), 4)) / (1 - eccentricitySquared))); /* * Following variables use upper-case because they are written that way in the EPSG guide. */ final double S1 = (1 + sinφ0) / (1 - sinφ0); final double S2 = (1 - ℯsinφ0) / (1 + ℯsinφ0); - final double w1 = pow(S1 * pow(S2, excentricity), n); + final double w1 = pow(S1 * pow(S2, eccentricity), n); /* * The χ₁ variable below was named χ₀ in the EPSG guide. We use the χ₁ name in order to avoid confusion with * the conformal latitude of origin, which is also named χ₀ in the EPSG guide. Mathematically, χ₀ and χ₁ are @@ -158,8 +159,8 @@ public class ObliqueStereographic extend * Since this is a linear operation, we can combine it with other linear operations performed by the * normalization matrix. */ - final MatrixSIS normalize = context.getMatrix(true); - final MatrixSIS denormalize = context.getMatrix(false); + final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION); + final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION); normalize.convertAfter(0, n, null); /* * One of the last steps performed by the stereographic projection is to multiply the easting and northing @@ -190,7 +191,7 @@ public class ObliqueStereographic extend * comparing two {@code ObliqueStereographic} projections or formatting them in debug mode. * * <p>We could report any of the internal parameters. But since they are all derived from φ₀ and - * the {@linkplain #excentricity excentricity} and since the excentricity is already reported by + * the {@linkplain #eccentricity eccentricity} and since the eccentricity is already reported by * the super-class, we report only χ₀ is a representative of the internal parameters.</p> */ @Override @@ -233,7 +234,7 @@ public class ObliqueStereographic extend } } ObliqueStereographic kernel = this; - if (excentricity == 0) { + if (eccentricity == 0) { kernel = new Spherical(this); } return context.completeTransform(factory, kernel); @@ -255,10 +256,10 @@ public class ObliqueStereographic extend final double Λ = srcPts[srcOff ]; // Λ = λ⋅n (see below), ignoring longitude of origin. final double φ = srcPts[srcOff+1]; final double sinφ = sin(φ); - final double ℯsinφ = excentricity * sinφ; + final double ℯsinφ = eccentricity * sinφ; final double Sa = (1 + sinφ) / (1 - sinφ); final double Sb = (1 - ℯsinφ) / (1 + ℯsinφ); - final double w = c * pow(Sa * pow(Sb, excentricity), n); + final double w = c * pow(Sa * pow(Sb, eccentricity), n); /* * Convert the geodetic coordinates (φ,λ) to conformal coordinates (χ,Λ) before to apply the * actual stereographic projection. The geodetic and conformal coordinates will be the same @@ -304,7 +305,7 @@ public class ObliqueStereographic extend * ∂w/∂φ = 2⋅n⋅w⋅(1/cosφ - ℯ²⋅cosφ/(1 - ℯ²⋅sin²φ)); */ final double cosφ = cos(φ); - final double dχ_dφ = (1/cosφ - cosφ*excentricitySquared/(1 - ℯsinφ*ℯsinφ)) * 2*n*sqrt(w) / (w + 1); + final double dχ_dφ = (1/cosφ - cosφ*eccentricitySquared/(1 - ℯsinφ*ℯsinφ)) * 2*n*sqrt(w) / (w + 1); /* * Above ∂χ/∂φ is equals to 1 in the spherical case. * Remaining formulas below are the same than in the spherical case. @@ -350,11 +351,10 @@ public class ObliqueStereographic extend final double sinχ = sin(χ0 + 2*atan(y - x*tan(j/2))); final double ψ = log((1 + sinχ) / ((1 - sinχ)*c)) / (2*n); double φ = 2*atan(exp(ψ)) - PI/2; // First approximation - final double he = excentricity/2; - final double me = 1 - excentricitySquared; - int r = MAXIMUM_ITERATIONS; - do { - final double ℯsinφ = excentricity * sin(φ); + final double he = eccentricity/2; + final double me = 1 - eccentricitySquared; + for (int it=0; it<MAXIMUM_ITERATIONS; it++) { + final double ℯsinφ = eccentricity * sin(φ); final double ψi = log(tan(φ/2 + PI/4) * pow((1 - ℯsinφ) / (1 + ℯsinφ), he)); final double Δφ = (ψ - ψi) * cos(φ) * (1 - ℯsinφ*ℯsinφ) / me; φ += Δφ; @@ -363,13 +363,16 @@ public class ObliqueStereographic extend dstPts[dstOff+1] = φ; return; } - } while (--r != 0); + } throw new ProjectionException(Errors.Keys.NoConvergence); } + + + /** * Provides the transform equations for the spherical case of the Oblique Stereographic projection. - * This implementation can be used when {@link #excentricity} = 0. + * This implementation can be used when {@link #eccentricity} = 0. * * @author Rémi Maréchal (Geomatys) * @author Martin Desruisseaux (Geomatys) Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -25,6 +25,7 @@ import org.opengis.referencing.operation import org.opengis.referencing.operation.Matrix; import org.apache.sis.referencing.operation.matrix.Matrix2; import org.apache.sis.referencing.operation.matrix.MatrixSIS; +import org.apache.sis.referencing.operation.transform.ContextualParameters; import org.apache.sis.internal.referencing.provider.PolarStereographicA; import org.apache.sis.internal.referencing.provider.PolarStereographicB; import org.apache.sis.internal.referencing.provider.PolarStereographicC; @@ -206,7 +207,7 @@ public class PolarStereographic extends * * In the spherical case, should give ρ == 2. */ - ρ = verbatim(2 / sqrt(pow(1+excentricity, 1+excentricity) * pow(1-excentricity, 1-excentricity))); + ρ = verbatim(2 / sqrt(pow(1+eccentricity, 1+eccentricity) * pow(1-eccentricity, 1-eccentricity))); ρF = null; } else { /* @@ -228,19 +229,19 @@ public class PolarStereographic extends */ final double sinφ1 = sin(φ1); final double mF = initializer.scaleAtφ(sinφ1, cos(φ1)); - ρ = verbatim(mF / expOfNorthing(φ1, excentricity*sinφ1)); + ρ = verbatim(mF / expOfNorthing(φ1, eccentricity*sinφ1)); ρF = (variant == C) ? verbatim(-mF) : null; } /* * At this point, all parameters have been processed. Now process to their * validation and the initialization of (de)normalize affine transforms. */ - final MatrixSIS denormalize = context.getMatrix(false); + final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION); denormalize.convertBefore(0, ρ, null); denormalize.convertBefore(1, ρ, ρF); if (isNorth) { final Number reverseSign = verbatim(-1); - final MatrixSIS normalize = context.getMatrix(true); + final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION); normalize .convertAfter (1, reverseSign, null); denormalize.convertBefore(1, reverseSign, null); } @@ -268,7 +269,7 @@ public class PolarStereographic extends @Override public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException { PolarStereographic kernel = this; - if (excentricity == 0) { + if (eccentricity == 0) { kernel = new Spherical(this); } return context.completeTransform(factory, kernel); @@ -303,7 +304,7 @@ public class PolarStereographic extends * The next step is to compute ρ = 2⋅a⋅k₀⋅t / …, but those steps are * applied by the denormalization matrix and shall not be done here. */ - final double t = expOfNorthing(φ, excentricity*sinφ); + final double t = expOfNorthing(φ, eccentricity*sinφ); final double x = t * sinθ; final double y = t * cosθ; if (dstPts != null) { Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -25,6 +25,7 @@ import org.opengis.referencing.operation import org.opengis.referencing.operation.OperationMethod; import org.apache.sis.referencing.operation.matrix.Matrix2; import org.apache.sis.referencing.operation.matrix.MatrixSIS; +import org.apache.sis.referencing.operation.transform.ContextualParameters; import org.apache.sis.internal.referencing.provider.TransverseMercatorSouth; import org.apache.sis.internal.util.DoubleDouble; import org.apache.sis.parameter.Parameters; @@ -72,7 +73,7 @@ public class TransverseMercator extends /** * Coefficients in the series expansion of the forward projection, - * depending only on {@linkplain #excentricity excentricity} value. + * depending only on {@linkplain #eccentricity eccentricity} value. * The series expansion is of the following form: * * <blockquote>cf₂⋅f(2θ) + cf₄⋅f(4θ) + cf₆⋅f(6θ) + cf₈⋅f(8θ)</blockquote> @@ -163,7 +164,7 @@ public class TransverseMercator extends * NOTE: the EPSG documentation makes special cases for φ₀ = 0 or ±π/2. This is not * needed here; we verified that the code below produces naturally the expected values. */ - final double Q = asinh(tan(φ0)) - excentricity * atanh(excentricity * sin(φ0)); + final double Q = asinh(tan(φ0)) - eccentricity * atanh(eccentricity * sin(φ0)); final double β = atan(sinh(Q)); final DoubleDouble M0 = new DoubleDouble(); M0.value = cf8 * sin(8*β) @@ -187,7 +188,7 @@ public class TransverseMercator extends * - Multiply by the scale factor (done by the super-class constructor). * - Add false easting and false northing (done by the super-class constructor). */ - final MatrixSIS denormalize = context.getMatrix(false); + final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION); denormalize.convertBefore(0, B, null); denormalize.convertBefore(1, B, M0); /* @@ -215,7 +216,7 @@ public class TransverseMercator extends * 'n' value at serialization time. */ final DoubleDouble t = new DoubleDouble(1, 0); - t.subtract(excentricitySquared, 0); + t.subtract(eccentricitySquared, 0); t.sqrt(); t.ratio_1m_1p(); computeCoefficients(t.doubleValue()); @@ -239,7 +240,7 @@ public class TransverseMercator extends * * As much as possible, b/a should be computed from the map projection parameters. * However if those parameters are not available anymore, then they can be computed - * from the excentricity as: + * from the eccentricity as: * * <blockquote>b/a = √(1 - ℯ²)</blockquote> * @@ -293,7 +294,7 @@ public class TransverseMercator extends @Override public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException { TransverseMercator kernel = this; - if (excentricity == 0) { + if (eccentricity == 0) { kernel = new Spherical(this); } return context.completeTransform(factory, kernel); @@ -315,8 +316,8 @@ public class TransverseMercator extends final double λ = srcPts[srcOff ]; final double φ = srcPts[srcOff+1]; final double sinλ = sin(λ); - final double ℯsinφ = sin(φ) * excentricity; - final double Q = asinh(tan(φ)) - atanh(ℯsinφ) * excentricity; + final double ℯsinφ = sin(φ) * eccentricity; + final double Q = asinh(tan(φ)) - atanh(ℯsinφ) * eccentricity; final double coshQ = cosh(Q); final double η0 = atanh(sinλ / coshQ); /* @@ -417,7 +418,7 @@ public class TransverseMercator extends final double sqrt1_thQchη0 = sqrt(1 - (tanhQ * tanhQ) * (coshη0 * coshη0)); //-- Qη0 //-- dQ_dλ = 0; - final double dQ_dφ = 1 / cosφ - excentricitySquared * cosφ / (1 - ℯsinφ * ℯsinφ); + final double dQ_dφ = 1 / cosφ - eccentricitySquared * cosφ / (1 - ℯsinφ * ℯsinφ); final double dη0_dλ = cosλ * coshQ / cosh2Q_sin2λ; final double dη0_dφ = - dQ_dφ * sinλ * sinhQ / cosh2Q_sin2λ; @@ -541,10 +542,12 @@ public class TransverseMercator extends final double Q = asinh(tan(β)); /* * Following usually converges in 4 iterations. + * The first iteration is unrolled. */ - double Qp = Q, p = 0; - for (int i=0; i<MAXIMUM_ITERATIONS; i++) { - final double c = excentricity * atanh(excentricity * tanh(Qp)); + double p = eccentricity * atanh(eccentricity * tanh(Q)); + double Qp = Q + p; + for (int it=0; it<MAXIMUM_ITERATIONS; it++) { + final double c = eccentricity * atanh(eccentricity * tanh(Qp)); Qp = Q + c; if (abs(c - p) <= ITERATION_TOLERANCE) { dstPts[dstOff ] = asin(tanh(η0) / cos(β)); @@ -557,6 +560,8 @@ public class TransverseMercator extends } + + /** * Provides the transform equations for the spherical case of the Transverse Mercator projection. * Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java?rev=1713527&r1=1713526&r2=1713527&view=diff ============================================================================== --- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java [UTF-8] (original) +++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractLinearTransform.java [UTF-8] Mon Nov 9 19:57:39 2015 @@ -16,8 +16,10 @@ */ package org.apache.sis.referencing.operation.transform; +import java.io.Serializable; import org.opengis.parameter.ParameterValueGroup; import org.opengis.parameter.ParameterDescriptorGroup; +import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.Matrix; import org.apache.sis.referencing.operation.matrix.Matrices; import org.apache.sis.internal.referencing.provider.Affine; @@ -37,13 +39,23 @@ import org.apache.sis.util.resources.Err * * @author Martin Desruisseaux (Geomatys) * @since 0.6 - * @version 0.6 + * @version 0.7 * @module */ -@SuppressWarnings("CloneInNonCloneableClass") -abstract class AbstractLinearTransform extends AbstractMathTransform - implements LinearTransform, Matrix // Not Cloneable, despite the clone() method. -{ +@SuppressWarnings("CloneInNonCloneableClass") // Intentionally not Cloneable despite the clone() method. +abstract class AbstractLinearTransform extends AbstractMathTransform implements LinearTransform, Matrix, Serializable { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = -4649708313541868599L; + + /** + * The inverse transform, or {@code null} if not yet created. + * This field is part of the serialization form in order to avoid rounding errors if a user + * asks for the inverse of the inverse (i.e. the original transform) after deserialization. + */ + MathTransform inverse; + /** * Constructs a transform. */
