Skip to content

Instantly share code, notes, and snippets.

@jeregrine
Last active August 29, 2015 13:59
Show Gist options
  • Select an option

  • Save jeregrine/10599463 to your computer and use it in GitHub Desktop.

Select an option

Save jeregrine/10599463 to your computer and use it in GitHub Desktop.
Google Maps Polyline Decoder. Based almost entirely off of https://gist.github.com/signed0/2031157#file-gistfile1-py-L55
defmodule Roadcast.Google.Polyline do
use Bitwise
#TODO Work on this code
def decode(polyline) when is_binary(polyline) do
decode(lc <<x>> inbits polyline, do: x - 63)
end
def decode(coll) when is_list(coll) do
coll
|> chunk_after_bit
|> Enum.map(fn(coord_chunk) ->
coord_chunk
|> merge_chunks
|> negate
|> bitshift_and_divide
end)
|> Enum.chunk(2)
|> drop_empty
|> calculate_points
end
defp calculate_points(coll) do
{points, _} = Enum.map_reduce(coll, {0, 0}, fn([x, y], {prev_x, prev_y}) ->
new_x = prev_x + x;
new_y = prev_y + y;
{[Float.round(new_x, 6), Float.round(new_y, 6)], {new_x, new_y}}
end)
points
end
defp merge_chunks(coll) do
Enum.map(coll, &(Bitwise.band(&1, 0x1F)))
|> Enum.with_index
|> Enum.reduce(0, fn({chunk, index}, coord) ->
Bitwise.bor(coord, Bitwise.bsl(chunk, (index * 5)))
end)
end
defp drop_empty(coll) do
Enum.filter(coll, fn([x, y]) -> (x != 0 && y != 0) end)
end
defp negate(item) do
case (Bitwise.band(item, 0x1) != 0) do
true -> Bitwise.bnot(item)
_ -> item
end
end
defp bitshift_and_divide(item) do
Bitwise.bsr(item, 1) / 100000.0
end
def chunk_after_bit(coll) do
chunk_after(coll, &( Bitwise.band(&1, 0x20) == 0 ))
end
#<<_::size(7), 1::size(1)>>
def chunk_after(coll, fun) do
ret = chunk(coll, fun)
case Enum.reverse(ret) do
[[] | tail] -> Enum.reverse(tail)
_ -> ret
end
end
defp chunk(coll, fun) do
Enum.reduce(coll, [[]], fn(item, acc) ->
acc = List.update_at(acc, -1, &(&1 ++ [item]))
if fun.(item), do: acc ++ [[]], else: acc
end)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment