Quetzal-CoaTL
The Coalescence Template Library
Loading...
Searching...
No Matches
coordinates.hpp
1// Copyright 2021 Arnaud Becheler <abechele@umich.edu>
2
3/*********************************************************************** * This program is free software; you can
4 *redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free
5 *Software Foundation; either version 2 of the License, or * (at your option) any later version. *
6 * *
7 ***************************************************************************/
8
9#pragma once
10
11#include <assert.h>
12#include <cmath> // trigonometry
13#include <ostream>
14#include <tuple>
15#include <numbers>
16
17#include <mp-units/systems/si.h>
18#include <mp-units/ostream.h>
19
20namespace quetzal::geography
21{
22
23using std::numbers::pi;
24
25class latlon;
26class lonlat;
27class rowcol;
28class colrow;
29
31template <typename T>
32concept GridCoordinate = requires(T t) {
33 {
34 t.col <=> t.row
35 };
36 };
37
39template <GridCoordinate C1, GridCoordinate C2> auto operator==(const C1 &c1, const C2 &c2)
40{
41 return std::tie(c1.col, c1.row) == std::tie(c2.col, c2.row);
42}
43
45template <GridCoordinate C1, GridCoordinate C2> auto operator<=>(const C1 &c1, const C2 &c2)
46{
47 return std::tie(c1.col, c1.row) <=> std::tie(c2.col, c2.row);
48}
49
51template <GridCoordinate C> std::ostream &operator<<(std::ostream &stream, const C &c)
52{
53 stream << "(Column: " << c.col << ", Row: " << c.row << ")";
54 return stream;
55}
56
60struct rowcol
61{
63 using value_type = int;
64
66 value_type row;
67
69 value_type col;
70
72 constexpr explicit rowcol(value_type row, value_type column) noexcept : row(row), col(column)
73 {
74 }
75};
76static_assert(GridCoordinate<rowcol>);
77
81struct colrow
82{
84 using value_type = int;
85
87 value_type col;
88
90 value_type row;
91
93 constexpr explicit colrow(value_type column, value_type row) noexcept : col(column), row(row)
94 {
95 }
96};
97static_assert(GridCoordinate<colrow>);
98
100template <typename T>
101concept Coordinate = requires(T t) {
102 {
103 t.lon <=> t.lat
104 };
105 };
106
108template <Coordinate C1, Coordinate C2> auto operator==(const C1 &c1, const C2 &c2)
109{
110 return std::tie(c1.lat, c1.lon) == std::tie(c2.lat, c2.lon);
111}
112
114template <Coordinate C1, Coordinate C2> auto operator<=>(const C1 &c1, const C2 &c2)
115{
116 return std::tie(c1.lat, c1.lon) <=> std::tie(c2.lat, c2.lon);
117}
118
120template <Coordinate C> std::ostream &operator<<(std::ostream &stream, const C &c)
121{
122 stream << "(Lat: " << c.lat << ", Lon: " << c.lon << ")";
123 return stream;
124}
125
126namespace details
127{
128
130void check(double lat, double lon)
131{
132 if ((lat > 90.) || (lat < -90.) || (lon < -180.) || (lon > 180.))
133 throw std::invalid_argument("invalid coordinates");
134}
135
137constexpr double deg2rad(double deg) noexcept
138{
139 return (deg * pi / 180.0);
140}
141
143constexpr double rad2deg(double rad) noexcept
144{
145 return (rad * 180.0 / pi);
146}
147
155constexpr double distanceEarth(double lat1d, double lon1d, double lat2d, double lon2d)
156{
157
158 const double earthRadiusKm = 6371.0;
159
160 const double lat1r = deg2rad(lat1d);
161 const double lon1r = deg2rad(lon1d);
162 const double lat2r = deg2rad(lat2d);
163 const double lon2r = deg2rad(lon2d);
164
165 const double u = sin((lat2r - lat1r) / 2);
166 const double v = sin((lon2r - lon1r) / 2);
167
168 const double d = 2.0 * earthRadiusKm * asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v));
169 assert(d >= 0);
170 return d;
171}
172
173} // namespace details
174
178struct latlon
179{
181 using decimal_degree = double;
182
184 decimal_degree lat;
185
187 decimal_degree lon;
188
190 constexpr explicit latlon(decimal_degree latitude, decimal_degree longitude) noexcept
191 : lat(latitude), lon(longitude)
192 {
193 }
194
203 template <class T> constexpr
204 mp_units::quantity<mp_units::si::metre> great_circle_distance_to(const T &other) const noexcept
205 {
206 const double d = details::distanceEarth(this->lat, this->lon, other.lat, other.lon);
207 assert(d >= 0.);
208 return d * 1000.0 * mp_units::si::metre;
209 }
210};
211
212static_assert(Coordinate<latlon>);
213
217struct lonlat
218{
220 using decimal_degree = double;
221
223 decimal_degree lon;
224
226 decimal_degree lat;
227
229 constexpr explicit lonlat(decimal_degree longitude, decimal_degree latitude) noexcept
230 : lon(longitude), lat(latitude)
231 {
232 }
233
242 template <class T>
243 constexpr
244 mp_units::quantity<mp_units::si::metre> great_circle_distance_to(const T &other) const noexcept
245 {
246 const double d = details::distanceEarth(this->lat, this->lon, other.lat, other.lon);
247 assert(d >= 0.0);
248 return d * 1000.0 * mp_units::si::metre;
249 }
250
251}; // end struct latlon
252static_assert(Coordinate<lonlat>);
253
254} // namespace quetzal::geography
Requires a type to define a lat and a lon member.
Definition coordinates.hpp:101
Requires a type to define a row and a col member.
Definition coordinates.hpp:32
Geospatial data formatting and processing.
Definition geography.hpp:17
auto operator<=>(const C1 &c1, const C2 &c2)
GridCoordinates are three-way comparable.
Definition coordinates.hpp:45
std::ostream & operator<<(std::ostream &stream, const C &c)
GridCoordinates are streamable.
Definition coordinates.hpp:51
auto operator==(const C1 &c1, const C2 &c2)
GridCoordinates are equality comparable.
Definition coordinates.hpp:39
Grid coordinates.
Definition coordinates.hpp:82
constexpr colrow(value_type column, value_type row) noexcept
Constructor.
Definition coordinates.hpp:93
value_type col
Column descriptor.
Definition coordinates.hpp:87
value_type row
Row descriptor.
Definition coordinates.hpp:90
Geographic coordinates.
Definition coordinates.hpp:179
decimal_degree lat
Latitude.
Definition coordinates.hpp:184
constexpr mp_units::quantity< mp_units::si::metre > great_circle_distance_to(const T &other) const noexcept
Compute great-circle distance between two points on the Earth.
Definition coordinates.hpp:204
constexpr latlon(decimal_degree latitude, decimal_degree longitude) noexcept
Constructor.
Definition coordinates.hpp:190
decimal_degree lon
Longitude.
Definition coordinates.hpp:187
Geographic coordinates.
Definition coordinates.hpp:218
constexpr lonlat(decimal_degree longitude, decimal_degree latitude) noexcept
Constructor.
Definition coordinates.hpp:229
decimal_degree lon
Longitude.
Definition coordinates.hpp:223
decimal_degree lat
Latitude.
Definition coordinates.hpp:226
constexpr mp_units::quantity< mp_units::si::metre > great_circle_distance_to(const T &other) const noexcept
Compute great-circle distance between two points on the Earth.
Definition coordinates.hpp:244
Grid coordinates.
Definition coordinates.hpp:61
constexpr rowcol(value_type row, value_type column) noexcept
Constructor.
Definition coordinates.hpp:72
value_type col
Column descriptor.
Definition coordinates.hpp:69
value_type row
Row descriptor.
Definition coordinates.hpp:66