17 const char*
const DMS::hemispheres_ =
"SNWE";
18 const char*
const DMS::signs_ =
"-+";
19 const char*
const DMS::digits_ =
"0123456789";
20 const char*
const DMS::dmsindicators_ =
"D'\":";
21 const char*
const DMS::components_[] = {
"degrees",
"minutes",
"seconds"};
24 void DMS::replace(std::string& s,
const std::string& pat,
char c) {
25 string::size_type p = 0;
26 int count = c ? 1 : 0;
29 if (p == string::npos)
31 s.replace(p, pat.length(), count, c);
99 replace(dmsa,
"\xc2\xb0",
'd' );
100 replace(dmsa,
"\xc2\xba",
'd' );
101 replace(dmsa,
"\xe2\x81\xb0",
'd' );
102 replace(dmsa,
"\xcb\x9a",
'd' );
103 replace(dmsa,
"\xe2\x88\x98",
'd' );
105 replace(dmsa,
"\xe2\x80\xb2",
'\'');
106 replace(dmsa,
"\xe2\x80\xb5",
'\'');
107 replace(dmsa,
"\xc2\xb4",
'\'');
108 replace(dmsa,
"\xe2\x80\x98",
'\'');
109 replace(dmsa,
"\xe2\x80\x99",
'\'');
110 replace(dmsa,
"\xe2\x80\x9b",
'\'');
111 replace(dmsa,
"\xca\xb9",
'\'');
112 replace(dmsa,
"\xcb\x8a",
'\'');
113 replace(dmsa,
"\xcb\x8b",
'\'');
115 replace(dmsa,
"\xe2\x80\xb3",
'"' );
116 replace(dmsa,
"\xe2\x80\xb6",
'"' );
117 replace(dmsa,
"\xcb\x9d",
'"' );
118 replace(dmsa,
"\xe2\x80\x9c",
'"' );
119 replace(dmsa,
"\xe2\x80\x9d",
'"' );
120 replace(dmsa,
"\xe2\x80\x9f",
'"' );
121 replace(dmsa,
"\xca\xba",
'"' );
123 replace(dmsa,
"\xe2\x9e\x95",
'+' );
124 replace(dmsa,
"\xe2\x81\xa4",
'+' );
126 replace(dmsa,
"\xe2\x80\x90",
'-' );
127 replace(dmsa,
"\xe2\x80\x91",
'-' );
128 replace(dmsa,
"\xe2\x80\x93",
'-' );
129 replace(dmsa,
"\xe2\x80\x94",
'-' );
130 replace(dmsa,
"\xe2\x88\x92",
'-' );
131 replace(dmsa,
"\xe2\x9e\x96",
'-' );
133 replace(dmsa,
"\xc2\xa0",
'\0');
134 replace(dmsa,
"\xe2\x80\x87",
'\0');
135 replace(dmsa,
"\xe2\x80\x89",
'\0');
136 replace(dmsa,
"\xe2\x80\x8a",
'\0');
137 replace(dmsa,
"\xe2\x80\x8b",
'\0');
138 replace(dmsa,
"\xe2\x80\xaf",
'\0');
139 replace(dmsa,
"\xe2\x81\xa3",
'\0');
141 replace(dmsa,
"\xb0",
'd' );
142 replace(dmsa,
"\xba",
'd' );
143 replace(dmsa,
"*",
'd' );
144 replace(dmsa,
"`",
'\'');
145 replace(dmsa,
"\xb4",
'\'');
153 replace(dmsa,
"\xa0",
'\0');
154 replace(dmsa,
"''",
'"' );
157 end = unsigned(dmsa.size());
158 while (beg < end && isspace(dmsa[beg]))
160 while (beg < end && isspace(dmsa[end - 1]))
167 for (string::size_type p = beg, pb; p < end; p = pb, ++i) {
168 string::size_type pa = p;
176 pb = min(dmsa.find_first_of(signs_, pa), end);
178 v += InternalDecode(dmsa.substr(p, pb - p), ind2);
181 else if (!(ind2 ==
NONE || ind1 == ind2))
182 throw GeographicErr(
"Incompatible hemisphere specifier in " +
183 dmsa.substr(beg, pb - beg));
187 dmsa.substr(beg, end - beg));
192 Math::real DMS::InternalDecode(
const string& dmsa, flag& ind) {
193 const int maxcomponents = 3;
199 end = unsigned(dmsa.size());
202 if (end > beg && (k =
Utility::lookup(hemispheres_, dmsa[beg])) >= 0) {
204 sign = k % 2 ? 1 : -1;
207 if (end > beg && (k =
Utility::lookup(hemispheres_, dmsa[end-1])) >= 0) {
210 if (toupper(dmsa[beg - 1]) == toupper(dmsa[end - 1]))
211 errormsg =
"Repeated hemisphere indicators "
213 +
" in " + dmsa.substr(beg - 1, end - beg + 1);
215 errormsg =
"Contradictory hemisphere indicators "
218 + dmsa.substr(beg - 1, end - beg + 1);
222 sign = k % 2 ? 1 : -1;
233 errormsg =
"Empty or incomplete DMS string " + dmsa;
236 real ipieces[maxcomponents] = {0, 0, 0};
237 real fpieces[maxcomponents] = {0, 0, 0};
241 unsigned ncurrent = 0, p = beg;
242 bool pointseen =
false;
243 unsigned digcount = 0, intcount = 0;
251 icurrent = 10 * icurrent + k;
254 }
else if (x ==
'.') {
256 errormsg =
"Multiple decimal points in "
257 + dmsa.substr(beg, end - beg);
263 if (k >= maxcomponents) {
265 errormsg =
"Illegal for : to appear at the end of " +
266 dmsa.substr(beg, end - beg);
271 if (
unsigned(k) == npiece - 1) {
272 errormsg =
"Repeated " + string(components_[k]) +
273 " component in " + dmsa.substr(beg, end - beg);
275 }
else if (
unsigned(k) < npiece) {
276 errormsg = string(components_[k]) +
" component follows "
277 + string(components_[npiece - 1]) +
" component in "
278 + dmsa.substr(beg, end - beg);
282 errormsg =
"Missing numbers in " + string(components_[k]) +
283 " component of " + dmsa.substr(beg, end - beg);
287 istringstream s(dmsa.substr(p - intcount - digcount - 1,
288 intcount + digcount));
292 ipieces[k] = icurrent;
293 fpieces[k] = icurrent + fcurrent;
296 if (npiece >= maxcomponents) {
297 errormsg =
"More than 3 DMS components in "
298 + dmsa.substr(beg, end - beg);
301 icurrent = fcurrent = 0;
302 ncurrent = digcount = intcount = 0;
305 errormsg =
"Internal sign in DMS string "
306 + dmsa.substr(beg, end - beg);
309 errormsg =
"Illegal character " +
Utility::str(x) +
" in DMS string "
310 + dmsa.substr(beg, end - beg);
314 if (!errormsg.empty())
317 if (npiece >= maxcomponents) {
318 errormsg =
"Extra text following seconds in DMS string "
319 + dmsa.substr(beg, end - beg);
323 errormsg =
"Missing numbers in trailing component of "
324 + dmsa.substr(beg, end - beg);
328 istringstream s(dmsa.substr(p - intcount - digcount,
329 intcount + digcount));
333 ipieces[npiece] = icurrent;
334 fpieces[npiece] = icurrent + fcurrent;
336 if (pointseen && digcount == 0) {
337 errormsg =
"Decimal point in non-terminal component of "
338 + dmsa.substr(beg, end - beg);
344 +
" not in range [0, " + to_string(
Math::dm) +
")";
349 +
" not in range [0, " + to_string(
Math::ms) +
")";
363 throw GeographicErr(errormsg);
370 real& lat, real& lon,
380 }
else if (ia ==
NONE)
386 + strb +
" interpreted as "
387 + (ia ==
LATITUDE ?
"latitudes" :
"longitudes"));
393 +
"d not in [-" + to_string(
Math::qd)
394 +
"d, " + to_string(
Math::qd) +
"d]");
401 real ang =
Decode(angstr, ind);
404 +
" includes a hemisphere, N/E/W/S");
410 real azi =
Decode(azistr, ind);
413 +
" has a latitude hemisphere, N/S");
421 if (!isfinite(angle))
422 return angle < 0 ? string(
"-inf") :
423 (angle > 0 ? string(
"inf") : string(
"nan"));
439 int sign = signbit(angle) ? -1 : 1;
445 idegree = trailing ==
DEGREE ? 0 : floor(angle),
446 fdegree = (angle - idegree) * scale;
447 string s =
Utility::str(fdegree, prec), degree, minute, second;
453 string::size_type p = s.find_first_of(
'.');
459 if (p == string::npos)
482 if (ind ==
NONE && sign < 0)
488 str << setw(1 + min(
int(ind), 2) + prec);
494 str << setw(1 + min(
int(ind), 2));
495 str << degree << (dmssep ? dmssep : char(tolower(dmsindicators_[0])))
496 << setw(2 + prec) << minute;
498 str << char(tolower(dmsindicators_[1]));
502 str << setw(1 + min(
int(ind), 2));
503 str << degree << (dmssep ? dmssep : char(tolower(dmsindicators_[0])))
505 << minute << (dmssep ? dmssep : char(tolower(dmsindicators_[1])))
506 << setw(2 + prec) << second;
508 str << char(tolower(dmsindicators_[2]));
512 str << hemispheres_[(ind ==
LATITUDE ? 0 : 2) + (sign < 0 ? 0 : 1)];
Header for GeographicLib::DMS class.
GeographicLib::Math::real real
Header for GeographicLib::Utility class.
static Math::real DecodeAzimuth(const std::string &azistr)
static Math::real DecodeAngle(const std::string &angstr)
static std::string Encode(real angle, component trailing, unsigned prec, flag ind=NONE, char dmssep=char(0))
static void DecodeLatLon(const std::string &dmsa, const std::string &dmsb, real &lat, real &lon, bool longfirst=false)
static Math::real Decode(const std::string &dms, flag &ind)
Exception handling for GeographicLib.
static constexpr int dm
minutes per degree
static constexpr int ds
seconds per degree
static constexpr int qd
degrees per quarter turn
static T AngNormalize(T x)
static constexpr int td
degrees per turn
static constexpr int ms
seconds per minute
static int extra_digits()
static int lookup(const std::string &s, char c)
static T nummatch(const std::string &s)
static std::string str(T x, int p=-1)
Namespace for GeographicLib.