GeographicLib
2.7
Toggle main menu visibility
Loading...
Searching...
No Matches
DMS.hpp
Go to the documentation of this file.
1
/**
2
* \file DMS.hpp
3
* \brief Header for GeographicLib::DMS class
4
*
5
* Copyright (c) Charles Karney (2008-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
#if !defined(GEOGRAPHICLIB_DMS_HPP)
11
#define GEOGRAPHICLIB_DMS_HPP 1
12
13
#include <
GeographicLib/Constants.hpp
>
14
#include <
GeographicLib/Utility.hpp
>
15
16
#if defined(_MSC_VER)
17
// Squelch warnings about unrepresentable characters
18
# pragma warning (push)
19
# pragma warning (disable: 4819)
20
#endif
21
22
namespace
GeographicLib
{
23
24
/**
25
* \brief Convert between degrees and the %DMS representation
26
*
27
* Parse a string representing degree, minutes, and seconds and return the
28
* angle in degrees and format an angle in degrees as degree, minutes, and
29
* seconds. In addition, handle NANs and infinities on input and output.
30
*
31
* Example of use:
32
* \include example-DMS.cpp
33
**********************************************************************/
34
class
GEOGRAPHICLIB_EXPORT
DMS {
35
public
:
36
37
/**
38
* Indicator for presence of hemisphere indicator (N/S/E/W) on latitudes
39
* and longitudes.
40
**********************************************************************/
41
enum
flag
{
42
/**
43
* No indicator present.
44
* @hideinitializer
45
**********************************************************************/
46
NONE
= 0,
47
/**
48
* Latitude indicator (N/S) present.
49
* @hideinitializer
50
**********************************************************************/
51
LATITUDE
= 1,
52
/**
53
* Longitude indicator (E/W) present.
54
* @hideinitializer
55
**********************************************************************/
56
LONGITUDE
= 2,
57
/**
58
* Used in Encode to indicate output of an azimuth in [000, 360) with no
59
* letter indicator.
60
* @hideinitializer
61
**********************************************************************/
62
AZIMUTH
= 3,
63
/**
64
* Used in Encode to indicate output of a plain number.
65
* @hideinitializer
66
**********************************************************************/
67
NUMBER
= 4,
68
};
69
70
/**
71
* Indicator for trailing units on an angle.
72
**********************************************************************/
73
enum
component
{
74
/**
75
* Trailing unit is degrees.
76
* @hideinitializer
77
**********************************************************************/
78
DEGREE
= 0,
79
/**
80
* Trailing unit is arc minutes.
81
* @hideinitializer
82
**********************************************************************/
83
MINUTE
= 1,
84
/**
85
* Trailing unit is arc seconds.
86
* @hideinitializer
87
**********************************************************************/
88
SECOND
= 2,
89
};
90
91
private
:
92
typedef
Math::real
real
;
93
// Replace all occurrences of pat by c. If c is NULL remove pat.
94
static
void
replace(std::string& s,
const
std::string& pat,
char
c);
95
static
const
char
*
const
hemispheres_;
96
static
const
char
*
const
signs_;
97
static
const
char
*
const
digits_;
98
static
const
char
*
const
dmsindicators_;
99
static
const
char
*
const
components_[3];
100
static
Math::real
NumMatch(
const
std::string& s);
101
static
Math::real
InternalDecode(
const
std::string& dmsa, flag& ind);
102
DMS
() =
delete
;
// Disable constructor
103
104
public
:
105
106
/**
107
* Convert a string in DMS to an angle.
108
*
109
* @param[in] dms string input.
110
* @param[out] ind a DMS::flag value signaling the presence of a
111
* hemisphere indicator.
112
* @exception GeographicErr if \e dms is malformed (see below).
113
* @return angle (degrees).
114
*
115
* Degrees, minutes, and seconds are indicated by the characters d, '
116
* (single quote), " (double quote), and these components may only be
117
* given in this order. Any (but not all) components may be omitted and
118
* other symbols (e.g., the ° symbol for degrees and the unicode prime
119
* and double prime symbols for minutes and seconds) may be substituted;
120
* two single quotes can be used instead of ". The last component
121
* indicator may be omitted and is assumed to be the next smallest unit
122
* (thus 33d10 is interpreted as 33d10'). The final component may be a
123
* decimal fraction but the non-final components must be integers. Instead
124
* of using d, ', and " to indicate degrees, minutes, and seconds, :
125
* (colon) may be used to <i>separate</i> these components (numbers must
126
* appear before and after each colon); thus 50d30'10.3" may be
127
* written as 50:30:10.3, 5.5' may be written 0:5.5, and so on. The
128
* integer parts of the minutes and seconds components must be less
129
* than 60. A single leading sign is permitted. A hemisphere designator
130
* (N, E, W, S) may be added to the beginning or end of the string. The
131
* result is multiplied by the implied sign of the hemisphere designator
132
* (negative for S and W). In addition \e ind is set to DMS::LATITUDE if N
133
* or S is present, to DMS::LONGITUDE if E or W is present, and to
134
* DMS::NONE otherwise. Leading and trailing whitespace is removed from
135
* the string before processing. This routine throws an error on a
136
* malformed string. No check is performed on the range of the result.
137
* Examples of legal and illegal strings are
138
* - <i>LEGAL</i> (all the entries on each line are equivalent)
139
* - -20.51125, 20d30'40.5"S, -20°30'40.5, -20d30.675,
140
* N-20d30'40.5", -20:30:40.5
141
* - 4d0'9, 4d9", 4d9'', 4:0:9, 004:00:09, 4.0025, 4.0025d, 4d0.15,
142
* 04:.15
143
* - 4:59.99999999999999, 4:60.0, 4:59:59.9999999999999, 4:59:60.0, 5
144
* - <i>ILLEGAL</i> (the exception thrown explains the problem)
145
* - 4d5"4', 4::5, 4:5:, :4:5, 4d4.5'4", -N20.5, 1.8e2d, 4:60,
146
* 4:59:60
147
*
148
* The decoding operation can also perform addition and subtraction
149
* operations. If the string includes <i>internal</i> signs (i.e., not at
150
* the beginning nor immediately after an initial hemisphere designator),
151
* then the string is split immediately before such signs and each piece is
152
* decoded according to the above rules and the results added; thus
153
* <code>S3-2.5+4.1N</code> is parsed as the sum of <code>S3</code>,
154
* <code>-2.5</code>, <code>+4.1N</code>. Any piece can include a
155
* hemisphere designator; however, if multiple designators are given, they
156
* must compatible; e.g., you cannot mix N and E. In addition, the
157
* designator can appear at the beginning or end of the first piece, but
158
* must be at the end of all subsequent pieces (a hemisphere designator is
159
* not allowed after the initial sign). Examples of legal and illegal
160
* combinations are
161
* - <i>LEGAL</i> (these are all equivalent)
162
* - -070:00:45, 70:01:15W+0:0.5, 70:01:15W-0:0:30W, W70:01:15+0:0:30E
163
* - <i>ILLEGAL</i> (the exception thrown explains the problem)
164
* - 70:01:15W+0:0:15N, W70:01:15+W0:0:15
165
*
166
* \warning The "exponential" notation is not recognized. Thus
167
* <code>7.0E1</code> is illegal, while <code>7.0E+1</code> is parsed as
168
* <code>(7.0E) + (+1)</code>, yielding the same result as
169
* <code>8.0E</code>.
170
*
171
* \note At present, all the string handling in the C++ implementation of
172
* %GeographicLib is with 8-bit characters. The support for unicode
173
* symbols for degrees, minutes, and seconds is therefore via the
174
* <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> encoding. (The
175
* JavaScript implementation of this class uses unicode natively, of
176
* course.)
177
*
178
* Here is the list of Unicode symbols supported for degrees, minutes,
179
* seconds, and the plus and minus signs; various symbols denoting variants
180
* of a space, which may separate the components of a DMS string, are
181
* removed:
182
* - degrees:
183
* - d, D lower and upper case letters
184
* - U+00b0 degree symbol (°)
185
* - U+00ba masculine ordinal indicator (º)
186
* - U+2070 superscript zero (⁰)
187
* - U+02da ring above (˚)
188
* - U+2218 compose function (∘)
189
* - * the <a href="https://grid.nga.mil">GRiD</a> symbol for degrees
190
* - minutes:
191
* - ' apostrophe
192
* - ` grave accent
193
* - U+2032 prime (′)
194
* - U+2035 back prime (‵)
195
* - U+00b4 acute accent (´)
196
* - U+2018 left single quote (‘)
197
* - U+2019 right single quote (’)
198
* - U+201b reversed-9 single quote (‛)
199
* - U+02b9 modifier letter prime (ʹ)
200
* - U+02ca modifier letter acute accent (ˊ)
201
* - U+02cb modifier letter grave accent (ˋ)
202
* - seconds:
203
* - " quotation mark
204
* - U+2033 double prime (″)
205
* - U+2036 reversed double prime (‶)
206
* + U+02dd double acute accent (˝)
207
* - U+201c left double quote (“)
208
* - U+201d right double quote (”)
209
* - U+201f reversed-9 double quote (‟)
210
* - U+02ba modifier letter double prime (ʺ)
211
* - ' ' any two consecutive symbols for minutes
212
* - plus sign:
213
* - + plus
214
* - U+2795 heavy plus (➕)
215
* - U+2064 invisible plus (||)
216
* - minus sign:
217
* - - hyphen
218
* - U+2010 dash (‐)
219
* - U+2011 non-breaking hyphen (‑)
220
* - U+2013 en dash (–)
221
* - U+2014 em dash (—)
222
* - U+2212 minus sign (−)
223
* - U+2796 heavy minus (➖)
224
* - ignored spaces:
225
* - U+00a0 non-breaking space
226
* - U+2007 figure space (| |)
227
* - U+2009 thin space (| |)
228
* - U+200a hair space ( | |)
229
* - U+200b invisible space (||)
230
* - U+202f narrow space ( | |)
231
* - U+2063 invisible separator (||)
232
* .
233
* The codes with a leading zero byte, e.g., U+00b0, are accepted in their
234
* UTF-8 coded form 0xc2 0xb0 and as a single byte 0xb0.
235
**********************************************************************/
236
static
Math::real
Decode(
const
std::string& dms, flag& ind);
237
238
/**
239
* Convert DMS to an angle.
240
*
241
* @param[in] d degrees.
242
* @param[in] m arc minutes.
243
* @param[in] s arc seconds.
244
* @return angle (degrees)
245
*
246
* This does not propagate the sign on \e d to the other components,
247
* so -3d20' would need to be represented as - DMS::Decode(3.0, 20.0) or
248
* DMS::Decode(-3.0, -20.0).
249
**********************************************************************/
250
static
Math::real
Decode
(real d, real m = 0, real s = 0)
251
{
return
d + (m + s /
real
(
Math::ms
)) /
real
(
Math::dm
); }
252
253
/**
254
* Convert a pair of strings to latitude and longitude.
255
*
256
* @param[in] dmsa first string.
257
* @param[in] dmsb second string.
258
* @param[out] lat latitude (degrees).
259
* @param[out] lon longitude (degrees).
260
* @param[in] longfirst if true assume longitude is given before latitude
261
* in the absence of hemisphere designators (default false).
262
* @exception GeographicErr if \e dmsa or \e dmsb is malformed.
263
* @exception GeographicErr if \e dmsa and \e dmsb are both interpreted as
264
* latitudes.
265
* @exception GeographicErr if \e dmsa and \e dmsb are both interpreted as
266
* longitudes.
267
* @exception GeographicErr if decoded latitude is not in [−90°,
268
* 90°].
269
*
270
* By default, the \e lat (resp., \e lon) is assigned to the results of
271
* decoding \e dmsa (resp., \e dmsb). However this is overridden if either
272
* \e dmsa or \e dmsb contain a latitude or longitude hemisphere designator
273
* (N, S, E, W). If an exception is thrown, \e lat and \e lon are
274
* unchanged.
275
**********************************************************************/
276
static
void
DecodeLatLon(
const
std::string& dmsa,
const
std::string& dmsb,
277
real
& lat,
real
& lon,
278
bool
longfirst =
false
);
279
280
/**
281
* Convert a string to an angle in degrees.
282
*
283
* @param[in] angstr input string.
284
* @exception GeographicErr if \e angstr is malformed.
285
* @exception GeographicErr if \e angstr includes a hemisphere designator.
286
* @return angle (degrees)
287
*
288
* No hemisphere designator is allowed and no check is done on the range of
289
* the result.
290
**********************************************************************/
291
static
Math::real
DecodeAngle(
const
std::string& angstr);
292
293
/**
294
* Convert a string to an azimuth in degrees.
295
*
296
* @param[in] azistr input string.
297
* @exception GeographicErr if \e azistr is malformed.
298
* @exception GeographicErr if \e azistr includes a N/S designator.
299
* @return azimuth (degrees) reduced to the range [−180°,
300
* 180°].
301
*
302
* A hemisphere designator E/W can be used; the result is multiplied by
303
* −1 if W is present.
304
**********************************************************************/
305
static
Math::real
DecodeAzimuth(
const
std::string& azistr);
306
307
/**
308
* Convert angle (in degrees) into a DMS string (using d, ', and ").
309
*
310
* @param[in] angle input angle (degrees)
311
* @param[in] trailing DMS::component value indicating the trailing units
312
* of the string (this component is given as a decimal number if
313
* necessary).
314
* @param[in] prec the number of digits after the decimal point for the
315
* trailing component.
316
* @param[in] ind DMS::flag value indicating additional formatting.
317
* @param[in] dmssep if non-null, use as the DMS separator character
318
* (instead of d, ', " delimiters).
319
* @exception std::bad_alloc if memory for the string can't be allocated.
320
* @return formatted string
321
*
322
* The interpretation of \e ind is as follows:
323
* - ind == DMS::NONE, signed result no leading zeros on degrees except in
324
* the units place, e.g., -8d03'.
325
* - ind == DMS::LATITUDE, trailing N or S hemisphere designator, no sign,
326
* pad degrees to 2 digits, e.g., 08d03'S.
327
* - ind == DMS::LONGITUDE, trailing E or W hemisphere designator, no
328
* sign, pad degrees to 3 digits, e.g., 008d03'W.
329
* - ind == DMS::AZIMUTH, convert to the range [0, 360°), no
330
* sign, pad degrees to 3 digits, e.g., 351d57'.
331
* .
332
* The integer parts of the minutes and seconds components are always given
333
* with 2 digits.
334
**********************************************************************/
335
static
std::string Encode(
real
angle, component trailing,
unsigned
prec,
336
flag ind = NONE,
char
dmssep =
char
(0));
337
338
/**
339
* Convert angle into a DMS string (using d, ', and ") selecting the
340
* trailing component based on the precision.
341
*
342
* @param[in] angle input angle (degrees)
343
* @param[in] prec the precision relative to 1 degree.
344
* @param[in] ind DMS::flag value indicated additional formatting.
345
* @param[in] dmssep if non-null, use as the DMS separator character
346
* (instead of d, ', " delimiters).
347
* @exception std::bad_alloc if memory for the string can't be allocated.
348
* @return formatted string
349
*
350
* \e prec indicates the precision relative to 1 degree, e.g., \e prec = 3
351
* gives a result accurate to 0.1' and \e prec = 4 gives a result accurate
352
* to 1". \e ind is interpreted as in DMS::Encode with the additional
353
* facility that DMS::NUMBER represents \e angle as a number in fixed
354
* format with precision \e prec.
355
**********************************************************************/
356
static
std::string
Encode
(real angle,
unsigned
prec,
flag
ind =
NONE
,
357
char
dmssep =
char
(0)) {
358
return
ind ==
NUMBER
?
Utility::str
(angle,
int
(prec)) :
359
Encode
(angle,
360
prec < 2 ?
DEGREE
: (prec < 4 ?
MINUTE
:
SECOND
),
361
prec < 2 ? prec : (prec < 4 ? prec - 2 : prec - 4),
362
ind, dmssep);
363
}
364
365
/**
366
* Split angle into degrees and minutes
367
*
368
* @param[in] ang angle (degrees)
369
* @param[out] d degrees (an integer returned as a real)
370
* @param[out] m arc minutes.
371
**********************************************************************/
372
static
void
Encode
(real
ang
, real& d, real& m) {
373
d = int(
ang
); m =
real
(
Math::dm
) * (
ang
- d);
374
}
375
376
/**
377
* Split angle into degrees and minutes and seconds.
378
*
379
* @param[in] ang angle (degrees)
380
* @param[out] d degrees (an integer returned as a real)
381
* @param[out] m arc minutes (an integer returned as a real)
382
* @param[out] s arc seconds.
383
**********************************************************************/
384
static
void
Encode
(real
ang
, real& d, real& m, real& s) {
385
d = int(
ang
);
ang
=
real
(
Math::dm
) * (
ang
- d);
386
m = int(
ang
); s =
real
(
Math::ms
) * (
ang
- m);
387
}
388
389
};
390
391
}
// namespace GeographicLib
392
393
#if defined(_MSC_VER)
394
# pragma warning (pop)
395
#endif
396
397
#endif
// GEOGRAPHICLIB_DMS_HPP
Constants.hpp
Header for GeographicLib::Constants class.
GEOGRAPHICLIB_EXPORT
#define GEOGRAPHICLIB_EXPORT
Definition
Constants.hpp:59
ang
GeographicLib::Angle ang
Definition
Geod3Solve.cpp:26
real
GeographicLib::Math::real real
Definition
Geod3Solve.cpp:25
Utility.hpp
Header for GeographicLib::Utility class.
GeographicLib::DMS
Convert between degrees and the DMS representation.
Definition
DMS.hpp:34
GeographicLib::DMS::Encode
static void Encode(real ang, real &d, real &m)
Definition
DMS.hpp:372
GeographicLib::DMS::flag
flag
Definition
DMS.hpp:41
GeographicLib::DMS::LONGITUDE
@ LONGITUDE
Definition
DMS.hpp:56
GeographicLib::DMS::NUMBER
@ NUMBER
Definition
DMS.hpp:67
GeographicLib::DMS::LATITUDE
@ LATITUDE
Definition
DMS.hpp:51
GeographicLib::DMS::AZIMUTH
@ AZIMUTH
Definition
DMS.hpp:62
GeographicLib::DMS::NONE
@ NONE
Definition
DMS.hpp:46
GeographicLib::DMS::Decode
static Math::real Decode(real d, real m=0, real s=0)
Definition
DMS.hpp:250
GeographicLib::DMS::component
component
Definition
DMS.hpp:73
GeographicLib::DMS::SECOND
@ SECOND
Definition
DMS.hpp:88
GeographicLib::DMS::DEGREE
@ DEGREE
Definition
DMS.hpp:78
GeographicLib::DMS::MINUTE
@ MINUTE
Definition
DMS.hpp:83
GeographicLib::DMS::Encode
static std::string Encode(real angle, component trailing, unsigned prec, flag ind=NONE, char dmssep=char(0))
Definition
DMS.cpp:422
GeographicLib::DMS::Encode
static std::string Encode(real angle, unsigned prec, flag ind=NONE, char dmssep=char(0))
Definition
DMS.hpp:356
GeographicLib::DMS::Encode
static void Encode(real ang, real &d, real &m, real &s)
Definition
DMS.hpp:384
GeographicLib::Math::dm
static constexpr int dm
minutes per degree
Definition
Math.hpp:143
GeographicLib::Math::real
double real
Definition
Math.hpp:115
GeographicLib::Math::ms
static constexpr int ms
seconds per minute
Definition
Math.hpp:144
GeographicLib::Utility::str
static std::string str(T x, int p=-1)
Definition
Utility.hpp:161
GeographicLib
Namespace for GeographicLib.
Definition
Accumulator.cpp:12
include
GeographicLib
DMS.hpp
Generated by
1.17.0