En pystynyt sittenkään pitämään näppejäni irti avoimen datan koodailuista. Olin jo vähän aikaa miettinyt, että olisi kiva kokeilla, miten noita Maanmittauslaitoksen esim. maastokarttoja saisi kännykkään näppärästi. iPhonessa on muutama ohjelma, jotka jotain noista kartoista näyttää. Ajattelin kuitenkin, että olisi parempi tehdä yleinen kirjasto, jonka avulla kuka tahansa saisi nuo kartat mukaan Android ohjelmiinsa.
Tämän tekeminen tuntui aika isolta hommalta, kunnes törmäsin avoimeen osmdroid-kirjastoon. Sillä pystyy helposti näyttämään Android-kännyköissä erilaisia karttoja, kuten OpenStreetMap-kartan. Vielä kun Maanmittauslaitoksella oli sopivan oloinen web rajapinta karttoihin eli Web Map Service-palvelun (WMS), joka on mahdollisesti tulossa aivan vapaaseen käyttöön, tuntui karttojen yhdistäminen osmdroid-ohjelmaan suoraviivaiselta jutulta.
Ensin piti hakea tunnukset rajapinta-palveluun, jotka saikin sutjakkaasti. Sitten osmdroid-softaa piti puukottaa hieman lisäämällä sinne uusi lähde karttojen laatoille (eng. tile).
public class TileSourceFactory {
...
public static final OnlineTileSourceBase MML =
new MML__XYTileSource("Maanmittauslaitos",
ResourceProxy.string.mml,
0, 18, 256, ".png",
"http://opendata.fi/tiles/proxy.php");
...
private static ArrayList mTileSources;
static {
mTileSources = new ArrayList();
mTileSources.add(MML);
...
}
}
Kuten koodista näkyy, tein oman “karttaproxyn” verkkoon (kyllä opendata.fi -domain on minulla käytössä
). Varsinainen karttojen laattalähde (MML__XYTileSource) yksinkertaisesti kertoi, miten tuohon minun proxyyn kysely pitää tehdä.
public class MML__XYTileSource extends XYTileSource {
....
@Override
public String getTileURLString(final MapTile aTile) {
return getBaseUrl()+"?zoom=" + aTile.getZoomLevel() +
+ "&X=" + aTile.getX() + "&Y=" + aTile.getY();
}
}
Tuolla proxyllä lähinnä kierretään WMS-palvelun vaatima HTTP Basic tunnistautuminen. Nyt kännykän sijaan proxy tunnistautuu palveluun käyttäjätunnuksella ja salasanalla. Proxy myös muuntaan nuo OpenStreetMap laattanumerot WGS-84 koordinaateiksi ja sitten vielä WMS-palvelun käyttämiksi ETRS-TM35FIN tasokoordinaateiksi.
$url = "https://ws.nls.fi/rasteriaineistot/image?service=WMS" .
"&version=1.1.1&request=GetMap&width=256&height=256".
"&format=image%2Fpng&layers=maastokartta_500k".
"&styles=normal&srs=EPSG%3A3067&bgcolor=ffffff".
"&transparent=false&time=&bbox=";
$zoom = $_GET['zoom'];
$X = $_GET['X'];
$Y = $_GET['Y'];
//Lasketaan kulmien koordinaatit minimi NE ja maksimi NE
$Y=$Y+1;
$wgs2 = tiles_to_wgs84($X,$Y,$zoom);
$etr2= wgs_etrs($wgs2['lat'], $wgs2['lon']);
$X = $X + 1;
$Y = $Y - 1;
$wgs4 = tiles_to_wgs84($X,$Y,$zoom);
$etr4= wgs_etrs($wgs4['lat'], $wgs4['lon']);
$url .= $etr2['E'] .",".$etr2['N'].",".$etr4['E'].",". $etr4['N'];
PHP:n cURL-functioilla käydään hakemassa karttakuva Maanmittauslaitoksen WMS-palvelusta, josta se heitetään se suoraan kännykkäsovellukselle.
$ch = curl_init();
$timeout = 0;
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
// Getting binary data
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERPWD, "käyttäjätunnus:salasana");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
$image = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
$im = @imagecreatefromstring($image);
header("Content-type: image/png");
imagepng($im);
imagedestroy($im);
Laskentakaavat joilla OpenStreetMap laattanumerot muutetaan WGS-84 koodinaateiksi ja sitten vielä ETRS-TM35FIN tasokoordinaateiksi piti hakea kissojen ja koirien kanssa netistä. Lopullinen totuus löytyi täältä ja täältä.
function tiles_to_wgs84($x,$y,$zoom){
$n = pow(2, $zoom);
$lon_deg =$x / $n * 360.0 - 180.0;
$lat_rad = atan(sinh( pi() * (1 - 2 * $y / $n)));
$lat_deg = $lat_rad * 180.0 / pi();
$wgs = array();
$wgs['lat'] = $lat_deg;
$wgs['lon'] = $lon_deg;
return $wgs;
}
function wgs_etrs($la, $lo){
$Ca = 6378137.0;
$Cb = 6356752.314245;
//WGS84 ellipsoid
//$Cf = 1.0 / 298.257223563;
$Cf = 1.0 / 298.257222101;
$Ck0 = 0.9996;
$Clo0 = deg2rad (27.0);
$CE0 = 500000.0;
$Cn = $Cf / (2.0 - $Cf);
$CA1 = $Ca / (1.0 + $Cn) * (1.0 + pow($Cn, 2.0) / 4.0 + pow($Cn, 4.0) / 64.0);
$Ce = sqrt(2.0 * $Cf - pow($Cf, 2.0));
$Ch1 = 1.0/2.0 * $Cn - 2.0/3.0 * pow($Cn, 2.0) + 37.0/96.0 * pow($Cn, 3.0) - 1.0/360.0 * pow($Cn, 4.0);
$Ch2 = 1.0/48.0 * pow($Cn, 2.0) + 1.0/15.0 * pow($Cn, 3.0) - 437.0/1440.0 * pow($Cn, 4.0);
$Ch3 = 17.0/480.0 * pow($Cn, 3.0) - 37.0/840.0 * pow($Cn, 4.0);
$Ch4 = 4397.0/161280.0 * pow($Cn, 4.0);
$Ch1p = 1.0/2.0 * $Cn - 2.0/3.0 * pow($Cn, 2.0) + 5.0/16.0 * pow($Cn, 3.0) + 41.0/180.0 * pow($Cn, 4.0);
$Ch2p = 13.0/48.0 * pow($Cn, 2.0) - 3.0/5.0 * pow($Cn, 3.0) + 557.0/1440.0 * pow($Cn, 4.0);
$Ch3p = 61.0/240.0 * pow($Cn, 3.0) - 103.0/140.0 * pow($Cn, 4.0);
$Ch4p = 49561.0/161280.0 * pow($Cn, 4.0);
$la = deg2rad($la);
$lo = deg2rad($lo);
$l = $lo - $Clo0;
$cos = cos($la)*$l;
// Mittakaavakerroin
//$Ck0 = $Ck0*(1 + 0.5 * pow($cos,2));
//logger("mittakaavakerroin: $Ck0");
$Q = asinh(tan($la)) - $Ce * atanh($Ce * sin($la));
$be = atan(sinh($Q));
$nnp = atanh(cos($be) * sin($lo - $Clo0));
$Ep = asin(sin($be) * cosh($nnp));
$E1 = $Ch1p * sin(2.0 * $Ep) * cosh(2.0 * $nnp);
$E2 = $Ch2p * sin(4.0 * $Ep) * cosh(4.0 * $nnp);
$E3 = $Ch3p * sin(6.0 * $Ep) * cosh(6.0 * $nnp);
$E4 = $Ch4p * sin(8.0 * $Ep) * cosh(8.0 * $nnp);
$nn1 = $Ch1p * cos(2.0 * $Ep) * sinh(2.0 * $nnp);
$nn2 = $Ch2p * cos(4.0 * $Ep) * sinh(4.0 * $nnp);
$nn3 = $Ch3p * cos(6.0 * $Ep) * sinh(6.0 * $nnp);
$nn4 = $Ch4p * cos(8.0 * $Ep) * sinh(8.0 * $nnp);
$E = $Ep + $E1 + $E2 + $E3 + $E4;
$nn = $nnp + $nn1 + $nn2 + $nn3 + $nn4;
$ETRS = array();
$ETRS['N'] = $CA1 * $E * $Ck0;
$ETRS['E'] = $CA1 * $nn * $Ck0 + $CE0;
return $ETRS;
}
Kun nämä saadaan tehtyä, ilmestyy tälläinen hieman sekava kartta kännykkään.
Kun tuota kuvaa tarkemmin katsoon, niin ohjelma lataa karttalaattoja hieman pieleen. Vierekkäiset karttalaatat eivät aivan täsmälleen osu kohdalleen ja siksi kuva on vähän sekava. Syy on (kai) se, että nuo WMS-palvelun laattojen koordinaatiolasku ei ole noista eri koordinaatistoista (WGS-84 ja ETRS-TM35FIN) johtuen ihan niin suoraviivainen kuin miten sen olen tehnyt. Tähän oikeastaan jätin homman, koska ajattelin, että ehkä joku geo-viisaampi osaisi neuvoa, miten jatkaa tästä eteenpäin.
Toivottavasti en tallonut kenenkään varpaille, koska tämä aihe liippaa myös hyvin läheisesti Apps4Finland-kilpailua, jota olen järjestämässä. Tämä kuitenkin osoitti, että tuollaisen ohjelman tekeminen ei ole mahdotonta ja vaikka homma jäi vielä aika pahasti vaiheeseen (esim. zoomauksen ottaminen paremmin huomioon proxyssä), tästä on hyvä jatkaa kenen tahansa ja tehdä kiinnostava ja etenkin toimiva sovellus Androidiin, joka käyttää noita karttoja. Ja tietenkin toivon näkeväni noita sovelluksia myös Apps4Finland-kilpailussakin!

Ei kai tuossa muunnoksessasi mitään vikaa ole. Mutta kun kun pyydät MML:n palvelusta karttakuvan, niin karttakuvien reunat ovat sitten eri kordinaateissa kuin kuvittelet.
Nopea ratkaisu voisi olla pyytää MMLn palvelusta useampia kuvia. Jaat vaikka alkuperäisen pyynnön 4 pienempään kuvaan. Virhe ei varmaan tuolla vielä kokonaan poistu, mutta pienenee.
Paras ratkaisu olisi tietysti muuntaa aidosti tuo karttakuva WGS84 maailmaan.
Pitääpä kokeilla tosiaan jos tuo karttaproxy kyseliskin pienempiä laattoja. Ihmettelen kyllä vähän, miksi nuo webbisivuilla olevat MML kartat (retkikartta.fi) näyttävät tismalleen tarkasti oikein kartat. Ihan kuin niissä ohittaisiin nuo WGS84 koordinaatit ja mäppättäisiin tuosta laattanumerosta suoraan oikean kokoinen MML karttakuvan. Tämä on kimuranttia hommaa tälläiselle noviisille.
Tälläinenkin viritys löytyi:
http://naprays.net/sekalaista/maastokartta-kannykkaan/
Todella mielenkiintoinen kirjoitus! Kiitos. Ehtispä alkaa askartelemaan tuon kanssa, sillä olis melkolailla parhautta saada androidiin maastokarttaa suoraan verkosta.
Onko tuossa wgs_etrs muunnoksessa hieman heittoa ja sen vuoksi tulee sitten myös tileen heittoja? Tutkailin vastaavaa luokaa code.google.com:sta ja törmäsin tällaiseen ratkaisuun (Androidissa):
https://code.google.com/p/etrstm35fin2wgs84/source/browse/trunk/src/com/etrstm35fin2wgs84/MainActivity.java?r=2
Näyttäisi tuossa laskennallisesti olevan hieman eroja, ainakin arvot ovat erilaisia parissa kohtaa?
Kiitti, pitääpä yrittää saada aikaiseksi tuon kokeilu. Epäilen kuitenkin, että nuo koordinaatisto erot tässä on se ongelma, eikä tuo kaava siihen vaikuta.
Totta on, itsekään en testannut, korjaako vain parin arvon muuttaminen tuota karttaa.
Itselläni tulee varmaan keväämmällä tähän liittyen eteen android-projekti, joten uskoisin, että samojen asian kanssa joudun pähkäilemään parin kuukauden päästä.
Maanmittauslaitoksen maastokarttoja avataankin kevään aikana paljon lisää ilmaiseen ja vapaaseen käyttöön joten niiden käyttämistä kannattaa kyllä kokeilla. Asiasta lisää infoa täältä:
http://www.maanmittauslaitos.fi/avoindata
Pitää itsekin palata tähän aiheeseen jälleen.
Jep, tuohon liittyen täytynee tehdä projekti tai ehkä parikin, jotka mulla on mielessä. Luultavasti laajennan tätä nykyistä projektiani maanmittaushallituksen karttoihin siten, että voi valita joko tarkat kartat tai google-maps puolen, tarpeen mukaan.
Tiedätkö muuten, tulevatko tien osat ja tienumerot vapaaseen käyttöön vai omistaako tämän datan edelleen tiehallinto (tai destia tai mikä se onkaan). Itselleni olisi käyttöä tälle datalle, eräs asiakas on sitä jo kysellyt, mutta ainakin vielä dataa ei ole avoimesti saatavilla. Käsittääkseni maanmittauslaitoksen kartoista ei ainakaan nyt löydy tätä tietoa.
En ole ihan varma tuosta. Tuollainen maastokartan tietosisältö näyttäisi olevan ehkä lähimpänä:
http://www.maanmittauslaitos.fi/digituotteet/maastotietokannan-tiesto-osoitteilla
Täältä voi katsoa lisää tietoa:
http://www.maanmittauslaitos.fi/luettelo-avattavista-aineistoista
http://www.maanmittauslaitos.fi/digituotteet/maastotietokanta
Btw, kiinnostava Maanmittauslaitoksen blogi datan avaamisesta:
http://maastotiedotauki.blogspot.com/
Kiitoksia kaivamisesta, olipas mielenkiintoiset linkit! Rupean samantien tutkimaan lähemmin asiaa.
Moikka,
onko näistä teidän pohdinnoista vielä Google Playssä mitään ladattavaa?
Missä menette, onko jotain tulossa? Kiitos etukäteen.
–HE
Omat pohdinnat eivät ole päätyneet Google Play:hin. Karttojen sarallahan on tapahtumassa kevään aikana paljon, kun Maanmittauslaitoksen maastokartta tulee vapaaseen käyttöön. Sovelluksia tulee varmaan mukavasti sen seurauksena.
Jep, kiitos, ja onhan noita maastokarttoja nytkin saatavilla, osa toki maksullisia vielä.
Toivotaan myös, että noita karttoja saa helposti yhdistettyä mihin tahansa kännykkäsovellukseen, mikä oli oikeastaan alkuperäinen tavoitteeni.
Itselläni on aikas pitkällä yksi projekti, joka tosin pyörii google maps pohjalta. Lähinnä joitakin overlayitem-asemointeja uupuu (nopeustiedoista). Mutta tarkoitus olisi (ikävä kyllä?) kerätä pieni maksu, jolla pystyisin saamaan omalle firmalle vähän tuottoa ja sitten tällä tuotolla kehittämään maanmittauslaitoksen karttojen päälle sovelluksen tai useitakin.
Katsotaan nyt, koska saan ongelmat ratkaistua, versio 1.0 olisi kyllä tässä tulossa niin pian ulos kuin suinkin. Mietin myös digitraffic-datan pohjalle tehtyä sovellusta liikennetiedotteisiin liittyen, koska ei olisi kovinkaan vaikeaa vaihtaa rajapinnan kyselyitä toiseen rajapintaan, kun ensin on luonut yhteen rajapintaan yhteydet kuntoon.
Yksityisyrittäjänä on kuitenkin vähän hankalaa tuo kehitystyö, kun leipä pitää tehdä jostakin perheelle ensin ja sitten vasta yrittää parhaansa, että saa koodattua projektia eteenpäin
Kerrohan sitten, kunohjelma on valmis. Tämä kyllä kiinnostaa. Ja maksun pyytäminen sovelluksesta on minusta ihan ok. Kyllä hommasta pitää saada joku korvaus!