Merge pull request #2036 from tschaub/transform
More convenient geometry transforms.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.layer.Tile');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.source.TileWMS');
|
||||
@@ -38,7 +39,7 @@ var map = new ol.Map({
|
||||
var radius = 800000;
|
||||
for (var x = -180; x < 180; x += 30) {
|
||||
for (var y = -90; y < 90; y += 30) {
|
||||
var geometry = ol.sphere.WGS84.circle([x, y], radius, 64);
|
||||
vectorSource.addFeature(new ol.Feature(geometry));
|
||||
var circle = ol.geom.Polygon.circular(ol.sphere.WGS84, [x, y], radius, 64);
|
||||
vectorSource.addFeature(new ol.Feature(circle));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -714,13 +714,15 @@ ol.extent.touches = function(extent1, extent2) {
|
||||
|
||||
|
||||
/**
|
||||
* Apply a transform function to the extent.
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {ol.TransformFunction} transformFn Transform function.
|
||||
* @param {ol.TransformFunction} transformFn Transform function. Called with
|
||||
* [minX, minY, maxX, maxY] extent coordinates.
|
||||
* @param {ol.Extent=} opt_extent Destination extent.
|
||||
* @return {ol.Extent} Extent.
|
||||
* @todo api
|
||||
*/
|
||||
ol.extent.transform = function(extent, transformFn, opt_extent) {
|
||||
ol.extent.applyTransform = function(extent, transformFn, opt_extent) {
|
||||
var coordinates = [
|
||||
extent[0], extent[1],
|
||||
extent[0], extent[3],
|
||||
|
||||
@@ -11,6 +11,7 @@ goog.require('ol.BrowserFeature');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.sphere.WGS84');
|
||||
|
||||
@@ -186,8 +187,9 @@ ol.Geolocation.prototype.positionChange_ = function(position) {
|
||||
this.set(ol.GeolocationProperty.POSITION, projectedPosition);
|
||||
this.set(ol.GeolocationProperty.SPEED,
|
||||
goog.isNull(coords.speed) ? undefined : coords.speed);
|
||||
var geometry = ol.sphere.WGS84.circle(this.position_, coords.accuracy);
|
||||
geometry.transform(this.transform_);
|
||||
var geometry = ol.geom.Polygon.circular(
|
||||
ol.sphere.WGS84, this.position_, coords.accuracy);
|
||||
geometry.applyTransform(this.transform_);
|
||||
this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry);
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
@@ -217,4 +217,4 @@ ol.geom.Circle.prototype.setRadius = function(radius) {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.Circle.prototype.transform = goog.abstractMethod;
|
||||
ol.geom.Circle.prototype.applyTransform = goog.abstractMethod;
|
||||
|
||||
@@ -4,6 +4,7 @@ goog.provide('ol.geom.GeometryType');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.functions');
|
||||
goog.require('ol.Observable');
|
||||
goog.require('ol.proj');
|
||||
|
||||
|
||||
/**
|
||||
@@ -159,10 +160,30 @@ ol.geom.Geometry.prototype.getType = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Apply a transform function to the geometry. Modifies the geometry in place.
|
||||
* @function
|
||||
* @param {ol.TransformFunction} transformFn Transform.
|
||||
* @todo api
|
||||
*/
|
||||
ol.geom.Geometry.prototype.transform = goog.abstractMethod;
|
||||
ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Transform a geometry from one coordinate reference system to another.
|
||||
* Modifies the geometry in place.
|
||||
*
|
||||
* @param {ol.proj.ProjectionLike} source The current projection. Can be a
|
||||
* string identifier or a {@link ol.proj.Projection} object.
|
||||
* @param {ol.proj.ProjectionLike} destination The desired projection. Can be a
|
||||
* string identifier or a {@link ol.proj.Projection} object.
|
||||
* @return {ol.geom.Geometry} This geometry. Note that original geometry is
|
||||
* modified in place.
|
||||
* @todo api
|
||||
*/
|
||||
ol.geom.Geometry.prototype.transform = function(source, destination) {
|
||||
this.applyTransform(ol.proj.getTransform(source, destination));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -247,11 +247,11 @@ ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.geom.GeometryCollection.prototype.transform = function(transformFn) {
|
||||
ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) {
|
||||
var geometries = this.geometries_;
|
||||
var i, ii;
|
||||
for (i = 0, ii = geometries.length; i < ii; ++i) {
|
||||
geometries[i].transform(transformFn);
|
||||
geometries[i].applyTransform(transformFn);
|
||||
}
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
@@ -314,3 +314,29 @@ ol.geom.Polygon.prototype.setFlatCoordinates =
|
||||
this.ends_ = ends;
|
||||
this.dispatchChangeEvent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create an approximation of a circle on the surface of a sphere.
|
||||
* @param {ol.Sphere} sphere The sphere.
|
||||
* @param {ol.Coordinate} center Center.
|
||||
* @param {number} radius Radius.
|
||||
* @param {number=} opt_n Optional number of points. Default is `32`.
|
||||
* @return {ol.geom.Polygon} Circle geometry.
|
||||
* @todo api
|
||||
*/
|
||||
ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) {
|
||||
var n = goog.isDef(opt_n) ? opt_n : 32;
|
||||
/** @type {Array.<number>} */
|
||||
var flatCoordinates = [];
|
||||
var i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
goog.array.extend(
|
||||
flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n));
|
||||
}
|
||||
flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);
|
||||
var polygon = new ol.geom.Polygon(null);
|
||||
polygon.setFlatCoordinates(
|
||||
ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
|
||||
return polygon;
|
||||
};
|
||||
|
||||
@@ -242,9 +242,8 @@ ol.geom.SimpleGeometry.prototype.setLayout =
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @todo api
|
||||
*/
|
||||
ol.geom.SimpleGeometry.prototype.transform = function(transformFn) {
|
||||
ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) {
|
||||
if (!goog.isNull(this.flatCoordinates)) {
|
||||
transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);
|
||||
this.dispatchChangeEvent();
|
||||
|
||||
@@ -118,7 +118,7 @@ ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, result) {
|
||||
var feature = readFeatures[j];
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
geometry.transform(transform);
|
||||
geometry.applyTransform(transform);
|
||||
}
|
||||
features.push(feature);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,8 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse =
|
||||
var maxZ = coverageArea.zoomMax;
|
||||
var bbox = coverageArea.bbox;
|
||||
var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]];
|
||||
var extent = ol.extent.transform(epsg4326Extent, transform);
|
||||
var extent = ol.extent.applyTransform(
|
||||
epsg4326Extent, transform);
|
||||
var tileRange, z, zKey;
|
||||
for (z = minZ; z <= maxZ; ++z) {
|
||||
zKey = z.toString();
|
||||
|
||||
@@ -125,7 +125,7 @@ ol.source.FormatVector.prototype.readFeatures = function(source) {
|
||||
var feature = features[i];
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
geometry.transform(transform);
|
||||
geometry.applyTransform(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
|
||||
if (goog.isDef(tileJSON.bounds)) {
|
||||
var transform = ol.proj.getTransformFromProjections(
|
||||
epsg4326Projection, this.getProjection());
|
||||
extent = ol.extent.transform(tileJSON.bounds, transform);
|
||||
extent = ol.extent.applyTransform(tileJSON.bounds, transform);
|
||||
this.setExtent(extent);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ goog.provide('ol.Sphere');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.math');
|
||||
goog.require('ol.geom.Polygon');
|
||||
|
||||
|
||||
|
||||
@@ -30,33 +29,6 @@ ol.Sphere = function(radius) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an approximation to a circle centered on `center` with radius
|
||||
* `radius` with `n` distinct points.
|
||||
*
|
||||
* @param {ol.Coordinate} center Center.
|
||||
* @param {number} radius Radius.
|
||||
* @param {number=} opt_n N.
|
||||
* @return {ol.geom.Geometry} Circle geometry.
|
||||
* @todo api
|
||||
*/
|
||||
ol.Sphere.prototype.circle = function(center, radius, opt_n) {
|
||||
var n = goog.isDef(opt_n) ? opt_n : 32;
|
||||
/** @type {Array.<number>} */
|
||||
var flatCoordinates = [];
|
||||
var i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
goog.array.extend(
|
||||
flatCoordinates, this.offset(center, radius, 2 * Math.PI * i / n));
|
||||
}
|
||||
flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);
|
||||
var polygon = new ol.geom.Polygon(null);
|
||||
polygon.setFlatCoordinates(
|
||||
ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
|
||||
return polygon;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the distance from c1 to c2 using the spherical law of cosines.
|
||||
*
|
||||
|
||||
@@ -425,12 +425,13 @@ describe('ol.extent', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('transform', function() {
|
||||
describe('#applyTransform()', function() {
|
||||
|
||||
it('does transform', function() {
|
||||
var transformFn = ol.proj.getTransform('EPSG:4326', 'EPSG:3857');
|
||||
var sourceExtent = [-15, -30, 45, 60];
|
||||
var destinationExtent = ol.extent.transform(sourceExtent, transformFn);
|
||||
var destinationExtent = ol.extent.applyTransform(
|
||||
sourceExtent, transformFn);
|
||||
expect(destinationExtent).not.to.be(undefined);
|
||||
expect(destinationExtent).not.to.be(null);
|
||||
// FIXME check values with third-party tool
|
||||
@@ -456,7 +457,8 @@ describe('ol.extent', function() {
|
||||
return output;
|
||||
};
|
||||
var sourceExtent = [-15, -30, 45, 60];
|
||||
var destinationExtent = ol.extent.transform(sourceExtent, transformFn);
|
||||
var destinationExtent = ol.extent.applyTransform(
|
||||
sourceExtent, transformFn);
|
||||
expect(destinationExtent).not.to.be(undefined);
|
||||
expect(destinationExtent).not.to.be(null);
|
||||
expect(destinationExtent[0]).to.be(-45);
|
||||
|
||||
@@ -207,7 +207,7 @@ describe('ol.geom.Circle', function() {
|
||||
|
||||
it('throws an exception', function() {
|
||||
expect(function() {
|
||||
circle.transform(ol.proj.identityTransform);
|
||||
circle.applyTransform(ol.proj.identityTransform);
|
||||
}).to.throwException();
|
||||
});
|
||||
|
||||
|
||||
@@ -139,6 +139,35 @@ describe('ol.geom.GeometryCollection', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('#transform()', function() {
|
||||
|
||||
var line, multi, point;
|
||||
beforeEach(function() {
|
||||
point = new ol.geom.Point([10, 20]);
|
||||
line = new ol.geom.LineString([[10, 20], [30, 40]]);
|
||||
multi = new ol.geom.GeometryCollection([point, line]);
|
||||
});
|
||||
|
||||
it('transforms all geometries', function() {
|
||||
multi.transform('EPSG:4326', 'EPSG:3857');
|
||||
|
||||
var geometries = multi.getGeometries();
|
||||
expect(geometries[0]).to.be.a(ol.geom.Point);
|
||||
expect(geometries[1]).to.be.a(ol.geom.LineString);
|
||||
|
||||
var coords = geometries[0].getCoordinates();
|
||||
expect(coords[0]).to.roughlyEqual(1113194.90, 1e-2);
|
||||
expect(coords[1]).to.roughlyEqual(2273030.92, 1e-2);
|
||||
|
||||
coords = geometries[1].getCoordinates();
|
||||
expect(coords[0][0]).to.roughlyEqual(1113194.90, 1e-2);
|
||||
expect(coords[0][1]).to.roughlyEqual(2273030.92, 1e-2);
|
||||
expect(coords[1][0]).to.roughlyEqual(3339584.72, 1e-2);
|
||||
expect(coords[1][1]).to.roughlyEqual(4865942.27, 1e-2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -192,6 +192,63 @@ describe('ol.geom.MultiPoint', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('#applyTransform()', function() {
|
||||
|
||||
var multi, transform;
|
||||
beforeEach(function() {
|
||||
multi = new ol.geom.MultiPoint([[1, 2], [3, 4]]);
|
||||
transform = sinon.spy();
|
||||
});
|
||||
|
||||
it('calls a transform function', function() {
|
||||
multi.applyTransform(transform);
|
||||
expect(transform.calledOnce).to.be(true);
|
||||
var args = transform.firstCall.args;
|
||||
expect(args).to.have.length(3);
|
||||
|
||||
expect(args[0]).to.be(multi.getFlatCoordinates()); // input coords
|
||||
expect(args[1]).to.be(multi.getFlatCoordinates()); // output coords
|
||||
expect(args[2]).to.be(2); // dimension
|
||||
});
|
||||
|
||||
it('allows for modification of coordinates', function() {
|
||||
var mod = function(input, output, dimension) {
|
||||
var copy = input.slice();
|
||||
for (var i = 0, ii = copy.length; i < ii; i += dimension) {
|
||||
output[i] = copy[i + 1];
|
||||
output[i + 1] = copy[i];
|
||||
}
|
||||
};
|
||||
multi.applyTransform(mod);
|
||||
expect(multi.getCoordinates()).to.eql([[2, 1], [4, 3]]);
|
||||
});
|
||||
|
||||
it('returns undefined', function() {
|
||||
var got = multi.applyTransform(transform);
|
||||
expect(got).to.be(undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#transform()', function() {
|
||||
|
||||
it('transforms a geometry given CRS identifiers', function() {
|
||||
var multi = new ol.geom.MultiPoint([[-111, 45], [111, -45]]).transform(
|
||||
'EPSG:4326', 'EPSG:3857');
|
||||
|
||||
expect(multi).to.be.a(ol.geom.MultiPoint);
|
||||
|
||||
var coords = multi.getCoordinates();
|
||||
|
||||
expect(coords[0][0]).to.roughlyEqual(-12356463.47, 1e-2);
|
||||
expect(coords[0][1]).to.roughlyEqual(5621521.48, 1e-2);
|
||||
|
||||
expect(coords[1][0]).to.roughlyEqual(12356463.47, 1e-2);
|
||||
expect(coords[1][1]).to.roughlyEqual(-5621521.48, 1e-2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -106,6 +106,67 @@ describe('ol.geom.Point', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('#applyTransform()', function() {
|
||||
|
||||
var point, transform;
|
||||
beforeEach(function() {
|
||||
point = new ol.geom.Point([1, 2]);
|
||||
transform = sinon.spy();
|
||||
});
|
||||
|
||||
it('calls a transform function', function() {
|
||||
point.applyTransform(transform);
|
||||
expect(transform.calledOnce).to.be(true);
|
||||
var args = transform.firstCall.args;
|
||||
expect(args).to.have.length(3);
|
||||
|
||||
expect(args[0]).to.be(point.getFlatCoordinates()); // input coords
|
||||
expect(args[1]).to.be(point.getFlatCoordinates()); // output coords
|
||||
expect(args[2]).to.be(2); // dimension
|
||||
});
|
||||
|
||||
it('allows for modification of coordinates', function() {
|
||||
var mod = function(input, output, dimension) {
|
||||
var copy = input.slice();
|
||||
output[1] = copy[0];
|
||||
output[0] = copy[1];
|
||||
};
|
||||
point.applyTransform(mod);
|
||||
expect(point.getCoordinates()).to.eql([2, 1]);
|
||||
});
|
||||
|
||||
it('returns undefined', function() {
|
||||
var got = point.applyTransform(transform);
|
||||
expect(got).to.be(undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#transform()', function() {
|
||||
|
||||
it('transforms a geometry given CRS identifiers', function() {
|
||||
var point = new ol.geom.Point([-111, 45]).transform(
|
||||
'EPSG:4326', 'EPSG:3857');
|
||||
|
||||
expect(point).to.be.a(ol.geom.Point);
|
||||
|
||||
var coords = point.getCoordinates();
|
||||
|
||||
expect(coords[0]).to.roughlyEqual(-12356463.47, 1e-2);
|
||||
expect(coords[1]).to.roughlyEqual(5621521.48, 1e-2);
|
||||
});
|
||||
|
||||
it('modifies the original', function() {
|
||||
var point = new ol.geom.Point([-111, 45]);
|
||||
point.transform('EPSG:4326', 'EPSG:3857');
|
||||
var coords = point.getCoordinates();
|
||||
|
||||
expect(coords[0]).to.roughlyEqual(-12356463.47, 1e-2);
|
||||
expect(coords[1]).to.roughlyEqual(5621521.48, 1e-2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user