Created
June 2, 2016 12:35
-
-
Save yetihehe/5fe63901ca613822ac436dfcb45c4af0 to your computer and use it in GitHub Desktop.
Openstreetmaps url shortening code in erlang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(osm_shortlink.erl). | |
% osm_shortlink.erl - Krzysztof Marciniak - Public Domain | |
% see http://wiki.openstreetmap.org/wiki/Shortlink | |
% https://github.com/openstreetmap/openstreetmap-website/blob/master/lib/short_link.rb | |
% and makeShortCode in | |
% https://github.com/openstreetmap/openstreetmap-website/blob/master/app/assets/javascripts/application.js | |
% based on https://gist.github.com/mdornseif/5652824 by Maximillian Dornseif | |
-export([osm_shortlink/3,osm_shortlink/4]). | |
osm_shortlink(Lat, Lng, Zoom) -> | |
osm_shortlink(Lat, Lng, Zoom, false). | |
% Lat, Lng - position in float, Marker - true or false to show marker on map | |
-spec osm_shortlink(number(), number(), pos_integer(), boolean()) -> binary(). | |
osm_shortlink(Lat, Lng, Zoom, Marker) when Zoom>=0 -> | |
X=trunc((Lng+180) * (1 bsl 32) / 360), | |
Y=trunc((Lat+90) * (1 bsl 32) / 180), | |
<<Code:64>> = interleave_bits(<<X:32>>,<<Y:32>>,<<"">>), | |
% add eight to the zoom level, which approximates an accuracy of | |
% one pixel in a tile. | |
LinkCode=osm_shortlink_code(Code,ceil((Zoom+8)/3.0)-1,[]), | |
% append characters onto the end of the string to represent | |
% partial zoom levels (characters themselves have a granularity | |
% of 3 zoom levels). | |
ZoomRemainder=binary:part(<<"--">>,0,((Zoom+8) rem 3)), | |
case Marker of | |
true -> <<"http://osm.org/go/",LinkCode/binary,ZoomRemainder/binary,"?m">>; | |
false -> <<"http://osm.org/go/",LinkCode/binary,ZoomRemainder/binary>> | |
end. | |
% This could be made much faster with bit twiddling, but it's left as an exercise for readers | |
% Interleaves bits of two equal-length binaries, appending them to last one | |
-spec interleave_bits(binary(), binary(), binary()) -> binary(). | |
interleave_bits(<<"">>,<<"">>,Ret) -> | |
Ret; | |
interleave_bits(<<A1:1,ARest/bits>>,<<B1:1,BRest/bits>>,Ret) -> | |
interleave_bits(ARest,BRest,<<Ret/bits,A1:1,B1:1>>). | |
% makes short link code from interleaved integer. | |
-spec osm_shortlink_code(pos_integer(), integer(), list()) -> binary(). | |
% When Z is below 0, we can return full string | |
osm_shortlink_code(_,-1,Ret) -> | |
list_to_binary(Ret); | |
% Going from Zoom to 0 - erlang optimisation | |
osm_shortlink_code(Code,Z,Ret) -> | |
Digit=(Code bsr (58-6*Z)) band 16#3F, | |
% array of 64 chars to encode 6 bits. this is almost like base64 encoding, but | |
% the symbolic chars are different, as base64's + and / aren't very | |
% URL-friendly. | |
osm_shortlink_code(Code,Z-1,[binary:at(<<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_~">>,Digit)|Ret]). | |
ceil(X) -> | |
T = erlang:trunc(X), | |
case (X - T) of | |
Neg when Neg < 0 -> T; | |
Pos when Pos > 0 -> T + 1; | |
_ -> T | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment