1 module nxt.geodetic;
2 
3 import std.traits : isFloatingPoint, isSomeString;
4 
5 /** WGS84 coordinate.
6     See_Also: https://en.wikipedia.org/wiki/World_Geodetic_System
7    */
8 struct WGS84Coordinate(T = double)
9 if (isFloatingPoint!T)
10 {
11     @safe: // TODO nothrow @nogc
12 
13     /// Construct from `latitude` and `longitude`.
14     this(T latitude,
15          T longitude)
16         pure nothrow @nogc
17     {
18         this.latitude = latitude;
19         this.longitude = longitude;
20     }
21 
22     /// Construct from string `s` and separator `separator`.
23     this(scope const(char)[] s,
24          scope string separator = ` `)
25     {
26         import nxt.array_algorithm : findSplit;
27         if (auto parts = s.findSplit(separator))
28         {
29             import std.conv : to;
30             this(parts.pre.to!T,
31                  parts.post.to!T);
32         }
33         else
34         {
35             this(T.nan, T.nan);
36         }
37     }
38 
39     /// Convert to `string`.
40     auto toString(scope void delegate(scope const(char)[]) @safe sink) const @safe
41     {
42         import std.format : formattedWrite;
43         sink.formattedWrite!(`%f° N %f° W`)(latitude, longitude);
44     }
45 
46     T latitude;
47     T longitude;
48 }
49 
50 auto wgs84Coordinate(T)(T latitude,
51                         T longitude)
52 if (isFloatingPoint!T)
53 {
54     return WGS84Coordinate!T(latitude, longitude);
55 }
56 
57 auto wgs84Coordinate(T = double, S, Separator)(S s, Separator separator = ` `)
58 if (isSomeString!S &&
59         isSomeString!Separator)
60 {
61     return WGS84Coordinate!T(s, separator);
62 }
63 
64 @safe // TODO pure/ nothrow
65 unittest
66 {
67     alias T = float;
68 
69     T latitude = 1.5;
70     T longitude = 2.5;
71 
72     import std.conv : to;
73     assert(wgs84Coordinate(latitude, longitude) ==
74            wgs84Coordinate!T(`1.5 2.5`));
75 
76     auto x = wgs84Coordinate(`36.7,3.216666666666667`, `,`);
77     assert(x.to!string == `36.700000° N 3.216667° W`);
78 }