Enlem ve boylam olarak verilen bazı dünya merkezli koordinat noktalarım var ( WGS-84 ).
Kökeni dünyanın merkezinde olacak şekilde Kartezyen koordinatlara (x, y, z) nasıl dönüştürebilirim?
Enlem ve boylam olarak verilen bazı dünya merkezli koordinat noktalarım var ( WGS-84 ).
Kökeni dünyanın merkezinde olacak şekilde Kartezyen koordinatlara (x, y, z) nasıl dönüştürebilirim?
Yanıtlar:
Son zamanlarda WGS-84 verileri üzerinde "Haversine Formülü" nü kullanarak, "Haversines Yasası" nın bir türevi olan ve çok tatmin edici sonuçlarla buna benzer bir şey yaptım.
Evet, WGS-84 Dünya'nın bir elipsoid olduğunu varsayar, ancak "Haversine Formülü" gibi bir yaklaşım kullanarak yalnızca yaklaşık% 0.5 ortalama hata aldığınıza inanıyorum, bu sizin durumunuzda kabul edilebilir bir hata miktarı olabilir. Birkaç fitlik bir mesafeden bahsetmediğiniz ve hatta Dünya'nın teorik olarak eğriliğinden bahsetmediğiniz sürece her zaman bir miktar hata yaşarsınız ... Daha katı bir şekilde WGS-84 uyumlu yaklaşıma ihtiyacınız varsa "Vincenty Formülü" nü kontrol edin.
Starblue'nun nereden geldiğini anlıyorum , ancak iyi bir yazılım mühendisliği genellikle değiş tokuşlarla ilgilidir, bu yüzden her şey yaptığınız şey için ihtiyaç duyduğunuz doğruluğa bağlıdır. Örneğin, "Manhattan Mesafe Formülü" nden hesaplanan sonuçla "Mesafe Formülü" nden hesaplanan sonuç, hesaplama açısından daha ucuz olduğu için belirli durumlar için daha iyi olabilir. "En yakın nokta hangisi?" Diye düşünün. hassas bir mesafe ölçümüne ihtiyaç duymadığınız senaryolar.
"Haversine Formülü" ile ilgili olarak, uygulanması kolaydır ve güzeldir çünkü iki boyutlu trigonometriye dayanan "Kosinüs Yasası" temelli bir yaklaşım yerine "Küresel Trigonometri" kullanır, bu nedenle güzel bir doğruluk dengesi elde edersiniz karmaşıklığın üzerinde.
Chris Veness adında bir beyefendinin http://www.movable-type.co.uk/scripts/latlong.html adresinde , ilgilendiğiniz bazı kavramları açıklayan ve çeşitli programatik uygulamaları gösteren harika bir web sitesi vardır; bu, x / y dönüştürme sorunuzu da yanıtlamalıdır.
İşte bulduğum cevap:
Kartezyen koordinat sisteminde tanımı tamamlamak için:
Dönüşüm şudur:
x = R * cos(lat) * cos(lon)
y = R * cos(lat) * sin(lon)
z = R *sin(lat)
R, dünyanın yaklaşık yarıçapıdır (örneğin 6371 km).
Trigonometrik fonksiyonlarınız radyan bekliyorsa (ki muhtemelen yaparlar), önce boylamınızı ve enleminizi radyana çevirmeniz gerekecektir. Açıkça ondalık gösterime ihtiyacınız var, derece \ dakika \ saniye değil ( örneğin dönüştürme hakkında buraya bakın ).
Geri dönüşüm formülü:
lat = asin(z / R)
lon = atan2(y, x)
asin tabii ki ark sinüs. wikipedia'da atan2 hakkında okuyun . Radyandan dereceye geri dönüştürmeyi unutmayın.
Bu sayfa bunun için c # kodu verir (formüllerden çok farklı olduğunu unutmayın) ve ayrıca bunun neden doğru olduğuna dair bazı açıklamalar ve güzel şema,
Dönüştürme için Teorisi GPS(WGS84)
için Kartezyen koordinatlar
https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_geodetic_to_ECEF_coordinates
Aşağıdakiler kullanıyorum:
Yazdığım bir VB kodunu ekledim:
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
Lütfen h
rakımın üzerinde olduğuna dikkat edin WGS 84 ellipsoid
.
Genellikle GPS
bize H
yukarıdaki MSL
yüksekliği verir. MSL
Yükseklik yüksekliğine dönüştürülecek olan h
, yukarıda WGS 84 ellipsoid
kullanarak izgesindeki modeli EGM96
( Lemoine et al, 1998 ).
Bu, jeoid yükseklik dosyasının bir ızgarasının 15 yay-dakikalık uzamsal çözünürlükle enterpolasyonu ile yapılır.
Bazı seviye varsa Veya profesyonel GPS
Rakımı sahiptir H
( msl, ortalama deniz seviyesinden heigh ) ve UNDULATION
arasındaki ilişkiyi geoid
ve ellipsoid (m)
seçilmiş bir sıfır noktası çıkışı iç tablosundan. alabilirsinizh = H(msl) + undulation
Kartezyen koordinatlara göre XYZ'ye:
x = R * cos(lat) * cos(lon)
y = R * cos(lat) * sin(lon)
z = R *sin(lat)
Python3.x içinde şu şekilde yapılabilir:
# 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 yazılım dönüştürme yapabilirsiniz bir komut satırı programı, örneğin sağlar
LAT=40
LON=-110
echo $LON $LAT | cs2cs +proj=latlong +datum=WGS84 +to +proj=geocent +datum=WGS84
Ayrıca bir C API sağlar . Özellikle, işlev pj_geodetic_to_geocentric
, önce bir projeksiyon nesnesi kurmaya gerek kalmadan dönüşümü gerçekleştirecektir.
Bir küre yerine bir elipsoide dayalı koordinatlar almayı önemsiyorsanız, http://en.wikipedia.org/wiki/Geodetic_system#From_geodetic_to_ECEF adresine bakın - formülleri ve dönüşüm için ihtiyacınız olan WGS84 sabitlerini verir .
Buradaki formüller ayrıca referans elipsoid yüzeye göre rakımı da hesaba katar (bir GPS cihazından yükseklik verisi alıyorsanız kullanışlıdır).
Zaten uygulanmış ve test edilmiş bir şeyi neden uygulayasınız?
Birincisi, C #, JTS Topology Suite'in .NET bağlantı noktası olan NetTopologySuite'e sahiptir.
Özellikle, hesaplamanızda ciddi bir kusurunuz var. Dünya mükemmel bir küre değildir ve dünyanın yarıçapının yaklaştırılması , kesin ölçümler için onu kesmeyebilir.
Bazı durumlarda homebrew işlevlerinin kullanılması kabul edilebilirse, CBS, güvenilir, testle kanıtlanmış bir kitaplık kullanmanın daha çok tercih edildiği bir alan için iyi bir örnektir.
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'da bu şekilde yapabilirsiniz.
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;
}