GeographicLib 2.7

Loading...
Searching...
No Matches
GARS.cpp
Go to the documentation of this file.
1/**
2 * \file GARS.cpp
3 * \brief Implementation for GeographicLib::GARS class
4 *
5 * Copyright (c) Charles Karney (2015-2022) <karney@alum.mit.edu> and licensed
6 * under the MIT/X11 License. For more information, see
7 * https://geographiclib.sourceforge.io/
8 **********************************************************************/
9
10#include <GeographicLib/GARS.hpp>
11#include <GeographicLib/Utility.hpp>
12
13 namespace GeographicLib {
14
15 using namespace std;
16
17 const char* const GARS::digits_ = "0123456789";
18 const char* const GARS::letters_ = "ABCDEFGHJKLMNPQRSTUVWXYZ";
19
20 void GARS::Forward(real lat, real lon, int prec, string& gars) {
21 if (fabs(lat) > Math::qd)
22 throw GeographicErr("Latitude " + Utility::str(lat)
23 + "d not in [-" + to_string(Math::qd)
24 + "d, " + to_string(Math::qd) + "d]");
25 if (isnan(lat) || isnan(lon)) {
26 gars = "INVALID";
27 return;
28 }
29 lon = Math::AngNormalize(lon);
30 if (lon == Math::hd) lon = -Math::hd; // lon now in [-180,180)
31 if (lat == Math::qd) lat *= (1 - numeric_limits<real>::epsilon() / 2);
32 prec = max(0, min(int(maxprec_), prec));
33 int
34 x = int(floor(lon * m_)) - lonorig_ * m_,
35 y = int(floor(lat * m_)) - latorig_ * m_,
36 ilon = x * mult1_ / m_,
37 ilat = y * mult1_ / m_;
38 x -= ilon * m_ / mult1_; y -= ilat * m_ / mult1_;
39 char gars1[maxlen_];
40 ++ilon;
41 for (int c = lonlen_; c--;) {
42 gars1[c] = digits_[ ilon % baselon_]; ilon /= baselon_;
43 }
44 for (int c = latlen_; c--;) {
45 gars1[lonlen_ + c] = letters_[ilat % baselat_]; ilat /= baselat_;
46 }
47 if (prec > 0) {
48 ilon = x / mult3_; ilat = y / mult3_;
49 gars1[baselen_] = digits_[mult2_ * (mult2_ - 1 - ilat) + ilon + 1];
50 if (prec > 1) {
51 ilon = x % mult3_; ilat = y % mult3_;
52 gars1[baselen_ + 1] = digits_[mult3_ * (mult3_ - 1 - ilat) + ilon + 1];
53 }
54 }
55 gars.resize(baselen_ + prec);
56 copy(gars1, gars1 + baselen_ + prec, gars.begin());
57 }
58
59 void GARS::Reverse(const string& gars, real& lat, real& lon,
60 int& prec, bool centerp) {
61 int len = int(gars.length());
62 if (len >= 3 &&
63 toupper(gars[0]) == 'I' &&
64 toupper(gars[1]) == 'N' &&
65 toupper(gars[2]) == 'V') {
66 lat = lon = Math::NaN();
67 return;
68 }
69 if (len < baselen_)
70 throw GeographicErr("GARS must have at least 5 characters " + gars);
71 if (len > maxlen_)
72 throw GeographicErr("GARS can have at most 7 characters " + gars);
73 int prec1 = len - baselen_;
74 int ilon = 0;
75 for (int c = 0; c < lonlen_; ++c) {
76 int k = Utility::lookup(digits_, gars[c]);
77 if (k < 0)
78 throw GeographicErr("GARS must start with 3 digits " + gars);
79 ilon = ilon * baselon_ + k;
80 }
81 if (!(ilon >= 1 && ilon <= 2 * Math::td))
82 throw GeographicErr("Initial digits in GARS must lie in [1, 720] " +
83 gars);
84 --ilon;
85 int ilat = 0;
86 for (int c = 0; c < latlen_; ++c) {
87 int k = Utility::lookup(letters_, gars[lonlen_ + c]);
88 if (k < 0)
89 throw GeographicErr("Illegal letters in GARS " + gars.substr(3,2));
90 ilat = ilat * baselat_ + k;
91 }
92 if (!(ilat < Math::td))
93 throw GeographicErr("GARS letters must lie in [AA, QZ] " + gars);
94 real
95 unit = mult1_,
96 lat1 = ilat + latorig_ * unit,
97 lon1 = ilon + lonorig_ * unit;
98 if (prec1 > 0) {
99 int k = Utility::lookup(digits_, gars[baselen_]);
100 if (!(k >= 1 && k <= mult2_ * mult2_))
101 throw GeographicErr("6th character in GARS must [1, 4] " + gars);
102 --k;
103 unit *= mult2_;
104 lat1 = mult2_ * lat1 + (mult2_ - 1 - k / mult2_);
105 lon1 = mult2_ * lon1 + (k % mult2_);
106 if (prec1 > 1) {
107 k = Utility::lookup(digits_, gars[baselen_ + 1]);
108 if (!(k >= 1 /* && k <= mult3_ * mult3_ */))
109 throw GeographicErr("7th character in GARS must [1, 9] " + gars);
110 --k;
111 unit *= mult3_;
112 lat1 = mult3_ * lat1 + (mult3_ - 1 - k / mult3_);
113 lon1 = mult3_ * lon1 + (k % mult3_);
114 }
115 }
116 if (centerp) {
117 unit *= 2; lat1 = 2 * lat1 + 1; lon1 = 2 * lon1 + 1;
118 }
119 lat = lat1 / unit;
120 lon = lon1 / unit;
121 prec = prec1;
122 }
123
124} // namespace GeographicLib
GARS.hpp
Header for GeographicLib::GARS class.
Utility.hpp
Header for GeographicLib::Utility class.
GeographicLib::GARS::Reverse
static void Reverse(const std::string &gars, real &lat, real &lon, int &prec, bool centerp=true)
Definition GARS.cpp:59
GeographicLib::GARS::Forward
static void Forward(real lat, real lon, int prec, std::string &gars)
Definition GARS.cpp:20
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition Constants.hpp:344
GeographicLib::Math::qd
static constexpr int qd
degrees per quarter turn
Definition Math.hpp:142
GeographicLib::Math::AngNormalize
static T AngNormalize(T x)
Definition Math.cpp:69
GeographicLib::Math::td
static constexpr int td
degrees per turn
Definition Math.hpp:146
GeographicLib::Math::NaN
static T NaN()
Definition Math.cpp:301
GeographicLib::Math::hd
static constexpr int hd
degrees per half turn
Definition Math.hpp:145
GeographicLib::Utility::lookup
static int lookup(const std::string &s, char c)
Definition Utility.cpp:160
GeographicLib::Utility::str
static std::string str(T x, int p=-1)
Definition Utility.hpp:161
GeographicLib
Namespace for GeographicLib.
Definition Accumulator.cpp:12