A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
geographic-positions.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 University of Washington
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Benjamin Cizdziel <ben.cizdziel@gmail.com>
18 */
19
21
22#include <ns3/log.h>
23
24#include <cmath>
25
26NS_LOG_COMPONENT_DEFINE("GeographicPositions");
27
28namespace ns3
29{
30
31/// Earth's radius in meters if modeled as a perfect sphere
32static constexpr double EARTH_RADIUS = 6371e3;
33
34/**
35 * GRS80 and WGS84 sources
36 *
37 * Moritz, H. "Geodetic Reference System 1980." GEODETIC REFERENCE SYSTEM 1980.
38 * <https://web.archive.org/web/20170712034716/http://www.gfy.ku.dk/~iag/HB2000/part4/grs80_corr.htm>.
39 *
40 * "Department of Defense World Geodetic System 1984." National Imagery and
41 * Mapping Agency, 1 Jan. 2000.
42 * <https://web.archive.org/web/20200730231853/http://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf>.
43 */
44
45/// Earth's semi-major axis in meters as defined by both GRS80 and WGS84
46static constexpr double EARTH_SEMIMAJOR_AXIS = 6378137;
47
48/// Earth's first eccentricity as defined by GRS80
49static constexpr double EARTH_GRS80_ECCENTRICITY = 0.0818191910428158;
50
51/// Earth's first eccentricity as defined by WGS84
52static constexpr double EARTH_WGS84_ECCENTRICITY = 0.0818191908426215;
53
54/// Conversion factor: degrees to radians
55static constexpr double DEG2RAD = M_PI / 180.0;
56
57/// Conversion factor: radians to degrees
58static constexpr double RAD2DEG = 180.0 * M_1_PI;
59
60Vector
62 double longitude,
63 double altitude,
64 EarthSpheroidType sphType)
65{
67 double latitudeRadians = DEG2RAD * latitude;
68 double longitudeRadians = DEG2RAD * longitude;
69 double a; // semi-major axis of earth
70 double e; // first eccentricity of earth
71 if (sphType == SPHERE)
72 {
73 a = EARTH_RADIUS;
74 e = 0;
75 }
76 else if (sphType == GRS80)
77 {
80 }
81 else // if sphType == WGS84
82 {
85 }
86
87 double Rn = a / (sqrt(1 - pow(e, 2) * pow(sin(latitudeRadians), 2))); // radius of
88 // curvature
89 double x = (Rn + altitude) * cos(latitudeRadians) * cos(longitudeRadians);
90 double y = (Rn + altitude) * cos(latitudeRadians) * sin(longitudeRadians);
91 double z = ((1 - pow(e, 2)) * Rn + altitude) * sin(latitudeRadians);
92 Vector cartesianCoordinates = Vector(x, y, z);
93 return cartesianCoordinates;
94}
95
96Vector
98{
99 NS_LOG_FUNCTION(pos << sphType);
100
101 double a; // semi-major axis of earth
102 double e; // first eccentricity of earth
103 if (sphType == SPHERE)
104 {
105 a = EARTH_RADIUS;
106 e = 0;
107 }
108 else if (sphType == GRS80)
109 {
112 }
113 else // if sphType == WGS84
114 {
117 }
118
119 Vector lla;
120 Vector tmp;
121 lla.y = atan2(pos.y, pos.x); // longitude (rad), in +/- pi
122
123 double e2 = e * e;
124 // sqrt (pos.x^2 + pos.y^2)
125 double p = CalculateDistance(pos, {0, 0, pos.z});
126 lla.x = atan2(pos.z, p * (1 - e2)); // init latitude (rad), in +/- pi
127
128 do
129 {
130 tmp = lla;
131 double N = a / sqrt(1 - e2 * sin(tmp.x) * sin(tmp.x));
132 double v = p / cos(tmp.x);
133 lla.z = v - N; // altitude
134 lla.x = atan2(pos.z, p * (1 - e2 * N / v));
135 }
136 // 1 m difference is approx 1 / 30 arc seconds = 9.26e-6 deg
137 while (fabs(lla.x - tmp.x) > 0.00000926 * DEG2RAD);
138
139 lla.x *= RAD2DEG;
140 lla.y *= RAD2DEG;
141
142 // canonicalize (latitude) x in [-90, 90] and (longitude) y in [-180, 180)
143 if (lla.x > 90.0)
144 {
145 lla.x = 180 - lla.x;
146 lla.y += lla.y < 0 ? 180 : -180;
147 }
148 else if (lla.x < -90.0)
149 {
150 lla.x = -180 - lla.x;
151 lla.y += lla.y < 0 ? 180 : -180;
152 }
153 if (lla.y == 180.0)
154 {
155 lla.y = -180;
156 }
157
158 // make sure lat/lon in the right range to double check canonicalization
159 // and conversion routine
160 NS_ASSERT_MSG(-180.0 <= lla.y, "Conversion error: longitude too negative");
161 NS_ASSERT_MSG(180.0 > lla.y, "Conversion error: longitude too positive");
162 NS_ASSERT_MSG(-90.0 <= lla.x, "Conversion error: latitude too negative");
163 NS_ASSERT_MSG(90.0 >= lla.x, "Conversion error: latitude too positive");
164
165 return lla;
166}
167
168std::list<Vector>
170 double originLongitude,
171 double maxAltitude,
172 int numPoints,
173 double maxDistFromOrigin,
175{
177 // fixes divide by zero case and limits latitude bounds
178 if (originLatitude >= 90)
179 {
180 NS_LOG_WARN("origin latitude must be less than 90. setting to 89.999");
181 originLatitude = 89.999;
182 }
183 else if (originLatitude <= -90)
184 {
185 NS_LOG_WARN("origin latitude must be greater than -90. setting to -89.999");
186 originLatitude = -89.999;
187 }
188
189 // restricts maximum altitude from being less than zero (below earth's surface).
190 // sets maximum altitude equal to zero if parameter is set to be less than zero.
191 if (maxAltitude < 0)
192 {
193 NS_LOG_WARN("maximum altitude must be greater than or equal to 0. setting to 0");
194 maxAltitude = 0;
195 }
196
197 double originLatitudeRadians = originLatitude * DEG2RAD;
198 double originLongitudeRadians = originLongitude * DEG2RAD;
199 double originColatitude = (M_PI_2)-originLatitudeRadians;
200
201 double a = maxDistFromOrigin / EARTH_RADIUS; // maximum alpha allowed
202 // (arc length formula)
203 if (a > M_PI)
204 {
205 a = M_PI; // pi is largest alpha possible (polar angle from origin that
206 // points can be generated within)
207 }
208
209 std::list<Vector> generatedPoints;
210 for (int i = 0; i < numPoints; i++)
211 {
212 // random distance from North Pole (towards center of earth)
213 double d = uniRand->GetValue(0, EARTH_RADIUS - EARTH_RADIUS * cos(a));
214 // random angle in latitude slice (wrt Prime Meridian), radians
215 double phi = uniRand->GetValue(0, M_PI * 2);
216 // random angle from Center of Earth (wrt North Pole), radians
217 double alpha = acos((EARTH_RADIUS - d) / EARTH_RADIUS);
218
219 // shift coordinate system from North Pole referred to origin point referred
220 // reference: http://en.wikibooks.org/wiki/General_Astronomy/Coordinate_Systems
221 double theta = M_PI_2 - alpha; // angle of elevation of new point wrt
222 // origin point (latitude in coordinate
223 // system referred to origin point)
224 double randPointLatitude = asin(sin(theta) * cos(originColatitude) +
225 cos(theta) * sin(originColatitude) * sin(phi));
226 // declination
227 double intermedLong = asin((sin(randPointLatitude) * cos(originColatitude) - sin(theta)) /
228 (cos(randPointLatitude) * sin(originColatitude)));
229 // right ascension
230 intermedLong = intermedLong + M_PI_2; // shift to longitude 0
231
232 // flip / mirror point if it has phi in quadrant II or III (wasn't
233 // resolved correctly by arcsin) across longitude 0
234 if (phi > (M_PI_2) && phi <= (3 * M_PI_2))
235 {
236 intermedLong = -intermedLong;
237 }
238
239 // shift longitude to be referenced to origin
240 double randPointLongitude = intermedLong + originLongitudeRadians;
241
242 // random altitude above earth's surface
243 double randAltitude = uniRand->GetValue(0, maxAltitude);
244
245 Vector pointPosition =
247 randPointLongitude * RAD2DEG,
248 randAltitude,
249 SPHERE);
250 // convert coordinates
251 // from geographic to cartesian
252
253 generatedPoints.push_back(pointPosition); // add generated coordinate
254 // points to list
255 }
256 return generatedPoints;
257}
258
259} // namespace ns3
static std::list< Vector > RandCartesianPointsAroundGeographicPoint(double originLatitude, double originLongitude, double maxAltitude, int numPoints, double maxDistFromOrigin, Ptr< UniformRandomVariable > uniRand)
Generates uniformly distributed random points (in ECEF Cartesian coordinates) within a given altitude...
EarthSpheroidType
Spheroid model to use for earth: perfect sphere (SPHERE), Geodetic Reference System 1980 (GRS80),...
static Vector GeographicToCartesianCoordinates(double latitude, double longitude, double altitude, EarthSpheroidType sphType)
Converts earth geographic/geodetic coordinates (latitude and longitude in degrees) with a given altit...
static Vector CartesianToGeographicCoordinates(Vector pos, EarthSpheroidType sphType)
Inverse of GeographicToCartesianCoordinates using [1].
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:261
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static constexpr double DEG2RAD
Conversion factor: degrees to radians.
static constexpr double EARTH_GRS80_ECCENTRICITY
Earth's first eccentricity as defined by GRS80.
static constexpr double EARTH_RADIUS
Earth's radius in meters if modeled as a perfect sphere.
static constexpr double EARTH_SEMIMAJOR_AXIS
GRS80 and WGS84 sources.
static constexpr double RAD2DEG
Conversion factor: radians to degrees.
double CalculateDistance(const Vector3D &a, const Vector3D &b)
Definition: vector.cc:109
static constexpr double EARTH_WGS84_ECCENTRICITY
Earth's first eccentricity as defined by WGS84.