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 <ios>
30 #include <istream>
31 #include <ostream>
32 #include <sstream>
33 #include <stdint.h>
34 
35 NS_LOG_COMPONENT_DEFINE("geo-coordinate");
36 
37 namespace ns3
38 {
39 
41 
43  double longitude,
44  double altitude,
45  ReferenceEllipsoid_t refEllipsoid,
46  bool correctIfInvalid)
47  : m_refEllipsoid(refEllipsoid)
48 {
49  NS_LOG_FUNCTION(this << latitude << longitude << altitude);
50 
51  Construct(latitude, longitude, altitude, correctIfInvalid);
52 }
53 
55  double longitude,
56  double altitude,
57  bool correctIfInvalid)
58  : m_refEllipsoid(GeoCoordinate::SPHERE)
59 {
60  NS_LOG_FUNCTION(this << latitude << longitude << altitude);
61 
62  Construct(latitude, longitude, altitude, correctIfInvalid);
63 }
64 
66  : m_refEllipsoid(GeoCoordinate::SPHERE)
67 {
68  NS_LOG_FUNCTION(this << vector);
69 
70  ConstructFromVector(vector);
71 }
72 
74  : m_refEllipsoid(refEllipsoid)
75 {
76  NS_LOG_FUNCTION(this << vector);
77 
78  ConstructFromVector(vector);
79 }
80 
82  : m_latitude(NAN),
83  m_longitude(NAN),
84  m_altitude(NAN),
85  m_refEllipsoid(GeoCoordinate::SPHERE)
86 {
87  NS_LOG_FUNCTION(this);
88 
89  Initialize();
90 }
91 
92 void
93 GeoCoordinate::Construct(double latitude, double longitude, double altitude, bool correctIfInvalid)
94 {
95  NS_LOG_FUNCTION(this << latitude << longitude << altitude);
96 
97  if (correctIfInvalid)
98  {
99  if (latitude > 90)
100  {
101  latitude = 180 - latitude;
102  longitude += 180;
103  }
104  if (latitude < -90)
105  {
106  latitude = -180 - latitude;
107  longitude += 180;
108  }
109 
110  while (longitude > 180)
111  {
112  longitude -= 360;
113  }
114  while (longitude < -180)
115  {
116  longitude += 360;
117  }
118  }
119 
120  if (IsValidLatitude(latitude) == false)
121  {
122  NS_FATAL_ERROR("Invalid latitude!!! Got " << latitude);
123  }
124 
125  if (IsValidLongitude(longitude) == false)
126  {
127  NS_FATAL_ERROR("Invalid longitude!!! Got " << longitude);
128  }
129 
130  if (IsValidAltitude(altitude, m_refEllipsoid) == false)
131  {
132  NS_FATAL_ERROR("Invalid altitude!!! Got " << altitude);
133  }
134 
135  Initialize();
136 
137  m_latitude = latitude;
138  m_longitude = longitude;
139  m_altitude = altitude;
140 }
141 
142 Vector
144 {
145  NS_LOG_FUNCTION(this);
146 
147  Vector cartesian;
148  double latRads = SatUtils::DegreesToRadians(m_latitude);
149  double lonRads = SatUtils::DegreesToRadians(m_longitude);
150 
151  cartesian.x =
152  (GetRadiusCurvature(latRads) + m_altitude) * std::cos(latRads) * std::cos(lonRads);
153  cartesian.y =
154  (GetRadiusCurvature(latRads) + m_altitude) * std::cos(latRads) * std::sin(lonRads);
155  cartesian.z = (GetRadiusCurvature(latRads) * (1 - m_e2Param) + m_altitude) * std::sin(latRads);
156 
157  return cartesian;
158 }
159 
160 void
162 {
163  NS_LOG_FUNCTION(this);
164 
165  switch (m_refEllipsoid)
166  {
167  case SPHERE:
169  break;
170 
171  case WGS84:
173  break;
174 
175  case GRS80:
177  break;
178 
179  default:
180  NS_FATAL_ERROR("Invalid Reference Ellipsoid!!!");
181  break;
182  }
183 
187 }
188 
189 double
191 {
192  NS_LOG_FUNCTION(this);
193  return m_longitude;
194 }
195 
196 double
198 {
199  NS_LOG_FUNCTION(this);
200  return m_latitude;
201 }
202 
203 double
205 {
206  NS_LOG_FUNCTION(this);
207  return m_altitude;
208 }
209 
210 void
212 {
213  NS_LOG_FUNCTION(this << longitude);
214 
215  if (IsValidLongitude(longitude) == false)
216  {
217  NS_FATAL_ERROR("Invalid longitude!!!");
218  }
219 
220  m_longitude = longitude;
221 }
222 
223 void
225 {
226  NS_LOG_FUNCTION(this << latitude);
227 
228  if (IsValidLatitude(latitude) == false)
229  {
230  NS_FATAL_ERROR("Invalid latitude!!!");
231  }
232 
233  m_latitude = latitude;
234 }
235 
236 void
238 {
239  NS_LOG_FUNCTION(this << altitude);
240 
241  if (IsValidAltitude(altitude, m_refEllipsoid) == false)
242  {
243  NS_FATAL_ERROR("Invalid altitude!!!");
244  }
245 
246  m_altitude = altitude;
247 }
248 
249 void
251 {
252  NS_LOG_FUNCTION(this << v);
253 
254  Initialize();
255 
256  // distance from the position point (P) to earth center point (origin O)
257  double op = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
258 
259  if (op > 0)
260  {
261  // longitude calculation
262  double lon = std::atan(v.y / v.x);
263 
264  // scale longitude between - PI and PI (-180 and 180 in degrees)
265  if (v.x != 0 || v.y != 0)
266  {
267  m_longitude = SatUtils::RadiansToDegrees(std::atan(v.y / v.x));
268 
269  if (v.x < 0)
270  {
271  if (v.y > 0)
272  {
273  m_longitude = 180 + m_longitude;
274  lon = lon - M_PI;
275  }
276  else
277  {
278  m_longitude = -180 + m_longitude;
279  lon = M_PI + lon;
280  }
281  }
282  }
283 
284  // Geocentric latitude
285  double latG = std::atan(v.z / (std::sqrt(v.x * v.x + v.y * v.y)));
286 
287  // Geocentric latitude (of point Q, Q is intersection point of segment OP and reference
288  // ellipsoid)
289  double latQ = std::atan(v.z / ((1 - m_e2Param) * (std::sqrt(v.x * v.x + v.y * v.y))));
290 
291  // calculate radius of the curvature
292  double rCurvature = GetRadiusCurvature(latQ);
293 
294  // x, y, z of point Q
295  double xQ = rCurvature * std::cos(latQ) * std::cos(lon);
296  double yQ = rCurvature * std::cos(latQ) * std::sin(lon);
297  double zQ = rCurvature * (1 - m_e2Param) * std::sin(latQ);
298 
299  // distance OQ
300  double oq = std::sqrt(xQ * xQ + yQ * yQ + zQ * zQ);
301 
302  // distance PQ is OP - OQ
303  double pq = op - oq;
304 
305  // length of the normal segment from point P of line (PO) to point T.
306  // T is intersection point of linen the PO normal and ellipsoid normal from point Q.
307  double tp = pq * std::sin(latG - latQ);
308 
309  m_latitude = SatUtils::RadiansToDegrees(latQ + tp / op * std::cos(latQ - latG));
310 
311  m_altitude = pq * std::cos(latQ - latG);
312  }
313 }
314 
315 double
316 GeoCoordinate::GetRadiusCurvature(double latitude) const
317 {
318  return (m_equatorRadius / std::sqrt(1 - m_e2Param * std::sin(latitude) * std::sin(latitude)));
319 }
320 
321 bool
323 {
324  double polarRadius = NAN;
325 
326  switch (refEllipsoid)
327  {
328  case SPHERE:
329  polarRadius = GeoCoordinate::polarRadius_sphere;
330  break;
331 
332  case WGS84:
333  polarRadius = GeoCoordinate::polarRadius_wgs84;
334  break;
335 
336  case GRS80:
337  polarRadius = GeoCoordinate::polarRadius_grs80;
338  break;
339 
340  default:
341  NS_FATAL_ERROR("Invalid polar radius value!!!");
342  break;
343  }
344 
345  return ((polarRadius + altitude) >= 0);
346 }
347 
348 std::ostream&
349 operator<<(std::ostream& os, const GeoCoordinate& coordinate)
350 {
351  double longitude = coordinate.GetLongitude();
352  double latitude = coordinate.GetLatitude();
353  double altitude = coordinate.GetAltitude();
354 
355  os << latitude << "," << longitude << "," << altitude;
356 
357  return os;
358 }
359 
360 std::istream&
361 operator>>(std::istream& is, GeoCoordinate& coordinate)
362 {
363  double longitude;
364  double latitude;
365  double altitude;
366  char c1;
367  char c2;
368 
369  is >> latitude >> c1 >> longitude >> c2 >> altitude;
370 
371  coordinate.SetLongitude(longitude);
372  coordinate.SetLatitude(latitude);
373  coordinate.SetAltitude(altitude);
374 
375  if (c1 != ',' || c2 != ',')
376  {
377  is.setstate(std::ios_base::failbit);
378  }
379  return is;
380 }
381 
382 } // 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)