1jQuery(function($) { 2 3 /** 4 * A collection of very fast approximations to common geodesic measurements. Useful for performance-sensitive code that measures things on a city scale. 5 * 6 * @param {number} lat latitude 7 * @param {string} [units='kilometers'] 8 * @returns {CheapRuler} 9 * @example 10 * var ruler = cheapRuler(35.05, 'miles'); 11 * //=ruler 12 */ 13 function cheapRuler(lat /*: number */, units /*: ?string */) { 14 return new CheapRuler(lat, units); 15 } 16 17 /** 18 * Multipliers for converting between units. 19 * 20 * @example 21 * // convert 50 meters to yards 22 * 50 * cheapRuler.units.yards / cheapRuler.units.meters; 23 */ 24 var factors = cheapRuler.units = { 25 kilometers: 1, 26 miles: 1000 / 1609.344, 27 nauticalmiles: 1000 / 1852, 28 meters: 1000, 29 metres: 1000, 30 yards: 1000 / 0.9144, 31 feet: 1000 / 0.3048, 32 inches: 1000 / 0.0254 33 }; 34 35 /** 36 * Creates a ruler object from tile coordinates (y and z). Convenient in tile-reduce scripts. 37 * 38 * @param {number} y 39 * @param {number} z 40 * @param {string} [units='kilometers'] 41 * @returns {CheapRuler} 42 * @example 43 * var ruler = cheapRuler.fromTile(1567, 12); 44 * //=ruler 45 */ 46 cheapRuler.fromTile = function (y, z, units) { 47 var n = Math.PI * (1 - 2 * (y + 0.5) / Math.pow(2, z)); 48 var lat = Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))) * 180 / Math.PI; 49 return new CheapRuler(lat, units); 50 }; 51 52 function CheapRuler(lat, units) { 53 if (lat === undefined) throw new Error('No latitude given.'); 54 if (units && !factors[units]) throw new Error('Unknown unit ' + units + '. Use one of: ' + Object.keys(factors).join(', ')); 55 56 var m = units ? factors[units] : 1; 57 58 var cos = Math.cos(lat * Math.PI / 180); 59 var cos2 = 2 * cos * cos - 1; 60 var cos3 = 2 * cos * cos2 - cos; 61 var cos4 = 2 * cos * cos3 - cos2; 62 var cos5 = 2 * cos * cos4 - cos3; 63 64 // multipliers for converting longitude and latitude degrees into distance (http://1.usa.gov/1Wb1bv7) 65 this.kx = m * (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5); 66 this.ky = m * (111.13209 - 0.56605 * cos2 + 0.0012 * cos4); 67 } 68 69 window.CheapRuler = CheapRuler; 70 window.cheapRuler = cheapRuler; 71 72 CheapRuler.prototype = { 73 /** 74 * Given two points of the form [longitude, latitude], returns the distance. 75 * 76 * @param {Array<number>} a point [longitude, latitude] 77 * @param {Array<number>} b point [longitude, latitude] 78 * @returns {number} distance 79 * @example 80 * var distance = ruler.distance([30.5, 50.5], [30.51, 50.49]); 81 * //=distance 82 */ 83 distance: function (a, b) { 84 var dx = (a[0] - b[0]) * this.kx; 85 var dy = (a[1] - b[1]) * this.ky; 86 return Math.sqrt(dx * dx + dy * dy); 87 }, 88 89 /** 90 * Returns the bearing between two points in angles. 91 * 92 * @param {Array<number>} a point [longitude, latitude] 93 * @param {Array<number>} b point [longitude, latitude] 94 * @returns {number} bearing 95 * @example 96 * var bearing = ruler.bearing([30.5, 50.5], [30.51, 50.49]); 97 * //=bearing 98 */ 99 bearing: function (a, b) { 100 var dx = (b[0] - a[0]) * this.kx; 101 var dy = (b[1] - a[1]) * this.ky; 102 if (!dx && !dy) return 0; 103 var bearing = Math.atan2(dx, dy) * 180 / Math.PI; 104 if (bearing > 180) bearing -= 360; 105 return bearing; 106 }, 107 108 /** 109 * Returns a new point given distance and bearing from the starting point. 110 * 111 * @param {Array<number>} p point [longitude, latitude] 112 * @param {number} dist distance 113 * @param {number} bearing 114 * @returns {Array<number>} point [longitude, latitude] 115 * @example 116 * var point = ruler.destination([30.5, 50.5], 0.1, 90); 117 * //=point 118 */ 119 destination: function (p, dist, bearing) { 120 var a = bearing * Math.PI / 180; 121 return this.offset(p, 122 Math.sin(a) * dist, 123 Math.cos(a) * dist); 124 }, 125 126 /** 127 * Returns a new point given easting and northing offsets (in ruler units) from the starting point. 128 * 129 * @param {Array<number>} p point [longitude, latitude] 130 * @param {number} dx easting 131 * @param {number} dy northing 132 * @returns {Array<number>} point [longitude, latitude] 133 * @example 134 * var point = ruler.offset([30.5, 50.5], 10, 10); 135 * //=point 136 */ 137 offset: function (p, dx, dy) { 138 return [ 139 p[0] + dx / this.kx, 140 p[1] + dy / this.ky 141 ]; 142 }, 143 144 /** 145 * Given a line (an array of points), returns the total line distance. 146 * 147 * @param {Array<Array<number>>} points [longitude, latitude] 148 * @returns {number} total line distance 149 * @example 150 * var length = ruler.lineDistance([ 151 * [-67.031, 50.458], [-67.031, 50.534], 152 * [-66.929, 50.534], [-66.929, 50.458] 153 * ]); 154 * //=length 155 */ 156 lineDistance: function (points) { 157 var total = 0; 158 for (var i = 0; i < points.length - 1; i++) { 159 total += this.distance(points[i], points[i + 1]); 160 } 161 return total; 162 }, 163 164 /** 165 * Given a polygon (an array of rings, where each ring is an array of points), returns the area. 166 * 167 * @param {Array<Array<Array<number>>>} polygon 168 * @returns {number} area value in the specified units (square kilometers by default) 169 * @example 170 * var area = ruler.area([[ 171 * [-67.031, 50.458], [-67.031, 50.534], [-66.929, 50.534], 172 * [-66.929, 50.458], [-67.031, 50.458] 173 * ]]); 174 * //=area 175 */ 176 area: function (polygon) { 177 var sum = 0; 178 179 for (var i = 0; i < polygon.length; i++) { 180 var ring = polygon[i]; 181 182 for (var j = 0, len = ring.length, k = len - 1; j < len; k = j++) { 183 sum += (ring[j][0] - ring[k][0]) * (ring[j][1] + ring[k][1]) * (i ? -1 : 1); 184 } 185 } 186 187 return (Math.abs(sum) / 2) * this.kx * this.ky; 188 }, 189 190 /** 191 * Returns the point at a specified distance along the line. 192 * 193 * @param {Array<Array<number>>} line 194 * @param {number} dist distance 195 * @returns {Array<number>} point [longitude, latitude] 196 * @example 197 * var point = ruler.along(line, 2.5); 198 * //=point 199 */ 200 along: function (line, dist) { 201 var sum = 0; 202 203 if (dist <= 0) return line[0]; 204 205 for (var i = 0; i < line.length - 1; i++) { 206 var p0 = line[i]; 207 var p1 = line[i + 1];
208 var d = this.distance(p0, p1); 209 sum += d; 210 if (sum > dist) return interpolate(p0, p1, (dist - (sum - d)) / d); 211 } 212 213 return line[line.length - 1]; 214 }, 215 216 /** 217 * Returns an object of the form {point, index, t}, where point is closest point on the line 218 * from the given point, index is the start index of the segment with the closest point, 219 * and t is a parameter from 0 to 1 that indicates where the closest point is on that segment. 220 * 221 * @pointOnLine 222 * @param {Array<Array<number>>} line 223 * @param {Array<number>} p point [longitude, latitude] 224 * @returns {Object} {point, index, t} 225 * @example 226 * var point = ruler.pointOnLine(line, [-67.04, 50.5]).point; 227 * //=point 228 */ 229 pointOnLine: function (line, p) { 230 var minDist = Infinity; 231 var minX, minY, minI, minT; 232 233 for (var i = 0; i < line.length - 1; i++) { 234 235 var x = line[i][0]; 236 var y = line[i][1]; 237 var dx = (line[i + 1][0] - x) * this.kx; 238 var dy = (line[i + 1][1] - y) * this.ky; 239 240 if (dx !== 0 || dy !== 0) { 241 242 var t = ((p[0] - x) * this.kx * dx + (p[1] - y) * this.ky * dy) / (dx * dx + dy * dy); 243 244 if (t > 1) { 245 x = line[i + 1][0]; 246 y = line[i + 1][1]; 247 248 } else if (t > 0) { 249 x += (dx / this.kx) * t; 250 y += (dy / this.ky) * t; 251 } 252 } 253 254 dx = (p[0] - x) * this.kx; 255 dy = (p[1] - y) * this.ky; 256 257 var sqDist = dx * dx + dy * dy; 258 if (sqDist < minDist) { 259 minDist = sqDist; 260 minX = x; 261 minY = y; 262 minI = i; 263 minT = t; 264 } 265 } 266 267 return { 268 point: [minX, minY], 269 index: minI, 270 t: Math.max(0, Math.min(1, minT)) 271 }; 272 }, 273 274 /** 275 * Returns a part of the given line between the start and the stop points (or their closest points on the line). 276 * 277 * @param {Array<number>} start point [longitude, latitude] 278 * @param {Array<number>} stop point [longitude, latitude] 279 * @param {Array<Array<number>>} line 280 * @returns {Array<Array<number>>} line part of a line 281 * @example 282 * var line2 = ruler.lineSlice([-67.04, 50.5], [-67.05, 50.56], line1); 283 * //=line2 284 */ 285 lineSlice: function (start, stop, line) { 286 var p1 = this.pointOnLine(line, start); 287 var p2 = this.pointOnLine(line, stop); 288 289 if (p1.index > p2.index || (p1.index === p2.index && p1.t > p2.t)) { 290 var tmp = p1; 291 p1 = p2; 292 p2 = tmp; 293 } 294 295 var slice = [p1.point]; 296 297 var l = p1.index + 1; 298 var r = p2.index; 299 300 if (!equals(line[l], slice[0]) && l <= r) 301 slice.push(line[l]); 302 303 for (var i = l + 1; i <= r; i++) { 304 slice.push(line[i]); 305 } 306 307 if (!equals(line[r], p2.point)) 308 slice.push(p2.point); 309 310 return slice; 311 }, 312 313 /** 314 * Returns a part of the given line between the start and the stop points indicated by distance along the line. 315 * 316 * @param {number} start distance 317 * @param {number} stop distance 318 * @param {Array<Array<number>>} line 319 * @returns {Array<Array<number>>} line part of a line 320 * @example 321 * var line2 = ruler.lineSliceAlong(10, 20, line1); 322 * //=line2 323 */ 324 lineSliceAlong: function (start, stop, line) { 325 var sum = 0; 326 var slice = []; 327 328 for (var i = 0; i < line.length - 1; i++) { 329 var p0 = line[i]; 330 var p1 = line[i + 1]; 331 var d = this.distance(p0, p1); 332 333 sum += d; 334 335 if (sum > start && slice.length === 0) { 336 slice.push(interpolate(p0, p1, (start - (sum - d)) / d)); 337 } 338 339 if (sum >= stop) { 340 slice.push(interpolate(p0, p1, (stop - (sum - d)) / d)); 341 return slice; 342 } 343 344 if (sum > start) slice.push(p1); 345 } 346 347 return slice; 348 }, 349 350 /** 351 * Given a point, returns a bounding box object ([w, s, e, n]) created from the given point buffered by a given distance. 352 * 353 * @param {Array<number>} p point [longitude, latitude] 354 * @param {number} buffer 355 * @returns {Array<number>} box object ([w, s, e, n]) 356 * @example 357 * var bbox = ruler.bufferPoint([30.5, 50.5], 0.01); 358 * //=bbox 359 */ 360 bufferPoint: function (p, buffer) { 361 var v = buffer / this.ky; 362 var h = buffer / this.kx; 363 return [ 364 p[0] - h, 365 p[1] - v, 366 p[0] + h, 367 p[1] + v 368 ]; 369 }, 370 371 /**
372 * Given a bounding box, returns the box buffered by a given distance. 373 * 374 * @param {Array<number>} box object ([w, s, e, n]) 375 * @param {number} buffer 376 * @returns {Array<number>} box object ([w, s, e, n]) 377 * @example 378 * var bbox = ruler.bufferBBox([30.5, 50.5, 31, 51], 0.2); 379 * //=bbox 380 */ 381 bufferBBox: function (bbox, buffer) { 382 var v = buffer / this.ky; 383 var h = buffer / this.kx; 384 return [ 385 bbox[0] - h, 386 bbox[1] - v, 387 bbox[2] + h, 388 bbox[3] + v 389 ]; 390 }, 391 392 /** 393 * Returns true if the given point is inside in the given bounding box, otherwise false. 394 * 395 * @param {Array<number>} p point [longitude, latitude] 396 * @param {Array<number>} box object ([w, s, e, n]) 397 * @returns {boolean} 398 * @example 399 * var inside = ruler.insideBBox([30.5, 50.5], [30, 50, 31, 51]); 400 * //=inside 401 */ 402 insideBBox: function (p, bbox) { 403 return p[0] >= bbox[0] && 404 p[0] <= bbox[2] && 405 p[1] >= bbox[1] && 406 p[1] <= bbox[3]; 407 } 408 }; 409 410 function equals(a, b) { 411 return a[0] === b[0] && a[1] === b[1]; 412 } 413 414 function interpolate(a, b, t) { 415 var dx = b[0] - a[0]; 416 var dy = b[1] - a[1]; 417 return [ 418 a[0] + dx * t, 419 a[1] + dy * t 420 ]; 421 } 422 423});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.