Packages
geo
4.1.0
4.1.0
4.0.1
4.0.0
3.6.0
3.5.1
3.5.0
3.4.3
3.4.2
3.4.1
3.4.0
3.3.8
3.3.7
3.3.5
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.0
3.1.0
3.0.0
2.1.0
2.0.0
1.5.0
1.4.1
1.4.0
1.3.1
1.3.0
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.18.0
0.17.0
0.16.1
0.16.0
0.15.2
0.15.1
0.15.0
0.14.0
0.13.0
0.12.0
0.11.2
0.11.1
0.11.0
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.2
0.7.1
0.6.1
0.5.1
Encodes and decodes WKB, WKT, and GeoJSON formats.
Current section
Files
Jump to
Current section
Files
lib/geo/wkb/decoder.ex
defmodule Geo.WKB.Decoder do
@moduledoc false
# these numbers can be referenced against postgis.git/doc/ZMSgeoms.txt
@point 0x00_00_00_01
@point_m 0x40_00_00_01
@point_z 0x80_00_00_01
@point_zm 0xC0_00_00_01
@line_string 0x00_00_00_02
@line_string_m 0x40_00_00_02
@line_string_z 0x80_00_00_02
@line_string_zm 0xC0_00_00_02
@polygon 0x00_00_00_03
@polygon_z 0x80_00_00_03
@multi_point 0x00_00_00_04
@multi_point_m 0x40_00_00_04
@multi_point_z 0x80_00_00_04
@multi_line_string 0x00_00_00_05
@multi_line_string_z 0x80_00_00_05
@multi_line_string_zm 0xC0_00_00_05
@multi_polygon 0x00_00_00_06
@multi_polygon_z 0x80_00_00_06
@geometry_collection 0x00_00_00_07
@wkbsridflag 0x20000000
import Bitwise
alias Geo.{
Point,
PointZ,
PointM,
PointZM,
LineString,
LineStringM,
LineStringZ,
LineStringZM,
Polygon,
PolygonZ,
GeometryCollection,
MultiPoint,
MultiPointM,
MultiPointZ,
MultiLineString,
MultiLineStringZ,
MultiLineStringZM,
MultiPolygon,
MultiPolygonZ
}
defguardp has_srid(type) when (type &&& @wkbsridflag) == @wkbsridflag
defp remove_srid(type), do: type - @wkbsridflag
for {endian, modifier} <- [{1, quote(do: little)}, {0, quote(do: big)}] do
def decode(
<<unquote(endian)::unquote(modifier)-integer-unsigned, type::32-unquote(modifier),
srid::32-unquote(modifier), rest::bits>>
)
when has_srid(type) do
do_decode(remove_srid(type), rest, srid, unquote(endian))
end
def decode(
<<unquote(endian)::unquote(modifier)-integer-unsigned, type::32-unquote(modifier),
rest::bits>>
) do
do_decode(type, rest, nil, unquote(endian))
end
defp do_decode(
@point,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64, rest::bits>>,
srid,
unquote(endian)
) do
{%Point{coordinates: {x, y}, srid: srid}, rest}
end
defp do_decode(
@point_m,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64,
m::unquote(modifier)-float-64, rest::bits>>,
srid,
unquote(endian)
) do
{%PointM{coordinates: {x, y, m}, srid: srid}, rest}
end
defp do_decode(
@point_z,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64, rest::bits>>,
srid,
unquote(endian)
) do
{%PointZ{coordinates: {x, y, z}, srid: srid}, rest}
end
defp do_decode(
@point_zm,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64, m::unquote(modifier)-float-64, rest::bits>>,
srid,
unquote(endian)
) do
{%PointZM{coordinates: {x, y, z, m}, srid: srid}, rest}
end
defp do_decode(
@line_string,
<<0::unquote(modifier)-32, "">>,
srid,
unquote(endian)
) do
{%Geo.LineString{
coordinates: [],
properties: %{},
srid: srid
}, ""}
end
defp do_decode(
@line_string,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(1..count, rest, fn _,
<<x::unquote(modifier)-float-64,
y::unquote(modifier)-float-64, rest::bits>> ->
{%Point{coordinates: coordinates}, _rest} =
do_decode(
@point,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64>>,
nil,
unquote(endian)
)
{coordinates, rest}
end)
{%LineString{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@line_string_m,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(1..count, rest, fn _,
<<x::unquote(modifier)-float-64,
y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64, rest::bits>> ->
{%PointM{coordinates: coordinates}, _rest} =
do_decode(
@point_m,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64>>,
nil,
unquote(endian)
)
{coordinates, rest}
end)
{%LineStringM{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@line_string_z,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(1..count, rest, fn _,
<<x::unquote(modifier)-float-64,
y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64, rest::bits>> ->
{%PointZ{coordinates: coordinates}, _rest} =
do_decode(
@point_z,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64>>,
nil,
unquote(endian)
)
{coordinates, rest}
end)
{%LineStringZ{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@line_string_zm,
<<0::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
),
do: {%LineStringZM{coordinates: [], srid: srid}, rest}
defp do_decode(
@line_string_zm,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(1..count, rest, fn _,
<<x::unquote(modifier)-float-64,
y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64,
m::unquote(modifier)-float-64, rest::bits>> ->
{%PointZM{coordinates: coordinates}, _rest} =
do_decode(
@point_zm,
<<x::unquote(modifier)-float-64, y::unquote(modifier)-float-64,
z::unquote(modifier)-float-64, m::unquote(modifier)-float-64>>,
nil,
unquote(endian)
)
{coordinates, rest}
end)
{%LineStringZM{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@polygon,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%LineString{coordinates: coordinates}, rest} =
do_decode(
@line_string,
rest,
nil,
unquote(endian)
)
{coordinates, rest}
end)
{%Polygon{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@polygon_z,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%LineStringZ{coordinates: coordinates}, rest} =
do_decode(
@line_string_z,
rest,
nil,
unquote(endian)
)
{coordinates, rest}
end)
{%PolygonZ{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_point,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%Point{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiPoint{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_point_m,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%PointM{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiPointM{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_point_z,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%PointZ{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiPointZ{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_line_string,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%LineString{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiLineString{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_line_string_z,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%LineStringZ{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiLineStringZ{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_line_string_zm,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%LineStringZM{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiLineStringZM{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_polygon,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%Polygon{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiPolygon{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@multi_polygon_z,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{coordinates, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
{%PolygonZ{coordinates: coordinates}, rest} = decode(rest)
{coordinates, rest}
end)
{%MultiPolygonZ{coordinates: coordinates, srid: srid}, rest}
end
defp do_decode(
@geometry_collection,
<<count::unquote(modifier)-32, rest::bits>>,
srid,
unquote(endian)
) do
{geometries, rest} =
Enum.map_reduce(List.duplicate(1, count), rest, fn _, <<rest::bits>> ->
decode(rest)
end)
geometries = Enum.map(geometries, fn geom -> %{geom | srid: srid} end)
{%GeometryCollection{geometries: geometries, srid: srid}, rest}
end
end
defp do_decode(
@point,
<<0, 0, 0, 0, 0, 0, 248, 127, 0, 0, 0, 0, 0, 0, 248, 127, rest::bits>>,
srid,
1
) do
{%Point{coordinates: nil, srid: srid}, rest}
end
defp do_decode(
@point,
binary,
srid,
0
) do
little_binary =
binary
|> :binary.decode_unsigned(:big)
|> :binary.encode_unsigned(:little)
do_decode(@point, little_binary, srid, 1)
end
end