У меня есть координатно-ориентированные координаты с землей, заданные как широта и долгота (WGS-84).
Как я могу преобразовать их в декартовы координаты (x, y, z) с началом в центре Земли?
У меня есть координатно-ориентированные координаты с землей, заданные как широта и долгота (WGS-84).
Как я могу преобразовать их в декартовы координаты (x, y, z) с началом в центре Земли?
Недавно я сделал что-то подобное этому, используя "Формула Хаверсина" по данным WGS-84, которая является производным от "Закона Хаверсинеса" с очень удовлетворительными результатами.
Да, WGS-84 предполагает, что Земля является эллипсоидом, но я считаю, что вы получаете примерно 0,5% -ную среднюю ошибку, используя подход, такой как "Формула Хаверсина", которая может быть приемлемой ошибкой в вашем случае. У вас всегда будет некоторая ошибка, если вы не говорите о расстоянии в несколько футов, и даже тогда теоретически кривизна Земли... Если вам потребуется более жесткая проверка соответствия с WGS-84 на "Формуле Vincenty".
Я понимаю, откуда приходит starblue, но хорошая разработка программного обеспечения часто связана с компромиссом, поэтому все зависит от точности, которую вы требуете от того, что вы делаете. Например, результат, рассчитанный по формуле "Формула расстояния Манхэттена" по сравнению с результатом "Формулы расстояния", может быть лучше для определенных ситуаций, поскольку он является расчетно менее дорогостоящим. Подумайте "какой момент ближе?" сценарии, в которых вам не требуется точное измерение расстояния.
Что касается "Формулы Хаверсина", ее легко реализовать и хорошо, потому что она использует "Сферическую тригонометрию" вместо подхода "Закон косинусов", основанного на двумерной тригонометрии, поэтому вы получаете приятное баланс точности по сложности.
У джентльменов по имени 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 - это, конечно, синус. читает об atan2 в википедии. Не забывайте переводить обратно с радианов на градусы.
Эта страница дает код С# для этого (обратите внимание, что она сильно отличается от формул), а также некоторое объяснение и хорошая диаграмма причин это правильно,
Теория преобразования 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
height.
Высота MSL
должна быть преобразована в высоту h
выше WGS 84 ellipsoid
с использованием геопотенциальной модели EGM96
(Lemoine et al, 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)
Зачем внедрять что-то, что уже было реализовано и проверено на тестирование?
С#, для одного, имеет NetTopologySuite, который является портом .NET топологии топологии JTS.
В частности, у вас есть серьезный недостаток в ваших расчетах. Земля не является идеальной сферой, и приближение радиуса земли может не вырезать ее для точных измерений.
Если в некоторых случаях это приемлемо для использования функций homebrew, GIS является хорошим примером поля, в котором гораздо предпочтительнее использовать надежную, проверенную тестирование библиотеку.
Если вы хотите получить координаты на основе эллипсоида, а не сферы, посмотрите http://en.wikipedia.org/wiki/Geodetic_system#From_geodetic_to_ECEF - он дает формулы как а также константы WGS84, необходимые для преобразования.
Формулы, которые также принимают во внимание высоту по отношению к поверхности референц-эллипсоида (полезно, если вы получаете данные высоты от устройства GPS).
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
выполнит преобразование без необходимости сначала создавать проекционный объект.
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;
}