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.algorithm.searching : 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 	=> WGS84Coordinate!T(latitude, longitude);
54 
55 auto wgs84Coordinate(T = double, S, Separator)(S s, Separator separator = ` `)
56 if (isSomeString!S &&
57 		isSomeString!Separator)
58 	=> WGS84Coordinate!T(s, separator);
59 
60 @safe unittest {
61 	alias T = float;
62 
63 	T latitude = 1.5;
64 	T longitude = 2.5;
65 
66 	import std.conv : to;
67 	assert(wgs84Coordinate(latitude, longitude) ==
68 		   wgs84Coordinate!T(`1.5 2.5`));
69 
70 	auto x = wgs84Coordinate(`36.7,3.216666666666667`, `,`);
71 	assert(x.to!string == `36.700000° N 3.216667° W`);
72 }