Merge pull request #337 from Turbo87/polyline

Added ol.parser.polyline module
This commit is contained in:
Tom Payne
2013-03-11 13:55:04 -07:00
2 changed files with 597 additions and 0 deletions

335
src/ol/parser/polyline.js Normal file
View File

@@ -0,0 +1,335 @@
goog.provide('ol.parser.polyline');
/**
* Encode a list of coordinates in a flat array and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} flatPoints A flat array of coordinates.
* @param {number=} opt_dimension The dimension of the coordinates in the array.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFlatCoordinates =
function(flatPoints, opt_dimension) {
var dimension = opt_dimension || 2;
return ol.parser.polyline.encodeDeltas(flatPoints, dimension);
};
/**
* Decode a list of coordinates from an encoded string into a flat array
*
* @param {string} encoded An encoded string.
* @param {number=} opt_dimension The dimension of the coordinates in the
* encoded string.
* @return {Array.<number>} A flat array of coordinates.
*/
ol.parser.polyline.decodeFlatCoordinates = function(encoded, opt_dimension) {
var dimension = opt_dimension || 2;
return ol.parser.polyline.decodeDeltas(encoded, dimension);
};
/**
* Encode a list of n-dimensional points and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of n-dimensional points.
* @param {number} dimension The dimension of the points in the list.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.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 ol.parser.polyline.encodeFloats(numbers, factor);
};
/**
* Decode a list of n-dimensional points from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number} dimension The dimension of the points in the encoded string.
* @param {number=} opt_factor The factor by which the resulting numbers will
* be divided.
* @return {Array.<number>} A list of n-dimensional points.
*/
ol.parser.polyline.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 = ol.parser.polyline.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;
};
/**
* Encode a list of floating point numbers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of floating point numbers.
* @param {number=} opt_factor The factor by which the numbers will be
* multiplied. The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.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 ol.parser.polyline.encodeSignedIntegers(numbers);
};
/**
* Decode a list of floating point numbers from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number=} opt_factor The factor by which the result will be divided.
* @return {Array.<number>} A list of floating point numbers.
*/
ol.parser.polyline.decodeFloats = function(encoded, opt_factor) {
var factor = opt_factor || 1e5;
var numbers = ol.parser.polyline.decodeSignedIntegers(encoded);
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
numbers[i] /= factor;
}
return numbers;
};
/**
* Encode a list of signed integers and return an encoded string
*
* Attention: This function will modify the passed array!
*
* @param {Array.<number>} numbers A list of signed integers.
* @return {string} The encoded string.
*/
ol.parser.polyline.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 ol.parser.polyline.encodeUnsignedIntegers(numbers);
};
/**
* Decode a list of signed integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of signed integers.
*/
ol.parser.polyline.decodeSignedIntegers = function(encoded) {
var numbers = ol.parser.polyline.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;
};
/**
* Encode a list of unsigned integers and return an encoded string
*
* @param {Array.<number>} numbers A list of unsigned integers.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeUnsignedIntegers = function(numbers) {
var encoded = '';
var numbersLength = numbers.length;
for (var i = 0; i < numbersLength; ++i) {
encoded += ol.parser.polyline.encodeUnsignedInteger(numbers[i]);
}
return encoded;
};
/**
* Decode a list of unsigned integers from an encoded string
*
* @param {string} encoded An encoded string.
* @return {Array.<number>} A list of unsigned integers.
*/
ol.parser.polyline.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;
};
/**
* Encode one single floating point number and return an encoded string
*
* @param {number} num Floating point number that should be encoded.
* @param {number=} opt_factor The factor by which num will be multiplied.
* The remaining decimal places will get rounded away.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeFloat = function(num, opt_factor) {
num = Math.round(num * (opt_factor || 1e5));
return ol.parser.polyline.encodeSignedInteger(num);
};
/**
* Decode one single floating point number from an encoded string
*
* @param {string} encoded An encoded string.
* @param {number=} opt_factor The factor by which the result will be divided.
* @return {number} The decoded floating point number.
*/
ol.parser.polyline.decodeFloat = function(encoded, opt_factor) {
var result = ol.parser.polyline.decodeSignedInteger(encoded);
return result / (opt_factor || 1e5);
};
/**
* Encode one single signed integer and return an encoded string
*
* @param {number} num Signed integer that should be encoded.
* @return {string} The encoded string.
*/
ol.parser.polyline.encodeSignedInteger = function(num) {
var signedNum = num << 1;
if (num < 0) {
signedNum = ~(signedNum);
}
return ol.parser.polyline.encodeUnsignedInteger(signedNum);
};
/**
* Decode one single signed integer from an encoded string
*
* @param {string} encoded An encoded string.
* @return {number} The decoded signed integer.
*/
ol.parser.polyline.decodeSignedInteger = function(encoded) {
var result = ol.parser.polyline.decodeUnsignedInteger(encoded);
return ((result & 1) ? ~(result >> 1) : (result >> 1));
};
/**
* Encode one single unsigned integer and return an encoded string
*
* @param {number} num Unsigned integer that should be encoded.
* @return {string} The encoded string.
*/
ol.parser.polyline.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;
};
/**
* Decode one single unsigned integer from an encoded string
*
* @param {string} encoded An encoded string.
* @return {number} The decoded unsigned integer.
*/
ol.parser.polyline.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;
};

View File

@@ -0,0 +1,262 @@
goog.provide('ol.test.parser.polyline');
describe('ol.parser.polyline', function() {
var flatPoints, encodedFlatPoints;
var floats, smallFloats, encodedFloats;
var signedIntegers, encodedSignedIntegers;
var unsignedIntegers, encodedUnsignedIntegers;
function resetTestingData() {
flatPoints = [38.50000, -120.20000,
40.70000, -120.95000,
43.25200, -126.45300];
encodedFlatPoints = '_p~iF~ps|U_ulLnnqC_mqNvxq`@';
floats = [0.00, 0.15, -0.01, -0.16, 0.16, 0.01];
smallFloats = [0.00000, 0.00015, -0.00001, -0.00016, 0.00016, 0.00001];
encodedFloats = '?]@^_@A';
signedIntegers = [0, 15, -1, -16, 16, 1];
encodedSignedIntegers = '?]@^_@A';
unsignedIntegers = [0, 30, 1, 31, 32, 2, 174];
encodedUnsignedIntegers = '?]@^_@AmD';
}
// Reset testing data
beforeEach(resetTestingData);
describe('encodeFlatCoordinates', function() {
it('returns expected value', function() {
var encodeFlatCoordinates = ol.parser.polyline.encodeFlatCoordinates;
// from the "Encoded Polyline Algorithm Format" page at Google
expect(encodeFlatCoordinates(flatPoints)).toEqual(encodedFlatPoints);
});
});
describe('decodeFlatCoordinates', function() {
it('returns expected value', function() {
var decodeFlatCoordinates = ol.parser.polyline.decodeFlatCoordinates;
// from the "Encoded Polyline Algorithm Format" page at Google
expect(decodeFlatCoordinates(encodedFlatPoints)).toEqual(flatPoints);
});
});
describe('encodeDeltas', function() {
it('returns expected value', function() {
var encodeDeltas = ol.parser.polyline.encodeDeltas;
expect(encodeDeltas(flatPoints, 2)).toEqual(encodedFlatPoints);
});
});
describe('decodeDeltas', function() {
it('returns expected value', function() {
var decodeDeltas = ol.parser.polyline.decodeDeltas;
expect(decodeDeltas(encodedFlatPoints, 2)).toEqual(flatPoints);
});
});
describe('encodeFloats', function() {
it('returns expected value', function() {
var encodeFloats = ol.parser.polyline.encodeFloats;
expect(encodeFloats(smallFloats)).toEqual(encodedFloats);
resetTestingData();
expect(encodeFloats(smallFloats, 1e5)).toEqual(encodedFloats);
expect(encodeFloats(floats, 1e2)).toEqual(encodedFloats);
});
});
describe('decodeFloats', function() {
it('returns expected value', function() {
var decodeFloats = ol.parser.polyline.decodeFloats;
expect(decodeFloats(encodedFloats)).toEqual(smallFloats);
expect(decodeFloats(encodedFloats, 1e5)).toEqual(smallFloats);
expect(decodeFloats(encodedFloats, 1e2)).toEqual(floats);
});
});
describe('encodeSignedIntegers', function() {
it('returns expected value', function() {
var encodeSignedIntegers = ol.parser.polyline.encodeSignedIntegers;
expect(encodeSignedIntegers(
signedIntegers)).toEqual(encodedSignedIntegers);
});
});
describe('decodeSignedIntegers', function() {
it('returns expected value', function() {
var decodeSignedIntegers = ol.parser.polyline.decodeSignedIntegers;
expect(decodeSignedIntegers(
encodedSignedIntegers)).toEqual(signedIntegers);
});
});
describe('encodeUnsignedIntegers', function() {
it('returns expected value', function() {
var encodeUnsignedIntegers = ol.parser.polyline.encodeUnsignedIntegers;
expect(encodeUnsignedIntegers(
unsignedIntegers)).toEqual(encodedUnsignedIntegers);
});
});
describe('decodeUnsignedIntegers', function() {
it('returns expected value', function() {
var decodeUnsignedIntegers = ol.parser.polyline.decodeUnsignedIntegers;
expect(decodeUnsignedIntegers(
encodedUnsignedIntegers)).toEqual(unsignedIntegers);
});
});
describe('encodeFloat', function() {
it('returns expected value', function() {
var encodeFloat = ol.parser.polyline.encodeFloat;
expect(encodeFloat(0.00000)).toEqual('?');
expect(encodeFloat(-0.00001)).toEqual('@');
expect(encodeFloat(0.00001)).toEqual('A');
expect(encodeFloat(-0.00002)).toEqual('B');
expect(encodeFloat(0.00002)).toEqual('C');
expect(encodeFloat(0.00015)).toEqual(']');
expect(encodeFloat(-0.00016)).toEqual('^');
expect(encodeFloat(-0.1, 10)).toEqual('@');
expect(encodeFloat(0.1, 10)).toEqual('A');
expect(encodeFloat(16 * 32 / 1e5)).toEqual('__@');
expect(encodeFloat(16 * 32 * 32 / 1e5)).toEqual('___@');
// from the "Encoded Polyline Algorithm Format" page at Google
expect(encodeFloat(-179.9832104)).toEqual('`~oia@');
});
});
describe('decodeFloat', function() {
it('returns expected value', function() {
var decodeFloat = ol.parser.polyline.decodeFloat;
expect(decodeFloat('?')).toEqual(0.00000);
expect(decodeFloat('@')).toEqual(-0.00001);
expect(decodeFloat('A')).toEqual(0.00001);
expect(decodeFloat('B')).toEqual(-0.00002);
expect(decodeFloat('C')).toEqual(0.00002);
expect(decodeFloat(']')).toEqual(0.00015);
expect(decodeFloat('^')).toEqual(-0.00016);
expect(decodeFloat('@', 10)).toEqual(-0.1);
expect(decodeFloat('A', 10)).toEqual(0.1);
expect(decodeFloat('__@')).toEqual(16 * 32 / 1e5);
expect(decodeFloat('___@')).toEqual(16 * 32 * 32 / 1e5);
// from the "Encoded Polyline Algorithm Format" page at Google
expect(decodeFloat('`~oia@')).toEqual(-179.98321);
});
});
describe('encodeSignedInteger', function() {
it('returns expected value', function() {
var encodeSignedInteger = ol.parser.polyline.encodeSignedInteger;
expect(encodeSignedInteger(0)).toEqual('?');
expect(encodeSignedInteger(-1)).toEqual('@');
expect(encodeSignedInteger(1)).toEqual('A');
expect(encodeSignedInteger(-2)).toEqual('B');
expect(encodeSignedInteger(2)).toEqual('C');
expect(encodeSignedInteger(15)).toEqual(']');
expect(encodeSignedInteger(-16)).toEqual('^');
expect(encodeSignedInteger(16)).toEqual('_@');
expect(encodeSignedInteger(16 * 32)).toEqual('__@');
expect(encodeSignedInteger(16 * 32 * 32)).toEqual('___@');
});
});
describe('decodeSignedInteger', function() {
it('returns expected value', function() {
var decodeSignedInteger = ol.parser.polyline.decodeSignedInteger;
expect(decodeSignedInteger('?')).toEqual(0);
expect(decodeSignedInteger('@')).toEqual(-1);
expect(decodeSignedInteger('A')).toEqual(1);
expect(decodeSignedInteger('B')).toEqual(-2);
expect(decodeSignedInteger('C')).toEqual(2);
expect(decodeSignedInteger(']')).toEqual(15);
expect(decodeSignedInteger('^')).toEqual(-16);
expect(decodeSignedInteger('_@')).toEqual(16);
expect(decodeSignedInteger('__@')).toEqual(16 * 32);
expect(decodeSignedInteger('___@')).toEqual(16 * 32 * 32);
});
});
describe('encodeUnsignedInteger', function() {
it('returns expected value', function() {
var encodeUnsignedInteger = ol.parser.polyline.encodeUnsignedInteger;
expect(encodeUnsignedInteger(0)).toEqual('?');
expect(encodeUnsignedInteger(1)).toEqual('@');
expect(encodeUnsignedInteger(2)).toEqual('A');
expect(encodeUnsignedInteger(30)).toEqual(']');
expect(encodeUnsignedInteger(31)).toEqual('^');
expect(encodeUnsignedInteger(32)).toEqual('_@');
expect(encodeUnsignedInteger(32 * 32)).toEqual('__@');
expect(encodeUnsignedInteger(5 * 32 * 32)).toEqual('__D');
expect(encodeUnsignedInteger(32 * 32 * 32)).toEqual('___@');
// from the "Encoded Polyline Algorithm Format" page at Google
expect(encodeUnsignedInteger(174)).toEqual('mD');
});
});
describe('decodeUnsignedInteger', function() {
it('returns expected value', function() {
var decodeUnsignedInteger = ol.parser.polyline.decodeUnsignedInteger;
expect(decodeUnsignedInteger('?')).toEqual(0);
expect(decodeUnsignedInteger('@')).toEqual(1);
expect(decodeUnsignedInteger('A')).toEqual(2);
expect(decodeUnsignedInteger(']')).toEqual(30);
expect(decodeUnsignedInteger('^')).toEqual(31);
expect(decodeUnsignedInteger('_@')).toEqual(32);
expect(decodeUnsignedInteger('__@')).toEqual(32 * 32);
expect(decodeUnsignedInteger('__D')).toEqual(5 * 32 * 32);
expect(decodeUnsignedInteger('___@')).toEqual(32 * 32 * 32);
// from the "Encoded Polyline Algorithm Format" page at Google
expect(decodeUnsignedInteger('mD')).toEqual(174);
});
});
});
goog.require('ol.parser.polyline');