Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 43 additions & 29 deletions lib/geo/wkt/decoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,75 +53,84 @@ defmodule Geo.WKT.Decoder do
end

defp do_decode("POINT ZM" <> coordinates, srid) do
%PointZM{coordinates: create_point(coordinates), srid: srid}
%PointZM{coordinates: create_coordinates(coordinates, &create_point/1), srid: srid}
end

defp do_decode("POINT Z" <> coordinates, srid) do
%PointZ{coordinates: create_point(coordinates), srid: srid}
%PointZ{coordinates: create_coordinates(coordinates, &create_point/1), srid: srid}
end

defp do_decode("POINT M" <> coordinates, srid) do
%PointM{coordinates: create_point(coordinates), srid: srid}
%PointM{coordinates: create_coordinates(coordinates, &create_point/1), srid: srid}
end

defp do_decode("POINT" <> coordinates, srid) do
%Point{coordinates: create_point(coordinates), srid: srid}
%Point{coordinates: create_coordinates(coordinates, &create_point/1), srid: srid}
end

defp do_decode("LINESTRINGM" <> coordinates, srid) do
%LineStringM{coordinates: create_line_string(coordinates), srid: srid}
%LineStringM{coordinates: create_coordinates(coordinates, &create_line_string/1), srid: srid}
end

defp do_decode("LINESTRINGZM" <> coordinates, srid) do
%LineStringZM{coordinates: create_line_string(coordinates), srid: srid}
%LineStringZM{coordinates: create_coordinates(coordinates, &create_line_string/1), srid: srid}
end

defp do_decode("LINESTRINGZ" <> coordinates, srid) do
%LineStringZ{coordinates: create_line_string(coordinates), srid: srid}
%LineStringZ{coordinates: create_coordinates(coordinates, &create_line_string/1), srid: srid}
end

defp do_decode("LINESTRING" <> coordinates, srid) do
%LineString{coordinates: create_line_string(coordinates), srid: srid}
%LineString{coordinates: create_coordinates(coordinates, &create_line_string/1), srid: srid}
end

defp do_decode("POLYGONZ" <> coordinates, srid) do
%PolygonZ{coordinates: create_polygon(coordinates), srid: srid}
%PolygonZ{coordinates: create_coordinates(coordinates, &create_polygon/1), srid: srid}
end

defp do_decode("POLYGON" <> coordinates, srid) do
%Polygon{coordinates: create_polygon(coordinates), srid: srid}
%Polygon{coordinates: create_coordinates(coordinates, &create_polygon/1), srid: srid}
end

defp do_decode("MULTIPOINTM" <> coordinates, srid) do
%MultiPointM{coordinates: create_line_string(coordinates), srid: srid}
%MultiPointM{coordinates: create_coordinates(coordinates, &create_line_string/1), srid: srid}
end

defp do_decode("MULTIPOINTZ" <> coordinates, srid) do
%MultiPointZ{coordinates: create_line_string(coordinates), srid: srid}
%MultiPointZ{coordinates: create_coordinates(coordinates, &create_line_string/1), srid: srid}
end

defp do_decode("MULTIPOINT" <> coordinates, srid) do
%MultiPoint{coordinates: create_line_string(coordinates), srid: srid}
%MultiPoint{coordinates: create_coordinates(coordinates, &create_line_string/1), srid: srid}
end

defp do_decode("MULTILINESTRINGZM" <> coordinates, srid) do
%MultiLineStringZM{coordinates: create_polygon(coordinates), srid: srid}
%MultiLineStringZM{
coordinates: create_coordinates(coordinates, &create_polygon/1),
srid: srid
}
end

defp do_decode("MULTILINESTRINGZ" <> coordinates, srid) do
%MultiLineStringZ{coordinates: create_polygon(coordinates), srid: srid}
%MultiLineStringZ{coordinates: create_coordinates(coordinates, &create_polygon/1), srid: srid}
end

defp do_decode("MULTILINESTRING" <> coordinates, srid) do
%MultiLineString{coordinates: create_polygon(coordinates), srid: srid}
%MultiLineString{coordinates: create_coordinates(coordinates, &create_polygon/1), srid: srid}
end

defp do_decode("MULTIPOLYGONZ" <> coordinates, srid) do
%MultiPolygonZ{coordinates: create_multi_polygon(coordinates), srid: srid}
%MultiPolygonZ{
coordinates: create_coordinates(coordinates, &create_multi_polygon/1),
srid: srid
}
end

defp do_decode("MULTIPOLYGON" <> coordinates, srid) do
%MultiPolygon{coordinates: create_multi_polygon(coordinates), srid: srid}
%MultiPolygon{
coordinates: create_coordinates(coordinates, &create_multi_polygon/1),
srid: srid
}
end

defp do_decode("GEOMETRYCOLLECTION" <> coordinates, srid) do
Expand All @@ -141,39 +150,44 @@ defmodule Geo.WKT.Decoder do
%GeometryCollection{geometries: geometries, srid: srid}
end

defp create_coordinates(coordinates, cont) do
bare =
coordinates
|> String.trim()
|> remove_outer_parenthesis()

case bare do
"" -> nil
"EMPTY" -> nil
coordinates -> cont.(coordinates)
end
end

defp create_point(coordinates) do
coordinates
|> String.trim()
|> remove_outer_parenthesis
|> String.split()
|> Enum.map(fn x -> binary_to_number(x) end)
|> List.to_tuple()
end

defp create_line_string(coordinates) do
coordinates
|> String.trim()
|> remove_outer_parenthesis
|> String.split(",")
|> Enum.map(&create_point(&1))
|> Enum.map(fn c -> create_coordinates(c, &create_point/1) end)
end

defp create_polygon(coordinates) do
coordinates
|> String.trim()
|> remove_outer_parenthesis
|> String.split(~r{\), *\(})
|> Enum.map(&repair_str(&1, "(", ")"))
|> Enum.map(&create_line_string(&1))
|> Enum.map(fn c -> create_coordinates(c, &create_line_string/1) end)
end

defp create_multi_polygon(coordinates) do
coordinates
|> String.trim()
|> remove_outer_parenthesis
|> String.split(~r{\)\), *\(\(})
|> Enum.map(&repair_str(&1, "((", "))"))
|> Enum.map(&create_polygon(&1))
|> Enum.map(fn c -> create_coordinates(c, &create_polygon/1) end)
end

defp binary_to_number(binary) do
Expand Down
14 changes: 14 additions & 0 deletions lib/geo/wkt/encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ defmodule Geo.WKT.Encoder do
get_srid_binary(geom.srid) <> do_encode(geom)
end

defp do_encode_empty(%x{}) do
typename =
x
|> Module.split()
|> Enum.at(-1)
|> to_string()
|> String.upcase()

"#{typename} EMPTY"
end

defp do_encode(%{coordinates: nil} = geometry), do: do_encode_empty(geometry)
defp do_encode(%{coordinates: []} = geometry), do: do_encode_empty(geometry)

defp do_encode(%Point{coordinates: {x, y}}) do
"POINT(#{x} #{y})"
end
Expand Down
22 changes: 22 additions & 0 deletions test/geo/wkt_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ defmodule Geo.WKT.Test do
use ExUnit.Case, async: false
use ExUnitProperties

test "Encodes nil coordinate geometries as EMPTY" do
geom = %Geo.Point{coordinates: nil}
assert(Geo.WKT.encode!(geom) == "POINT EMPTY")

geom = %Geo.Polygon{coordinates: nil}
assert(Geo.WKT.encode!(geom) == "POLYGON EMPTY")

geom = %Geo.Polygon{coordinates: []}
assert(Geo.WKT.encode!(geom) == "POLYGON EMPTY")

geom = %Geo.LineStringZM{coordinates: nil}
assert(Geo.WKT.encode!(geom) == "LINESTRINGZM EMPTY")
end

test "Encode Point to WKT" do
geom = %Geo.Point{coordinates: {30, -90}}
assert(Geo.WKT.encode!(geom) == "POINT(30 -90)")
Expand Down Expand Up @@ -53,6 +67,14 @@ defmodule Geo.WKT.Test do
assert(Geo.WKT.encode!(geom) == "LINESTRING(30 10,10 30,40 40)")
end

test "Decode WKT to empty Linestring" do
linestring = Geo.WKT.decode!("LINESTRING EMPTY")
assert(linestring.coordinates == nil)

point = Geo.WKT.decode!("POINT EMPTY")
assert(point.coordinates == nil)
end

test "Decode WKT to Linestring" do
geom = Geo.WKT.decode!("LINESTRING(30 10,10 30,40 40)")
assert(geom.coordinates == [{30, 10}, {10, 30}, {40, 40}])
Expand Down