web-dev-qa-db-ja.com

現在のポイント、距離、方位を指定して緯度/経度を取得する

緯度/経度の既存のポイント、距離(KM)および方位(ラジアンに変換された度数)が与えられた場合、新しい緯度/経度を計算したいと思います。 これ サイトは何度も切り替わるが、公式がうまく機能しない。

上記のリンクから取得した式は次のとおりです。

lat2 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(θ))

lon2 = lon1 + atan2(sin(θ)*sin(d/R)*cos(lat1), cos(d/R)−sin(lat1)*sin(lat2))

上記の式はMSExcel用です。

asin          = arc sin()   
d             = distance (in any unit)   
R             = Radius of the earth (in the same unit as above)  
and hence d/r = is the angular distance (in radians)  
atan2(a,b)    = arc tan(b/a)  
θ is the bearing (in radians, clockwise from north);  

Pythonで取得したコードは次のとおりです。

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2  52.20444 - the lat result I'm hoping for
#lon2  0.36056 - the long result I'm hoping for.

lat1 = 52.20472 * (math.pi * 180) #Current lat point converted to radians
lon1 = 0.14056 * (math.pi * 180) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
             math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
                     math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

print(lat2)
print(lon2)

私は得る

lat2 = 0.472492248844 
lon2 = 79.4821662373
60
David M

回答をラジアンから度に戻す必要がありました。以下の作業コード:

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2  52.20444 - the lat result I'm hoping for
#lon2  0.36056 - the long result I'm hoping for.

lat1 = math.radians(52.20472) #Current lat point converted to radians
lon1 = math.radians(0.14056) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
     math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
             math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)

print(lat2)
print(lon2)
62
David M

geopy ライブラリはこれをサポートします:

import geopy
from geopy.distance import VincentyDistance

# given: lat1, lon1, b = bearing in degrees, d = distance in kilometers

Origin = geopy.Point(lat1, lon1)
destination = VincentyDistance(kilometers=d).destination(Origin, b)

lat2, lon2 = destination.latitude, destination.longitude

https://stackoverflow.com/a/4531227/3761 で見つかりました

28
elliot42

回答に少し遅れる場合がありますが、他の回答をテストした後、正しく機能していないようです。ここに、システムに使用するPHPコードを示します。すべての方向で作業します。

PHPコード:

lat1 =開始点の緯度(度)

long1 =開始点の経度(度単位)

d = KM単位の距離

角度=方位(度)

function get_gps_distance($lat1,$long1,$d,$angle)
{
    # Earth Radious in KM
    $R = 6378.14;

    # Degree to Radian
    $latitude1 = $lat1 * (M_PI/180);
    $longitude1 = $long1 * (M_PI/180);
    $brng = $angle * (M_PI/180);

    $latitude2 = asin(sin($latitude1)*cos($d/$R) + cos($latitude1)*sin($d/$R)*cos($brng));
    $longitude2 = $longitude1 + atan2(sin($brng)*sin($d/$R)*cos($latitude1),cos($d/$R)-sin($latitude1)*sin($latitude2));

    # back to degrees
    $latitude2 = $latitude2 * (180/M_PI);
    $longitude2 = $longitude2 * (180/M_PI);

    # 6 decimal for Leaflet and other system compatibility
   $lat2 = round ($latitude2,6);
   $long2 = round ($longitude2,6);

   // Push in array and get back
   $tab[0] = $lat2;
   $tab[1] = $long2;
   return $tab;
 }
11
Peter

この質問は、 geodesy の研究ではdirect problemとして知られています。

これは確かに非常に一般的な質問であり、常に混乱の原因となっています。その理由は、ほとんどの人がシンプルでわかりやすい答えを探しているからです。しかし、この質問をしているほとんどの人が十分な情報を提供していないので、何もありません。単に次のことに気づいていないからです。

  1. 地球は完全な球体ではありません。
  2. (1)地球には一定の半径Rがないためです。 here を参照してください。
  3. 地球は完全に滑らかではありません(高度の変動)など。
  4. 構造プレートの動きにより、地理的ポイントの緯度/経度の位置は毎年数ミリメートル(少なくとも)変化する可能性があります。

したがって、必要な精度に応じて、さまざまな幾何モデルで使用されるさまざまな仮定がさまざまに適用されます。したがって、質問に答えるには、accuracyを検討する必要があります。

いくつかの例:

  • latitudes間の0-70 degの距離が小さい(<100 km)の場合、最も近い数キロメートルに近い場所を探しています。N | S。 (地球は〜平面モデルです。)
  • 世界中のどこでも良いが、数メートル程度の精度の答えが欲しい
  • nanometers [nm]の原子スケールまで有効な超正確な位置決めが必要です。
  • 計算が非常に速く、計算が簡単で、計算量が多くない答えが欲しいです。

そのため、どのアルゴリズムを使用するかについて多くの選択肢があります。さらに、各プログラミング言語には、モデルの数とモデル開発者固有のニーズを掛け合わせた独自の実装または「パッケージ」があります。ここでのすべての実用的な目的のために、javascript以外の他の言語を無視することは、その性質により擬似コードに非常によく似ているので、見返りがあります。したがって、最小限の変更で他の言語に簡単に変換できます。

次に、主なモデルは次のとおりです。

  • Euclidian/Flat earth model:10 km未満の非常に短い距離に適しています
  • Spherical model:縦方向の距離が長い場合に適していますが、緯度の差はわずかです。人気モデル:
    • Haversinemeter[km]スケールの精度、非常に単純なコード。
  • Ellipsoidal models:緯度/経度と距離で最も正確ですが、必要な精度に依存する数値近似です。人気のあるモデルは次のとおりです。

参照:

10
not2qubit

度単位のlon1およびlat1

brng =ラジアン単位の方位

d = km単位の距離

R =地球の半径(km)

lat2 = math.degrees((d/R) * math.cos(brng)) + lat1
long2 = math.degrees((d/(R*math.sin(math.radians(lat2)))) * math.sin(brng)) + long1

私はあなたのアルゴリズムをPHP=で実装し、ベンチマークしました。このバージョンは約50%の時間で実行されました。生成された結果は同一であったため、数学的に同等です。

上記のpythonコードをテストしなかったため、構文エラーが発生する可能性があります。

3
Chris

Geopyを使用した簡単な方法

from geopy import distance
#distance.distance(unit=15).destination((lat,lon),bering) 
#Exemples
distance.distance(nautical=15).destination((-24,-42),90) 
distance.distance(miles=15).destination((-24,-42),90)
distance.distance(kilometers=15).destination((-24,-42),90) 

Bradの回答をVanilla JSの回答に移植しました。Bingマップの依存関係はありません。

https://jsfiddle.net/kodisha/8a3hcjtd/

// ----------------------------------------
// Calculate new Lat/Lng from original points
// on a distance and bearing (angle)
// ----------------------------------------
let llFromDistance = function(latitude, longitude, distance, bearing) {
  // taken from: https://stackoverflow.com/a/46410871/13549 
  // distance in KM, bearing in degrees

  const R = 6378.1; // Radius of the Earth
  const brng = bearing * Math.PI / 180; // Convert bearing to radian
  let lat = latitude * Math.PI / 180; // Current coords to radians
  let lon = longitude * Math.PI / 180;

  // Do the math magic
  lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng));
  lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance / R) - Math.sin(lat) * Math.sin(lat));

  // Coords back to degrees and return
  return [(lat * 180 / Math.PI), (lon * 180 / Math.PI)];

}

let pointsOnMapCircle = function(latitude, longitude, distance, numPoints) {
  const points = [];
  for (let i = 0; i <= numPoints - 1; i++) {
    const bearing = Math.round((360 / numPoints) * i);
    console.log(bearing, i);
    const newPoints = llFromDistance(latitude, longitude, distance, bearing);
    points.Push(newPoints);
  }
  return points;
}


const points = pointsOnMapCircle(41.890242042122836, 12.492358982563019, 0.2, 8);


let geoJSON = {
  "type": "FeatureCollection",
  "features": []
};
points.forEach((p) => {
  geoJSON.features.Push({
    "type": "Feature",
    "properties": {},
    "geometry": {
      "type": "Point",
      "coordinates": [
        p[1],
        p[0]
      ]
    }
  });
});



document.getElementById('res').innerHTML = JSON.stringify(geoJSON, true, 2);

さらに、geoJSONエクスポートを追加したため、結果のgeoJSONを http://geojson.io/#map=17/41.89017/12.49171 に貼り付けて、すぐに結果を確認できます。

結果: geoJSON Screenshot

2
kodisha

また遅くなりますが、これを見つけるかもしれない人のために、 geographiclib ライブラリを使用してより正確な結果を得るでしょう。測地線の問題の説明とJavaScriptの例を確認して、主題の質問や他の多くの質問に答える方法を簡単に紹介してください。 Pythonを含むさまざまな言語での実装。正確性を重視する場合は、独自のコーディングよりもはるかに優れています。以前の「ライブラリを使用する」推奨事項のVincentyDistanceよりも優れています。ドキュメントには次のように記載されています。「重要なのは、丸めに近い誤差(約5〜15ナノメートル)で正確な結果を返すことです。」

1
jwd630

Atan2(y、x)関数の値を交換するだけです。 atan2(x、y)ではありません!

1
Asrat

@David Mからの回答をJavaにこれが必要な場合は移植しました... 52.20462299620793、0.360433887489931のわずかに異なる結果が得られます

    double R = 6378.1;  //Radius of the Earth
    double brng = 1.57;  //Bearing is 90 degrees converted to radians.
    double d = 15;  //Distance in km

    double lat2 = 52.20444; // - the lat result I'm hoping for
    double lon2 = 0.36056; // - the long result I'm hoping for.

    double lat1 = Math.toRadians(52.20472); //Current lat point converted to radians
    double lon1 = Math.toRadians(0.14056); //Current long point converted to radians

    lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
            Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng));

    lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),
            Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));

    lat2 = Math.toDegrees(lat2);
    lon2 = Math.toDegrees(lon2);

    System.out.println(lat2 + ", " + lon2);
0
Alessandro

Python=をJavascriptに移植しました。これにより、Bing Maps Locationオブジェクトが返されます。必要に応じて変更できます。

getLocationXDistanceFromLocation: function(latitude, longitude, distance, bearing) {
    // distance in KM, bearing in degrees

    var R = 6378.1,                         // Radius of the Earth
        brng = Math.radians(bearing)       // Convert bearing to radian
        lat = Math.radians(latitude),       // Current coords to radians
        lon = Math.radians(longitude);

    // Do the math magic
    lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng));
    lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance/R)-Math.sin(lat)*Math.sin(lat));

    // Coords back to degrees and return
    return new Microsoft.Maps.Location(Math.degrees(lat), Math.degrees(lon));

},
0
Brad Mathews

エド・ウィリアムズ航空処方に基づいたPHPバージョンです。モジュラスはPHPで少し異なる方法で処理されます。これは私には有効です。

function get_new_waypoint ( $lat, $lon, $radial, $magvar, $range )
{

   // $range in nm.
   // $radial is heading to or bearing from    
   // $magvar for local area.

   $range = $range * pi() /(180*60);
   $radial = $radial - $magvar ;

   if ( $radial < 1 )
     {
        $radial = 360 + $radial - $magvar; 
     }
   $radial =  deg2rad($radial);
   $tmp_lat = deg2rad($lat);
   $tmp_lon = deg2rad($lon);
   $new_lat = asin(sin($tmp_lat)* cos($range) + cos($tmp_lat) * sin($range) * cos($radial));
   $new_lat = rad2deg($new_lat);
   $new_lon = $tmp_lon - asin(sin($radial) * sin($range)/cos($new_lat))+ pi() % 2 * pi() -  pi();
   $new_lon = rad2deg($new_lon);

   return $new_lat." ".$new_lon;

}
0
Bruce