Class Formulas

java.lang.Object
org.apache.sis.util.Static
org.apache.sis.internal.referencing.Formulas

public final class Formulas extends Static
Miscellaneous numerical utilities which should not be put in public API. This class contains methods that depend on hard-coded arbitrary tolerance threshold, and we do not want to expose publicly those arbitrary values (or at least not in a too direct way).
Since:
0.4
Version:
1.3
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final double
    Default tolerance threshold for comparing coordinate values in a geographic CRS, assuming that the unit of measurement is decimal degrees and using the standard nautical mile length.
    static final long
    The length of a Julian year in milliseconds.
    static final double
    Default tolerance threshold for comparing coordinate values in a projected CRS, assuming that the unit of measurement is metre.
    static final double
    The maximal longitude value before normalization if a centimetric precision is desired.
    static final int
    Maximum number of iterations for iterative computations.
    static final double
    Default tolerance threshold for comparing coordinate values in temporal CRS, assuming that the unit of measurement is second.
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
    private
    Do not allow instantiation of this class.
  • Method Summary

    Modifier and Type
    Method
    Description
    static double
    fastHypot(double x, double y)
    Returns sqrt(x² + y²) for coordinate values on an ellipsoid of semi-major axis length of 1.
    static double
    getAuthalicRadius(double a, double b)
    Returns the radius of a hypothetical sphere having the same surface than the ellipsoid specified by the given axis length.
    static double
    getAuthalicRadius(org.opengis.referencing.datum.Ellipsoid ellipsoid)
    Returns the radius of a hypothetical sphere having the same surface than the given ellipsoid.
    static double
    getInverseFlattening(double semiMajorAxis, double semiMinorAxis)
    Computes the inverse flattening factor from the given axis lengths.
    static double
    getRadius(org.opengis.referencing.datum.Ellipsoid ellipsoid, double φ)
    Returns the radius at the given latitude.
    static double
    getSemiMinor(double semiMajorAxis, double inverseFlattening)
    Computes the semi-minor axis length from the given semi-major axis and inverse flattening factor.
    static boolean
    isPoleToPole(double ymin, double ymax)
    Returns true if ymin is the south pole and ymax is the north pole.
    static double
    radiusOfConformalSphere(org.opengis.referencing.datum.Ellipsoid ellipsoid, double φ)
    Returns the radius of the conformal sphere at a given latitude.
    static double
    scaleComparedToEarth(org.opengis.referencing.datum.Ellipsoid planet)
    Returns the size of a planet described by the given ellipsoid compared to earth.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • LINEAR_TOLERANCE

      public static final double LINEAR_TOLERANCE
      Default tolerance threshold for comparing coordinate values in a projected CRS, assuming that the unit of measurement is metre. This constant determines also (indirectly) the minimum accuracy of iterative methods in map projections.

      Maintenance

      If this value is modified, then all usages of this constant should be verified. Some usages may need to be compensated. For example, GeodesicsOnEllipsoid uses a millimetric precision by dividing the tolerance by 10 or more. We way want to keep the same precision there even if LINEAR_TOLERANCE was made smaller.
      See Also:
    • ANGULAR_TOLERANCE

      public static final double ANGULAR_TOLERANCE
      Default tolerance threshold for comparing coordinate values in a geographic CRS, assuming that the unit of measurement is decimal degrees and using the standard nautical mile length.

      For a LINEAR_TOLERANCE of 1 centimetre, this is slightly less than 1E-7°.

      See Also:
    • TEMPORAL_TOLERANCE

      public static final double TEMPORAL_TOLERANCE
      Default tolerance threshold for comparing coordinate values in temporal CRS, assuming that the unit of measurement is second. Current value is arbitrary and may change in any future Apache SIS version.
      See Also:
    • LONGITUDE_MAX

      public static final double LONGITUDE_MAX
      The maximal longitude value before normalization if a centimetric precision is desired. This is about 4×10⁸ degrees.
      See Also:
    • JULIAN_YEAR_LENGTH

      public static final long JULIAN_YEAR_LENGTH
      The length of a Julian year in milliseconds. From Wikipedia, "In astronomy, a Julian year (symbol: a) is a unit of measurement of time defined as exactly 365.25 days of 86,400 SI seconds each.".
      See Also:
    • MAXIMUM_ITERATIONS

      public static final int MAXIMUM_ITERATIONS
      Maximum number of iterations for iterative computations. Defined in this Formulas class as a default value, but some classes may use a derived value (for example twice this amount). This constant is mostly useful for identifying places where iterations occur.

      Current value has been determined empirically for allowing GeodesicsOnEllipsoidTest to pass.

      See Also:
  • Constructor Details

    • Formulas

      private Formulas()
      Do not allow instantiation of this class.
  • Method Details

    • isPoleToPole

      public static boolean isPoleToPole(double ymin, double ymax)
      Returns true if ymin is the south pole and ymax is the north pole.
      Parameters:
      ymin - the minimal latitude to test.
      ymax - the maximal latitude to test.
      Returns:
      true if the given latitudes are south pole to north pole respectively.
    • scaleComparedToEarth

      public static double scaleComparedToEarth(org.opengis.referencing.datum.Ellipsoid planet)
      Returns the size of a planet described by the given ellipsoid compared to earth. This method returns a ratio of given planet authalic radius compared to WGS84. This can be used for adjusting LINEAR_TOLERANCE and ANGULAR_TOLERANCE to another planet.
      Parameters:
      planet - ellipsoid of the other planet to compare to Earth, or null.
      Returns:
      ratio of planet authalic radius on WGS84 authalic radius, or NaN if the given ellipsoid is null.
    • getAuthalicRadius

      public static double getAuthalicRadius(org.opengis.referencing.datum.Ellipsoid ellipsoid)
      Returns the radius of a hypothetical sphere having the same surface than the given ellipsoid.
      Parameters:
      ellipsoid - the ellipsoid for which to get the radius, or null.
      Returns:
      the authalic radius, or Double.NaN if the given ellipsoid is null.
    • getAuthalicRadius

      public static double getAuthalicRadius(double a, double b)
      Returns the radius of a hypothetical sphere having the same surface than the ellipsoid specified by the given axis length.
      Parameters:
      a - the semi-major axis length.
      b - the semi-minor axis length.
      Returns:
      the radius of a sphere having the same surface than the specified ellipsoid.
      See Also:
    • radiusOfConformalSphere

      public static double radiusOfConformalSphere(org.opengis.referencing.datum.Ellipsoid ellipsoid, double φ)
      Returns the radius of the conformal sphere at a given latitude. The radius of conformal sphere is computed as below:
      Rc = √(1 – ℯ²) / (1 – ℯ²sin²φ) where ℯ² = 1 - (b/a)²
      This is a function of latitude and therefore not constant.
      Parameters:
      ellipsoid - the ellipsoid for which to compute the radius of conformal sphere.
      φ - the latitude in radians where to compute the radius of conformal sphere.
      Returns:
      radius of the conformal sphere at latitude φ.
    • getRadius

      public static double getRadius(org.opengis.referencing.datum.Ellipsoid ellipsoid, double φ)
      Returns the radius at the given latitude.
      Parameters:
      ellipsoid - the ellipsoid for which to compute the radius.
      φ - the latitude in radians where to compute the radius.
      Returns:
      radius at latitude φ.
    • getSemiMinor

      public static double getSemiMinor(double semiMajorAxis, double inverseFlattening)
      Computes the semi-minor axis length from the given semi-major axis and inverse flattening factor.
      Parameters:
      semiMajorAxis - the semi-major axis length.
      inverseFlattening - the inverse flattening factor.
      Returns:
      the semi-minor axis length.
    • getInverseFlattening

      public static double getInverseFlattening(double semiMajorAxis, double semiMinorAxis)
      Computes the inverse flattening factor from the given axis lengths.
      Parameters:
      semiMajorAxis - the semi-major axis length.
      semiMinorAxis - the semi-minor axis length.
      Returns:
      the inverse flattening factor.
    • fastHypot

      public static double fastHypot(double x, double y)
      Returns sqrt(x² + y²) for coordinate values on an ellipsoid of semi-major axis length of 1. This method does not provides the accuracy guarantees offered by Math.hypot(double, double). However for values close to 1, this approximation seems to stay within 1 ULP of Math.hypot(…). We tested with random values in ranges up to [-6 … +6].

      We define this method because Math.hypot(double, double) has been measured with JMH as 6 times slower than Math.sqrt(double) on Java 14. According posts on internet, the same performance cost is observed in C/C++ too. Despite its cost, hypot(…) is generally recommended because computing a hypotenuse from large magnitudes has accuracy problems. But in the context of NormalizedProjection where semi-axis lengths are close to 1, input values should be (x,y) coordinates in the [−1 … +1] range. The actual range may be greater (e.g. [−5 … +5]), but it still far from ranges requiring protection against overflow.

      Caution

      We may not need the full Math.hypot(x,y) accuracy in the context of map projections on ellipsoids. However, some projection formulas require that fastHypot(x,y) ≥ max(|x|,|y|), otherwise normalizations such as x/hypot(x,y) could result in values larger than 1, which in turn result in Double.NaN when given to Math.asin(double). The assumption on x, y and sqrt(x²+y²) relative magnitude is broken when x=0 and |y| ≤ 1.4914711209038602E-154 or conversely. This method does not check for such cases; it is caller responsibility to add this check is necessary, for example as below: According JMH, above check is 1.65 time slower than fastHypot without checks. We define this fastHypot(…) method for tracing where sqrt(x² + y²) is used, so we can verify if it is used in context where the inaccuracy is acceptable.

      When to use

      We reserve this method to ellipsoidal formulas where approximations are used anyway. Implementations using exact formulas, such as spherical formulas, should use Math.hypot(double, double) for its accuracy.
      Parameters:
      x - one side of the triangle. Should be approximately in the [-1 … +1] range.
      y - other side of the triangle. Should be approximately in the [-1 … +1] range.
      Returns:
      hypotenuse, not smaller than max(|x|,|y|) unless the values are less than 1.5E-154.
      See Also: