web-dev-qa-db-fra.com

convertir de latitude, longitude en x, y

Je souhaite convertir la position GPS (latitude, longitude) en coordonnées x, y. J'ai trouvé de nombreux liens sur ce sujet et l'ai appliqué, mais cela ne me donne pas la bonne réponse!

Je suis ces étapes pour tester la réponse: (1) tout d'abord, je prends deux positions et calcule la distance entre elles en utilisant des cartes. (2) puis convertissez les deux positions en coordonnées x, y. (3) puis calculez à nouveau la distance entre les deux points dans les coordonnées x, y et voyez si cela me donne le même résultat au point (1) ou non.

l'une des solutions que j'ai trouvée la suivante, mais elle ne me donne pas la bonne réponse!

latitude = Math.PI * latitude / 180;
longitude = Math.PI * longitude / 180;

// adjust position by radians
latitude -= 1.570795765134; // subtract 90 degrees (in radians)

// and switch z and y 
xPos = (app.radius) * Math.sin(latitude) * Math.cos(longitude);
zPos = (app.radius) * Math.sin(latitude) * Math.sin(longitude);
yPos = (app.radius) * Math.cos(latitude);

aussi j'ai essayé cela lien mais ne fonctionne toujours pas bien avec moi!

une aide comment convertir de (latitude, longitude) en (x, y)?

Merci,

18
userInThisWorld

Aucune solution exacte n'existe

Il n'y a pas de carte isométrique de la sphère à l'avion. Lorsque vous convertissez les coordonnées lat/lon de la sphère en coordonnées x/y dans le plan, vous ne pouvez pas espérer que toutes les longueurs seront préservées par cette opération. Vous devez accepter une sorte de déformation. Il existe de nombreuses projections cartographiques différentes, qui peuvent réaliser différents compromis entre la préservation des longueurs, des angles et des zones. Pour les petites parties de la surface terrestre, Mercator transverse est assez courant. Vous avez peut-être entendu parler de UTM . Mais il y a beaucoup plus .

Les formules que vous citez calculent x/y/z, c'est-à-dire un point dans l'espace 3D. Mais même là, vous n'obtiendrez pas automatiquement les distances correctes. La distance la plus courte entre deux points à la surface de la sphère passerait par cette sphère, tandis que les distances sur la terre sont principalement des longueurs géodésiques qui suivent la surface. Ils seront donc plus longs.

Approximation pour les petites zones

Si la partie de la surface de la terre que vous souhaitez dessiner est relativement petite, vous pouvez utiliser une approximation très simple. Vous pouvez simplement utiliser l'axe horizontal x pour désigner la longitude λ, l'axe vertical y pour désigner la latitude φ. Le rapport entre ceux-ci ne devrait cependant pas être de 1: 1. Au lieu de cela, vous devez utiliser cos (φ) comme rapport d'aspect, où φ indique une latitude proche du centre de votre carte. De plus, pour convertir des angles (mesurés en radians) en longueurs, vous multipliez par le rayon de la terre (qui dans ce modèle est supposé être une sphère).

  • x = r λ cos (φ)
  • y = r φ

C'est simple projection équirectangulaire . Dans la plupart des cas, vous pourrez calculer cos (φ) une seule fois, ce qui rend les calculs ultérieurs d'un grand nombre de points vraiment bon marché.

39
MvG

Je veux partager avec vous comment j'ai géré le problème. J'ai utilisé la projection équirectangulaire comme l'a dit @MvG, mais cette méthode vous donne des positions X et Y liées au globe (ou à la carte entière), cela signifie que vous obtenez des positions globales. Dans mon cas, je voulais convertir des coordonnées dans une petite zone (environ 500 mètres carrés), j'ai donc lié le point de projection à 2 autres points, obtenant les positions globales et relatives aux positions locales (à l'écran), comme ceci:

Tout d'abord, je choisis 2 points (en haut à gauche et en bas à droite) autour de la zone où je veux projeter, tout comme cette image:

enter image description here

Une fois que j'ai la zone de référence globale en lat et lng, je fais de même pour les positions d'écran. Les objets contenant ces données sont présentés ci-dessous.

//top-left reference point
var p0 = {
    scrX: 23.69,        // Minimum X position on screen
    scrY: -0.5,         // Minimum Y position on screen
    lat: -22.814895,    // Latitude
    lng: -47.072892     // Longitude
}
//bottom-right reference point
var p1 = {
    scrX: 276,          // Maximum X position on screen
    scrY: 178.9,        // Maximum Y position on screen
    lat: -22.816419,    // Latitude
    lng: -47.070563     // Longitude
}
var radius = 6.371;     //Earth Radius in Km

//## Now I can calculate the global X and Y for each reference point ##\\

// This function converts lat and lng coordinates to GLOBAL X and Y positions
function latlngToGlobalXY(lat, lng){
    //Calculates x based on cos of average of the latitudes
    let x = radius*lng*Math.cos((p0.lat + p1.lat)/2);
    //Calculates y based on latitude
    let y = radius*lat;
    return {x: x, y: y}
}
// Calculate global X and Y for top-left reference point
p0.pos = latlngToGlobalXY(p0.lat, p0.lng);
// Calculate global X and Y for bottom-right reference point
p1.pos = latlngToGlobalXY(p1.lat, p1.lng);

/*
* This gives me the X and Y in relation to map for the 2 reference points.
* Now we have the global AND screen areas and then we can relate both for the projection point.
*/

// This function converts lat and lng coordinates to SCREEN X and Y positions
function latlngToScreenXY(lat, lng){
    //Calculate global X and Y for projection point
    let pos = latlngToGlobalXY(lat, lng);
    //Calculate the percentage of Global X position in relation to total global width
    pos.perX = ((pos.x-p0.pos.x)/(p1.pos.x - p0.pos.x));
    //Calculate the percentage of Global Y position in relation to total global height
    pos.perY = ((pos.y-p0.pos.y)/(p1.pos.y - p0.pos.y));

    //Returns the screen position based on reference points
    return {
        x: p0.scrX + (p1.scrX - p0.scrX)*pos.perX,
        y: p0.scrY + (p1.scrY - p0.scrY)*pos.perY
    }
}

//# The usage is like this #\\

var pos = latlngToScreenXY(-22.815319, -47.071718);
$point = $("#point-to-project");
$point.css("left", pos.x+"em");
$point.css("top", pos.y+"em");

Comme vous pouvez le voir, j'ai fait cela en javascript, mais les calculs peuvent être traduits dans n'importe quelle langue.

PS: j'applique les positions converties à un élément html dont l'id est "point-to-project". Afin d'utiliser ce morceau de code sur votre projet, vous devez créer cet élément (appelé position absolue) ou modifier le bloc "utilisation".

4
allexrm

Étant donné que cette page s'affiche au-dessus de Google pendant que je recherche ce même problème, je voudrais fournir des réponses plus pratiques. La réponse de MVG est correcte mais plutôt théorique.

J'ai créé une application de traçage pour le fitbit ionic en javascript. Le code ci-dessous est la façon dont j'ai abordé le problème.

//LOCATION PROVIDER
index.js
var gpsFix = false;
var circumferenceAtLat = 0;
function locationSuccess(pos){
  if(!gpsFix){
    gpsFix = true;
    circumferenceAtLat = Math.cos(pos.coords.latitude*0.01745329251)*111305;
  }
  pos.x:Math.round(pos.coords.longitude*circumferenceAtLat),
  pos.y:Math.round(pos.coords.latitude*110919), 
  plotTrack(pos);
}

plotting.js

plotTrack(position){

let x = Math.round((this.segments[i].start.x - this.bounds.minX)*this.scale);
let y = Math.round(this.bounds.maxY - this.segments[i].start.y)*this.scale; //heights needs to be inverted

//redraw?
let redraw = false;

//x or y bounds?
 if(position.x>this.bounds.maxX){
   this.bounds.maxX = (position.x-this.bounds.minX)*1.1+this.bounds.minX; //increase by 10%
   redraw = true;
 }
 if(position.x<this.bounds.minX){
   this.bounds.minX = this.bounds.maxX-(this.bounds.maxX-position.x)*1.1;
    redraw = true;
 };
 if(position.y>this.bounds.maxY){
   this.bounds.maxY = (position.y-this.bounds.minY)*1.1+this.bounds.minY; //increase by 10%
    redraw = true;
 }
 if(position.y<this.bounds.minY){
   this.bounds.minY = this.bounds.maxY-(this.bounds.maxY-position.y)*1.1;
    redraw = true;
 }
 if(redraw){
   reDraw();
 }
}


function reDraw(){

let xScale = device.screen.width / (this.bounds.maxX-this.bounds.minX);
let yScale = device.screen.height / (this.bounds.maxY-this.bounds.minY); 
if(xScale<yScale) this.scale = xScale; 
else this.scale = yScale;

//Loop trough your object to redraw all of them
}
2
Pieter Oskam

Il vaut mieux convertir en coordonnées utm et traiter cela comme x et y.

import utm
u = utm.from_latlon(12.917091, 77.573586)

Le résultat sera (779260.623156606, 1429369.8665238516, 43, 'P') Les deux premiers peuvent être traités comme des coordonnées x, y, le 43P est la zone UTM, qui peut être ignorée pour les petites zones (largeur jusqu'à 668 km).

0
Krishna Nagaraj