geographiclib 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +12 -0
  3. data/LICENSE +24 -0
  4. data/ext/geographiclib/Accumulator.cpp +23 -0
  5. data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
  6. data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
  7. data/ext/geographiclib/CassiniSoldner.cpp +89 -0
  8. data/ext/geographiclib/CircularEngine.cpp +96 -0
  9. data/ext/geographiclib/DMS.cpp +381 -0
  10. data/ext/geographiclib/Ellipsoid.cpp +125 -0
  11. data/ext/geographiclib/EllipticFunction.cpp +512 -0
  12. data/ext/geographiclib/GARS.cpp +122 -0
  13. data/ext/geographiclib/GeoCoords.cpp +175 -0
  14. data/ext/geographiclib/Geocentric.cpp +172 -0
  15. data/ext/geographiclib/Geodesic.cpp +1908 -0
  16. data/ext/geographiclib/GeodesicExact.cpp +927 -0
  17. data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
  18. data/ext/geographiclib/GeodesicLine.cpp +321 -0
  19. data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
  20. data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
  21. data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
  22. data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
  23. data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
  24. data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
  25. data/ext/geographiclib/GeographicLib/Config.h +12 -0
  26. data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
  27. data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
  28. data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
  29. data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
  30. data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
  31. data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
  32. data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
  33. data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
  34. data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
  35. data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
  36. data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
  37. data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
  38. data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
  39. data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
  40. data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
  41. data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
  42. data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
  43. data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
  44. data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
  45. data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
  46. data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
  47. data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
  48. data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
  49. data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
  50. data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
  51. data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
  52. data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
  53. data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
  54. data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
  55. data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
  56. data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
  57. data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
  58. data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
  59. data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
  60. data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
  61. data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
  62. data/ext/geographiclib/Geohash.cpp +102 -0
  63. data/ext/geographiclib/Geoid.cpp +509 -0
  64. data/ext/geographiclib/Georef.cpp +135 -0
  65. data/ext/geographiclib/Gnomonic.cpp +85 -0
  66. data/ext/geographiclib/GravityCircle.cpp +129 -0
  67. data/ext/geographiclib/GravityModel.cpp +360 -0
  68. data/ext/geographiclib/LambertConformalConic.cpp +456 -0
  69. data/ext/geographiclib/LocalCartesian.cpp +62 -0
  70. data/ext/geographiclib/MGRS.cpp +461 -0
  71. data/ext/geographiclib/MagneticCircle.cpp +52 -0
  72. data/ext/geographiclib/MagneticModel.cpp +269 -0
  73. data/ext/geographiclib/Math.cpp +63 -0
  74. data/ext/geographiclib/NormalGravity.cpp +262 -0
  75. data/ext/geographiclib/OSGB.cpp +167 -0
  76. data/ext/geographiclib/PolarStereographic.cpp +108 -0
  77. data/ext/geographiclib/PolygonArea.cpp +204 -0
  78. data/ext/geographiclib/Rhumb.cpp +383 -0
  79. data/ext/geographiclib/SphericalEngine.cpp +477 -0
  80. data/ext/geographiclib/TransverseMercator.cpp +603 -0
  81. data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
  82. data/ext/geographiclib/UTMUPS.cpp +296 -0
  83. data/ext/geographiclib/Utility.cpp +61 -0
  84. data/ext/geographiclib/extconf.rb +3 -0
  85. data/ext/geographiclib/geographiclib.cpp +62 -0
  86. data/lib/geographiclib.rb +20 -0
  87. metadata +140 -0
@@ -0,0 +1,612 @@
1
+ /**
2
+ * \file Utility.hpp
3
+ * \brief Header for GeographicLib::Utility class
4
+ *
5
+ * Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
6
+ * under the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ **********************************************************************/
9
+
10
+ #if !defined(GEOGRAPHICLIB_UTILITY_HPP)
11
+ #define GEOGRAPHICLIB_UTILITY_HPP 1
12
+
13
+ #include <GeographicLib/Constants.hpp>
14
+ #include <iomanip>
15
+ #include <vector>
16
+ #include <sstream>
17
+ #include <cctype>
18
+ #include <ctime>
19
+
20
+ #if defined(_MSC_VER)
21
+ // Squelch warnings about constant conditional expressions and unsafe gmtime
22
+ # pragma warning (push)
23
+ # pragma warning (disable: 4127 4996)
24
+ #endif
25
+
26
+ namespace GeographicLib {
27
+
28
+ /**
29
+ * \brief Some utility routines for %GeographicLib
30
+ *
31
+ * Example of use:
32
+ * \include example-Utility.cpp
33
+ **********************************************************************/
34
+ class GEOGRAPHICLIB_EXPORT Utility {
35
+ private:
36
+ static bool gregorian(int y, int m, int d) {
37
+ // The original cut over to the Gregorian calendar in Pope Gregory XIII's
38
+ // time had 1582-10-04 followed by 1582-10-15. Here we implement the
39
+ // switch over used by the English-speaking world where 1752-09-02 was
40
+ // followed by 1752-09-14. We also assume that the year always begins
41
+ // with January 1, whereas in reality it often was reckoned to begin in
42
+ // March.
43
+ return 100 * (100 * y + m) + d >= 17520914; // or 15821004
44
+ }
45
+ static bool gregorian(int s) {
46
+ return s >= 639799; // 1752-09-14
47
+ }
48
+ public:
49
+
50
+ /**
51
+ * Convert a date to the day numbering sequentially starting with
52
+ * 0001-01-01 as day 1.
53
+ *
54
+ * @param[in] y the year (must be positive).
55
+ * @param[in] m the month, Jan = 1, etc. (must be positive). Default = 1.
56
+ * @param[in] d the day of the month (must be positive). Default = 1.
57
+ * @return the sequential day number.
58
+ **********************************************************************/
59
+ static int day(int y, int m = 1, int d = 1) {
60
+ // Convert from date to sequential day and vice versa
61
+ //
62
+ // Here is some code to convert a date to sequential day and vice
63
+ // versa. The sequential day is numbered so that January 1, 1 AD is day 1
64
+ // (a Saturday). So this is offset from the "Julian" day which starts the
65
+ // numbering with 4713 BC.
66
+ //
67
+ // This is inspired by a talk by John Conway at the John von Neumann
68
+ // National Supercomputer Center when he described his Doomsday algorithm
69
+ // for figuring the day of the week. The code avoids explicitly doing ifs
70
+ // (except for the decision of whether to use the Julian or Gregorian
71
+ // calendar). Instead the equivalent result is achieved using integer
72
+ // arithmetic. I got this idea from the routine for the day of the week
73
+ // in MACLisp (I believe that that routine was written by Guy Steele).
74
+ //
75
+ // There are three issues to take care of
76
+ //
77
+ // 1. the rules for leap years,
78
+ // 2. the inconvenient placement of leap days at the end of February,
79
+ // 3. the irregular pattern of month lengths.
80
+ //
81
+ // We deal with these as follows:
82
+ //
83
+ // 1. Leap years are given by simple rules which are straightforward to
84
+ // accommodate.
85
+ //
86
+ // 2. We simplify the calculations by moving January and February to the
87
+ // previous year. Here we internally number the months March–December,
88
+ // January, February as 0–9, 10, 11.
89
+ //
90
+ // 3. The pattern of month lengths from March through January is regular
91
+ // with a 5-month period—31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31. The
92
+ // 5-month period is 153 days long. Since February is now at the end of
93
+ // the year, we don't need to include its length in this part of the
94
+ // calculation.
95
+ bool greg = gregorian(y, m, d);
96
+ y += (m + 9) / 12 - 1; // Move Jan and Feb to previous year,
97
+ m = (m + 9) % 12; // making March month 0.
98
+ return
99
+ (1461 * y) / 4 // Julian years converted to days. Julian year is 365 +
100
+ // 1/4 = 1461/4 days.
101
+ // Gregorian leap year corrections. The 2 offset with respect to the
102
+ // Julian calendar synchronizes the vernal equinox with that at the time
103
+ // of the Council of Nicea (325 AD).
104
+ + (greg ? (y / 100) / 4 - (y / 100) + 2 : 0)
105
+ + (153 * m + 2) / 5 // The zero-based start of the m'th month
106
+ + d - 1 // The zero-based day
107
+ - 305; // The number of days between March 1 and December 31.
108
+ // This makes 0001-01-01 day 1
109
+ }
110
+
111
+ /**
112
+ * Convert a date to the day numbering sequentially starting with
113
+ * 0001-01-01 as day 1.
114
+ *
115
+ * @param[in] y the year (must be positive).
116
+ * @param[in] m the month, Jan = 1, etc. (must be positive). Default = 1.
117
+ * @param[in] d the day of the month (must be positive). Default = 1.
118
+ * @param[in] check whether to check the date.
119
+ * @exception GeographicErr if the date is invalid and \e check is true.
120
+ * @return the sequential day number.
121
+ **********************************************************************/
122
+ static int day(int y, int m, int d, bool check) {
123
+ int s = day(y, m, d);
124
+ if (!check)
125
+ return s;
126
+ int y1, m1, d1;
127
+ date(s, y1, m1, d1);
128
+ if (!(s > 0 && y == y1 && m == m1 && d == d1))
129
+ throw GeographicErr("Invalid date " +
130
+ str(y) + "-" + str(m) + "-" + str(d)
131
+ + (s > 0 ? "; use " +
132
+ str(y1) + "-" + str(m1) + "-" + str(d1) :
133
+ " before 0001-01-01"));
134
+ return s;
135
+ }
136
+
137
+ /**
138
+ * Given a day (counting from 0001-01-01 as day 1), return the date.
139
+ *
140
+ * @param[in] s the sequential day number (must be positive)
141
+ * @param[out] y the year.
142
+ * @param[out] m the month, Jan = 1, etc.
143
+ * @param[out] d the day of the month.
144
+ **********************************************************************/
145
+ static void date(int s, int& y, int& m, int& d) {
146
+ int c = 0;
147
+ bool greg = gregorian(s);
148
+ s += 305; // s = 0 on March 1, 1BC
149
+ if (greg) {
150
+ s -= 2; // The 2 day Gregorian offset
151
+ // Determine century with the Gregorian rules for leap years. The
152
+ // Gregorian year is 365 + 1/4 - 1/100 + 1/400 = 146097/400 days.
153
+ c = (4 * s + 3) / 146097;
154
+ s -= (c * 146097) / 4; // s = 0 at beginning of century
155
+ }
156
+ y = (4 * s + 3) / 1461; // Determine the year using Julian rules.
157
+ s -= (1461 * y) / 4; // s = 0 at start of year, i.e., March 1
158
+ y += c * 100; // Assemble full year
159
+ m = (5 * s + 2) / 153; // Determine the month
160
+ s -= (153 * m + 2) / 5; // s = 0 at beginning of month
161
+ d = s + 1; // Determine day of month
162
+ y += (m + 2) / 12; // Move Jan and Feb back to original year
163
+ m = (m + 2) % 12 + 1; // Renumber the months so January = 1
164
+ }
165
+
166
+ /**
167
+ * Given a date as a string in the format yyyy, yyyy-mm, or yyyy-mm-dd,
168
+ * return the numeric values for the year, month, and day. No checking is
169
+ * done on these values. The string "now" is interpreted as the present
170
+ * date (in UTC).
171
+ *
172
+ * @param[in] s the date in string format.
173
+ * @param[out] y the year.
174
+ * @param[out] m the month, Jan = 1, etc.
175
+ * @param[out] d the day of the month.
176
+ * @exception GeographicErr is \e s is malformed.
177
+ **********************************************************************/
178
+ static void date(const std::string& s, int& y, int& m, int& d) {
179
+ if (s == "now") {
180
+ std::time_t t = std::time(0);
181
+ struct tm* now = gmtime(&t);
182
+ y = now->tm_year + 1900;
183
+ m = now->tm_mon + 1;
184
+ d = now->tm_mday;
185
+ return;
186
+ }
187
+ int y1, m1 = 1, d1 = 1;
188
+ const char* digits = "0123456789";
189
+ std::string::size_type p1 = s.find_first_not_of(digits);
190
+ if (p1 == std::string::npos)
191
+ y1 = num<int>(s);
192
+ else if (s[p1] != '-')
193
+ throw GeographicErr("Delimiter not hyphen in date " + s);
194
+ else if (p1 == 0)
195
+ throw GeographicErr("Empty year field in date " + s);
196
+ else {
197
+ y1 = num<int>(s.substr(0, p1));
198
+ if (++p1 == s.size())
199
+ throw GeographicErr("Empty month field in date " + s);
200
+ std::string::size_type p2 = s.find_first_not_of(digits, p1);
201
+ if (p2 == std::string::npos)
202
+ m1 = num<int>(s.substr(p1));
203
+ else if (s[p2] != '-')
204
+ throw GeographicErr("Delimiter not hyphen in date " + s);
205
+ else if (p2 == p1)
206
+ throw GeographicErr("Empty month field in date " + s);
207
+ else {
208
+ m1 = num<int>(s.substr(p1, p2 - p1));
209
+ if (++p2 == s.size())
210
+ throw GeographicErr("Empty day field in date " + s);
211
+ d1 = num<int>(s.substr(p2));
212
+ }
213
+ }
214
+ y = y1; m = m1; d = d1;
215
+ }
216
+
217
+ /**
218
+ * Given the date, return the day of the week.
219
+ *
220
+ * @param[in] y the year (must be positive).
221
+ * @param[in] m the month, Jan = 1, etc. (must be positive).
222
+ * @param[in] d the day of the month (must be positive).
223
+ * @return the day of the week with Sunday, Monday--Saturday = 0,
224
+ * 1--6.
225
+ **********************************************************************/
226
+ static int dow(int y, int m, int d) { return dow(day(y, m, d)); }
227
+
228
+ /**
229
+ * Given the sequential day, return the day of the week.
230
+ *
231
+ * @param[in] s the sequential day (must be positive).
232
+ * @return the day of the week with Sunday, Monday--Saturday = 0,
233
+ * 1--6.
234
+ **********************************************************************/
235
+ static int dow(int s) {
236
+ return (s + 5) % 7; // The 5 offset makes day 1 (0001-01-01) a Saturday.
237
+ }
238
+
239
+ /**
240
+ * Convert a string representing a date to a fractional year.
241
+ *
242
+ * @tparam T the type of the argument.
243
+ * @param[in] s the string to be converted.
244
+ * @exception GeographicErr if \e s can't be interpreted as a date.
245
+ * @return the fractional year.
246
+ *
247
+ * The string is first read as an ordinary number (e.g., 2010 or 2012.5);
248
+ * if this is successful, the value is returned. Otherwise the string
249
+ * should be of the form yyyy-mm or yyyy-mm-dd and this is converted to a
250
+ * number with 2010-01-01 giving 2010.0 and 2012-07-03 giving 2012.5.
251
+ **********************************************************************/
252
+ template<typename T> static T fractionalyear(const std::string& s) {
253
+ try {
254
+ return num<T>(s);
255
+ }
256
+ catch (const std::exception&) {
257
+ }
258
+ int y, m, d;
259
+ date(s, y, m, d);
260
+ int t = day(y, m, d, true);
261
+ return T(y) + T(t - day(y)) / T(day(y + 1) - day(y));
262
+ }
263
+
264
+ /**
265
+ * Convert a object of type T to a string.
266
+ *
267
+ * @tparam T the type of the argument.
268
+ * @param[in] x the value to be converted.
269
+ * @param[in] p the precision used (default &minus;1).
270
+ * @exception std::bad_alloc if memory for the string can't be allocated.
271
+ * @return the string representation.
272
+ *
273
+ * If \e p &ge; 0, then the number fixed format is used with p bits of
274
+ * precision. With p < 0, there is no manipulation of the format.
275
+ **********************************************************************/
276
+ template<typename T> static std::string str(T x, int p = -1) {
277
+ std::ostringstream s;
278
+ if (p >= 0) s << std::fixed << std::setprecision(p);
279
+ s << x; return s.str();
280
+ }
281
+
282
+ /**
283
+ * Convert a Math::real object to a string.
284
+ *
285
+ * @param[in] x the value to be converted.
286
+ * @param[in] p the precision used (default &minus;1).
287
+ * @exception std::bad_alloc if memory for the string can't be allocated.
288
+ * @return the string representation.
289
+ *
290
+ * If \e p &ge; 0, then the number fixed format is used with p bits of
291
+ * precision. With p < 0, there is no manipulation of the format. This is
292
+ * an overload of str<T> which deals with inf and nan.
293
+ **********************************************************************/
294
+ static std::string str(Math::real x, int p = -1) {
295
+ if (!Math::isfinite(x))
296
+ return x < 0 ? std::string("-inf") :
297
+ (x > 0 ? std::string("inf") : std::string("nan"));
298
+ std::ostringstream s;
299
+ #if GEOGRAPHICLIB_PRECISION == 4
300
+ // boost-quadmath treats precision == 0 as "use as many digits as
301
+ // necessary" (see https://svn.boost.org/trac/boost/ticket/10103), so...
302
+ using std::floor; using std::fmod;
303
+ if (p == 0) {
304
+ x += Math::real(0.5);
305
+ Math::real ix = floor(x);
306
+ // Implement the "round ties to even" rule
307
+ x = (ix == x && fmod(ix, Math::real(2)) == 1) ? ix - 1 : ix;
308
+ s << std::fixed << std::setprecision(1) << x;
309
+ std::string r(s.str());
310
+ // strip off trailing ".0"
311
+ return r.substr(0, (std::max)(int(r.size()) - 2, 0));
312
+ }
313
+ #endif
314
+ if (p >= 0) s << std::fixed << std::setprecision(p);
315
+ s << x; return s.str();
316
+ }
317
+
318
+ /**
319
+ * Convert a string to an object of type T.
320
+ *
321
+ * @tparam T the type of the return value.
322
+ * @param[in] s the string to be converted.
323
+ * @exception GeographicErr is \e s is not readable as a T.
324
+ * @return object of type T
325
+ *
326
+ * White space at the beginning and end of \e s is ignored.
327
+ **********************************************************************/
328
+ template<typename T> static T num(const std::string& s) {
329
+ T x;
330
+ std::string errmsg;
331
+ std::string::size_type
332
+ beg = 0,
333
+ end = unsigned(s.size());
334
+ while (beg < end && isspace(s[beg]))
335
+ ++beg;
336
+ while (beg < end && isspace(s[end - 1]))
337
+ --end;
338
+ std::string t = s.substr(beg, end-beg);
339
+ do { // Executed once (provides the ability to break)
340
+ std::istringstream is(t);
341
+ if (!(is >> x)) {
342
+ errmsg = "Cannot decode " + t;
343
+ break;
344
+ }
345
+ int pos = int(is.tellg()); // Returns -1 at end of string?
346
+ if (!(pos < 0 || pos == int(t.size()))) {
347
+ errmsg = "Extra text " + t.substr(pos) + " at end of " + t;
348
+ break;
349
+ }
350
+ return x;
351
+ } while (false);
352
+ x = std::numeric_limits<T>::is_integer ? 0 : nummatch<T>(t);
353
+ if (x == 0)
354
+ throw GeographicErr(errmsg);
355
+ return x;
356
+ }
357
+
358
+ /**
359
+ * Match "nan" and "inf" (and variants thereof) in a string.
360
+ *
361
+ * @tparam T the type of the return value.
362
+ * @param[in] s the string to be matched.
363
+ * @return appropriate special value (&plusmn;&infin;, nan) or 0 if none is
364
+ * found.
365
+ *
366
+ * White space is not allowed at the beginning or end of \e s.
367
+ **********************************************************************/
368
+ template<typename T> static T nummatch(const std::string& s) {
369
+ if (s.length() < 3)
370
+ return 0;
371
+ std::string t;
372
+ t.resize(s.length());
373
+ std::transform(s.begin(), s.end(), t.begin(), (int(*)(int))std::toupper);
374
+ for (size_t i = s.length(); i--;)
375
+ t[i] = char(std::toupper(s[i]));
376
+ int sign = t[0] == '-' ? -1 : 1;
377
+ std::string::size_type p0 = t[0] == '-' || t[0] == '+' ? 1 : 0;
378
+ std::string::size_type p1 = t.find_last_not_of('0');
379
+ if (p1 == std::string::npos || p1 + 1 < p0 + 3)
380
+ return 0;
381
+ // Strip off sign and trailing 0s
382
+ t = t.substr(p0, p1 + 1 - p0); // Length at least 3
383
+ if (t == "NAN" || t == "1.#QNAN" || t == "1.#SNAN" || t == "1.#IND" ||
384
+ t == "1.#R")
385
+ return Math::NaN<T>();
386
+ else if (t == "INF" || t == "1.#INF")
387
+ return sign * Math::infinity<T>();
388
+ return 0;
389
+ }
390
+
391
+ /**
392
+ * Read a simple fraction, e.g., 3/4, from a string to an object of type T.
393
+ *
394
+ * @tparam T the type of the return value.
395
+ * @param[in] s the string to be converted.
396
+ * @exception GeographicErr is \e s is not readable as a fraction of type T.
397
+ * @return object of type T
398
+ *
399
+ * <b>NOTE</b>: The msys shell under Windows converts arguments which look
400
+ * like pathnames into their Windows equivalents. As a result the argument
401
+ * "-1/300" gets mangled into something unrecognizable. A workaround is to
402
+ * use a floating point number in the numerator, i.e., "-1.0/300".
403
+ **********************************************************************/
404
+ template<typename T> static T fract(const std::string& s) {
405
+ std::string::size_type delim = s.find('/');
406
+ return
407
+ !(delim != std::string::npos && delim >= 1 && delim + 2 <= s.size()) ?
408
+ num<T>(s) :
409
+ // delim in [1, size() - 2]
410
+ num<T>(s.substr(0, delim)) / num<T>(s.substr(delim + 1));
411
+ }
412
+
413
+ /**
414
+ * Lookup up a character in a string.
415
+ *
416
+ * @param[in] s the string to be searched.
417
+ * @param[in] c the character to look for.
418
+ * @return the index of the first occurrence character in the string or
419
+ * &minus;1 is the character is not present.
420
+ *
421
+ * \e c is converted to upper case before search \e s. Therefore, it is
422
+ * intended that \e s should not contain any lower case letters.
423
+ **********************************************************************/
424
+ static int lookup(const std::string& s, char c) {
425
+ std::string::size_type r = s.find(char(toupper(c)));
426
+ return r == std::string::npos ? -1 : int(r);
427
+ }
428
+
429
+ /**
430
+ * Read data of type ExtT from a binary stream to an array of type IntT.
431
+ * The data in the file is in (bigendp ? big : little)-endian format.
432
+ *
433
+ * @tparam ExtT the type of the objects in the binary stream (external).
434
+ * @tparam IntT the type of the objects in the array (internal).
435
+ * @tparam bigendp true if the external storage format is big-endian.
436
+ * @param[in] str the input stream containing the data of type ExtT
437
+ * (external).
438
+ * @param[out] array the output array of type IntT (internal).
439
+ * @param[in] num the size of the array.
440
+ * @exception GeographicErr if the data cannot be read.
441
+ **********************************************************************/
442
+ template<typename ExtT, typename IntT, bool bigendp>
443
+ static inline void readarray(std::istream& str,
444
+ IntT array[], size_t num) {
445
+ #if GEOGRAPHICLIB_PRECISION < 4
446
+ if (sizeof(IntT) == sizeof(ExtT) &&
447
+ std::numeric_limits<IntT>::is_integer ==
448
+ std::numeric_limits<ExtT>::is_integer)
449
+ {
450
+ // Data is compatible (aside from the issue of endian-ness).
451
+ str.read(reinterpret_cast<char*>(array), num * sizeof(ExtT));
452
+ if (!str.good())
453
+ throw GeographicErr("Failure reading data");
454
+ if (bigendp != Math::bigendian) { // endian mismatch -> swap bytes
455
+ for (size_t i = num; i--;)
456
+ array[i] = Math::swab<IntT>(array[i]);
457
+ }
458
+ }
459
+ else
460
+ #endif
461
+ {
462
+ const int bufsize = 1024; // read this many values at a time
463
+ ExtT buffer[bufsize]; // temporary buffer
464
+ int k = int(num); // data values left to read
465
+ int i = 0; // index into output array
466
+ while (k) {
467
+ int n = (std::min)(k, bufsize);
468
+ str.read(reinterpret_cast<char*>(buffer), n * sizeof(ExtT));
469
+ if (!str.good())
470
+ throw GeographicErr("Failure reading data");
471
+ for (int j = 0; j < n; ++j)
472
+ // fix endian-ness and cast to IntT
473
+ array[i++] = IntT(bigendp == Math::bigendian ? buffer[j] :
474
+ Math::swab<ExtT>(buffer[j]));
475
+ k -= n;
476
+ }
477
+ }
478
+ return;
479
+ }
480
+
481
+ /**
482
+ * Read data of type ExtT from a binary stream to a vector array of type
483
+ * IntT. The data in the file is in (bigendp ? big : little)-endian
484
+ * format.
485
+ *
486
+ * @tparam ExtT the type of the objects in the binary stream (external).
487
+ * @tparam IntT the type of the objects in the array (internal).
488
+ * @tparam bigendp true if the external storage format is big-endian.
489
+ * @param[in] str the input stream containing the data of type ExtT
490
+ * (external).
491
+ * @param[out] array the output vector of type IntT (internal).
492
+ * @exception GeographicErr if the data cannot be read.
493
+ **********************************************************************/
494
+ template<typename ExtT, typename IntT, bool bigendp>
495
+ static inline void readarray(std::istream& str,
496
+ std::vector<IntT>& array) {
497
+ if (array.size() > 0)
498
+ readarray<ExtT, IntT, bigendp>(str, &array[0], array.size());
499
+ }
500
+
501
+ /**
502
+ * Write data in an array of type IntT as type ExtT to a binary stream.
503
+ * The data in the file is in (bigendp ? big : little)-endian format.
504
+ *
505
+ * @tparam ExtT the type of the objects in the binary stream (external).
506
+ * @tparam IntT the type of the objects in the array (internal).
507
+ * @tparam bigendp true if the external storage format is big-endian.
508
+ * @param[out] str the output stream for the data of type ExtT (external).
509
+ * @param[in] array the input array of type IntT (internal).
510
+ * @param[in] num the size of the array.
511
+ * @exception GeographicErr if the data cannot be written.
512
+ **********************************************************************/
513
+ template<typename ExtT, typename IntT, bool bigendp>
514
+ static inline void writearray(std::ostream& str,
515
+ const IntT array[], size_t num) {
516
+ #if GEOGRAPHICLIB_PRECISION < 4
517
+ if (sizeof(IntT) == sizeof(ExtT) &&
518
+ std::numeric_limits<IntT>::is_integer ==
519
+ std::numeric_limits<ExtT>::is_integer &&
520
+ bigendp == Math::bigendian)
521
+ {
522
+ // Data is compatible (including endian-ness).
523
+ str.write(reinterpret_cast<const char*>(array), num * sizeof(ExtT));
524
+ if (!str.good())
525
+ throw GeographicErr("Failure writing data");
526
+ }
527
+ else
528
+ #endif
529
+ {
530
+ const int bufsize = 1024; // write this many values at a time
531
+ ExtT buffer[bufsize]; // temporary buffer
532
+ int k = int(num); // data values left to write
533
+ int i = 0; // index into output array
534
+ while (k) {
535
+ int n = (std::min)(k, bufsize);
536
+ for (int j = 0; j < n; ++j)
537
+ // cast to ExtT and fix endian-ness
538
+ buffer[j] = bigendp == Math::bigendian ? ExtT(array[i++]) :
539
+ Math::swab<ExtT>(ExtT(array[i++]));
540
+ str.write(reinterpret_cast<const char*>(buffer), n * sizeof(ExtT));
541
+ if (!str.good())
542
+ throw GeographicErr("Failure writing data");
543
+ k -= n;
544
+ }
545
+ }
546
+ return;
547
+ }
548
+
549
+ /**
550
+ * Write data in an array of type IntT as type ExtT to a binary stream.
551
+ * The data in the file is in (bigendp ? big : little)-endian format.
552
+ *
553
+ * @tparam ExtT the type of the objects in the binary stream (external).
554
+ * @tparam IntT the type of the objects in the array (internal).
555
+ * @tparam bigendp true if the external storage format is big-endian.
556
+ * @param[out] str the output stream for the data of type ExtT (external).
557
+ * @param[in] array the input vector of type IntT (internal).
558
+ * @exception GeographicErr if the data cannot be written.
559
+ **********************************************************************/
560
+ template<typename ExtT, typename IntT, bool bigendp>
561
+ static inline void writearray(std::ostream& str,
562
+ std::vector<IntT>& array) {
563
+ if (array.size() > 0)
564
+ writearray<ExtT, IntT, bigendp>(str, &array[0], array.size());
565
+ }
566
+
567
+ /**
568
+ * Parse a KEY VALUE line.
569
+ *
570
+ * @param[in] line the input line.
571
+ * @param[out] key the key.
572
+ * @param[out] val the value.
573
+ * @exception std::bad_alloc if memory for the internal strings can't be
574
+ * allocated.
575
+ * @return whether a key was found.
576
+ *
577
+ * A # character and everything after it are discarded. If the result is
578
+ * just white space, the routine returns false (and \e key and \e val are
579
+ * not set). Otherwise the first token is taken to be the key and the rest
580
+ * of the line (trimmed of leading and trailing white space) is the value.
581
+ **********************************************************************/
582
+ static bool ParseLine(const std::string& line,
583
+ std::string& key, std::string& val);
584
+
585
+ /**
586
+ * Set the binary precision of a real number.
587
+ *
588
+ * @param[in] ndigits the number of bits of precision. If ndigits is 0
589
+ * (the default), then determine the precision from the environment
590
+ * variable GEOGRAPHICLIB_DIGITS. If this is undefined, use ndigits =
591
+ * 256 (i.e., about 77 decimal digits).
592
+ * @return the resulting number of bits of precision.
593
+ *
594
+ * This only has an effect when GEOGRAPHICLIB_PRECISION == 5. The
595
+ * precision should only be set once and before calls to any other
596
+ * GeographicLib functions. (Several functions, for example Math::pi(),
597
+ * cache the return value in a static local variable. The precision needs
598
+ * to be set before a call to any such functions.) In multi-threaded
599
+ * applications, it is necessary also to set the precision in each thread
600
+ * (see the example GeoidToGTX.cpp).
601
+ **********************************************************************/
602
+ static int set_digits(int ndigits = 0);
603
+
604
+ };
605
+
606
+ } // namespace GeographicLib
607
+
608
+ #if defined(_MSC_VER)
609
+ # pragma warning (pop)
610
+ #endif
611
+
612
+ #endif // GEOGRAPHICLIB_UTILITY_HPP