add GeographicLib
This commit is contained in:
405
external/include/GeographicLib/DMS.hpp
vendored
Normal file
405
external/include/GeographicLib/DMS.hpp
vendored
Normal file
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* \file DMS.hpp
|
||||
* \brief Header for GeographicLib::DMS class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_DMS_HPP)
|
||||
#define GEOGRAPHICLIB_DMS_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/Utility.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs vector and constant conditional expressions
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251 4127)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Convert between degrees and the %DMS representation
|
||||
*
|
||||
* Parse a string representing degree, minutes, and seconds and return the
|
||||
* angle in degrees and format an angle in degrees as degree, minutes, and
|
||||
* seconds. In addition, handle NANs and infinities on input and output.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-DMS.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT DMS {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Indicator for presence of hemisphere indicator (N/S/E/W) on latitudes
|
||||
* and longitudes.
|
||||
**********************************************************************/
|
||||
enum flag {
|
||||
/**
|
||||
* No indicator present.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = 0,
|
||||
/**
|
||||
* Latitude indicator (N/S) present.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = 1,
|
||||
/**
|
||||
* Longitude indicator (E/W) present.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = 2,
|
||||
/**
|
||||
* Used in Encode to indicate output of an azimuth in [000, 360) with no
|
||||
* letter indicator.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = 3,
|
||||
/**
|
||||
* Used in Encode to indicate output of a plain number.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NUMBER = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicator for trailing units on an angle.
|
||||
**********************************************************************/
|
||||
enum component {
|
||||
/**
|
||||
* Trailing unit is degrees.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DEGREE = 0,
|
||||
/**
|
||||
* Trailing unit is arc minutes.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
MINUTE = 1,
|
||||
/**
|
||||
* Trailing unit is arc seconds.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
SECOND = 2,
|
||||
};
|
||||
|
||||
private:
|
||||
typedef Math::real real;
|
||||
// Replace all occurrences of pat by c. If c is NULL remove pat.
|
||||
static void replace(std::string& s, const std::string& pat, char c) {
|
||||
std::string::size_type p = 0;
|
||||
int count = c ? 1 : 0;
|
||||
while (true) {
|
||||
p = s.find(pat, p);
|
||||
if (p == std::string::npos)
|
||||
break;
|
||||
s.replace(p, pat.length(), count, c);
|
||||
}
|
||||
}
|
||||
static const char* const hemispheres_;
|
||||
static const char* const signs_;
|
||||
static const char* const digits_;
|
||||
static const char* const dmsindicators_;
|
||||
static const char* const components_[3];
|
||||
static Math::real NumMatch(const std::string& s);
|
||||
static Math::real InternalDecode(const std::string& dmsa, flag& ind);
|
||||
DMS(); // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert a string in DMS to an angle.
|
||||
*
|
||||
* @param[in] dms string input.
|
||||
* @param[out] ind a DMS::flag value signaling the presence of a
|
||||
* hemisphere indicator.
|
||||
* @exception GeographicErr if \e dms is malformed (see below).
|
||||
* @return angle (degrees).
|
||||
*
|
||||
* Degrees, minutes, and seconds are indicated by the characters d, '
|
||||
* (single quote), " (double quote), and these components may only be
|
||||
* given in this order. Any (but not all) components may be omitted and
|
||||
* other symbols (e.g., the ° symbol for degrees and the unicode prime
|
||||
* and double prime symbols for minutes and seconds) may be substituted;
|
||||
* two single quotes can be used instead of ". The last component
|
||||
* indicator may be omitted and is assumed to be the next smallest unit
|
||||
* (thus 33d10 is interpreted as 33d10'). The final component may be a
|
||||
* decimal fraction but the non-final components must be integers. Instead
|
||||
* of using d, ', and " to indicate degrees, minutes, and seconds, :
|
||||
* (colon) may be used to <i>separate</i> these components (numbers must
|
||||
* appear before and after each colon); thus 50d30'10.3" may be
|
||||
* written as 50:30:10.3, 5.5' may be written 0:5.5, and so on. The
|
||||
* integer parts of the minutes and seconds components must be less
|
||||
* than 60. A single leading sign is permitted. A hemisphere designator
|
||||
* (N, E, W, S) may be added to the beginning or end of the string. The
|
||||
* result is multiplied by the implied sign of the hemisphere designator
|
||||
* (negative for S and W). In addition \e ind is set to DMS::LATITUDE if N
|
||||
* or S is present, to DMS::LONGITUDE if E or W is present, and to
|
||||
* DMS::NONE otherwise. Throws an error on a malformed string. No check
|
||||
* is performed on the range of the result. Examples of legal and illegal
|
||||
* strings are
|
||||
* - <i>LEGAL</i> (all the entries on each line are equivalent)
|
||||
* - -20.51125, 20d30'40.5"S, -20°30'40.5, -20d30.675,
|
||||
* N-20d30'40.5", -20:30:40.5
|
||||
* - 4d0'9, 4d9", 4d9'', 4:0:9, 004:00:09, 4.0025, 4.0025d, 4d0.15,
|
||||
* 04:.15
|
||||
* - 4:59.99999999999999, 4:60.0, 4:59:59.9999999999999, 4:59:60.0, 5
|
||||
* - <i>ILLEGAL</i> (the exception thrown explains the problem)
|
||||
* - 4d5"4', 4::5, 4:5:, :4:5, 4d4.5'4", -N20.5, 1.8e2d, 4:60,
|
||||
* 4:59:60
|
||||
*
|
||||
* The decoding operation can also perform addition and subtraction
|
||||
* operations. If the string includes <i>internal</i> signs (i.e., not at
|
||||
* the beginning nor immediately after an initial hemisphere designator),
|
||||
* then the string is split immediately before such signs and each piece is
|
||||
* decoded according to the above rules and the results added; thus
|
||||
* <code>S3-2.5+4.1N</code> is parsed as the sum of <code>S3</code>,
|
||||
* <code>-2.5</code>, <code>+4.1N</code>. Any piece can include a
|
||||
* hemisphere designator; however, if multiple designators are given, they
|
||||
* must compatible; e.g., you cannot mix N and E. In addition, the
|
||||
* designator can appear at the beginning or end of the first piece, but
|
||||
* must be at the end of all subsequent pieces (a hemisphere designator is
|
||||
* not allowed after the initial sign). Examples of legal and illegal
|
||||
* combinations are
|
||||
* - <i>LEGAL</i> (these are all equivalent)
|
||||
* - 070:00:45, 70:01:15W+0:0.5, 70:01:15W-0:0:30W, W70:01:15+0:0:30E
|
||||
* - <i>ILLEGAL</i> (the exception thrown explains the problem)
|
||||
* - 70:01:15W+0:0:15N, W70:01:15+W0:0:15
|
||||
*
|
||||
* \warning The "exponential" notation is not recognized. Thus
|
||||
* <code>7.0E1</code> is illegal, while <code>7.0E+1</code> is parsed as
|
||||
* <code>(7.0E) + (+1)</code>, yielding the same result as
|
||||
* <code>8.0E</code>.
|
||||
*
|
||||
* \note At present, all the string handling in the C++ implementation of
|
||||
* %GeographicLib is with 8-bit characters. The support for unicode
|
||||
* symbols for degrees, minutes, and seconds is therefore via the
|
||||
* <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> encoding. (The
|
||||
* JavaScript implementation of this class uses unicode natively, of
|
||||
* course.)
|
||||
*
|
||||
* Here is the list of Unicode symbols supported for degrees, minutes,
|
||||
* seconds, and the plus and minus signs; various symbols denoting variants
|
||||
* of a space, which may separate the components of a DMS string, are
|
||||
* removed:
|
||||
* - degrees:
|
||||
* - d, D lower and upper case letters
|
||||
* - U+00b0 degree symbol (°)
|
||||
* - U+00ba masculine ordinal indicator (º)
|
||||
* - U+2070 superscript zero (⁰)
|
||||
* - U+02da ring above (˚)
|
||||
* - U+2218 compose function (∘)
|
||||
* - * the <a href="https://grid.nga.mil">GRiD</a> symbol for degrees
|
||||
* - minutes:
|
||||
* - ' apostrophe
|
||||
* - ` grave accent
|
||||
* - U+2032 prime (′)
|
||||
* - U+2035 back prime (‵)
|
||||
* - U+00b4 acute accent (´)
|
||||
* - U+2018 left single quote (‘)
|
||||
* - U+2019 right single quote (’)
|
||||
* - U+201b reversed-9 single quote (‛)
|
||||
* - U+02b9 modifier letter prime (ʹ)
|
||||
* - U+02ca modifier letter acute accent (ˊ)
|
||||
* - U+02cb modifier letter grave accent (ˋ)
|
||||
* - seconds:
|
||||
* - " quotation mark
|
||||
* - U+2033 double prime (″)
|
||||
* - U+2036 reversed double prime (‶)
|
||||
* + U+02dd double acute accent (˝)
|
||||
* - U+201c left double quote (“)
|
||||
* - U+201d right double quote (”)
|
||||
* - U+201f reversed-9 double quote (‟)
|
||||
* - U+02ba modifier letter double prime (ʺ)
|
||||
* - ' ' any two consecutive symbols for minutes
|
||||
* - plus sign:
|
||||
* - + plus
|
||||
* - U+2795 heavy plus (➕)
|
||||
* - U+2064 invisible plus (||)
|
||||
* - minus sign:
|
||||
* - - hyphen
|
||||
* - U+2010 dash (‐)
|
||||
* - U+2011 non-breaking hyphen (‑)
|
||||
* - U+2013 en dash (–)
|
||||
* - U+2014 em dash (—)
|
||||
* - U+2212 minus sign (−)
|
||||
* - U+2796 heavy minus (➖)
|
||||
* - ignored spaces:
|
||||
* - U+00a0 non-breaking space
|
||||
* - U+2007 figure space (| |)
|
||||
* - U+2009 thin space (| |)
|
||||
* - U+200a hair space ( | |)
|
||||
* - U+200b invisible space (||)
|
||||
* - U+202f narrow space ( | |)
|
||||
* - U+2063 invisible separator (||)
|
||||
* .
|
||||
* The codes with a leading zero byte, e.g., U+00b0, are accepted in their
|
||||
* UTF-8 coded form 0xc2 0xb0 and as a single byte 0xb0.
|
||||
**********************************************************************/
|
||||
static Math::real Decode(const std::string& dms, flag& ind);
|
||||
|
||||
/**
|
||||
* Convert DMS to an angle.
|
||||
*
|
||||
* @param[in] d degrees.
|
||||
* @param[in] m arc minutes.
|
||||
* @param[in] s arc seconds.
|
||||
* @return angle (degrees)
|
||||
*
|
||||
* This does not propagate the sign on \e d to the other components,
|
||||
* so -3d20' would need to be represented as - DMS::Decode(3.0, 20.0) or
|
||||
* DMS::Decode(-3.0, -20.0).
|
||||
**********************************************************************/
|
||||
static Math::real Decode(real d, real m = 0, real s = 0)
|
||||
{ return d + (m + s / 60) / 60; }
|
||||
|
||||
/**
|
||||
* Convert a pair of strings to latitude and longitude.
|
||||
*
|
||||
* @param[in] dmsa first string.
|
||||
* @param[in] dmsb second string.
|
||||
* @param[out] lat latitude (degrees).
|
||||
* @param[out] lon longitude (degrees).
|
||||
* @param[in] longfirst if true assume longitude is given before latitude
|
||||
* in the absence of hemisphere designators (default false).
|
||||
* @exception GeographicErr if \e dmsa or \e dmsb is malformed.
|
||||
* @exception GeographicErr if \e dmsa and \e dmsb are both interpreted as
|
||||
* latitudes.
|
||||
* @exception GeographicErr if \e dmsa and \e dmsb are both interpreted as
|
||||
* longitudes.
|
||||
* @exception GeographicErr if decoded latitude is not in [−90°,
|
||||
* 90°].
|
||||
*
|
||||
* By default, the \e lat (resp., \e lon) is assigned to the results of
|
||||
* decoding \e dmsa (resp., \e dmsb). However this is overridden if either
|
||||
* \e dmsa or \e dmsb contain a latitude or longitude hemisphere designator
|
||||
* (N, S, E, W). If an exception is thrown, \e lat and \e lon are
|
||||
* unchanged.
|
||||
**********************************************************************/
|
||||
static void DecodeLatLon(const std::string& dmsa, const std::string& dmsb,
|
||||
real& lat, real& lon,
|
||||
bool longfirst = false);
|
||||
|
||||
/**
|
||||
* Convert a string to an angle in degrees.
|
||||
*
|
||||
* @param[in] angstr input string.
|
||||
* @exception GeographicErr if \e angstr is malformed.
|
||||
* @exception GeographicErr if \e angstr includes a hemisphere designator.
|
||||
* @return angle (degrees)
|
||||
*
|
||||
* No hemisphere designator is allowed and no check is done on the range of
|
||||
* the result.
|
||||
**********************************************************************/
|
||||
static Math::real DecodeAngle(const std::string& angstr);
|
||||
|
||||
/**
|
||||
* Convert a string to an azimuth in degrees.
|
||||
*
|
||||
* @param[in] azistr input string.
|
||||
* @exception GeographicErr if \e azistr is malformed.
|
||||
* @exception GeographicErr if \e azistr includes a N/S designator.
|
||||
* @return azimuth (degrees) reduced to the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* A hemisphere designator E/W can be used; the result is multiplied by
|
||||
* −1 if W is present.
|
||||
**********************************************************************/
|
||||
static Math::real DecodeAzimuth(const std::string& azistr);
|
||||
|
||||
/**
|
||||
* Convert angle (in degrees) into a DMS string (using d, ', and ").
|
||||
*
|
||||
* @param[in] angle input angle (degrees)
|
||||
* @param[in] trailing DMS::component value indicating the trailing units
|
||||
* of the string (this component is given as a decimal number if
|
||||
* necessary).
|
||||
* @param[in] prec the number of digits after the decimal point for the
|
||||
* trailing component.
|
||||
* @param[in] ind DMS::flag value indicating additional formatting.
|
||||
* @param[in] dmssep if non-null, use as the DMS separator character
|
||||
* (instead of d, ', " delimiters).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return formatted string
|
||||
*
|
||||
* The interpretation of \e ind is as follows:
|
||||
* - ind == DMS::NONE, signed result no leading zeros on degrees except in
|
||||
* the units place, e.g., -8d03'.
|
||||
* - ind == DMS::LATITUDE, trailing N or S hemisphere designator, no sign,
|
||||
* pad degrees to 2 digits, e.g., 08d03'S.
|
||||
* - ind == DMS::LONGITUDE, trailing E or W hemisphere designator, no
|
||||
* sign, pad degrees to 3 digits, e.g., 008d03'W.
|
||||
* - ind == DMS::AZIMUTH, convert to the range [0, 360°), no
|
||||
* sign, pad degrees to 3 digits, e.g., 351d57'.
|
||||
* .
|
||||
* The integer parts of the minutes and seconds components are always given
|
||||
* with 2 digits.
|
||||
**********************************************************************/
|
||||
static std::string Encode(real angle, component trailing, unsigned prec,
|
||||
flag ind = NONE, char dmssep = char(0));
|
||||
|
||||
/**
|
||||
* Convert angle into a DMS string (using d, ', and ") selecting the
|
||||
* trailing component based on the precision.
|
||||
*
|
||||
* @param[in] angle input angle (degrees)
|
||||
* @param[in] prec the precision relative to 1 degree.
|
||||
* @param[in] ind DMS::flag value indicated additional formatting.
|
||||
* @param[in] dmssep if non-null, use as the DMS separator character
|
||||
* (instead of d, ', " delimiters).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return formatted string
|
||||
*
|
||||
* \e prec indicates the precision relative to 1 degree, e.g., \e prec = 3
|
||||
* gives a result accurate to 0.1' and \e prec = 4 gives a result accurate
|
||||
* to 1". \e ind is interpreted as in DMS::Encode with the additional
|
||||
* facility that DMS::NUMBER represents \e angle as a number in fixed
|
||||
* format with precision \e prec.
|
||||
**********************************************************************/
|
||||
static std::string Encode(real angle, unsigned prec, flag ind = NONE,
|
||||
char dmssep = char(0)) {
|
||||
return ind == NUMBER ? Utility::str(angle, int(prec)) :
|
||||
Encode(angle,
|
||||
prec < 2 ? DEGREE : (prec < 4 ? MINUTE : SECOND),
|
||||
prec < 2 ? prec : (prec < 4 ? prec - 2 : prec - 4),
|
||||
ind, dmssep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split angle into degrees and minutes
|
||||
*
|
||||
* @param[in] ang angle (degrees)
|
||||
* @param[out] d degrees (an integer returned as a real)
|
||||
* @param[out] m arc minutes.
|
||||
**********************************************************************/
|
||||
static void Encode(real ang, real& d, real& m) {
|
||||
d = int(ang); m = 60 * (ang - d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split angle into degrees and minutes and seconds.
|
||||
*
|
||||
* @param[in] ang angle (degrees)
|
||||
* @param[out] d degrees (an integer returned as a real)
|
||||
* @param[out] m arc minutes (an integer returned as a real)
|
||||
* @param[out] s arc seconds.
|
||||
**********************************************************************/
|
||||
static void Encode(real ang, real& d, real& m, real& s) {
|
||||
d = int(ang); ang = 60 * (ang - d);
|
||||
m = int(ang); s = 60 * (ang - m);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_DMS_HPP
|
||||
Reference in New Issue
Block a user