ポイントから緯度/経度Xマイルを計算しますか?


46

方位、距離、開始緯度と経度を指定して、緯度と経度のポイントを見つけたいです。

これは、この質問の反対のようです(緯度/経度ポイント間の距離)。

私はすでにHaversineの式を調べましたが、世界の近似値はおそらく十分近いと思います。

未知の緯度/経度のHaversine式を解く必要があると仮定していますが、これは正しいですか?この種のことについて語る良いウェブサイトはありますか?それは一般的なことのように思えますが、私のグーグルは上記のような質問を見つけました。

私が本当に探しているのは、このための公式です。開始時の緯度/経度、方位、距離(マイルまたはキロメートル)を指定したいと思います。そのルート。


これを行うツール(Esriのpe.dllなど)または数式をお探しですか?
カーククイケンダル

申し訳ありませんが、具体的ではありませんでした...式を探しています。質問をより具体的に更新します。
ジェイソンホワイトホーン

多数の計算された数学サンプルは、<a href=" moving-type.co.uk/scripts/latlong.html">緯度/経度ポイント間の距離、方位などを計算します</a>。開始点からの距離と方位を与えられた点」。
スティーブンクアン


ここでは緯度/経度の計算[緯度/経度の計算](へのリンクというページだmovable-type.co.uk/scripts/latlong.htmlが)も、このページ緯度/経度の計算コード+電卓があります
阿保gaseem

回答:


21

この式の結果がEsriのpe.dllとどのように比較されるのか興味があります。

引用)。

ポイント{lat、lon}は、ポイント1から放射状にtc上の距離d outです。

 lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
 IF (cos(lat)=0)
    lon=lon1      // endpoint a pole
 ELSE
    lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
 ENDIF

このアルゴリズムは、dlon <pi / 2となる距離、つまり経度で地球の円周の4分の1未満に広がる距離に制限されます。より大きな距離が許可される場合、完全に一般的ですが、より複雑なアルゴリズムが必要です。

 lat =asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
 dlon=atan2(sin(tc)*sin(d)*cos(lat1),cos(d)-sin(lat1)*sin(lat))
 lon=mod( lon1-dlon +pi,2*pi )-pi

これがテスト用のhtmlページです


迅速な返信ありがとうございます。この情報の一部をダイジェストさせてください。折り返しご連絡いたします。表面的には、しかし、これはスポットに見えます。
ジェイソンホワイトホーン

1
32N、117Wから40N、82Wのhtmlページから距離と前方方位を取得した後、pe.dll(実際にはsolarisのlibpe.so)を使用して、直接的なケースを試しました。32N、117W、d = 3255.056515890041、azi = 64.24498012065699を使用すると、40N、82W(実際には82.00000000064)になりました。
mkennedy

3
驚くばかり!エド・ウィリアムズによる航空フォーミュラリーの記事へのリンクをありがとうございました。私はこれを前に見たことがありませんでしたが、これは素晴らしい読書であることがこれまでに証明されました。将来これを見る人への注意点として、この式の入力と出力はすべてラジアン単位で、距離さえもです。
ジェイソンホワイトホーン

1
この式の距離の単位は何ですか?
カルティクMurugan

1
@KarthikMurugan Edのイントロは、距離単位は大円に沿ったラジアン単位であると言います。
カーククイケンダル

18

あなたが平面であった場合には、ある点のRメートルのベアリングで北東度がrで変位さ*北方向およびR COS()*東方向に罪()。(これらのステートメントは、多少サインとコサインを定義します。)

あなたは飛行機に乗っていませんが、地球の表面をモデル化する曲線楕円体の表面で作業していますが、数百キロメートル未満の距離は、ほとんどの実用的な目的のために表面のそのような小さな部分をカバーしますフラットと見なされます。唯一残っている問題は、経度の1度が緯度の同じ距離をカバーしていないことです。球形の地球モデルでは、緯度が1度である限り、経度1度はcos(緯度)のみです。(楕円モデルでは、これは依然として優れた近似値であり、約2.5桁の有効数字まで良好です。)

最後に、1度の緯度は約10 ^ 7/90 = 111,111メートルです。これで、メートルを度に変換するために必要なすべての情報が得られました。

北への変位はr * cos(a)/ 111111度です。

東への変位はr * sin(a)/ cos(緯度)/ 111111度です。

たとえば、緯度が-0.31399度で、方位が北=東の30度の場合、次のように計算できます。

cos(a) = cos(30 degrees) = cos(pi/6 radians) = Sqrt(3)/2 = 0.866025.
sin(a) = sin(30 degrees) = sin(pi/6 radians) = 1/2 = 0.5.
cos(latitude) = cos(-0.31399 degrees) = cos(-0.00548016 radian) = 0.999984984.
r = 100 meters.
east displacement = 100 * 0.5 / 0.999984984 / 111111 = 0.000450007 degree.
north displacement = 100 * 0.866025 / 111111 = 0.000779423 degree.

そこから、(-78.4437、-0.31399)から、新しい場所は(-78.4437 + 0.00045、-0.31399 + 0.0007794)=(-78.4432、-0.313211)になります。

最新のITRF00参照システムでのより正確な回答は(-78.4433、-0.313207)です。これは近似回答から0.43メートル離れており、この場合0.43%の近似エラーを示しています。より高い精度を実現するには、楕円距離式(はるかに複雑)または発散がゼロの忠実度の高い正角図法(方位が正しい)を使用する必要があります。


2
数学的なコンテキスト(つまり、そのローカルな平面)を適切に理解するために+1
フランクコンリー14

4

JavaScriptソリューションが必要な場合は、これらfunctionsこのフィドルを検討してください。

var gis = {
  /**
  * All coordinates expected EPSG:4326
  * @param {Array} start Expected [lon, lat]
  * @param {Array} end Expected [lon, lat]
  * @return {number} Distance - meter.
  */
  calculateDistance: function(start, end) {
    var lat1 = parseFloat(start[1]),
        lon1 = parseFloat(start[0]),
        lat2 = parseFloat(end[1]),
        lon2 = parseFloat(end[0]);

    return gis.sphericalCosinus(lat1, lon1, lat2, lon2);
  },

  /**
  * All coordinates expected EPSG:4326
  * @param {number} lat1 Start Latitude
  * @param {number} lon1 Start Longitude
  * @param {number} lat2 End Latitude
  * @param {number} lon2 End Longitude
  * @return {number} Distance - meters.
  */
  sphericalCosinus: function(lat1, lon1, lat2, lon2) {
    var radius = 6371e3; // meters
    var dLon = gis.toRad(lon2 - lon1),
        lat1 = gis.toRad(lat1),
        lat2 = gis.toRad(lat2),
        distance = Math.acos(Math.sin(lat1) * Math.sin(lat2) +
            Math.cos(lat1) * Math.cos(lat2) * Math.cos(dLon)) * radius;

    return distance;
  },

  /**
  * @param {Array} coord Expected [lon, lat] EPSG:4326
  * @param {number} bearing Bearing in degrees
  * @param {number} distance Distance in meters
  * @return {Array} Lon-lat coordinate.
  */
  createCoord: function(coord, bearing, distance) {
    /** http://www.movable-type.co.uk/scripts/latlong.html
    * φ is latitude, λ is longitude, 
    * θ is the bearing (clockwise from north), 
    * δ is the angular distance d/R; 
    * d being the distance travelled, R the earth’s radius*
    **/
    var 
      radius = 6371e3, // meters
      δ = Number(distance) / radius, // angular distance in radians
      θ = gis.toRad(Number(bearing));
      φ1 = gis.toRad(coord[1]),
      λ1 = gis.toRad(coord[0]);

    var φ2 = Math.asin(Math.sin(φ1)*Math.cos(δ) + 
      Math.cos(φ1)*Math.sin(δ)*Math.cos(θ));

    var λ2 = λ1 + Math.atan2(Math.sin(θ) * Math.sin(δ)*Math.cos(φ1),
      Math.cos(δ)-Math.sin(φ1)*Math.sin(φ2));
    // normalise to -180..+180°
    λ2 = (λ2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI; 

    return [gis.toDeg(λ2), gis.toDeg(φ2)];
  },
  /**
   * All coordinates expected EPSG:4326
   * @param {Array} start Expected [lon, lat]
   * @param {Array} end Expected [lon, lat]
   * @return {number} Bearing in degrees.
   */
  getBearing: function(start, end){
    var
      startLat = gis.toRad(start[1]),
      startLong = gis.toRad(start[0]),
      endLat = gis.toRad(end[1]),
      endLong = gis.toRad(end[0]),
      dLong = endLong - startLong;

    var dPhi = Math.log(Math.tan(endLat/2.0 + Math.PI/4.0) / 
      Math.tan(startLat/2.0 + Math.PI/4.0));

    if (Math.abs(dLong) > Math.PI) {
      dLong = (dLong > 0.0) ? -(2.0 * Math.PI - dLong) : (2.0 * Math.PI + dLong);
    }

    return (gis.toDeg(Math.atan2(dLong, dPhi)) + 360.0) % 360.0;
  },
  toDeg: function(n) { return n * 180 / Math.PI; },
  toRad: function(n) { return n * Math.PI / 180; }
};

したがって、新しい座標を計算する場合、次のようになります。

var start = [15, 38.70250];
var end = [21.54967, 38.70250];
var total_distance = gis.calculateDistance(start, end); // meters
var percent = 10;
// this can be also meters
var distance = (percent / 100) * total_distance;
var bearing = gis.getBearing(start, end);
var new_coord = gis.createCoord(icon_coord, bearing, distance);

2

これをObjectiveCで動作させました。ここで重要なのは、ラジアン単位の緯度/経度のポイントが必要であり、方程式を適用した後にそれらを緯度/経度に変換する必要があることを知ることです。また、距離とtcはラジアン単位であることも知ってください。

元の方程式は次のとおりです。

 lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
 IF (cos(lat)=0)
    lon=lon1      // endpoint a pole
 ELSE
    lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
 ENDIF

ここでは、ラジアンはNから反時計回りに測定されたラジアン(例:PI / 2はW、PIはS、2 PI / 3はE)であり、距離はキロメートル単位です。

+ (CLLocationCoordinate2D)displaceLatLng:(CLLocationCoordinate2D)coordinate2D withRadian:(double)radian
                            withDistance:(CGFloat)distance {
  double lat1Radians = coordinate2D.latitude * (M_PI / 180);
  double lon1Radians = coordinate2D.longitude * (M_PI / 180);
  double distanceRadians = distance / 6371;
  double lat = asin(sin(lat1Radians)*cos(distanceRadians)+cos(lat1Radians)*sin(distanceRadians)
      *cos(radian));
  double lon;
  if (cos(lat) == 0) {
    lon = lon1Radians;
  } else {
    lon = fmodf((float) (lon1Radians - asin(sin(radian) * sin(distanceRadians) / cos(lat)) + M_PI),
        (float) (2 * M_PI)) - M_PI;
  }
  double newLat = lat * (180 / M_PI);
  double newLon = lon * (180 / M_PI);
  return CLLocationCoordinate2DMake(newLat, newLon);
}

北緯50マイル、西経50マイル、東経50マイルなど、4 latを取得するソリューションを探しています...上記の回答では、どのように達成できるか説明できますか?この ?
ラーフルヴィアス

1

精度の向上に関心がある場合は、Vincentyがあります。(リンクは「直接」形式へのリンクであり、これはまさにあなたが求めているものです)。

あなたがコードを追っているなら、かなりの数の既存の実装があります。

また、質問:旅行者が旅行全体で同じ方位を維持しているとは思わないのですか?もしそうなら、これらの方法は正しい質問に答えていません。(メルカトルに投影し、直線を描画してから、結果の投影を解除する方が良いでしょう。)


非常に良い質問です。旅行者の目的地を計算していることを示しているかもしれない私の質問の文言にもかかわらず、私はそうではありません。良い点。これは主に、境界領域を計算できるようにするためです(50マイルなどの小さな順序で)。
ジェイソンホワイトホーン

gis.stackexchange.com/questions/3264/…同じ質問(ポイントと距離から境界領域を構築する)
ダンS.

0

Pythonソリューションは次のとおりです。

    def displace(self, theta, distance):
    """
    Displace a LatLng theta degrees counterclockwise and some
    meters in that direction.
    Notes:
        http://www.movable-type.co.uk/scripts/latlong.html
        0 DEGREES IS THE VERTICAL Y AXIS! IMPORTANT!
    Args:
        theta:    A number in degrees.
        distance: A number in meters.
    Returns:
        A new LatLng.
    """
    theta = np.float32(theta)

    delta = np.divide(np.float32(distance), np.float32(E_RADIUS))

    def to_radians(theta):
        return np.divide(np.dot(theta, np.pi), np.float32(180.0))

    def to_degrees(theta):
        return np.divide(np.dot(theta, np.float32(180.0)), np.pi)

    theta = to_radians(theta)
    lat1 = to_radians(self.lat)
    lng1 = to_radians(self.lng)

    lat2 = np.arcsin( np.sin(lat1) * np.cos(delta) +
                      np.cos(lat1) * np.sin(delta) * np.cos(theta) )

    lng2 = lng1 + np.arctan2( np.sin(theta) * np.sin(delta) * np.cos(lat1),
                              np.cos(delta) - np.sin(lat1) * np.sin(lat2))

    lng2 = (lng2 + 3 * np.pi) % (2 * np.pi) - np.pi

    return LatLng(to_degrees(lat2), to_degrees(lng2))

-2

次のアプローチを使用して、方位と前の座標からの距離を考慮して次の座標を決定します。私はインターネットから読んだ他のアプローチの精度に問題があります。

これを使用して、ポリゴンである土地の面積を決定し、Google Earthでそのポリゴンをプロットします。土地のタイトルには、「NorthOrSouth x度y分EastOrWest、zメートルからポイントn;」のように記述された方位と距離があります。

したがって、基準点の指定された座標から開始し、最初にHaversine式を使用して緯度1度と経度1度あたりの距離を計算します。これは場所によって異なるためです。次に、三角法のサインとコサインの式から次の座標を決定します。

以下はjavascriptです。

var mapCenter = new google.maps.LatLng(referencePointLatitude, referencePointLongitude); //the ref point lat and lon must be given, usually a land mark (BLLM)
var latDiv = latDiv(mapCenter); //distance per one degree latitude in this location
var lngDiv = lngDiv(mapCenter); //distance per one degree longitude in this location
var LatLng2 = NextCoord(PrevCoord,NorthOrSouth,x,y,EastOrWest,z); //next coordinate given the bearing and distance from previous coordinate
var Lat2 = LatLng2.lat(); //next coord latitude in degrees
var Lng2 = LatLng2.lng(); //next coord longitude in degrees
var polygon=[p1,p2,...,pn-1,pn,p1]; //p1,p2,etc. are the coordinates of points of the polygon, i.e. the land Title. Be sure to close the polygon to the point of beginning p1
var area = Area(polygon); //area of the polygon in sq.m.
function NextCoord(PrevCoord,NorthOrSouth,x,y,EastOrWest,z) {
  var angle = ( x + ( y / 60 ) ) * Math.PI / 180;
  var a = 1;
  var b = 1;
  if (NorthOrSouth == 'South') { a = -1; }
  if (EastOrWest == 'West') { b = -1; }
  var nextLat = PrevCoord.lat() +  ( a * z * Math.cos(angle) / latDiv );
  var nextLng = PrevCoord.lng() +  ( b * z * Math.sin(angle) / lngDiv );
  var nextCoord = new google.maps.LatLng(nextLat, nextLng);
  return nextCoord;
}
function latDiv(mapCenter) {
  var p1 = new google.maps.LatLng(mapCenter.lat()-0.5, mapCenter.lng());
  var p2 = new google.maps.LatLng(mapCenter.lat()+0.5, mapCenter.lng());
  return dist(p1,p2);
}
function lngDiv(mapCenter) {
  var p3 = new google.maps.LatLng(mapCenter.lat(), mapCenter.lng()-0.5);
  var p4 = new google.maps.LatLng(mapCenter.lat(), mapCenter.lng()+0.5);
  return dist(p3,p4);
}
function dist(pt1, pt2) {
    var dLat  = ( pt2.lat() - pt1.lat() ) * Math.PI / 180;
    var dLng = ( pt2.lng() - pt1.lng() ) * Math.PI / 180;
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +                 
            Math.cos(rad(pt1.lat())) * Math.cos(rad(pt2.lat())) *
            Math.sin(dLng/2) * Math.sin(dLng/2);
    var R = 6372800; //earth's radius
    var distance = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    return distance;
}
function Area(polygon) {
  var xPts=[];
  for (i=1; i&lt;polygon.length; i++) {
    xPts[i-1] = ( polygon[i].lat() - polygon[0].lat() ) * latDiv;
  }
  var yPts=[];
  for (i=1; i&lt;polygon.length; i++) {
    yPts[i-1] = ( polygon[i].lng() - polygon[0].lng() ) * lngDiv;
  }
  var area = 0;
  j = polygon.length-2;
  for (i=0; i&lt;polygon.length-1; i++) {
    area = area +  ( xPts[j] + xPts[i] ) * ( yPts[j] - yPts[i] );
    j = i;
  }
  area = Math.abs(area/2);
  return area;
}

1
ここで適用しようとするポリゴン領域のデカルト式は、曲面(回転楕円体など)で計算された距離と角度には適用できません。この式では、緯度と経度をデカルト座標であるかのように使用することにより、追加のエラーが発生します。その使用が考慮される唯一の状況は、とにかくhaversineの式が不要である(非常に小さなポリゴンの)場合だけです。全体として、このコードは無益に機能しすぎているようです。
whuber
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.