web-dev-qa-db-fra.com

Conversion de longitude\latitude en coordonnées cartésiennes

J'ai des points de coordonnées centrés sur la Terre, exprimés en latitude et en longitude ( WGS-84 ).

Comment puis-je les convertir en coordonnées cartésiennes (x, y, z) avec l'origine au centre de la terre?

86
daphshez

J'ai récemment fait quelque chose de similaire en utilisant la "formule de Haversine" sur les données WGS-84 , Qui est un dérivé de la "loi de Haversines" avec des résultats très satisfaisants. 

Oui, WGS-84 suppose que la Terre est un ellipsoïde, mais je pense que vous obtenez une erreur moyenne d’environ 0,5% en utilisant une approche telle que la "formule de Haversine", ce qui peut être une quantité acceptable d’erreur dans votre cas. Vous aurez toujours une certaine quantité d'erreur sauf si vous parlez d'une distance de quelques pieds et même dans ce cas, il y a théoriquement une courbure de la Terre ... Si vous avez besoin d'une approche plus rigide compatible avec le WGS-84, vérifiez la "formule de Vincenty".

Je comprends l’origine de starblue, mais une bonne ingénierie logicielle est souvent synonyme de compromis. Tout dépend donc de la précision dont vous avez besoin pour ce que vous faites. Par exemple, le résultat calculé à partir de "Formule de distance de Manhattan" par rapport au résultat de "Formule à distance" peut être meilleur dans certaines situations, car il est moins coûteux en calcul. Pensez "quel point est le plus proche?" scénarios où vous n'avez pas besoin d'une mesure de distance précise.

En ce qui concerne la "formule Haversine", elle est facile à mettre en œuvre et est agréable car elle utilise la "trigonométrie sphérique" au lieu d’une approche basée sur la "loi des cosinus" basée sur la trigonométrie bidimensionnelle. Vous obtenez donc un bon équilibre de précision. sur la complexité.

Un certain Messieurs du nom de Chris Veness a un site web génial à l'adresse http://www.movable-type.co.uk/scripts/latlong.html , ce qui explique certains les concepts qui vous intéressent et illustre diverses implémentations programmatiques; cela devrait également répondre à votre question de conversion x/y.

39
bn.

Voici la réponse que j'ai trouvée:

Pour compléter la définition, dans le système de coordonnées cartésien:

  • l'axe des x traverse long, lat (0,0), de sorte que la longitude 0 rencontre l'équateur; 
  • l'axe des y passe à travers (0,90);
  • et l'axe z passe par les pôles. 

La conversion est:

x = R * cos(lat) * cos(lon)

y = R * cos(lat) * sin(lon)

z = R *sin(lat)

Où R est le rayon approximatif de la terre (par exemple 6371KM).

Si vos fonctions trigonométriques s’attendent à des radians (ce qu’elles font probablement), vous devrez d’abord convertir votre longitude et votre latitude en radians. Vous avez évidemment besoin d’une représentation décimale et non de degrés\minutes\secondes (voir par exemple ici à propos de la conversion).

La formule de reconversion:

   lat = asin(z / R)
   lon = atan2(y, x)

asin est bien sûr arc sine. en savoir plus sur atan2 dans wikipedia . N’oubliez pas de reconvertir des radians en degrés. 

Cette page donne le code c # pour cela (notez qu'il est très différent des formules), ainsi que quelques explications et un joli diagramme expliquant pourquoi cela est correct,

107
daphshez

Théorie pour convertir GPS(WGS84) en coordonnées cartésienneshttps://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_geodetic_to_ECEF_coordinates

Voici ce que j'utilise:

  • La longitude dans le GPS (WGS84 et les coordonnées cartésiennes sont identiques. 
  • La latitude doit être convertie par les paramètres de l'ellipsoïde WGS 84 semi-grand axe est 6378137 m, et 
  • L'inverse de l'aplatissement est 298.257223563.

J'ai joint un code VB J'ai écrit:

Imports System.Math

'Input GPSLatitude is WGS84 Latitude,h is altitude above the WGS 84 ellipsoid

Public Function GetSphericalLatitude(ByVal GPSLatitude As Double, ByVal h As Double) As Double

        Dim A As Double = 6378137 'semi-major axis 
        Dim f As Double = 1 / 298.257223563  '1/f Reciprocal of flattening
        Dim e2 As Double = f * (2 - f)
        Dim Rc As Double = A / (Sqrt(1 - e2 * (Sin(GPSLatitude * PI / 180) ^ 2)))
        Dim p As Double = (Rc + h) * Cos(GPSLatitude * PI / 180)
        Dim z As Double = (Rc * (1 - e2) + h) * Sin(GPSLatitude * PI / 180)
        Dim r As Double = Sqrt(p ^ 2 + z ^ 2)
        Dim SphericalLatitude As Double =  Asin(z / r) * 180 / PI
        Return SphericalLatitude
End Function

Veuillez noter que la h est une altitude supérieure au WGS 84 ellipsoid.

Généralement, GPS nous donnera H de plus de MSL hauteur. La hauteur MSL doit être convertie en hauteur h au-dessus du WGS 84 ellipsoid à l'aide du modèle géopotentielEGM96 (Lemoine et al, 1998).
Ceci est effectué en interpolant une grille du fichier de hauteur du géoïde avec une résolution spatiale de 15 minutes d'arc.

Ou si vous avez un niveau professionnelGPS a Altitude H (msl, haut au-dessus du niveau moyen de la mer) et UNDULATION, la relation entre geoid et ellipsoid (m) de la sortie donnée sous forme de données de interne table. vous pouvez obtenir h = H(msl) + undulation 

À XYZ par coordonnées cartésiennes:

x = R * cos(lat) * cos(lon)

y = R * cos(lat) * sin(lon)

z = R *sin(lat)
6
Howie

Pourquoi implémenter quelque chose qui a déjà été implémenté et qui a fait ses preuves?

C #, par exemple, a la NetTopologySuite , qui est le port .NET de la suite de topologie JTS.

En particulier, votre calcul présente un grave défaut. La Terre n'est pas une sphère parfaite et il est possible que le approximation du rayon de la Terre ne la coupe pas pour des mesures précises.

Si, dans certains cas, il est acceptable d’utiliser des fonctions homebrew, le système d’information géographique est un bon exemple de domaine dans lequel il est de loin préférable d’utiliser une bibliothèque fiable et éprouvée.

5
Yuval Adam

Le logiciel proj.4 fournit un programme en ligne de commande pouvant effectuer la conversion, par exemple.

LAT=40
LON=-110
echo $LON $LAT | cs2cs +proj=latlong +datum=WGS84 +to +proj=geocent +datum=WGS84

Il fournit également un C API . En particulier, la fonction pj_geodetic_to_geocentric effectuera la conversion sans avoir à configurer un objet de projection au préalable.

4
Brian Hawkins

Si vous souhaitez obtenir des coordonnées basées sur un ellipsoïde plutôt que sur une sphère, consultez http://en.wikipedia.org/wiki/Geodetic_system#From_geodetic_to_ECEF - qui donne les formules ainsi que les constantes WGS84 besoin de la conversion.

Les formules qui y figurent prennent également en compte l’altitude par rapport à la surface de l’ellipsoïde de référence (utile si vous obtenez des données d’altitude d’un appareil GPS).

3
Stjepan Rajko

En python3.x, cela peut être fait en utilisant:

# Converting lat/long to cartesian
import numpy as np

def get_cartesian(lat=None,lon=None):
    lat, lon = np.deg2rad(lat), np.deg2rad(lon)
    R = 6371 # radius of the earth
    x = R * np.cos(lat) * np.cos(lon)
    y = R * np.cos(lat) * np.sin(lon)
    z = R *np.sin(lat)
    return x,y,z
1
Mayank Kumar
Coordinate[] coordinates = new Coordinate[3];
coordinates[0] = new Coordinate(102, 26);
coordinates[1] = new Coordinate(103, 25.12);
coordinates[2] = new Coordinate(104, 16.11);
CoordinateSequence coordinateSequence = new CoordinateArraySequence(coordinates);

Geometry geo = new LineString(coordinateSequence, geometryFactory);

CoordinateReferenceSystem wgs84 = DefaultGeographicCRS.WGS84;
CoordinateReferenceSystem cartesinaCrs = DefaultGeocentricCRS.CARTESIAN;

MathTransform mathTransform = CRS.findMathTransform(wgs84, cartesinaCrs, true);

Geometry geo1 = JTS.transform(geo, mathTransform);
1
yang jun

Vous pouvez le faire de cette façon sur Java.

public List<Double> convertGpsToECEF(double lat, double longi, float alt) {

    double a=6378.1;
    double b=6356.8;
    double N;
    double e= 1-(Math.pow(b, 2)/Math.pow(a, 2));
    N= a/(Math.sqrt(1.0-(e*Math.pow(Math.sin(Math.toRadians(lat)), 2))));
    double cosLatRad=Math.cos(Math.toRadians(lat));
    double cosLongiRad=Math.cos(Math.toRadians(longi));
    double sinLatRad=Math.sin(Math.toRadians(lat));
    double sinLongiRad=Math.sin(Math.toRadians(longi));
    double x =(N+0.001*alt)*cosLatRad*cosLongiRad;
    double y =(N+0.001*alt)*cosLatRad*sinLongiRad;
    double z =((Math.pow(b, 2)/Math.pow(a, 2))*N+0.001*alt)*sinLatRad;

    List<Double> ecef= new ArrayList<>();
    ecef.add(x);
    ecef.add(y);
    ecef.add(z);

    return ecef;


}
0
Ashutosh Chapagain