위도 / 경도 포인트 3 개와 거리 3 개를 사용한 평가?


34

알 수없는 대상 위치 (위도와 경도 좌표)를 찾고 싶습니다. 3 개의 알려진 지점 (위도와 경도 좌표 쌍)이 있으며 각 지점에 대해 대상 위치까지 킬로미터 거리입니다. 대상 위치의 좌표를 어떻게 계산할 수 있습니까?

예를 들어 다음과 같은 데이터 포인트가 있다고 가정 해보십시오.

37.418436,-121.963477   0.265710701754km
37.417243,-121.961889   0.234592423446km
37.418692,-121.960194   0.0548954278262km

내가 좋아하는 것은 입력으로 사용하고 출력으로 37.417959, -121.961954를 반환하는 함수의 수학입니다.

나는에서 두 점 사이의 거리를 계산하는 방법을 이해 http://www.movable-type.co.uk/scripts/latlong.html 다음과 같은 세 개의 원으로 당신이 중복 정확히 하나의 포인트를 얻을 나는 일반적인 원리를 이해합니다. 내가 헷갈리는 것은이 입력으로 그 지점을 계산하는 데 필요한 수학입니다.


다음은 세 좌표의 중심을 찾는 수학을 안내하는 페이지입니다. 아마도 어떤 식 으로든 도움이 될 수 있습니다. < mathforum.org/library/drmath/view/68373.html >
Jon Bringhurst

1
이것이 구 / 구형에 있어야합니까, 아니면 평면 알고리즘입니까?
fmark

1
답을 드릴 수는 없지만 올바른 방향으로 안내 할 수 있다고 생각합니다. 3 개의 좌표 = 3 개의 중심점. 세 거리 = 세 원. 교차하는 두 개의 원은 none / one / two 솔루션의 가능성을 가질 수 있습니다. 3 개의 원은 솔루션으로 없음 / 하나 / 지역을 가질 수 있습니다. 세 개의 원에 대한 원 수식을 구하고 Equations / Algebra 시스템으로 풉니 다.
CrazyEnigma

실제로이 문제를 해결하기 위해 시스템이 필요하지 않습니다. 하나 또는 두 가지 가능성이 있지만 거리 값이 있으므로 정답을 분리 할 수 ​​있습니다.
George Silva

1
+1 이것은 좋은 질문입니다. 처음에는 Google에서 솔루션을 쉽게 찾을 수 있지만 분명히 그렇지 않다고 생각했습니다. 아마도 문제는 더 일반적으로 언급 될 수 있습니다. 각 점에 거리뿐만 아니라 오차 한계가있는 N 점이 주어지면 신뢰 타원을 찾으십시오.
Kirk Kuykendall

답변:


34

Wikipedia 를 둘러보고 StackOverflow 에서 동일한 질문 / 답변을 한 후에 , 나는 그것을 찌르고 격차를 메우려 고 노력했습니다.

첫째, 출력을 어디서 얻었는지 확실하지 않지만 잘못된 것으로 보입니다. ArcMap에서 점을 플로팅하고 지정된 거리까지 버퍼링하고 버퍼에서 교차 한 다음 교차 정점을 캡처하여 솔루션을 얻었습니다. 제안 된 출력은 녹색입니다. 콜 아웃 박스의 값을 계산했는데, 이는 ArcMap이 교차로부터 파생 된 솔루션에 대해 준 약 3 미터입니다.

대체 텍스트

위키 피 디아 페이지의 수학은 찾을 수 직교 ECEF, 당신의 측지 좌표를 은밀한 할 필요도 나쁘지 않다 여기 . 타원체를 사용하지 않는 경우 a / x + h 항을 정통 구형 반지름으로 바꿀 수 있습니다.

아마도 가장 쉬운 문서화 된 코드를 제공하므로 파이썬으로되어 있습니다.

import math
import numpy

#assuming elevation = 0
earthR = 6371
LatA = 37.418436
LonA = -121.963477
DistA = 0.265710701754
LatB = 37.417243
LonB = -121.961889
DistB = 0.234592423446
LatC = 37.418692
LonC = -121.960194
DistC = 0.0548954278262

#using authalic sphere
#if using an ellipsoid this step is slightly different
#Convert geodetic Lat/Long to ECEF xyz
#   1. Convert Lat/Long to radians
#   2. Convert Lat/Long(radians) to ECEF
xA = earthR *(math.cos(math.radians(LatA)) * math.cos(math.radians(LonA)))
yA = earthR *(math.cos(math.radians(LatA)) * math.sin(math.radians(LonA)))
zA = earthR *(math.sin(math.radians(LatA)))

xB = earthR *(math.cos(math.radians(LatB)) * math.cos(math.radians(LonB)))
yB = earthR *(math.cos(math.radians(LatB)) * math.sin(math.radians(LonB)))
zB = earthR *(math.sin(math.radians(LatB)))

xC = earthR *(math.cos(math.radians(LatC)) * math.cos(math.radians(LonC)))
yC = earthR *(math.cos(math.radians(LatC)) * math.sin(math.radians(LonC)))
zC = earthR *(math.sin(math.radians(LatC)))

P1 = numpy.array([xA, yA, zA])
P2 = numpy.array([xB, yB, zB])
P3 = numpy.array([xC, yC, zC])

#from wikipedia
#transform to get circle 1 at origin
#transform to get circle 2 on x axis
ex = (P2 - P1)/(numpy.linalg.norm(P2 - P1))
i = numpy.dot(ex, P3 - P1)
ey = (P3 - P1 - i*ex)/(numpy.linalg.norm(P3 - P1 - i*ex))
ez = numpy.cross(ex,ey)
d = numpy.linalg.norm(P2 - P1)
j = numpy.dot(ey, P3 - P1)

#from wikipedia
#plug and chug using above values
x = (pow(DistA,2) - pow(DistB,2) + pow(d,2))/(2*d)
y = ((pow(DistA,2) - pow(DistC,2) + pow(i,2) + pow(j,2))/(2*j)) - ((i/j)*x)

# only one case shown here
z = numpy.sqrt(pow(DistA,2) - pow(x,2) - pow(y,2))

#triPt is an array with ECEF x,y,z of trilateration point
triPt = P1 + x*ex + y*ey + z*ez

#convert back to lat/long from ECEF
#convert to degrees
lat = math.degrees(math.asin(triPt[2] / earthR))
lon = math.degrees(math.atan2(triPt[1],triPt[0]))

print lat, lon

1
비슷한 대답을 모 으려고했지만 이제는 필요 없습니다! 내 투표를 가져옵니다.
Wrass

구조에 numpy! 'triPt'이 'triLatPt'로 바뀌면 컴파일되지만 그렇지 않으면 37.4191023738 -121.960579208을 반환합니다. 잘 했어
WolfOdrade

잘 했어! 지리적 좌표계를 로컬 [Cartesian] 좌표계로 교체해도 여전히 작동합니까?
zengr

C ++ 도메인에있는 사람들을 위해 .. 진짜 빠른 하나 pastebin.com/9Dur6RAP
raaj

2
@wwnick 감사합니다! 이것을 JavaScript로 이식했습니다 (노드 용이지만 브라우저에서 작동하도록 쉽게 변환 할 수 있음). gist.github.com/dav-/bb7103008cdf9359887f
DC_

6

순진한 지 확실하지 않지만 각 점을 크기별로 버퍼링 한 다음 세 위치를 모두 교차하면 올바른 위치를 얻을 수 있습니까?

공간 API를 사용하여 교차를 계산할 수 있습니다. 예 :

  • 지오 스크립트
  • 자바 토폴로지 스위트
  • NET 토폴로지 스위트
  • 지오스

1
정확히, 그는 그 교점을 얻는 공식에 관심이 있습니다.
Vinko Vrsalovic

공간 API를 사용하면 순수한 수학을 사용하지 않고도 수행 할 수 있습니다.
George Silva

1
@George 그러한 API의 예를 들어 줄 수 있습니까?
nohat

nohat의 요청을 반영하도록 게시물을 수정했습니다.
George Silva

+1, 좋은 측면 사고력, 아마도 가장 계산 효율이 높지 않더라도!
fmark

2

다음 노트는 평면 기하학을 사용합니다 (즉, 적절한 로컬 좌표계에 좌표를 투영해야 함).

파이썬에서 작동하는 예제를 사용한 나의 추론은 다음과 같습니다.

데이터 포인트 중 2 개를 가져옵니다 ( a및 호출 b). 목표 지점으로 전화하십시오 x. 우리는 이미 거리를 알고 axbx. ab피타고라스 정리를 사용 하여 거리 를 계산할 수 있습니다 .

>>> import math
>>> a = (1, 4)
>>> b = (3, 6)
>>> dist_ax = 3
>>> dist_bx = 5.385
# Pythagoras's theorem
>>> dist_ab = math.sqrt(abs(a[0]-b[0])**2 + abs(a[1]-b[1])**2)
>>> dist_ab
2.8284271247461903

이제 다음 선의 각도를 계산할 수 있습니다.

>>> angle_abx = math.acos((dist_bx * dist_bx + dist_ab * dist_ab - dist_ax * dist_ax)/(2 * dist_bx * dist_ab))
>>> math.degrees(angle_abx)
23.202973815040256
>>> angle_bax = math.acos((dist_ax * dist_ax + dist_ab * dist_ab - dist_bx * dist_bx)/(2 * dist_ax * dist_ab))
>>> math.degrees(angle_bax)
134.9915256259537
>>> angle_axb = math.acos((dist_ax * dist_ax + dist_bx * dist_bx - dist_ab * dist_ab)/(2 * dist_ax * dist_bx))
>>> math.degrees(angle_axb)
21.805500559006095

불행히도 나는 당신을 위해 대답을 완료 할 시간이 짧습니다. 그러나 이제 각도를 알면 가능한 두 위치를 계산할 수 있습니다 x. 그런 다음 세 번째 점 c를 사용하여 올바른 위치를 계산할 수 있습니다.


2

이 작동 할 수 있습니다. 파이썬에서 다시 빨리, 이것을 함수 xN, yN = 점의 좌표, r1 & r2 = 반경 값의 본문에 넣을 수 있습니다

dX = x2 - x1
dY = y2 - y1

centroidDistance = math.sqrt(math.pow(e,2) + math.pow(dY,2)) #distance from centroids
distancePL = (math.pow(centroidDistance,2) + (math.pow(r1,2) - math.pow(r2,2))) / (2 * centroidDistance) #distance from point to a line splitting the two centroids

rx1 = x1 + (dX *k)/centroidDistance + (dY/centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))
ry1 = y1 + (dY*k)/centroidDistance - (dX /centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))

rx2 = x1 + (dX *k)/centroidDistance - (dY/centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))
ry2 = y1 + (dY*k)/centroidDistance + (dX /centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))

rx & ry 값은 원을 명확하게하는 데 도움이되는 경우 원의 두 교차점에 대한 반환 값 (배열에 있어야 함)입니다.

처음 2 개 서클에 대해이 작업을 수행 한 다음 첫 번째와 마지막에 다시 수행하십시오. 첫 번째 반복의 결과 중 하나가 두 번째의 결과와 비교할 경우 (어쩌면 공차 내에서) 교차점이 있습니다. 프로세스에 점 이상을 추가하기 시작할 때 특히 좋은 해결책은 아니지만 방정식 시스템을 풀지 않고 볼 수있는 가장 간단합니다.


코드에서 'e'와 'k'는 무엇입니까?
ReinierDG

나는 기억이 안납니다 :-) wwnick의 답변은 세 개의 원이 있다면 구현하고 싶은 것의 선을 따라 더 있습니다.
WolfOdrade

1

postgis (St_Intersection, St_buffer 함수)의 공간 API를 사용할 수 있습니다. fmark에서 알 수 있듯이 Postgis는 평면 알고리즘을 사용하지만 작은 영역의 경우 등거리 추출을 사용하면 많은 오류가 발생하지 않습니다.


PostGIS는 GEOGRAPHY유형이 아닌 유형을 사용하여 구상 계산을 수행 할 수 있습니다 GEOMETRY.
fmark

1

PHP 언어로하세요 :

// 고도를 0으로 가정
$ earthR = 6371; // km 단위 (= 3959 마일)

$ LatA = 37.418436;
$ LonA = -121.963477;
$ DistA = 0.265710701754;

$ LatB = 37.417243;
$ LonB = -121.961889;
$ DistB = 0.234592423446;

$ LatC = 37.418692;
$ LonC = -121.960194;
$ DistC = 0.0548954278262;

/ *
#Authoric Sphere 사용
# 타원체를 사용하는 경우이 단계는 약간 다릅니다
# 측지 위도 / 경도를 ECEF xyz로 변환
# 1. 위도 / 경도를 라디안으로 변환
# 2. Lat / Long (radians)을 ECEF로 변환
* /
$ xA = $ earthR * (cos (deg2rad ($ LatA)) * cos (deg2rad ($ LonA)));
$ yA = $ earthR * (cos (deg2rad ($ LatA)) * sin (deg2rad ($ LonA)));
$ zA = $ earthR * (sin (deg2rad ($ LatA)));

$ xB = $ earthR * (cos (deg2rad ($ LatB)) * cos (deg2rad ($ LonB)));
$ yB = $ earthR * (cos (deg2rad ($ LatB)) * sin (deg2rad ($ LonB)));
$ zB = $ earthR * (sin (deg2rad ($ LatB)));

$ xC = $ earthR * (cos (deg2rad ($ LatC)) * cos (deg2rad ($ LonC)));
$ yC = $ earthR * (cos (deg2rad ($ LatC)) * sin (deg2rad ($ LonC)));
$ zC = $ earthR * (sin (deg2rad ($ LatC)));

/ *
설치 :
sudo 배 설치 Math_Vector-0.7.0
sudo 배 설치 Math_Matrix-0.8.7
* /
// PEAR :: Math_Matrix 포함
// /usr/share/php/Math/Matrix.php
// include_path = ". : / usr / local / php / pear /"
require_once 'Math / Matrix.php';
require_once 'Math / Vector.php';
require_once 'Math / Vector3.php';


$ P1vector = 새로운 Math_Vector3 (배열 ($ xA, $ yA, $ zA));
$ P2vector = 새로운 Math_Vector3 (배열 ($ xB, $ yB, $ zB));
$ P3vector = 새로운 Math_Vector3 (배열 ($ xC, $ yC, $ zC));

#wikipedia에서 : http://en.wikipedia.org/wiki/Trilateration
원점에서 원 1을 얻는 #transform
x 축에서 원 2를 얻기위한 #transform

// CALC EX
$ P2minusP1 = Math_VectorOp :: substract ($ P2vector, $ P1vector);
$ 1 = 새로운 Math_Vector ($ P2minusP1);
$ P2minusP1_length = $ l-> 길이 ();
$ norm = 새로운 Math_Vector3 (배열 ($ P2minusP1_length, $ P2minusP1_length, $ P2minusP1_length));
$ d = $ norm; // calc D 저장
$ ex = Math_VectorOp :: divide ($ P2minusP1, $ norm);
// echo "ex :". $ ex-> toString (). "\ n";
$ ex_x = floatval ($ ex-> _ tuple-> getData () [0]);
$ ex_y = floatval ($ ex-> _ tuple-> getData () [1]);
$ ex_z = floatval ($ ex-> _ tuple-> getData () [2]);
$ ex = 새로운 Math_Vector3 (배열 ($ ex_x, $ ex_y, $ ex_z));

// CALC i
$ P3minusP1 = Math_VectorOp :: substract ($ P3vector, $ P1vector);
$ P3minusP1_x = floatval ($ P3minusP1-> _ tuple-> getData () [0]);
$ P3minusP1_y = floatval ($ P3minusP1-> _ tuple-> getData () [1]);
$ P3minusP1_z = floatval ($ P3minusP1-> _ tuple-> getData () [2]);
$ P3minusP1 = 새로운 Math_Vector3 (배열 ($ P3minusP1_x, $ P3minusP1_y, $ P3minusP1_z));
$ i = Math_VectorOp :: dotProduct ($ ex, $ P3minusP1);
// echo "i = $ i \ n";

// CALC 아이
$ iex = Math_VectorOp :: scale ($ i, $ ex);
// echo "iex =". $ iex-> toString (). "\ n";
$ P3P1iex = Math_VectorOp :: substract ($ P3minusP1, $ iex);
// echo "P3P1iex =". $ P3P1iex-> toString (). "\ n";
$ 1 = 새로운 Math_Vector ($ P3P1iex);
$ P3P1iex_length = $ l-> 길이 ();
$ norm = 새로운 Math_Vector3 (배열 ($ P3P1iex_length, $ P3P1iex_length, $ P3P1iex_length));
// echo "norm :". $ norm-> toString (). "\ n";
$ ey = Math_VectorOp :: divide ($ P3P1iex, $ norm);
// echo "ey =". $ ey-> toString (). "\ n";
$ ey_x = floatval ($ ey-> _ tuple-> getData () [0]);
$ ey_y = floatval ($ ey-> _ tuple-> getData () [1]);
$ ey_z = floatval ($ ey-> _ tuple-> getData () [2]);
$ ey = 새로운 Math_Vector3 (배열 ($ ey_x, $ ey_y, $ ey_z));

// CALC EZ
$ ez = Math_VectorOp :: crossProduct ($ ex, $ ey);
// echo "ez =". $ ez-> toString (). "\ n";

// CALC D
// 전에해라
$ d = floatval ($ d-> _ tuple-> getData () [0]);
// echo "d = $ d \ n";

// CALC J
$ j = Math_VectorOp :: dotProduct ($ ey, $ P3minusP1);
// echo "j = $ j \ n";

# 위키 백과에서
위의 값을 사용하는 #plug and chug
$ x = (pow ($ DistA, 2)-pow ($ DistB, 2) + pow ($ d, 2)) / (2 * $ d);
$ y = ((pow ($ DistA, 2)-pow ($ DistC, 2) + pow ($ i, 2) + pow ($ j, 2)) / (2 * $ j))-(($ i / $ j) * $ x);

# 여기에 표시된 하나의 사례 만
$ z = sqrt (pow ($ DistA, 2)-pow ($ x, 2)-pow ($ y, 2));

// echo "x = $ x-y = $ y-z = $ z \ n";

#triPt는 ​​ECEF x, y, z의 평가 포인트가있는 배열입니다.
$ xex = Math_VectorOp :: scale ($ x, $ ex);
$ yey = Math_VectorOp :: scale ($ y, $ ey);
$ zez = Math_VectorOp :: scale ($ z, $ ez);

// CALC $ triPt = $ P1vector + $ xex + $ yey + $ zez;
$ triPt = Math_VectorOp :: add ($ P1vector, $ xex);
$ triPt = Math_VectorOp :: add ($ triPt, $ yey);
$ triPt = Math_VectorOp :: add ($ triPt, $ zez);
// echo "triPt =". $ triPt-> toString (). "\ n";
$ triPt_x = floatval ($ triPt-> _ tuple-> getData () [0]);
$ triPt_y = floatval ($ triPt-> _ tuple-> getData () [1]);
$ triPt_z = floatval ($ triPt-> _ tuple-> getData () [2]);


ECEF에서 위도 / 경도로 다시 변환
#도 단위로 변환
$ lat = rad2deg (asin ($ triPt_z / $ earthR));
$ lon = rad2deg (atan2 ($ triPt_y, $ triPt_x));

echo $ lat. ','. $ lon;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.