From a5cc2e3ae25a2baa2978dd5697cb3bd002dd85e3 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 27 Sep 2010 14:54:10 -0400 Subject: [PATCH] more accurate marker positioning on map, and a reasonable custom projection --- template.html | 162 ++++++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 70 deletions(-) diff --git a/template.html b/template.html index ef2868f..63ebdb6 100644 --- a/template.html +++ b/template.html @@ -22,6 +22,65 @@ debug: false }; + // our custom projection maps Latitude to Y, and Longitude to X as normal, + // but it maps the range [0.0, 1.0] to [0, tileSize] in both directions + // so it is easier to position markers, etc. based on their position + // (find their position in the lowest-zoom image, and divide by tileSize) + function MCMapProjection() { + this.inverseTileSize = 1.0 / config.tileSize; + } + + MCMapProjection.prototype.fromLatLngToPoint = function(latLng) { + var x = latLng.lng() * config.tileSize; + var y = latLng.lat() * config.tileSize; + return new google.maps.Point(x, y); + }; + + MCMapProjection.prototype.fromPointToLatLng = function(point) { + var lng = point.x * this.inverseTileSize; + var lat = point.y * this.inverseTileSize; + return new google.maps.LatLng(lat, lng); + }; + + // helper to get map LatLng from world coordinates + // takes arguments in X, Y, Z order + // (arguments are *out of order*, because within the function we use + // the axes like the rest of Minecraft Overviewer -- with the Z and Y + // flipped from normal minecraft usage.) + function fromWorldToLatLng(x, z, y) + { + // the width and height of all the highest-zoom tiles combined, inverted + var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom)); + + // This information about where the center column is may change with a different + // drawing implementation -- check it again after any drawing overhauls! + + // point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2) + // so the Y coordinate is at 0.5, and the X is at 0.5 - ((tileSize / 2) / (tileSize * 2^maxZoom)) + // or equivalently, 0.5 - (1 / 2^(maxZoom + 1)) + var lng = 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1)); + var lat = 0.5; + + // the following metrics mimic those in ChunkRenderer.chunk_render in "chunk.py" + + // each block on X axis adds 12px to x and subtracts 6px from y + lng += 12 * x * perPixel; + lat -= 6 * x * perPixel; + + // each block on Y axis adds 12px to x and adds 6px to y + lng += 12 * y * perPixel; + lat += 6 * y * perPixel; + + // each block down along Z adds 12px to y + lat += 12 * (128 - z) * perPixel; + + // add on 12 px to the X coordinate and 18px to the Y to center our point + lng += 12 * perPixel; + lat += 18 * perPixel; + + return new google.maps.LatLng(lat, lng); + } + var MCMapOptions = { getTileUrl: function(tile, zoom) { var url = config.path; @@ -52,6 +111,7 @@ var MCMapType = new google.maps.ImageMapType(MCMapOptions); MCMapType.name = "MC Map"; MCMapType.alt = "Minecraft Map"; + MCMapType.projection = new MCMapProjection(); function CoordMapType() { } @@ -75,61 +135,30 @@ }; var map; - var prot; - + var markersInit = false; - - function convertCoords (x,y,z) { - - var imgx = 0; - var imgy = 0; - - imgx = imgx + (12*x); - imgy = imgy - (6*x); - - imgx = imgx + (12 * y); - imgy = imgy + (6* y); - - imgy = imgy - (12*z); - - // this math is mysterious. i don't fully understand it - // but the idea is to assume that block 0,0,0 in chunk 0,0 - // is drawn in the very middle of the gmap at (192,192) - return [192*Math.pow(2,config.maxZoom)+imgx, 192*Math.pow(2,config.maxZoom)+imgy+768+768]; - } - + function initMarkers() { - if (markersInit) { return; } - - markersInit = true; - - prot = map.getProjection(); - - for (i in markerData) { - var item = markerData[i]; - - var converted = convertCoords(item.x-16, item.z, item.y); - - - var x = converted[0] / Math.pow(2, config.maxZoom); - var y = converted[1] / Math.pow(2, config.maxZoom); - var p = new google.maps.Point(x,y); - var marker = new google.maps.Marker({ -position: prot.fromPointToLatLng(p), -map: map, -title:item.msg -}); - -} - - - -} + if (markersInit) { return; } + + markersInit = true; + for (i in markerData) { + var item = markerData[i]; + + var converted = fromWorldToLatLng(item.x, item.y, item.z); + var marker = new google.maps.Marker({ + position: converted, + map: map, + title: item.msg + }); + } + } + function initialize() { var mapOptions = { zoom: config.defaultZoom, - center: new google.maps.LatLng(-45, 90), + center: new google.maps.LatLng(0.5, 0.5), navigationControl: true, scaleControl: false, mapTypeControl: false, @@ -139,34 +168,27 @@ title:item.msg if(config.debug) { map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(config.tileSize, config.tileSize))); + + google.maps.event.addListener(map, 'click', function(event) { + console.log("latLng; " + event.latLng.lat() + ", " + event.latLng.lng()); + + var pnt = map.getProjection().fromLatLngToPoint(event.latLng); + console.log("point: " + pnt); + + var pxx = pnt.x * config.tileSize * Math.pow(2, config.maxZoom); + var pxy = pnt.y * config.tileSize * Math.pow(2, config.maxZoom); + console.log("pixel: " + pxx + ", " + pxy); + }); } - - // Now attach the coordinate map type to the map's registry map.mapTypes.set('mcmap', MCMapType); // We can now set the map to use the 'coordinate' map type map.setMapTypeId('mcmap'); - - prot = map.getProjection(); - - if (config.debug) - google.maps.event.addListener(map, 'click', function(event) { - console.log("latLng: " + event.latLng.lat() + ", " + event.latLng.lng()); - var pnt = prot.fromLatLngToPoint(event.latLng); - - console.log("point: " + pnt);// - var pxx = pnt.x * Math.pow(2,config.maxZoom); - var pxy = pnt.y * Math.pow(2,config.maxZoom); - console.log("pixel: " + pxx + ", " + pxy); - }); - - google.maps.event.addListener(map, 'projection_changed', function(event) { - initMarkers(); - }); - - + + // initialize the markers + initMarkers(); }