EncodedPolyline: Backported ol3 polyline parser library

The ol3 version of the library is more advanced and complete. It can also
parse into flat array. It can handle unsigned integers, signed integers
and floats.
This commit is contained in:
Tobias Bieniek
2013-03-20 20:56:47 +01:00
parent 410a88c674
commit 17e972de3d
2 changed files with 615 additions and 75 deletions

View File

@@ -62,15 +62,16 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, {
else if (this.geometryType != "point" && this.geometryType != "polygon")
return null;
var points = this.decode(encoded, 2);
var pointGeometries = new Array();
for (var i in points) {
var point = points[i];
pointGeometries.push(
new OpenLayers.Geometry.Point(point[1] * 1e-5, point[0] * 1e-5)
);
var flatPoints = this.decodeDeltas(encoded, 2);
var flatPointsLength = flatPoints.length;
var pointGeometries = [];
for (var i = 0; i + 1 < flatPointsLength;) {
var y = flatPoints[i++], x = flatPoints[i++];
pointGeometries.push(new OpenLayers.Geometry.Point(x, y));
}
if (this.geometryType == "point")
return new OpenLayers.Feature.Vector(
pointGeometries[0]
@@ -102,29 +103,18 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, {
* coordinates.
*/
decode: function(encoded, dims) {
var points = new Array();
var point = new Array(dims);
var flatPoints = this.decodeDeltas(encoded, dims, 1);
var flatPointsLength = flatPoints.length;
// Reset the point array
for (var i = 0; i < point.length; ++i)
point[i] = 0;
var points = [];
for (var i = 0; i + (dims - 1) < flatPointsLength;) {
var point = [];
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));
point.push(flatPoints[i++])
}
points.push(point.slice(0));
points.push(point);
}
return points;
@@ -163,16 +153,16 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, {
else
return null;
var points = new Array();
for (var i in pointGeometries) {
var flatPoints = [];
var pointGeometriesLength = pointGeometries.length;
for (var i = 0; i < pointGeometriesLength; ++i) {
var pointGeometry = pointGeometries[i];
var point = [Math.round(pointGeometry.y * 1e5),
Math.round(pointGeometry.x * 1e5)];
points.push(point);
flatPoints.push(pointGeometry.y);
flatPoints.push(pointGeometry.x);
}
var result = this.encode(points, 2);
return result;
return this.encodeDeltas(flatPoints, 2);
},
/**
@@ -188,66 +178,377 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, {
* {String} An encoded string
*/
encode: function (points, dims) {
var encoded_points = "";
var flatPoints = [];
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 pointsLength = points.length;
for (var i = 0; i < pointsLength; ++i) {
var point = points[i];
for (var dim = 0; dim < lastPoint.length; ++dim) {
var delta = point[dim] - lastPoint[dim];
encoded_points += this.encodeSignedNumber(delta);
for (var dim = 0; dim < dims; ++dim) {
flatPoints.push(point[dim]);
}
lastPoint = point;
}
return encoded_points;
return this.encodeDeltas(flatPoints, dims, 1);
},
/**
* Method: encodeSignedNumber
* APIMethod: encodeDeltas
* Encode a list of n-dimensional points and return an encoded string
*
* Attention: This function will modify the passed array!
*
* Parameters:
* numbers - {Array.<number>} A list of n-dimensional points.
* dimension - {number} The dimension of the points in the list.
* opt_factor - {number=} The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
*
* Returns:
* {string} The encoded string.
*/
encodeDeltas: function(numbers, dimension, opt_factor) {
var factor = opt_factor || 1e5;
var d;
var lastNumbers = new Array(dimension);
for (d = 0; d < dimension; ++d) {
lastNumbers[d] = 0;
}
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength;) {
for (d = 0; d < dimension; ++d, ++i) {
var num = numbers[i];
var delta = num - lastNumbers[d];
lastNumbers[d] = num;
numbers[i] = delta;
}
}
return this.encodeFloats(numbers, factor);
},
/**
* APIMethod: decodeDeltas
* Decode a list of n-dimensional points from an encoded string
*
* Parameters:
* encoded - {string} An encoded string.
* dimension - {number} The dimension of the points in the encoded string.
* opt_factor - {number=} The factor by which the resulting numbers will
* be divided.
*
* Returns:
* {Array.<number>} A list of n-dimensional points.
*/
decodeDeltas: function(encoded, dimension, opt_factor) {
var factor = opt_factor || 1e5;
var d;
var lastNumbers = new Array(dimension);
for (d = 0; d < dimension; ++d) {
lastNumbers[d] = 0;
}
var numbers = this.decodeFloats(encoded, factor);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength;) {
for (d = 0; d < dimension; ++d, ++i) {
lastNumbers[d] += numbers[i];
numbers[i] = lastNumbers[d];
}
}
return numbers;
},
/**
* APIMethod: encodeFloats
* Encode a list of floating point numbers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* Parameters:
* numbers - {Array.<number>} A list of floating point numbers.
* opt_factor - {number=} The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
*
* Returns:
* {string} The encoded string.
*/
encodeFloats: function(numbers, opt_factor) {
var factor = opt_factor || 1e5;
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
numbers[i] = Math.round(numbers[i] * factor);
}
return this.encodeSignedIntegers(numbers);
},
/**
* APIMethod: decodeFloats
* Decode a list of floating point numbers from an encoded string
*
* Parameters:
* encoded - {string} An encoded string.
* opt_factor - {number=} The factor by which the result will be divided.
*
* Returns:
* {Array.<number>} A list of floating point numbers.
*/
decodeFloats: function(encoded, opt_factor) {
var factor = opt_factor || 1e5;
var numbers = this.decodeSignedIntegers(encoded);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
numbers[i] /= factor;
}
return numbers;
},
/**
* APIMethod: encodeSignedIntegers
* Encode a list of signed integers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* Parameters:
* numbers - {Array.<number>} A list of signed integers.
*
* Returns:
* {string} The encoded string.
*/
encodeSignedIntegers: function(numbers) {
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
var num = numbers[i];
var signedNum = num << 1;
if (num < 0) {
signedNum = ~(signedNum);
}
numbers[i] = signedNum;
}
return this.encodeUnsignedIntegers(numbers);
},
/**
* APIMethod: decodeSignedIntegers
* Decode a list of signed integers from an encoded string
*
* Parameters:
* encoded - {string} An encoded string.
*
* Returns:
* {Array.<number>} A list of signed integers.
*/
decodeSignedIntegers: function(encoded) {
var numbers = this.decodeUnsignedIntegers(encoded);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
var num = numbers[i];
numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
}
return numbers;
},
/**
* APIMethod: encodeUnsignedIntegers
* Encode a list of unsigned integers and return an encoded string
*
* Parameters:
* numbers - {Array.<number>} A list of unsigned integers.
*
* Returns:
* {string} The encoded string.
*/
encodeUnsignedIntegers: function(numbers) {
var encoded = '';
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
encoded += this.encodeUnsignedInteger(numbers[i]);
}
return encoded;
},
/**
* APIMethod: decodeUnsignedIntegers
* Decode a list of unsigned integers from an encoded string
*
* Parameters:
* encoded - {string} An encoded string.
*
* Returns:
* {Array.<number>} A list of unsigned integers.
*/
decodeUnsignedIntegers: function(encoded) {
var numbers = [];
var current = 0;
var shift = 0;
var encodedLength = encoded.length;
for (var i = 0; i < encodedLength; ++i) {
var b = encoded.charCodeAt(i) - 63;
current |= (b & 0x1f) << shift;
if (b < 0x20) {
numbers.push(current);
current = 0;
shift = 0;
} else {
shift += 5;
}
}
return numbers;
},
/**
* Method: encodeFloat
* Encode one single floating point number and return an encoded string
*
* Parameters:
* num - {number} Floating point number that should be encoded.
* opt_factor - {number=} The factor by which num will be multiplied.
* The remaining decimal places will get rounded away.
*
* Returns:
* {string} The encoded string.
*/
encodeFloat: function(num, opt_factor) {
num = Math.round(num * (opt_factor || 1e5));
return this.encodeSignedInteger(num);
},
/**
* Method: decodeFloat
* Decode one single floating point number from an encoded string
*
* Parameters:
* encoded - {string} An encoded string.
* opt_factor - {number=} The factor by which the result will be divided.
*
* Returns:
* {number} The decoded floating point number.
*/
decodeFloat: function(encoded, opt_factor) {
var result = this.decodeSignedInteger(encoded);
return result / (opt_factor || 1e5);
},
/**
* Method: encodeSignedInteger
* Encode one single signed integer and return an encoded string
*
* Parameters:
* num - {int} A signed integer that should be encoded
* num - {number} Signed integer that should be encoded.
*
* Returns:
* {String} An encoded string
* {string} The encoded string.
*/
encodeSignedNumber: function (num) {
var sgn_num = num << 1;
if (num < 0)
sgn_num = ~(sgn_num);
encodeSignedInteger: function(num) {
var signedNum = num << 1;
if (num < 0) {
signedNum = ~(signedNum);
}
return this.encodeNumber(sgn_num);
return this.encodeUnsignedInteger(signedNum);
},
/**
* Method: encodeNumber
* Encode one single unsigned integer and return an encoded string
*
* encodeSignedNumber should be used instead of using this method directly!
* Method: decodeSignedInteger
* Decode one single signed integer from an encoded string
*
* Parameters:
* num - {int} An unsigned integer that should be encoded
* encoded - {string} An encoded string.
*
* Returns:
* {String} An encoded string
* {number} The decoded signed integer.
*/
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;
decodeSignedInteger: function(encoded) {
var result = this.decodeUnsignedInteger(encoded);
return ((result & 1) ? ~(result >> 1) : (result >> 1));
},
/**
* Method: encodeUnsignedInteger
* Encode one single unsigned integer and return an encoded string
*
* Parameters:
* num - {number} Unsigned integer that should be encoded.
*
* Returns:
* {string} The encoded string.
*/
encodeUnsignedInteger: function(num) {
var value, encoded = '';
while (num >= 0x20) {
value = (0x20 | (num & 0x1f)) + 63;
encoded += (String.fromCharCode(value));
num >>= 5;
}
value = num + 63;
encoded += (String.fromCharCode(value));
return encoded;
},
/**
* Method: decodeUnsignedInteger
* Decode one single unsigned integer from an encoded string
*
* Parameters:
* encoded - {string} An encoded string.
*
* Returns:
* {number} The decoded unsigned integer.
*/
decodeUnsignedInteger: function(encoded) {
var result = 0;
var shift = 0;
var encodedLength = encoded.length;
for (var i = 0; i < encodedLength; ++i) {
var b = encoded.charCodeAt(i) - 63;
result |= (b & 0x1f) << shift;
if (b < 0x20)
break;
shift += 5;
}
return result;
},
CLASS_NAME: "OpenLayers.Format.EncodedPolyline"