Jegyzet
Kézenfekvő gondolatnak tűnik, hogy ha a Google-nek van szabadon használható térképe, amelyen meg lehet
határozni két földrajzi hely között a távolságot (sőt az utazási időt is), akkor mindezt egy API-n
keresztül is lehetőség van lekérdezni. Valóban így van: erre való a
Google Distance Matrix API,
de ez sem nem ingyenes, sem nem használható általánosan, anonim módon.
Mi tehetünk ilyenkor? Esetleg mi is készíthetnénk egy sajátot?
1.AEgy földrajzi hely GPS koordinátáinak meghatározása
Vajon létezik-e más, ingyenes, nyílt forráskódú térkép, melynek alapján vélelmezhetünk API-t, ami
lehetővé teszi a távolságmérést? Vagy legalább azt, hogy
egy földrajzi név esetén megtudhassuk
a hozzá tartozó GPS koordinátákat. Eszünkbe juthat az
openstreetmap.org
weboldal, aminek a nevét összekombinálva az API szóval rákereshetünk az
openstreetmap API
kifejezésre. Innen már hamar eljutunk a
nominatim.org
oldalra, mely egészen hasznos információkat kínál számunkra: éppen az OpenStreetMap API-jának
elérhetőségét és leírását. Ez alapján ha rá szeretnénk keresni pl.
Velence településre,
akkor azt ekképpen tehetjük meg:
https://nominatim.openstreetmap.org/search?q=velence&format=jsonv2
ami olvashatóbban megjelenítve
így néz ki.
Két tapasztalattal azonnal gazdagabbak lehetünk:
- valóban megkaptuk Velence GPS koordinátáit;
- az olaszországi Velence, és a magyarországi Velence adatait is.
Érdemes tesztelni az API-t: mit mond, ha a keresett település pl.
Visegrád,
vagy éppen
Verőce!
És vajon csak településeket ismer az API? Vagy egyéb helyeket is megtalál?
Mint kipróbálható,
az openstreetmap.org API-ja valóban jól vizsgázik a fenti keresések esetén is.
Épp úgy be tud azonosítani intézményneveket, vagy turisztikai látványosságoat, mint ahogyan a különböző
a településrészek is felismeri.
Ugyanakkor az
Üllői út vonatkozásában érdemes észre venni, hogy ennek a budapesti útnak a teljes
hossza eléri a 15 km-t, így célszerű lehet tesztelni az API-t, vajon a házszámokkal is boldogul-e.
Néhány kísérlet után be kell látnunk: az API
nincs felkészítve a címekben található házszámok
kezelésére.
1.BCímkereső API GPS koordináták visszaadásával
Vajon milyen találatokat kapunk Google-ben az
address API
kifejezés keresése esetén?
A találatok között turkálva felfedezhetünk egy érdekes ajánlatot:
European Union Address API
Belelapozva az ENDPOINTS menüpont tartalmába, nemcsak leírást, hanem konkrét példákat is találunk,
melyek alapján tesztelhetjük az 1. pontban tárgyalt API gyenge pontját, vagyis az Üllői út házszámait:
Csekkolva a visszaadott GPS koordinátákat, megállapíthatjuk, hogy ez az API csakugyan
jól vizsgázik
házszámmal történő keresés esetén is - némi kiegészítéssel. Egyrészt nem szabadszavasan, hanem struktúráltan
kell paraméterezni, vagyis külön-külön paraméterben kell megadni a várost, az utcát, és a házszámot. Másrészt
Budapest esetén a kerületet is muszáj megadni, ellenkező esetben többnyire nem kapunk találatot.
Az API tehát meglehetősen ügyes konkrét címek keresése esetén, de vajon boldogul-e a nem címekkel adott
földrajzi helyekkel? A válasz nem túl pozitív, hiszen végignézve a kapcsolódó dokumentációt, a struktúrált
paraméterezés lehetőségei között egész egyszerűen
nem található olyan opció, ahol meg lehetne adni intézményt,
turisztikai látványosságot, vagy éppen tavak nevét. Tapasztalhatjuk továbbá, hogy nem ismeri fel az egyes
települések nevesebb településrészeit sem, mint pl. Lillafüred, Mátraszentistván, vagy épp Salgóbánya.
2. GPS koordinátákkal adott földrajzi helyek közötti távolság
Kiindulási elképzelésünk alapján olyan szabad felhasználású API-t kerestünk, mely meg tudja mondani
két tetszőleges földrajzi hely között a távolságot. Ám ha ilyet nem találunk, az még nem jelenti azt,
hogy olyanra sem bukkanhatunk rá, ami GPS koordinátákkal adott helyek közt mondja meg a távolságot.
Ráadásul ha találnánk ilyet, akkor a fenti két API felhasználásával már tudnánk saját API-t készíteni a
kívánt cél eléréséhez.
De vajon hogyan kell meghatározni a távolságot földrajzi koordinátákkal adott helyek között?
A kérdés azért is érdekes, mert ha a távolságot légvonalban értjük, akkor igazából API-ra sincs
szükség, csupán matematikára.
A térképen a Föld gömb jellege miatt - külö-nösen nagy távolságok, pl. a légiközlekedés
esetén - nem mindig a legrövidebbnek tűnő út a legrövidebb.
Ám ekkor is van lehetőség kiszámolni a távolságot a földrajzi koordináták alapján,
pl. a
Haversine formulával:
ahol értelemszerűen a
lat, és a
lon értékei a szélességi és a hosszúsági fokokat
jelölik, illetve
R a Föld sugara, melynek középértéke 6371 km.
Persze, nem sokra megyünk a matematikával, ha mi a közúti távolságra vagyunk kíváncsiak.
Rákeresve a
from gps to distance api free
kifejezésre mi most teszteljük le az Open Source Routing Machine ajánlatát a
project-osrm.org
oldalon. Itt válasszuk a
Documentation gombot!
A lehetőségek között görgetve rátalálhatunk a
Trip service
opcióra, mely egy kiindulási pont és egy úticél GPS koordinátái között képes megadni a térképi
távolságot (méterben), illetve az ennek megtételéhez szükséges időt (másodpercben). Vegyük észre azonban,
hogy a szokásostól eltérő módon
ez az API fordított sorrendben várja a szélesség-magasság koordináta-párokat,
vagyis a korábbi API-k által kapott [lat,lon] adatpárost megcserélve kell majd a mostani API-nknak odaadni!
Teszteljük!
1. tesztpélda
Szeretnénk eljutni Budapestről a Népligettől Keszthelyre a Festetics-kastélyhoz. Mennyi idő kell ehhez?
Milyen hosszú az út?
A
Népliget GPS koordinátái az OpenStreetMap API-ja szerint
lat:47.4752959, lon:19.0999512
A
Festetics-kastély GPS koordinátái az OpenStreetMap API-ja szerint
lat:46.7707287, lon:17.24190147849614
Ezeket a koordinátákat
odaadva az OSRM API-jának
(figyelve a fentebb már említett lat-lon cserére) azt kapjuk, hogy a két helyszín között
- a távolság 194215.7, vagyis nagyjából 194 km
- az utazási idő pedig 7790.3, tehát kb. 2 óra 10 perc
Ellenőrzésként hasonlítsuk össze a kapott adatokat a
Google Maps
által mondott adatokkal!
Mint látható,
a távolság kilométerre pontosan egyezik, az utazáshoz szükséges időt azonban a forgalmi adatok
függvényében nem feltétlenül azonosan számítja a két térkép.
2. tesztpélda
Határozzuk meg, milyen hosszú az Üllői út!
Az
Üllői út 2. GPS koordinátái az EU Address API-ja szerint
"XY":[19.0630406,47.4892366]
Az
Üllői út 798. GPS koordinátái az EU Address API-ja szerint
"XY":[19.2337405,47.4239647]
Ezeket a koordinátákat
odaadva az OSRM API-jának
(a lat-lon csere itt nem szükséges, mert az EU Address API is fordítva dolgozik velük) azt kapjuk, hogy a két helyszín között
- a távolság 16890.5, vagyis 16,89 km
Ellenőrzésként hasonlítsuk össze a kapott adatokat a
Google Maps
által mondott adatokkal!
Itt érdemes észrevenni, hogy bár
a két térkép szinte méterre pontosan azonos távolságot ad vissza,
valójában nem az Üllői út hosszát kaptuk meg, hanem a két végpont között leggyorsabban megtehető útnak a
hosszát. Ám ez egy picit hosszabb út, mintha végig az Üllői úton mennénk.
Tesztpéldáink meggyőzhetnek minket arról, hogy a felhasznált API-k lehetővé teszik egy saját
Distance API megalkotását.
Feladat
A fent bemutatott API-k összeépítésével készítsen saját API-t, mely
két adott földrajzi hely
között képes megmondani
- a légvonalban mért távolságot,
- a közúti távolságot,
- és az út autóval való megtételéhez szükséges időt!
A távolságokat kilometerben, egytizedes pontossággal, az időt pedig percben,
egész számra kerekítve adja vissza!
Oldja meg, hogy az API akkor is működjön, ha a felhasználó különféle földrajzi helyeket (városokat,
település-részeket, turisztikai látványosságokat, intézményneveket, stb.) szeretne szerepeltetni
a keresésben, és akkor is, ha inkább konkrét címeket adna meg házszámok használatával együtt.
Az API kényelmesebb tesztelhetősége érdekében készítsen webes űrlapot (frontend felületet), melyen
szövegesen megadható a tervezett utazás kiindulási pontja, illetve a kívánt érkezési hely. E felületen
oldja meg az API által visszaadott értékek megjelenítését is, de egy linken keresztül adjon lehetőséget rá,
hogy az érdeklődők az API eredményeit közvetlenül az API-hívással is megtekinthessék a böngészőben, egy
önálló fülön!
Tipp a megoldáshoz
Munkánk során tapasztalni fogjuk, hogy az OpenStreetMap API-ja nem hagyja magát kiolvasni
a szokásos módon, vagyis az
fopen() függvénnyel. Éppen ezért itt egy picit összetettebb
megoldásra lesz szükség. Ehhez használja az alábbi PHP forráskódot!
$url = "https://nominatim.openstreetmap.org/search?q=Galyateto&format=json";
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_REFERER, $url);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36");
$json = curl_exec($ch);
curl_close($ch);
Precizitás és anomáliák
Vegyük észre, hogy helyenként meglehetősen fontos a földrajzi hely precíz megnevezése ahhoz, hogy találatként, pláne első
találatként valóban a keresett helyet kapjuk eredményül. Lássunk néhány félreértési lehetőséget.
- Visegrad - ékezet nélkül - elsőként Boszniában kerül megtalálásra, míg ékezettel a magyar helyszín ugrik az első helyre az OpenStreepMap API-jában.
- Hasonlóan Makó ugyan Magyarországon van, de Mako előfordul Szenegálban, Nigériában, Etiópiában, Csádban, Ugandában, de még Pápua Új-Guineán is - épp csak nálunk nem.
- Velence Olaszországban található. Ha a mi Velencénket szeretnénk találatként első helyen látni, akkor Velencefürdő célravezető pontosítás lehet.
- A térképek sem mindig következetesek: pl. Salgótarjánban az OpenStreepMap API-ja szerint Báthory István utca létezik, míg az EU Address API szerint Báthori István utca. Fordítva próbálkozva nem kapunk találatot.
- Mint fentebb is olvasható volt: az EU Address API-ja a fővárosi utcanevek azonosításához a kerületek megjelőlését is megköveteli, méghozzá római számokkal.
Hasonló tapasztalatokba Ön is beleszaladhat. Ilyenkor kísérletezzen, pontosítson - és igyekezzen úgy megírni a feladatként elkészítendő API-t, hogy az
- találatok esetén mindig adja vissza válaszban a megtalált helyek precíz neveit is, amelyek között a távolság számítását elvégzi;
- találat hiányában pedig jelezze, hogy a kiindulási vagy az érkezési helyszínt nem sikerült-e beazonosítania.
Minta
Nézzünk mindkét esetre egy-egy lehetséges példát!
Ha
van találat a kiindulási és az érkezési helyre is
http://localhost/api/tavolsag/?from=bkszc&to=jégpark
akkor a kapott JSON kibontva pl. az alábbi tartalommal bírhat:
stdClass Object
(
[result] => ok
[from] => stdClass Object
(
[query] => bkszc
[gps] => 47.41978215,19.05715843424581
[location] => BKSZC Weiss Manfréd Szakgimnáziuma és Szakközépiskolája, 7, Tanműhely köz, Csepel-Gyártelep, XXI. kerület, Budapest, Közép-Magyarország, 1211, Magyarország
)
[to] => stdClass Object
(
[query] => jégpark
[gps] => 47.4297729,19.0672983
[location] => Csepeli Jégpark Jegypénztár, II. Rákóczi Ferenc út, Csepel-Gyártelep, XXI. kerület, Budapest, Közép-Magyarország, 1211, Magyarország
)
[distance] => stdClass Object
(
[airkm] => 1.3
[km] => 1.8
[time] => 4
)
)
Tehát a két helyszín között a távolság légvonalban
1,3 km, ám ez közúton valójában
1,8 km,
melyet autóval
4 perc alatt lehet megtenni.
Ha
nincs találat pl. az érkezési helyre
http://localhost/api/tavolsag/?from=bkszc&to=nszfh
akkor a kapott JSON hasonló lehet:
{"result":"error","error":"to is unknown","documentation":"http://localhost/api/"}