답변:
저는 최근에 WGS-84 데이터의 "Haversine Formula"를 사용하여 이와 유사한 작업을 수행했습니다. 이는 "Law of Haversines"의 파생물이며 매우 만족스러운 결과입니다.
예, WGS-84는 지구가 타원체라고 가정하지만 "Haversine Formula"와 같은 접근 방식을 사용하면 평균 0.5 %의 오차 만 얻을 수 있다고 생각합니다. 몇 피트의 거리에 대해 이야기하지 않는 한 항상 약간의 오류가있을 것이며 이론적으로 지구의 곡률이있는 경우도 있습니다. 더 엄격하게 WGS-84 호환 접근 방식이 필요한 경우 "빈 센티 공식"을 확인하십시오.
나는 starblue 가 어디에서 왔는지 이해 하지만 좋은 소프트웨어 엔지니어링은 종종 트레이드 오프에 관한 것이므로 모두 수행하는 작업에 필요한 정확성에 달려 있습니다. 예를 들어, "Manhattan Distance Formula"에서 계산 된 결과와 "Distance Formula"의 결과는 계산 비용이 더 저렴하므로 특정 상황에서는 더 좋을 수 있습니다. "가장 가까운 지점은?" 정확한 거리 측정이 필요하지 않은 시나리오.
"하버 사인 공식"은 2 차원 삼각법을 기반으로하는 "코사인 법칙"기반 접근 방식 대신 "구형 삼각법"을 사용하기 때문에 구현하기 쉽고 좋습니다. 따라서 정확도의 균형을 잘 맞 춥니 다. 복잡성에.
이름의 신사 Chris Veness는 http://www.movable-type.co.uk/scripts/latlong.html 에 귀하가 관심있는 개념을 설명하고 다양한 프로그래밍 방식 구현을 보여주는훌륭한 웹 사이트를 운영하고 있습니다. 이것은 x / y 변환 질문에도 답할 것입니다.
내가 찾은 답은 다음과 같습니다.
정의를 완성하기 위해 데카르트 좌표계에서 :
변환은 다음과 같습니다.
x = R * cos(lat) * cos(lon)
y = R * cos(lat) * sin(lon)
z = R *sin(lat)
여기서 R은 대략적인 지구의 반경입니다 (예 : 6371km).
삼각 함수가 라디안을 예상하는 경우 (아마도 그렇게 할 것임) 먼저 경도와 위도를 라디안으로 변환해야합니다. 당신은 분명하지도 \ 분 \ 초 (참조, 진수 표현을 필요로 여기 예를 들어 변환에 대해).
역변환 공식 :
lat = asin(z / R)
lon = atan2(y, x)
asin은 물론 아크 사인입니다. wikipedia에서 atan2에 대해 읽어보십시오 . 라디안에서 도로 다시 변환하는 것을 잊지 마십시오.
이 페이지 는 이에 대한 C # 코드 (공식과 매우 다릅니다)와 이것이 올바른 이유에 대한 설명과 멋진 다이어그램을 제공합니다.
데카르트 좌표 로 변환 GPS(WGS84)
하는 이론 https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_geodetic_to_ECEF_coordinates
다음은 내가 사용하는 것입니다.
내가 작성한 VB 코드를 첨부했습니다 .
Imports System.Math
'Input GPSLatitude is WGS84 Latitude,h is altitude above the WGS 84 ellipsoid
Public Function GetSphericalLatitude(ByVal GPSLatitude As Double, ByVal h As Double) As Double
Dim A As Double = 6378137 'semi-major axis
Dim f As Double = 1 / 298.257223563 '1/f Reciprocal of flattening
Dim e2 As Double = f * (2 - f)
Dim Rc As Double = A / (Sqrt(1 - e2 * (Sin(GPSLatitude * PI / 180) ^ 2)))
Dim p As Double = (Rc + h) * Cos(GPSLatitude * PI / 180)
Dim z As Double = (Rc * (1 - e2) + h) * Sin(GPSLatitude * PI / 180)
Dim r As Double = Sqrt(p ^ 2 + z ^ 2)
Dim SphericalLatitude As Double = Asin(z / r) * 180 / PI
Return SphericalLatitude
End Function
의 h
고도가 WGS 84 ellipsoid
.
보통 GPS
우리에게 H
위의 MSL
높이를 줄 것 입니다 . MSL
높이는 높이로 변환하는 h
상기 WGS 84 ellipsoid
하여 중력 포텐샬 모델 EGM96
( Lemoine은 등, 1998 ).
이것은 공간 해상도가 15 arc-minutes 인 지오이드 높이 파일의 그리드를 보간하여 수행됩니다.
당신은 몇 가지 레벨이있는 경우 또는 전문가를 GPS
고도를 가지고 H
( MSL, 평균 해발 어이 )과 UNDULATION
의 사이의 관계 geoid
와 ellipsoid (m)
선택된의 자료 출력 내부 테이블을. 당신은 얻을 수 있습니다h = H(msl) + undulation
데카르트 좌표로 XYZ하려면 :
x = R * cos(lat) * cos(lon)
y = R * cos(lat) * sin(lon)
z = R *sin(lat)
python3.x에서는 다음을 사용하여 수행 할 수 있습니다.
# Converting lat/long to cartesian
import numpy as np
def get_cartesian(lat=None,lon=None):
lat, lon = np.deg2rad(lat), np.deg2rad(lon)
R = 6371 # radius of the earth
x = R * np.cos(lat) * np.cos(lon)
y = R * np.cos(lat) * np.sin(lon)
z = R *np.sin(lat)
return x,y,z
구가 아닌 타원체를 기반으로 좌표를 얻는 데 관심이 있다면 http://en.wikipedia.org/wiki/Geodetic_system#From_geodetic_to_ECEF 를 참조하십시오. 변환에 필요한 WGS84 상수와 수식을 제공합니다. .
공식은 또한 참조 타원 표면에 상대적인 고도를 고려합니다 (GPS 장치에서 고도 데이터를 가져 오는 경우 유용함).
이미 구현되고 테스트 검증 된 것을 구현하는 이유는 무엇입니까?
우선 C # 에는 JTS Topology Suite의 .NET 포트 인 NetTopologySuite 가 있습니다.
특히 계산에 심각한 결함이 있습니다. 지구는 완벽한 구체가 아니며 지구 반경 의 근사치 가 정확한 측정을 위해 잘라 내지 않을 수 있습니다.
어떤 경우에 홈브류 기능을 사용하는 것이 허용된다면 GIS는 신뢰할 수 있고 테스트가 입증 된 라이브러리를 사용하는 것이 훨씬 선호되는 분야의 좋은 예입니다.
Coordinate[] coordinates = new Coordinate[3];
coordinates[0] = new Coordinate(102, 26);
coordinates[1] = new Coordinate(103, 25.12);
coordinates[2] = new Coordinate(104, 16.11);
CoordinateSequence coordinateSequence = new CoordinateArraySequence(coordinates);
Geometry geo = new LineString(coordinateSequence, geometryFactory);
CoordinateReferenceSystem wgs84 = DefaultGeographicCRS.WGS84;
CoordinateReferenceSystem cartesinaCrs = DefaultGeocentricCRS.CARTESIAN;
MathTransform mathTransform = CRS.findMathTransform(wgs84, cartesinaCrs, true);
Geometry geo1 = JTS.transform(geo, mathTransform);
Java에서 이런 식으로 할 수 있습니다.
public List<Double> convertGpsToECEF(double lat, double longi, float alt) {
double a=6378.1;
double b=6356.8;
double N;
double e= 1-(Math.pow(b, 2)/Math.pow(a, 2));
N= a/(Math.sqrt(1.0-(e*Math.pow(Math.sin(Math.toRadians(lat)), 2))));
double cosLatRad=Math.cos(Math.toRadians(lat));
double cosLongiRad=Math.cos(Math.toRadians(longi));
double sinLatRad=Math.sin(Math.toRadians(lat));
double sinLongiRad=Math.sin(Math.toRadians(longi));
double x =(N+0.001*alt)*cosLatRad*cosLongiRad;
double y =(N+0.001*alt)*cosLatRad*sinLongiRad;
double z =((Math.pow(b, 2)/Math.pow(a, 2))*N+0.001*alt)*sinLatRad;
List<Double> ecef= new ArrayList<>();
ecef.add(x);
ecef.add(y);
ecef.add(z);
return ecef;
}