geo-coordinate.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013 Magister Solutions Ltd
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Sami Rantanen <sami.rantanen@magister.fi>
19  */
20 
21 #include "geo-coordinate.h"
22 
23 #include "satellite-utils.h"
24 
25 #include <ns3/fatal-error.h>
26 #include <ns3/log.h>
27 
28 #include <cmath>
29 #include <sstream>
30 
31 NS_LOG_COMPONENT_DEFINE("geo-coordinate");
32 
33 namespace ns3
34 {
35 
37 
39  double longitude,
40  double altitude,
41  ReferenceEllipsoid_t refEllipsoid,
42  bool correctIfInvalid)
43  : m_refEllipsoid(refEllipsoid)
44 {
45  NS_LOG_FUNCTION(this << latitude << longitude << altitude);
46 
47  Construct(latitude, longitude, altitude, correctIfInvalid);
48 }
49 
51  double longitude,
52  double altitude,
53  bool correctIfInvalid)
54  : m_refEllipsoid(GeoCoordinate::SPHERE)
55 {
56  NS_LOG_FUNCTION(this << latitude << longitude << altitude);
57 
58  Construct(latitude, longitude, altitude, correctIfInvalid);
59 }
60 
62  : m_refEllipsoid(GeoCoordinate::SPHERE)
63 {
64  NS_LOG_FUNCTION(this << vector);
65 
66  ConstructFromVector(vector);
67 }
68 
70  : m_refEllipsoid(refEllipsoid)
71 {
72  NS_LOG_FUNCTION(this << vector);
73 
74  ConstructFromVector(vector);
75 }
76 
78  : m_latitude(NAN),
79  m_longitude(NAN),
80  m_altitude(NAN),
81  m_refEllipsoid(GeoCoordinate::SPHERE)
82 {
83  NS_LOG_FUNCTION(this);
84 
85  Initialize();
86 }
87 
88 void
89 GeoCoordinate::Construct(double latitude, double longitude, double altitude, bool correctIfInvalid)
90 {
91  NS_LOG_FUNCTION(this << latitude << longitude << altitude);
92 
93  if (correctIfInvalid)
94  {
95  if (latitude > 90)
96  {
97  latitude = 180 - latitude;
98  longitude += 180;
99  }
100  if (latitude < -90)
101  {
102  latitude = -180 - latitude;
103  longitude += 180;
104  }
105 
106  while (longitude > 180)
107  {
108  longitude -= 360;
109  }
110  while (longitude < -180)
111  {
112  longitude += 360;
113  }
114  }
115 
116  if (IsValidLatitude(latitude) == false)
117  {
118  NS_FATAL_ERROR("Invalid latitude!!! Got " << latitude);
119  }
120 
121  if (IsValidLongitude(longitude) == false)
122  {
123  NS_FATAL_ERROR("Invalid longitude!!! Got " << longitude);
124  }
125 
126  if (IsValidAltitude(altitude, m_refEllipsoid) == false)
127  {
128  NS_FATAL_ERROR("Invalid altitude!!! Got " << altitude);
129  }
130 
131  Initialize();
132 
133  m_latitude = latitude;
134  m_longitude = longitude;
135  m_altitude = altitude;
136 }
137 
138 Vector
140 {
141  NS_LOG_FUNCTION(this);
142 
143  Vector cartesian;
144  double latRads = SatUtils::DegreesToRadians(m_latitude);
145  double lonRads = SatUtils::DegreesToRadians(m_longitude);
146 
147  cartesian.x =
148  (GetRadiusCurvature(latRads) + m_altitude) * std::cos(latRads) * std::cos(lonRads);
149  cartesian.y =
150  (GetRadiusCurvature(latRads) + m_altitude) * std::cos(latRads) * std::sin(lonRads);
151  cartesian.z = (GetRadiusCurvature(latRads) * (1 - m_e2Param) + m_altitude) * std::sin(latRads);
152 
153  return cartesian;
154 }
155 
156 void
158 {
159  NS_LOG_FUNCTION(this);
160 
161  switch (m_refEllipsoid)
162  {
163  case SPHERE:
165  break;
166 
167  case WGS84:
169  break;
170 
171  case GRS80:
173  break;
174 
175  default:
176  NS_FATAL_ERROR("Invalid Reference Ellipsoid!!!");
177  break;
178  }
179 
183 }
184 
185 double
187 {
188  NS_LOG_FUNCTION(this);
189  return m_longitude;
190 }
191 
192 double
194 {
195  NS_LOG_FUNCTION(this);
196  return m_latitude;
197 }
198 
199 double
201 {
202  NS_LOG_FUNCTION(this);
203  return m_altitude;
204 }
205 
206 void
208 {
209  NS_LOG_FUNCTION(this << longitude);
210 
211  if (IsValidLongitude(longitude) == false)
212  {
213  NS_FATAL_ERROR("Invalid longitude!!!");
214  }
215 
216  m_longitude = longitude;
217 }
218 
219 void
221 {
222  NS_LOG_FUNCTION(this << latitude);
223 
224  if (IsValidLatitude(latitude) == false)
225  {
226  NS_FATAL_ERROR("Invalid latitude!!!");
227  }
228 
229  m_latitude = latitude;
230 }
231 
232 void
234 {
235  NS_LOG_FUNCTION(this << altitude);
236 
237  if (IsValidAltitude(altitude, m_refEllipsoid) == false)
238  {
239  NS_FATAL_ERROR("Invalid altitude!!!");
240  }
241 
242  m_altitude = altitude;
243 }
244 
245 void
247 {
248  NS_LOG_FUNCTION(this << v);
249 
250  Initialize();
251 
252  // distance from the position point (P) to earth center point (origin O)
253  double op = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
254 
255  if (op > 0)
256  {
257  // longitude calculation
258  double lon = std::atan(v.y / v.x);
259 
260  // scale longitude between - PI and PI (-180 and 180 in degrees)
261  if (v.x != 0 || v.y != 0)
262  {
263  m_longitude = SatUtils::RadiansToDegrees(std::atan(v.y / v.x));
264 
265  if (v.x < 0)
266  {
267  if (v.y > 0)
268  {
269  m_longitude = 180 + m_longitude;
270  lon = lon - M_PI;
271  }
272  else
273  {
274  m_longitude = -180 + m_longitude;
275  lon = M_PI + lon;
276  }
277  }
278  }
279 
280  // Geocentric latitude
281  double latG = std::atan(v.z / (std::sqrt(v.x * v.x + v.y * v.y)));
282 
283  // Geocentric latitude (of point Q, Q is intersection point of segment OP and reference
284  // ellipsoid)
285  double latQ = std::atan(v.z / ((1 - m_e2Param) * (std::sqrt(v.x * v.x + v.y * v.y))));
286 
287  // calculate radius of the curvature
288  double rCurvature = GetRadiusCurvature(latQ);
289 
290  // x, y, z of point Q
291  double xQ = rCurvature * std::cos(latQ) * std::cos(lon);
292  double yQ = rCurvature * std::cos(latQ) * std::sin(lon);
293  double zQ = rCurvature * (1 - m_e2Param) * std::sin(latQ);
294 
295  // distance OQ
296  double oq = std::sqrt(xQ * xQ + yQ * yQ + zQ * zQ);
297 
298  // distance PQ is OP - OQ
299  double pq = op - oq;
300 
301  // length of the normal segment from point P of line (PO) to point T.
302  // T is intersection point of linen the PO normal and ellipsoid normal from point Q.
303  double tp = pq * std::sin(latG - latQ);
304 
305  m_latitude = SatUtils::RadiansToDegrees(latQ + tp / op * std::cos(latQ - latG));
306 
307  m_altitude = pq * std::cos(latQ - latG);
308  }
309 }
310 
311 double
312 GeoCoordinate::GetRadiusCurvature(double latitude) const
313 {
314  return (m_equatorRadius / std::sqrt(1 - m_e2Param * std::sin(latitude) * std::sin(latitude)));
315 }
316 
317 bool
319 {
320  double polarRadius = NAN;
321 
322  switch (refEllipsoid)
323  {
324  case SPHERE:
325  polarRadius = GeoCoordinate::polarRadius_sphere;
326  break;
327 
328  case WGS84:
329  polarRadius = GeoCoordinate::polarRadius_wgs84;
330  break;
331 
332  case GRS80:
333  polarRadius = GeoCoordinate::polarRadius_grs80;
334  break;
335 
336  default:
337  NS_FATAL_ERROR("Invalid polar radius value!!!");
338  break;
339  }
340 
341  return ((polarRadius + altitude) >= 0);
342 }
343 
344 std::ostream&
345 operator<<(std::ostream& os, const GeoCoordinate& coordinate)
346 {
347  double longitude = coordinate.GetLongitude();
348  double latitude = coordinate.GetLatitude();
349  double altitude = coordinate.GetAltitude();
350 
351  os << latitude << "," << longitude << "," << altitude;
352 
353  return os;
354 }
355 
356 std::istream&
357 operator>>(std::istream& is, GeoCoordinate& coordinate)
358 {
359  double longitude;
360  double latitude;
361  double altitude;
362  char c1;
363  char c2;
364 
365  is >> latitude >> c1 >> longitude >> c2 >> altitude;
366 
367  coordinate.SetLongitude(longitude);
368  coordinate.SetLatitude(latitude);
369  coordinate.SetAltitude(altitude);
370 
371  if (c1 != ',' || c2 != ',')
372  {
373  is.setstate(std::ios_base::failbit);
374  }
375  return is;
376 }
377 
378 } // namespace ns3
GeoCoordinate class is used to store and operate with geodetic coordinates.
static constexpr double polarRadius_grs80
void SetAltitude(double altitude)
Sets altitude value of coordinate.
ReferenceEllipsoid_t m_refEllipsoid
void SetLatitude(double latitude)
Sets latitude value of coordinate.
static constexpr double polarRadius_wgs84
static bool IsValidAltitude(double altitude, ReferenceEllipsoid_t refEllipsoide)
Checks if altitude is in valid range.
double m_altitude
altitude of coordinate
double GetAltitude() const
Gets altitude value of coordinate.
void SetLongitude(double longitude)
Sets longitude value of coordinate.
double GetLatitude() const
Gets latitude value of coordinate.
void Initialize()
This method is called to initialize needed parameters according to used reference ellipsoide.
GeoCoordinate()
Create GeoCoordinate with zero values of longitude, latitude and altitude.
static bool IsValidLongitude(double longitude)
Checks if longitude is in valid range.
double GetLongitude() const
Gets longitude value of coordinate.
static bool IsValidLatitude(double latitude)
Checks if latitude is in valid range.
Vector ToVector() const
Converts Geodetic coordinates to Cartesian coordinates.
void ConstructFromVector(const Vector &vector)
Creates Geodetic coordinates from given Cartesian coordinates.
double m_latitude
latitude of coordinate
double GetRadiusCurvature(double latitude) const
Gets the radius of curvature in the prime vertical.
static constexpr double equatorRadius
double m_longitude
longitude of coordinate
void Construct(double latitude, double longitude, double altitude, bool correctIfInvalid)
static constexpr double polarRadius_sphere
static T RadiansToDegrees(T radian)
Converts radians to degrees.
static T DegreesToRadians(T degree)
Converts degrees to radians.
SatArqSequenceNumber is handling the sequence numbers for the ARQ process.
std::istream & operator>>(std::istream &is, GeoCoordinate &coordinate)
std::ostream & operator<<(std::ostream &os, const GeoCoordinate &coordinate)
ATTRIBUTE_HELPER_CPP(GeoCoordinate)