Skip to content

Instantly share code, notes, and snippets.

@christocracy
Created August 7, 2014 07:20
Show Gist options
  • Save christocracy/934b95e429e4f2086239 to your computer and use it in GitHub Desktop.
Save christocracy/934b95e429e4f2086239 to your computer and use it in GitHub Desktop.
grid_clusterer.rb
module GeoKit
#It is half of the earth circumference in pixels at zoom level 21.
#You can visualize it by thinking of full map. Full map size is 536870912 × 536870912 pixels.
#Center of the map in pixel coordinates is 268435456,268435456 which in latitude and longitude would be 0,0.
PIXEL_OFFSET = 268435456
PIXEL_RADIUS = PIXEL_OFFSET / Math::PI
module Mappable
module ClassMethods
def pixel_distance(from, to, zoom)
Math.sqrt((from[:x]-to[:x])**2 + (from[:y]-to[:y])**2).to_i >> (21-zoom)
end
def cluster(markers, grid_size, zoom)
# Scale grid-size based upon zoom
distance = grid_size - (grid_size/ 21 * zoom / 1.5)
# Once markers' pixel-distance become 4*grid_size, break from the each loop.
threshold = grid_size * 4
clusters = []
while(markers.count > 0) do
marker = markers.shift
cluster = []
markers.each_index do |i|
pd = pixel_distance(marker, markers[i], zoom)
if distance > pd
cluster << markers.slice!(i)
elsif pd > threshold
break
end
end
if cluster.length > 0
count = 0
len = 0
avg_lat = 0
avg_lng = 0
cluster.each do |i|
len += 1
avg_lat += i[:lat]
avg_lng += i[:lng]
count += i[:count]
end
cluster.sort {|i|
i[:count]
}
last = cluster.last
clusters << ["cluster:#{last[:id].to_s}", avg_lat/len, avg_lng/len, count]
else
clusters << [marker[:id], marker[:lat], marker[:lng], marker[:count]]
end
end
clusters
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment