9 #include <utl/UTMPoint.h>
10 #include <utl/Point.h>
11 #include <utl/CoordinateSystem.h>
12 #include <utl/ErrorLogger.h>
13 #include <utl/AugerUnits.h>
14 #include <utl/MathConstants.h>
16 #include <boost/tuple/tuple.hpp>
17 #include <boost/tuple/tuple_io.hpp>
28 const double utmZoneWidth = 6*
deg;
29 const double utmZoneOffset = 180*
deg;
33 const char utmBandLetter[] =
"CDEFGHJKLMNPQRSTUVWX";
34 const int numberOfUTMBands =
sizeof(utmBandLetter) /
sizeof(
char) - 1;
35 const double widthOfUTMBand = 8*
deg;
36 [[maybe_unused]]
const double southernmostUTMBand = -80*
deg;
37 const char firstNorthernBand =
'N';
56 pt.TransformTo(theCS);
66 boost::tuple<double, double, double>
78 const double e1 = (1 -
sqrt(1-eccSquared)) / (1 +
sqrt(1-eccSquared));
83 const bool inNorthernHemisphere =
fBand >= firstNorthernBand;
84 if (!inNorthernHemisphere)
88 const double LongitudeOrigin = (
fZone - 0.5) * utmZoneWidth - utmZoneOffset;
90 const double eccPrimeSquared = eccSquared / (1-eccSquared);
91 const double e4 = eccSquared*eccSquared;
92 const double e6 = e4*eccSquared;
93 const double e8 = e4*e4;
94 const double e1_2 = e1*e1;
96 const double M = y / k0;
97 const double mu = M / (a * (1 - eccSquared/4 - 3*e4/64 - 5*e6/256 - 175*e8/16384));
98 const double mur = mu/
rad;
99 const double phi1 = mur
100 + (3*e1/2 - 27*e1_2*e1/32)*sin(2*mur)
101 + (21*e1_2/16 - 55*e1_2*e1_2/32)*sin(4*mur)
102 + (151*e1*e1_2/96)*sin(6*mur)
103 + (1097*e1_2*e1_2/512)*sin(8*mur);
105 const double phi1r = phi1/
rad;
106 const double cosPhi1 = cos(phi1r);
107 const double sinPhi1 = sin(phi1r);
108 const double tanPhi1 = sinPhi1/cosPhi1;
110 const double N1 = a /
sqrt(1 - eccSquared * sinPhi1*sinPhi1);
111 const double T1 = tanPhi1*tanPhi1;
112 const double C1 = eccPrimeSquared * cosPhi1*cosPhi1;
113 const double R1 = a * (1-eccSquared) /
pow(1 - eccSquared * sinPhi1*sinPhi1, 1.5);
114 const double D = x / (N1*k0);
115 const double D2 = D*D;
116 const double D4 = D2*D2;
117 const double C1_2 = C1*C1;
118 const double T1_2 = T1*T1;
120 const double latitude = phi1
123 - (5 + 3*T1 + 10*C1 - 4*C1_2 - 9*eccPrimeSquared) * D4 / 24
124 + (61 + 90*T1 + 298*C1 + 45*T1_2 - 252*eccPrimeSquared - 3*C1_2) * D2*D4 / 720
127 const double longitude =
129 - (1 + 2*T1 + C1) * D*D2 / 6
130 + (5 - 2*C1 + 28*T1 - 3*C1_2 + 8*eccPrimeSquared + 24*T1_2) * D*D4 / 120
131 ) / cosPhi1 + LongitudeOrigin;
133 return boost::make_tuple(latitude, longitude,
fHeight);
145 std::ostringstream msg;
146 msg <<
"DATUM conversions not implemented in UTMPoint constructor";
166 boost::tie(latitude, longitude, height) =
180 const double theLongitude)
185 const double LongitudeOrigin = (
fZone-0.5)*utmZoneWidth - utmZoneOffset;
195 const double lat = theLatitude /
rad;
196 const double cosLatitude = cos(lat);
197 const double sinLatitude = sin(lat);
198 const double tanLatitude = sinLatitude / cosLatitude;
200 const double eccPrimeSquared = eccSquared / (1 - eccSquared);
202 const double N = a /
sqrt(1 - eccSquared * sinLatitude*sinLatitude);
203 const double T = tanLatitude*tanLatitude;
204 const double C = eccPrimeSquared * cosLatitude*cosLatitude;
205 const double A = cosLatitude * (theLongitude/
rad - LongitudeOrigin/
rad);
207 const double e4 = eccSquared*eccSquared;
208 const double e6 = e4 * eccSquared;
209 const double e8 = e4*e4;
229 const double c5 = 315 * e8 / 131072;
239 const double A2 = A*A;
240 const double A3 = A2*A;
241 const double T2 = T*T;
243 fEasting = k0 * N * (A + (1-T+C) * A3/6
244 + (5 - 18*T + T2 + 72*C - 58*eccPrimeSquared) * A2*A3 / 120)
248 (A2/2 + (5 - T + 9*C + 4*C*C) * A*A3 / 24
249 + (61 - 58*T + T2 + 600*C - 330*eccPrimeSquared) * A3*A3 / 720));
252 fNorthing += 10000000;
259 if (fZone < eZoneMin || fZone >
eZoneMax) {
260 std::ostringstream msg;
261 msg <<
"Zone out of bounds: " <<
fZone
262 <<
" not in " <<
eZoneMin <<
".." << eZoneMax <<
".";
275 const double theLongitude)
278 int zone = int(floor(theLongitude / utmZoneWidth)) +
eZoneMax/2 + 1;
281 if (56*
deg <= theLatitude && theLatitude < 64*
deg &&
282 3*
deg <= theLongitude && theLatitude < 12*
deg) {
285 else if (72*
deg <= theLatitude && theLatitude < 84*
deg) {
287 if (0 <= theLongitude && theLongitude < 9*
deg)
289 else if (9*
deg <= theLongitude && theLongitude < 21*
deg)
291 else if (21*
deg <= theLongitude && theLongitude < 33*
deg)
293 else if (33*
deg <= theLongitude && theLongitude < 42*
deg)
305 int index = int(floor(theLatitude / widthOfUTMBand)) + numberOfUTMBands/2;
306 if (0 <= index && index < numberOfUTMBands)
307 return utmBandLetter[index];
308 else if (72*
deg <= theLatitude && theLatitude < 84*
deg)
311 std::ostringstream msg;
312 msg <<
"Latitude " << theLatitude/
deg
313 <<
" deg out of range [-80 .. 84]. "
314 "Cannot calculate band letter." << std::endl;
double GetEccentricity2() const
Get eccentricity.
boost::tuple< double, double, double, int, char > GetCoordinates() const
Get norting, easting, height, zone, and band.
Class to hold and convert a point in geodetic coordinates.
static int ZoneFromLatitudeLongitude(const double theLatitude, const double theLongitude)
Calculate zone number from latitude and longitude.
void SetFromOtherDatum(const UTMPoint &theUTMPoint)
Datum transformation.
Point LatitudeLongitudeHeightToPoint(double const latitude, double const longitude, double const height) const
Convert Lat/Long/Height to Point.
#define FATAL(message)
Macro for logging fatal messages.
double pow(const double x, const unsigned int i)
Report attempts to use invalid UTM zone.
Stream & operator<<(Stream &s, MessageLoggerConfig &mlc)
Applies the configuration to the given stream.
void VerifyZone()
verify zone and throw exception if out of bounds
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
double GetEquatorialRadius() const
Get equatorial radius ( )
Triple PointToLatitudeLongitudeHeight(const Point &thePoint) const
Convert Point to Lat/Long/Height.
int fZone
zone runs from 1 to 60
Report problems in UTM handling.
const ReferenceEllipsoid * fEllipsoid
char fBand
Letter indicating band, C-X, w/o O, I.
void SetFromLatitudeLongitude(const double theLatitude, const double theLongitude)
Construction from geodetic Latitude and Longitude (height identical)
static char BandFromLatitude(const double theLatitude)
Calculate band letter from latitude and longitude.
void SetFromCartesian(const Point &thePoint)
Construction from Cartesian coordinates.
Point GetPoint(const CoordinateSystemPtr &theCS=CoordinateSystemPtr()) const
Get a cartesian point from an UTMPoint.
#define ERROR(message)
Macro for logging error messages.
boost::tuple< double, double, double > GetGeodeticCoordinates() const
Get geodetic latitude, longitude, height.