지점에서 위도 / 경도 X 마일을 계산 하시겠습니까?


46

방위, 거리 및 시작 위도 및 경도가 주어진 위도 및 경도 지점을 찾고 싶습니다.

이것은이 질문의 반대 인 것처럼 보입니다 ( 위도 / 경도 사이의 거리 ).

나는 이미 haversine 공식을 살펴 보았고 그것이 세계의 근사치라고 생각합니다.

알 수없는 위도 / 경도에 대한 haversine 공식을 풀어야한다고 가정하고 있습니다. 맞습니까? 이런 종류의 일에 대해 이야기하는 좋은 웹 사이트가 있습니까? 일반적인 것 같지만 내 인터넷 검색은 위의 질문과 비슷한 질문 만 나타났습니다.

내가 정말로 찾고있는 것은 이것에 대한 공식입니다. 나는 시작 위도 / 경도, 베어링 및 거리 (마일 또는 킬로미터)를주고 싶습니다. 그 길.


이 작업을 수행하는 도구 (예 : Esri 's pe.dll) 또는 수식을 찾고 있습니까?
Kirk Kuykendall

구체적이지 않아서 죄송합니다. 수식을 찾고 있습니다. 질문을 좀 더 구체적으로 업데이트하겠습니다.
Jason Whitehorn

해결 된 수학 샘플은 " aest = " 시작점으로부터의 거리와 베어링이 주어진 지점 ".
Stephen Quan


여기 페이지가 링크 위도에 / 긴 계산 [위도 / 경도 계산 (있음의 movable-type.co.uk/scripts/latlong.html )이 페이지 위도 / 경도 계산 코드 + 계산기있다
ABO 식 gaseem

답변:


21

이 수식의 결과가 Esri의 pe.dll 과 어떻게 비교되는지 궁금합니다 .

( 인용 ).

점 {lat, lon}은 다음과 같은 경우 점 1에서 tc 반경의 거리 d입니다.

 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와 같은 거리, 즉 지구 둘레의 1/4 미만에서 경도로 확장되는 거리로 제한됩니다. 더 먼 거리가 허용되는 경우 완전히 일반적이지만 더 복잡한 알고리즘이 필요합니다.

 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 페이지입니다 .


빠른 답변 감사합니다. 이 정보 중 일부를 요약 해 보도록하겠습니다. 그러나 표면 상으로는이 점이 드러납니다.
Jason Whitehorn

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
대박! Ed Williams의 Aviation Formulary 기사에 대한 링크에 대해 대단히 감사합니다. 이전에는 이것을 보지 못했지만 지금까지는 크게 읽혔습니다. 미래에 이것을보고있는 사람들을위한 참고 사항,이 공식의 입력 및 출력은 모두 거리, 라디안으로 표시됩니다.
Jason Whitehorn

1
이 공식에서 거리의 단위는 무엇입니까?
Karthik Murugan

1
@KarthikMurugan Ed의 소개에 따르면 거리 단위는 큰 원을 따라 라디안으로 표시됩니다.
Kirk Kuykendall

18

당신이 비행기에 있다면, 그 다음 인 점 R의 미터 거리의 베어링에 북쪽 동쪽의 정도가 R로 변위 * 북쪽 방향과 R의 COS (A) * 동쪽 방향으로 죄의 (a). (이 문장 들은 사인과 코사인을 다소 정의 합니다.)

지구 표면을 모델링하는 곡면 타원체의 표면에서 작업하고있는 비행기는 아니지만 수백 킬로미터 미만의 거리는 표면의 작은 부분을 커버하여 대부분의 실제적인 목적으로 할 수 있습니다. 평평한 것으로 간주됩니다. 유일하게 남아있는 합병증은 경도의 한도가 경도의 위도와 같은 거리를 커버하지 않는다는 것입니다. 구형 지구 모델에서 경도의 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
Frank Conry

4

당신은 자바 스크립트 솔루션을 필요로하는 경우이 고려 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, 2PI / 3은 E)이고 거리가 킬로미터 단위 인 ObjC에서 구현됩니다.

+ (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 위도를 얻고 싶은 해결책을 찾고 있습니다 ... 위의 답변에서 내가 달성 할 수있는 방법을 설명 할 수 있습니다 이 ?
Rahul Vyas

1

더 나은 정확도에 관심이 있다면 Vincenty가 있습니다. (링크는 '직접'양식으로 연결되며, 이는 바로 귀하가 추구하는 양식입니다).

코드를 따르는 경우 기존 구현이 상당히 있습니다.

또한 질문 : 당신은 여행자가 전체 여행에 대해 동일한 베어링을 유지한다고 가정하지 않습니다. 그렇다면 이러한 방법으로 올바른 질문에 대답하지 못합니다. (메르카토르로 투사하고 직선을 그린 다음 결과를 투사하지 않는 것이 좋습니다.)


매우 좋은 질문은 여행자의 목적지를 계산하고 있음을 나타내는 내 질문의 문구에도 불구하고 그렇지 않습니다. 그래도 좋은 지적입니다. 이것은 주로 경계 영역을 계산할 수 있도록하기위한 것입니다 (소액 주문, 50 마일).
Jason Whitehorn

gis.stackexchange.com/questions/3264/… 같은 질문을했습니다 (점 및 거리에서 경계 영역 구성)
Dan 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 어스에 플로팅합니다. 토지 제목에는 다음과 같은 방식으로 작성된 방위 및 거리가 있습니다. "NorthOrSouth x도 y 분 EastOrWest, z 미터에서 n까지 포인트";

따라서, 주어진 기준점 좌표에서 시작하여, 위치에 따라 다르기 때문에 hasrsine 공식을 사용하여 1도 위도 및 1도 경도 당 거리를 먼저 계산합니다. 그런 다음 삼각법 사인 및 코사인 공식에서 다음 좌표를 결정합니다.

아래는 자바 스크립트입니다.

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.