Peano
Loading...
Searching...
No Matches
EllipsoidProjection.h
Go to the documentation of this file.
1#pragma once
2
3#include "../Constants.h"
4
5#include <cmath>
6#include <utility>
7
8namespace projection {
9 namespace albers_equal_area {
10 namespace ellipsoid {
11 namespace constants = ::applications::exahype2::swe;
12 /*
13 * @brief
14 * Projects geographic coordinates (longitude, latitude) onto a planar surface
15 * using the Albers Equal-Area Conic projection for the WGS_1984 ellipsoid.
16 *
17 * This implementation is based on the equations provided in USGS Professional Paper 1395.
18 * It supports standard parallels and is suitable for regional-scale mapping where
19 * area preservation is important.
20 *
21 * @see https://doi.org/10.3133/pp1395
22 */
23 inline auto forward(const auto lon, const auto lat) {
24 constexpr auto a = constants::aeaEllipsoidA; // Halbachse des WGS_1984-Ellipsoids (Meter)
25 constexpr auto e = constants::aeaEllipsoidE;
26 constexpr auto stdParallel1 = constants::aeaStdParallel1; // Standard Parallel 1 (Grad)
27 constexpr auto stdParallel2 = constants::aeaStdParallel2; // Standard Parallel 2 (Grad)
28 constexpr auto lon0 = constants::aeaLon0; // Central Meridian (Grad)
29 constexpr auto lat0 = constants::aeaLat0; // Latitude of Origin (Grad)
30
31 constexpr auto toRad = M_PI / 180.0;
32
33 constexpr auto stdParallel1Rad = stdParallel1 * toRad;
34 constexpr auto stdParallel2Rad = stdParallel2 * toRad;
35 constexpr auto lat0Rad = lat0 * toRad;
36 constexpr auto lon0Rad = lon0 * toRad;
37
38 const auto lonRad = lon * toRad;
39 const auto latRad = lat * toRad;
40
41 constexpr auto e2 = e * e;
42 constexpr auto oneMinusE2 = 1.0 - (e * e);
43
44 auto m = [](const auto phi) { return std::cos(phi) / std::sqrt(1.0 - (e2 * std::sin(phi) * std::sin(phi))); };
45
46 static const auto m1 = m(stdParallel1Rad);
47 static const auto m2 = m(stdParallel2Rad);
48
49 auto q = [](const auto phi) {
50 const auto sinPhi = std::sin(phi);
51 const auto sinPhi2 = sinPhi * sinPhi;
52 return oneMinusE2
53 * ((std::sin(phi) / (1.0 - (e2 * sinPhi2))) - ((1.0 / (2.0 * e)) * std::log((1.0 - (e * std::sin(phi))) / (1.0 + (e * std::sin(phi))))));
54 };
55
56 static const auto q0 = q(lat0Rad);
57 static const auto q1 = q(stdParallel1Rad);
58 static const auto q2 = q(stdParallel2Rad);
59
60
61 const auto qLat = q(latRad);
62
63 static const auto n = ((m1 * m1) - (m2 * m2)) / (q2 - q1);
64 static const auto C = (m1 * m1) + (n * q1);
65 static const auto p0 = a * std::sqrt(C - (n * q0)) / n;
66
67 const auto p = a * std::sqrt(C - (n * qLat)) / n;
68 const auto theta = n * (lonRad - lon0Rad);
69
70 const auto x = p * std::sin(theta);
71 const auto y = p0 - (p * std::cos(theta));
72
73 return std::pair{x, y};
74 };
75
86 inline auto inverse(const auto x, const auto y) {
87 constexpr size_t maxIter = 10;
88 constexpr auto tol = 1e-12;
89
90 constexpr auto a = constants::aeaEllipsoidA; // Halbachse des WGS_1984-Ellipsoids (Meter)
91 constexpr auto e = constants::aeaEllipsoidE;
92 constexpr auto stdParallel1 = constants::aeaStdParallel1; // Standard Parallel 1 (Grad)
93 constexpr auto stdParallel2 = constants::aeaStdParallel2; // Standard Parallel 2 (Grad)
94 constexpr auto lon0 = constants::aeaLon0; // Central Meridian (Grad)
95 constexpr auto lat0 = constants::aeaLat0; // Latitude of Origin (Grad)
96
97 constexpr auto toRad = M_PI / 180.0;
98
99 constexpr auto stdParallel1Rad = stdParallel1 * toRad;
100 constexpr auto stdParallel2Rad = stdParallel2 * toRad;
101 constexpr auto lat0Rad = lat0 * toRad;
102 constexpr auto lon0Rad = lon0 * toRad;
103
104 constexpr auto e2 = e * e;
105 constexpr auto oneMinusE2 = 1.0 - (e * e);
106
107 auto m = [](const auto phi) { return std::cos(phi) / std::sqrt(1.0 - (e2 * std::sin(phi) * std::sin(phi))); };
108
109 static const auto m1 = m(stdParallel1Rad);
110 static const auto m2 = m(stdParallel2Rad);
111
112 auto q = [](const auto phi) {
113 const auto sinPhi = std::sin(phi);
114 const auto sinPhi2 = sinPhi * sinPhi;
115 return oneMinusE2
116 * ((std::sin(phi) / (1.0 - (e2 * sinPhi2))) - ((1.0 / (2.0 * e)) * std::log((1.0 - (e * std::sin(phi))) / (1.0 + (e * std::sin(phi))))));
117 };
118
119 static const auto q0 = q(lat0Rad);
120 static const auto q1 = q(stdParallel1Rad);
121 static const auto q2 = q(stdParallel2Rad);
122
123 static const auto n = ((m1 * m1) - (m2 * m2)) / (q2 - q1);
124 static const auto C = (m1 * m1) + (n * q1);
125 static const auto p0 = a * std::sqrt(C - (n * q0)) / n;
126
127 const auto p = std::sqrt((x * x) + ((p0 - y) * (p0 - y)));
128 const auto qnew = (C - (p * p * n * n / (a * a))) / n;
129
130 auto phi = std::asin(qnew / 2);
131
132#pragma unroll
133 for (int i = 0; i < maxIter; ++i) {
134 const auto sinPhi = std::sin(phi);
135 const auto cosPhi = std::cos(phi);
136 const auto sinPhi2 = sinPhi * sinPhi;
137 const auto denom = 1.0 - (e2 * sinPhi2);
138
139 const auto num1 = qnew / oneMinusE2;
140 const auto num2 = sinPhi / denom;
141 const auto num3 = (1.0 / (2.0 * e)) * std::log((1.0 - e * sinPhi) / (1.0 + e * sinPhi));
142
143 const auto deltaPhi = (1.0 - (e2 * sinPhi2)) * (1.0 - (e2 * sinPhi2)) / (2.0 * cosPhi) * (num1 - num2 + num3);
144 const auto phiNew = phi + deltaPhi;
145
146 if (std::abs(phiNew - phi) < tol) {
147 break;
148 }
149 phi = phiNew;
150 }
151
152
153 const auto theta = std::atan2(x, p0 - y);
154 const auto lon = lon0Rad + (theta / n);
155
156 return std::pair{
157 lon / toRad,
158 phi / toRad,
159 };
160 };
161 } // namespace ellipsoid
162 } // namespace albers_equal_area
163} // namespace projection
auto inverse(const auto x, const auto y)
Inverts the Albers Equal-Area Conic projection for WGS_1984 and returns the geographic coordinates (l...
auto forward(const auto lon, const auto lat)