Last active
August 29, 2015 13:59
-
-
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
This file contains hidden or 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
| 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