緯度/経度の既存のポイント、距離(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
回答をラジアンから度に戻す必要がありました。以下の作業コード:
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)
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
回答に少し遅れる場合がありますが、他の回答をテストした後、正しく機能していないようです。ここに、システムに使用する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;
}
この質問は、 geodesy の研究ではdirect problemとして知られています。
これは確かに非常に一般的な質問であり、常に混乱の原因となっています。その理由は、ほとんどの人がシンプルでわかりやすい答えを探しているからです。しかし、この質問をしているほとんどの人が十分な情報を提供していないので、何もありません。単に次のことに気づいていないからです。
R
がないためです。 here を参照してください。したがって、必要な精度に応じて、さまざまな幾何モデルで使用されるさまざまな仮定がさまざまに適用されます。したがって、質問に答えるには、accuracyを検討する必要があります。
いくつかの例:
latitudes
間の0-70 deg
の距離が小さい(<100 km)の場合、最も近い数キロメートルに近い場所を探しています。N | S。 (地球は〜平面モデルです。)nanometers
[nm]の原子スケールまで有効な超正確な位置決めが必要です。そのため、どのアルゴリズムを使用するかについて多くの選択肢があります。さらに、各プログラミング言語には、モデルの数とモデル開発者固有のニーズを掛け合わせた独自の実装または「パッケージ」があります。ここでのすべての実用的な目的のために、javascript
以外の他の言語を無視することは、その性質により擬似コードに非常によく似ているので、見返りがあります。したがって、最小限の変更で他の言語に簡単に変換できます。
次に、主なモデルは次のとおりです。
Euclidian/Flat earth model
:10 km未満の非常に短い距離に適していますSpherical model
:縦方向の距離が長い場合に適していますが、緯度の差はわずかです。人気モデル:Ellipsoidal models
:緯度/経度と距離で最も正確ですが、必要な精度に依存する数値近似です。人気のあるモデルは次のとおりです。参照:
度単位の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コードをテストしなかったため、構文エラーが発生する可能性があります。
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 に貼り付けて、すぐに結果を確認できます。
また遅くなりますが、これを見つけるかもしれない人のために、 geographiclib ライブラリを使用してより正確な結果を得るでしょう。測地線の問題の説明とJavaScriptの例を確認して、主題の質問や他の多くの質問に答える方法を簡単に紹介してください。 Pythonを含むさまざまな言語での実装。正確性を重視する場合は、独自のコーディングよりもはるかに優れています。以前の「ライブラリを使用する」推奨事項のVincentyDistanceよりも優れています。ドキュメントには次のように記載されています。「重要なのは、丸めに近い誤差(約5〜15ナノメートル)で正確な結果を返すことです。」
Atan2(y、x)関数の値を交換するだけです。 atan2(x、y)ではありません!
@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);
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));
},
エド・ウィリアムズ航空処方に基づいた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;
}