Add transform method to geometries

In the typical sequence of parse-transform-render the most efficient place to transform coordinate values is deep within the parser immediately after values have been read (this would avoid a second pass over whatever structure is used to back geometries).  To accomplish this transform during parsing, we could add back parser read options to pass the transform function around.

Until then, a transform method on geometries is straightforward to implement.  This means we do a second pass through coordinate structures to transform, but this is typically done only once immediately after parsing.
This commit is contained in:
Tim Schaub
2013-09-25 15:59:21 +02:00
parent e1ba1d8887
commit 33457c48de
9 changed files with 192 additions and 0 deletions

View File

@@ -67,3 +67,15 @@ ol.geom.AbstractCollection.prototype.getCoordinates = function() {
* @inheritDoc
*/
ol.geom.AbstractCollection.prototype.getType = goog.abstractMethod;
/**
* @inheritDoc
*/
ol.geom.AbstractCollection.prototype.transform = function(transform) {
var components = this.components;
for (var i = 0, ii = components.length; i < ii; ++i) {
components[i].transform(transform);
}
this.bounds = null;
};

View File

@@ -2,6 +2,7 @@ goog.provide('ol.geom.Geometry');
goog.provide('ol.geom.GeometryType');
goog.require('ol.Extent');
goog.require('ol.TransformFunction');

View File

@@ -112,3 +112,18 @@ ol.geom.LineString.prototype.distanceFromCoordinate = function(coordinate) {
}
return Math.sqrt(dist2);
};
/**
* @inheritDoc
*/
ol.geom.LineString.prototype.transform = function(transform) {
var coordinates = this.getCoordinates();
var dimension = this.dimension;
var coord;
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
coord = coordinates[i];
transform(coord, coord, dimension);
}
this.bounds_ = null;
};

View File

@@ -75,3 +75,13 @@ ol.geom.Point.prototype.getCoordinates = function() {
ol.geom.Point.prototype.getType = function() {
return ol.geom.GeometryType.POINT;
};
/**
* @inheritDoc
*/
ol.geom.Point.prototype.transform = function(transform) {
var coordinates = this.getCoordinates();
transform(coordinates, coordinates, this.dimension);
this.bounds_ = null;
};

View File

@@ -163,3 +163,14 @@ ol.geom.Polygon.prototype.getInteriorPoint = function() {
return this.labelPoint_;
};
/**
* @inheritDoc
*/
ol.geom.Polygon.prototype.transform = function(transform) {
var rings = this.rings;
for (var i = 0, ii = rings.length; i < ii; ++i) {
rings[i].transform(transform);
}
};

View File

@@ -48,7 +48,39 @@ describe('ol.geom.LineString', function() {
});
describe('#transform()', function() {
var forward = ol.proj.getTransform('EPSG:4326', 'EPSG:3857');
var inverse = ol.proj.getTransform('EPSG:3857', 'EPSG:4326');
it('forward transforms a linestring in place', function() {
var line = new ol.geom.LineString([[10, 20], [20, 30], [30, 40]]);
line.transform(forward);
expect(line.get(0, 0)).to.roughlyEqual(1113195, 1);
expect(line.get(0, 1)).to.roughlyEqual(2273031, 1);
expect(line.get(1, 0)).to.roughlyEqual(2226390, 1);
expect(line.get(1, 1)).to.roughlyEqual(3503550, 1);
expect(line.get(2, 0)).to.roughlyEqual(3339585, 1);
expect(line.get(2, 1)).to.roughlyEqual(4865942, 1);
});
it('inverse transforms a linestring in place', function() {
var line = new ol.geom.LineString([
[1113195, 2273031], [2226390, 3503550], [3339585, 4865942]
]);
line.transform(inverse);
expect(line.get(0, 0)).to.roughlyEqual(10, 0.001);
expect(line.get(0, 1)).to.roughlyEqual(20, 0.001);
expect(line.get(1, 0)).to.roughlyEqual(20, 0.001);
expect(line.get(1, 1)).to.roughlyEqual(30, 0.001);
expect(line.get(2, 0)).to.roughlyEqual(30, 0.001);
expect(line.get(2, 1)).to.roughlyEqual(40, 0.001);
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.LineString');
goog.require('ol.proj');

View File

@@ -68,8 +68,37 @@ describe('ol.geom.MultiPoint', function() {
});
describe('#transform', function() {
var forward = ol.proj.getTransform('EPSG:4326', 'EPSG:3857');
var inverse = ol.proj.getTransform('EPSG:3857', 'EPSG:4326');
it('forward transforms a multi-point', function() {
var multi = new ol.geom.MultiPoint([[10, 20], [30, 40]]);
multi.transform(forward);
expect(multi.components[0].get(0)).to.roughlyEqual(1113195, 1);
expect(multi.components[0].get(1)).to.roughlyEqual(2273031, 1);
expect(multi.components[1].get(0)).to.roughlyEqual(3339584, 1);
expect(multi.components[1].get(1)).to.roughlyEqual(4865942, 1);
});
it('inverse transforms a multi-point', function() {
var multi = new ol.geom.MultiPoint(
[[1113195, 2273031], [3339584, 4865942]]);
multi.transform(inverse);
expect(multi.components[0].get(0)).to.roughlyEqual(10, 0.001);
expect(multi.components[0].get(1)).to.roughlyEqual(20, 0.001);
expect(multi.components[1].get(0)).to.roughlyEqual(30, 0.001);
expect(multi.components[1].get(1)).to.roughlyEqual(40, 0.001);
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.Point');
goog.require('ol.proj');

View File

@@ -55,7 +55,29 @@ describe('ol.geom.Point', function() {
});
describe('#transform()', function() {
var forward = ol.proj.getTransform('EPSG:4326', 'EPSG:3857');
var inverse = ol.proj.getTransform('EPSG:3857', 'EPSG:4326');
it('forward transforms a point in place', function() {
var point = new ol.geom.Point([10, 20]);
point.transform(forward);
expect(point.get(0)).to.roughlyEqual(1113195, 1);
expect(point.get(1)).to.roughlyEqual(2273031, 1);
});
it('inverse transforms a point in place', function() {
var point = new ol.geom.Point([1113195, 2273031]);
point.transform(inverse);
expect(point.get(0)).to.roughlyEqual(10, 0.001);
expect(point.get(1)).to.roughlyEqual(20, 0.001);
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.Point');
goog.require('ol.proj');

View File

@@ -87,8 +87,68 @@ describe('ol.geom.Polygon', function() {
});
describe('#transform()', function() {
var forward = ol.proj.getTransform('EPSG:4326', 'EPSG:3857');
var inverse = ol.proj.getTransform('EPSG:3857', 'EPSG:4326');
var gg, sm;
beforeEach(function() {
gg = [
[[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]],
[[1, 1], [2, 1], [2, 2], [1, 2], [1, 1]],
[[8, 8], [9, 8], [9, 9], [8, 9], [8, 8]]
];
sm = [[
[0, 0], [0, 1118890], [1113195, 1118890], [1113195, 0], [0, 0]
], [
[111319, 111325], [222639, 111325], [222639, 222684],
[111319, 222684], [111319, 111325]
], [
[890556, 893464], [1001875, 893464], [1001875, 1006021],
[890556, 1006021], [890556, 893464]
]];
});
it('forward transforms a polygon in place', function() {
var poly = new ol.geom.Polygon(gg);
poly.transform(forward);
var coordinates = poly.getCoordinates();
var ring;
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
var ring = coordinates[i];
for (var j = 0, jj = ring.length; j < jj; ++j) {
expect(ring[j][0]).to.roughlyEqual(sm[i][j][0], 1);
expect(ring[j][1]).to.roughlyEqual(sm[i][j][1], 1);
}
}
});
it('inverse transforms a polygon in place', function() {
var poly = new ol.geom.Polygon(sm);
poly.transform(inverse);
var coordinates = poly.getCoordinates();
var ring;
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
var ring = coordinates[i];
for (var j = 0, jj = ring.length; j < jj; ++j) {
expect(ring[j][0]).to.roughlyEqual(gg[i][j][0], 0.001);
expect(ring[j][1]).to.roughlyEqual(gg[i][j][1], 0.001);
}
}
});
});
});
goog.require('ol.geom.Geometry');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.Polygon');
goog.require('ol.proj');