{"id":1497,"date":"2014-11-23T20:29:48","date_gmt":"2014-11-23T20:29:48","guid":{"rendered":"http:\/\/41j.com\/blog\/?p=1497"},"modified":"2015-03-13T04:23:34","modified_gmt":"2015-03-13T04:23:34","slug":"slippy_maps","status":"publish","type":"post","link":"https:\/\/41j.com\/blog\/2014\/11\/slippy_maps\/","title":{"rendered":"Slippy maps"},"content":{"rendered":"<p>I&#8217;ve been looking at Javascript, googlemap-like maps. It seems that these are called &#8220;slippy maps&#8221;.<\/p>\n<p>There&#8217;s some useful information of the Openstreetmap wiki <a href=\"http:\/\/wiki.openstreetmap.org\/wiki\/Deploying_your_own_Slippy_Map#OpenStreetMap_tile_servers\">here<\/a>.<\/p>\n<p>They recommend a few Javascript libraries, including LeafletJS and OpenLayers. I tried OpenLayers first, but it&#8217;s pretty big, just to get the examples working from github I&#8217;d need node.js\/JVM etc&#8230;<\/p>\n<p>I decided to play with <a href=\"http:\/\/leafletjs.com\/\">LeafletJS<\/a>, it was a lot quicker to get the examples working!<\/p>\n<p>The LeafletJS demo pulls tile images from URLs that look like this:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nhttps:\/\/c.tiles.mapbox.com\/v3\/examples.map-i875mjb7\/13\/4094\/2724.png\r\n<\/pre>\n<p>I sptent some time trying to figure out how coordinates are translated into the URL. The above representing a tile near [51.505, -0.09] at zoom level 13. The 13 is obvious enough. However the latitude and longitude took some googling.<\/p>\n<p>It seems that pretty much all mapping services use the Spherical Mercator projection (see <a href=\"http:\/\/en.wikipedia.org\/wiki\/Web_Mercator\">wikipedia<\/a> and <a href=\"http:\/\/wiki.openstreetmap.org\/wiki\/Mercator\">openstreetmap<\/a>  ). There are a bunch of tools for making tile sets (particularly from flat images).<\/p>\n<p>Anyway, I wanted to make my dataset manually at first to try things out. I created a directory structure that looks like this:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n.\/13\/4094\/2723.png\r\n.\/13\/4094\/2724.png\r\n.\/13\/4095\/2723.png\r\n.\/13\/4095\/2724.png\r\n.\/13\/4092\/2723.png\r\n.\/13\/4092\/2724.png\r\n.\/13\/4093\/2723.png\r\n.\/13\/4093\/2724.png\r\n<\/pre>\n<p>And used a modified version of the LeafletJS example, telling it to pull data from my server:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n&lt;head&gt;\r\n        &lt;meta charset=&quot;utf-8&quot; \/&gt;\r\n\r\n        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;\r\n\r\n        &lt;link rel=&quot;stylesheet&quot; href=&quot;leaflet.css&quot; \/&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n        &lt;div id=&quot;map&quot; style=&quot;width: 600px; height: 400px&quot;&gt;&lt;\/div&gt;\r\n\r\n        &lt;script src=&quot;leaflet.js&quot;&gt;&lt;\/script&gt;\r\n        &lt;script&gt;\r\n\r\n                var map = L.map('map').setView(&#x5B;51.505, -0.09], 13);\r\n\r\n                L.tileLayer('http:\/\/192.168.0.12\/maptest\/{z}\/{x}\/{y}.png', {\r\n                        maxZoom: 18,\r\n                        attribution: '41j',\r\n                        id: 'example'\r\n                }).addTo(map);\r\n\r\n\r\n                var popup = L.popup();\r\n\r\n                function onMapClick(e) {\r\n                        popup\r\n                                .setLatLng(e.latlng)\r\n                                .setContent(&quot;You clicked the map at &quot; + e.latlng.toString())\r\n                                .openOn(map);\r\n                }\r\n\r\n                map.on('click', onMapClick);\r\n\r\n        &lt;\/script&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n\r\n<\/pre>\n<p>This worked pretty well, and gives me a basis for trying other stuff out.<\/p>\n<h2>Notes<\/h2>\n<p>The C code which performs this conversion replicated from the <a href=\"http:\/\/wiki.openstreetmap.org\/wiki\/Tilenames\">OSM wiki<\/a> is as follows:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &lt;math.h&gt;\r\n#include &lt;iostream&gt;\r\n\r\nusing namespace std;\r\n\r\nint long2tilex(double lon, int z) \r\n{ \r\n\treturn (int)(floor((lon + 180.0) \/ 360.0 * pow(2.0, z))); \r\n}\r\n \r\nint lat2tiley(double lat, int z)\r\n{ \r\n\treturn (int)(floor((1.0 - log( tan(lat * M_PI\/180.0) + 1.0 \/ cos(lat * M_PI\/180.0)) \/ M_PI) \/ 2.0 * pow(2.0, z))); \r\n}\r\n \r\ndouble tilex2long(int x, int z) \r\n{\r\n\treturn x \/ pow(2.0, z) * 360.0 - 180;\r\n}\r\n \r\ndouble tiley2lat(int y, int z) \r\n{\r\n\tdouble n = M_PI - 2.0 * M_PI * y \/ pow(2.0, z);\r\n\treturn 180.0 \/ M_PI * atan(0.5 * (exp(n) - exp(-n)));\r\n}\r\n\r\nint main() {\r\n  cout &lt;&lt; long2tilex(-0.09,13) &lt;&lt; endl;\r\n  cout &lt;&lt; lat2tiley(51.505,13) &lt;&lt; endl;\r\n}\r\n<\/pre>\n<p>Some data sources I&#8217;ve been thinking about look at.<\/p>\n<p>OSM Data:<br \/>\nhttp:\/\/planet.openstreetmap.org\/<\/p>\n<p>Oil GIS Data:<br \/>\nhttps:\/\/www.gov.uk\/oil-and-gas-offshore-maps-and-gis-shapefiles#offshore-gis-data<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been looking at Javascript, googlemap-like maps. It seems that these are called &#8220;slippy maps&#8221;. There&#8217;s some useful information of the Openstreetmap wiki here. They recommend a few Javascript libraries, including LeafletJS and OpenLayers. I tried OpenLayers first, but it&#8217;s pretty big, just to get the examples working from github I&#8217;d need node.js\/JVM etc&#8230; I [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-1497","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1RRoU-o9","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/1497","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/comments?post=1497"}],"version-history":[{"count":5,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/1497\/revisions"}],"predecessor-version":[{"id":2369,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/1497\/revisions\/2369"}],"wp:attachment":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/media?parent=1497"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/categories?post=1497"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/tags?post=1497"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}