У мене є деякі точки, орієнтовані на землю, координати, задані як широта і довгота ( 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_coordinate
Далі - це те, що я використовую:
Я додав код 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
( мсл, висота вище середнього рівня моря ), а 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)
Програмне забезпечення proj.4 забезпечує програму командного рядка, яка може здійснити перетворення, наприклад
LAT=40
LON=-110
echo $LON $LAT | cs2cs +proj=latlong +datum=WGS84 +to +proj=geocent +datum=WGS84
Він також надає API C . Зокрема, функція pj_geodetic_to_geocentric
здійснюватиме перетворення без попереднього встановлення об'єкта проекції.
У 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 #, наприклад, є NetTopologySuite, який є портом .NET пакету JT Topology.
Зокрема, у вас є сильний недолік у вашому розрахунку. Земля не є досконалою сферою, і наближення радіусу Землі може не вирішити її для точних вимірювань.
Якщо в деяких випадках прийнятно використовувати функції домашнього перекладу, ГІС є хорошим прикладом поля, в якому набагато переважніше використовувати надійну, перевірену тестом бібліотеку.
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;
}