Конвертировать из широты, долготы в x, y

Я хочу преобразовать местоположение GPS (широта, долгота) в координаты x, y. Я нашел много ссылок на эту тему и применил ее, но это не дает мне правильный ответ!

Я следую этим шагам, чтобы проверить ответ: (1) во-первых, я беру две позиции и вычисляю расстояние между ними с помощью карт. (2) затем преобразуют две позиции в координаты x, y. (3), то снова вычислить расстояние между двумя точками в координатах x, y и посмотрим, даст ли он мне тот же результат в точке (1) или нет.

одно из решений я нашел следующее, но это не дает мне правильного ответа!

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);

также я пробовал эту ссылку , но все равно не работает со мной хорошо!

любая помощь, как конвертировать из (широта, долгота) в (x, y)?

Спасибо,

Ответ 1

Нет точного решения

Нет изометрического отображения от сферы к плоскости. Когда вы конвертируете координаты lat/lon из сферы в координаты x/y в плоскости, вы не можете надеяться, что вся эта длина будет сохранена этой операцией. Вы должны принять какую-то деформацию. Существует множество различных проекций карт, которые могут достичь различных компромиссов между сохранением длин, углов и областей. Для небольших частей земной поверхности, поперечный Меркатор довольно распространен. Возможно, вы слышали о UTM. Но есть еще много.

Формулы, которые вы цитируете, вычисляют x/y/z, т.е. точку в трехмерном пространстве. Но даже там вы не получите правильные расстояния автоматически. Самое короткое расстояние между двумя точками на поверхности сферы проходило бы через эту сферу, тогда как расстояния на Земле в основном являются геодезическими длиной после поверхности. Поэтому они будут длиннее.

Аппроксимация для небольших областей

Если часть поверхности земли, которую вы хотите нарисовать, относительно невелика, вы можете использовать очень простое приближение. Вы можете просто использовать горизонтальную ось x для обозначения долготы λ, вертикальной оси y для обозначения широты φ. Соотношение между ними должно быть не 1:1. Вместо этого вы должны использовать cos (φ 0) как соотношение сторон, где φ 0 обозначает широту, близкую к центру вашей карты. Кроме того, для преобразования от углов (измеренных в радианах) к длинам, вы умножаетесь на радиус земли (который в этой модели считается сферой).

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

Это простая равноугольная проекция. В большинстве случаев вы сможете вычислять cos (φ 0) только один раз, что делает последующие вычисления большого количества точек действительно дешевыми.

Ответ 2

Поскольку эта страница отображается поверх Google, в то время как я искал эту же проблему, я хотел бы дать более практичные ответы. Ответ MVG правильный, но скорее теоретический.

Я сделал приложение для построения треков для fitbit ionic в javascript. Код ниже, как я решил эту проблему.

//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
}

Ответ 3

Я хочу поделиться с вами тем, как мне удалось решить проблему. Я использовал равностороннюю проекцию, как сказал @MvG, но этот метод дает вам координаты X и Y, связанные с глобусом (или всей картой), это означает, что вы получаете глобальные позиции. В моем случае я хотел преобразовать координаты в небольшой области (около 500 м кв.), Поэтому я связал точку проекции с двумя другими точками, получив глобальные позиции и относящиеся к местным (на экране) позициям, вот так:

Сначала я выбираю 2 точки (вверху слева и внизу справа) вокруг области, где я хочу проецировать, как на этом рисунке:

enter image description here

Как только я получу глобальную справочную область в широтах и влево, я делаю то же самое для позиций на экране. Объекты, содержащие эти данные, показаны ниже.

//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");

Как видите, я сделал это в javascript, но расчеты можно перевести на любой язык.

PS: я применяю преобразованные позиции к html-элементу с идентификатором "point-to-project". Чтобы использовать этот фрагмент кода в своем проекте, вы должны создать этот элемент (в стиле абсолютного положения) или изменить блок "использование".

Ответ 4

Лучше преобразовать в координаты utm, и рассматривать это как x и y.

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

Результат будет (779260.623156606, 1429369.8665238516, 43, 'P'). Первые два можно рассматривать как координаты x, y, 43P - это зона UTM, которую можно игнорировать для небольших областей (ширина до 668 км).