All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cts.datum.Ellipsoid Maven / Gradle / Ivy

Go to download

Coordinate Transformation Suite (abridged CTS) is a library developed to perform coordinate transformations using well known geodetic algorithms and parameter sets. It strives to be simple, flexible and interoperable, in this order.

There is a newer version: 1.7.1
Show newest version
/*
 * Coordinate Transformations Suite (abridged CTS)  is a library developped to 
 * perform Coordinate Transformations using well known geodetic algorithms 
 * and parameter sets. 
 * Its main focus are simplicity, flexibility, interoperability, in this order.
 *
 * This library has been originally developed by Michaël Michaud under the JGeod
 * name. It has been renamed CTS in 2009 and shared to the community from 
 * the OrbisGIS code repository.
 *
 * CTS is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License.
 *
 * CTS is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * CTS. If not, see .
 *
 * For more information, please consult: 
 */

package org.cts.datum;

import static java.lang.Math.abs;
import static java.lang.Math.atan;
import static java.lang.Math.exp;
import static java.lang.Math.log;
import static java.lang.Math.pow;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;
import static java.lang.Math.tan;

import java.util.HashMap;
import java.util.Map;

import org.cts.Identifiable;
import org.cts.IdentifiableComponent;
import org.cts.Identifier;

/**
 * An ellipsoid is a mathematical surface used to describe the Earth surface.

* It is only an approximation of the Earth surface, but it is used as a * reference surface for the expression of coordinates as a latitude and a * longitude.

The definition of an ellipsoid is based on two parameters : *

  • 1st parameter = semi-major axis
  • 2nd parameter = inverse * flattening, semi-minor axis or eccentricity. The parameter type is choosen * among the values of SecondParameter enum.

Note on the * precision of some algorithms :

  • The calculation of semi-minor * axis, inverse flattening and eccentricity are precise. For example, the * construction of 10 successive ellipsoids using alternatively the 3 parameters * keeps a precision of less than 0.01 micron for the semi-minor axis
  • *
  • Default curvilinearAbscissa method or arcFromLat method using parameters * computed from 4, 5 or 6 iteration (see initKCoeff) give consistant results at * a precision of 1 micron (1E-6).
* * @author Michaël Michaud, Jules Party */ public class Ellipsoid extends IdentifiableComponent { /** * The second parameter use to create the ellipsoid, this parameter can be * the inverse flattening, the semi-minor axis or the eccentricity. */ public static enum SecondParameter { InverseFlattening, SemiMinorAxis, Eccentricity }; /** * The double value of PI/2. */ private static final double PI_2 = Math.PI / 2.; /** * Perfect SPHERE. */ public static final Ellipsoid SPHERE = createEllipsoidFromSemiMinorAxis( new Identifier("EPSG", "7035", "SPHERE"), 6371000.0, 6371000.0); /** * GRS 1980 ellipsoid, used in most recent spatial geodetic system (1990 and * after). */ public static final Ellipsoid GRS80 = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7019", "GRS 1980", "GRS80"), 6378137.0, 298.257222101); /** * WGS84 ellipsoid, used with the WGS84 spatial geodetic datum. This * ellipsoid (and datum) is coherent with GRS80 and the ITRS. */ public static final Ellipsoid WGS84 = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7030", "WGS 84", "WGS84"), 6378137.0, 298.257223563); /** * International 1924. */ public static final Ellipsoid INTERNATIONAL1924 = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7022", "Intenational 1924", "Int_1924"), 6378388, 297); /** * Bessel 1841. */ public static final Ellipsoid BESSEL1841 = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7004", "Bessel 1841", "Bessel_1841"), 6377397.155, 299.1528128); /** * Clarke 1866. */ public static final Ellipsoid CLARKE1866 = createEllipsoidFromSemiMinorAxis( new Identifier("EPSG", "7008", "Clarke 1866", "Clarke_1866"), 6378206.4, 6356583.8); /** * Clarke 1880 (IGN). */ public static final Ellipsoid CLARKE1880IGN = createEllipsoidFromSemiMinorAxis( new Identifier("EPSG", "7011", "Clarke 1880 (IGN)", "Clarke_1880_IGN"), 6378249.2, 6356515.0); //public static final Ellipsoid CLARKE1880IGN = createEllipsoidFromInverseFlattening( // new Identifier("EPSG", "7011", "Clarke 1880 (IGN)", "Clarke_1880_IGN"), 6378249.2, 293.466021); /** * Clarke 1880 (RGS) or Clarke 1880 modified. */ public static final Ellipsoid CLARKE1880RGS = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7012", "Clarke 1880 (RGS)", "Clarke_1880_mod"), 6378249.2, 293.465); /** * Clarke 1880 (Arc). Note that the ellipsoid called clrk80 in the proj * library is defined as the Clarke 1880 mod. (modified) which is refered as * the Clarke 1880 (RGS) in the epsg database, with an inverse flattening * parameter of 293.465 instead of 293.466 */ public static final Ellipsoid CLARKE1880ARC = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7013", "Clarke 1880 (Arc)", "Clarke_1880_Arc"), 6378249.145, 293.4663077); /** * Krassowski 1940. */ public static final Ellipsoid KRASSOWSKI = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7024", "Krassowski 1940", "Krassowski_1940"), 6378245.0, 298.3); /** * Everest 1830 (1967 definition). */ public static final Ellipsoid EVERESTSS = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7016", "Everest 1830 (1967 Definition)", "evrstSS"), 6377298.556, 300.8017); /** * GRS 1967 ellipsoid, used in Australian Geodetic Datum and in South * American Datum 1969. */ public static final Ellipsoid GRS67 = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7036", "GRS 1967", "GRS67"), 6378160, 298.247167427); /** * GRS 1967 (SAD 1969) ellipsoid, used in Australian Geodetic Datum and in * South American Datum 1969. */ public static final Ellipsoid AustSA = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7050", "GRS 1967 (SAD 1969)", "aust_SA"), 6378160, 298.25); /** * Airy 1830. */ public static final Ellipsoid AIRY = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7001", "AIRY 1830", "airy"), 6377563.396, 299.3249646); /** * Bessel Namibia (GLM). */ public static final Ellipsoid BESSNAM = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7046", "Bessel Namibia (GLM)", "bess_nam"), 6377483.865280419, 299.1528128); /** * Helmert 1906. */ public static final Ellipsoid HELMERT = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7020", "Helmert 1906", "helmert"), 6378200, 298.3); /** * Airy Modified 1849. */ public static final Ellipsoid AIRYMOD = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7002", "Airy Modified 1849", "mod_airy"), 6377340.189, 299.3249646); /** * WGS 66. */ public static final Ellipsoid WGS66 = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7025", "WGS 66", "WGS66"), 6378145, 298.25); /** * WGS 72. */ public static final Ellipsoid WGS72 = createEllipsoidFromInverseFlattening( new Identifier("EPSG", "7043", "WGS 72", "WGS72"), 6378135, 298.26); /** * The SecondParameters used to create this Ellipsoid. */ final SecondParameter secondParameter; /** * The semi-major axis of this Ellipsoid. */ final private double a; /** * The semi-minor axis of this Ellipsoid. */ final private double b; /** * The flattening of this Ellipsoid. */ final private double f; /** * The inverse flattening of this Ellipsoid. */ final private double invf; /** * The eccentricity of this Ellipsoid. */ final private double e; /** * The square eccentricity of this Ellipsoid. */ final private double e2; /** * The second square eccentricity of this Ellipsoid. */ final private double eprime2; /** * The coefficients used to compute the meridian arc length. */ transient private double[] arc_coeff; /** * The coefficients for the direct UTM projection. */ transient private double[] dir_utm_coeff; /** * The coefficients for the inverse UTM projection. */ transient private double[] inv_utm_coeff; /** * The coefficients used to compute meridian arc length from/to latitude * this second method is taken from here . It makes it * possible to choose the precision of the result. */ transient private double[] kk; /** * The coefficients for the inverse Mercator projection. */ transient private double[] inv_merc_coeff; /** * ellipsoidFromName associates each ellipsoid to a short string used to * recognize it in CTS. */ public static final Map ellipsoidFromName = new HashMap(); static { ellipsoidFromName.put("airy", AIRY); ellipsoidFromName.put("austsa", AustSA); ellipsoidFromName.put("bessel", BESSEL1841); ellipsoidFromName.put("bessnam", BESSNAM); ellipsoidFromName.put("clrk66", CLARKE1866); ellipsoidFromName.put("clrk80", CLARKE1880RGS); ellipsoidFromName.put("clrk80ign", CLARKE1880IGN); ellipsoidFromName.put("clrk80arc", CLARKE1880ARC); ellipsoidFromName.put("evrstss", EVERESTSS); ellipsoidFromName.put("grs67", GRS67); ellipsoidFromName.put("grs80", GRS80); ellipsoidFromName.put("helmert", HELMERT); ellipsoidFromName.put("intl", INTERNATIONAL1924); ellipsoidFromName.put("airymod", AIRYMOD); ellipsoidFromName.put("krass", KRASSOWSKI); ellipsoidFromName.put("wgs66", WGS66); ellipsoidFromName.put("wgs72", WGS72); ellipsoidFromName.put("wgs84", WGS84); } /** * Create a new Ellipsoid and initialize common parameters : a, b, e, e2, f, * 1/f, e'2 and coefficients for the meridian arc. * * @param identifier Ellipsoid identifier in the EPSG database * @param semiMajorAxis length of the semi major axis in meters * @param secondParameter second parameter type (inverse flattening, * semi-minor axis or eccentricity). * @param secondParameterValue value of the second parameter. */ private Ellipsoid(Identifier identifier, double semiMajorAxis, SecondParameter secondParameter, double secondParameterValue) throws IllegalArgumentException { super(identifier); this.a = semiMajorAxis; this.secondParameter = secondParameter; switch (secondParameter) { case InverseFlattening: this.invf = secondParameterValue; this.f = 1.0 / this.invf; this.b = this.a - this.a / this.invf; this.e2 = (2.0 - 1.0 / this.invf) / this.invf; this.e = sqrt(this.e2); break; case SemiMinorAxis: this.b = secondParameterValue; this.f = 1.0 - this.b / this.a; invf = a / (a - b); this.e2 = 1.0 - ((this.b * this.b) / (this.a * this.a)); this.e = sqrt((this.a * this.a - this.b * this.b) / (this.a * this.a)); break; case Eccentricity: this.e = secondParameterValue; this.e2 = this.e * this.e; this.b = this.a * sqrt(1.0 - this.e2); this.f = 1.0 - sqrt(1.0 - this.e2); invf = 1.0 / (1.0 - sqrt(1.0 - e2)); break; default: this.b = this.a; this.f = 0.0; this.invf = Double.POSITIVE_INFINITY; this.e = 0.0; this.e2 = 0.0; } eprime2 = e2 / (1.0 - e2); } /** * Return the semi-major axis of this ellipsoid (fr : demi grand axe). */ public double getSemiMajorAxis() { return a; } /** * Return the inverse flattening of this ellipsoid (fr : aplatissement * inverse). */ public double getInverseFlattening() { return invf; } /** * Return the semi-minor axis of this ellipsoid (fr : demi petit axe). */ public double getSemiMinorAxis() { return b; } /** * Return the flattening of this ellipsoid (fr : aplatissement). */ public double getFlattening() { return f; } /** * Return the eccentricity of this ellipsoid (fr : excentricit�). */ public double getEccentricity() { return e; } /** * Return the square eccentricity of this ellipsoid (fr : carré de * l'excentricité). */ public double getSquareEccentricity() { return e2; } /** * Return the second eccentricity ((a-b)/b) of this ellipsoid (fr : seconde * excentricité). */ public double getSecondEccentricitySquared() { return e2 / (1.0 - e2); } /** * Get coefficients for the meridian arc length. */ public double[] getArcCoeff() { if (arc_coeff == null) { initMeridianArcCoefficients(); } return arc_coeff; } /** * Get k coefficients computed with an iterative method. */ public double[] getKCoeff(int max) { initKCoeff(max); return kk; } /** * Creates a new Ellipsoid whose definition is based on semi-major axis and * inverse flattening and initializes common parameters such as a, b, e, e2, * f, 1/f, e'2 and coefficients for the meridian arc. * * @param semiMajorAxis length of the semi-major axis in meters * @param invFlattening inverse flattening of the ellipsoid */ public static Ellipsoid createEllipsoidFromInverseFlattening( double semiMajorAxis, double invFlattening) throws IllegalArgumentException { Identifier id = new Identifier(Ellipsoid.class); Ellipsoid ellps = new Ellipsoid(id, semiMajorAxis, SecondParameter.InverseFlattening, invFlattening); return ellps.checkExistingEllipsoid(); } /** * Creates a new Ellipsoid whose definition is based on semi-major axis and * inverse flattening and initializes common parameters such as a, b, e, e2, * f, 1/f, e'2 and coefficients for the meridian arc. * * @param identifier ellipsoid identifier * @param semiMajorAxis length of the semi-major axis in meters * @param invFlattening inverse flattening of the ellipsoid */ public static Ellipsoid createEllipsoidFromInverseFlattening( Identifier identifier, double semiMajorAxis, double invFlattening) throws IllegalArgumentException { Ellipsoid ellps = new Ellipsoid(identifier, semiMajorAxis, SecondParameter.InverseFlattening, invFlattening); return ellps.checkExistingEllipsoid(); } /** * Creates a new Ellipsoid whose definition is based on semi-major axis and * semi-minor axis and initializes common parameters such as a, b, e, e2, f, * 1/f, e'2 and coefficients for the meridian arc. * * @param semiMajorAxis length of the semi-major axis in meters * @param semiMinorAxis semi-minor-axis of the ellipsoid */ public static Ellipsoid createEllipsoidFromSemiMinorAxis( double semiMajorAxis, double semiMinorAxis) throws IllegalArgumentException { Identifier id = new Identifier(Ellipsoid.class); Ellipsoid ellps = new Ellipsoid(id, semiMajorAxis, SecondParameter.SemiMinorAxis, semiMinorAxis); return ellps.checkExistingEllipsoid(); } /** * Creates a new Ellipsoid whose definition is based on semi-major axis and * semi-minor axis and initializes common parameters such as a, b, e, e2, f, * 1/f, e'2 and coefficients for the meridian arc. * * @param identifier ellipsoid identifier * @param semiMajorAxis length of the semi-major axis in meters * @param semiMinorAxis semi-minor-axis of the ellipsoid */ public static Ellipsoid createEllipsoidFromSemiMinorAxis( Identifier identifier, double semiMajorAxis, double semiMinorAxis) throws IllegalArgumentException { Ellipsoid ellps = new Ellipsoid(identifier, semiMajorAxis, SecondParameter.SemiMinorAxis, semiMinorAxis); return ellps.checkExistingEllipsoid(); } /** * Creates a new Ellipsoid whose definition is based on semi-major axis and * eccentricity and initializes common parameters such as a, b, e, e2, f, * 1/f, e'2 and coefficients for the meridian arc. * * @param semiMajorAxis length of the semi-major axis in meters * @param eccentricity semi-minor-axis of the ellipsoid */ public static Ellipsoid createEllipsoidFromEccentricity( double semiMajorAxis, double eccentricity) throws IllegalArgumentException { Identifier id = new Identifier(Ellipsoid.class); Ellipsoid ellps = new Ellipsoid(id, semiMajorAxis, SecondParameter.Eccentricity, eccentricity); return ellps.checkExistingEllipsoid(); } /** * Creates a new Ellipsoid whose definition is based on semi-major axis and * eccentricity and initializes common parameters such as a, b, e, e2, f, * 1/f, e'2 and coefficients for the meridian arc. * * @param identifier ellipsoid identifier * @param semiMajorAxis length of the semi-major axis in meters * @param eccentricity semi-minor-axis of the ellipsoid */ public static Ellipsoid createEllipsoidFromEccentricity( Identifier identifier, double semiMajorAxis, double eccentricity) throws IllegalArgumentException { Ellipsoid ellps = new Ellipsoid(identifier, semiMajorAxis, SecondParameter.Eccentricity, eccentricity); return ellps.checkExistingEllipsoid(); } /** * Check if * this is equals to one of the predefined Ellipsoid (GRS80, * WGS84,…). Return the predifined Ellipsoid that matches if exists, * otherwise return * this. */ private Ellipsoid checkExistingEllipsoid() { if (this.equals(Ellipsoid.GRS80)) { return Ellipsoid.GRS80; } else if (this.equals(Ellipsoid.WGS84)) { return Ellipsoid.WGS84; } else if (this.equals(Ellipsoid.INTERNATIONAL1924)) { return Ellipsoid.INTERNATIONAL1924; } else if (this.equals(Ellipsoid.CLARKE1866)) { return Ellipsoid.CLARKE1866; } else if (this.equals(Ellipsoid.CLARKE1880ARC)) { return Ellipsoid.CLARKE1880ARC; } else if (this.equals(Ellipsoid.CLARKE1880IGN)) { return Ellipsoid.CLARKE1880IGN; } else if (this.equals(Ellipsoid.CLARKE1880RGS)) { return Ellipsoid.CLARKE1880RGS; } else if (this.equals(Ellipsoid.SPHERE)) { return Ellipsoid.SPHERE; } else if (this.equals(Ellipsoid.BESSEL1841)) { return Ellipsoid.BESSEL1841; } else if (this.equals(Ellipsoid.KRASSOWSKI)) { return Ellipsoid.KRASSOWSKI; } else if (this.equals(Ellipsoid.GRS67)) { return Ellipsoid.GRS67; } else if (this.equals(Ellipsoid.AustSA)) { return Ellipsoid.AustSA; } else if (this.equals(Ellipsoid.AIRY)) { return Ellipsoid.AIRY; } else if (this.equals(Ellipsoid.AIRYMOD)) { return Ellipsoid.AIRYMOD; } else if (this.equals(Ellipsoid.BESSNAM)) { return Ellipsoid.BESSNAM; } else if (this.equals(Ellipsoid.HELMERT)) { return Ellipsoid.HELMERT; } else if (this.equals(Ellipsoid.WGS66)) { return Ellipsoid.WGS66; } else if (this.equals(Ellipsoid.WGS72)) { return Ellipsoid.WGS72; } else { return this; } } /** * Initialize the coefficients for the meridian arc length. */ private void initMeridianArcCoefficients() { double e4 = e2 * e2; double e6 = e4 * e2; double e8 = e4 * e4; arc_coeff = new double[5]; arc_coeff[0] = 1.0 - e2 * 1 / 4 - e4 * 3 / 64 - e6 * 5 / 256 - e8 * 175 / 16384; arc_coeff[1] = -e2 * 3 / 8 - e4 * 3 / 32 - e6 * 45 / 1024 - e8 * 105 / 4096; arc_coeff[2] = e4 * 15 / 256 + e6 * 45 / 1024 + e8 * 525 / 16384; arc_coeff[3] = -e6 * 35 / 3072 - e8 * 175 / 12288; arc_coeff[4] = e8 * 315 / 131072; } /** * This second method to compute the meridian arc length is taken from . It is based upon an * iterative method and the precision of the result will depend on the * number of iterations. It is to be used with arcFromLat or from * latFromArc. */ public void initKCoeff(int max) { if (max < 1) { max = 1; } if (max > 8) { max = 8; } kk = new double[max]; //for(int n = 0; n < max; n++) k[n] = 0.0; double c = 1.0; for (int n = 1; n <= max; n++) { double n2 = 2.0 * n; c *= (n2 - 1.0) * (n2 - 3.0) / n2 / n2 * e2; for (int m = 0; m < n; m++) { kk[m] += c; } } } /** * Return the first coefficient of series expansion. */ private double k1() { if (kk == null) { initKCoeff(5); } return 1.0 + kk[0]; } /** * Return the second coefficient of series expansion */ private double k2(double beta_rad) { if (kk == null) { initKCoeff(5); } double cos2 = Math.cos(beta_rad) * Math.cos(beta_rad); double result = kk[0]; double k = 1.0; for (int n = 1; n < kk.length; n++) { k *= (2.0 * n) / (2.0 * n + 1.0) * cos2; result += kk[n] * k; } return (result); } /** * Computes the meridian arc from equator to point with ellipsoidal latitude * phi. * * @param phi the ellipsoidal latitude * @return the meridian arc in meters */ public double arcFromLat(double phi) { double beta = Math.atan((1.0 - f) * Math.tan(phi)); return a * beta * k1() + a / 2.0 * Math.sin(2.0 * beta) * k2(beta); } /** * Computes the ellipsoidal latitude from meridian arc length. * * @param s the meridian arc length in meters * @return the ellipsoidal latitude */ public double latFromArc(double s) throws ArithmeticException { final int MAXITER = 10; double beta0 = s / a / k1(); double beta = beta0, betaold = 1.E30; int iter = 0; while (++iter < MAXITER && Math.abs(beta - betaold) > 1.E-15) { betaold = beta; beta = beta0 - k2(beta) / 2. / k1() * Math.sin(2. * beta); } if (iter == MAXITER) { throw new ArithmeticException("The latitudeFromArc method diverges"); } return (Math.atan(Math.tan(beta) / (1. - f))); } /** * The Meridional Radius of Curvature is the radius of curvature, at a * specific latitude, of the ellipse used to generate the ellipsoid. * * @param latitude the geographic latitude * @return the radius of curvature in meters */ public final double meridionalRadiusOfCurvature(double latitude) { double sinlat = sin(latitude); return a * (1 - e2) / pow((1 - e2 * sinlat * sinlat), 1.5); } /** * The Transverse Radius of Curvature or radius of the first vertical * section or prime vertical radius of curvature (fr : Grande Normale).

* This is the radius of curvature in the plane which is normal to (i.e. * perpendicular to) both the surface of the ellipsoid at, and the meridian * passing through, the specific point of interest. * * @param latitude geographic latitude in radians * @return a double value representing a length in meters */ public final double transverseRadiusOfCurvature(double latitude) { // trigonometric function are slow, use it one time instead of two double sinlat = sin(latitude); return a / sqrt(1 - (e2 * sinlat * sinlat)); } // The same method with a french name : DEPRECATED public final double grandeNormale(double latitude) { // trigonometric function are slow, use it one time instead of two double sinlat = sin(latitude); return a / sqrt(1 - (e2 * sinlat * sinlat)); } /** * Computes isometric latitude from geographic (or geodetic) latitude.

* Geographic latitude of a point P located on the surface of the ellipsoid * is the angle between the perpendicular to the ellipsoid surface at P and * the equatorial plan.

Isometric latitude is a function of geographic * latitude L(lat) such as (lambda, L) is a symmetric parametric form of the * ellipsoid surface.

Ref. * IGN ALG0001 * * @param latitude geographic latitude * @return isometric latitude in radians */ public final double isometricLatitude(double latitude) { double esinlat = e * sin(latitude); return log(tan((PI_2 + latitude) / 2) * pow((1 - esinlat) / (1 + esinlat), e / 2)); } /** * Computes the geographic latitude from the isometric latitude (fr : calcul * de la latitude géographique à partir de la latitude isometrique).

* Geographic latitude of a point P located on the surface of the ellipsoid * is the angle between the perpendicular to the ellipsoid surface at P and * the equatorial plan.

Isometric latitude is a function of geographic * latitude L(lat) such as (lambda, L) is a symmetric parametric form of the * ellipsoid surface.

Geographic latitude is computed as the limit of a * convergent suite. The loop is stopped when two consecutive terms of the * suite is less than epsilon.

Ref. * IGN ALG0002 * * @param isoLatitude latitude isometrique * @param epsilon value controlling the stop condition of this convergent * sequence. Use 1E-10 for a precision of about 0.6 mm, 1E-11 for a * precision of about 0.06 mm and 1E-12 for a preciison of about 0.006 mm * @return the geographic latitude as a double */ public final double latitude(double isoLatitude, double epsilon) { double exp_isolatitude = exp(isoLatitude); double lat0 = 2 * atan(exp_isolatitude) - PI_2; double lati = lat0; double latj = 1000; while (abs(latj - lati) >= epsilon) { lati = latj; double esinlat = e * sin(lati); latj = 2 * atan(pow((1 + esinlat) / (1 - esinlat), e / 2) * exp_isolatitude) - PI_2; } return latj; } /** * Computes geographic latitude from isometric latitude. The process stops * as soon as the result reaches a pecision of 1.0E-11.

fr : Calcul la * latitude géographique d'un point P à partir de sa latitude * isométrique.

La latitude géographique est définie comme étant la * limite d'une suite convergente. Le calcul de cette suite est interrompu * lorsque la différence entre deux termes consécutifs est plus petit que * 1E-11 (soit environ 0.006 mm). * * @param isoLatitude isometric latitude * @return the geographic latitude in radians */ public final double latitude(double isoLatitude) { return latitude(isoLatitude, 1E-11); } /** * Returns the curvilinear abscissa of the meridian arc for this latitude on * an ellipsoid with eccentricity = this.e and semi-major axis = 1.0.

* Usually noted beta, the meridian arc length is obtained by multiplying * this result by the semi-major axis. * * @param latitude latitude. * @return the curvilinear abscissa of this latitude on the meridian arc */ public double curvilinearAbscissa(double latitude) { if (arc_coeff == null) { initMeridianArcCoefficients(); } return arc_coeff[0] * latitude + arc_coeff[1] * sin(2 * latitude) + arc_coeff[2] * sin(4 * latitude) + arc_coeff[3] * sin(6 * latitude) + arc_coeff[4] * sin(8 * latitude); } /** * Returns a WKT representation of the ellipsoid. * */ public String toWKT() { StringBuilder w = new StringBuilder(); w.append("SPHEROID[\""); w.append(this.getName()); w.append("\","); w.append(this.getSemiMajorAxis()); w.append(','); if (this.getInverseFlattening() != Double.POSITIVE_INFINITY) { w.append(this.getInverseFlattening()); } else { w.append(0); } if (!this.getAuthorityName().startsWith(Identifiable.LOCAL)) { w.append(','); w.append(this.getIdentifier().toWKT()); } w.append(']'); return w.toString(); } /** * Return a string representtaion of this ellipsoid. */ @Override public String toString() { StringBuilder sb = new StringBuilder(getIdentifier().toString()); sb.append(" (Semi-major axis = ").append(a); switch (secondParameter) { case SemiMinorAxis: sb.append(" | ").append("Semi-minor axis = ").append(b).append(")"); break; case InverseFlattening: sb.append(" | ").append("Flattening = 1/").append(invf).append(")"); break; case Eccentricity: sb.append(" | ").append("Eccentricity = ").append(e).append(")"); break; default: sb.append(")"); } return sb.toString(); } /** * Returns true if this Ellipsoid can be considered as equals to another * one. Ellipsoid equals method is based on a comparison of the object * dimensions with a sensibility of 0.1 mm. * * @param other the object to compare this Ellipsoid against */ @Override public boolean equals(Object other) { // short circuit to compare final static Ellipsoids if (this == other) { return true; } if (other instanceof Ellipsoid) { Ellipsoid ell = (Ellipsoid) other; // if ellipsoid codes are equals, ellipsoids are equals if (getCode().equals(ell.getCode())) { return true; } // else if ellipsoid semi-major axis and ellipsoid semi-minor axis // are equals (+/- 0.1 mm) ellipoids are also considered as equals double a2 = ell.getSemiMajorAxis(); double b2 = ell.getSemiMinorAxis(); return (Math.abs(a2 - a) < 1e-4 && Math.abs(b2 - b) < 1e-4); } return false; } /** * Returns the hash code for this Ellipsoid. */ @Override public int hashCode() { int hash = 5; hash = 97 * hash + (int) (Double.doubleToLongBits(this.a) ^ (Double.doubleToLongBits(this.a) >>> 32)); hash = 97 * hash + (int) (Double.doubleToLongBits(this.b) ^ (Double.doubleToLongBits(this.b) >>> 32)); return hash; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy