1 /**
2  * \file GARS.hpp
3  * \brief Header for GeographicLib::GARS class
4  *
5  * Copyright (c) Charles Karney (2015-2021) <charles@karney.com> and licensed
6  * under the MIT/X11 License.  For more information, see
7  * https://geographiclib.sourceforge.io/
8  **********************************************************************/
9 
10 #if !defined(GEOGRAPHICLIB_GARS_HPP)
11 #define GEOGRAPHICLIB_GARS_HPP 1
12 
13 #include <GeographicLib/Constants.hpp>
14 
15 #if defined(_MSC_VER)
16 // Squelch warnings about dll vs string
17 #  pragma warning (push)
18 #  pragma warning (disable: 4251)
19 #endif
20 
21 namespace GeographicLib {
22 
23   /**
24    * \brief Conversions for the Global Area Reference System (GARS)
25    *
26    * The Global Area Reference System is described in
27    * - https://en.wikipedia.org/wiki/Global_Area_Reference_System
28    * - https://earth-info.nga.mil/index.php?dir=coordsys&action=coordsys#tab_gars
29    * .
30    * It provides a compact string representation of a geographic area
31    * (expressed as latitude and longitude).  The classes Georef and Geohash
32    * implement similar compact representations.
33    *
34    * Example of use:
35    * \include example-GARS.cpp
36    **********************************************************************/
37 
38   class GEOGRAPHICLIB_EXPORT GARS {
39   private:
40     typedef Math::real real;
41     static const char* const digits_;
42     static const char* const letters_;
43     enum {
44       lonorig_ = -180,          // Origin for longitude
45       latorig_ = -90,           // Origin for latitude
46       baselon_ = 10,            // Base for longitude tiles
47       baselat_ = 24,            // Base for latitude tiles
48       lonlen_ = 3,
49       latlen_ = 2,
50       baselen_ = lonlen_ + latlen_,
51       mult1_ = 2,               // base precision = 1/2 degree
52       mult2_ = 2,               // 6th char gives 2x more precision
53       mult3_ = 3,               // 7th char gives 3x more precision
54       m_ = mult1_ * mult2_ * mult3_,
55       maxprec_ = 2,
56       maxlen_ = baselen_ + maxprec_,
57     };
58     GARS();                     // Disable constructor
59 
60   public:
61 
62     /**
63      * Convert from geographic coordinates to GARS.
64      *
65      * @param[in] lat latitude of point (degrees).
66      * @param[in] lon longitude of point (degrees).
67      * @param[in] prec the precision of the resulting GARS.
68      * @param[out] gars the GARS string.
69      * @exception GeographicErr if \e lat is not in [&minus;90&deg;,
70      *   90&deg;].
71      * @exception std::bad_alloc if memory for \e gars can't be allocated.
72      *
73      * \e prec specifies the precision of \e gars as follows:
74      * - \e prec = 0 (min), 30' precision, e.g., 006AG;
75      * - \e prec = 1, 15' precision, e.g., 006AG3;
76      * - \e prec = 2 (max), 5' precision, e.g., 006AG39.
77      *
78      * If \e lat or \e lon is NaN, then \e gars is set to "INVALID".
79      **********************************************************************/
80     static void Forward(real lat, real lon, int prec, std::string& gars);
81 
82     /**
83      * Convert from GARS to geographic coordinates.
84      *
85      * @param[in] gars the GARS.
86      * @param[out] lat latitude of point (degrees).
87      * @param[out] lon longitude of point (degrees).
88      * @param[out] prec the precision of \e gars.
89      * @param[in] centerp if true (the default) return the center of the
90      *   \e gars, otherwise return the south-west corner.
91      * @exception GeographicErr if \e gars is illegal.
92      *
93      * The case of the letters in \e gars is ignored.  \e prec is in the range
94      * [0, 2] and gives the precision of \e gars as follows:
95      * - \e prec = 0 (min), 30' precision, e.g., 006AG;
96      * - \e prec = 1, 15' precision, e.g., 006AG3;
97      * - \e prec = 2 (max), 5' precision, e.g., 006AG39.
98      *
99      * If the first 3 characters of \e gars are "INV", then \e lat and \e lon
100      * are set to NaN and \e prec is unchanged.
101      **********************************************************************/
102     static void Reverse(const std::string& gars, real& lat, real& lon,
103                         int& prec, bool centerp = true);
104 
105     /**
106      * The angular resolution of a GARS.
107      *
108      * @param[in] prec the precision of the GARS.
109      * @return the latitude-longitude resolution (degrees).
110      *
111      * Internally, \e prec is first put in the range [0, 2].
112      **********************************************************************/
Resolution(int prec)113     static Math::real Resolution(int prec) {
114       return 1/real(prec <= 0 ? mult1_ : (prec == 1 ? mult1_ * mult2_ :
115                                           mult1_ * mult2_ * mult3_));
116     }
117 
118     /**
119      * The GARS precision required to meet a given geographic resolution.
120      *
121      * @param[in] res the minimum of resolution in latitude and longitude
122      *   (degrees).
123      * @return GARS precision.
124      *
125      * The returned length is in the range [0, 2].
126      **********************************************************************/
Precision(real res)127     static int Precision(real res) {
128       using std::abs; res = abs(res);
129       for (int prec = 0; prec < maxprec_; ++prec)
130         if (Resolution(prec) <= res)
131           return prec;
132       return maxprec_;
133     }
134 
135   };
136 
137 } // namespace GeographicLib
138 
139 #if defined(_MSC_VER)
140 #  pragma warning (pop)
141 #endif
142 
143 #endif  // GEOGRAPHICLIB_GARS_HPP
144