ADD: new track message, Entity class and Position class
This commit is contained in:
406
libs/geographiclib/include/GeographicLib/MGRS.hpp
Normal file
406
libs/geographiclib/include/GeographicLib/MGRS.hpp
Normal file
@@ -0,0 +1,406 @@
|
||||
/**
|
||||
* \file MGRS.hpp
|
||||
* \brief Header for GeographicLib::MGRS class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2022) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_MGRS_HPP)
|
||||
#define GEOGRAPHICLIB_MGRS_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/UTMUPS.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs string
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Convert between UTM/UPS and %MGRS
|
||||
*
|
||||
* MGRS is defined in Chapter 3 of
|
||||
* - J. W. Hager, L. L. Fry, S. S. Jacks, D. R. Hill,
|
||||
* <a href="https://web.archive.org/web/20161214054445/http://earth-info.nga.mil/GandG/publications/tm8358.1/pdf/TM8358_1.pdf">
|
||||
* Datums, Ellipsoids, Grids, and Grid Reference Systems</a>,
|
||||
* Defense Mapping Agency, Technical Manual TM8358.1 (1990).
|
||||
* .
|
||||
* This document has been updated by the two NGA documents
|
||||
* - <a href="https://earth-info.nga.mil/php/download.php?file=coord-grids">
|
||||
* Universal Grids and Grid Reference Systems</a>,
|
||||
* NGA.STND.0037 (2014).
|
||||
* - <a href="https://earth-info.nga.mil/php/download.php?file=coord-utmups">
|
||||
* The Universal Grids and the Transverse Mercator and Polar Stereographic
|
||||
* Map Projections</a>, NGA.SIG.0012 (2014).
|
||||
*
|
||||
* This implementation has the following properties:
|
||||
* - The conversions are closed, i.e., output from Forward is legal input for
|
||||
* Reverse and vice versa. Conversion in both directions preserve the
|
||||
* UTM/UPS selection and the UTM zone.
|
||||
* - Forward followed by Reverse and vice versa is approximately the
|
||||
* identity. (This is affected in predictable ways by errors in
|
||||
* determining the latitude band and by loss of precision in the MGRS
|
||||
* coordinates.)
|
||||
* - The trailing digits produced by Forward are consistent as the precision
|
||||
* is varied. Specifically, the digits are obtained by operating on the
|
||||
* easting with ⌊10<sup>6</sup> <i>x</i>⌋ and extracting the
|
||||
* required digits from the resulting number (and similarly for the
|
||||
* northing).
|
||||
* - All MGRS coordinates truncate to legal 100 km blocks. All MGRS
|
||||
* coordinates with a legal 100 km block prefix are legal (even though the
|
||||
* latitude band letter may now belong to a neighboring band).
|
||||
* - The range of UTM/UPS coordinates allowed for conversion to MGRS
|
||||
* coordinates is the maximum consistent with staying within the letter
|
||||
* ranges of the MGRS scheme.
|
||||
* - All the transformations are implemented as static methods in the MGRS
|
||||
* class.
|
||||
*
|
||||
* The <a href="http://www.nga.mil">NGA</a> software package
|
||||
* <a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_geotrans">geotrans</a>
|
||||
* also provides conversions to and from MGRS. Version 3.0 (and earlier)
|
||||
* suffers from some drawbacks:
|
||||
* - Inconsistent rules are used to determine the whether a particular MGRS
|
||||
* coordinate is legal. A more systematic approach is taken here.
|
||||
* - The underlying projections are not very accurately implemented.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-MGRS.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT MGRS {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const char* const hemispheres_;
|
||||
static const char* const utmcols_[3];
|
||||
static const char* const utmrow_;
|
||||
static const char* const upscols_[4];
|
||||
static const char* const upsrows_[2];
|
||||
static const char* const latband_;
|
||||
static const char* const upsband_;
|
||||
static const char* const digits_;
|
||||
static const char* const alpha_;
|
||||
|
||||
static const int mineasting_[4];
|
||||
static const int maxeasting_[4];
|
||||
static const int minnorthing_[4];
|
||||
static const int maxnorthing_[4];
|
||||
#if GEOGRAPHICLIB_PRECISION == 4
|
||||
// Work around an enum lossage introduced in boost 1.76
|
||||
// https://github.com/boostorg/multiprecision/issues/324
|
||||
// and fixed in
|
||||
// https://github.com/boostorg/multiprecision/pull/333
|
||||
static const int
|
||||
#else
|
||||
enum {
|
||||
#endif
|
||||
base_ = 10,
|
||||
// Top-level tiles are 10^5 m = 100 km on a side
|
||||
tilelevel_ = 5,
|
||||
// Period of UTM row letters
|
||||
utmrowperiod_ = 20,
|
||||
// Row letters are shifted by 5 for even zones
|
||||
utmevenrowshift_ = 5,
|
||||
// Maximum precision is um
|
||||
maxprec_ = 5 + 6,
|
||||
// For generating digits at maxprec
|
||||
mult_ = 1000000
|
||||
#if GEOGRAPHICLIB_PRECISION == 4
|
||||
;
|
||||
#else
|
||||
};
|
||||
#endif
|
||||
static void CheckCoords(bool utmp, bool& northp, real& x, real& y);
|
||||
static int UTMRow(int iband, int icol, int irow);
|
||||
|
||||
friend class UTMUPS; // UTMUPS::StandardZone calls LatitudeBand
|
||||
// Return latitude band number [-10, 10) for the given latitude (degrees).
|
||||
// The bands are reckoned in include their southern edges.
|
||||
static int LatitudeBand(real lat) {
|
||||
using std::floor;
|
||||
int ilat = int(floor(lat));
|
||||
return (std::max)(-10, (std::min)(9, (ilat + 80)/8 - 10));
|
||||
}
|
||||
// Return approximate latitude band number [-10, 10) for the given northing
|
||||
// (meters). With this rule, each 100km tile would have a unique band
|
||||
// letter corresponding to the latitude at the center of the tile. This
|
||||
// function isn't currently used.
|
||||
static int ApproxLatitudeBand(real y) {
|
||||
// northing at tile center in units of tile = 100km
|
||||
using std::floor; using std::fabs; using std::fmin;
|
||||
real ya = floor( fmin(real(88), fabs(y / real(tile_))) ) + real(0.5);
|
||||
// convert to lat (mult by 90/100) and then to band (divide by 8)
|
||||
// the +1 fine tunes the boundary between bands 3 and 4
|
||||
int b = int(floor( ((ya * 9 + 1) / 10) / 8 ));
|
||||
// For the northern hemisphere we have
|
||||
// band rows num
|
||||
// N 0 0:8 9
|
||||
// P 1 9:17 9
|
||||
// Q 2 18:26 9
|
||||
// R 3 27:34 8
|
||||
// S 4 35:43 9
|
||||
// T 5 44:52 9
|
||||
// U 6 53:61 9
|
||||
// V 7 62:70 9
|
||||
// W 8 71:79 9
|
||||
// X 9 80:94 15
|
||||
return y >= 0 ? b : -(b + 1);
|
||||
}
|
||||
// UTMUPS accesses these enums
|
||||
#if GEOGRAPHICLIB_PRECISION == 4
|
||||
// Work around an enum lossage introduced in boost 1.76
|
||||
// https://github.com/boostorg/multiprecision/issues/324
|
||||
// and fixed in
|
||||
// https://github.com/boostorg/multiprecision/pull/333
|
||||
static const int
|
||||
#else
|
||||
enum {
|
||||
#endif
|
||||
tile_ = 100000, // Size MGRS blocks
|
||||
minutmcol_ = 1,
|
||||
maxutmcol_ = 9,
|
||||
minutmSrow_ = 10,
|
||||
maxutmSrow_ = 100, // Also used for UTM S false northing
|
||||
minutmNrow_ = 0, // Also used for UTM N false northing
|
||||
maxutmNrow_ = 95,
|
||||
minupsSind_ = 8, // These 4 ind's apply to easting and northing
|
||||
maxupsSind_ = 32,
|
||||
minupsNind_ = 13,
|
||||
maxupsNind_ = 27,
|
||||
upseasting_ = 20, // Also used for UPS false northing
|
||||
utmeasting_ = 5, // UTM false easting
|
||||
// Difference between S hemisphere northing and N hemisphere northing
|
||||
utmNshift_ = (maxutmSrow_ - minutmNrow_) * tile_
|
||||
#if GEOGRAPHICLIB_PRECISION == 4
|
||||
;
|
||||
#else
|
||||
};
|
||||
#endif
|
||||
MGRS() = delete; // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert UTM or UPS coordinate to an MGRS coordinate.
|
||||
*
|
||||
* @param[in] zone UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[in] prec precision relative to 100 km.
|
||||
* @param[out] mgrs MGRS string.
|
||||
* @exception GeographicErr if \e zone, \e x, or \e y is outside its
|
||||
* allowed range.
|
||||
* @exception GeographicErr if the memory for the MGRS string can't be
|
||||
* allocated.
|
||||
*
|
||||
* \e prec specifies the precision of the MGRS string as follows:
|
||||
* - \e prec = −1 (min), only the grid zone is returned
|
||||
* - \e prec = 0, 100 km
|
||||
* - \e prec = 1, 10 km
|
||||
* - \e prec = 2, 1 km
|
||||
* - \e prec = 3, 100 m
|
||||
* - \e prec = 4, 10 m
|
||||
* - \e prec = 5, 1 m
|
||||
* - \e prec = 6, 0.1 m
|
||||
* - …
|
||||
* - \e prec = 11 (max), 1 μm
|
||||
*
|
||||
* UTM eastings are allowed to be in the range [100 km, 900 km], northings
|
||||
* are allowed to be in in [0 km, 9500 km] for the northern hemisphere and
|
||||
* in [1000 km, 10000 km] for the southern hemisphere. (However UTM
|
||||
* northings can be continued across the equator. So the actual limits on
|
||||
* the northings are [−9000 km, 9500 km] for the "northern"
|
||||
* hemisphere and [1000 km, 19500 km] for the "southern" hemisphere.)
|
||||
*
|
||||
* UPS eastings/northings are allowed to be in the range [1300 km, 2700 km]
|
||||
* in the northern hemisphere and in [800 km, 3200 km] in the southern
|
||||
* hemisphere.
|
||||
*
|
||||
* The ranges are 100 km more restrictive than for the conversion between
|
||||
* geographic coordinates and UTM and UPS given by UTMUPS. These
|
||||
* restrictions are dictated by the allowed letters in MGRS coordinates.
|
||||
* The choice of 9500 km for the maximum northing for northern hemisphere
|
||||
* and of 1000 km as the minimum northing for southern hemisphere provide
|
||||
* at least 0.5 degree extension into standard UPS zones. The upper ends
|
||||
* of the ranges for the UPS coordinates is dictated by requiring symmetry
|
||||
* about the meridians 0E and 90E.
|
||||
*
|
||||
* All allowed UTM and UPS coordinates may now be converted to legal MGRS
|
||||
* coordinates with the proviso that eastings and northings on the upper
|
||||
* boundaries are silently reduced by about 4 nm (4 nanometers) to place
|
||||
* them \e within the allowed range. (This includes reducing a southern
|
||||
* hemisphere northing of 10000 km by 4 nm so that it is placed in latitude
|
||||
* band M.) The UTM or UPS coordinates are truncated to requested
|
||||
* precision to determine the MGRS coordinate. Thus in UTM zone 38n, the
|
||||
* square area with easting in [444 km, 445 km) and northing in [3688 km,
|
||||
* 3689 km) maps to MGRS coordinate 38SMB4488 (at \e prec = 2, 1 km),
|
||||
* Khulani Sq., Baghdad.
|
||||
*
|
||||
* The UTM/UPS selection and the UTM zone is preserved in the conversion to
|
||||
* MGRS coordinate. Thus for \e zone > 0, the MGRS coordinate begins with
|
||||
* the zone number followed by one of [C--M] for the southern
|
||||
* hemisphere and [N--X] for the northern hemisphere. For \e zone =
|
||||
* 0, the MGRS coordinates begins with one of [AB] for the southern
|
||||
* hemisphere and [XY] for the northern hemisphere.
|
||||
*
|
||||
* The conversion to the MGRS is exact for prec in [0, 5] except that a
|
||||
* neighboring latitude band letter may be given if the point is within 5nm
|
||||
* of a band boundary. For prec in [6, 11], the conversion is accurate to
|
||||
* roundoff.
|
||||
*
|
||||
* If \e prec = −1, then the "grid zone designation", e.g., 18T, is
|
||||
* returned. This consists of the UTM zone number (absent for UPS) and the
|
||||
* first letter of the MGRS string which labels the latitude band for UTM
|
||||
* and the hemisphere for UPS.
|
||||
*
|
||||
* If \e x or \e y is NaN or if \e zone is UTMUPS::INVALID, the returned
|
||||
* MGRS string is "INVALID".
|
||||
*
|
||||
* Return the result via a reference argument to avoid the overhead of
|
||||
* allocating a potentially large number of small strings. If an error is
|
||||
* thrown, then \e mgrs is unchanged.
|
||||
**********************************************************************/
|
||||
static void Forward(int zone, bool northp, real x, real y,
|
||||
int prec, std::string& mgrs);
|
||||
|
||||
/**
|
||||
* Convert UTM or UPS coordinate to an MGRS coordinate when the latitude is
|
||||
* known.
|
||||
*
|
||||
* @param[in] zone UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[in] lat latitude (degrees).
|
||||
* @param[in] prec precision relative to 100 km.
|
||||
* @param[out] mgrs MGRS string.
|
||||
* @exception GeographicErr if \e zone, \e x, or \e y is outside its
|
||||
* allowed range.
|
||||
* @exception GeographicErr if \e lat is inconsistent with the given UTM
|
||||
* coordinates.
|
||||
* @exception std::bad_alloc if the memory for \e mgrs can't be allocated.
|
||||
*
|
||||
* The latitude is ignored for \e zone = 0 (UPS); otherwise the latitude is
|
||||
* used to determine the latitude band and this is checked for consistency
|
||||
* using the same tests as Reverse.
|
||||
**********************************************************************/
|
||||
static void Forward(int zone, bool northp, real x, real y, real lat,
|
||||
int prec, std::string& mgrs);
|
||||
|
||||
/**
|
||||
* Convert a MGRS coordinate to UTM or UPS coordinates.
|
||||
*
|
||||
* @param[in] mgrs MGRS string.
|
||||
* @param[out] zone UTM zone (zero means UPS).
|
||||
* @param[out] northp hemisphere (true means north, false means south).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] prec precision relative to 100 km.
|
||||
* @param[in] centerp if true (default), return center of the MGRS square,
|
||||
* else return SW (lower left) corner.
|
||||
* @exception GeographicErr if \e mgrs is illegal.
|
||||
*
|
||||
* All conversions from MGRS to UTM/UPS are permitted provided the MGRS
|
||||
* coordinate is a possible result of a conversion in the other direction.
|
||||
* (The leading 0 may be dropped from an input MGRS coordinate for UTM
|
||||
* zones 1--9.) In addition, MGRS coordinates with a neighboring
|
||||
* latitude band letter are permitted provided that some portion of the
|
||||
* 100 km block is within the given latitude band. Thus
|
||||
* - 38VLS and 38WLS are allowed (latitude 64N intersects the square
|
||||
* 38[VW]LS); but 38VMS is not permitted (all of 38WMS is north of 64N)
|
||||
* - 38MPE and 38NPF are permitted (they straddle the equator); but 38NPE
|
||||
* and 38MPF are not permitted (the equator does not intersect either
|
||||
* block).
|
||||
* - Similarly ZAB and YZB are permitted (they straddle the prime
|
||||
* meridian); but YAB and ZZB are not (the prime meridian does not
|
||||
* intersect either block).
|
||||
*
|
||||
* The UTM/UPS selection and the UTM zone is preserved in the conversion
|
||||
* from MGRS coordinate. The conversion is exact for prec in [0, 5]. With
|
||||
* \e centerp = true, the conversion from MGRS to geographic and back is
|
||||
* stable. This is not assured if \e centerp = false.
|
||||
*
|
||||
* If a "grid zone designation" (for example, 18T or A) is given, then some
|
||||
* suitable (but essentially arbitrary) point within that grid zone is
|
||||
* returned. The main utility of the conversion is to allow \e zone and \e
|
||||
* northp to be determined. In this case, the \e centerp parameter is
|
||||
* ignored and \e prec is set to −1.
|
||||
*
|
||||
* If the first 3 characters of \e mgrs are "INV", then \e x and \e y are
|
||||
* set to NaN, \e zone is set to UTMUPS::INVALID, and \e prec is set to
|
||||
* −2.
|
||||
*
|
||||
* If an exception is thrown, then the arguments are unchanged.
|
||||
**********************************************************************/
|
||||
static void Reverse(const std::string& mgrs,
|
||||
int& zone, bool& northp, real& x, real& y,
|
||||
int& prec, bool centerp = true);
|
||||
|
||||
/**
|
||||
* Split a MGRS grid reference into its components.
|
||||
*
|
||||
* @param[in] mgrs MGRS string, e.g., 38SMB4488.
|
||||
* @param[out] gridzone the grid zone, e.g., 38S.
|
||||
* @param[out] block the 100km block id, e.g., MB.
|
||||
* @param[out] easting the leading digits of the block easting, e.g., 44.
|
||||
* @param[out] northing the leading digits of the block easting, e.g., 88.
|
||||
* @exception GeographicErr if \e mgrs is illegal.
|
||||
*
|
||||
* Only the most rudimentary checking of MGRS grid ref is done: it is
|
||||
* expected to consist of 0-2 digits followed by 1 or 3 letters, followed
|
||||
* (in the case of 3 letters) by an even number (possibly 0) of digits. In
|
||||
* reporting errors, the letters I and O (illegal in MSRS) are regarded as
|
||||
* non-alphabetic. The returned \e gridzone will always be non-empty. The
|
||||
* other output arguments may be empty strings.
|
||||
*
|
||||
* If the first 3 characters of \e mgrs are "INV", then \e gridzone is set
|
||||
* to those 3 characters and the other return arguments are set to empty
|
||||
* strings..
|
||||
*
|
||||
* If an exception is thrown, then the arguments are unchanged.
|
||||
**********************************************************************/
|
||||
static void Decode(const std::string& mgrs,
|
||||
std::string& gridzone, std::string& block,
|
||||
std::string& easting, std::string& northing);
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
static Math::real EquatorialRadius() { return UTMUPS::EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the WGS84 ellipsoid.
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
static Math::real Flattening() { return UTMUPS::Flattening(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Perform some checks on the UTMUPS coordinates on this ellipsoid. Throw
|
||||
* an error if any of the assumptions made in the MGRS class is not true.
|
||||
* This check needs to be carried out if the ellipsoid parameters (or the
|
||||
* UTM/UPS scales) are ever changed.
|
||||
**********************************************************************/
|
||||
static void Check();
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_MGRS_HPP
|
||||
Reference in New Issue
Block a user