15 # pragma warning (disable: 4127)
22 const char*
const DMS::hemispheres_ =
"SNWE";
23 const char*
const DMS::signs_ =
"-+";
24 const char*
const DMS::digits_ =
"0123456789";
25 const char*
const DMS::dmsindicators_ =
"D'\":";
26 const char*
const DMS::components_[] = {
"degrees",
"minutes",
"seconds"};
30 replace(dmsa,
"\xc2\xb0",
'd');
31 replace(dmsa,
"\xc2\xba",
'd');
32 replace(dmsa,
"\xe2\x81\xb0",
'd');
33 replace(dmsa,
"\xcb\x9a",
'd');
34 replace(dmsa,
"\xe2\x80\xb2",
'\'');
35 replace(dmsa,
"\xc2\xb4",
'\'');
36 replace(dmsa,
"\xe2\x80\x99",
'\'');
37 replace(dmsa,
"\xe2\x80\xb3",
'"');
38 replace(dmsa,
"\xe2\x80\x9d",
'"');
39 replace(dmsa,
"\xe2\x88\x92",
'-');
40 replace(dmsa,
"\xb0",
'd');
41 replace(dmsa,
"\xba",
'd');
42 replace(dmsa,
"\xb4",
'\'');
43 replace(dmsa,
"''",
'"');
46 end = unsigned(dmsa.size());
47 while (beg < end && isspace(dmsa[beg]))
49 while (beg < end && isspace(dmsa[end - 1]))
56 for (string::size_type p = beg, pb; p < end; p = pb, ++i) {
57 string::size_type pa = p;
65 pb = min(dmsa.find_first_of(signs_, pa), end);
67 v += InternalDecode(dmsa.substr(p, pb - p), ind2);
70 else if (!(ind2 == NONE || ind1 == ind2))
72 dmsa.substr(beg, pb - beg));
76 dmsa.substr(beg, end - beg));
81 Math::real DMS::InternalDecode(
const std::string& dmsa, flag& ind) {
82 const int maxcomponents = 3;
88 end = unsigned(dmsa.size());
92 ind1 = (k / 2) ? LONGITUDE : LATITUDE;
93 sign = k % 2 ? 1 : -1;
96 if (end > beg && (k =
Utility::lookup(hemispheres_, dmsa[end-1])) >= 0) {
99 if (toupper(dmsa[beg - 1]) == toupper(dmsa[end - 1]))
100 errormsg =
"Repeated hemisphere indicators "
102 +
" in " + dmsa.substr(beg - 1, end - beg + 1);
104 errormsg =
"Contradictory hemisphere indicators "
107 + dmsa.substr(beg - 1, end - beg + 1);
110 ind1 = (k / 2) ? LONGITUDE : LATITUDE;
111 sign = k % 2 ? 1 : -1;
122 errormsg =
"Empty or incomplete DMS string " + dmsa;
125 real ipieces[maxcomponents] = {0, 0, 0};
126 real fpieces[maxcomponents] = {0, 0, 0};
130 unsigned ncurrent = 0, p = beg;
131 bool pointseen =
false;
132 unsigned digcount = 0, intcount = 0;
140 icurrent = 10 * icurrent + k;
143 }
else if (x ==
'.') {
145 errormsg =
"Multiple decimal points in "
146 + dmsa.substr(beg, end - beg);
152 if (k >= maxcomponents) {
154 errormsg =
"Illegal for : to appear at the end of " +
155 dmsa.substr(beg, end - beg);
160 if (
unsigned(k) == npiece - 1) {
161 errormsg =
"Repeated " + string(components_[k]) +
162 " component in " + dmsa.substr(beg, end - beg);
164 }
else if (
unsigned(k) < npiece) {
165 errormsg = string(components_[k]) +
" component follows "
166 + string(components_[npiece - 1]) +
" component in "
167 + dmsa.substr(beg, end - beg);
171 errormsg =
"Missing numbers in " + string(components_[k]) +
172 " component of " + dmsa.substr(beg, end - beg);
176 istringstream s(dmsa.substr(p - intcount - digcount - 1,
177 intcount + digcount));
181 ipieces[k] = icurrent;
182 fpieces[k] = icurrent + fcurrent;
185 if (npiece >= maxcomponents) {
186 errormsg =
"More than 3 DMS components in "
187 + dmsa.substr(beg, end - beg);
190 icurrent = fcurrent = 0;
191 ncurrent = digcount = intcount = 0;
194 errormsg =
"Internal sign in DMS string "
195 + dmsa.substr(beg, end - beg);
198 errormsg =
"Illegal character " +
Utility::str(x) +
" in DMS string "
199 + dmsa.substr(beg, end - beg);
203 if (!errormsg.empty())
206 if (npiece >= maxcomponents) {
207 errormsg =
"Extra text following seconds in DMS string "
208 + dmsa.substr(beg, end - beg);
212 errormsg =
"Missing numbers in trailing component of "
213 + dmsa.substr(beg, end - beg);
217 istringstream s(dmsa.substr(p - intcount - digcount,
218 intcount + digcount));
222 ipieces[npiece] = icurrent;
223 fpieces[npiece] = icurrent + fcurrent;
225 if (pointseen && digcount == 0) {
226 errormsg =
"Decimal point in non-terminal component of "
227 + dmsa.substr(beg, end - beg);
231 if (ipieces[1] >= 60 || fpieces[1] > 60 ) {
233 +
" not in range [0, 60)";
236 if (ipieces[2] >= 60 || fpieces[2] > 60) {
238 +
" not in range [0, 60)";
246 (60*(60*fpieces[0] + fpieces[1]) + fpieces[2]) / 3600 :
248 (60*fpieces[0] + fpieces[1]) / 60 : fpieces[0] ) );
250 real val = Utility::nummatch<real>(dmsa);
252 throw GeographicErr(errormsg);
259 real& lat, real& lon,
263 a = Decode(stra, ia);
264 b = Decode(strb, ib);
265 if (ia == NONE && ib == NONE) {
267 ia = longfirst ? LONGITUDE : LATITUDE;
268 ib = longfirst ? LATITUDE : LONGITUDE;
269 }
else if (ia == NONE)
270 ia =
flag(LATITUDE + LONGITUDE - ib);
272 ib =
flag(LATITUDE + LONGITUDE - ia);
275 + strb +
" interpreted as "
276 + (ia == LATITUDE ?
"latitudes" :
"longitudes"));
278 lat1 = ia == LATITUDE ? a : b,
279 lon1 = ia == LATITUDE ? b : a;
282 +
"d not in [-90d, 90d]");
289 real ang = Decode(angstr, ind);
292 +
" includes a hemisphere, N/E/W/S");
298 real azi = Decode(azistr, ind);
301 +
" has a latitude hemisphere, N/S");
310 return angle < 0 ? string(
"-inf") :
311 (angle > 0 ? string(
"inf") : string(
"nan"));
317 for (
unsigned i = 0; i < unsigned(trailing); ++i)
319 for (
unsigned i = 0; i < prec; ++i)
322 angle -= floor(angle/360) * 360;
323 int sign = angle < 0 ? -1 : 1;
329 idegree = floor(angle),
330 fdegree = (angle - idegree) * scale +
real(0.5);
333 real f = floor(fdegree);
334 fdegree = (f == fdegree && fmod(f,
real(2)) == 1) ? f - 1 : f;
341 real pieces[3] = {fdegree, 0, 0};
342 for (
unsigned i = 1; i <= unsigned(trailing); ++i) {
344 ip = floor(pieces[i - 1]),
345 fp = pieces[i - 1] - ip;
349 pieces[0] += idegree;
351 s << fixed << setfill(
'0');
352 if (ind == NONE && sign < 0)
357 s << setw(1 + min(
int(ind), 2) + prec + (prec ? 1 : 0));
363 s << setw(1 + min(
int(ind), 2));
365 << (dmssep ? dmssep : char(tolower(dmsindicators_[0])));
368 s << setw(2 + prec + (prec ? 1 : 0)) <<
Utility::str(pieces[1], prec);
370 s << char(tolower(dmsindicators_[1]));
375 << (dmssep ? dmssep : char(tolower(dmsindicators_[1])))
376 << setw(2 + prec + (prec ? 1 : 0)) <<
Utility::str(pieces[2], prec);
378 s << char(tolower(dmsindicators_[2]));
384 if (ind != NONE && ind != AZIMUTH)
385 s << hemispheres_[(ind == LATITUDE ? 0 : 2) + (sign < 0 ? 0 : 1)];