15 # pragma warning (disable: 4127)
18 namespace GeographicLib {
22 const string DMS::hemispheres_ =
"SNWE";
23 const string DMS::signs_ =
"-+";
24 const string DMS::digits_ =
"0123456789";
25 const string DMS::dmsindicators_ =
"D'\":";
26 const string DMS::components_[] = {
"degrees",
"minutes",
"seconds"};
31 replace(dmsa,
"\xc2\xb0",
'd');
32 replace(dmsa,
"\xc2\xba",
'd');
33 replace(dmsa,
"\xe2\x81\xb0",
'd');
34 replace(dmsa,
"\xcb\x9a",
'd');
35 replace(dmsa,
"\xe2\x80\xb2",
'\'');
36 replace(dmsa,
"\xc2\xb4",
'\'');
37 replace(dmsa,
"\xe2\x80\x99",
'\'');
38 replace(dmsa,
"\xe2\x80\xb3",
'"');
39 replace(dmsa,
"\xe2\x80\x9d",
'"');
40 replace(dmsa,
"\xe2\x88\x92",
'-');
41 replace(dmsa,
"\xb0",
'd');
42 replace(dmsa,
"\xba",
'd');
43 replace(dmsa,
"\xb4",
'\'');
44 replace(dmsa,
"''",
'"');
47 end = unsigned(dmsa.size());
48 while (beg < end && isspace(dmsa[beg]))
50 while (beg < end && isspace(dmsa[end - 1]))
57 string::size_type p = dmsa.find_first_of(signs_, bega);
59 real v = InternalDecode(dmsa.substr(beg,
60 (p == string::npos ? end : p) - beg),
62 if (p == string::npos)
66 v += InternalDecode(dmsa.substr(p, end - p), ind2);
69 else if (ind1 == NONE || ind1 == ind2)
73 dmsa.substr(beg, p - beg) +
" and " +
74 dmsa.substr(p, end - p));
79 Math::real DMS::InternalDecode(
const std::string& dmsa, flag& ind) {
85 end = unsigned(dmsa.size());
89 ind1 = (k / 2) ? LONGITUDE : LATITUDE;
90 sign = k % 2 ? 1 : -1;
93 if (end > beg && (k =
Utility::lookup(hemispheres_, dmsa[end-1])) >= 0) {
96 if (toupper(dmsa[beg - 1]) == toupper(dmsa[end - 1]))
97 errormsg =
"Repeated hemisphere indicators "
99 +
" in " + dmsa.substr(beg - 1, end - beg + 1);
101 errormsg =
"Contradictory hemisphere indicators "
104 + dmsa.substr(beg - 1, end - beg + 1);
107 ind1 = (k / 2) ? LONGITUDE : LATITUDE;
108 sign = k % 2 ? 1 : -1;
119 errormsg =
"Empty or incomplete DMS string " + dmsa;
122 real ipieces[] = {0, 0, 0};
123 real fpieces[] = {0, 0, 0};
127 unsigned ncurrent = 0, p = beg;
128 bool pointseen =
false;
129 unsigned digcount = 0, intcount = 0;
137 icurrent = 10 * icurrent + k;
140 }
else if (x ==
'.') {
142 errormsg =
"Multiple decimal points in "
143 + dmsa.substr(beg, end - beg);
151 errormsg =
"Illegal for : to appear at the end of " +
152 dmsa.substr(beg, end - beg);
157 if (
unsigned(k) == npiece - 1) {
158 errormsg =
"Repeated " + components_[k] +
159 " component in " + dmsa.substr(beg, end - beg);
161 }
else if (
unsigned(k) < npiece) {
162 errormsg = components_[k] +
" component follows "
163 + components_[npiece - 1] +
" component in "
164 + dmsa.substr(beg, end - beg);
168 errormsg =
"Missing numbers in " + components_[k] +
169 " component of " + dmsa.substr(beg, end - beg);
173 istringstream s(dmsa.substr(p - intcount - digcount - 1,
174 intcount + digcount));
178 ipieces[k] = icurrent;
179 fpieces[k] = icurrent + fcurrent;
182 icurrent = fcurrent = 0;
183 ncurrent = digcount = intcount = 0;
186 errormsg =
"Internal sign in DMS string "
187 + dmsa.substr(beg, end - beg);
190 errormsg =
"Illegal character " +
Utility::str(x) +
" in DMS string "
191 + dmsa.substr(beg, end - beg);
195 if (!errormsg.empty())
199 errormsg =
"Extra text following seconds in DMS string "
200 + dmsa.substr(beg, end - beg);
204 errormsg =
"Missing numbers in trailing component of "
205 + dmsa.substr(beg, end - beg);
209 istringstream s(dmsa.substr(p - intcount - digcount,
210 intcount + digcount));
214 ipieces[npiece] = icurrent;
215 fpieces[npiece] = icurrent + fcurrent;
217 if (pointseen && digcount == 0) {
218 errormsg =
"Decimal point in non-terminal component of "
219 + dmsa.substr(beg, end - beg);
223 if (ipieces[1] >= 60) {
225 +
" not in range [0, 60)";
228 if (ipieces[2] >= 60) {
230 +
" not in range [0, 60)";
236 return real(sign) * (fpieces[0] + (fpieces[1] + fpieces[2] / 60) / 60);
238 real val = Utility::nummatch<real>(dmsa);
240 throw GeographicErr(errormsg);
247 real& lat, real& lon,
251 a = Decode(stra, ia);
252 b = Decode(strb, ib);
253 if (ia == NONE && ib == NONE) {
255 ia = swaplatlong ? LONGITUDE : LATITUDE;
256 ib = swaplatlong ? LATITUDE : LONGITUDE;
257 }
else if (ia == NONE)
258 ia =
flag(LATITUDE + LONGITUDE - ib);
260 ib =
flag(LATITUDE + LONGITUDE - ia);
263 + strb +
" interpreted as "
264 + (ia == LATITUDE ?
"latitudes" :
"longitudes"));
266 lat1 = ia == LATITUDE ? a : b,
267 lon1 = ia == LATITUDE ? b : a;
270 +
"d not in [-90d, 90d]");
271 if (lon1 < -540 || lon1 >= 540)
273 +
"d not in [-540d, 540d)");
280 real ang = Decode(angstr, ind);
283 +
" includes a hemisphere, N/E/W/S");
289 real azi = Decode(azistr, ind);
292 +
" has a latitude hemisphere, N/S");
293 if (azi < -540 || azi >= 540)
294 throw GeographicErr(
"Azimuth " + azistr +
" not in range [-540d, 540d)");
303 return angle < 0 ? string(
"-inf") :
304 (angle > 0 ? string(
"inf") : string(
"nan"));
310 for (
unsigned i = 0; i < unsigned(trailing); ++i)
312 for (
unsigned i = 0; i < prec; ++i)
315 angle -= floor(angle/360) * 360;
316 int sign = angle < 0 ? -1 : 1;
322 idegree = floor(angle),
323 fdegree = floor((angle - idegree) * scale +
real(0.5)) / scale;
328 real pieces[3] = {fdegree, 0, 0};
329 for (
unsigned i = 1; i <= unsigned(trailing); ++i) {
331 ip = floor(pieces[i - 1]),
332 fp = pieces[i - 1] - ip;
336 pieces[0] += idegree;
338 s << fixed << setfill(
'0');
339 if (ind == NONE && sign < 0)
344 s << setw(1 + min(
int(ind), 2) + prec + (prec ? 1 : 0));
350 s << setw(1 + min(
int(ind), 2));
352 << (dmssep ? dmssep : char(tolower(dmsindicators_[0])));
355 s << setw(2 + prec + (prec ? 1 : 0)) <<
Utility::str(pieces[1], prec);
357 s << char(tolower(dmsindicators_[1]));
362 << (dmssep ? dmssep : char(tolower(dmsindicators_[1])))
363 << setw(2 + prec + (prec ? 1 : 0)) << Utility::str(pieces[2], prec);
365 s << char(tolower(dmsindicators_[2]));
371 if (ind != NONE && ind != AZIMUTH)
372 s << hemispheres_[(ind == LATITUDE ? 0 : 2) + (sign < 0 ? 0 : 1)];
static T AngNormalize(T x)
static Math::real DecodeAngle(const std::string &angstr)
GeographicLib::Math::real real
Header for GeographicLib::Utility class.
static bool isfinite(T x)
static int extra_digits()
static std::string Encode(real angle, component trailing, unsigned prec, flag ind=NONE, char dmssep=char(0))
static Math::real DecodeAzimuth(const std::string &azistr)
static void DecodeLatLon(const std::string &dmsa, const std::string &dmsb, real &lat, real &lon, bool swaplatlong=false)
static Math::real Decode(const std::string &dms, flag &ind)
static std::string str(T x, int p=-1)
Exception handling for GeographicLib.
static int lookup(const std::string &s, char c)
Header for GeographicLib::DMS class.