forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 2
/
nsGeoGridFuzzer.cpp
135 lines (111 loc) · 5.13 KB
/
nsGeoGridFuzzer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <math.h>
#include "nsGeoGridFuzzer.h"
#include "nsGeoPosition.h"
#ifdef MOZ_APPROX_LOCATION
/* The following constants are taken from the World Geodetic System 1984 (WGS84)
* reference model for the earth ellipsoid [1]. The values in the model are
* an accepted standard for GPS and other navigational systems.
*
* [1] http://www.oosa.unvienna.org/pdf/icg/2012/template/WGS_84.pdf
*/
#define WGS84_a (6378137.0) // equitorial axis
#define WGS84_b (6356752.314245179) // polar axis (a * (1-f))
#define WGS84_f (1.0/298.257223563) // inverse flattening
#define WGS84_EPSILON (5.72957795e-9) // 1e-10 radians in degrees
#define sq(f) ((f) * (f))
#define sign(f) (((f) < 0) ? -1 : 1)
/* if you have an ellipsoid with semi-major axis A and semi-minor axis B, the
* radius at angle phi along the semi-major axis can be calculated with this
* formula. by using the WGS84 values for A and B, we calculate the radius of
* earth, given the angle of latitude, phi.*/
#define LON_RADIUS(phi) (sqrt((sq(sq(WGS84_a) * cos(phi)) + sq(sq(WGS84_b) * sin(phi))) / \
(sq(WGS84_a * cos(phi)) + sq(WGS84_b * sin(phi)))))
/* the radius of earth changes as a function of latitude, to simplify I am
* assuming the fixed radius of the earth halfway between the poles and the
* equator. this is calculated from LON_RADIUS(M_PI/4), or the radius at
* 45 degrees N.*/
#define LAT_RADIUS (6367489.543863)
/* This function figures out the latitudinal grid square that the given
* latitude coordinate falls into and then returns the latitudinal center of
* that grid square. It handles the proper wrapping at the poles +/- 90
* (e.g. +95 wraps to +85 and -95 wraps to -85) */
static double GridAlgorithmLat(int32_t aDistMeters, double aLatDeg)
{
/* switch to radians */
double phi = (aLatDeg * M_PI) / 180;
/* properly wrap the latitude */
phi = atan(sin(phi) / fabs(cos(phi)));
/* calculate grid size in radians */
double gridSizeRad = aDistMeters / LAT_RADIUS;
/* find the southern edge, in radians, of the grid cell, then add half of a
* grid cell to find the center latitude in radians */
double gridCenterPhi = gridSizeRad * floor(phi / gridSizeRad) + gridSizeRad / 2;
/* properly wrap it and return it in degrees */
return atan(sin(gridCenterPhi) / fabs(cos(gridCenterPhi))) * (180.0 / M_PI);
}
/* This function figures out the longitudinal grid square that the given longitude
* coordinate falls into and then returns the longitudinal center of that grid
* square. It handles the proper wrapping at +/- 180 (e.g. +185 wraps to -175
* and -185 wraps to +175) */
static double GridAlgorithmLon(int32_t aDistMeters, double aLatDeg, double aLonDeg)
{
/* switch to radians */
double phi = (aLatDeg * M_PI) / 180;
double theta = (aLonDeg * M_PI) / 180;
/* properly wrap the lat/lon */
phi = atan(sin(phi) / fabs(cos(phi)));
theta = atan2(sin(theta), cos(theta));
/* calculate grid size in radians */
double gridSizeRad = aDistMeters / LON_RADIUS(phi);
/* find the western edge, in radians, of the grid cell, then add half of a
* grid cell to find the center longitude in radians */
double gridCenterTheta = gridSizeRad * floor(theta / gridSizeRad) + gridSizeRad / 2;
/* properly wrap it and return it in degrees */
return atan2(sin(gridCenterTheta), cos(gridCenterTheta)) * (180.0 / M_PI);
}
/* This function takes the grid size and the graticule coordinates of a
* location and calculates which grid cell the coordinates fall within and
* then returns the coordinates of the geographical center of the grid square.
*/
static void CalculateGridCoords(int32_t aDistKm, double& aLatDeg, double& aLonDeg)
{
// a grid size of 0 is the same as precise
if (aDistKm == 0) {
return;
}
aLonDeg = GridAlgorithmLon(aDistKm * 1000, aLatDeg, aLonDeg);
aLatDeg = GridAlgorithmLat(aDistKm * 1000, aLatDeg);
}
already_AddRefed<nsIDOMGeoPosition>
nsGeoGridFuzzer::FuzzLocation(const GeolocationSetting & aSetting,
nsIDOMGeoPosition * aPosition)
{
if (!aPosition) {
return nullptr;
}
nsCOMPtr<nsIDOMGeoPositionCoords> coords;
nsresult rv = aPosition->GetCoords(getter_AddRefs(coords));
NS_ENSURE_SUCCESS(rv, nullptr);
if (!coords) {
return nullptr;
}
double lat = 0.0, lon = 0.0;
coords->GetLatitude(&lat);
coords->GetLongitude(&lon);
// adjust lat/lon to be the center of the grid square
CalculateGridCoords(aSetting.GetApproxDistance(), lat, lon);
GPSLOG("approximate location with delta %d is %f, %f",
aSetting.GetApproxDistance(), lat, lon);
// reusing the timestamp
DOMTimeStamp ts;
rv = aPosition->GetTimestamp(&ts);
NS_ENSURE_SUCCESS(rv, nullptr);
// return a position at sea level, N heading, 0 speed, 0 error.
nsRefPtr<nsGeoPosition> pos = new nsGeoPosition(lat, lon, 0.0, 0.0,
0.0, 0.0, 0.0, ts);
return pos.forget();
}
#endif