diff --git a/examples/encoded-polyline.html b/examples/encoded-polyline.html new file mode 100644 index 0000000000..c40a243201 --- /dev/null +++ b/examples/encoded-polyline.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + +

Encoded Polyline Example

+ +
+ Encoded Polyline, Google +
+ +

+ Demonstrate the use of the Encoded Polyline format. +

+
+
+

This example uses the Encoded Polyline format.

+
+ + diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 4df00ddf62..b6d5b397ff 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -306,6 +306,7 @@ "OpenLayers/Format/GML/v2.js", "OpenLayers/Format/GML/v3.js", "OpenLayers/Format/Atom.js", + "OpenLayers/Format/EncodedPolyline.js", "OpenLayers/Format/KML.js", "OpenLayers/Format/GeoRSS.js", "OpenLayers/Format/WFS.js", diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js new file mode 100644 index 0000000000..1255eb1c91 --- /dev/null +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -0,0 +1,254 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.Format.EncodedPolyline + * Class for reading and writing encoded polylines. Create a new instance + * with the constructor. + * + * Inherits from: + * - + */ +OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { + + /** + * APIProperty: geometryType + * {String} Geometry type to output. One of: linestring (default), + * linearring, point, multipoint or polygon. If the geometryType is + * point, only the first point of the string is returned. + */ + geometryType: "linestring", + + /** + * Constructor: OpenLayers.Format.EncodedPolyline + * Create a new parser for encoded polylines + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance + * + * Returns: + * {} A new encoded polylines parser. + */ + initialize: function(options) { + OpenLayers.Format.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Deserialize an encoded polyline string and return a vector feature. + * + * Parameters: + * encoded - {String} An encoded polyline string + * + * Returns: + * {} A vector feature with a linestring. + */ + read: function(encoded) { + var geomType; + if (this.geometryType == "linestring") + geomType = OpenLayers.Geometry.LineString; + else if (this.geometryType == "linearring") + geomType = OpenLayers.Geometry.LinearRing; + else if (this.geometryType == "multipoint") + geomType = OpenLayers.Geometry.MultiPoint; + else if (this.geometryType != "point" && this.geometryType != "polygon") + return null; + + var points = this.decode(encoded, 2); + var pointGeometries = new Array(); + for (i in points) { + var point = points[i]; + pointGeometries.push( + new OpenLayers.Geometry.Point(point[1] * 1e-5, point[0] * 1e-5) + ); + } + + if (this.geometryType == "point") + return new OpenLayers.Feature.Vector( + pointGeometries[0] + ); + + if (this.geometryType == "polygon") + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Polygon([ + new OpenLayers.Geometry.LinearRing(pointGeometries) + ]) + ); + + return new OpenLayers.Feature.Vector( + new geomType(pointGeometries) + ); + }, + + /** + * APIMethod: decode + * Deserialize an encoded string and return an array of n-dimensional + * points. + * + * Parameters: + * encoded - {String} An encoded string + * dims - {int} The dimension of the points that are returned + * + * Returns: + * {Array(Array(int))} An array containing n-dimensional arrays of + * coordinates. + */ + decode: function(encoded, dims) { + var points = new Array(); + var point = new Array(dims); + + // Reset the point array + for (var i = 0; i < point.length; ++i) + point[i] = 0; + + for (var i = 0; i < encoded.length;) { + for (var dim = 0; dim < dims; ++dim) { + var result = 0; + var shift = 0; + + var b; + do { + b = encoded.charCodeAt(i++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + + point[dim] += ((result & 1) ? ~(result >> 1) : (result >> 1)); + } + + points.push(point.slice(0)); + } + + return points; + }, + + /** + * APIMethod: write + * Serialize a feature or array of features into a WKT string. + * + * Parameters: + * features - {|Array} A feature or array of + * features + * + * Returns: + * {String} The WKT string representation of the input geometries + */ + write: function(features) { + var feature; + if (features.constructor == Array) + feature = features[0]; + else + feature = features; + + var geometry = feature.geometry; + var type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); + + var pointGeometries; + if (type == "point") + pointGeometries = new Array(geometry); + else if (type == "linestring" || + type == "linearring" || + type == "multipoint") + pointGeometries = geometry.components; + else if (type == "polygon") + pointGeometries = geometry.components[0].components; + else + return null; + + var points = new Array(); + for (var i in pointGeometries) { + var pointGeometry = pointGeometries[i]; + var point = [Math.round(pointGeometry.y * 1e5), + Math.round(pointGeometry.x * 1e5)]; + points.push(point); + } + + var result = this.encode(points, 2); + return result; + }, + + /** + * APIMethod: encode + * Serialize an array of n-dimensional points and return an encoded string + * + * Parameters: + * points - {Array(Array(int))} An array containing n-dimensional + * arrays of coordinates + * dims - {int} The dimension of the points that should be read + * + * Returns: + * {String} An encoded string + */ + encode: function (points, dims) { + var encoded_points = ""; + + var lastPoint = new Array(dims); + for (var i = 0; i < lastPoint.length; ++i) + lastPoint[i] = 0; + + for (var i = 0; i < points.length; i++) { + var point = points[i]; + + for (var dim = 0; dim < lastPoint.length; ++dim) { + var delta = point[dim] - lastPoint[dim]; + encoded_points += this.encodeSignedNumber(delta); + } + + lastPoint = point; + } + return encoded_points; + }, + + /** + * Method: encodeSignedNumber + * Encode one single signed integer and return an encoded string + * + * Parameters: + * num - {int} A signed integer that should be encoded + * + * Returns: + * {String} An encoded string + */ + encodeSignedNumber: function (num) { + var sgn_num = num << 1; + if (num < 0) + sgn_num = ~(sgn_num); + + return this.encodeNumber(sgn_num); + }, + + /** + * Method: encodeNumber + * Encode one single unsigned integer and return an encoded string + * + * encodeSignedNumber should be used instead of using this method directly! + * + * Parameters: + * num - {int} An unsigned integer that should be encoded + * + * Returns: + * {String} An encoded string + */ + encodeNumber: function (num) { + var encodeString = ""; + var value; + while (num >= 0x20) { + value = (0x20 | (num & 0x1f)) + 63; + encodeString += (String.fromCharCode(value)); + num >>= 5; + } + value = num + 63; + encodeString += (String.fromCharCode(value)); + return encodeString; + }, + + CLASS_NAME: "OpenLayers.Format.EncodedPolyline" +}); diff --git a/tests/Format/EncodedPolyline.html b/tests/Format/EncodedPolyline.html new file mode 100644 index 0000000000..1a93a41afa --- /dev/null +++ b/tests/Format/EncodedPolyline.html @@ -0,0 +1,133 @@ + + + + + + + + diff --git a/tests/list-tests.html b/tests/list-tests.html index 8c37464b84..dfcaa2f4a0 100644 --- a/tests/list-tests.html +++ b/tests/list-tests.html @@ -66,6 +66,7 @@
  • Format/XML/VersionedOGC.html
  • Format/ArcXML/Features.html
  • Format/CQL.html
  • +
  • Format/EncodedPolyline.html
  • Format/GeoJSON.html
  • Format/GeoRSS.html
  • Format/GML.html