~ihabunek/triglav

ref: 3a1876166aa129c76c1b09fc562af764d04df4e1 triglav/lib/triglav/josm.ex -rw-r--r-- 2.2 KiB
3a187616Ivan Habunek Fix detecting unexpected master route members 7 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
defmodule Triglav.Josm do
  @moduledoc """
  Generate JOSM remote control links.

  Remote docs:
  https://josm.openstreetmap.de/wiki/Help/RemoteControlCommands
  """
  alias Triglav.Schemas.Osmosis.Node
  alias Triglav.Schemas.Osmosis.Relation
  alias Triglav.Schemas.Osmosis.Way

  @type object :: Relation.t() | Way.t() | Node.t()
  @type option :: [new_layer: boolean()]
  @type options :: [option]

  @base "http://127.0.0.1:8111"

  @spec load_object(object, options) :: String.t()
  def load_object(object, opts \\ []) do
    load_objects([object], opts)
  end

  @spec load_objects([object], options) :: String.t()
  def load_objects(objects, opts \\ []) do
    new_layer = Keyword.get(opts, :new_layer, false)
    relation_members = Keyword.get(opts, :relation_members, true)

    url("/load_object", %{
      objects: object_ids(objects),
      new_layer: to_string(new_layer),
      relation_members: to_string(relation_members)
    })
  end

  def zoom(lat, lon) do
    url("/zoom", %{
      top: lat,
      bottom: lat,
      left: lon,
      right: lon
    })
  end

  def add_tags(object, tags) do
    str_tags =
      tags
      |> Enum.map(fn {k, v} -> "#{k}=#{v}" end)
      |> Enum.join("|")

    params =
      bounds(object)
      |> Map.put(:select, object_id(object))
      |> Map.put(:addtags, str_tags)

    url("/load_and_zoom", params)
  end

  defp url(path, params) do
    "#{@base}#{path}?#{URI.encode_query(params)}"
  end

  defp object_ids(objects) do
    objects
    |> Enum.map(&object_id/1)
    |> Enum.join(",")
  end

  defp object_id(%Relation{} = relation), do: "r#{relation.id}"
  defp object_id(%Way{} = way), do: "w#{way.id}"
  defp object_id(%Node{} = node), do: "n#{node.id}"

  defp bounds(%Node{} = node) do
    {lon, lat} = node.geom.coordinates

    %{
      top: lat,
      bottom: lat,
      left: lon,
      right: lon
    }
  end

  defp bounds(%Way{} = way) do
    {lon_min, lon_max} =
      way.linestring.coordinates
      |> Enum.map(&elem(&1, 0))
      |> Enum.min_max()

    {lat_min, lat_max} =
      way.linestring.coordinates
      |> Enum.map(&elem(&1, 1))
      |> Enum.min_max()

    %{
      top: lat_max,
      bottom: lat_min,
      left: lon_min,
      right: lon_max
    }
  end
end