У меня есть несколько ориентированных на Землю координатных точек, заданных как широта и долгота ( WGS-84 ).
Как я могу преобразовать их в декартовы координаты (x, y, z) с началом в центре Земли?
У меня есть несколько ориентированных на Землю координатных точек, заданных как широта и долгота ( WGS-84 ).
Как я могу преобразовать их в декартовы координаты (x, y, z) с началом в центре Земли?
Ответы:
Недавно я проделал нечто подобное, используя «Формулу Гаверсина» для данных WGS-84, которая является производной от «Закона Гаверсинов» с очень удовлетворительными результатами.
Да, WGS-84 предполагает, что Земля является эллипсоидом, но я считаю, что вы получите только около 0,5% средней ошибки, используя такой подход, как «Формула Хаверсина», что может быть приемлемым количеством ошибок в вашем случае. Вы всегда будете иметь некоторую ошибку, если только вы не говорите о расстоянии в несколько футов, и даже тогда теоретически существует кривизна Земли ... Если вам требуется более жесткий подход, совместимый с WGS-84, проверьте "Формулу Винсенти".
Я понимаю, откуда взялся starblue , но хорошая разработка программного обеспечения часто сводится к компромиссам, поэтому все зависит от точности, которая вам нужна для того, что вы делаете. Например, результат, рассчитанный по «Манхэттенской формуле расстояния» по сравнению с результатом «Формулы расстояния», может быть лучше для определенных ситуаций, поскольку требует меньших вычислительных затрат. Подумайте, "какая точка ближайшая?" сценарии, в которых точное измерение расстояния не требуется.
Что касается «формулы Хаверсинуса», ее легко реализовать, и она хороша тем, что в ней используется «сферическая тригонометрия» вместо подхода, основанного на «законе косинусов», который основан на двумерной тригонометрии, поэтому вы получаете хороший баланс точности по сложности.
У господина по имени Крис Венесс есть отличный веб-сайт 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 - приблизительный радиус Земли (например, 6371 км).
Если ваши тригонометрические функции ожидают радианы (что, вероятно, так и есть), вам сначала нужно будет преобразовать долготу и широту в радианы. Очевидно, вам нужно десятичное представление, а не градусы \ минуты \ секунды (см., Например, здесь о преобразовании).
Формула обратного преобразования:
lat = asin(z / R)
lon = atan2(y, x)
asin - это, конечно, арксинус. почитайте про 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 угловых минут.
Или, если у вас есть профессионал определенного уровня, 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
Программное обеспечение proj.4 предоставляет программу командной строки, которая может выполнять преобразование, например
LAT=40
LON=-110
echo $LON $LAT | cs2cs +proj=latlong +datum=WGS84 +to +proj=geocent +datum=WGS84
Он также предоставляет C API . В частности, функция pj_geodetic_to_geocentric
выполнит преобразование без предварительной настройки объекта проекции.
Если вам нужно получить координаты на основе эллипсоида, а не сферы, взгляните на http://en.wikipedia.org/wiki/Geodetic_system#From_geodetic_to_ECEF - он дает формулы, а также константы WGS84, необходимые для преобразования. .
Формулы, которые также учитывают высоту относительно опорной поверхности эллипсоида (полезно, если вы получаете данные высоты от устройства GPS).
Зачем внедрять то, что уже реализовано и проверено испытаниями?
В C #, например, есть NetTopologySuite, который является портом .NET для JTS Topology Suite.
В частности, у вас есть серьезная ошибка в расчетах. Земля не является идеальной сферой, и приближение радиуса Земли может не подрезать ее для точных измерений.
Если в некоторых случаях можно использовать домашние функции, ГИС является хорошим примером области, в которой гораздо предпочтительнее использовать надежную, проверенную тестами библиотеку.
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
Вы можете сделать это на 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;
}