# This script generates modules and tests for geometries. The ZM version of the # geometries is used as a template. # # The file `lib/geometry/point_zm.ex`: # - `lib/geometry/point_z.ex` # - `lib/geometry/point_m.ex` # - `lib/geometry/point.ex` # # # A note for contributors, interested readers or a future me. # # There are several ways to create the modules generated by this script. It is # possible to create all modules at compile-time. In some other modules, this # approach is in use. Another method could be the use of EEx. # # I have chosen the present way to keep developing the "*ZM" modules easier and # the code readable. As a disadvantage, we get this unelegant script. # As mentioned above, in some modules, code is created at compile-time. So we # have two approaches to create code. These approaches should not be mixed in # one module. defmodule GenFromZM do @lib_path "lib/geometry" @test_path "test/geometry" @geometries [ "Point", "LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon", "GeometryCollection" ] @geometries_m Enum.map(@geometries, fn geometry -> "#{geometry}M" end) @geometries_z Enum.map(@geometries, fn geometry -> "#{geometry}Z" end) @geometries_zm Enum.map(@geometries, fn geometry -> "#{geometry}ZM" end) @types [:xy, :xym, :xyz] def main do info("Generate geometry modules/tests") Enum.each(@geometries, &generate/1) end defp generate(geometry) do if !check_lib!(geometry) do code = read_lib!(geometry) Enum.each(@types, fn type -> write_lib!(geometry, type, gen(code, type)) end) end if !check_test!(geometry) do test_code = read_test!(geometry) Enum.each(@types, fn type -> write_test!(geometry, type, gen_test(test_code, type)) end) end end # returns true if the template (zm) is older as all the generated files defp check_lib!(geometry) do src_time = @lib_path |> Path.join("#{Macro.underscore(geometry)}_zm.ex") |> change_time() Enum.all?(@types, fn type -> filename = "#{filename(geometry)}#{filename_extension(type)}.ex" dest_time = @lib_path |> Path.join(filename) |> change_time() src_time < dest_time end) end # returns true if the template (zm) is older as all the generated files defp check_test!(geometry) do src_time = @test_path |> Path.join("#{Macro.underscore(geometry)}_zm_test.exs") |> change_time() Enum.all?(@types, fn type -> filename = "#{filename(geometry)}#{filename_extension(type)}_test.exs" dest_time = @test_path |> Path.join(filename) |> change_time() src_time < dest_time end) end defp change_time(file) do case File.stat(file, time: :posix) do {:ok, %File.Stat{ctime: time}} -> time _error -> 0 end end defp read_lib!(geometry) do @lib_path |> Path.join("#{Macro.underscore(geometry)}_zm.ex") |> File.read!() end defp read_test!(geometry) do @test_path |> Path.join("#{Macro.underscore(geometry)}_zm_test.exs") |> File.read!() end defp write_lib!(geometry, type, code) do filename = "#{filename(geometry)}#{filename_extension(type)}.ex" file = Path.join(@lib_path, filename) info("Write #{file}") File.write!(file, code) end defp write_test!(geometry, type, code) do filename = "#{filename(geometry)}#{filename_extension(type)}_test.exs" file = Path.join(@test_path, filename) info("Write #{file}") File.write!(file, code) end defp filename(geometry), do: Macro.underscore(geometry) defp filename_extension(type) do case type do :xy -> "" :xym -> "_m" :xyz -> "_z" end end defp gen(code, type) do code |> replace(geometries(type)) |> replace(comment(code, type)) |> replace(args(code, type)) |> replace(lists(code, type)) |> replace(props(code, type)) |> replace(tuples(code, type)) |> replace(wkt_coordinates(code, type)) |> replace(wkt_tag(type)) |> replace(point_test(type)) |> replace(point(type)) |> replace(geometry_collection(type)) |> replace(wkb_code(type)) |> replace(hint(:code)) end defp gen_test(code, type) do code |> replace(geometries(type)) |> replace(args(code, type)) |> replace(lists(code, type)) |> replace(props(code, type)) |> replace(tuples(code, type)) |> replace(wkt_coordinates(code, type)) |> replace(wkt_tag(type)) |> replace(hint(:test)) |> replace(point_test(type)) |> replace(point(type)) |> replace(line_string_test(type)) |> replace(polygon_test(type)) |> replace(multi_point_test(type)) |> replace(multi_line_string_test(type)) |> replace(multi_polygon_test(type)) |> replace(geometry_collection_test(type)) end defp geometries(type) do new = case type do :xy -> @geometries :xyz -> @geometries_z :xym -> @geometries_m end {@geometries_zm, new} end defp wkt_tag(type) do new = case type do :xy -> "" :xyz -> " Z" :xym -> " M" end {" ZM", new} end defp hint(:code) do {""" @behaviour Geometry """, """ # This file is auto-generated by `mix geometry.gen`. # The ZM version of this file is used as a template. @behaviour Geometry """} end defp hint(:test) do {""" use ExUnit.Case\ """, """ # This file is auto-generated by `mix geometry.gen`. # The ZM version of this file is used as a template. use ExUnit.Case\ """} end defp point(type) do replacements(type) |> replacements( xyzm: "fn [x, _y, _z, _m] -> x end", xyz: "fn [x, _y, _z] -> x end", xym: "fn [x, _y, _m] -> x end", xy: "fn [x, _y] -> x end" ) |> replacements( xyzm: "new(number(), number(), number(), number())", xyz: "new(number(), number(), number())", xym: "new(number(), number(), number())", xy: "new(number(), number())" ) |> replacements( xyzm: "defstruct [:x, :y, :z, :m]", xyz: "defstruct [:x, :y, :z]", xym: "defstruct [:x, :y, :m]", xy: "defstruct [:x, :y]" ) |> replacements( xyzm: "{x: Geometry.x(), y: Geometry.y(), z: Geometry.y(), z: Geometry.m()}", xy: "{x: Geometry.x(), y: Geometry.y()}", xyz: "{x: Geometry.x(), y: Geometry.y(), z: Geometry.z()}", xym: "{x: Geometry.x(), y: Geometry.y(), m: Geometry.m()}" ) |> replacements( xyzm: "[nil, nil, nil, nil]", xyz: "[nil, nil, nil]", xym: "[nil, nil, nil]", xy: "[nil, nil]" ) |> replacements( xyzm: "x, y, z, m", xy: "x, y", xyz: "x, y, z", xym: "x, y, m" ) |> replacements( xyzm: "Geometry.x(), Geometry.y(), Geometry.z(), Geometry.m()", xy: "Geometry.x(), Geometry.y()", xyz: "Geometry.x(), Geometry.y(), Geometry.z()", xym: "Geometry.x(), Geometry.y(), Geometry.m()" ) |> replacements( xyzm: "{x: x, y: y, z: z, m: m}", xy: "{x: x, y: y}", xyz: "{x: x, y: y, z: z}", xym: "{x: x, y: y, m: m}" ) |> replacements( xyzm: "`x`, `y`, `z`, and `m`", xy: "`x` and `y`", xyz: "`x`, `y`, and `z`", xym: "`x`, `y`, and `m`" ) |> replacements( xyzm: ~S""" to_wkt_number(x)::binary(), @blank, to_wkt_number(y)::binary(), @blank, to_wkt_number(z)::binary(), @blank, to_wkt_number(m)::binary() """, xyz: ~S""" to_wkt_number(x)::binary(), @blank, to_wkt_number(y)::binary(), @blank, to_wkt_number(z)::binary() """, xym: ~S""" to_wkt_number(x)::binary(), @blank, to_wkt_number(y)::binary(), @blank, to_wkt_number(m)::binary() """, xy: ~S""" to_wkt_number(x)::binary(), @blank, to_wkt_number(y)::binary() """ ) |> replacements( xyzm: """ 7FF8000000000000\ 7FF8000000000000\ 7FF8000000000000\ 7FF8000000000000\ """, xy: """ 7FF8000000000000\ 7FF8000000000000\ """, xyz: """ 7FF8000000000000\ 7FF8000000000000\ 7FF8000000000000\ """, xym: """ 7FF8000000000000\ 7FF8000000000000\ 7FF8000000000000\ """ ) |> replacements( xyzm: """ 000000000000F87F\ 000000000000F87F\ 000000000000F87F\ 000000000000F87F\ """, xy: """ 000000000000F87F\ 000000000000F87F\ """, xyz: """ 000000000000F87F\ 000000000000F87F\ 000000000000F87F\ """, xym: """ 000000000000F87F\ 000000000000F87F\ 000000000000F87F\ """ ) |> replacements( xyzm: ~S""" to_wkb_number(x, endian, mode)::binary(), to_wkb_number(y, endian, mode)::binary(), to_wkb_number(z, endian, mode)::binary(), to_wkb_number(m, endian, mode)::binary() """, xy: ~S""" to_wkb_number(x, endian, mode)::binary(), to_wkb_number(y, endian, mode)::binary() """, xym: ~S""" to_wkb_number(x, endian, mode)::binary(), to_wkb_number(y, endian, mode)::binary(), to_wkb_number(m, endian, mode)::binary() """, xyz: ~S""" to_wkb_number(x, endian, mode)::binary(), to_wkb_number(y, endian, mode)::binary(), to_wkb_number(z, endian, mode)::binary() """ ) |> replacements() end defp comment(code, type) do case Regex.run(~r/3D\s(.*)\swith a measurement/m, code) do [old, name] -> new = case type do :xy -> "2D #{name}" :xym -> "2D #{name} with a measurement" :xyz -> "3D #{name}" end {old, new} _not_found -> :skip end end defp args(code) do regex = ~r/\( ([-.0-9]+),\s ([-.0-9]+),\s ([-.0-9]+),\s ([-.0-9]+) \)/mx Regex.scan(regex, code) end defp lists(code) do regex = ~r/\[ ([-.0-9]+),\s ([-.0-9]+),\s ([-.0-9]+),\s ([-.0-9]+) \]/mx Regex.scan(regex, code) end defp props(code) do regex = ~r/\{ x:\s([-.0-9]+),\s y:\s([-.0-9]+),\s z:\s([-.0-9]+),\s m:\s([-.0-9]+) \}/mx Regex.scan(regex, code) end defp tuples(code) do regex = ~r/\{ ([-.0-9]+),\s ([-.0-9]+),\s ([-.0-9]+),\s ([-.0-9]+) \}/mx Regex.scan(regex, code) end defp wkt_coordinates(code) do regex = ~r/([-.0-9]+)\s([-.0-9]+)\s([-.0-9]+)\s([-.0-9]+)/m Regex.scan(regex, code) end defp args(code, :xy) do code |> args() |> Enum.map(fn [pattern, x, y | _] -> [pattern, "(#{x}, #{y})"] end) |> unzip() end defp args(code, :xyz) do code |> args() |> Enum.map(fn [pattern, x, y, z, _] -> [pattern, "(#{x}, #{y}, #{z})"] end) |> unzip() end defp args(code, :xym) do code |> args() |> Enum.map(fn [pattern, x, y, _, m] -> [pattern, "(#{x}, #{y}, #{m})"] end) |> unzip() end defp lists(code, :xy) do code |> lists() |> Enum.map(fn [pattern, x, y | _] -> [pattern, "[#{x}, #{y}]"] end) |> unzip() end defp lists(code, :xyz) do code |> lists() |> Enum.map(fn [pattern, x, y, z, _] -> [pattern, "[#{x}, #{y}, #{z}]"] end) |> unzip() end defp lists(code, :xym) do code |> lists() |> Enum.map(fn [pattern, x, y, _, m] -> [pattern, "[#{x}, #{y}, #{m}]"] end) |> unzip() end defp props(code, :xy) do code |> props() |> Enum.map(fn [pattern, x, y | _] -> [pattern, "{x: #{x}, y: #{y}}"] end) |> unzip() end defp props(code, :xyz) do code |> props() |> Enum.map(fn [pattern, x, y, z, _] -> [pattern, "{x: #{x}, y: #{y}, z: #{z}}"] end) |> unzip() end defp props(code, :xym) do code |> props() |> Enum.map(fn [pattern, x, y, _, m] -> [pattern, "{x: #{x}, y: #{y}, m: #{m}}"] end) |> unzip() end defp tuples(code, :xy) do code |> tuples() |> Enum.map(fn [pattern, x, y | _] -> [pattern, "{#{x}, #{y}}"] end) |> unzip() end defp tuples(code, :xyz) do code |> tuples() |> Enum.map(fn [pattern, x, y, z, _] -> [pattern, "{#{x}, #{y}, #{z}}"] end) |> unzip() end defp tuples(code, :xym) do code |> tuples() |> Enum.map(fn [pattern, x, y, _, m] -> [pattern, "{#{x}, #{y}, #{m}}"] end) |> unzip() end defp wkt_coordinates(code, :xy) do code |> wkt_coordinates() |> Enum.map(fn [pattern, x, y | _] -> [pattern, "#{x} #{y}"] end) |> unzip() end defp wkt_coordinates(code, :xyz) do code |> wkt_coordinates() |> Enum.map(fn [pattern, x, y, z, _] -> [pattern, "#{x} #{y} #{z}"] end) |> unzip() end defp wkt_coordinates(code, :xym) do code |> wkt_coordinates() |> Enum.map(fn [pattern, x, y, _, m] -> [pattern, "#{x} #{y} #{m}"] end) |> unzip() end defp point_test(type) do replacements(type) |> replacements( xyzm: "01010000C0000000000000F87F000000000000F87F000000000000F87F000000000000F87F", xyz: "0101000080000000000000F87F000000000000F87F000000000000F87F", xym: "0101000040000000000000F87F000000000000F87F000000000000F87F", xy: "0101000000000000000000F87F000000000000F87F" ) |> replacements( xyzm: "00C00000013FF199999999999A400199999999999A400A666666666666401199999999999A", xyz: "00800000013FF199999999999A400199999999999A400A666666666666", xym: "00400000013FF199999999999A400199999999999A401199999999999A", xy: "00000000013FF199999999999A400199999999999A" ) |> replacements( xyzm: "01010000C09A9999999999F13F9A999999999901406666666666660A409A99999999991140", xyz: "01010000809A9999999999F13F9A999999999901406666666666660A40", xym: "01010000409A9999999999F13F9A999999999901409A99999999991140", xy: "01010000009A9999999999F13F9A99999999990140" ) |> replacements( xyzm: "00C00000017FF80000000000007FF80000000000007FF80000000000007FF8000000000000", xyz: "00800000017FF80000000000007FF80000000000007FF8000000000000", xym: "00400000017FF80000000000007FF80000000000007FF8000000000000", xy: "00000000017FF80000000000007FF8000000000000" ) |> replacements( xyzm: "00E0000001000012673FF199999999999A400199999999999A400A666666666666401199999999999A", xyz: "00A0000001000012673FF199999999999A400199999999999A400A666666666666", xym: "0060000001000012673FF199999999999A400199999999999A401199999999999A", xy: "0020000001000012673FF199999999999A400199999999999A" ) |> replacements( xyzm: "00E00000010000014D3FF199999999999A400199999999999A400A666666666666401199999999999A", xyz: "00A00000010000014D3FF199999999999A400199999999999A400A666666666666", xym: "00600000010000014D3FF199999999999A400199999999999A401199999999999A", xy: "00200000010000014D3FF199999999999A400199999999999A" ) |> replacements( xyzm: "01010000E04D0100009A9999999999F13F9A999999999901406666666666660A409A99999999991140", xyz: "01010000A04D0100009A9999999999F13F9A999999999901406666666666660A40", xym: "01010000604D0100009A9999999999F13F9A999999999901409A99999999991140", xy: "01010000204D0100009A9999999999F13F9A99999999990140" ) |> replacements() end defp line_string_test(type) do replacements(type) |> replacements( xyzm: ~S""" 00\ E0000002\ 0000004D\ 00000002\ BFF199999999999AC00199999999999AC00A666666666666C01199999999999A\ 4016000000000000401A666666666666401ECCCCCCCCCCCD402199999999999A\ """, xyz: ~S""" 00\ A0000002\ 0000004D\ 00000002\ BFF199999999999AC00199999999999AC00A666666666666\ 4016000000000000401A666666666666401ECCCCCCCCCCCD\ """, xym: ~S""" 00\ 60000002\ 0000004D\ 00000002\ BFF199999999999AC00199999999999AC01199999999999A\ 4016000000000000401A666666666666402199999999999A\ """, xy: ~S""" 00\ 20000002\ 0000004D\ 00000002\ BFF199999999999AC00199999999999A\ 4016000000000000401A666666666666\ """ ) |> replacements( xyzm: ~S""" 01\ 020000C0\ 02000000\ 9A9999999999F1BF9A999999999901C06666666666660AC09A999999999911C0\ 00000000000016406666666666661A40CDCCCCCCCCCC1E409A99999999992140\ """, xyz: ~S""" 01\ 02000080\ 02000000\ 9A9999999999F1BF9A999999999901C06666666666660AC0\ 00000000000016406666666666661A40CDCCCCCCCCCC1E40\ """, xym: ~S""" 01\ 02000040\ 02000000\ 9A9999999999F1BF9A999999999901C09A999999999911C0\ 00000000000016406666666666661A409A99999999992140\ """, xy: ~S""" 01\ 02000000\ 02000000\ 9A9999999999F1BF9A999999999901C0\ 00000000000016406666666666661A40\ """ ) |> replacements( xyzm: ~S""" 01\ 020000E0\ 67120000\ 02000000\ CB49287D21C451C0F0BF95ECD824454066666666666614409A9999999999F13F\ E5D022DBF93E24C0CDCCCCCCCC0C2440CDCCCCCCCCCC21409A99999999990140\ """, xyz: ~S""" 01\ 020000A0\ 67120000\ 02000000\ CB49287D21C451C0F0BF95ECD82445406666666666661440\ E5D022DBF93E24C0CDCCCCCCCC0C2440CDCCCCCCCCCC2140\ """, xym: ~S""" 01\ 02000060\ 67120000\ 02000000\ CB49287D21C451C0F0BF95ECD82445409A9999999999F13F\ E5D022DBF93E24C0CDCCCCCCCC0C24409A99999999990140\ """, xy: ~S""" 01\ 02000020\ 67120000\ 02000000\ CB49287D21C451C0F0BF95ECD8244540\ E5D022DBF93E24C0CDCCCCCCCC0C2440\ """ ) |> replacements() end defp polygon_test(type) do replacements(type) |> replacements( xyzm: ~S""" 01\ 030000E0\ 4D010000\ 02000000\ 05000000\ 000000000080414000000000000024400000000000002E400000000000003940\ 0000000000804640000000000080464000000000000024400000000000003440\ 0000000000002E40000000000000444000000000000034400000000000002440\ 000000000000244000000000000034400000000000002E400000000000003940\ 000000000080414000000000000024400000000000002E400000000000003940\ 04000000\ 00000000000034400000000000003E400000000000002E400000000000002440\ 0000000000804140000000000080414000000000000024400000000000004940\ 0000000000003E40000000000000344000000000000039400000000000804140\ 00000000000034400000000000003E400000000000002E400000000000002440\ """, xyz: ~S""" 01\ 030000A0\ 4D010000\ 02000000\ 05000000\ 000000000080414000000000000024400000000000002E40\ 000000000080464000000000008046400000000000002440\ 0000000000002E4000000000000044400000000000003440\ 000000000000244000000000000034400000000000002E40\ 000000000080414000000000000024400000000000002E40\ 04000000\ 00000000000034400000000000003E400000000000002E40\ 000000000080414000000000008041400000000000002440\ 0000000000003E4000000000000034400000000000003940\ 00000000000034400000000000003E400000000000002E40\ """, xym: ~S""" 01\ 03000060\ 4D010000\ 02000000\ 05000000\ 000000000080414000000000000024400000000000003940\ 000000000080464000000000008046400000000000003440\ 0000000000002E4000000000000044400000000000002440\ 000000000000244000000000000034400000000000003940\ 000000000080414000000000000024400000000000003940\ 04000000\ 00000000000034400000000000003E400000000000002440\ 000000000080414000000000008041400000000000004940\ 0000000000003E4000000000000034400000000000804140\ 00000000000034400000000000003E400000000000002440\ """, xy: ~S""" 01\ 03000020\ 4D010000\ 02000000\ 05000000\ 00000000008041400000000000002440\ 00000000008046400000000000804640\ 0000000000002E400000000000004440\ 00000000000024400000000000003440\ 00000000008041400000000000002440\ 04000000\ 00000000000034400000000000003E40\ 00000000008041400000000000804140\ 0000000000003E400000000000003440\ 00000000000034400000000000003E40\ """ ) |> replacements( xyzm: ~S""" 00\ C0000003\ 00000001\ 00000005\ 403E00000000000040240000000000004034000000000000402E000000000000\ 4044000000000000404400000000000040240000000000004034000000000000\ 403400000000000040440000000000004039000000000000402E000000000000\ 40240000000000004034000000000000402E0000000000004039000000000000\ 403E00000000000040240000000000004034000000000000402E000000000000\ """, xyz: ~S""" 00\ 80000003\ 00000001\ 00000005\ 403E00000000000040240000000000004034000000000000\ 404400000000000040440000000000004024000000000000\ 403400000000000040440000000000004039000000000000\ 40240000000000004034000000000000402E000000000000\ 403E00000000000040240000000000004034000000000000\ """, xym: ~S""" 00\ 40000003\ 00000001\ 00000005\ 403E0000000000004024000000000000402E000000000000\ 404400000000000040440000000000004034000000000000\ 40340000000000004044000000000000402E000000000000\ 402400000000000040340000000000004039000000000000\ 403E0000000000004024000000000000402E000000000000\ """, xy: ~S""" 00\ 00000003\ 00000001\ 00000005\ 403E0000000000004024000000000000\ 40440000000000004044000000000000\ 40340000000000004044000000000000\ 40240000000000004034000000000000\ 403E0000000000004024000000000000\ """ ) |> replacements( xyzm: ~S""" 00\ E0000003\ 00001267\ 00000001\ 00000004\ 403E000000000000402400000000000040140000000000004000000000000000\ 4044000000000000404400000000000040100000000000004020000000000000\ 4034000000000000404400000000000040200000000000004020000000000000\ 403E000000000000402400000000000040140000000000004000000000000000\ """, xyz: ~S""" 00\ A0000003\ 00001267\ 00000001\ 00000004\ 403E00000000000040240000000000004014000000000000\ 404400000000000040440000000000004010000000000000\ 403400000000000040440000000000004020000000000000\ 403E00000000000040240000000000004014000000000000\ """, xym: ~S""" 00\ 60000003\ 00001267\ 00000001\ 00000004\ 403E00000000000040240000000000004000000000000000\ 404400000000000040440000000000004020000000000000\ 403400000000000040440000000000004020000000000000\ 403E00000000000040240000000000004000000000000000\ """, xy: ~S""" 00\ 20000003\ 00001267\ 00000001\ 00000004\ 403E0000000000004024000000000000\ 40440000000000004044000000000000\ 40340000000000004044000000000000\ 403E0000000000004024000000000000\ """ ) |> replacements() end defp multi_line_string_test(type) do replacements(type) |> replacements( xyzm: ~S""" 00\ C0000005\ 00000002\ 00\ C0000002\ 00000003\ 402400000000000040240000000000004034000000000000403E000000000000\ 4034000000000000403400000000000040440000000000004049000000000000\ 4024000000000000404400000000000040240000000000004034000000000000\ 00\ C0000002\ 00000002\ 40440000000000004044000000000000403E0000000000004034000000000000\ 403E000000000000403E00000000000040440000000000004049000000000000\ """, xyz: ~S""" 00\ 80000005\ 00000002\ 00\ 80000002\ 00000003\ 402400000000000040240000000000004034000000000000\ 403400000000000040340000000000004044000000000000\ 402400000000000040440000000000004024000000000000\ 00\ 80000002\ 00000002\ 40440000000000004044000000000000403E000000000000\ 403E000000000000403E0000000000004044000000000000\ """, xym: ~S""" 00\ 40000005\ 00000002\ 00\ 40000002\ 00000003\ 40240000000000004024000000000000403E000000000000\ 403400000000000040340000000000004049000000000000\ 402400000000000040440000000000004034000000000000\ 00\ 40000002\ 00000002\ 404400000000000040440000000000004034000000000000\ 403E000000000000403E0000000000004049000000000000\ """, xy: ~S""" 00\ 00000005\ 00000002\ 00\ 00000002\ 00000003\ 40240000000000004024000000000000\ 40340000000000004034000000000000\ 40240000000000004044000000000000\ 00\ 00000002\ 00000002\ 40440000000000004044000000000000\ 403E000000000000403E000000000000\ """ ) |> replacements( xyzm: ~S""" 01\ 050000E0\ 15030000\ 01000000\ 01\ 020000C0\ 02000000\ 9A9999999999F13F333333333333F33FCDCCCCCCCCCCF43F666666666666F63F\ 000000000000F83F9A9999999999F93F333333333333FB3FCDCCCCCCCCCCFC3F\ """, xyz: ~S""" 01\ 050000A0\ 15030000\ 01000000\ 01\ 02000080\ 02000000\ 9A9999999999F13F333333333333F33FCDCCCCCCCCCCF43F\ 000000000000F83F9A9999999999F93F333333333333FB3F\ """, xym: ~S""" 01\ 05000060\ 15030000\ 01000000\ 01\ 02000040\ 02000000\ 9A9999999999F13F333333333333F33F666666666666F63F\ 000000000000F83F9A9999999999F93FCDCCCCCCCCCCFC3F\ """, xy: ~S""" 01\ 05000020\ 15030000\ 01000000\ 01\ 02000000\ 02000000\ 9A9999999999F13F333333333333F33F\ 000000000000F83F9A9999999999F93F\ """ ) |> replacements( xyzm: ~S""" 01\ 050000C0\ 01000000\ 01\ 020000C0\ 02000000\ 9A9999999999F13F333333333333F33FCDCCCCCCCCCCF43F666666666666F63F\ 000000000000F83F9A9999999999F93F333333333333FB3FCDCCCCCCCCCCFC3F\ """, xyz: ~S""" 01\ 05000080\ 01000000\ 01\ 02000080\ 02000000\ 9A9999999999F13F333333333333F33FCDCCCCCCCCCCF43F\ 000000000000F83F9A9999999999F93F333333333333FB3F\ """, xym: ~S""" 01\ 05000040\ 01000000\ 01\ 02000040\ 02000000\ 9A9999999999F13F333333333333F33F666666666666F63F\ 000000000000F83F9A9999999999F93FCDCCCCCCCCCCFC3F\ """, xy: ~S""" 01\ 05000000\ 01000000\ 01\ 02000000\ 02000000\ 9A9999999999F13F333333333333F33F\ 000000000000F83F9A9999999999F93F\ """ ) |> replacements( xyzm: ~S""" 00\ E0000005\ 0000028E\ 00000001\ 00\ C0000002\ 00000002\ 3FF199999999999A3FF33333333333333FF4CCCCCCCCCCCD3FF6666666666666\ 3FF80000000000003FF999999999999A3FFB3333333333333FFCCCCCCCCCCCCD\ """, xyz: ~S""" 00\ A0000005\ 0000028E\ 00000001\ 00\ 80000002\ 00000002\ 3FF199999999999A3FF33333333333333FF4CCCCCCCCCCCD\ 3FF80000000000003FF999999999999A3FFB333333333333\ """, xym: ~S""" 00\ 60000005\ 0000028E\ 00000001\ 00\ 40000002\ 00000002\ 3FF199999999999A3FF33333333333333FF6666666666666\ 3FF80000000000003FF999999999999A3FFCCCCCCCCCCCCD\ """, xy: ~S""" 00\ 20000005\ 0000028E\ 00000001\ 00\ 00000002\ 00000002\ 3FF199999999999A3FF3333333333333\ 3FF80000000000003FF999999999999A\ """ ) |> replacements( xyzm: ~S(wkb_start = "00C00000050000000200C0000002"), xyz: ~S(wkb_start = "0080000005000000020080000002"), xym: ~S(wkb_start = "0040000005000000020040000002"), xy: ~S(wkb_start = "0000000005000000020000000002") ) |> replacements() end defp geometry_collection_test(type) do replacements(type) |> replacements( xyzm: ~S""" 01\ 070000C0\ 03000000\ """, xyz: ~S""" 01\ 07000080\ 03000000\ """, xym: ~S""" 01\ 07000040\ 03000000\ """, xy: ~S""" 01\ 07000000\ 03000000\ """ ) |> replacements( xyzm: ~S""" 01\ 070000C0\ 01000000\ 01\ 010000C0\ 000000000000F03F000000000000004000000000000008400000000000001040\ """, xyz: ~S""" 01\ 07000080\ 01000000\ 01\ 01000080\ 000000000000F03F00000000000000400000000000000840\ """, xym: ~S""" 01\ 07000040\ 01000000\ 01\ 01000040\ 000000000000F03F00000000000000400000000000001040\ """, xy: ~S""" 01\ 07000000\ 01000000\ 01\ 01000000\ 000000000000F03F0000000000000040\ """ ) |> replacements( xyzm: ~S""" 01\ 070000E0\ 37000000\ 01000000\ 01\ 010000C0\ 000000000000F03F000000000000004000000000000008400000000000001040\ """, xyz: ~S""" 01\ 070000A0\ 37000000\ 01000000\ 01\ 01000080\ 000000000000F03F00000000000000400000000000000840\ """, xym: ~S""" 01\ 07000060\ 37000000\ 01000000\ 01\ 01000040\ 000000000000F03F00000000000000400000000000001040\ """, xy: ~S""" 01\ 07000020\ 37000000\ 01000000\ 01\ 01000000\ 000000000000F03F0000000000000040\ """ ) |> replacements( xyzm: """ 01\ 070000C0\ 01000000\ 01\ 010000E0\ 37000000\ 000000000000F03F000000000000004000000000000008400000000000001040\ """, xym: """ 01\ 07000080\ 01000000\ 01\ 010000A0\ 37000000\ 000000000000F03F00000000000000400000000000001040\ """, xyz: """ 01\ 07000040\ 01000000\ 01\ 01000060\ 37000000\ 000000000000F03F00000000000000400000000000000840\ """, xy: """ 01\ 07000000\ 01000000\ 01\ 01000020\ 37000000\ 000000000000F03F0000000000000040\ """ ) |> replacements( xyzm: "01070000C000000000", xyz: "010700008000000000", xym: "010700004000000000", xy: "010700000000000000" ) |> replacements() end defp multi_polygon_test(type) do replacements(type) |> replacements( xyzm: ~S""" 01\ 060000C0\ 02000000\ 01\ 030000C0\ 02000000\ 04000000\ 000000000000F03F000000000000F03F00000000000008400000000000001040\ 0000000000002240000000000000F03F00000000000010400000000000001440\ 0000000000002240000000000000204000000000000014400000000000001840\ 000000000000F03F000000000000F03F00000000000008400000000000001040\ 04000000\ 0000000000001840000000000000004000000000000010400000000000000840\ 0000000000001C40000000000000004000000000000018400000000000001C40\ 0000000000001C40000000000000084000000000000008400000000000001040\ 0000000000001840000000000000004000000000000010400000000000000840\ 01\ 030000C0\ 01000000\ 04000000\ 0000000000001840000000000000004000000000000008400000000000001040\ 0000000000002040000000000000004000000000000010400000000000001440\ 0000000000002040000000000000104000000000000014400000000000001840\ 0000000000001840000000000000004000000000000008400000000000001040\ """, xyz: ~S""" 01\ 06000080\ 02000000\ 01\ 03000080\ 02000000\ 04000000\ 000000000000F03F000000000000F03F0000000000000840\ 0000000000002240000000000000F03F0000000000001040\ 000000000000224000000000000020400000000000001440\ 000000000000F03F000000000000F03F0000000000000840\ 04000000\ 000000000000184000000000000000400000000000001040\ 0000000000001C4000000000000000400000000000001840\ 0000000000001C4000000000000008400000000000000840\ 000000000000184000000000000000400000000000001040\ 01\ 03000080\ 01000000\ 04000000\ 000000000000184000000000000000400000000000000840\ 000000000000204000000000000000400000000000001040\ 000000000000204000000000000010400000000000001440\ 000000000000184000000000000000400000000000000840\ """, xym: ~S""" 01\ 06000040\ 02000000\ 01\ 03000040\ 02000000\ 04000000\ 000000000000F03F000000000000F03F0000000000001040\ 0000000000002240000000000000F03F0000000000001440\ 000000000000224000000000000020400000000000001840\ 000000000000F03F000000000000F03F0000000000001040\ 04000000\ 000000000000184000000000000000400000000000000840\ 0000000000001C4000000000000000400000000000001C40\ 0000000000001C4000000000000008400000000000001040\ 000000000000184000000000000000400000000000000840\ 01\ 03000040\ 01000000\ 04000000\ 000000000000184000000000000000400000000000001040\ 000000000000204000000000000000400000000000001440\ 000000000000204000000000000010400000000000001840\ 000000000000184000000000000000400000000000001040\ """, xy: ~S""" 01\ 06000000\ 02000000\ 01\ 03000000\ 02000000\ 04000000\ 000000000000F03F000000000000F03F\ 0000000000002240000000000000F03F\ 00000000000022400000000000002040\ 000000000000F03F000000000000F03F\ 04000000\ 00000000000018400000000000000040\ 0000000000001C400000000000000040\ 0000000000001C400000000000000840\ 00000000000018400000000000000040\ 01\ 03000000\ 01000000\ 04000000\ 00000000000018400000000000000040\ 00000000000020400000000000000040\ 00000000000020400000000000001040\ 00000000000018400000000000000040\ """ ) |> replacements( xyzm: ~S(wkb = "00C000000700000000"), xyz: ~S(wkb = "008000000700000000"), xym: ~S(wkb = "004000000700000000"), xy: ~S(wkb = "000000000700000000") ) |> replacements( xyzm: ~S(wkb = "01070000E07B00000000000000"), xyz: ~S(wkb = "01070000A07B00000000000000"), xym: ~S(wkb = "01070000607B00000000000000"), xy: ~S(wkb = "01070000207B00000000000000") ) |> replacements( xyzm: ~S(wkb = "00E00000070000014100000000"), xyz: ~S(wkb = "00A00000070000014100000000"), xym: ~S(wkb = "00600000070000014100000000"), xy: ~S(wkb = "00200000070000014100000000") ) |> replacements( xyzm: ~S(wkb = "01060000E00903000000000000"), xyz: ~S(wkb = "01060000A00903000000000000"), xym: ~S(wkb = "01060000600903000000000000"), xy: ~S(wkb = "01060000200903000000000000") ) |> replacements( xyzm: ~S(wkb = "00E00000060000023400000000"), xyz: ~S(wkb = "00A00000060000023400000000"), xym: ~S(wkb = "00600000060000023400000000"), xy: ~S(wkb = "00200000060000023400000000") ) |> replacements( xyzm: ~S(wkb = "00C000000600000000"), xyz: ~S(wkb = "008000000600000000"), xym: ~S(wkb = "004000000600000000"), xy: ~S(wkb = "000000000600000000") ) |> replacements( xyzm: ~S(wkb_start = "01060000C00200000001030000C0"), xyz: ~S(wkb_start = "0106000080020000000103000080"), xym: ~S(wkb_start = "0106000040020000000103000040"), xy: ~S(wkb_start = "0106000000020000000103000000") ) |> replacements() end defp multi_point_test(type) do replacements(type) |> replacements( xyzm: ~S""" 00\ C0000004\ 00000003\ 00\ C0000001\ 403E0000000000004024000000000000402E0000000000004024000000000000\ 00\ C0000001\ 404400000000000040440000000000004034000000000000403E000000000000\ 00\ C0000001\ 40340000000000004044000000000000402E0000000000004034000000000000\ """, xyz: ~S""" 00\ 80000004\ 00000003\ 00\ 80000001\ 403E0000000000004024000000000000402E000000000000\ 00\ 80000001\ 404400000000000040440000000000004034000000000000\ 00\ 80000001\ 40340000000000004044000000000000402E000000000000\ """, xym: ~S""" 00\ 40000004\ 00000003\ 00\ 40000001\ 403E00000000000040240000000000004024000000000000\ 00\ 40000001\ 40440000000000004044000000000000403E000000000000\ 00\ 40000001\ 403400000000000040440000000000004034000000000000\ """, xy: ~S""" 00\ 00000004\ 00000003\ 00\ 00000001\ 403E0000000000004024000000000000\ 00\ 00000001\ 40440000000000004044000000000000\ 00\ 00000001\ 40340000000000004044000000000000\ """ ) |> replacements( xyzm: ~S""" 01\ 040000E0\ 0F270000\ 01000000\ 01\ 010000C0\ 0000000000003E4000000000000024400000000000002E400000000000002440\ """, xyz: ~S""" 01\ 040000A0\ 0F270000\ 01000000\ 01\ 01000080\ 0000000000003E4000000000000024400000000000002E40\ """, xym: ~S""" 01\ 04000060\ 0F270000\ 01000000\ 01\ 01000040\ 0000000000003E4000000000000024400000000000002440\ """, xy: ~S""" 01\ 04000020\ 0F270000\ 01000000\ 01\ 01000000\ 0000000000003E400000000000002440\ """ ) |> replacements( xyzm: ~S""" 00\ C0000004\ 00000000\ """, xyz: ~S""" 00\ 80000004\ 00000000\ """, xym: ~S""" 00\ 40000004\ 00000000\ """, xy: ~S""" 00\ 00000004\ 00000000\ """ ) |> replacements( xyzm: ~S""" 01\ 040000C0\ 00000000\ """, xyz: ~S""" 01\ 04000080\ 00000000\ """, xym: ~S""" 01\ 04000040\ 00000000\ """, xy: ~S""" 01\ 04000000\ 00000000\ """ ) |> replacements( xyzm: ~S""" 00\ E0000004\ 0000270F\ 00000001\ 00\ C0000001\ C051C4217D2849CB404524D8EC95BFF040265FB15B573EAB40149DB22D0E5604\ """, xyz: ~S""" 00\ A0000004\ 0000270F\ 00000001\ 00\ 80000001\ C051C4217D2849CB404524D8EC95BFF040265FB15B573EAB\ """, xym: ~S""" 00\ 60000004\ 0000270F\ 00000001\ 00\ 40000001\ C051C4217D2849CB404524D8EC95BFF040149DB22D0E5604\ """, xy: ~S""" 00\ 20000004\ 0000270F\ 00000001\ 00\ 00000001\ C051C4217D2849CB404524D8EC95BFF0\ """ ) |> replacements( xyzm: ~S(wkb_start = "00C00000040000000300C0000001"), xyz: ~S(wkb_start = "0080000004000000030080000001"), xym: ~S(wkb_start = "0040000004000000030040000001"), xy: ~S(wkb_start = "0000000004000000030000000001") ) |> replacements() end defp geometry_collection(type) do replacements(type) |> replacements( xyzm: ", type: :zm", xyz: ", type: :z", xym: ", type: :m", xy: "" ) |> replacements() end defp wkb_code(type) do replacements(type) |> replacements( # Geometries without SRID xyzm: "0xC", xyz: "0x8", xym: "0x4", xy: "0x0" ) |> replacements( # Geometries with SRID xyzm: "0xE", xyz: "0xA", xym: "0x6", xy: "0x2" ) |> replacements( # Point xy: """ {:xdr, false} -> "00000001" {:ndr, false} -> "01000000" {:xdr, true} -> "20000001" {:ndr, true} -> "01000020" """, xym: """ {:xdr, false} -> "40000001" {:ndr, false} -> "01000040" {:xdr, true} -> "60000001" {:ndr, true} -> "01000060" """, xyz: """ {:xdr, false} -> "80000001" {:ndr, false} -> "01000080" {:xdr, true} -> "A0000001" {:ndr, true} -> "010000A0" """, xyzm: """ {:xdr, false} -> "C0000001" {:ndr, false} -> "010000C0" {:xdr, true} -> "E0000001" {:ndr, true} -> "010000E0" """ ) |> replacements( # LineString xy: """ {:xdr, false} -> "00000002" {:ndr, false} -> "02000000" {:xdr, true} -> "20000002" {:ndr, true} -> "02000020" """, xym: """ {:xdr, false} -> "40000002" {:ndr, false} -> "02000040" {:xdr, true} -> "60000002" {:ndr, true} -> "02000060" """, xyz: """ {:xdr, false} -> "80000002" {:ndr, false} -> "02000080" {:xdr, true} -> "A0000002" {:ndr, true} -> "020000A0" """, xyzm: """ {:xdr, false} -> "C0000002" {:ndr, false} -> "020000C0" {:xdr, true} -> "E0000002" {:ndr, true} -> "020000E0" """ ) |> replacements( # Polygon xy: """ {:xdr, false} -> "00000003" {:ndr, false} -> "03000000" {:xdr, true} -> "20000003" {:ndr, true} -> "03000020" """, xym: """ {:xdr, false} -> "40000003" {:ndr, false} -> "03000040" {:xdr, true} -> "60000003" {:ndr, true} -> "03000060" """, xyz: """ {:xdr, false} -> "80000003" {:ndr, false} -> "03000080" {:xdr, true} -> "A0000003" {:ndr, true} -> "030000A0" """, xyzm: """ {:xdr, false} -> "C0000003" {:ndr, false} -> "030000C0" {:xdr, true} -> "E0000003" {:ndr, true} -> "030000E0" """ ) |> replacements( # MultiPoint xy: """ {:xdr, false} -> "00000004" {:ndr, false} -> "04000000" {:xdr, true} -> "20000004" {:ndr, true} -> "04000020" """, xym: """ {:xdr, false} -> "40000004" {:ndr, false} -> "04000040" {:xdr, true} -> "60000004" {:ndr, true} -> "04000060" """, xyz: """ {:xdr, false} -> "80000004" {:ndr, false} -> "04000080" {:xdr, true} -> "A0000004" {:ndr, true} -> "040000A0" """, xyzm: """ {:xdr, false} -> "C0000004" {:ndr, false} -> "040000C0" {:xdr, true} -> "E0000004" {:ndr, true} -> "040000E0" """ ) |> replacements( # MultiLineString xy: """ {:xdr, false} -> "00000005" {:ndr, false} -> "05000000" {:xdr, true} -> "20000005" {:ndr, true} -> "05000020" """, xym: """ {:xdr, false} -> "40000005" {:ndr, false} -> "05000040" {:xdr, true} -> "60000005" {:ndr, true} -> "05000060" """, xyz: """ {:xdr, false} -> "80000005" {:ndr, false} -> "05000080" {:xdr, true} -> "A0000005" {:ndr, true} -> "050000A0" """, xyzm: """ {:xdr, false} -> "C0000005" {:ndr, false} -> "050000C0" {:xdr, true} -> "E0000005" {:ndr, true} -> "050000E0" """ ) |> replacements( # MultiPolygon xy: """ {:xdr, false} -> "00000006" {:ndr, false} -> "06000000" {:xdr, true} -> "20000006" {:ndr, true} -> "06000020" """, xym: """ {:xdr, false} -> "40000006" {:ndr, false} -> "06000040" {:xdr, true} -> "60000006" {:ndr, true} -> "06000060" """, xyz: """ {:xdr, false} -> "80000006" {:ndr, false} -> "06000080" {:xdr, true} -> "A0000006" {:ndr, true} -> "060000A0" """, xyzm: """ {:xdr, false} -> "C0000006" {:ndr, false} -> "060000C0" {:xdr, true} -> "E0000006" {:ndr, true} -> "060000E0" """ ) |> replacements( # GeometryCollection xy: """ {:xdr, false} -> "00000007" {:ndr, false} -> "07000000" {:xdr, true} -> "20000007" {:ndr, true} -> "07000020" """, xym: """ {:xdr, false} -> "40000007" {:ndr, false} -> "07000040" {:xdr, true} -> "60000007" {:ndr, true} -> "07000060" """, xyz: """ {:xdr, false} -> "80000007" {:ndr, false} -> "07000080" {:xdr, true} -> "A0000007" {:ndr, true} -> "070000A0" """, xyzm: """ {:xdr, false} -> "C0000007" {:ndr, false} -> "070000C0" {:xdr, true} -> "E0000007" {:ndr, true} -> "070000E0" """ ) |> replacements() end defp replacements({old, new, _type}), do: {List.flatten(old), List.flatten(new)} defp replacements(type), do: {[], [], type} defp replacements({old, new, type}, items) do {[Keyword.get(items, :xyzm) | old], [Keyword.fetch!(items, type) | new], type} end defp replace(code, :skip), do: code defp replace(code, {patterns, replacements}) when is_list(patterns) and is_list(replacements) do patterns |> Enum.zip(replacements) |> Enum.reduce(code, fn {pattern, replacement}, acc -> String.replace(acc, pattern, replacement, global: true) end) end defp replace(code, {pattern, replacement}), do: String.replace(code, pattern, replacement, global: true) defp unzip(list) do Enum.reduce(list, {[], []}, fn [a, b], {as, bs} -> {[a | as], [b | bs]} end) end defp info(str), do: IO.write("#{str}\n") end GenFromZM.main()