1'use strict'; 2 3/** 4 * Based off of [the offical Google document](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) 5 * 6 * Some parts from [this implementation](http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoder.js) 7 * by [Mark McClure](http://facstaff.unca.edu/mcmcclur/) 8 * 9 * @module polyline 10 */ 11 12var polyline = {}; 13 14function py2_round(value) { 15 // Google's polyline algorithm uses the same rounding strategy as Python 2, which is different from JS for negative values 16 return Math.floor(Math.abs(value) + 0.5) * (value >= 0 ? 1 : -1); 17} 18 19function encode(current, previous, factor) { 20 current = py2_round(current * factor); 21 previous = py2_round(previous * factor); 22 var coordinate = current - previous; 23 coordinate <<= 1; 24 if (current - previous < 0) { 25 coordinate = ~coordinate; 26 } 27 var output = ''; 28 while (coordinate >= 0x20) { 29 output += String.fromCharCode((0x20 | (coordinate & 0x1f)) + 63); 30 coordinate >>= 5; 31 } 32 output += String.fromCharCode(coordinate + 63); 33 return output; 34} 35 36/** 37 * Decodes to a [latitude, longitude] coordinates array. 38 * 39 * This is adapted from the implementation in Project-OSRM. 40 * 41 * @param {String} str 42 * @param {Number} precision 43 * @returns {Array} 44 * 45 * @see https://github.com/Project-OSRM/osrm-frontend/blob/master/WebContent/routing/OSRM.RoutingGeometry.js 46 */ 47polyline.decode = function(str, precision) { 48 var index = 0, 49 lat = 0, 50 lng = 0, 51 coordinates = [], 52 shift = 0, 53 result = 0, 54 byte = null, 55 latitude_change, 56 longitude_change, 57 factor = Math.pow(10, Number.isInteger(precision) ? precision : 5); 58 59 // Coordinates have variable length when encoded, so just keep 60 // track of whether we've hit the end of the string. In each 61 // loop iteration, a single coordinate is decoded. 62 while (index < str.length) { 63 64 // Reset shift, result, and byte 65 byte = null; 66 shift = 0; 67 result = 0; 68 69 do { 70 byte = str.charCodeAt(index++) - 63; 71 result |= (byte & 0x1f) << shift; 72 shift += 5; 73 } while (byte >= 0x20); 74 75 latitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1)); 76 77 shift = result = 0; 78 79 do { 80 byte = str.charCodeAt(index++) - 63; 81 result |= (byte & 0x1f) << shift; 82 shift += 5; 83 } while (byte >= 0x20); 84 85 longitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1)); 86 87 lat += latitude_change; 88 lng += longitude_change; 89 90 coordinates.push([lat / factor, lng / factor]); 91 } 92 93 return coordinates; 94}; 95 96/** 97 * Encodes the given [latitude, longitude] coordinates array. 98 * 99 * @param {Array.<Array.<Number>>} coordinates 100 * @param {Number} precision 101 * @returns {String} 102 */ 103polyline.encode = function(coordinates, precision) { 104 if (!coordinates.length) { return ''; } 105 106 var factor = Math.pow(10, Number.isInteger(precision) ? precision : 5), 107 output = encode(coordinates[0][0], 0, factor) + encode(coordinates[0][1], 0, factor); 108 109 for (var i = 1; i < coordinates.length; i++) { 110 var a = coordinates[i], b = coordinates[i - 1]; 111 output += encode(a[0], b[0], factor); 112 output += encode(a[1], b[1], factor); 113 } 114 115 return output; 116}; 117 118function flipped(coords) { 119 var flipped = []; 120 for (var i = 0; i < coords.length; i++) { 121 flipped.push(coords[i].slice().reverse()); 122 } 123 return flipped; 124} 125 126/** 127 * Encodes a GeoJSON LineString feature/geometry. 128 * 129 * @param {Object} geojson 130 * @param {Number} precision 131 * @returns {String} 132 */ 133polyline.fromGeoJSON = function(geojson, precision) { 134 if (geojson && geojson.type === 'Feature') { 135 geojson = geojson.geometry; 136 } 137 if (!geojson || geojson.type !== 'LineString') { 138 throw new Error('Input must be a GeoJSON LineString'); 139 } 140 return polyline.encode(flipped(geojson.coordinates), precision); 141}; 142 143/** 144 * Decodes to a GeoJSON LineString geometry. 145 * 146 * @param {String} str 147 * @param {Number} precision 148 * @returns {Object} 149 */ 150polyline.toGeoJSON = function(str, precision) { 151 var coords = polyline.decode(str, precision); 152 return { 153 type: 'LineString', 154 coordinates: flipped(coords) 155 }; 156}; 157 158if (typeof module === 'object' && module.exports) { 159 module.exports = polyline; 160}
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.