-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathgeopoint.js
220 lines (207 loc) · 6.4 KB
/
geopoint.js
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
* Represents a point on the surface of the Earth.
*
* This library is derived from the Java code originally published at
* http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates
*
* @author Jan Philip Matuschek
* @version 22 September 2010
*/
(function () {
var toString = Object.prototype.toString,
DEG2RAD = Math.PI / 180, // degrees to radian conversion
RAD2DEG = 180 / Math.PI, // radians to degrees conversion
MI2KM = 1.6093439999999999, // miles to kilometers conversion
KM2MI = 0.621371192237334, // kilometers to miles conversion
EARTH_RADIUS_KM = 6371.01, // Earth's radius in km
EARTH_RADIUS_MI = 3958.762079, // Earth's radius in miles
MAX_LAT = Math.PI / 2, // 90 degrees
MIN_LAT = -MAX_LAT, // -90 degrees
MAX_LON = Math.PI, // 180 degrees
MIN_LON = -MAX_LON, // -180 degrees
FULL_CIRCLE_RAD = Math.PI * 2; // Full cirle (360 degrees) in radians
/**
* Check if an object is a valid number
*
* @param {Number} value Value to check
* @return {Boolean} true if a number and not NaN
*/
function isNumber(value) {
return toString.call(value) === '[object Number]' && value === +value;
}
/**
* Constructor
*
* @param {Number} lat Latitude
* @param {Number} long Longitude
* @param {Boolean} inRadians true if latitude and longitude are in radians
*/
function GeoPoint(lat, lon, inRadians) {
if (!isNumber(lat)) {
throw new Error('Invalid latitude');
}
if (!isNumber(lon)) {
throw new Error('Invalid longitude');
}
if (inRadians === true) {
this._degLat = GeoPoint.radiansToDegrees(lat);
this._degLon = GeoPoint.radiansToDegrees(lon);
this._radLat = lat;
this._radLon = lon;
} else {
this._degLat = lat;
this._degLon = lon;
this._radLat = GeoPoint.degreesToRadians(lat);
this._radLon = GeoPoint.degreesToRadians(lon);
}
if (this._radLat < MIN_LAT || this._radLat > MAX_LAT) {
throw new Error('Latitude out of bounds');
} else if (this._radLon < MIN_LON || this._radLon > MAX_LON) {
throw new Error('Longitude out of bounds');
}
}
/**
* Return the latitude
*
* @param {Boolean} inRadians true to return the latitude in radians
* @param {Number} latitude
*/
GeoPoint.prototype.latitude = function(inRadians) {
if (inRadians === true) {
return this._radLat;
}
return this._degLat;
};
/**
* Return the longitude
*
* @param {Boolean} inRadians true to return the longitude in radians
* @param {Number} longitude
*/
GeoPoint.prototype.longitude = function(inRadians) {
if (inRadians === true) {
return this._radLon;
}
return this._degLon;
};
/**
* Calculates the distance between two points
*
* @param {Object} point GeoPoint instance
* @param {Boolean} inKilometers true to return the distance in kilometers
* @return {Number} distance between points
*/
GeoPoint.prototype.distanceTo = function(point, inKilometers) {
if (!(point instanceof GeoPoint)) {
throw new Error('Invalid GeoPoint');
}
var radius = inKilometers === true ? EARTH_RADIUS_KM : EARTH_RADIUS_MI,
lat1 = this.latitude(true),
lat2 = point.latitude(true),
lon1 = this.longitude(true),
lon2 = point.longitude(true);
return Math.acos(
Math.sin(lat1) * Math.sin(lat2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.cos(lon1 - lon2)) * radius;
};
/**
* Calculate the bouding coordinates
*
* @param {Number} distance distance from the point
* @param {Number} radius optional sphere radius to use
* @param {Boolean} inKilometers true to return the distance in kilometers
* @return {Array} array containing SW and NE points of bounding box
*/
GeoPoint.prototype.boundingCoordinates = function(distance, radius, inKilometers) {
if (!isNumber(distance) || distance <= 0) {
throw new Error('Invalid distance');
}
if (radius === true || radius === false) {
inKilometers = radius;
radius = null;
}
if (!isNumber(radius) || radius <= 0) {
radius = inKilometers === true ? EARTH_RADIUS_KM : EARTH_RADIUS_MI;
}
var lat = this.latitude(true),
lon = this.longitude(true),
radDist = distance / radius,
minLat = lat - radDist,
maxLat = lat + radDist,
minLon,
maxLon,
deltaLon;
if (minLat > MIN_LAT && maxLat < MAX_LAT) {
deltaLon = Math.asin(Math.sin(radDist) / Math.cos(lat));
minLon = lon - deltaLon;
if (minLon < MIN_LON) {
minLon += FULL_CIRCLE_RAD;
}
maxLon = lon + deltaLon;
if (maxLon > MAX_LON) {
maxLon -= FULL_CIRCLE_RAD;
}
} else {
minLat = Math.max(minLat, MIN_LAT);
maxLat = Math.min(maxLat, MAX_LAT);
minLon = MIN_LON;
maxLon = MAX_LON;
}
return [new GeoPoint(minLat, minLon, true), new GeoPoint(maxLat, maxLon, true)];
};
/**
* Convert degrees to radians
*
* @param {Number} value degree value
* @return {Number} radian value
*/
GeoPoint.degreesToRadians = function(value) {
if (!isNumber(value)) {
throw new Error('Invalid degree value');
}
return value * DEG2RAD;
};
/**
* Convert radians to degrees
*
* @param {Number} value radian value
* @return {Number} degree value
*/
GeoPoint.radiansToDegrees = function(value) {
if (!isNumber(value)) {
throw new Error('Invalid radian value');
}
return value * RAD2DEG;
};
/**
* Cnvert miles to kilometers
*
* @param {Number} value miles value
* @return {Number} kilometers value
*/
GeoPoint.milesToKilometers = function(value) {
if (!isNumber(value)) {
throw new Error('Invalid mile value');
}
return value * MI2KM;
};
/**
* Convert kilometers to miles
*
* @param {Number} value kilometer value
* @return {Number} miles value
*/
GeoPoint.kilometersToMiles = function(value) {
if (!isNumber(value)) {
throw new Error('Invalid kilometer value');
}
return value * KM2MI;
};
// Export
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = GeoPoint;
} else {
this.GeoPoint = GeoPoint;
}
}).call(this);