web-dev-qa-db-ja.com

緯度、経度からx、yへの変換

GPSの位置(緯度、経度)をX、Y座標に変換したい。このトピックに関する多くのリンクを見つけて適用しましたが、正しい答えが得られません!

私はこれらの手順に従って答えをテストしています:(1)まず、2つの位置を取り、マップを使用してそれらの間の距離を計算します。 (2)次に、2つの位置をx、y座標に変換します。 (3)次に、x、y座標の2点間の距離を再度計算し、point(1)で同じ結果が得られるかどうかを確認します。

解決策の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);

また、私はこれを試してみました link しかし、それでもうまく動作しません!

(緯度、経度)を(x、y)に変換する方法はありますか?

おかげで、

18
userInThisWorld

正確な解決策はありません

球から平面へのアイソメトリックマップはありません。緯度/経度座標を球体から平面内のx/y座標に変換する場合、この操作によってすべての長さが保持されることを期待することはできません。何らかの変形を受け入れる必要があります。多くの異なる地図投影法が存在します。これにより、長さ、角度、および領域の保存間で異なる妥協点を達成できます。地表の小さな部分の場合、 横メルカトル図法 は非常に一般的です。 [〜#〜] utm [〜#〜] について聞いたことがあるかもしれません。しかし、 多く があります。

引用する式は、x/y/z、つまり3D空間の点を計算します。しかし、そこでも正しい距離を自動的に取得することはできません。球体の表面上の2点間の最短距離はその球体を通過しますが、地球上の距離はほとんどが表面に続く測地線の長さです。したがって、それらはより長くなります。

小さな領域の近似

描画する地球の表面の部分が比較的小さい場合、非常に単純な近似を使用できます。単純に水平軸xを使用して経度λを示し、垂直軸y緯度φを示します。ただし、これらの比率は1:1であってはなりません。代わりに、cos(φ)アスペクト比として、ここでφ は、マップの中心に近い緯度を示します。さらに、角度(ラジアンで測定)から長さに変換するには、地球の半径(このモデルでは球体であると想定)を掛けます。

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

これは単純です 正距円筒図法 。ほとんどの場合、cos(φ)1回のみ。これにより、その後の多数のポイントの計算が非常に安価になります。

39
MvG

問題をどのように管理したかを共有したいと思います。 @MvGが言ったように正距円筒図法を使用しましたが、この方法は地球(またはマップ全体)に関連するXおよびY位置を提供します。つまり、グローバル位置を取得します。私の場合、小さな領域(約500m四方)の座標を変換したかったので、次のように投影点を別の2点に関連付け、グローバル位置を取得し、ローカル(画面上)位置に関連付けました。

まず、次の図のように、投影したい領域の周囲に2つのポイント(左上と右下)を選択します。

enter image description here

Latとlngにグローバル参照領域ができたら、画面の位置にも同じことを行います。このデータを含むオブジェクトを以下に示します。

//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:idが「point-to-project」であるhtml要素に変換された位置を適用しています。プロジェクトでこのコードを使用するには、この要素(絶対位置としてスタイル設定)を作成するか、「使用」ブロックを変更する必要があります。

4
allexrm

この同じ問題を検索している間、このページがグーグルの上に表示されるので、より実用的な答えを提供したいと思います。 MVGによる答えは正しいが、理論的です。

JavaScriptでfitbit ionicのトラックプロットアプリを作成しました。以下のコードは、この問題への取り組み方法です。

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

Utm座標に変換し、それをxおよびyとして扱う方が適切です。

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

結果は次のようになります(779260.623156606、1429369.8665238516、43、「P」)最初の2つはx、y座標として扱うことができます。43PはUTMゾーンであり、小さなエリア(幅668 kmまで)では無視できます。

0
Krishna Nagaraj