Merge pull request #256 from tschaub/transform-arrays

Updating ol.TransformFunction instances so they work with arrays instead of coordinates.
This commit is contained in:
Tim Schaub
2013-03-03 14:46:22 -08:00
8 changed files with 219 additions and 63 deletions
+4 -1
View File
@@ -8,6 +8,7 @@ goog.require('goog.dom');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('goog.style'); goog.require('goog.style');
goog.require('ol.Coordinate');
goog.require('ol.CoordinateFormatType'); goog.require('ol.CoordinateFormatType');
goog.require('ol.MapEvent'); goog.require('ol.MapEvent');
goog.require('ol.MapEventType'); goog.require('ol.MapEventType');
@@ -177,7 +178,9 @@ ol.control.MousePosition.prototype.updateHTML_ = function(pixel) {
var map = this.getMap(); var map = this.getMap();
var coordinate = map.getCoordinateFromPixel(pixel); var coordinate = map.getCoordinateFromPixel(pixel);
if (!goog.isNull(coordinate)) { if (!goog.isNull(coordinate)) {
coordinate = this.transform_(coordinate); var vertex = [coordinate.x, coordinate.y];
vertex = this.transform_(vertex, vertex);
coordinate = new ol.Coordinate(vertex[0], vertex[1]);
if (goog.isDef(this.coordinateFormat_)) { if (goog.isDef(this.coordinateFormat_)) {
html = this.coordinateFormat_(coordinate); html = this.coordinateFormat_(coordinate);
} else { } else {
+6 -4
View File
@@ -108,8 +108,10 @@ ol.Extent.prototype.getTopRight = function() {
* @return {ol.Extent} Extent. * @return {ol.Extent} Extent.
*/ */
ol.Extent.prototype.transform = function(transformFn) { ol.Extent.prototype.transform = function(transformFn) {
var a = transformFn(new ol.Coordinate(this.minX, this.minY)); var input = [this.minX, this.minY, this.maxX, this.maxY];
var b = transformFn(new ol.Coordinate(this.maxX, this.maxY)); input = transformFn(input, input, 2);
return new ol.Extent(Math.min(a.x, b.x), Math.min(a.y, b.y), return new ol.Extent(Math.min(input[0], input[2]),
Math.max(a.x, b.x), Math.max(a.y, b.y)); Math.min(input[1], input[3]),
Math.max(input[0], input[2]),
Math.max(input[1], input[3]));
}; };
+12 -6
View File
@@ -76,11 +76,13 @@ ol.Geolocation.prototype.disposeInternal = function() {
ol.Geolocation.prototype.handleProjectionChanged_ = function() { ol.Geolocation.prototype.handleProjectionChanged_ = function() {
var projection = this.getProjection(); var projection = this.getProjection();
if (goog.isDefAndNotNull(projection)) { if (goog.isDefAndNotNull(projection)) {
this.transformCoords_ = ol.projection.getTransform( this.transformFn_ = ol.projection.getTransform(
ol.projection.getFromCode('EPSG:4326'), projection); ol.projection.getFromCode('EPSG:4326'), projection);
if (!goog.isNull(this.position_)) { if (!goog.isNull(this.position_)) {
var vertex = [this.position_.x, this.position_.y];
vertex = this.transformFn_(vertex, vertex, 2);
this.set(ol.GeolocationProperty.POSITION, this.set(ol.GeolocationProperty.POSITION,
this.transformCoords_(this.position_)); new ol.Coordinate(vertex[0], vertex[1]));
} }
} }
}; };
@@ -108,8 +110,10 @@ ol.Geolocation.prototype.positionChange_ = function(position) {
this.set(ol.GeolocationProperty.HEADING, goog.isNull(coords.heading) ? this.set(ol.GeolocationProperty.HEADING, goog.isNull(coords.heading) ?
undefined : goog.math.toRadians(coords.heading)); undefined : goog.math.toRadians(coords.heading));
this.position_ = new ol.Coordinate(coords.longitude, coords.latitude); this.position_ = new ol.Coordinate(coords.longitude, coords.latitude);
var vertex = [coords.longitude, coords.latitude];
vertex = this.transformFn_(vertex, vertex, 2);
this.set(ol.GeolocationProperty.POSITION, this.set(ol.GeolocationProperty.POSITION,
this.transformCoords_(this.position_)); new ol.Coordinate(vertex[0], vertex[1]));
this.set(ol.GeolocationProperty.SPEED, this.set(ol.GeolocationProperty.SPEED,
goog.isNull(coords.speed) ? undefined : coords.speed); goog.isNull(coords.speed) ? undefined : coords.speed);
}; };
@@ -230,7 +234,9 @@ goog.exportProperty(
/** /**
* @private * @private
* @param {ol.Coordinate} coordinate Coordinate. * @param {Array.<number>} input Input coordinate values.
* @return {ol.Coordinate} Coordinate. * @param {Array.<number>=} opt_output Output array of coordinate values.
* @param {number=} opt_dimension Dimension (default is 2).
* @return {Array.<number>} Output coordinate values.
*/ */
ol.Geolocation.prototype.transformCoords_ = goog.functions.identity; ol.Geolocation.prototype.transformFn_ = goog.functions.identity;
+61 -18
View File
@@ -397,14 +397,33 @@ ol.projection.getTransform = function(source, destination) {
var destinationProj4jsProj = proj4jsDestination.getProj4jsProj(); var destinationProj4jsProj = proj4jsDestination.getProj4jsProj();
transform = transform =
/** /**
* @param {ol.Coordinate} coordinate Coordinate. * @param {Array.<number>} input Input coordinate values.
* @return {ol.Coordinate} Coordinate. * @param {Array.<number>=} opt_output Output array of coordinates.
* @param {number=} opt_dimension Dimension.
* @return {Array.<number>} Output coordinate values.
*/ */
function(coordinate) { function(input, opt_output, opt_dimension) {
var proj4jsPoint = new Proj4js.Point(coordinate.x, coordinate.y); var length = input.length,
proj4jsPoint = Proj4js.transform( dimension = opt_dimension > 1 ? opt_dimension : 2,
sourceProj4jsProj, destinationProj4jsProj, proj4jsPoint); output = opt_output;
return new ol.Coordinate(proj4jsPoint.x, proj4jsPoint.y); if (!goog.isDef(output)) {
if (dimension > 2) {
// preserve values beyond second dimension
output = input.slice();
} else {
output = new Array(length);
}
}
goog.asserts.assert(output.length % dimension === 0);
var proj4jsPoint;
for (var i = 0; i < length; i += dimension) {
proj4jsPoint = new Proj4js.Point(input[i], input[i + 1]);
proj4jsPoint = Proj4js.transform(
sourceProj4jsProj, destinationProj4jsProj, proj4jsPoint);
output[i] = proj4jsPoint.x;
output[i + 1] = proj4jsPoint.y;
}
return output;
}; };
ol.projection.addTransform(source, destination, transform); ol.projection.addTransform(source, destination, transform);
} }
@@ -418,7 +437,7 @@ ol.projection.getTransform = function(source, destination) {
/** /**
* Given the projection codes this method searches for a transformation function * Given the projection codes this method searches for a transformation function
* to convert coordinate from the source projection to the destination * to convert a coordinates array from the source projection to the destination
* projection. * projection.
* *
* @param {string} sourceCode Source code. * @param {string} sourceCode Source code.
@@ -433,20 +452,42 @@ ol.projection.getTransformFromCodes = function(sourceCode, destinationCode) {
/** /**
* @param {ol.Coordinate} point Point. * @param {Array.<number>} input Input coordinate array.
* @return {ol.Coordinate} Unaltered point (same reference). * @param {Array.<number>=} opt_output Output array of coordinate values.
* @param {number=} opt_dimension Dimension.
* @return {Array.<number>} Input coordinate array (same array as input).
*/ */
ol.projection.identityTransform = function(point) { ol.projection.identityTransform = function(input, opt_output, opt_dimension) {
return point; if (goog.isDef(opt_output) && input !== opt_output) {
// TODO: consider making this a warning instead
goog.asserts.assert(false, 'This should not be used internally.');
for (var i = 0, ii = input.length; i < ii; ++i) {
opt_output[i] = input[i];
}
input = opt_output;
}
return input;
}; };
/** /**
* @param {ol.Coordinate} point Point. * @param {Array.<number>} input Input coordinate array.
* @return {ol.Coordinate} Equal point (different reference). * @param {Array.<number>=} opt_output Output array of coordinate values.
* @param {number=} opt_dimension Dimension.
* @return {Array.<number>} Output coordinate array (new array, same coordinate
* values).
*/ */
ol.projection.cloneTransform = function(point) { ol.projection.cloneTransform = function(input, opt_output, opt_dimension) {
return new ol.Coordinate(point.x, point.y); var output;
if (goog.isDef(opt_output)) {
for (var i = 0, ii = input.length; i < ii; ++i) {
opt_output[i] = input[i];
}
output = opt_output;
} else {
output = input.slice();
}
return output;
}; };
@@ -460,7 +501,8 @@ ol.projection.cloneTransform = function(point) {
*/ */
ol.projection.transform = function(point, source, destination) { ol.projection.transform = function(point, source, destination) {
var transformFn = ol.projection.getTransform(source, destination); var transformFn = ol.projection.getTransform(source, destination);
return transformFn(point); var output = transformFn([point.x, point.y]);
return new ol.Coordinate(output[0], output[1]);
}; };
@@ -474,5 +516,6 @@ ol.projection.transformWithCodes =
function(point, sourceCode, destinationCode) { function(point, sourceCode, destinationCode) {
var transformFn = ol.projection.getTransformFromCodes( var transformFn = ol.projection.getTransformFromCodes(
sourceCode, destinationCode); sourceCode, destinationCode);
return transformFn(point); var output = transformFn([point.x, point.y]);
return new ol.Coordinate(output[0], output[1]);
}; };
+47 -15
View File
@@ -1,7 +1,6 @@
goog.provide('ol.projection.EPSG3857'); goog.provide('ol.projection.EPSG3857');
goog.require('goog.array'); goog.require('goog.array');
goog.require('ol.Coordinate');
goog.require('ol.Extent'); goog.require('ol.Extent');
goog.require('ol.Projection'); goog.require('ol.Projection');
goog.require('ol.ProjectionUnits'); goog.require('ol.ProjectionUnits');
@@ -73,26 +72,59 @@ ol.projection.EPSG3857.PROJECTIONS = goog.array.map(
/** /**
* Transformation from EPSG:4326 to EPSG:3857. * Transformation from EPSG:4326 to EPSG:3857.
* *
* @param {ol.Coordinate} point Point. * @param {Array.<number>} input Input array of coordinate values.
* @return {ol.Coordinate} Point. * @param {Array.<number>=} opt_output Output array of coordinate values.
* @param {number=} opt_dimension Dimension (default is 2).
* @return {Array.<number>} Output array of coordinate values.
*/ */
ol.projection.EPSG3857.fromEPSG4326 = function(point) { ol.projection.EPSG3857.fromEPSG4326 = function(
var x = ol.projection.EPSG3857.RADIUS * Math.PI * point.x / 180; input, opt_output, opt_dimension) {
var y = ol.projection.EPSG3857.RADIUS * var length = input.length,
Math.log(Math.tan(Math.PI * (point.y + 90) / 360)); dimension = opt_dimension > 1 ? opt_dimension : 2,
return new ol.Coordinate(x, y); output = opt_output;
if (!goog.isDef(output)) {
if (dimension > 2) {
// preserve values beyond second dimension
output = input.slice();
} else {
output = new Array(length);
}
}
goog.asserts.assert(output.length % dimension === 0);
for (var i = 0; i < length; i += dimension) {
output[i] = ol.projection.EPSG3857.RADIUS * Math.PI * input[i] / 180;
output[i + 1] = ol.projection.EPSG3857.RADIUS *
Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360));
}
return output;
}; };
/** /**
* Transformation from EPSG:3857 to EPSG:4326. * Transformation from EPSG:3857 to EPSG:4326.
* *
* @param {ol.Coordinate} point Point. * @param {Array.<number>} input Input array of coordinate values.
* @return {ol.Coordinate} Point. * @param {Array.<number>=} opt_output Output array of coordinate values.
* @param {number=} opt_dimension Dimension (default is 2).
* @return {Array.<number>} Output array of coordinate values.
*/ */
ol.projection.EPSG3857.toEPSG4326 = function(point) { ol.projection.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) {
var x = 180 * point.x / (ol.projection.EPSG3857.RADIUS * Math.PI); var length = input.length,
var y = 360 * Math.atan( dimension = opt_dimension > 1 ? opt_dimension : 2,
Math.exp(point.y / ol.projection.EPSG3857.RADIUS)) / Math.PI - 90; output = opt_output;
return new ol.Coordinate(x, y); if (!goog.isDef(output)) {
if (dimension > 2) {
// preserve values beyond second dimension
output = input.slice();
} else {
output = new Array(length);
}
}
goog.asserts.assert(output.length % dimension === 0);
for (var i = 0; i < length; i += dimension) {
output[i] = 180 * input[i] / (ol.projection.EPSG3857.RADIUS * Math.PI);
output[i + 1] = 360 * Math.atan(
Math.exp(input[i + 1] / ol.projection.EPSG3857.RADIUS)) / Math.PI - 90;
}
return output;
}; };
+6 -3
View File
@@ -1,9 +1,12 @@
goog.provide('ol.TransformFunction'); goog.provide('ol.TransformFunction');
goog.require('ol.Coordinate');
/** /**
* @typedef {function(ol.Coordinate): ol.Coordinate} * A transform function accepts an array of input coordinate values, an optional
* output array, and an optional dimension (default should be 2). The function
* transforms the input coordinate values, populates the output array, and
* returns the output array.
*
* @typedef {function(Array.<number>, Array.<number>=, number=): Array.<number>}
*/ */
ol.TransformFunction; ol.TransformFunction;
+8 -8
View File
@@ -52,17 +52,17 @@ describe('ol.Extent', function() {
expect(extent.containsCoordinate( expect(extent.containsCoordinate(
new ol.Coordinate(3, 1))).toBeFalsy(); new ol.Coordinate(3, 1))).toBeFalsy();
expect(extent.containsCoordinate( expect(extent.containsCoordinate(
new ol.Coordinate(3, 5))).toBeFalsy(); new ol.Coordinate(3, 5))).toBeFalsy();
expect(extent.containsCoordinate( expect(extent.containsCoordinate(
new ol.Coordinate(4, 1))).toBeFalsy(); new ol.Coordinate(4, 1))).toBeFalsy();
expect(extent.containsCoordinate( expect(extent.containsCoordinate(
new ol.Coordinate(4, 2))).toBeFalsy(); new ol.Coordinate(4, 2))).toBeFalsy();
expect(extent.containsCoordinate( expect(extent.containsCoordinate(
new ol.Coordinate(4, 3))).toBeFalsy(); new ol.Coordinate(4, 3))).toBeFalsy();
expect(extent.containsCoordinate( expect(extent.containsCoordinate(
new ol.Coordinate(4, 4))).toBeFalsy(); new ol.Coordinate(4, 4))).toBeFalsy();
expect(extent.containsCoordinate( expect(extent.containsCoordinate(
new ol.Coordinate(4, 5))).toBeFalsy(); new ol.Coordinate(4, 5))).toBeFalsy();
}); });
}); });
}); });
@@ -84,8 +84,8 @@ describe('ol.Extent', function() {
}); });
it('takes arbitrary function', function() { it('takes arbitrary function', function() {
var transformFn = function(coordinate) { var transformFn = function(input) {
return new ol.Coordinate(-coordinate.x, -coordinate.y); return [-input[0], -input[1], -input[2], -input[3]];
}; };
var sourceExtent = new ol.Extent(-15, -30, 45, 60); var sourceExtent = new ol.Extent(-15, -30, 45, 60);
var destinationExtent = sourceExtent.transform(transformFn); var destinationExtent = sourceExtent.transform(transformFn);
+75 -8
View File
@@ -155,10 +155,22 @@ describe('ol.projection', function() {
var transform = ol.projection.getTransform(sm, gg); var transform = ol.projection.getTransform(sm, gg);
expect(typeof transform).toBe('function'); expect(typeof transform).toBe('function');
var coordinate = transform(new ol.Coordinate(-12000000, 5000000)); var output = transform([-12000000, 5000000]);
expect(coordinate.x).toRoughlyEqual(-107.79783409434258, 1e-9); expect(output[0]).toRoughlyEqual(-107.79783409434258, 1e-9);
expect(coordinate.y).toRoughlyEqual(40.91627447067577, 1e-9); expect(output[1]).toRoughlyEqual(40.91627447067577, 1e-9);
});
it('works for longer arrays', function() {
var transform = ol.projection.getTransform(sm, gg);
expect(typeof transform).toBe('function');
var output = transform([-12000000, 5000000, -12000000, 5000000]);
expect(output[0]).toRoughlyEqual(-107.79783409434258, 1e-9);
expect(output[1]).toRoughlyEqual(40.91627447067577, 1e-9);
expect(output[2]).toRoughlyEqual(-107.79783409434258, 1e-9);
expect(output[3]).toRoughlyEqual(40.91627447067577, 1e-9);
}); });
}); });
@@ -177,14 +189,69 @@ describe('ol.projection', function() {
'GOOGLE', 'EPSG:4326'); 'GOOGLE', 'EPSG:4326');
expect(typeof transform).toBe('function'); expect(typeof transform).toBe('function');
var coordinate = transform( var output = transform([-626172.13571216376, 6887893.4928337997]);
new ol.Coordinate(-626172.13571216376, 6887893.4928337997));
expect(coordinate.x).toRoughlyEqual(-5.625, 1e-9); expect(output[0]).toRoughlyEqual(-5.625, 1e-9);
expect(coordinate.y).toRoughlyEqual(52.4827802220782, 1e-9); expect(output[1]).toRoughlyEqual(52.4827802220782, 1e-9);
}); });
it('works for longer arrays of coordinate values', function() {
var transform = ol.projection.getTransformFromCodes(
'GOOGLE', 'EPSG:4326');
expect(typeof transform).toBe('function');
var output = transform([
-626172.13571216376, 6887893.4928337997,
-12000000, 5000000,
-626172.13571216376, 6887893.4928337997
]);
expect(output[0]).toRoughlyEqual(-5.625, 1e-9);
expect(output[1]).toRoughlyEqual(52.4827802220782, 1e-9);
expect(output[2]).toRoughlyEqual(-107.79783409434258, 1e-9);
expect(output[3]).toRoughlyEqual(40.91627447067577, 1e-9);
expect(output[4]).toRoughlyEqual(-5.625, 1e-9);
expect(output[5]).toRoughlyEqual(52.4827802220782, 1e-9);
});
it('accepts an optional destination array', function() {
var transform = ol.projection.getTransformFromCodes(
'EPSG:3857', 'EPSG:4326');
var input = [-12000000, 5000000];
var output = [];
var got = transform(input, output);
expect(got).toBe(output);
expect(output[0]).toRoughlyEqual(-107.79783409434258, 1e-9);
expect(output[1]).toRoughlyEqual(40.91627447067577, 1e-9);
expect(input).toEqual([-12000000, 5000000]);
});
it('accepts a dimension', function() {
var transform = ol.projection.getTransformFromCodes(
'GOOGLE', 'EPSG:4326');
expect(typeof transform).toBe('function');
var dimension = 3;
var output = transform([
-626172.13571216376, 6887893.4928337997, 100,
-12000000, 5000000, 200,
-626172.13571216376, 6887893.4928337997, 300
], undefined, dimension);
expect(output[0]).toRoughlyEqual(-5.625, 1e-9);
expect(output[1]).toRoughlyEqual(52.4827802220782, 1e-9);
expect(output[2]).toBe(100);
expect(output[3]).toRoughlyEqual(-107.79783409434258, 1e-9);
expect(output[4]).toRoughlyEqual(40.91627447067577, 1e-9);
expect(output[5]).toBe(200);
expect(output[6]).toRoughlyEqual(-5.625, 1e-9);
expect(output[7]).toRoughlyEqual(52.4827802220782, 1e-9);
expect(output[8]).toBe(300);
});
}); });
describe('ol.projection.removeTransform()', function() { describe('ol.projection.removeTransform()', function() {
@@ -195,7 +262,7 @@ describe('ol.projection', function() {
it('removes functions cached by addTransform', function() { it('removes functions cached by addTransform', function() {
var foo = new ol.Projection('foo', units, extent); var foo = new ol.Projection('foo', units, extent);
var bar = new ol.Projection('bar', units, extent); var bar = new ol.Projection('bar', units, extent);
var transform = function() {}; var transform = function(input, output, dimension) {return input};
ol.projection.addTransform(foo, bar, transform); ol.projection.addTransform(foo, bar, transform);
expect(ol.projection.transforms_).not.toBeUndefined(); expect(ol.projection.transforms_).not.toBeUndefined();
expect(ol.projection.transforms_.foo).not.toBeUndefined(); expect(ol.projection.transforms_.foo).not.toBeUndefined();