GeographicLib
2.7
Toggle main menu visibility
Loading...
Searching...
No Matches
Georef.cpp
Go to the documentation of this file.
1
/**
2
* \file Georef.cpp
3
* \brief Implementation for GeographicLib::Georef 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/Georef.hpp
>
11
#include <
GeographicLib/Utility.hpp
>
12
13
namespace
GeographicLib
{
14
15
using namespace
std;
16
17
const
char
*
const
Georef::digits_ =
"0123456789"
;
18
const
char
*
const
Georef::lontile_ =
"ABCDEFGHJKLMNPQRSTUVWXYZ"
;
19
const
char
*
const
Georef::lattile_ =
"ABCDEFGHJKLM"
;
20
const
char
*
const
Georef::degrees_ =
"ABCDEFGHJKLMNPQ"
;
21
22
void
Georef::Forward
(real lat, real lon,
int
prec,
string
& georef) {
23
if
(fabs(lat) >
Math::qd
)
24
throw
GeographicErr
(
"Latitude "
+
Utility::str
(lat)
25
+
"d not in [-"
+ to_string(
Math::qd
)
26
+
"d, "
+ to_string(
Math::qd
) +
"d]"
);
27
if
(isnan(lat) || isnan(lon)) {
28
georef =
"INVALID"
;
29
return
;
30
}
31
lon =
Math::AngNormalize
(lon);
// lon in [-180,180)
32
if
(lat ==
Math::qd
) lat *= (1 - numeric_limits<real>::epsilon() / 2);
33
prec = max(-1, min(
int
(maxprec_), prec));
34
if
(prec == 1) ++prec;
// Disallow prec = 1
35
// The C++ standard mandates 64 bits for long long. But
36
// check, to make sure.
37
static_assert
(numeric_limits<long long>::digits >= 45,
38
"long long not wide enough to store 21600e9"
);
39
const
long
long
m = 60000000000LL;
40
long
long
41
x = (
long
long)(floor(lon *
real
(m))) - lonorig_ * m,
42
y = (
long
long)(floor(lat *
real
(m))) - latorig_ * m;
43
int
ilon = int(x / m);
int
ilat = int(y / m);
44
char
georef1[maxlen_];
45
georef1[0] = lontile_[ilon / tile_];
46
georef1[1] = lattile_[ilat / tile_];
47
if
(prec >= 0) {
48
georef1[2] = degrees_[ilon % tile_];
49
georef1[3] = degrees_[ilat % tile_];
50
if
(prec > 0) {
51
x -= m * ilon; y -= m * ilat;
52
long
long
d = (
long
long)pow(
real
(base_), maxprec_ - prec);
53
x /= d; y /= d;
54
for
(
int
c = prec; c--;) {
55
georef1[baselen_ + c ] = digits_[x % base_]; x /= base_;
56
georef1[baselen_ + c + prec] = digits_[y % base_]; y /= base_;
57
}
58
}
59
}
60
georef.resize(baselen_ + 2 * prec);
61
copy(georef1, georef1 + baselen_ + 2 * prec, georef.begin());
62
}
63
64
void
Georef::Reverse
(
const
string
& georef, real& lat, real& lon,
65
int
& prec,
bool
centerp) {
66
int
len = int(georef.length());
67
if
(len >= 3 &&
68
toupper(georef[0]) ==
'I'
&&
69
toupper(georef[1]) ==
'N'
&&
70
toupper(georef[2]) ==
'V'
) {
71
lat = lon =
Math::NaN
();
72
return
;
73
}
74
if
(len < baselen_ - 2)
75
throw
GeographicErr
(
"Georef must start with at least 2 letters "
76
+ georef);
77
int
prec1 = (2 + len - baselen_) / 2 - 1;
78
int
k;
79
k =
Utility::lookup
(lontile_, georef[0]);
80
if
(k < 0)
81
throw
GeographicErr
(
"Bad longitude tile letter in georef "
+ georef);
82
real lon1 = k + lonorig_ / tile_;
83
k =
Utility::lookup
(lattile_, georef[1]);
84
if
(k < 0)
85
throw
GeographicErr
(
"Bad latitude tile letter in georef "
+ georef);
86
real lat1 = k + latorig_ / tile_;
87
real unit = 1;
88
if
(len > 2) {
89
unit *= tile_;
90
k =
Utility::lookup
(degrees_, georef[2]);
91
if
(k < 0)
92
throw
GeographicErr
(
"Bad longitude degree letter in georef "
+ georef);
93
lon1 = lon1 * tile_ + k;
94
if
(len < 4)
95
throw
GeographicErr
(
"Missing latitude degree letter in georef "
96
+ georef);
97
k =
Utility::lookup
(degrees_, georef[3]);
98
if
(k < 0)
99
throw
GeographicErr
(
"Bad latitude degree letter in georef "
+ georef);
100
lat1 = lat1 * tile_ + k;
101
if
(prec1 > 0) {
102
if
(georef.find_first_not_of(digits_, baselen_) != string::npos)
103
throw
GeographicErr
(
"Non digits in trailing portion of georef "
104
+ georef.substr(baselen_));
105
if
(len % 2)
106
throw
GeographicErr
(
"Georef must end with an even number of digits "
107
+ georef.substr(baselen_));
108
if
(prec1 == 1)
109
throw
GeographicErr
(
"Georef needs at least 4 digits for minutes "
110
+ georef.substr(baselen_));
111
if
(prec1 > maxprec_)
112
throw
GeographicErr
(
"More than "
+
Utility::str
(2*maxprec_)
113
+
" digits in georef "
114
+ georef.substr(baselen_));
115
for
(
int
i = 0; i < prec1; ++i) {
116
int
m = i ? base_ : 6;
117
unit *= m;
118
int
119
x =
Utility::lookup
(digits_, georef[baselen_ + i]),
120
y =
Utility::lookup
(digits_, georef[baselen_ + i + prec1]);
121
if
(!(i || (x < m && y < m)))
122
throw
GeographicErr
(
"Minutes terms in georef must be less than 60 "
123
+ georef.substr(baselen_));
124
lon1 = m * lon1 + x;
125
lat1 = m * lat1 + y;
126
}
127
}
128
}
129
if
(centerp) {
130
unit *= 2; lat1 = 2 * lat1 + 1; lon1 = 2 * lon1 + 1;
131
}
132
lat = (tile_ * lat1) / unit;
133
lon = (tile_ * lon1) / unit;
134
prec = prec1;
135
}
136
137
}
// namespace GeographicLib
real
GeographicLib::Math::real real
Definition
Geod3Solve.cpp:25
Georef.hpp
Header for GeographicLib::Georef class.
Utility.hpp
Header for GeographicLib::Utility class.
GeographicLib::GeographicErr
Exception handling for GeographicLib.
Definition
Constants.hpp:344
GeographicLib::Georef::Forward
static void Forward(real lat, real lon, int prec, std::string &georef)
Definition
Georef.cpp:22
GeographicLib::Georef::Reverse
static void Reverse(const std::string &georef, real &lat, real &lon, int &prec, bool centerp=true)
Definition
Georef.cpp:64
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::NaN
static T NaN()
Definition
Math.cpp:301
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
src
Georef.cpp
Generated by
1.17.0