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
|
module LngLat exposing (LngLat, decodeFromObject, decodeFromPair, encodeAsObject, encodeAsPair, map, toString)
{-| Encodes geographic position.
@docs LngLat, encodeAsPair, encodeAsObject, decodeFromPair, decodeFromObject, map, toString
-}
import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode exposing (Value)
{-| A LngLat represents a geographic position.
-}
type alias LngLat =
{ lng : Float
, lat : Float
}
{-| Most implementations seem to encode these as a 2 member array.
-}
encodeAsPair : LngLat -> Value
encodeAsPair { lng, lat } =
Encode.list Encode.float [ lng, lat ]
{-| Most implementations seem to encode these as a 2 member array.
-}
decodeFromPair : Decoder LngLat
decodeFromPair =
Decode.list Decode.float
|> Decode.andThen
(\l ->
case l of
[ lng, lat ] ->
Decode.succeed (LngLat lng lat)
_ ->
Decode.fail "Doesn't apear to be a valid lng lat pair"
)
{-| We can also encode as an `{lng: 32, lat: 435}` object.
-}
encodeAsObject : LngLat -> Value
encodeAsObject { lng, lat } =
Encode.object [ ( "lng", Encode.float lng ), ( "lat", Encode.float lat ) ]
{-| We can also encode from an `{lng: 32, lat: 435}` object.
-}
decodeFromObject : Decoder LngLat
decodeFromObject =
Decode.map2 LngLat (Decode.field "lng" Decode.float) (Decode.field "lat" Decode.float)
{-| -}
map : (Float -> Float) -> LngLat -> LngLat
map f { lng, lat } =
{ lng = f lng, lat = f lat }
toDMS : Float -> String -> String -> String
toDMS angle pos neg =
let
absAngle =
abs angle
degrees =
truncate absAngle
minutes =
(absAngle - toFloat degrees) * 60
seconds =
(minutes - toFloat (truncate minutes)) * 60 |> round
prefix =
if angle > 0 then
pos
else
neg
in
String.fromInt degrees ++ "° " ++ String.fromInt (truncate minutes) ++ "' " ++ String.fromInt seconds ++ "\"" ++ prefix
{-| Returns a text representation suitable for humans.
-}
toString : LngLat -> String
toString { lng, lat } =
toDMS lat "N" "S" ++ " " ++ toDMS lng "E" "W"
|