diff --git a/src/ol/extent.js b/src/ol/extent.js index 766beeaa62..ba146637fc 100644 --- a/src/ol/extent.js +++ b/src/ol/extent.js @@ -3,6 +3,7 @@ goog.provide('ol.extent'); goog.provide('ol.extent.Relationship'); goog.require('goog.asserts'); +goog.require('goog.vec.Mat4'); goog.require('ol.Coordinate'); goog.require('ol.Size'); goog.require('ol.TransformFunction'); @@ -729,3 +730,37 @@ ol.extent.transform = function(extent, transformFn, opt_extent) { var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]]; return ol.extent.boundingExtentXYs_(xs, ys, opt_extent); }; + + +/** + * Apply a 2d transform to an extent. + * @param {ol.Extent} extent Input extent. + * @param {goog.vec.Mat4.Number} transform The transform matrix. + * @param {ol.Extent=} opt_extent Optional extent for return values. + * @return {ol.Extent} The transformed extent. + */ +ol.extent.transform2D = function(extent, transform, opt_extent) { + var dest = goog.isDef(opt_extent) ? opt_extent : []; + var m00 = goog.vec.Mat4.getElement(transform, 0, 0); + var m10 = goog.vec.Mat4.getElement(transform, 1, 0); + var m01 = goog.vec.Mat4.getElement(transform, 0, 1); + var m11 = goog.vec.Mat4.getElement(transform, 1, 1); + var m03 = goog.vec.Mat4.getElement(transform, 0, 3); + var m13 = goog.vec.Mat4.getElement(transform, 1, 3); + var xi = [0, 2, 0, 2]; + var yi = [1, 1, 3, 3]; + var xs = []; + var ys = []; + var i, x, y; + for (i = 0; i < 4; ++i) { + x = extent[xi[i]]; + y = extent[yi[i]]; + xs[i] = m00 * x + m01 * y + m03; + ys[i] = m10 * x + m11 * y + m13; + } + dest[0] = Math.min.apply(null, xs); + dest[1] = Math.min.apply(null, ys); + dest[2] = Math.max.apply(null, xs); + dest[3] = Math.max.apply(null, ys); + return dest; +}; diff --git a/test/spec/ol/extent.test.js b/test/spec/ol/extent.test.js index 52901cff5f..23a21ea675 100644 --- a/test/spec/ol/extent.test.js +++ b/test/spec/ol/extent.test.js @@ -467,9 +467,50 @@ describe('ol.extent', function() { }); + describe('transform2D()', function() { + + var extent; + beforeEach(function() { + extent = [-180, -90, 180, 90]; + }); + + it('applies a translate transform', function() { + var mat = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.makeTranslate(mat, 10, 20, 0); + var transformed = ol.extent.transform2D(extent, mat); + expect(transformed).to.eql([-170, -70, 190, 110]); + }); + + it('applies a rotate transform', function() { + var mat = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.makeRotateZ(mat, Math.PI / 2); + var transformed = ol.extent.transform2D(extent, mat); + expect(transformed[0]).to.roughlyEqual(-90, 1e-5); + expect(transformed[1]).to.roughlyEqual(-180, 1e-5); + expect(transformed[2]).to.roughlyEqual(90, 1e-5); + expect(transformed[3]).to.roughlyEqual(180, 1e-5); + }); + + it('does not modify original', function() { + var mat = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.makeRotateZ(mat, Math.PI / 2); + ol.extent.transform2D(extent, mat); + expect(extent).to.eql([-180, -90, 180, 90]); + }); + + it('accepts an extent to modify', function() { + var mat = goog.vec.Mat4.createNumber(); + goog.vec.Mat4.makeScale(mat, 2, 0.5); + ol.extent.transform2D(extent, mat, extent); + expect(extent).to.eql([-360, -45, 360, 45]); + }); + + }); + }); +goog.require('goog.vec.Mat4'); goog.require('ol.extent'); goog.require('ol.extent.Relationship'); goog.require('ol.proj');