2016-02-17 29 views
2

我試圖在Google地圖上的六邊形網格中顯示地理空間數據。在Google地圖中將數據分爲六邊形網格

爲了做到這一點,給予了六邊形平鋪網格大小X我需要能夠轉換({lat, lng})座標轉換爲包含它們的六邊形網格小塊的({lat, lng})中心。

最後,我希望能夠在一個谷歌地圖這樣的顯示數據:

enter image description here

沒有任何人有任何見解如何做到這一點?

我試着將這個Python六邊形裝箱腳本binner.py移植到Javascript,但它似乎沒有正常工作 - 輸出值與輸入值完全相同。

爲了這個例子,我不在乎在一個位置是否有多個多邊形,我只需要弄清楚如何將它們放入正確的座標中。下面

代碼,(Plunker here!

var map; 
var pointCount = 0; 
var locations = []; 
var gridWidth = 200000; // hex tile size in meters 
var bounds; 

var places = [ 
    [44.13, -69.51], 
    [45.23, -67.42], 
    [46.33, -66.53], 
    [44.43, -65.24], 
    [46.53, -64.15], 
    [44.63, -63.06], 
    [44.73, -62.17], 
    [43.83, -63.28], 
    [44.93, -64.39], 
    [44.13, -65.41], 
    [41.23, -66.52], 
    [44.33, -67.63], 
    [42.43, -68.74], 
    [44.53, -69.65], 
    [40.63, -70.97], 
] 

var SQRT3 = 1.73205080756887729352744634150587236; 

$(document).ready(function(){ 

    bounds = new google.maps.LatLngBounds(); 

    map = new google.maps.Map(document.getElementById("map_canvas"), {center: {lat: 0, lng: 0}, zoom: 2}); 

    // Adding a marker just so we can visualize where the actual data points are. 
    // In the end, we want to see the hex tile that contain them 
    places.forEach(function(place, p){ 

    latlng = new google.maps.LatLng({lat: place[0], lng: place[1]}); 
    marker = new google.maps.Marker({position: latlng, map: map}) 

    // Fitting to bounds so the map is zoomed to the right place 
    bounds.extend(latlng); 
    }); 

    map.fitBounds(bounds); 

    // Now, we draw our hexagons! (or try to) 
    locations = makeBins(places); 

    locations.forEach(function(place, p){ 
    drawHorizontalHexagon(map, place, gridWidth); 
    }) 


}); 


    function drawHorizontalHexagon(map,position,radius){ 
    var coordinates = []; 
    for(var angle= 0;angle < 360; angle+=60) { 
     coordinates.push(google.maps.geometry.spherical.computeOffset(position, radius, angle));  
    } 

    // Construct the polygon. 
    var polygon = new google.maps.Polygon({ 
     paths: coordinates, 
     position: position, 
     strokeColor: '#FF0000', 
     strokeOpacity: 0.8, 
     strokeWeight: 2, 
     fillColor: '#FF0000', 
     fillOpacity: 0.35, 
     geodesic: true 
    }); 
    polygon.setMap(map); 
} 

// Below is my attempt at porting binner.py to Javascript. 
// Source: https://github.com/coryfoo/hexbins/blob/master/hexbin/binner.py 

function distance(x1, y1, x2, y2){ 
    console.log(x1, y1, x2, y2); 
    result = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2))); 
    console.log("Distance: ", result); 
    return result; 
} 

function nearestCenterPoint(value, scale){ 
    div = (value/(scale/2)); 
    mod = value % (scale/2); 

    if(div % 2 == 1){ 
     increment = 1; 
    } else { 
     increment = 0; 
    } 

    rounded = (scale/2) * (div + increment); 

    if(div % 2 === 0){ 
     increment = 1; 
    } else { 
     increment = 0; 
    } 

    rounded_scaled = (scale/2) * (div + increment) 
    result = [rounded, rounded_scaled]; 

    return result; 
} 

function makeBins(data){ 
    bins = []; 

    data.forEach(function(place, p){ 
    x = place[0]; 
    y = place[1]; 

    console.log("Original location:", x, y); 

    px_nearest = nearestCenterPoint(x, gridWidth); 

    py_nearest = nearestCenterPoint(y, gridWidth * SQRT3); 

    z1 = distance(x, y, px_nearest[0], py_nearest[0]); 

    z2 = distance(x, y, px_nearest[1], py_nearest[1]); 

    console.log(z1, z2); 

    if(z1 > z2){ 
     bin = new google.maps.LatLng({lat: px_nearest[0], lng: py_nearest[0]}); 
     console.log("Final location:", px_nearest[0], py_nearest[0]); 
    } else { 
     bin = new google.maps.LatLng({lat: px_nearest[1], lng: py_nearest[1]}); 
     console.log("Final location:", px_nearest[1], py_nearest[1]); 
    } 

    bins.push(bin); 

    }) 
    return bins; 
} 
+0

可能重複([我怎樣才能做一個谷歌地圖API V3六邊形平鋪圖,最好是基於座標?] http://stackoverflow.com/questions/11761738/how-can-i-make-a-google-maps-api-v3-hexagon-tiled-map-preferably-coordinate-bas) – geocodezip

+0

類似的問題,但那個問題(及其答案)討論瞭如何繪製多邊形,當時我更關心如何將數據合併到合適的圖塊中。 – schnauss

+0

重疊六邊形應該做什麼?請在問題本身提供一個[最小,完整,測試和可讀的示例](http://stackoverflow.com/help/mcve)**(一個plunker或jsfiddle是有用的,但不應該被要求理解/回答問題)。 – geocodezip

回答

3

使用google.maps.geometry.poly.containsLocation

for (var i = 0; i < hexgrid.length; i++) { 
    if (google.maps.geometry.poly.containsLocation(place, hexgrid[i])) { 
    if (!hexgrid[i].contains) { 
     hexgrid[i].contains = 0; 
    } 
    hexgrid[i].contains++ 
    } 
} 

基於此相關問題的示例:How can I make a Google Maps API v3 hexagon tiled map, preferably coordinate-based?。每個六邊形中心的白色框中的數字是它所包含的標記的數量。

proof of concept fiddle

代碼片段:

var map = null; 
 
var hexgrid = []; 
 

 
function initMap() { 
 
    var myOptions = { 
 
    zoom: 8, 
 
    center: new google.maps.LatLng(43, -79.5), 
 
    mapTypeControl: true, 
 
    mapTypeControlOptions: { 
 
     style: google.maps.MapTypeControlStyle.DROPDOWN_MENU 
 
    }, 
 
    navigationControl: true, 
 
    mapTypeId: google.maps.MapTypeId.ROADMAP 
 
    } 
 
    map = new google.maps.Map(document.getElementById("map"), 
 
    myOptions); 
 
    createHexGrid(); 
 
    var bounds = new google.maps.LatLngBounds(); 
 
    // Seed our dataset with random locations 
 
    for (var i = 0; i < hexgrid.length; i++) { 
 
    var hexbounds = new google.maps.LatLngBounds(); 
 
    for (var j = 0; j < hexgrid[i].getPath().getLength(); j++) { 
 
     bounds.extend(hexgrid[i].getPath().getAt(j)); 
 
     hexbounds.extend(hexgrid[i].getPath().getAt(j)); 
 
    } 
 
    hexgrid[i].bounds = hexbounds; 
 
    } 
 
    var span = bounds.toSpan(); 
 
    var locations = []; 
 
    for (pointCount = 0; pointCount < 50; pointCount++) { 
 
    place = new google.maps.LatLng(Math.random() * span.lat() + bounds.getSouthWest().lat(), Math.random() * span.lng() + bounds.getSouthWest().lng()); 
 
    bounds.extend(place); 
 
    locations.push(place); 
 
    var mark = new google.maps.Marker({ 
 
     map: map, 
 
     position: place 
 
    }); 
 
    // bin points in hexgrid 
 
    for (var i = 0; i < hexgrid.length; i++) { 
 
     if (google.maps.geometry.poly.containsLocation(place, hexgrid[i])) { 
 
     if (!hexgrid[i].contains) { 
 
      hexgrid[i].contains = 0; 
 
     } 
 
     hexgrid[i].contains++ 
 
     } 
 
    } 
 
    } 
 
    // add labels 
 
    for (var i = 0; i < hexgrid.length; i++) { 
 
    if (typeof hexgrid[i].contains == 'undefined') { 
 
     hexgrid[i].contains = 0; 
 
    } 
 
    var labelText = "<div style='background-color:white'>" + hexgrid[i].contains + "</div>"; 
 

 

 
    var myOptions = { 
 
     content: labelText, 
 
     boxStyle: { 
 
     border: "1px solid black", 
 
     textAlign: "center", 
 
     fontSize: "8pt", 
 
     width: "20px" 
 
     }, 
 
     disableAutoPan: true, 
 
     pixelOffset: new google.maps.Size(-10, 0), 
 
     position: hexgrid[i].bounds.getCenter(), 
 
     closeBoxURL: "", 
 
     isHidden: false, 
 
     pane: "floatPane", 
 
     enableEventPropagation: true 
 
    }; 
 

 
    var ibLabel = new InfoBox(myOptions); 
 
    ibLabel.open(map); 
 
    } 
 

 
} 
 

 
function createHexGrid() { 
 
    // === Hexagonal grid === 
 
    var point = new google.maps.LatLng(42, -78.8); 
 
    map.setCenter(point); 
 
    var hex1 = google.maps.Polygon.RegularPoly(point, 25000, 6, 90, "#000000", 1, 1, "#00ff00", 0.5); 
 
    hex1.setMap(map); 
 
    var d = 2 * 25000 * Math.cos(Math.PI/6); 
 
    hexgrid.push(hex1); 
 
    var hex30 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 30), 25000, 6, 90, "#000000", 1, 1, "#00ffff", 0.5); 
 
    hex30.setMap(map); 
 
    hexgrid.push(hex30); 
 
    var hex90 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 90), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5); 
 
    hex90.setMap(map); 
 
    hexgrid.push(hex90); 
 
    var hex150 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 150), 25000, 6, 90, "#000000", 1, 1, "#00ffff", 0.5); 
 
    hex150.setMap(map); 
 
    hexgrid.push(hex150); 
 
    var hex210 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 210), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5); 
 
    hex210.setMap(map); 
 
    hexgrid.push(hex210); 
 
    hex270 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 270), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5); 
 
    hex270.setMap(map); 
 
    hexgrid.push(hex270); 
 
    var hex330 = google.maps.Polygon.RegularPoly(EOffsetBearing(point, d, 330), 25000, 6, 90, "#000000", 1, 1, "#ffff00", 0.5); 
 
    hex330.setMap(map); 
 
    hexgrid.push(hex330); 
 
    var hex30_2 = google.maps.Polygon.RegularPoly(EOffsetBearing(EOffsetBearing(point, d, 30), d, 90), 25000, 6, 90, "#000000", 1, 1, "#ff0000", 0.5); 
 
    hex30_2.setMap(map); 
 
    hexgrid.push(hex30_2); 
 
    var hex150_2 = google.maps.Polygon.RegularPoly(EOffsetBearing(EOffsetBearing(point, d, 150), d, 90), 25000, 6, 90, "#000000", 1, 1, "#0000ff", 0.5); 
 
    hex150_2.setMap(map); 
 
    hexgrid.push(hex150_2); 
 
    var hex90_2 = google.maps.Polygon.RegularPoly(EOffsetBearing(EOffsetBearing(point, d, 90), d, 90), 25000, 6, 90, "#000000", 1, 1, "#00ff00", 0.5); 
 
    hex90_2.setMap(map); 
 
    hexgrid.push(hex90_2); 
 

 
    // This Javascript is based on code provided by the 
 
    // Community Church Javascript Team 
 
    // http://www.bisphamchurch.org.uk/ 
 
    // http://econym.org.uk/gmap/ 
 

 
    //]]> 
 
} 
 
google.maps.event.addDomListener(window, 'load', initMap); 
 

 
// EShapes.js 
 
// 
 
// Based on an idea, and some lines of code, by "thetoy" 
 
// 
 
// This Javascript is provided by Mike Williams 
 
// Community Church Javascript Team 
 
// http://www.bisphamchurch.org.uk/ 
 
// http://econym.org.uk/gmap/ 
 
// 
 
// This work is licenced under a Creative Commons Licence 
 
// http://creativecommons.org/licenses/by/2.0/uk/ 
 
// 
 
// Version 0.0 04/Apr/2008 Not quite finished yet 
 
// Version 1.0 10/Apr/2008 Initial release 
 
// Version 3.0 12/Oct/2011 Ported to v3 by Lawrence Ross 
 

 
google.maps.Polygon.Shape = function(point, r1, r2, r3, r4, rotation, vertexCount, strokeColour, strokeWeight, Strokepacity, fillColour, fillOpacity, opts, tilt) { 
 
    var rot = -rotation * Math.PI/180; 
 
    var points = []; 
 
    var latConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat() + 0.1, point.lng())) * 10; 
 
    var lngConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat(), point.lng() + 0.1)) * 10; 
 
    var step = (360/vertexCount) || 10; 
 

 
    var flop = -1; 
 
    if (tilt) { 
 
    var I1 = 180/vertexCount; 
 
    } else { 
 
    var I1 = 0; 
 
    } 
 
    for (var i = I1; i <= 360.001 + I1; i += step) { 
 
    var r1a = flop ? r1 : r3; 
 
    var r2a = flop ? r2 : r4; 
 
    flop = -1 - flop; 
 
    var y = r1a * Math.cos(i * Math.PI/180); 
 
    var x = r2a * Math.sin(i * Math.PI/180); 
 
    var lng = (x * Math.cos(rot) - y * Math.sin(rot))/lngConv; 
 
    var lat = (y * Math.cos(rot) + x * Math.sin(rot))/latConv; 
 

 
    points.push(new google.maps.LatLng(point.lat() + lat, point.lng() + lng)); 
 
    } 
 
    return (new google.maps.Polygon({ 
 
    paths: points, 
 
    strokeColor: strokeColour, 
 
    strokeWeight: strokeWeight, 
 
    strokeOpacity: Strokepacity, 
 
    fillColor: fillColour, 
 
    fillOpacity: fillOpacity 
 
    })) 
 
} 
 

 
google.maps.Polygon.RegularPoly = function(point, radius, vertexCount, rotation, strokeColour, strokeWeight, Strokepacity, fillColour, fillOpacity, opts) { 
 
    rotation = rotation || 0; 
 
    var tilt = !(vertexCount & 1); 
 
    return google.maps.Polygon.Shape(point, radius, radius, radius, radius, rotation, vertexCount, strokeColour, strokeWeight, Strokepacity, fillColour, fillOpacity, opts, tilt) 
 
} 
 

 
function EOffsetBearing(point, dist, bearing) { 
 
    var latConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat() + 0.1, point.lng())) * 10; 
 
    var lngConv = google.maps.geometry.spherical.computeDistanceBetween(point, new google.maps.LatLng(point.lat(), point.lng() + 0.1)) * 10; 
 
    var lat = dist * Math.cos(bearing * Math.PI/180)/latConv; 
 
    var lng = dist * Math.sin(bearing * Math.PI/180)/lngConv; 
 
    return new google.maps.LatLng(point.lat() + lat, point.lng() + lng) 
 
}
html, 
 
body, 
 
#map { 
 
    height: 100%; 
 
    width: 100%; 
 
    margin: 0px; 
 
    padding: 0px 
 
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script> 
 
<script src="https://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox.js"></script> 
 
<div id="map"></div>

+0

這是一個有趣的方法!但是如果我不知道箱子的位置怎麼辦? – schnauss

+0

我不知道。你將如何確定垃圾箱的位置?你打算如何製作你的六角網格? – geocodezip

+0

給定一個六角形網格大小X和一個緯度/經度對,我試圖計算最接近那個位置的網格中心點。有了這些信息,我就可以在該位置繪製一個網格大小爲X的六邊形。 – schnauss

相關問題