Goby v2
moos_geodesy.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Goby Underwater Autonomy Project Libraries
8 // ("The Goby Libraries").
9 //
10 // The Goby Libraries are free software: you can redistribute them and/or modify
11 // them under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // The Goby Libraries are distributed in the hope that they will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
22 
23 #include <cmath>
24 #include <iostream>
25 #include <limits>
26 #include <sstream>
27 
28 #include "moos_geodesy.h"
29 
30 CMOOSGeodesy::CMOOSGeodesy()
31  : m_sUTMZone(0), m_dOriginEasting(0), m_dOriginNorthing(0), m_dOriginLongitude(0),
32  m_dOriginLatitude(0), pj_utm_(0), pj_latlong_(0)
33 {
34 }
35 
36 CMOOSGeodesy::~CMOOSGeodesy()
37 {
38  pj_free(pj_utm_);
39  pj_free(pj_latlong_);
40 }
41 
42 bool CMOOSGeodesy::Initialise(double lat, double lon)
43 {
44  //Set the Origin of the local Grid Coordinate System
45  SetOriginLatitude(lat);
46  SetOriginLongitude(lon);
47 
48  int zone = (static_cast<int>(std::floor((lon + 180) / 6)) + 1) % 60;
49 
50  std::stringstream proj_utm;
51  proj_utm << "+proj=utm +ellps=WGS84 +zone=" << zone;
52 
53  if (!(pj_utm_ = pj_init_plus(proj_utm.str().c_str())))
54  {
55  std::cerr << "Failed to initiate utm proj" << std::endl;
56  return false;
57  }
58  if (!(pj_latlong_ = pj_init_plus("+proj=latlong +ellps=WGS84")))
59  {
60  std::cerr << "Failed to initiate latlong proj" << std::endl;
61  return false;
62  }
63 
64  //Translate the Origin coordinates into Northings and Eastings
65  double tempNorth = lat * DEG_TO_RAD, tempEast = lon * DEG_TO_RAD;
66 
67  int err;
68  if (err = pj_transform(pj_latlong_, pj_utm_, 1, 1, &tempEast, &tempNorth, NULL))
69  {
70  std::cerr << "Failed to transform datum, reason: " << pj_strerrno(err) << std::endl;
71  return false;
72  }
73 
74  //Then set the Origin for the Northing/Easting coordinate frame
75  //Also make a note of the UTM Zone we are operating in
76  SetOriginNorthing(tempNorth);
77  SetOriginEasting(tempEast);
78  SetUTMZone(zone);
79 
80  return true;
81 }
82 
83 double CMOOSGeodesy::GetOriginLongitude() { return m_dOriginLongitude; }
84 
85 double CMOOSGeodesy::GetOriginLatitude() { return m_dOriginLatitude; }
86 
87 void CMOOSGeodesy::SetOriginLongitude(double lon) { m_dOriginLongitude = lon; }
88 
89 void CMOOSGeodesy::SetOriginLatitude(double lat) { m_dOriginLatitude = lat; }
90 
91 void CMOOSGeodesy::SetOriginNorthing(double North) { m_dOriginNorthing = North; }
92 
93 void CMOOSGeodesy::SetOriginEasting(double East) { m_dOriginEasting = East; }
94 
95 void CMOOSGeodesy::SetUTMZone(int zone) { m_sUTMZone = zone; }
96 
97 int CMOOSGeodesy::GetUTMZone() { return m_sUTMZone; }
98 
99 bool CMOOSGeodesy::LatLong2LocalUTM(double lat, double lon, double& MetersNorth, double& MetersEast)
100 {
101  double dN, dE;
102  double tmpEast = lon * DEG_TO_RAD;
103  double tmpNorth = lat * DEG_TO_RAD;
104  MetersNorth = std::numeric_limits<double>::quiet_NaN();
105  MetersEast = std::numeric_limits<double>::quiet_NaN();
106 
107  if (!pj_latlong_ || !pj_utm_)
108  {
109  std::cerr << "Must call Initialise before calling LatLong2LocalUTM" << std::endl;
110  return false;
111  }
112 
113  int err;
114  if (err = pj_transform(pj_latlong_, pj_utm_, 1, 1, &tmpEast, &tmpNorth, NULL))
115  {
116  std::cerr << "Failed to transform (lat,lon) = (" << lat << "," << lon
117  << "), reason: " << pj_strerrno(err) << std::endl;
118  return false;
119  }
120 
121  MetersNorth = tmpNorth - GetOriginNorthing();
122  MetersEast = tmpEast - GetOriginEasting();
123  return true;
124 }
125 
126 double CMOOSGeodesy::GetOriginEasting() { return m_dOriginEasting; }
127 
128 double CMOOSGeodesy::GetOriginNorthing() { return m_dOriginNorthing; }
129 
130 bool CMOOSGeodesy::UTM2LatLong(double dfX, double dfY, double& dfLat, double& dfLong)
131 {
132  double x = dfX + GetOriginEasting();
133  double y = dfY + GetOriginNorthing();
134 
135  dfLat = std::numeric_limits<double>::quiet_NaN();
136  dfLong = std::numeric_limits<double>::quiet_NaN();
137 
138  if (!pj_latlong_ || !pj_utm_)
139  {
140  std::cerr << "Must call Initialise before calling UTM2LatLong" << std::endl;
141  return false;
142  }
143 
144  int err;
145  if (err = pj_transform(pj_utm_, pj_latlong_, 1, 1, &x, &y, NULL))
146  {
147  std::cerr << "Failed to transform (x,y) = (" << dfX << "," << dfY
148  << "), reason: " << pj_strerrno(err) << std::endl;
149  return false;
150  }
151 
152  dfLat = y * RAD_TO_DEG;
153  dfLong = x * RAD_TO_DEG;
154  return true;
155 }