Packages
geo
3.3.4
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/encoder.ex
defmodule Geo.WKB.Encoder do
@moduledoc false
use Bitwise
alias Geo.{
Point,
PointZ,
PointM,
PointZM,
LineString,
LineStringZ,
Polygon,
PolygonZ,
MultiPoint,
MultiPointZ,
MultiLineString,
MultiLineStringZ,
MultiPolygon,
MultiPolygonZ,
GeometryCollection,
Utils
}
alias Geo.WKB.Writer
@doc """
Takes a Geometry and returns a WKB string. The endian decides
what the byte order will be
"""
@spec encode(binary, Geo.endian()) :: {:ok, binary} | {:error, Exception.t()}
def encode(geom, endian \\ :xdr) do
{:ok, encode!(geom, endian)}
rescue
exception ->
{:error, exception}
end
@doc """
Takes a Geometry and returns a WKB string. The endian decides
what the byte order will be
"""
@spec encode!(Geo.geometry(), Geo.endian()) :: binary | no_return
def encode!(geom, endian \\ :xdr) do
writer = Writer.new(endian)
do_encode(geom, writer)
end
defp do_encode(%GeometryCollection{} = geom, writer) do
type =
Utils.type_to_hex(geom, geom.srid != nil)
|> Integer.to_string(16)
|> Utils.pad_left(8)
srid = if geom.srid, do: Integer.to_string(geom.srid, 16) |> Utils.pad_left(8), else: ""
count = Integer.to_string(Enum.count(geom.geometries), 16) |> Utils.pad_left(8)
writer = Writer.write(writer, type)
writer = Writer.write(writer, srid)
writer = Writer.write(writer, count)
coordinates =
Enum.map(geom.geometries, fn x ->
x = %{x | srid: nil}
encode!(x, writer.endian)
end)
coordinates = Enum.join(coordinates)
writer.wkb <> coordinates
end
defp do_encode(geom, writer) do
type =
Utils.type_to_hex(geom, geom.srid != nil)
|> Integer.to_string(16)
|> Utils.pad_left(8)
srid = if geom.srid, do: Integer.to_string(geom.srid, 16) |> Utils.pad_left(8), else: ""
writer = Writer.write(writer, type)
writer = Writer.write(writer, srid)
writer = encode_coordinates(writer, geom)
writer.wkb
end
defp encode_coordinates(writer, %Point{coordinates: {x, y}}) do
x = x |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
y = y |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
writer = Writer.write(writer, x)
Writer.write(writer, y)
end
defp encode_coordinates(writer, %PointZ{coordinates: {x, y, z}}) do
x = x |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
y = y |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
z = z |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
writer
|> Writer.write(x)
|> Writer.write(y)
|> Writer.write(z)
end
defp encode_coordinates(writer, %PointM{coordinates: {x, y, m}}) do
x = x |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
y = y |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
m = m |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
writer
|> Writer.write(x)
|> Writer.write(y)
|> Writer.write(m)
end
defp encode_coordinates(writer, %PointZM{coordinates: {x, y, z, m}}) do
x = x |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
y = y |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
z = z |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
m = m |> Utils.float_to_hex(64) |> Integer.to_string(16) |> Utils.pad_left(16)
writer
|> Writer.write(x)
|> Writer.write(y)
|> Writer.write(z)
|> Writer.write(m)
end
defp encode_coordinates(writer, %LineString{coordinates: coordinates}) do
number_of_points = Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8)
writer = Writer.write(writer, number_of_points)
{_nils, writer} =
Enum.map_reduce(coordinates, writer, fn pair, acc ->
acc = encode_coordinates(acc, %Point{coordinates: pair})
{nil, acc}
end)
writer
end
defp encode_coordinates(writer, %LineStringZ{coordinates: coordinates}) do
number_of_points = Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8)
writer = Writer.write(writer, number_of_points)
{_nils, writer} =
Enum.map_reduce(coordinates, writer, fn point, acc ->
acc = encode_coordinates(acc, %PointZ{coordinates: point})
{nil, acc}
end)
writer
end
defp encode_coordinates(writer, %Polygon{coordinates: coordinates}) do
number_of_lines = Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8)
writer = Writer.write(writer, number_of_lines)
{_nils, writer} =
Enum.map_reduce(coordinates, writer, fn line, acc ->
acc = encode_coordinates(acc, %LineString{coordinates: line})
{nil, acc}
end)
writer
end
defp encode_coordinates(writer, %PolygonZ{coordinates: coordinates}) do
number_of_lines = Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8)
writer = Writer.write(writer, number_of_lines)
{_nils, writer} =
Enum.map_reduce(coordinates, writer, fn line, acc ->
acc = encode_coordinates(acc, %LineStringZ{coordinates: line})
{nil, acc}
end)
writer
end
defp encode_coordinates(writer, %MultiPoint{coordinates: coordinates}) do
writer = Writer.write(writer, Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8))
geoms =
Enum.map(coordinates, fn geom ->
encode!(%Point{coordinates: geom}, writer.endian)
end)
|> Enum.join()
Writer.write_no_endian(writer, geoms)
end
defp encode_coordinates(writer, %MultiPointZ{coordinates: coordinates}) do
writer = Writer.write(writer, Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8))
geoms =
Enum.map(coordinates, fn geom ->
encode!(%PointZ{coordinates: geom}, writer.endian)
end)
|> Enum.join()
Writer.write_no_endian(writer, geoms)
end
defp encode_coordinates(writer, %MultiLineString{coordinates: coordinates}) do
writer = Writer.write(writer, Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8))
geoms =
Enum.map(coordinates, fn geom ->
encode!(%LineString{coordinates: geom}, writer.endian)
end)
|> Enum.join()
Writer.write_no_endian(writer, geoms)
end
defp encode_coordinates(writer, %MultiLineStringZ{coordinates: coordinates}) do
writer = Writer.write(writer, Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8))
geoms =
Enum.map(coordinates, fn geom ->
encode!(%LineStringZ{coordinates: geom}, writer.endian)
end)
|> Enum.join()
Writer.write_no_endian(writer, geoms)
end
defp encode_coordinates(writer, %MultiPolygon{coordinates: coordinates}) do
writer = Writer.write(writer, Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8))
geoms =
Enum.map(coordinates, fn geom ->
encode!(%Polygon{coordinates: geom}, writer.endian)
end)
|> Enum.join()
Writer.write_no_endian(writer, geoms)
end
defp encode_coordinates(writer, %MultiPolygonZ{coordinates: coordinates}) do
writer = Writer.write(writer, Integer.to_string(length(coordinates), 16) |> Utils.pad_left(8))
geoms =
Enum.map(coordinates, fn geom ->
encode!(%PolygonZ{coordinates: geom}, writer.endian)
end)
|> Enum.join()
Writer.write_no_endian(writer, geoms)
end
end