Tôi có một số điểm tọa độ trung tâm trái đất được cung cấp dưới dạng vĩ độ và kinh độ ( WGS-84 ).
Làm cách nào để chuyển đổi chúng sang tọa độ Descartes (x, y, z) với điểm gốc là tâm trái đất?
Tôi có một số điểm tọa độ trung tâm trái đất được cung cấp dưới dạng vĩ độ và kinh độ ( WGS-84 ).
Làm cách nào để chuyển đổi chúng sang tọa độ Descartes (x, y, z) với điểm gốc là tâm trái đất?
Câu trả lời:
Gần đây tôi đã làm một việc tương tự như vậy bằng cách sử dụng "Công thức Haversine" trên dữ liệu WGS-84, là một dẫn xuất của "Định luật Haversines" với kết quả rất hài lòng.
Có, WGS-84 giả định Trái đất là một ellipsoid, nhưng tôi tin rằng bạn chỉ nhận được sai số trung bình khoảng 0,5% khi sử dụng phương pháp như "Công thức Haversine", đây có thể là mức sai số chấp nhận được trong trường hợp của bạn. Bạn sẽ luôn có một số sai sót trừ khi bạn đang nói về khoảng cách vài feet và thậm chí sau đó về mặt lý thuyết là độ cong của Trái đất ... Nếu bạn yêu cầu cách tiếp cận tương thích với WGS-84 khắt khe hơn, hãy kiểm tra "Công thức Vincenty."
Tôi hiểu starblue đến từ đâu, nhưng kỹ thuật phần mềm tốt thường là đánh đổi, vì vậy tất cả phụ thuộc vào độ chính xác mà bạn yêu cầu cho những gì bạn đang làm. Ví dụ: kết quả được tính từ "Công thức khoảng cách Manhattan" so với kết quả từ "Công thức khoảng cách" có thể tốt hơn trong một số trường hợp nhất định vì nó ít tốn kém hơn về mặt tính toán. Hãy suy nghĩ "điểm nào là gần nhất?" tình huống mà bạn không cần đo khoảng cách chính xác.
Về vấn đề, "Công thức Haversine" rất dễ thực hiện và hay vì nó sử dụng "Lượng giác hình cầu" thay vì cách tiếp cận dựa trên "Định luật Cosin" dựa trên lượng giác hai chiều, do đó bạn sẽ có được sự cân bằng tốt về độ chính xác quá phức tạp.
Một quý ông tên là Chris Veness có một trang web tuyệt vời tại http://www.movable-type.co.uk/scripts/latlong.html giải thích một số khái niệm mà bạn quan tâm và thể hiện các triển khai có lập trình khác nhau; điều này cũng sẽ trả lời câu hỏi chuyển đổi x / y của bạn.
Đây là câu trả lời tôi đã tìm thấy:
Chỉ để làm cho định nghĩa hoàn chỉnh, trong hệ tọa độ Descartes:
Sự chuyển đổi là:
x = R * cos(lat) * cos(lon)
y = R * cos(lat) * sin(lon)
z = R *sin(lat)
Trong đó R là bán kính gần đúng của trái đất (ví dụ 6371 km).
Nếu các hàm lượng giác của bạn mong đợi radian (mà chúng có thể làm như vậy), trước tiên bạn sẽ cần chuyển đổi kinh độ và vĩ độ của mình sang radian. Rõ ràng bạn cần một biểu diễn thập phân, không phải độ \ phút \ giây (xem ví dụ: ở đây về chuyển đổi).
Công thức cho chuyển đổi ngược:
lat = asin(z / R)
lon = atan2(y, x)
asin tất nhiên là cung sin. đọc về atan2 trong wikipedia . Đừng quên chuyển đổi ngược lại từ radian sang độ.
Trang này cung cấp mã c # cho điều này (lưu ý rằng nó rất khác với các công thức), và cũng có một số giải thích và sơ đồ đẹp về lý do tại sao điều này đúng,
Lý thuyết chuyển đổi GPS(WGS84)
sang tọa độ Descartes
https://en.wikipedia.org/wiki/Geographic_coosystem_conversion#From_geodetic_to_ECEF_coosystem
Sau đây là những gì tôi đang sử dụng:
Tôi đã đính kèm mã VB mà tôi đã viết:
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
Xin lưu ý rằng h
độ cao là trên WGS 84 ellipsoid
.
Thông thường GPS
sẽ cho chúng ta chiều cao H
trên MSL
. Các MSL
chiều cao phải được chuyển đổi sang chiều cao h
phía trên WGS 84 ellipsoid
bằng cách sử dụng các geopotential mô hình EGM96
( Lemoine et al, 1998 ).
Điều này được thực hiện bằng cách nội suy một lưới của tệp chiều cao geoid với độ phân giải không gian là 15 vòng cung-phút.
Hoặc nếu bạn có một số chuyên gia cấp độ GPS
có Độ cao H
( msl, độ cao trên mực nước biển trung bình ) và UNDULATION
, mối quan hệ giữa geoid
và đầu ra dữ liệuellipsoid (m)
đã chọn từ bảng nội bộ. bạn có thể làm đượch = H(msl) + undulation
Tới XYZ theo tọa độ Descartes:
x = R * cos(lat) * cos(lon)
y = R * cos(lat) * sin(lon)
z = R *sin(lat)
Phần mềm proj.4 cung cấp một chương trình dòng lệnh có thể thực hiện chuyển đổi, ví dụ:
LAT=40
LON=-110
echo $LON $LAT | cs2cs +proj=latlong +datum=WGS84 +to +proj=geocent +datum=WGS84
Nó cũng cung cấp một API C . Đặc biệt, hàm pj_geodetic_to_geocentric
sẽ thực hiện chuyển đổi mà không cần phải thiết lập đối tượng chiếu trước.
Trong python3.x, nó có thể được thực hiện bằng cách sử dụng:
# 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
Nếu bạn quan tâm đến việc lấy tọa độ dựa trên hình elipsoid thay vì hình cầu, hãy xem tại http://en.wikipedia.org/wiki/Geodetic_system#From_geodetic_to_ECEF - nó cung cấp các công thức cũng như hằng số WGS84 mà bạn cần để chuyển đổi .
Các công thức ở đó cũng tính đến độ cao so với bề mặt ellipsoid tham chiếu (hữu ích nếu bạn đang nhận dữ liệu độ cao từ thiết bị GPS).
Tại sao phải triển khai một thứ gì đó đã được triển khai và đã được kiểm chứng?
C #, ví dụ, có NetTopologySuite là cổng .NET của JTS Topology Suite.
Cụ thể, bạn có một sai sót nghiêm trọng trong tính toán của mình. Trái đất không phải là một hình cầu hoàn hảo, và tính gần đúng bán kính của trái đất có thể không cắt nó để có các phép đo chính xác.
Nếu trong một số trường hợp, việc sử dụng các hàm homebrew được chấp nhận, thì GIS là một ví dụ điển hình về lĩnh vực mà nó được ưu tiên sử dụng một thư viện đáng tin cậy, đã được kiểm chứng.
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.lang.IllegalArgumentException: dimension must be <= 3
Bạn có thể thực hiện theo cách này trên 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;
}