Geodéziai vonatkozási rendszerek és vetületek#

Bevezetés#

Figyelem

Ennek a bevezetőnek nem szándéka hogy teljes legyen, csupán megismétli a vetülettanból, illetve felsőgeodéziából tanultakat, valamint rendszerezi azokat oly módon, hogy megértsük a térinformatikában alkalmazott vetület definíciókat.

Egy pontot a térben természetes módon megadhatunk X, Y, Z térbeli (descartes-i) koordinátákkal. A geodéziában a térbeli koordináta rendszert a Föld középpontjához és annak forgásához kötik, ekkor geocentrikus koordináta rendszerről beszélünk, vagy külföldi szakirodalomban gyakran (ECEF) koordináta rendszerként hivatkoznak rá.

A térbeli koordináta rendszerben adott pont koordinátái nagy számok, mely számok alapján nehéz megmondani a pont körübelüli helyzetét a Földön. Ezért a három X, Y, Z koordináta helyett, a gyakorlatban gyakran alkalmazunk szög alapú (hosszúság és szélesség) koordinátákat. Ezek megadásához azonban gömb vagy ellipszoid használata szükséges. Ahhoz hogy ezt megtehessük, meg kell adnunk az ellipszoid méretére és alakjára (pl. a fél nagytengely hossza és a az ellipszoid lapultsága) vonatkozó adatokat, továbbá szükségünk van az ellipszoidnak a korábban említett térbeli koordináta rendszerben történő elhelyezéséhez és tájékozásához szükséges paraméterekre. Az ellipszoid elhelyezése lehetséges oly módon, hogy az a világ minden pontjában a legjobban közelítse a geoidot (pl. WGS84, ITRS), vagy úgy is, történhet, hogy az ellipszoid a Föld bizonyos részeit (lokálisan) jobban közelíti (pl. ETRS89, NAD83). A magasságot ezután a pont ellipszoid feletti magasságaként adjuk meg. Az így kapott koordinátákat földrajzi koordinátáknak nevezzük.

Látható, hogy az földrajzi koordináták megadásához szükségünk van egy térbeli koordináta rendszerre, így a két fajta pont reprezentáció a gyakrolatban szorosan összefügg. A térbeli koordináta rendszer leírását, valamint az ellipszoid alakját és eléhelyzését megadó parametereket együttesen geodéziai dátumnak hívjuk. A WGS84 geocentrikus koordináta rendszerében adott koordinátákat a WGS84 referencia ellipszoid segítségével átszámíthatjuk földrajzi koordinátákra.

Végül a vetületi koordinátákat az ellipszoidról, mint alapfelületről valamilyen sík vetületre történő vetítéssel kapjuk. Egy példa a vetületi rendszerre, az UTM, mely esetén a vetítés egy transzverzális elhelyezésű hengervetületre történik. Így tehát a vetítéshez szükségünk van egy alapfületre, vagy ellipszoidra, melynek elhelyzésére szükségünk van egy térbeli koordináta rendszerhez. Például a gyarkorlatban az UTM vetülethez használhatjuk a WGS84, vagy az ETRS89 dátumokat. (Az utóbbi Norvégia és egyes német tartományok hivatalos vetületei).

Ezek alapján egy pont megadása a következő módokon adható meg:

  • Geocentrikus koordináta: három X, Y, Z descartes-i koordánátával adható meg egy pont. Példák EPSG:4978 (WGS84), EPSG:4936 (ETRS89)

  • Földrajzi koordináta: egy térbeli pont megadásához a hosszúság, szélesség és esetlegesen ellipszoid vagy geoid feletti magasságot használjuk. Ahhoz hogy a hosszúság és szélességet értelmezni tudjuk, egy ellipszoidot illesztenek egy adott térbeli koordináta rendszerhez. Példák EPSG:4326 (WGS84), EPSG:4937 (ETRS89)

  • Vetületi koordináta: a vetületi koordináták esetén az eredmény x, y koordináta pár, melyet úgy kapunk, hogy az alapfelületről valamilyen sík vetületre vetítünk. Példák az UTM és az EOV.

Az EOV esetén az ellipszoidról egy ferde tengelyű sülyesztett hengervetületre történik a vetítés. A számítás során, a vetítés két lépésben történik: először az ellipszoidról egy simuló gömbre (az ún. új Gauss gömbre), majd onnan a ferde tengelyű sülyesztett hengervetületre. A nemzetközi szakirodalom, illetve térinformatikai rendszerek az ilyen típusú vetületet Hotine néven ismerik, lásd Snyder, Map projections: A working manual, p. 70. Megjegyezzük azonban, hogy a Hotine vetület egyenletei nem teljesen azonosak az EOV egyenleteivel, így az azzal adott megoldások csak közelítőek.

Eddig nem ejtettünk szót a magasság kezeléséről. Ismert, hogy a geodéziában a vizszintes és magassági koordinátákat gyakran külön kezeltek azok gyakorlati különbözőségei miatt. Általánosságban elmondhatjuk hogy két fajta magassági dátumot különböztethetünk meg: ellipszoid magasság, illetve tengerszint feletti (geoidi) magasság. Az ellipszoidi magasság könnyen megadható a térbeli koordinátákból, azonban a tengerszint feletti magasság megadásához ismerni kell az adott pontban a geoid unduláció értékét.

Irodalom:

Geodéziai rendszerek megadása#

import numpy as np

Ebben a leckében a pyroj könyvtárat fogjuk használni, mely lehetővé tesz koordináta-rendszerek definiálást és azok közötti átszámításokat. A könyvtárat Colabben először telepítenünk kell a következő módon:

!pip install pyproj
Requirement already satisfied: pyproj in /home/zoltan/env/uni/lib/python3.8/site-packages (3.5.0)
Requirement already satisfied: certifi in /home/zoltan/env/uni/lib/python3.8/site-packages (from pyproj) (2023.5.7)

Ezután a következő típusokat fogjuk használni a könyvtárból:

from pyproj import CRS, Transformer, Proj

Geodéziai koordináta-rendszereket különböző szabvány vagy kvázi-szabványok, konvenciók alapján tudjuk definálni. Az egyik legfontosabb ezek közül az ún. EPSG szabvány mely szinte a világ összes koordináta rendszeréhez egy számot rendel. Így például a WGS84 geocentrikus koordinátákkal, azaz X, Y, Z alakban a 4978:

crs = CRS.from_epsg(4978) # wgs84 xyz

A fenti kódban létrehozott crs változó tartalmazza a koordináta rendszert.

print(crs)
print(type(crs))
EPSG:4978
<class 'pyproj.crs.crs.CRS'>

Magáról a koordinát rendszerről további információkat tudunk lekérdezni:

print(crs.is_geocentric)
print(crs.is_geographic)
print(crs.is_projected)
True
False
False

Koordináta rendszer definíció WKT formátumban:

print(crs.to_wkt(pretty=True))
GEODCRS["WGS 84",
    ENSEMBLE["World Geodetic System 1984 ensemble",
        MEMBER["World Geodetic System 1984 (Transit)"],
        MEMBER["World Geodetic System 1984 (G730)"],
        MEMBER["World Geodetic System 1984 (G873)"],
        MEMBER["World Geodetic System 1984 (G1150)"],
        MEMBER["World Geodetic System 1984 (G1674)"],
        MEMBER["World Geodetic System 1984 (G1762)"],
        MEMBER["World Geodetic System 1984 (G2139)"],
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]],
        ENSEMBLEACCURACY[2.0]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[Cartesian,3],
        AXIS["(X)",geocentricX,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["(Y)",geocentricY,
            ORDER[2],
            LENGTHUNIT["metre",1]],
        AXIS["(Z)",geocentricZ,
            ORDER[3],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Geodesy. Navigation and positioning using GPS satellite system."],
        AREA["World."],
        BBOX[-90,-180,90,180]],
    ID["EPSG",4978]]

Koordináta rendszer definíció proj4 formátumban:

print(crs.to_proj4())
+proj=geocent +datum=WGS84 +units=m +no_defs +type=crs
/home/zoltan/env/uni/lib/python3.8/site-packages/pyproj/crs/crs.py:1286: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems
  proj = self._crs.to_proj4(version=version)

Hozzuk létre az ETRS89 “koordináta rendszert, és nézzük meg hogy, az geocentrikus.

crs = CRS.from_epsg(4936) # ETRS89 XYZ

print(crs.is_geocentric)
print(crs.is_geographic)
print(crs.is_projected)
True
False
False

A WGS84 rendszer földrajzi koordinátákkal adott változatát a 4326-os kóddal jelöli az EPSG:

crs = CRS.from_epsg(4326) # wgs84 latlon

print(crs.is_geocentric)
print(crs.is_geographic)
print(crs.is_projected)
False
True
False

Nézzük meg az ehhez tartozó WKT definíciót és hasonlítsuk össze a geocentrikus 4978-as változattal:

print(crs.to_wkt(pretty=True))
GEOGCRS["WGS 84",
    ENSEMBLE["World Geodetic System 1984 ensemble",
        MEMBER["World Geodetic System 1984 (Transit)"],
        MEMBER["World Geodetic System 1984 (G730)"],
        MEMBER["World Geodetic System 1984 (G873)"],
        MEMBER["World Geodetic System 1984 (G1150)"],
        MEMBER["World Geodetic System 1984 (G1674)"],
        MEMBER["World Geodetic System 1984 (G1762)"],
        MEMBER["World Geodetic System 1984 (G2139)"],
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]],
        ENSEMBLEACCURACY[2.0]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
        SCOPE["Horizontal component of 3D system."],
        AREA["World."],
        BBOX[-90,-180,90,180]],
    ID["EPSG",4326]]

Az EOV-t a 23700-as kóddal találjuk:

crs_eov = CRS.from_epsg(23700) # eov

print(crs_eov.is_geocentric)
print(crs_eov.is_geographic)
print(crs_eov.is_projected)
False
False
True

A vetületi koordináta rendszerek esetén, létezik egy alapfelület, melyet le tudunk kérdeni a következő módon:

crs_eov.geodetic_crs
<Geographic 2D CRS: EPSG:4237>
Name: HD72
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: Hungary.
- bounds: (16.11, 45.74, 22.9, 48.58)
Datum: Hungarian Datum 1972
- Ellipsoid: GRS 1967
- Prime Meridian: Greenwich
print(crs_eov.to_wkt(pretty=True))
PROJCRS["HD72 / EOV",
    BASEGEOGCRS["HD72",
        DATUM["Hungarian Datum 1972",
            ELLIPSOID["GRS 1967",6378160,298.247167427,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4237]],
    CONVERSION["Egyseges Orszagos Vetuleti",
        METHOD["Hotine Oblique Mercator (variant B)",
            ID["EPSG",9815]],
        PARAMETER["Latitude of projection centre",47.1443937222222,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8811]],
        PARAMETER["Longitude of projection centre",19.0485717777778,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8812]],
        PARAMETER["Azimuth of initial line",90,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8813]],
        PARAMETER["Angle from Rectified to Skew Grid",90,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8814]],
        PARAMETER["Scale factor on initial line",0.99993,
            SCALEUNIT["unity",1],
            ID["EPSG",8815]],
        PARAMETER["Easting at projection centre",650000,
            LENGTHUNIT["metre",1],
            ID["EPSG",8816]],
        PARAMETER["Northing at projection centre",200000,
            LENGTHUNIT["metre",1],
            ID["EPSG",8817]]],
    CS[Cartesian,2],
        AXIS["easting (Y)",east,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["northing (X)",north,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Engineering survey, topographic mapping."],
        AREA["Hungary."],
        BBOX[45.74,16.11,48.58,22.9]],
    ID["EPSG",23700]]
print(crs_eov.to_proj4())
+proj=somerc +lat_0=47.1443937222222 +lon_0=19.0485717777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +units=m +no_defs +type=crs

Transzformációk#

A BME permanens mérőállomás koordinátáit fogjuk használni a továbbiakban, amelynek koordinátái a következőek:

# %%
# BUTE GPS Point: https://www.gnssnet.hu/pdf/BUTE.pdf
y_eov = 650684.479 # easting
x_eov = 237444.175 # northing
z_eov = 137.177 # EOMA height

Végezzünk transzformációt az EOV és a WGS84 rendszer között. Az eredményt földrajzi koordinátákban szereténk megkapni. Ehhez először definiáljuk a két rendszert a korábbiaknak megfelelően:

crs_eov = CRS.from_epsg(23700)
crs_wgs84_llh = CRS.from_epsg(4326)

Majd a pyroj Transformer osztályát használjuk hogy egy Transformer típust hozzunk létre:

transformer = Transformer.from_crs(crs_eov, crs_wgs84_llh)

print(type(transformer))
<class 'pyproj.transformer.Transformer'>

Ezt a típust használhatjuk utána a transzformáció elvégzésére:

wgs_xyz = transformer.transform(y_eov, x_eov, z_eov)

print(wgs_xyz)
(47.480942681093, 19.05652711329527, 137.177)

Az eredmény egy tuple típus, mely a WGS84 földrajzi koordinátákat tartalmazza.

Hasonló módon végezzük el a transzformációt az EOV és a ETRS89 rendszerek között. Adjuk meg a földrajzi és geocentrikus koordinátákat is.

crs_eov = CRS.from_epsg(23700) # HD72 / EOV
crs_etrs89_llh = CRS.from_epsg(4258) # ETRS89/GRS80, lat/lon
crs_etrs89_xyz = CRS.from_epsg(4936) # ETRS89, ECEF-XYZ
# %%
eov2etrs89_xyz = Transformer.from_crs(crs_eov, crs_etrs89_xyz)
eov2etrs89_llh = Transformer.from_crs(crs_eov, crs_etrs89_llh)
# %%
# BUTE GPS Point: https://www.gnssnet.hu/pdf/BUTE.pdf
y_eov = 650684.479 # easting
x_eov = 237444.175 # northing
z_eov = 137.177 # EOMA height
p_etrs89_xyz = eov2etrs89_xyz.transform(y_eov, x_eov, z_eov)
p_etrs89_llh = eov2etrs89_llh.transform(y_eov, x_eov, z_eov)

print(p_etrs89_xyz)
print(p_etrs89_llh)
(4081854.584760393, 1410001.4285596195, 4678167.186847403)
(47.48094314528847, 19.05652833851546, 137.177)

Műveletek az ellipszoidon#

from geopy.distance import geodesic
# %% Geodetic distance between two points defined with lat/lon
coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)
sol_1 = geodesic(coords_1, coords_2, ellipsoid='GRS-80').m * 100
sol_2 = geodesic(coords_1, coords_2, ellipsoid='WGS-84').m * 100
print('Difference GRS-80 vs. WGS-84 [cm]: ', sol_1 - sol_2)
Difference GRS-80 vs. WGS-84 [cm]:  0.00028607621788978577

Transzformációs gridek#

# %% Comparison to eht2: http://eht.gnssnet.hu/index.php
p_eht_etrs89_xyz = np.array([4081882.378, 1410011.142, 4678199.391])
p_eht_etrs89_llh = np.array([47.4809437284, 19.0565297521, 180.811])

print(p_etrs89_xyz - p_eht_etrs89_xyz)
[-27.79323961  -9.71344038 -32.2041526 ]
# %%
print('Difference XY [cm]: ', geodesic(p_eht_etrs89_llh[0:2], p_etrs89_llh[0:2]).m * 100)
# Note: the Z of p_etrs89_llh[2] is the same as input, no Z coordinate transformation
# print('Difference Z  [m]: ', (p_eht_etrs89_llh[2] - p_etrs89_llh[2]))
Difference XY [cm]:  12.471731150364025
# %% Original definiation of HD72/EOV in proj4 format
print('Original definiation:')
print(crs_eov.to_proj4())
Original definiation:
+proj=somerc +lat_0=47.1443937222222 +lon_0=19.0485717777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +units=m +no_defs +type=crs
/home/zoltan/env/uni/lib/python3.8/site-packages/pyproj/crs/crs.py:1286: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems
  proj = self._crs.to_proj4(version=version)
# %%
# Grid letölthető: https://github.com/OSGeoLabBp/eov2etrs
# < transzformáció 1 cm-es középhibán belül azonos az EHT-vel
# az EHT transzformációja 10 cm-es középhibájú
nadgrids = './data/etrs2eov_notowgs.gsb'# XY grid
geoidgrids = './data/geoid_eht2014.gtx' # geoid model for Z transformation
crs_eov_grid = Proj(init='EPSG:23700', nadgrids=nadgrids, geoidgrids=geoidgrids) # HD72 / EOV
print(crs_eov_grid.to_proj4())
+proj=somerc +lat_0=47.1443937222222 +lon_0=19.0485717777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +nadgrids=./data/etrs2eov_notowgs.gsb +units=m +geoidgrids=./data/geoid_eht2014.gtx +geoid_crs=WGS84 +vunits=m +no_defs
/home/zoltan/env/uni/lib/python3.8/site-packages/pyproj/crs/crs.py:141: FutureWarning: '+init=<authority>:<code>' syntax is deprecated. '<authority>:<code>' is the preferred initialization method. When making the change, be mindful of axis order changes: https://pyproj4.github.io/pyproj/stable/gotchas.html#axis-order-changes-in-proj-6
  in_crs_string = _prepare_from_proj_string(in_crs_string)
# %% XYZ transformation
eov2etrs89_xyz = Transformer.from_proj(crs_eov_grid, crs_etrs89_xyz)
p_etrs89_xyz = eov2etrs89_xyz.transform(y_eov, x_eov, z_eov)

print(p_etrs89_xyz)
print(p_eht_etrs89_xyz)
print('Difference [cm]: ', np.linalg.norm(p_etrs89_xyz - p_eht_etrs89_xyz) * 100)
(4081882.3770687627, 1410011.1433535905, 4678199.3908524215)
[4081882.378 1410011.142 4678199.391]
Difference [cm]:  0.16496028796703496
# %% LLH transformation:
eov2etrs89_llh = Transformer.from_proj(crs_eov_grid, crs_etrs89_llh)
p_etrs89_llh = eov2etrs89_llh.transform(y_eov, x_eov, z_eov)
print('Difference [cm]: ', geodesic(p_etrs89_llh[0:2], p_eht_etrs89_llh[0:2]).m * 100)
print('Difference Z  [cm]: ', (p_etrs89_llh[2] - p_eht_etrs89_llh[2])*100)
Difference [cm]:  0.16408611991976702
Difference Z  [cm]:  -4363.4000000000015
print(p_eht_etrs89_llh)
[ 47.48094373  19.05652975 180.811     ]