Author: desruisseaux
Date: Thu Jul 30 15:27:52 2015
New Revision: 1693439
URL: http://svn.apache.org/r1693439
Log:
Moved the code used for map projection initialisation in a separated
Initializer class (package private).
Opportunistically use more double-double arithmetic. While the digits modified
by this extra-precision are
not significant, the intend is not to increase map projection accuracy but
rather to improve the result of
concatenations of MathTransforms (through an attempt to improve the result of
matrix multiplications and inversions).
Added:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
- copied, changed from r1693283,
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java?rev=1693439&r1=1693438&r2=1693439&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
[UTF-8] Thu Jul 30 15:27:52 2015
@@ -16,13 +16,9 @@
*/
package org.apache.sis.referencing.operation.projection;
-import java.util.Map;
import java.io.IOException;
import java.io.ObjectInputStream;
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.referencing.operation.OperationMethod;
import org.apache.sis.util.resources.Errors;
-import org.apache.sis.parameter.Parameters;
import static java.lang.Math.*;
@@ -107,17 +103,12 @@ abstract class ConformalProjection exten
private transient boolean useIterations;
/**
- * Constructs a new map projection from the supplied parameters.
+ * Creates a new normalized projection from the parameters computed by the
given initializer.
*
- * @param method Description of the map projection parameters.
- * @param parameters The parameters of the projection to be created.
- * @param roles Parameters to look for <cite>central meridian</cite>,
<cite>scale factor</cite>,
- * <cite>false easting</cite>, <cite>false northing</cite> and
other values.
- */
- protected ConformalProjection(final OperationMethod method, final
Parameters parameters,
- final Map<ParameterRole, ? extends ParameterDescriptor<Double>>
roles)
- {
- super(method, parameters, roles);
+ * @param initializer The initializer for computing map projection
internal parameters.
+ */
+ ConformalProjection(final Initializer initializer) {
+ super(initializer);
initialize();
}
Copied:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
(from r1693283,
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java)
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java?p2=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java&r1=1693283&r2=1693439&rev=1693439&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
[UTF-8] Thu Jul 30 15:27:52 2015
@@ -17,179 +17,44 @@
package org.apache.sis.referencing.operation.projection;
import java.util.Map;
-import java.util.HashMap;
-import java.io.Serializable;
-import java.lang.reflect.Modifier;
-import org.opengis.metadata.Identifier;
-import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterDescriptorGroup;
-import org.opengis.referencing.operation.Matrix;
-import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.referencing.operation.TransformException;
-import org.opengis.referencing.operation.MathTransformFactory;
-import org.opengis.util.FactoryException;
-import org.apache.sis.util.Debug;
-import org.apache.sis.util.CharSequences;
-import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.internal.referencing.provider.MapProjection;
import org.apache.sis.parameter.Parameters;
-import org.apache.sis.parameter.ParameterBuilder;
-import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.internal.util.DoubleDouble;
import org.apache.sis.referencing.operation.matrix.MatrixSIS;
-import org.apache.sis.referencing.operation.transform.AbstractMathTransform2D;
import org.apache.sis.referencing.operation.transform.ContextualParameters;
-import org.apache.sis.internal.referencing.provider.MapProjection;
-import org.apache.sis.internal.referencing.Formulas;
-import org.apache.sis.internal.util.CollectionsExt;
-import org.apache.sis.internal.util.DoubleDouble;
-import org.apache.sis.internal.util.Constants;
-import org.apache.sis.internal.util.Utilities;
-import org.apache.sis.internal.util.Numerics;
+import
org.apache.sis.referencing.operation.projection.NormalizedProjection.ParameterRole;
import static java.lang.Math.*;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-// Branch-dependent imports
-import java.util.Objects;
-
/**
- * Base class for conversion services between ellipsoidal and cartographic
projections.
- * This conversion works on a normalized spaces, where angles are expressed in
radians and
- * computations are performed for a sphere having a semi-major axis of 1. More
specifically:
- *
- * <ul class="verbose">
- * <li>On input, the {@link #transform(double[], int, double[], int,
boolean) transform(…)} method
- * expects (<var>longitude</var>, <var>latitude</var>) angles in
<strong>radians</strong>.
- * Longitudes have the <cite>central meridian</cite> (λ₀) removed before the
transform method is invoked.
- * The conversion from degrees to radians and the longitude rotation are
applied by the
- * {@linkplain ContextualParameters#normalizeGeographicInputs normalization}
affine transform.</li>
- *
- * <li>On output, the {@link #transform(double[],int,double[],int,boolean)
transform(…)} method returns
- * (<var>x</var>, <var>y</var>) values on a sphere or ellipse having a
semi-major axis length (<var>a</var>) of 1.
- * The multiplication by the scale factor (<var>k</var>₀) and the
translation by false easting (FE) and false
- * northing (FN) are applied by the {@linkplain
ContextualParameters#getMatrix denormalization} affine transform.</li>
- * </ul>
- *
- * The normalization and denormalization steps are represented below by the
matrices immediately on the left and right
- * sides of {@code NormalizedProjection} respectively. Those matrices show
only the basic parameters common to most projections.
- * Some projections will put more elements in those matrices.
- *
- * <center>
- * <table class="compact" style="td {vertical-align: middle}"
summary="Decomposition of a map projection">
- * <tr>
- * <td>{@include ../transform/formulas.html#SwapAxes}</td>
- * <td>→</td>
- * <td>{@include ../transform/formulas.html#NormalizeGeographic}</td>
- * <td>→</td>
- * <td>{@code NormalizedProjection}</td>
- * <td>→</td>
- * <td>{@include ../transform/formulas.html#DenormalizeCartesian}</td>
- * </tr>
- * </table>
- * </center>
- *
- * <div class="note"><b>Note:</b>
- * The first matrix on the left side is for {@linkplain
org.apache.sis.referencing.cs.CoordinateSystems#swapAndScaleAxes
- * swapping axes} from (<var>latitude</var>, <var>longitude</var>) to
(<var>longitude</var>, <var>latitude</var>) order.
- * This matrix is shown here for completeness, but is not managed by this
projection package. Axes swapping is managed
- * at a {@linkplain
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#createBaseToDerived(
- * org.opengis.referencing.cs.CoordinateSystem,
org.opengis.referencing.operation.MathTransform,
- * org.opengis.referencing.cs.CoordinateSystem) higher level}.</div>
- *
- * {@code NormalizedProjection} does not store the above cited parameters
(central meridian, scale factor, <i>etc.</i>)
- * on intend (except indirectly), in order to make clear that those parameters
are not used by subclasses.
- * The ability to recognize two {@code NormalizedProjection}s as {@linkplain
#equals(Object, ComparisonMode) equivalent}
- * without consideration for the scale factor (among other) allow more
efficient concatenation in some cases
- * (typically some combinations of inverse projection followed by a direct
projection).
- *
- * <p>All angles (either fields, method parameters or return values) in this
class and subclasses are
- * in radians. This is the opposite of {@link Parameters} where all angles are
in CRS-dependent units,
- * typically decimal degrees.</p>
- *
- * <div class="section">Serialization</div>
- * Serialization of this class is appropriate for short-term storage or RMI
use, but may not be compatible
- * with future versions. For long term storage, WKT (Well Know Text) or XML
are more appropriate.
+ * Helper class for map projection constructions, providing formulas normally
needed only at construction time.
+ * Since map projection constructions should not happen very often, we afford
using double-double arithmetic here.
+ * The main intend is not to provide more accurate coordinate conversions
(while it may be a nice side-effect),
+ * but rather to increase the chances that the concatenations of
(de)normalization matrices with the matrices of
+ * other transforms give back identity matrices when such result is expected.
*
- * @author Martin Desruisseaux (MPO, IRD, Geomatys)
- * @author André Gosselin (MPO)
- * @author Rueben Schulz (UBC)
- * @author Rémi Maréchal (Geomatys)
+ * @author Martin Desruisseaux (Geomatys)
* @since 0.6
* @version 0.6
* @module
- *
- * @see ContextualParameters
- * @see <a href="http://mathworld.wolfram.com/MapProjection.html">Map
projections on MathWorld</a>
*/
-public abstract class NormalizedProjection extends AbstractMathTransform2D
implements Serializable {
- /**
- * For cross-version compatibility.
- */
- private static final long serialVersionUID = 1969740225939106310L;
-
+final class Initializer {
/**
- * Maximum difference allowed when comparing longitudes or latitudes in
radians.
- * The current value takes the system-wide angular tolerance value
(equivalent to
- * about 1 cm on Earth) converted to radians.
+ * The parameters used for creating the map projection.
+ * This object will be stored in the map projection.
*
- * <p>Some formulas use this tolerance value for testing sines or cosines
of an angle.
- * In the sine case, this is justified because sin(θ) ≅ θ when θ is small.
- * Similar reasoning applies to cosine with cos(θ) ≅ θ + π/2 when θ is
small.</p>
- *
- * <p>Some formulas may use this tolerance value as a <em>linear</em>
tolerance on the unit sphere.
- * This is okay because the arc length for an angular tolerance θ is r⋅θ,
but in this class r=1.</p>
- */
- static final double ANGULAR_TOLERANCE = Formulas.ANGULAR_TOLERANCE *
(PI/180);
- // Note: an alternative way to compute this value could be
Formulas.LINEAR_TOLERANCE / AUTHALIC_RADIUS.
- // But the later is only 0.07% lower than the current value.
-
- /**
- * Desired accuracy for the result of iterative computations, in radians.
- * This constant defines the desired accuracy of methods like {@link
ConformalProjection#φ(double)}.
- *
- * <p>The current value is 0.25 time the accuracy derived from {@link
Formulas#LINEAR_TOLERANCE}.
- * So if the linear tolerance is 1 cm, then the accuracy that we will seek
for is 0.25 cm (about
- * 4E-10 radians). The 0.25 factor is a safety margin for meeting the 1 cm
accuracy.</p>
- */
- static final double ITERATION_TOLERANCE = ANGULAR_TOLERANCE * 0.25;
-
- /**
- * 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.
- */
- static final int MAXIMUM_ITERATIONS = 15;
-
- /**
- * 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
- * added by some subclasses.
- *
- * <p>Entries are created only when first needed. Those descriptors are
usually never created since they are
- * used only by {@link #getParameterDescriptors()}, which is itself
invoked mostly for debugging purpose.</p>
- */
- @Debug
- private static final Map<Class<?>,ParameterDescriptorGroup> DESCRIPTORS =
new HashMap<>();
-
- /**
- * The parameters used for creating this projection. They are used for
formatting <cite>Well Known Text</cite> (WKT)
- * and error messages. Subclasses shall not use the values defined in this
object for computation purpose, except at
- * construction time.
- *
- * @see #getContextualParameters()
+ * @see NormalizedProjection#getContextualParameters()
*/
final ContextualParameters context;
/**
- * Ellipsoid excentricity, equals to <code>sqrt({@linkplain
#excentricitySquared})</code>.
- * Value 0 means that the ellipsoid is spherical.
+ * The user-supplied parameters, stored temporarily while we transfer the
information to {@link #context}.
*/
- protected final double excentricity;
+ final Parameters parameters;
/**
* The square of excentricity: ℯ² = (a²-b²)/a² where
@@ -197,215 +62,27 @@ public abstract class NormalizedProjecti
* <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;
+ final DoubleDouble excentricitySquared;
/**
- * The inverse of this map projection.
- */
- private final MathTransform2D inverse;
-
- /**
- * Maps the parameters to be used for initializing {@link
NormalizedProjection} and its
- * {@linkplain ContextualParameters#getMatrix(boolean) 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
- * {@linkplain NormalizedProjection#NormalizedProjection(OperationMethod,
Parameters, Map) projection constructor}.
- *
- * <p>{@code NormalizedProjection} subclasses will typically provide
values only for the following keys:
- * {@link #CENTRAL_MERIDIAN}, {@link #SCALE_FACTOR}, {@link
#FALSE_EASTING} and {@link #FALSE_NORTHING}.</p>
- *
- * @author Martin Desruisseaux (Geomatys)
- * @since 0.6
- * @version 0.6
- * @module
- *
- * @see NormalizedProjection#NormalizedProjection(OperationMethod,
Parameters, Map)
+ * Map projection variant. This is a convenience field left at
+ * the discretion of {@link NormalizedProjection} subclasses.
*/
- 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},
- * 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"}.
- * {@code NormalizedProjection} subclasses typically do not need to
provide a value for this key.</p>
- */
- SEMI_MAJOR,
-
- /**
- * Maps the <cite>semi-minor axis length</cite> parameter (symbol:
<var>b</var>).
- * This value is used for computing {@link
NormalizedProjection#excentricity}.
- *
- * <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>
- */
- SEMI_MINOR,
-
- /**
- * Maps the parameter for the latitude where to compute the
<cite>radius of conformal sphere</cite>
- * (symbol: <var>R</var><sub>c</sub>). If this parameter is provided,
then the radius of the conformal
- * sphere at latitude φ will be used instead than the semi-major axis
length in the denormalisation matrix.
- * In other words, if provided then <var>a</var> is replaced by
<var>R</var><sub>c</sub> below:
- *
- * <center>{@include
../transform/formulas.html#DenormalizeCartesian}</center>
- *
- * <p>This enumeration shall be used <strong>only</strong> when the
user requested explicitely spherical
- * formulas, for example the <cite>"Mercator (Spherical)"</cite>
projection (EPSG:1026), but the figure
- * of the Earth may be an ellipsoid rather than a sphere. In the
majority of cases, this enumeration should
- * not be used.</p>
- */
- LATITUDE_OF_CONFORMAL_SPHERE_RADIUS,
-
- /**
- * Maps the <cite>central meridian</cite> parameter (symbol: λ₀).
- * This value is subtracted from the longitude values before the map
projections.
- *
- * <p>Some common names for this parameter are:</p>
- * <ul>
- * <li>Longitude of origin</li>
- * <li>Longitude of false origin</li>
- * <li>Longitude of natural origin</li>
- * <li>Spherical longitude of origin</li>
- * <li>Longitude of projection centre</li>
- * </ul>
- */
- CENTRAL_MERIDIAN,
-
- /**
- * Maps the <cite>scale factor</cite> parameter (symbol:
<var>k</var>₀).
- * This is a multiplication factor for the (<var>x</var>,<var>y</var>)
values obtained after map projections.
- *
- * <p>Some common names for this parameter are:</p>
- * <ul>
- * <li>Scale factor at natural origin</li>
- * <li>Scale factor on initial line</li>
- * <li>Scale factor on pseudo standard parallel</li>
- * </ul>
- */
- SCALE_FACTOR,
-
- /**
- * Maps the <cite>false easting</cite> parameter (symbol:
<var>FE</var>).
- * This is a translation term for the <var>x</var> values obtained
after map projections.
- *
- * <p>Some common names for this parameter are:</p>
- * <ul>
- * <li>False easting</li>
- * <li>Easting at false origin</li>
- * <li>Easting at projection centre</li>
- * </ul>
- */
- FALSE_EASTING,
-
- /**
- * Maps the <cite>false westing</cite> parameter (symbol:
<var>FW</var>).
- * This is the same <var>x</var> translation than {@link
#FALSE_EASTING}, but of opposite sign.
- *
- * <p>Actually, there is usually no parameter named "false westing" in
a map projection.
- * But some projections like <cite>"Lambert Conic Conformal (West
Orientated)"</cite> are
- * defined in such a way that their "false easting" parameter is
effectively a "false westing".
- * This enumeration value can be used for informing {@link
NormalizedProjection} about that fact.</p>
- */
- FALSE_WESTING,
-
- /**
- * Maps the <cite>false northing</cite> parameter (symbol:
<var>FN</var>).
- * This is a translation term for the <var>y</var> values obtained
after map projections.
- *
- * <p>Some common names for this parameter are:</p>
- * <ul>
- * <li>False northing</li>
- * <li>Northing at false origin</li>
- * <li>Northing at projection centre</li>
- * </ul>
- */
- FALSE_NORTHING,
-
- /**
- * Maps the <cite>false southing</cite> parameter (symbol:
<var>FS</var>).
- * This is the same <var>y</var> translation than {@link
#FALSE_NORTHING}, but of opposite sign.
- *
- * <p>Actually, there is usually no parameter named "false southing"
in a map projection.
- * But some projections like <cite>"Transverse Mercator (South
Orientated)"</cite> are
- * defined in such a way that their "false northing" parameter is
effectively a "false southing".
- * This enumeration value can be used for informing {@link
NormalizedProjection} about that fact.</p>
- */
- FALSE_SOUTHING
- }
+ final byte variant;
/**
- * Constructs a new map projection from the supplied parameters.
- * This constructor applies the following operations on the {@link
ContextualParameter}:
- *
- * <ul>
- * <li>On the <b>normalization</b> matrix (to be applied before {@code
this} transform):
- * <ul>
- * <li>{@linkplain
ContextualParameters#normalizeGeographicInputs(double) Subtract}
- * the <cite>central meridian</cite> value.</li>
- * <li>Convert from degrees to radians.</li>
- * </ul>
- * </li>
- * <li>On the <b>denormalization</b> matrix (to be applied after {@code
this} transform):
- * <ul>
- * <li>{@linkplain MatrixSIS#convertAfter(int, Number, Number)
Scale} by the <cite>semi-major</cite> axis length.</li>
- * <li>If a scale factor is present (not all map projections have a
scale factor), apply that scale.</li>
- * <li>Translate by the <cite>false easting</cite> and <cite>false
northing</cite> (after the scale).</li>
- * </ul>
- * </li>
- * <li>On the <b>contextual parameters</b> (not the parameters of {@code
this} transform):
- * <ul>
- * <li>Store the values for <cite>semi-major</cite> axis length,
<cite>semi-minor</cite> axis length,
- * <cite>scale factor</cite> (if present), <cite>central
meridian</cite>,
- * <cite>false easting</cite> and <cite>false northing</cite>
values.</li>
- * </ul>
- * </li>
- * </ul>
- *
- * In matrix form, this constructor creates the following matrices
(subclasses are free to modify):
- * <table class="sis">
- * <caption>Initial matrix coefficients after construction</caption>
- * <tr>
- * <th>Normalization</th>
- * <th class="sep">Denormalization</th>
- * </tr>
- * <tr>
- * <td>{@include ../transform/formulas.html#NormalizeGeographic}</td>
- * <td class="sep">{@include
../transform/formulas.html#DenormalizeCartesian}</td>
- * </tr>
- * </table>
- *
- * <div class="section">Which parameters are considered</div>
- * The {@code roles} map specifies which parameters to look for
<cite>central meridian</cite>,
- * <cite>scale factor</cite>, <cite>false easting</cite>, <cite>false
northing</cite> and other values.
- * All entries in the {@code roles} map are optional.
- * All descriptors in the map shall comply to the following constraints:
- *
- * <ul>
- * <li>Descriptors associated to {@link ParameterRole#SEMI_MAJOR},
{@link ParameterRole#SEMI_MINOR SEMI_MINOR},
- * {@link ParameterRole#FALSE_EASTING FALSE_EASTING} and {@link
ParameterRole#FALSE_NORTHING FALSE_NORTHING}
- * shall have the same linear unit of measurement (usually metre).</li>
- * <li>Descriptors associated to angular measures ({@link
ParameterRole#CENTRAL_MERIDIAN} and
- * {@link ParameterRole#LATITUDE_OF_CONFORMAL_SPHERE_RADIUS
LATITUDE_OF_CONFORMAL_SPHERE_RADIUS})
- * shall use degrees.</li>
- * </ul>
- *
- * Note that users can still use units of their choice in the {@link
Parameters} object given in argument to
- * this constructor. But those values will be converted to the units of
measurement specified by the parameter
- * descriptors in the {@code roles} map, which must be the above-cited
units.
- *
- * @param method Description of the map projection parameters.
- * @param parameters The parameters of the projection to be created.
- * @param roles Parameters to look for <cite>central meridian</cite>,
<cite>scale factor</cite>,
- * <cite>false easting</cite>, <cite>false northing</cite> and
other values.
+ * Creates a new initializer.
*/
- protected NormalizedProjection(final OperationMethod method, final
Parameters parameters,
- final Map<ParameterRole, ? extends ParameterDescriptor<Double>>
roles)
+ Initializer(final OperationMethod method, final Parameters parameters,
+ final Map<ParameterRole, ? extends ParameterDescriptor<Double>>
roles,
+ final byte variant)
{
ensureNonNull("method", method);
ensureNonNull("parameters", parameters);
ensureNonNull("roles", roles);
- context = new ContextualParameters(method);
+ this.context = new ContextualParameters(method);
+ this.parameters = parameters;
+ this.variant = variant;
/*
* Note: we do not use Map.getOrDefault(K,V) below because the user
could have explicitly associated
* a null value to keys (we are paranoiac...) and because it conflicts
with the "? extends" part of
@@ -416,17 +93,34 @@ public abstract class NormalizedProjecti
if (semiMajor == null) semiMajor = MapProjection.SEMI_MAJOR;
if (semiMinor == null) semiMinor = MapProjection.SEMI_MINOR;
- double a = getAndStore(parameters, semiMajor);
- final double b = getAndStore(parameters, semiMinor);
- final double λ0 = getAndStore(parameters,
roles.get(ParameterRole.CENTRAL_MERIDIAN));
- final double fe = getAndStore(parameters,
roles.get(ParameterRole.FALSE_EASTING))
- - getAndStore(parameters,
roles.get(ParameterRole.FALSE_WESTING));
- final double fn = getAndStore(parameters,
roles.get(ParameterRole.FALSE_NORTHING))
- - getAndStore(parameters,
roles.get(ParameterRole.FALSE_SOUTHING));
- final double rs = b / a;
- excentricitySquared = 1 - (rs * rs);
- excentricity = sqrt(excentricitySquared);
- if (excentricitySquared != 0) {
+ final double a = getAndStore(semiMajor);
+ final double b = getAndStore(semiMinor);
+ final double λ0 =
getAndStore(roles.get(ParameterRole.CENTRAL_MERIDIAN));
+ final double fe = getAndStore(roles.get(ParameterRole.FALSE_EASTING))
+ - getAndStore(roles.get(ParameterRole.FALSE_WESTING));
+ final double fn = getAndStore(roles.get(ParameterRole.FALSE_NORTHING))
+ - getAndStore(roles.get(ParameterRole.FALSE_SOUTHING));
+
+ excentricitySquared = new DoubleDouble();
+ final DoubleDouble k = new DoubleDouble(a); // The value by which to
multiply all results of normalized projection.
+ if (a != b) {
+ /*
+ * Equivalent Java code for the following lines:
+ *
+ * final double rs = b / a;
+ * excentricitySquared = 1 - (rs * rs);
+ *
+ * Test show that double-double arithmetic here makes a difference
in the 3 last digits for WGS84 ellipsoid.
+ * Those 3 digits are not significant since the parameter are not
so accurate (furthermore the 'b' parameter
+ * used below may have been computed from the inverse flattening
factor).
+ */
+ final DoubleDouble rs = new DoubleDouble(b);
+ final double eb = rs.error;
+ rs.divide(k); // rs = b/a
+ rs.multiply(rs);
+ excentricitySquared.value = 1;
+ excentricitySquared.subtract(rs);
+
final ParameterDescriptor<Double> radius =
roles.get(ParameterRole.LATITUDE_OF_CONFORMAL_SPHERE_RADIUS);
if (radius != null) {
/*
@@ -439,61 +133,29 @@ public abstract class NormalizedProjecti
* Radius of conformal sphere Rc = a √(1 – ℯ²) / (1 – ℯ²⋅sin²φ)
*
* Using √(1 – ℯ²) = b/a we rewrite as: Rc = b / (1 – ℯ²⋅sin²φ)
+ *
+ * Equivalent Java code:
+ *
+ * final double sinφ =
sin(toRadians(parameters.doubleValue(radius)));
+ * k = b / (1 - excentricitySquared * (sinφ*sinφ));
*/
- final double sinφ =
sin(toRadians(parameters.doubleValue(radius)));
- a = b / (1 - excentricitySquared * (sinφ*sinφ));
+ final DoubleDouble t = new
DoubleDouble(sin(toRadians(parameters.doubleValue(radius))), 0);
+ t.multiply(t);
+ t.multiply(excentricitySquared);
+ k.clear();
+ k.value = 1;
+ k.subtract(t);
+ k.inverseDivide(b, eb);
}
}
context.normalizeGeographicInputs(λ0);
- final DoubleDouble k = new DoubleDouble(a);
final ParameterDescriptor<Double> scaleFactor =
roles.get(ParameterRole.SCALE_FACTOR);
if (scaleFactor != null) {
- k.multiply(getAndStore(parameters, scaleFactor));
+ k.multiply(getAndStore(scaleFactor));
}
final MatrixSIS denormalize = context.getMatrix(false);
denormalize.convertAfter(0, k, new DoubleDouble(fe));
denormalize.convertAfter(1, k, new DoubleDouble(fn));
- inverse = new Inverse();
- }
-
- /**
- * Creates a new projection initialized to the values of the given one.
This constructor may be invoked after
- * we determined that the default implementation can be replaced by an
other one, for example using spherical
- * formulas instead than the ellipsoidal ones. This constructor allows to
transfer all parameters to the new
- * instance without recomputing them.
- */
- NormalizedProjection(final NormalizedProjection other) {
- context = other.context;
- excentricity = other.excentricity;
- excentricitySquared = other.excentricitySquared;
- inverse = new Inverse();
- }
-
- /**
- * Returns {@code true} if the projection specified by the given method
has the given keyword or identifier.
- * If non-null, the given identifier is presumed in the EPSG namespace and
has precedence over the keyword.
- *
- * <div class="note"><b>Implementation note:</b>
- * Since callers usually give a constant string for the {@code regex}
argument, it would be more efficient to
- * compile the {@link java.util.regex.Pattern} once for all. However the
regular expression is used only as a
- * fallback if the descriptor does not contain EPSG identifier, which
should be rare. Usually, the regular
- * expression will never be compiled.</div>
- *
- * @param parameters The user-specified parameters.
- * @param regex The regular expression to use when using the
operation name as the criterion.
- * @param identifier The identifier to compare against the operation
method name.
- * @return {@code true} if the name of the given operation method contains
the given keyword
- * or has an EPSG identifier equals to the given identifier.
- */
- static boolean identMatch(final OperationMethod method, final String
regex, final String identifier) {
- if (identifier != null) {
- for (final Identifier id : method.getIdentifiers()) {
- if (Constants.EPSG.equals(id.getCodeSpace())) {
- return identifier.equals(id.getCode());
- }
- }
- }
- return method.getName().getCode().replace('_',' ').matches(regex);
}
/**
@@ -507,10 +169,8 @@ public abstract class NormalizedProjecti
* <li>Ensure that the value is contained in the range specified by the
descriptor.</li>
* <li>Store the value only if different than the default value.</li>
* </ul>
- *
- * This method shall be invoked at construction time only.
*/
- final double getAndStore(final Parameters parameters, final
ParameterDescriptor<Double> descriptor) {
+ final double getAndStore(final ParameterDescriptor<Double> descriptor) {
if (descriptor == null) {
return 0; // Default value for all parameters except scale
factor.
}
@@ -528,9 +188,7 @@ public abstract class NormalizedProjecti
* if the parameter is not specified. This method shall be used only for
parameters having a default
* value more complex than what we can represent in {@link
ParameterDescriptor#getDefaultValue()}.
*/
- final double getAndStore(final Parameters parameters, final
ParameterDescriptor<Double> descriptor,
- final double defaultValue)
- {
+ final double getAndStore(final ParameterDescriptor<Double> descriptor,
final double defaultValue) {
final Double value = parameters.getValue(descriptor); // Apply a
unit conversion if needed.
if (value == null) {
return defaultValue;
@@ -540,382 +198,6 @@ public abstract class NormalizedProjecti
return value;
}
- /**
- * Returns the sequence of <cite>normalization</cite> → {@code this} →
<cite>denormalization</cite> transforms
- * as a whole. The transform returned by this method except
(<var>longitude</var>, <var>latitude</var>)
- * coordinates in <em>degrees</em> and returns (<var>x</var>,<var>y</var>)
coordinates in <em>metres</em>.
- * Conversion to other units and {@linkplain
org.apache.sis.referencing.cs.CoordinateSystems#swapAndScaleAxes
- * changes in axis order} are <strong>not</strong> managed by the returned
transform.
- *
- * <p>The default implementation is as below:</p>
- * {@preformat java
- * return getContextualParameters().completeTransform(factory, this);
- * }
- *
- * Subclasses can override this method if they wish to use alternative
implementations under some circumstances.
- * For example many subclasses will replace {@code this} by a specialized
implementation if they detect that the
- * ellipsoid is actually spherical.
- *
- * @param factory The factory to use for creating the transform.
- * @return The map projection from (λ,φ) to (<var>x</var>,<var>y</var>)
coordinates.
- * @throws FactoryException if an error occurred while creating a
transform.
- *
- * @see ContextualParameters#completeTransform(MathTransformFactory,
MathTransform)
- */
- public MathTransform createMapProjection(final MathTransformFactory
factory) throws FactoryException {
- return context.completeTransform(factory, this);
- }
-
- /**
- * Returns the parameters used for creating the complete map projection.
Those parameters describe a sequence of
- * <cite>normalize</cite> → {@code this} → <cite>denormalize</cite>
transforms, <strong>not</strong> including
- * {@linkplain
org.apache.sis.referencing.cs.CoordinateSystems#swapAndScaleAxes axis swapping}.
- * Those parameters are used for formatting <cite>Well Known Text</cite>
(WKT) and error messages.
- * Subclasses shall not use the values defined in the returned object for
computation purpose,
- * except at construction time.
- *
- * @return The parameters values for the sequence of
<cite>normalize</cite> → {@code this} → <cite>denormalize</cite>
- * transforms, or {@code null} if unspecified.
- */
- @Override
- protected final ContextualParameters getContextualParameters() {
- return context;
- }
-
- /**
- * Returns a copy of non-linear internal parameter values of this {@code
NormalizedProjection}.
- * The returned group contained at least the {@link #excentricity}
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.
- *
- * <div class="note"><b>Note:</b>
- * This method is mostly for {@linkplain
org.apache.sis.io.wkt.Convention#INTERNAL debugging purposes}
- * since the isolation of non-linear parameters in this class is highly
implementation dependent.
- * Most GIS applications will instead be interested in the {@linkplain
#getContextualParameters()
- * contextual parameters}.</div>
- *
- * @return A copy of the internal parameter values for this normalized
projection.
- */
- @Debug
- @Override
- public ParameterValueGroup getParameterValues() {
- final ParameterValueGroup group =
getParameterDescriptors().createValue();
- group.parameter("excentricity").setValue(excentricity);
- final String[] names = getInternalParameterNames();
- final double[] values = getInternalParameterValues();
- for (int i=0; i<names.length; i++) {
- group.parameter(names[i]).setValue(values[i]);
- }
- return group;
- }
-
- /**
- * 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.
- * Subclasses may add more parameters.
- *
- * <p>This method is for inspecting the parameter values of this
non-linear kernel only,
- * not for inspecting the {@linkplain #getContextualParameters()
contextual parameters}.
- * Inspecting the kernel parameter values is usually for debugging purpose
only.</p>
- *
- * @return A description of the internal parameters.
- */
- @Debug
- @Override
- public ParameterDescriptorGroup getParameterDescriptors() {
- Class<?> type = getClass();
- while (!Modifier.isPublic(type.getModifiers())) {
- type = type.getSuperclass();
- }
- ParameterDescriptorGroup group;
- synchronized (DESCRIPTORS) {
- group = DESCRIPTORS.get(type);
- if (group == null) {
- final ParameterBuilder builder = new
ParameterBuilder().setRequired(true);
- if (Utilities.isSIS(type)) {
- builder.setCodeSpace(Citations.SIS, "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;
- }
- group =
builder.addName(CharSequences.camelCaseToSentence(type.getSimpleName())).createGroup(1,
1, parameters);
- DESCRIPTORS.put(type, group);
- }
- }
- return group;
- }
-
- /**
- * Returns the names of any additional internal parameters (other than
{@link #excentricity})
- * 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.
- */
- String[] getInternalParameterNames() {
- return CharSequences.EMPTY_ARRAY;
- }
-
- /**
- * Returns the values of any additional internal parameters (other than
{@link #excentricity}) that
- * this projection has. Those values are also compared by {@link
#equals(Object, ComparisonMode)}.
- */
- double[] getInternalParameterValues() {
- return null;
- }
-
- /**
- * Converts a single coordinate in {@code srcPts} at the given offset and
stores the result
- * in {@code dstPts} at the given offset. In addition, opportunistically
computes the
- * transform derivative if requested.
- *
- * <div class="section">Normalization</div>
- * The input ordinates are (<var>λ</var>,<var>φ</var>) (the variable names
for <var>longitude</var> and
- * <var>latitude</var> respectively) angles in radians.
- * Input coordinate shall have the <cite>central meridian</cite> removed
from the longitude by the caller
- * before this method is invoked. After this method is invoked, the caller
will need to multiply the output
- * coordinate by the global <cite>scale factor</cite>
- * and apply the (<cite>false easting</cite>, <cite>false northing</cite>)
offset.
- * This means that projections that implement this method are performed on
a sphere or ellipse
- * having a semi-major axis length of 1.
- *
- * <div class="note"><b>Note:</b> in <a
href="http://trac.osgeo.org/proj/">Proj.4</a>, the same standardization,
- * described above, is handled by {@code pj_fwd.c}.</div>
- *
- * <div class="section">Argument checks</div>
- * The input longitude and latitude are usually (but not always) in the
range [-π … π] and [-π/2 … π/2] respectively.
- * However values outside those ranges are accepted on the assumption that
most implementations use those values
- * only in trigonometric functions like {@linkplain Math#sin(double) sine}
and {@linkplain Math#cos(double) cosine}.
- * If this assumption is not applicable to a particular subclass, then it
is implementor's responsibility to check
- * the range.
- *
- * @param srcPts The array containing the source point coordinate, as
(<var>longitude</var>, <var>latitude</var>)
- * angles in <strong>radians</strong>.
- * @param srcOff The offset of the single coordinate to be converted in
the source array.
- * @param dstPts The array into which the converted coordinate is
returned (may be the same than {@code srcPts}).
- * Ordinates will be expressed in a dimensionless unit, as
a linear distance on a unit sphere or ellipse.
- * @param dstOff The offset of the location of the converted coordinate
that is stored in the destination array.
- * @param derivate {@code true} for computing the derivative, or {@code
false} if not needed.
- * @return The matrix of the projection derivative at the given source
position,
- * or {@code null} if the {@code derivate} argument is {@code
false}.
- * @throws ProjectionException if the coordinate can not be converted.
- */
- @Override
- public abstract Matrix transform(double[] srcPts, int srcOff, double[]
dstPts, int dstOff, boolean derivate)
- throws ProjectionException;
-
- /**
- * Inverse converts the single coordinate in {@code srcPts} at the given
offset and stores the result in
- * {@code ptDst} at the given offset. The output ordinates are
(<var>longitude</var>, <var>latitude</var>)
- * angles in radians, usually (but not necessarily) in the range [-π … π]
and [-π/2 … π/2] respectively.
- *
- * <div class="section">Normalization</div>
- * Input coordinate shall have the (<cite>false easting</cite>,
<cite>false northing</cite>) removed
- * by the caller and the result divided by the global <cite>scale
factor</cite> before this method is invoked.
- * After this method is invoked, the caller will need to add the
<cite>central meridian</cite> to the longitude
- * in the output coordinate. This means that projections that implement
this method are performed on a sphere
- * or ellipse having a semi-major axis of 1.
- *
- * <div class="note"><b>Note:</b> in <a
href="http://trac.osgeo.org/proj/">Proj.4</a>, the same standardization,
- * described above, is handled by {@code pj_inv.c}.</div>
- *
- * @param srcPts The array containing the source point coordinate, as
linear distance on a unit sphere or ellipse.
- * @param srcOff The offset of the point to be converted in the source
array.
- * @param dstPts The array into which the converted point coordinate is
returned (may be the same than {@code srcPts}).
- * Ordinates will be (<var>longitude</var>,
<var>latitude</var>) angles in <strong>radians</strong>.
- * @param dstOff The offset of the location of the converted point that is
stored in the destination array.
- * @throws ProjectionException if the point can not be converted.
- */
- protected abstract void inverseTransform(double[] srcPts, int srcOff,
double[] dstPts, int dstOff)
- throws ProjectionException;
-
- /**
- * Returns the inverse of this map projection.
- * Subclasses do not need to override this method, as they should override
- * {@link #inverseTransform(double[], int, double[], int)
inverseTransform(…)} instead.
- *
- * @return The inverse of this map projection.
- */
- @Override
- public MathTransform2D inverse() {
- return inverse;
- }
-
- /**
- * Inverse of a normalized map projection.
- *
- * @author Martin Desruisseaux (Geomatys)
- * @since 0.6
- * @version 0.6
- * @module
- */
- private final class Inverse extends AbstractMathTransform2D.Inverse {
- /**
- * For cross-version compatibility.
- */
- private static final long serialVersionUID = -9138242780765956870L;
-
- /**
- * Default constructor.
- */
- public Inverse() {
- NormalizedProjection.this.super();
- }
-
- /**
- * Inverse transforms the specified {@code srcPts} and stores the
result in {@code dstPts}.
- * If the derivative has been requested, then this method will
delegate the derivative
- * calculation to the enclosing class and inverts the resulting matrix.
- */
- @Override
- public Matrix transform(final double[] srcPts, final int srcOff,
- double[] dstPts, int dstOff,
- final boolean derivate) throws
TransformException
- {
- if (!derivate) {
- inverseTransform(srcPts, srcOff, dstPts, dstOff);
- return null;
- } else {
- if (dstPts == null) {
- dstPts = new double[2];
- dstOff = 0;
- }
- inverseTransform(srcPts, srcOff, dstPts, dstOff);
- return
Matrices.inverse(NormalizedProjection.this.transform(dstPts, dstOff, null, 0,
true));
- }
- }
- }
-
- /**
- * Computes a hash code value for this {@code NormalizedProjection}.
- *
- * @return The hash code value.
- */
- @Override
- protected int computeHashCode() {
- long c = Double.doubleToLongBits(excentricity);
- final double[] parameters = getInternalParameterValues();
- if (parameters != null) {
- for (int i=0; i<parameters.length; i++) {
- c = c*31 + Double.doubleToLongBits(parameters[i]);
- }
- }
- return super.computeHashCode() ^ Numerics.hashCode(c);
- }
-
- /**
- * 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.
- *
- * <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()
- * contextual parameters} used for creating the map projections are
irrelevant and do not need to be known.
- * Those projection parameters will be compared only if the comparison
mode is {@link ComparisonMode#STRICT}
- * or {@link ComparisonMode#BY_CONTRACT BY_CONTRACT}.</p>
- *
- * <div class="note"><b>Example:</b>
- * a {@linkplain Mercator Mercator} projection can be created in the 2SP
case with a <cite>standard parallel</cite>
- * value of 60°. The same projection can also be created in the 1SP case
with a <cite>scale factor</cite> of 0.5.
- * Nevertheless those two map projections applied on a sphere gives
identical results. Considering them as
- * equivalent allows the referencing module to transform coordinates
between those two projections more efficiently.
- * </div>
- *
- * @param object The object to compare with this map projection for
equivalence.
- * @param mode The strictness level of the comparison. Default to {@link
ComparisonMode#STRICT}.
- * @return {@code true} if the given object is equivalent to this map
projection.
- */
- @Override
- @SuppressWarnings("fallthrough")
- public boolean equals(final Object object, final ComparisonMode mode) {
- if (object == this) {
- return true;
- }
- if (!super.equals(object, mode)) {
- return false;
- }
- final NormalizedProjection that = (NormalizedProjection) object;
- switch (mode) {
- case STRICT:
- case BY_CONTRACT: {
- if (!Objects.equals(context, that.context)) {
- return false;
- }
- // Fall through for comparing the excentricity.
- }
- 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
- * original value from which the other value is derived.
- */
- if (!Numerics.equals(excentricitySquared,
that.excentricitySquared)) {
- 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:
- *
- * ℯ² = 1 - b²
- *
- * If we add a slight ε error to the semi-minor axis length
(where ε will be our linear tolerance
- * threshold), we get:
- *
- * (ℯ + ε′)² = 1 - (b + ε)² ≈ 1 - (b² + 2⋅b⋅ε)
assuming ε ≪ b
- *
- * Replacing 1 - b² by ℯ²:
- *
- * ℯ² + 2⋅ℯ⋅ε′ ≈ ℯ² - 2⋅b⋅ε
- *
- * After a few rearrangements:
- *
- * ε′ ≈ ε⋅(ℯ - 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.
- */
- final double e = max(excentricity, that.excentricity);
- if (!Numerics.epsilonEqual(excentricity, that.excentricity,
ANGULAR_TOLERANCE * (1/e - e))) {
- assert (mode != ComparisonMode.DEBUG) :
Numerics.messageForDifference(
- "excentricity", excentricity, that.excentricity);
- return false;
- }
- break;
- }
- }
- final double[] parameters = getInternalParameterValues();
- if (parameters != null) {
- /*
- * super.equals(…) guarantees that the two objects are of the same
class.
- * So in SIS implementation, this implies that the arrays have the
same length.
- */
- final double[] others = that.getInternalParameterValues();
- assert others.length == parameters.length;
- for (int i=0; i<parameters.length; i++) {
- if (!Numerics.epsilonEqual(parameters[i], others[i], mode)) {
- assert (mode != ComparisonMode.DEBUG) :
Numerics.messageForDifference(
- getInternalParameterNames()[i], parameters[i],
others[i]);
- return false;
- }
- }
- }
- return true;
- }
-
@@ -949,7 +231,21 @@ public abstract class NormalizedProjecti
* @param sinφ The sine of the φ latitude in radians.
* @return Reciprocal of the radius of curvature of the ellipsoid
perpendicular to the meridian at latitude φ.
*/
- final double rν(final double sinφ) {
- return sqrt(1 - excentricitySquared * (sinφ*sinφ));
+ final DoubleDouble rν(final double sinφ) {
+ /*
+ * Equivalent Java code:
+ *
+ * return sqrt(1 - excentricitySquared * (sinφ*sinφ));
+ */
+ final DoubleDouble t = new DoubleDouble(sinφ, 0);
+ t.multiply(t);
+ t.multiply(excentricitySquared);
+ final double value = t.value;
+ final double error = t.error;
+ t.clear();
+ t.value = 1;
+ t.subtract(value, error);
+ t.sqrt();
+ return t;
}
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java?rev=1693439&r1=1693438&r2=1693439&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
[UTF-8] Thu Jul 30 15:27:52 2015
@@ -16,7 +16,6 @@
*/
package org.apache.sis.referencing.operation.projection;
-import java.util.Map;
import java.util.EnumMap;
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterDescriptor;
@@ -123,13 +122,32 @@ public class LambertConicConformal exten
final double n;
/**
- * Returns the (<var>role</var> → <var>parameter</var>) associations for a
Lambert projection of the given variant.
+ * Creates a Lambert projection from the given parameters.
+ * The {@code method} argument can be the description of one of the
following:
+ *
+ * <ul>
+ * <li><cite>"Lambert Conic Conformal (1SP)"</cite>.</li>
+ * <li><cite>"Lambert Conic Conformal (West Orientated)"</cite>.</li>
+ * <li><cite>"Lambert Conic Conformal (2SP)"</cite>.</li>
+ * <li><cite>"Lambert Conic Conformal (2SP Belgium)"</cite>.</li>
+ * <li><cite>"Lambert Conic Conformal (2SP Michigan)"</cite>.</li>
+ * </ul>
*
- * @param variant One of {@link #SP1}, {@link #SP2}, {@link #WEST},
{@link #BELGIUM} and {@link #MICHIGAN} constants.
- * @return The roles map to give to super-class constructor.
+ * @param method Description of the projection parameters.
+ * @param parameters The parameter values of the projection to create.
+ */
+ public LambertConicConformal(final OperationMethod method, final
Parameters parameters) {
+ this(initializer(method, parameters));
+ }
+
+ /**
+ * Work around for RFE #4093999 in Sun's bug database
+ * ("Relax constraint on placement of this()/super() call in
constructors").
*/
@SuppressWarnings("fallthrough")
- private static Map<ParameterRole, ParameterDescriptor<Double>> roles(final
byte variant) {
+ @Workaround(library="JDK", version="1.7")
+ private static Initializer initializer(final OperationMethod method, final
Parameters parameters) {
+ final byte variant = getVariant(method);
final EnumMap<ParameterRole, ParameterDescriptor<Double>> roles = new
EnumMap<>(ParameterRole.class);
/*
* "Scale factor" is not formally a "Lambert Conformal (2SP)"
argument, but we accept it
@@ -166,26 +184,7 @@ public class LambertConicConformal exten
default: throw new AssertionError(variant);
}
roles.put(ParameterRole.SCALE_FACTOR, scaleFactor);
- return roles;
- }
-
- /**
- * Creates a Lambert projection from the given parameters.
- * The {@code method} argument can be the description of one of the
following:
- *
- * <ul>
- * <li><cite>"Lambert Conic Conformal (1SP)"</cite>.</li>
- * <li><cite>"Lambert Conic Conformal (West Orientated)"</cite>.</li>
- * <li><cite>"Lambert Conic Conformal (2SP)"</cite>.</li>
- * <li><cite>"Lambert Conic Conformal (2SP Belgium)"</cite>.</li>
- * <li><cite>"Lambert Conic Conformal (2SP Michigan)"</cite>.</li>
- * </ul>
- *
- * @param method Description of the projection parameters.
- * @param parameters The parameter values of the projection to create.
- */
- public LambertConicConformal(final OperationMethod method, final
Parameters parameters) {
- this(method, parameters, getVariant(method));
+ return new Initializer(method, parameters, roles, variant);
}
/**
@@ -193,17 +192,17 @@ public class LambertConicConformal exten
* ("Relax constraint on placement of this()/super() call in
constructors").
*/
@Workaround(library="JDK", version="1.7")
- private LambertConicConformal(final OperationMethod method, final
Parameters parameters, final byte type) {
- super(method, parameters, roles(type));
- double φ0 = getAndStore(parameters, ((type & 1) != 0) ? // Odd 'type'
are SP1, even 'type' are SP2.
+ private LambertConicConformal(final Initializer initializer) {
+ super(initializer);
+ double φ0 = initializer.getAndStore(((initializer.variant & 1) != 0) ?
// Odd 'type' are SP1, even 'type' are SP2.
LambertConformal1SP.LATITUDE_OF_ORIGIN :
LambertConformal2SP.LATITUDE_OF_FALSE_ORIGIN);
/*
* Standard parallels (SP) are defined only for the 2SP case, but we
look for them unconditionally
* in case the user gave us non-standard parameters. For the 1SP case,
or for the 2SP case left to
* their default values, EPSG says that we shall use the latitude of
origin as the SP.
*/
- double φ1 = getAndStore(parameters,
LambertConformal2SP.STANDARD_PARALLEL_1, φ0);
- double φ2 = getAndStore(parameters,
LambertConformal2SP.STANDARD_PARALLEL_2, φ1);
+ double φ1 =
initializer.getAndStore(LambertConformal2SP.STANDARD_PARALLEL_1, φ0);
+ double φ2 =
initializer.getAndStore(LambertConformal2SP.STANDARD_PARALLEL_2, φ1);
if (abs(φ1 + φ2) < Formulas.ANGULAR_TOLERANCE) {
/*
* We can not allow that because if φ1 = -φ2, then n = 0 and the
equations
@@ -248,33 +247,60 @@ public class LambertConicConformal exten
* since rν(sinφ) = 1 and expOfNorthing(φ) = tan(π/4 + φ/2) when the
excentricity is zero.
* However we need special formulas for φ1 ≈ φ2 in the calculation of
n, otherwise we got
* a 0/0 indetermination.
+ *
+ * Opportunistically use double-double arithmetic below since this is
what we will store in the
+ * (de)normalization matrices. The extra precision that we get is not
necessarily significant,
+ * but we do that more in an attempt to reduce rounding errors in
concatenations of a sequence
+ * of MathTransforms (through matrix multiplications) than for map
projection precisions.
+ * Equivalent Java code for the following double-double arithmetic:
+ *
+ * final double m1 = cos(φ1) / rν(sinφ1);
*/
final double sinφ1 = sin(φ1);
- final double m1 = cos(φ1) / rν(sinφ1);
- final double t1 = expOfNorthing(φ1, excentricity*sinφ1);
+ final DoubleDouble m1 = initializer.rν(sinφ1);
+ m1.inverseDivide(cos(φ1), 0);
+ final double t1 = expOfNorthing(φ1, excentricity*sinφ1);
/*
* Computes n = (ln m₁ – ln m₂) / (ln t₁ – ln t₂), which we rewrite as
ln(m₁/m₂) / ln(t₁/t₂)
* since division is less at risk of precision lost than subtraction.
Note that this equation
* tends toward 0/0 if φ₁ ≈ φ₂, which force us to do a special check
for the SP1 case.
+ *
+ * Equivalent Java code for the following double-double arithmetic:
+ *
+ * final double sinφ2 = sin(φ2);
+ * final double m2 = cos(φ2) / rν(sinφ2);
+ * final double t2 = expOfNorthing(φ2, excentricity*sinφ2);
+ * n = log(m1/m2) / log(t1/t2); // Tend toward 0/0 if φ1 ≈ φ2.
*/
+ final DoubleDouble F = new DoubleDouble();
if (abs(φ1 - φ2) >= ANGULAR_TOLERANCE) { // Should be 'true' for 2SP
case.
final double sinφ2 = sin(φ2);
- final double m2 = cos(φ2) / rν(sinφ2);
+ final DoubleDouble m2 = initializer.rν(sinφ2);
+ m2.inverseDivide(cos(φ2), 0);
final double t2 = expOfNorthing(φ2, excentricity*sinφ2);
- n = log(m1/m2) / log(t1/t2); // Tend toward 0/0 if φ1 ≈ φ2.
+ m2.inverseDivide(m1);
+ F.value = log(m2.value);
+ F.divide(log(t1/t2), 0);
} else {
- n = -sinφ1;
+ F.value = -sinφ1;
+ }
+ n = F.value;
+ /*
+ * Scale factor for longitudes, stored now before we modify the F
value.
+ */
+ final DoubleDouble sx = new DoubleDouble(F);
+ if (!isNorth) {
+ sx.negate();
}
/*
* Computes F = m₁/(n⋅t₁ⁿ) from Geomatics Guidance Note number 7.
- * Following constants will be stored in the denormalization matrix,
to be applied after
- * the non-linear formulas implemented by this LambertConicConformal
class. Opportunistically
- * use double-double arithmetic since we the matrix coefficients will
be stored in this
- * format anyway. This makes a change in the 2 or 3 last digits.
+ * Following constants will be stored in the denormalization matrix,
to be applied
+ * after the non-linear formulas implemented by this
LambertConicConformal class.
+ * Opportunistically use double-double arithmetic since the matrix
coefficients will
+ * be stored in that format anyway. This makes a change in the 2 or 3
last digits.
*/
- final DoubleDouble F = new DoubleDouble(n, 0);
F.multiply(pow(t1, n), 0);
- F.inverseDivide(m1, 0);
+ F.inverseDivide(m1);
if (!isNorth) {
F.negate();
}
@@ -287,7 +313,7 @@ public class LambertConicConformal exten
* EPSG uses this term in the computation of y = FN + rF – r⋅cos(θ).
*/
final DoubleDouble rF = new DoubleDouble(); // Initialized to zero.
- if (φ0 != copySign(PI/2, -n)) { // For avoiding the rounding error
documented in expOfNorthing(+π/2).
+ if (φ0 != copySign(PI/2, -n)) { // For reducing the rounding error
documented in expOfNorthing(+π/2).
rF.value = pow(expOfNorthing(φ0, excentricity*sin(φ0)), n);
rF.multiply(F);
}
@@ -309,8 +335,7 @@ public class LambertConicConformal exten
* - Add false easting and false northing (done by the super-class
constructor).
*/
final MatrixSIS normalize = context.getMatrix(true);
- normalize.convertAfter(0, new DoubleDouble(isNorth ? n : -n, 0), //
Multiplication factor for longitudes.
- (type == BELGIUM) ? new DoubleDouble(-BELGE_A, 0) : null); //
Longitude translation for Belgium.
+ normalize.convertAfter(0, sx, (initializer.variant == BELGIUM) ? new
DoubleDouble(-BELGE_A, 0) : null);
if (isNorth) {
normalize.convertAfter(1, new DoubleDouble(-1, 0), null);
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java?rev=1693439&r1=1693438&r2=1693439&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
[UTF-8] Thu Jul 30 15:27:52 2015
@@ -16,7 +16,6 @@
*/
package org.apache.sis.referencing.operation.projection;
-import java.util.Map;
import java.util.EnumMap;
import org.opengis.util.FactoryException;
import org.opengis.parameter.ParameterDescriptor;
@@ -125,13 +124,33 @@ public class Mercator extends ConformalP
private final byte variant;
/**
- * Returns the (<var>role</var> → <var>parameter</var>) associations for a
Mercator projection of the given variant.
+ * Creates a Mercator projection from the given parameters.
+ * The {@code method} argument can be the description of one of the
following:
+ *
+ * <ul>
+ * <li><cite>"Mercator (variant A)"</cite>, also known as
<cite>"Mercator (1SP)"</cite>.</li>
+ * <li><cite>"Mercator (variant B)"</cite>, also known as
<cite>"Mercator (2SP)"</cite>.</li>
+ * <li><cite>"Mercator (variant C)"</cite>.</li>
+ * <li><cite>"Mercator (Spherical)"</cite>.</li>
+ * <li><cite>"Popular Visualisation Pseudo Mercator"</cite>.</li>
+ * <li><cite>"Miller Cylindrical"</cite>.</li>
+ * </ul>
*
- * @param variant One of {@link #REGIONAL}, {@link #SPHERICAL}, {@link
#PSEUDO} or {@link #MILLER} constants.
- * @return The roles map to give to super-class constructor.
+ * @param method Description of the projection parameters.
+ * @param parameters The parameter values of the projection to create.
+ */
+ public Mercator(final OperationMethod method, final Parameters parameters)
{
+ this(initializer(method, parameters));
+ }
+
+ /**
+ * Work around for RFE #4093999 in Sun's bug database
+ * ("Relax constraint on placement of this()/super() call in
constructors").
*/
@SuppressWarnings("fallthrough")
- private static Map<ParameterRole, ParameterDescriptor<Double>> roles(final
byte variant) {
+ @Workaround(library="JDK", version="1.7")
+ private static Initializer initializer(final OperationMethod method, final
Parameters parameters) {
+ final byte variant = getVariant(method);
final EnumMap<ParameterRole, ParameterDescriptor<Double>> roles = new
EnumMap<>(ParameterRole.class);
/*
* "Longitude of origin" is a parameter of all Mercator projections,
but is intentionally omitted from
@@ -171,27 +190,7 @@ public class Mercator extends ConformalP
break;
}
}
- return roles;
- }
-
- /**
- * Creates a Mercator projection from the given parameters.
- * The {@code method} argument can be the description of one of the
following:
- *
- * <ul>
- * <li><cite>"Mercator (variant A)"</cite>, also known as
<cite>"Mercator (1SP)"</cite>.</li>
- * <li><cite>"Mercator (variant B)"</cite>, also known as
<cite>"Mercator (2SP)"</cite>.</li>
- * <li><cite>"Mercator (variant C)"</cite>.</li>
- * <li><cite>"Mercator (Spherical)"</cite>.</li>
- * <li><cite>"Popular Visualisation Pseudo Mercator"</cite>.</li>
- * <li><cite>"Miller Cylindrical"</cite>.</li>
- * </ul>
- *
- * @param method Description of the projection parameters.
- * @param parameters The parameter values of the projection to create.
- */
- public Mercator(final OperationMethod method, final Parameters parameters)
{
- this(method, parameters, getVariant(method));
+ return new Initializer(method, parameters, roles, variant);
}
/**
@@ -199,15 +198,15 @@ public class Mercator extends ConformalP
* ("Relax constraint on placement of this()/super() call in
constructors").
*/
@Workaround(library="JDK", version="1.7")
- private Mercator(final OperationMethod method, final Parameters
parameters, final byte variant) {
- super(method, parameters, roles(variant));
- this.variant = variant;
+ private Mercator(final Initializer initializer) {
+ super(initializer);
+ this.variant = initializer.variant;
/*
* The "Longitude of natural origin" parameter is found in all
Mercator projections and is mandatory.
* Since this is usually the Greenwich meridian, the default value is
0°. We keep the value in degrees
* for now; it will be converted to radians later.
*/
- final double λ0 = getAndStore(parameters,
Mercator1SP.LONGITUDE_OF_ORIGIN);
+ final double λ0 =
initializer.getAndStore(Mercator1SP.LONGITUDE_OF_ORIGIN);
/*
* The "Latitude of natural origin" is not formally a parameter of
Mercator projection. But the parameter
* is included for completeness in CRS labelling, with the restriction
(specified in EPSG documentation)
@@ -220,7 +219,7 @@ public class Mercator extends ConformalP
* "Latitude of origin" can not have a non-zero value, if it still
have non-zero value we will process as
* for "Latitude of false origin".
*/
- final double φ0 = toRadians(getAndStore(parameters, (variant ==
REGIONAL)
+ final double φ0 = toRadians(initializer.getAndStore((variant ==
REGIONAL)
? RegionalMercator.LATITUDE_OF_FALSE_ORIGIN :
Mercator1SP.LATITUDE_OF_ORIGIN));
/*
* In theory, the "Latitude of 1st standard parallel" and the "Scale
factor at natural origin" parameters
@@ -228,9 +227,9 @@ public class Mercator extends ConformalP
* the later is for projections "1SP" (namely variant A and
spherical). However we let users specify both
* if they really want, since we sometime see such CRS definitions.
*/
- final double φ1 = toRadians(getAndStore(parameters,
Mercator2SP.STANDARD_PARALLEL));
+ final double φ1 =
toRadians(initializer.getAndStore(Mercator2SP.STANDARD_PARALLEL));
final DoubleDouble k0 = new DoubleDouble(cos(φ1), 0);
- k0.divide(rν(sin(φ1)), 0);
+ k0.divide(initializer.rν(sin(φ1)));
/*
* In principle we should rotate the central meridian (λ0) in the
normalization transform, as below:
*
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1693439&r1=1693438&r2=1693439&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
[UTF-8] Thu Jul 30 15:27:52 2015
@@ -41,16 +41,13 @@ import org.apache.sis.referencing.operat
import org.apache.sis.referencing.operation.matrix.MatrixSIS;
import org.apache.sis.referencing.operation.transform.AbstractMathTransform2D;
import org.apache.sis.referencing.operation.transform.ContextualParameters;
-import org.apache.sis.internal.referencing.provider.MapProjection;
import org.apache.sis.internal.referencing.Formulas;
import org.apache.sis.internal.util.CollectionsExt;
-import org.apache.sis.internal.util.DoubleDouble;
import org.apache.sis.internal.util.Constants;
import org.apache.sis.internal.util.Utilities;
import org.apache.sis.internal.util.Numerics;
import static java.lang.Math.*;
-import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
// Branch-dependent imports
import java.util.Objects;
@@ -402,58 +399,19 @@ public abstract class NormalizedProjecti
protected NormalizedProjection(final OperationMethod method, final
Parameters parameters,
final Map<ParameterRole, ? extends ParameterDescriptor<Double>>
roles)
{
- ensureNonNull("method", method);
- ensureNonNull("parameters", parameters);
- ensureNonNull("roles", roles);
- context = new ContextualParameters(method);
- /*
- * Note: we do not use Map.getOrDefault(K,V) below because the user
could have explicitly associated
- * a null value to keys (we are paranoiac...) and because it conflicts
with the "? extends" part of
- * in this constructor signature.
- */
- ParameterDescriptor<Double> semiMajor =
roles.get(ParameterRole.SEMI_MAJOR);
- ParameterDescriptor<Double> semiMinor =
roles.get(ParameterRole.SEMI_MINOR);
- if (semiMajor == null) semiMajor = MapProjection.SEMI_MAJOR;
- if (semiMinor == null) semiMinor = MapProjection.SEMI_MINOR;
-
- double a = getAndStore(parameters, semiMajor);
- final double b = getAndStore(parameters, semiMinor);
- final double λ0 = getAndStore(parameters,
roles.get(ParameterRole.CENTRAL_MERIDIAN));
- final double fe = getAndStore(parameters,
roles.get(ParameterRole.FALSE_EASTING))
- - getAndStore(parameters,
roles.get(ParameterRole.FALSE_WESTING));
- final double fn = getAndStore(parameters,
roles.get(ParameterRole.FALSE_NORTHING))
- - getAndStore(parameters,
roles.get(ParameterRole.FALSE_SOUTHING));
- final double rs = b / a;
- excentricitySquared = 1 - (rs * rs);
- excentricity = sqrt(excentricitySquared);
- if (excentricitySquared != 0) {
- final ParameterDescriptor<Double> radius =
roles.get(ParameterRole.LATITUDE_OF_CONFORMAL_SPHERE_RADIUS);
- if (radius != null) {
- /*
- * EPSG said: R is the radius of the sphere and will normally
be one of the CRS parameters.
- * If the figure of the earth used is an ellipsoid rather than
a sphere then R should be calculated
- * as the radius of the conformal sphere at the projection
origin at latitude φ₀ using the formula
- * for Rc given in section 1.2, table 3.
- *
- * Table 3 gives:
- * Radius of conformal sphere Rc = a √(1 – ℯ²) / (1 – ℯ²⋅sin²φ)
- *
- * Using √(1 – ℯ²) = b/a we rewrite as: Rc = b / (1 – ℯ²⋅sin²φ)
- */
- final double sinφ =
sin(toRadians(parameters.doubleValue(radius)));
- a = b / (1 - excentricitySquared * (sinφ*sinφ));
- }
- }
- context.normalizeGeographicInputs(λ0);
- final DoubleDouble k = new DoubleDouble(a);
- final ParameterDescriptor<Double> scaleFactor =
roles.get(ParameterRole.SCALE_FACTOR);
- if (scaleFactor != null) {
- k.multiply(getAndStore(parameters, scaleFactor));
- }
- final MatrixSIS denormalize = context.getMatrix(false);
- denormalize.convertAfter(0, k, new DoubleDouble(fe));
- denormalize.convertAfter(1, k, new DoubleDouble(fn));
- inverse = new Inverse();
+ this(new Initializer(method, parameters, roles, (byte) 0));
+ }
+
+ /**
+ * Creates a new normalized projection from the parameters computed by the
given initializer.
+ *
+ * @param initializer The initializer for computing map projection
internal parameters.
+ */
+ NormalizedProjection(final Initializer initializer) {
+ context = initializer.context;
+ excentricitySquared = initializer.excentricitySquared.value;
+ excentricity = sqrt(excentricitySquared);
+ inverse = new Inverse();
}
/**
@@ -497,50 +455,6 @@ public abstract class NormalizedProjecti
}
/**
- * Gets a parameter value identified by the given descriptor and stores it
in the {@link #context}.
- * A "contextual parameter" is a parameter that apply to the normalize →
{@code this} → denormalize
- * chain as a whole. It does not really apply to this {@code
NormalizedProjection} instance when taken alone.
- *
- * <p>This method performs the following actions:</p>
- * <ul>
- * <li>Convert the value to the units specified by the descriptor.</li>
- * <li>Ensure that the value is contained in the range specified by the
descriptor.</li>
- * <li>Store the value only if different than the default value.</li>
- * </ul>
- *
- * This method shall be invoked at construction time only.
- */
- final double getAndStore(final Parameters parameters, final
ParameterDescriptor<Double> descriptor) {
- if (descriptor == null) {
- return 0; // Default value for all parameters except scale
factor.
- }
- final double value = parameters.doubleValue(descriptor); // Apply a
unit conversion if needed.
- final Double defaultValue = descriptor.getDefaultValue();
- if (defaultValue == null || !defaultValue.equals(value)) {
- MapProjection.validate(descriptor, value);
- context.getOrCreate(descriptor).setValue(value);
- }
- return value;
- }
-
- /**
- * Same as {@link #getAndStore(Parameters, ParameterDescriptor)}, but
returns the given default value
- * if the parameter is not specified. This method shall be used only for
parameters having a default
- * value more complex than what we can represent in {@link
ParameterDescriptor#getDefaultValue()}.
- */
- final double getAndStore(final Parameters parameters, final
ParameterDescriptor<Double> descriptor,
- final double defaultValue)
- {
- final Double value = parameters.getValue(descriptor); // Apply a
unit conversion if needed.
- if (value == null) {
- return defaultValue;
- }
- MapProjection.validate(descriptor, value);
- context.parameter(descriptor.getName().getCode()).setValue(value);
- return value;
- }
-
- /**
* Returns the sequence of <cite>normalization</cite> → {@code this} →
<cite>denormalization</cite> transforms
* as a whole. The transform returned by this method except
(<var>longitude</var>, <var>latitude</var>)
* coordinates in <em>degrees</em> and returns (<var>x</var>,<var>y</var>)
coordinates in <em>metres</em>.
@@ -915,41 +829,4 @@ public abstract class NormalizedProjecti
}
return true;
}
-
-
-
-
-
//////////////////////////////////////////////////////////////////////////////////////////
- ////////
////////
- //////// FORMULAS FROM EPSG or SNYDER
////////
- ////////
////////
-
//////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Computes the reciprocal of the radius of curvature of the ellipsoid
perpendicular to the meridian at latitude φ.
- * That radius of curvature is:
- *
- * <blockquote>ν = 1 / √(1 - ℯ²⋅sin²φ)</blockquote>
- *
- * This method returns 1/ν.
- *
- * <div class="section">Relationship with Snyder</div>
- * This is related to functions (14-15) from Snyder (used for computation
of scale factors
- * at the true scale latitude) as below:
- *
- * <blockquote>m = cosφ / rν</blockquote>
- *
- * Special cases:
- * <ul>
- * <li>If φ is 0°, then <var>m</var> is 1.</li>
- * <li>If φ is ±90°, then <var>m</var> is 0 provided that we are not in
the spherical case
- * (otherwise we get {@link Double#NaN}).</li>
- * </ul>
- *
- * @param sinφ The sine of the φ latitude in radians.
- * @return Reciprocal of the radius of curvature of the ellipsoid
perpendicular to the meridian at latitude φ.
- */
- final double rν(final double sinφ) {
- return sqrt(1 - excentricitySquared * (sinφ*sinφ));
- }
}