program story

현재 지점, 거리 및 방위각에 따라 위도 / 경도를 가져옵니다.

inputbox 2020. 12. 4. 08:10
반응형

현재 지점, 거리 및 방위각에 따라 위도 / 경도를 가져옵니다.


위도 / 경도, 거리 (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);  

여기에 제가 파이썬으로 작성한 코드가 있습니다.

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

https://stackoverflow.com/a/4531227/37610을 통해 찾았습니다.


답변하는 데 약간 늦을 수 있지만 다른 답변을 테스트 한 후 제대로 작동하지 않는 것 같습니다. 다음은 시스템에 사용하는 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;
 }

이 질문은 측지학 연구에서 직접적인 문제 로 알려져 있습니다.

이것은 실제로 매우 인기있는 질문이며 끊임없는 혼란의 원인입니다. 그 이유는 대부분의 사람들이 간단하고 직접적인 대답을 찾고 있기 때문입니다. 그러나이 질문을하는 대부분의 사람들은 다음을 알지 못하기 때문에 충분한 정보를 제공하지 않기 때문에 없습니다.

  1. 지구는 극에 의해 평평 해지고 압축되기 때문에 완벽한 구체가 아닙니다.
  2. (1) 지구에는 일정한 반경이 없기 때문에 R. 를 참조하십시오 여기 .
  3. 지구는 완벽하게 부드럽 지 않습니다 (고도 변화).
  4. 지각 판의 움직임으로 인해 지리적 지점의 위도 / 경도 위치가 매년 수 밀리미터 (적어도) 변경 될 수 있습니다.

따라서 필요한 정확도에 따라 다르게 적용되는 다양한 지오메트리 모델에 사용되는 다양한 가정이 있습니다. 따라서 질문에 답하려면 결과를 얻고 자 하는 정확성 을 고려해야합니다 .

몇 가지 예 :

  • 나는 단지 N | S 사이 작은 ( < 100km) 거리에 대해 가장 가까운 몇 킬로미터에 대한 대략적인 위치를 찾고 있습니다. (지구는 ~ 플랫 모델입니다.)latitudes0-70 deg
  • 전 세계 어느 곳에서나 좋은 답변을 원하지만 몇 미터 정도만 정확합니다.
  • 저는 nanometers[nm] 의 원자 규모까지 유효한 매우 정확한 위치를 원합니다 .
  • 매우 빠르고 계산하기 쉽고 계산 집약적이지 않은 답변을 원합니다.

따라서 어떤 알고리즘을 사용할지 선택할 수 있습니다. 또한 각 프로그래밍 언어에는 자체 구현 또는 "패키지"에 모델 수와 모델 개발자의 특정 요구가 곱해집니다. 여기서 모든 실용적인 목적을 위해 다른 언어는 무시하는 javascript것이 좋습니다. 그 특성상 의사 코드와 매우 유사하기 때문입니다. 따라서 최소한의 변경으로 다른 언어로 쉽게 변환 할 수 있습니다.

그런 다음 주요 모델은 다음과 같습니다.

  • Euclidian/Flat earth model: 약 10km 미만의 매우 짧은 거리에 적합
  • Spherical model: 긴 종 방향 거리에 적합하지만 위도 차이가 작습니다. 인기 모델 :
    • Haversine : [km] 단위의 미터 정확도, 매우 간단한 코드.
  • 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 %의 시간에 실행되었습니다. 생성 된 결과는 동일하므로 수학적으로 동일한 것 같습니다.

위의 파이썬 코드를 테스트하지 않았으므로 구문 오류가있을 수 있습니다.


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의 답변을 Bing 맵 종속성없이 바닐라 JS 답변으로 포팅했습니다.

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 스크린 샷


Also late but for those who might find this, you will get more accurate results using the geographiclib library. Check out the geodesic problem descriptions and the JavaScript examples for an easy introduction to how to use to answer the subject question as well as many others. Implementations in a variety of languages including Python. Far better than coding your own if you care about accuracy; better than VincentyDistance in the earlier "use a library" recommendation. As the documentation says: "The emphasis is on returning accurate results with errors close to round-off (about 5–15 nanometers)."


Just interchange the values in the atan2(y,x) function. Not atan2(x,y)!


I ported the Python to Javascript. This returns a Bing Maps Location object, you can change to whatever you like.

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

},

다음은 Ed Williams Aviation Formulary를 기반으로하는 PHP 버전입니다. Modulus는 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;

}

누군가 이것을 원하면 @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);

참고 URL : https://stackoverflow.com/questions/7222382/get-lat-long-given-current-point-distance-and-bearing

반응형