From 76a6e08ec15cc740bcda1f79b9058bcbb7f70953 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 14:43:06 +0100 Subject: [PATCH 1/9] Factor out ol.geom.SimpleGeometry --- src/ol/geom/geometry.exports | 5 +- src/ol/geom/geometry.js | 221 +-------------------- src/ol/geom/linearring.js | 6 +- src/ol/geom/linestring.js | 6 +- src/ol/geom/multilinestring.js | 6 +- src/ol/geom/multipoint.js | 6 +- src/ol/geom/multipolygon.js | 6 +- src/ol/geom/point.js | 6 +- src/ol/geom/polygon.js | 6 +- src/ol/geom/simplegeometry.exports | 5 + src/ol/geom/simplegeometry.js | 247 ++++++++++++++++++++++++ src/ol/render/canvas/canvasimmediate.js | 12 +- 12 files changed, 289 insertions(+), 243 deletions(-) create mode 100644 src/ol/geom/simplegeometry.exports create mode 100644 src/ol/geom/simplegeometry.js diff --git a/src/ol/geom/geometry.exports b/src/ol/geom/geometry.exports index 9737cb2f7d..4c332d46de 100644 --- a/src/ol/geom/geometry.exports +++ b/src/ol/geom/geometry.exports @@ -1,6 +1,3 @@ @exportSymbol ol.geom.Geometry @exportProperty ol.geom.Geometry.prototype.getClosestPoint -@exportProperty ol.geom.Geometry.prototype.getExtent -@exportProperty ol.geom.Geometry.prototype.getLayout -@exportProperty ol.geom.Geometry.prototype.getSimplifiedGeometry -@exportProperty ol.geom.Geometry.prototype.transform +@exportProperty ol.geom.Geometry.prototype.getType diff --git a/src/ol/geom/geometry.js b/src/ol/geom/geometry.js index 2b8d58ae6b..40c7aec271 100644 --- a/src/ol/geom/geometry.js +++ b/src/ol/geom/geometry.js @@ -5,10 +5,7 @@ goog.provide('ol.geom.Geometry'); goog.require('goog.asserts'); goog.require('goog.events.EventType'); goog.require('goog.functions'); -goog.require('goog.object'); goog.require('ol.Observable'); -goog.require('ol.extent'); -goog.require('ol.geom.flat'); /** @@ -45,24 +42,6 @@ ol.geom.Geometry = function() { goog.base(this); - /** - * @protected - * @type {ol.geom.GeometryLayout} - */ - this.layout = ol.geom.GeometryLayout.XY; - - /** - * @protected - * @type {number} - */ - this.stride = 2; - - /** - * @protected - * @type {Array.} - */ - this.flatCoordinates = null; - /** * @protected * @type {number} @@ -82,22 +61,22 @@ ol.geom.Geometry = function() { this.extentRevision = -1; /** - * @private + * @protected * @type {Object.} */ - this.simplifiedGeometryCache_ = {}; + this.simplifiedGeometryCache = {}; /** - * @private + * @protected * @type {number} */ - this.simplifiedGeometryMaxMinSquaredTolerance_ = 0; + this.simplifiedGeometryMaxMinSquaredTolerance = 0; /** - * @private + * @protected * @type {number} */ - this.simplifiedGeometryRevision_ = 0; + this.simplifiedGeometryRevision = 0; }; goog.inherits(ol.geom.Geometry, ol.Observable); @@ -126,44 +105,6 @@ ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) { }; -/** - * @param {number} stride Stride. - * @private - * @return {ol.geom.GeometryLayout} layout Layout. - */ -ol.geom.Geometry.getLayoutForStride_ = function(stride) { - if (stride == 2) { - return ol.geom.GeometryLayout.XY; - } else if (stride == 3) { - return ol.geom.GeometryLayout.XYZ; - } else if (stride == 4) { - return ol.geom.GeometryLayout.XYZM; - } else { - throw new Error('unsupported stride: ' + stride); - } -}; - - -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @private - * @return {number} Stride. - */ -ol.geom.Geometry.getStrideForLayout_ = function(layout) { - if (layout == ol.geom.GeometryLayout.XY) { - return 2; - } else if (layout == ol.geom.GeometryLayout.XYZ) { - return 3; - } else if (layout == ol.geom.GeometryLayout.XYM) { - return 3; - } else if (layout == ol.geom.GeometryLayout.XYZM) { - return 4; - } else { - throw new Error('unsupported layout: ' + layout); - } -}; - - /** * @param {ol.Coordinate} coordinate Coordinate. * @return {boolean} Contains coordinate. @@ -194,31 +135,7 @@ ol.geom.Geometry.prototype.dispatchChangeEvent = function() { * @param {ol.Extent=} opt_extent Extent. * @return {ol.Extent} extent Extent. */ -ol.geom.Geometry.prototype.getExtent = function(opt_extent) { - if (this.extentRevision != this.revision) { - this.extent = ol.extent.createOrUpdateFromFlatCoordinates( - this.flatCoordinates, this.stride, this.extent); - this.extentRevision = this.revision; - } - goog.asserts.assert(goog.isDef(this.extent)); - return ol.extent.returnOrUpdate(this.extent, opt_extent); -}; - - -/** - * @return {Array.} Flat coordinates. - */ -ol.geom.Geometry.prototype.getFlatCoordinates = function() { - return this.flatCoordinates; -}; - - -/** - * @return {ol.geom.GeometryLayout} Layout. - */ -ol.geom.Geometry.prototype.getLayout = function() { - return this.layout; -}; +ol.geom.Geometry.prototype.getExtent = goog.abstractMethod; /** @@ -233,60 +150,7 @@ ol.geom.Geometry.prototype.getRevision = function() { * @param {number} squaredTolerance Squared tolerance. * @return {ol.geom.Geometry} Simplified geometry. */ -ol.geom.Geometry.prototype.getSimplifiedGeometry = function(squaredTolerance) { - if (this.simplifiedGeometryRevision_ != this.revision) { - goog.object.clear(this.simplifiedGeometryCache_); - this.simplifiedGeometryMaxMinSquaredTolerance_ = 0; - this.simplifiedGeometryRevision_ = this.revision; - } - // If squaredTolerance is negative or if we know that simplification will not - // have any effect then just return this. - if (squaredTolerance < 0 || - (this.simplifiedGeometryMaxMinSquaredTolerance_ !== 0 && - squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance_)) { - return this; - } - var key = squaredTolerance.toString(); - if (this.simplifiedGeometryCache_.hasOwnProperty(key)) { - return this.simplifiedGeometryCache_[key]; - } else { - var simplifiedGeometry = - this.getSimplifiedGeometryInternal(squaredTolerance); - var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates(); - if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) { - this.simplifiedGeometryCache_[key] = simplifiedGeometry; - return simplifiedGeometry; - } else { - // Simplification did not actually remove any coordinates. We now know - // that any calls to getSimplifiedGeometry with a squaredTolerance less - // than or equal to the current squaredTolerance will also not have any - // effect. This allows us to short circuit simplification (saving CPU - // cycles) and prevents the cache of simplified geometries from filling - // up with useless identical copies of this geometry (saving memory). - this.simplifiedGeometryMaxMinSquaredTolerance_ = squaredTolerance; - return this; - } - } -}; - - -/** - * @param {number} squaredTolerance Squared tolerance. - * @return {ol.geom.Geometry} Simplified geometry. - * @protected - */ -ol.geom.Geometry.prototype.getSimplifiedGeometryInternal = - function(squaredTolerance) { - return this; -}; - - -/** - * @return {number} Stride. - */ -ol.geom.Geometry.prototype.getStride = function() { - return this.stride; -}; +ol.geom.Geometry.prototype.getSimplifiedGeometry = goog.abstractMethod; /** @@ -295,59 +159,10 @@ ol.geom.Geometry.prototype.getStride = function() { ol.geom.Geometry.prototype.getType = goog.abstractMethod; -/** - * @param {ol.geom.GeometryLayout} layout Layout. - * @param {Array.} flatCoordinates Flat coordinates. - * @protected - */ -ol.geom.Geometry.prototype.setFlatCoordinatesInternal = - function(layout, flatCoordinates) { - this.stride = ol.geom.Geometry.getStrideForLayout_(layout); - this.layout = layout; - this.flatCoordinates = flatCoordinates; -}; - - -/** - * @param {ol.geom.GeometryLayout|undefined} layout Layout. - * @param {Array} coordinates Coordinates. - * @param {number} nesting Nesting. - * @protected - */ -ol.geom.Geometry.prototype.setLayout = - function(layout, coordinates, nesting) { - /** @type {number} */ - var stride; - if (goog.isDef(layout)) { - stride = ol.geom.Geometry.getStrideForLayout_(layout); - } else { - var i; - for (i = 0; i < nesting; ++i) { - if (coordinates.length === 0) { - this.layout = ol.geom.GeometryLayout.XY; - this.stride = 2; - return; - } else { - coordinates = /** @type {Array} */ (coordinates[0]); - } - } - stride = (/** @type {Array} */ (coordinates)).length; - layout = ol.geom.Geometry.getLayoutForStride_(stride); - } - this.layout = layout; - this.stride = stride; -}; - - /** * @param {ol.TransformFunction} transformFn Transform. */ -ol.geom.Geometry.prototype.transform = function(transformFn) { - if (!goog.isNull(this.flatCoordinates)) { - transformFn(this.flatCoordinates, this.flatCoordinates, this.stride); - this.dispatchChangeEvent(); - } -}; +ol.geom.Geometry.prototype.transform = goog.abstractMethod; /** @@ -391,21 +206,3 @@ ol.geom.RawMultiLineString; * @typedef {Array.} */ ol.geom.RawMultiPolygon; - - -/** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {goog.vec.Mat4.AnyType} transform Transform. - * @param {Array.=} opt_dest Destination. - * @return {Array.} Transformed flat coordinates. - */ -ol.geom.transformGeometry2D = function(geometry, transform, opt_dest) { - var flatCoordinates = geometry.getFlatCoordinates(); - if (goog.isNull(flatCoordinates)) { - return null; - } else { - var stride = geometry.getStride(); - return ol.geom.flat.transform2D( - flatCoordinates, stride, transform, opt_dest); - } -}; diff --git a/src/ol/geom/linearring.js b/src/ol/geom/linearring.js index 4531ecf474..1407d5b74c 100644 --- a/src/ol/geom/linearring.js +++ b/src/ol/geom/linearring.js @@ -1,7 +1,7 @@ goog.provide('ol.geom.LinearRing'); goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.closest'); goog.require('ol.geom.flat'); goog.require('ol.geom.simplify'); @@ -10,7 +10,7 @@ goog.require('ol.geom.simplify'); /** * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.geom.SimpleGeometry} * @param {ol.geom.RawLinearRing} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ @@ -33,7 +33,7 @@ ol.geom.LinearRing = function(coordinates, opt_layout) { this.setCoordinates(coordinates, opt_layout); }; -goog.inherits(ol.geom.LinearRing, ol.geom.Geometry); +goog.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry); /** diff --git a/src/ol/geom/linestring.js b/src/ol/geom/linestring.js index 45760bcc73..74258465d9 100644 --- a/src/ol/geom/linestring.js +++ b/src/ol/geom/linestring.js @@ -1,7 +1,7 @@ goog.provide('ol.geom.LineString'); goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.closest'); goog.require('ol.geom.flat'); goog.require('ol.geom.simplify'); @@ -10,7 +10,7 @@ goog.require('ol.geom.simplify'); /** * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.geom.SimpleGeometry} * @param {ol.geom.RawLineString} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ @@ -33,7 +33,7 @@ ol.geom.LineString = function(coordinates, opt_layout) { this.setCoordinates(coordinates, opt_layout); }; -goog.inherits(ol.geom.LineString, ol.geom.Geometry); +goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry); /** diff --git a/src/ol/geom/multilinestring.js b/src/ol/geom/multilinestring.js index 15e5d578d9..9ab574574f 100644 --- a/src/ol/geom/multilinestring.js +++ b/src/ol/geom/multilinestring.js @@ -1,8 +1,8 @@ goog.provide('ol.geom.MultiLineString'); goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); goog.require('ol.geom.LineString'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.closest'); goog.require('ol.geom.flat'); goog.require('ol.geom.simplify'); @@ -11,7 +11,7 @@ goog.require('ol.geom.simplify'); /** * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.geom.SimpleGeometry} * @param {ol.geom.RawMultiLineString} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ @@ -40,7 +40,7 @@ ol.geom.MultiLineString = function(coordinates, opt_layout) { this.setCoordinates(coordinates, opt_layout); }; -goog.inherits(ol.geom.MultiLineString, ol.geom.Geometry); +goog.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry); /** diff --git a/src/ol/geom/multipoint.js b/src/ol/geom/multipoint.js index ad390a7adf..5a8fd5282f 100644 --- a/src/ol/geom/multipoint.js +++ b/src/ol/geom/multipoint.js @@ -1,15 +1,15 @@ goog.provide('ol.geom.MultiPoint'); goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); goog.require('ol.geom.Point'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.flat'); /** * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.geom.SimpleGeometry} * @param {ol.geom.RawMultiPoint} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ @@ -17,7 +17,7 @@ ol.geom.MultiPoint = function(coordinates, opt_layout) { goog.base(this); this.setCoordinates(coordinates, opt_layout); }; -goog.inherits(ol.geom.MultiPoint, ol.geom.Geometry); +goog.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry); /** diff --git a/src/ol/geom/multipolygon.js b/src/ol/geom/multipolygon.js index 41014f4c0c..ac7554874a 100644 --- a/src/ol/geom/multipolygon.js +++ b/src/ol/geom/multipolygon.js @@ -1,8 +1,8 @@ goog.provide('ol.geom.MultiPolygon'); goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); goog.require('ol.geom.Polygon'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.closest'); goog.require('ol.geom.flat'); goog.require('ol.geom.simplify'); @@ -11,7 +11,7 @@ goog.require('ol.geom.simplify'); /** * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.geom.SimpleGeometry} * @param {ol.geom.RawMultiPolygon} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ @@ -52,7 +52,7 @@ ol.geom.MultiPolygon = function(coordinates, opt_layout) { this.setCoordinates(coordinates, opt_layout); }; -goog.inherits(ol.geom.MultiPolygon, ol.geom.Geometry); +goog.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry); /** diff --git a/src/ol/geom/point.js b/src/ol/geom/point.js index 8d8ab4a343..6ae66ad28a 100644 --- a/src/ol/geom/point.js +++ b/src/ol/geom/point.js @@ -2,14 +2,14 @@ goog.provide('ol.geom.Point'); goog.require('goog.asserts'); goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.flat'); /** * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.geom.SimpleGeometry} * @param {ol.geom.RawPoint} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ @@ -17,7 +17,7 @@ ol.geom.Point = function(coordinates, opt_layout) { goog.base(this); this.setCoordinates(coordinates, opt_layout); }; -goog.inherits(ol.geom.Point, ol.geom.Geometry); +goog.inherits(ol.geom.Point, ol.geom.SimpleGeometry); /** diff --git a/src/ol/geom/polygon.js b/src/ol/geom/polygon.js index fc4b3a891a..601cc849d4 100644 --- a/src/ol/geom/polygon.js +++ b/src/ol/geom/polygon.js @@ -1,8 +1,8 @@ goog.provide('ol.geom.Polygon'); goog.require('ol.extent'); -goog.require('ol.geom.Geometry'); goog.require('ol.geom.LinearRing'); +goog.require('ol.geom.SimpleGeometry'); goog.require('ol.geom.closest'); goog.require('ol.geom.flat'); goog.require('ol.geom.simplify'); @@ -11,7 +11,7 @@ goog.require('ol.geom.simplify'); /** * @constructor - * @extends {ol.geom.Geometry} + * @extends {ol.geom.SimpleGeometry} * @param {ol.geom.RawPolygon} coordinates Coordinates. * @param {ol.geom.GeometryLayout=} opt_layout Layout. */ @@ -52,7 +52,7 @@ ol.geom.Polygon = function(coordinates, opt_layout) { this.setCoordinates(coordinates, opt_layout); }; -goog.inherits(ol.geom.Polygon, ol.geom.Geometry); +goog.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry); /** diff --git a/src/ol/geom/simplegeometry.exports b/src/ol/geom/simplegeometry.exports new file mode 100644 index 0000000000..89c0067b62 --- /dev/null +++ b/src/ol/geom/simplegeometry.exports @@ -0,0 +1,5 @@ +@exportSymbol ol.geom.SimpleGeometry +@exportProperty ol.geom.SimpleGeometry.prototype.getExtent +@exportProperty ol.geom.SimpleGeometry.prototype.getLayout +@exportProperty ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry +@exportProperty ol.geom.SimpleGeometry.prototype.transform diff --git a/src/ol/geom/simplegeometry.js b/src/ol/geom/simplegeometry.js new file mode 100644 index 0000000000..29a92f6b97 --- /dev/null +++ b/src/ol/geom/simplegeometry.js @@ -0,0 +1,247 @@ +goog.provide('ol.geom.SimpleGeometry'); + +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('goog.object'); +goog.require('ol.extent'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.flat'); + + + +/** + * @constructor + * @extends {ol.geom.Geometry} + */ +ol.geom.SimpleGeometry = function() { + + goog.base(this); + + /** + * @protected + * @type {ol.geom.GeometryLayout} + */ + this.layout = ol.geom.GeometryLayout.XY; + + /** + * @protected + * @type {number} + */ + this.stride = 2; + + /** + * @protected + * @type {Array.} + */ + this.flatCoordinates = null; + +}; +goog.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry); + + +/** + * @param {number} stride Stride. + * @private + * @return {ol.geom.GeometryLayout} layout Layout. + */ +ol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) { + if (stride == 2) { + return ol.geom.GeometryLayout.XY; + } else if (stride == 3) { + return ol.geom.GeometryLayout.XYZ; + } else if (stride == 4) { + return ol.geom.GeometryLayout.XYZM; + } else { + throw new Error('unsupported stride: ' + stride); + } +}; + + +/** + * @param {ol.geom.GeometryLayout} layout Layout. + * @private + * @return {number} Stride. + */ +ol.geom.SimpleGeometry.getStrideForLayout_ = function(layout) { + if (layout == ol.geom.GeometryLayout.XY) { + return 2; + } else if (layout == ol.geom.GeometryLayout.XYZ) { + return 3; + } else if (layout == ol.geom.GeometryLayout.XYM) { + return 3; + } else if (layout == ol.geom.GeometryLayout.XYZM) { + return 4; + } else { + throw new Error('unsupported layout: ' + layout); + } +}; + + +/** + * @inheritDoc + */ +ol.geom.SimpleGeometry.prototype.containsXY = goog.functions.FALSE; + + +/** + * @inheritDoc + */ +ol.geom.SimpleGeometry.prototype.getExtent = function(opt_extent) { + if (this.extentRevision != this.revision) { + this.extent = ol.extent.createOrUpdateFromFlatCoordinates( + this.flatCoordinates, this.stride, this.extent); + this.extentRevision = this.revision; + } + goog.asserts.assert(goog.isDef(this.extent)); + return ol.extent.returnOrUpdate(this.extent, opt_extent); +}; + + +/** + * @return {Array.} Flat coordinates. + */ +ol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() { + return this.flatCoordinates; +}; + + +/** + * @return {ol.geom.GeometryLayout} Layout. + */ +ol.geom.SimpleGeometry.prototype.getLayout = function() { + return this.layout; +}; + + +/** + * @inheritDoc + */ +ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry = + function(squaredTolerance) { + if (this.simplifiedGeometryRevision != this.revision) { + goog.object.clear(this.simplifiedGeometryCache); + this.simplifiedGeometryMaxMinSquaredTolerance = 0; + this.simplifiedGeometryRevision = this.revision; + } + // If squaredTolerance is negative or if we know that simplification will not + // have any effect then just return this. + if (squaredTolerance < 0 || + (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && + squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) { + return this; + } + var key = squaredTolerance.toString(); + if (this.simplifiedGeometryCache.hasOwnProperty(key)) { + return this.simplifiedGeometryCache[key]; + } else { + var simplifiedGeometry = + this.getSimplifiedGeometryInternal(squaredTolerance); + var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates(); + if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) { + this.simplifiedGeometryCache[key] = simplifiedGeometry; + return simplifiedGeometry; + } else { + // Simplification did not actually remove any coordinates. We now know + // that any calls to getSimplifiedGeometry with a squaredTolerance less + // than or equal to the current squaredTolerance will also not have any + // effect. This allows us to short circuit simplification (saving CPU + // cycles) and prevents the cache of simplified geometries from filling + // up with useless identical copies of this geometry (saving memory). + this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; + return this; + } + } +}; + + +/** + * @param {number} squaredTolerance Squared tolerance. + * @return {ol.geom.SimpleGeometry} Simplified geometry. + * @protected + */ +ol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal = + function(squaredTolerance) { + return this; +}; + + +/** + * @return {number} Stride. + */ +ol.geom.SimpleGeometry.prototype.getStride = function() { + return this.stride; +}; + + +/** + * @param {ol.geom.GeometryLayout} layout Layout. + * @param {Array.} flatCoordinates Flat coordinates. + * @protected + */ +ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal = + function(layout, flatCoordinates) { + this.stride = ol.geom.SimpleGeometry.getStrideForLayout_(layout); + this.layout = layout; + this.flatCoordinates = flatCoordinates; +}; + + +/** + * @param {ol.geom.GeometryLayout|undefined} layout Layout. + * @param {Array} coordinates Coordinates. + * @param {number} nesting Nesting. + * @protected + */ +ol.geom.SimpleGeometry.prototype.setLayout = + function(layout, coordinates, nesting) { + /** @type {number} */ + var stride; + if (goog.isDef(layout)) { + stride = ol.geom.SimpleGeometry.getStrideForLayout_(layout); + } else { + var i; + for (i = 0; i < nesting; ++i) { + if (coordinates.length === 0) { + this.layout = ol.geom.GeometryLayout.XY; + this.stride = 2; + return; + } else { + coordinates = /** @type {Array} */ (coordinates[0]); + } + } + stride = (/** @type {Array} */ (coordinates)).length; + layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride); + } + this.layout = layout; + this.stride = stride; +}; + + +/** + * @inheritDoc + */ +ol.geom.SimpleGeometry.prototype.transform = function(transformFn) { + if (!goog.isNull(this.flatCoordinates)) { + transformFn(this.flatCoordinates, this.flatCoordinates, this.stride); + this.dispatchChangeEvent(); + } +}; + + +/** + * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry. + * @param {goog.vec.Mat4.AnyType} transform Transform. + * @param {Array.=} opt_dest Destination. + * @return {Array.} Transformed flat coordinates. + */ +ol.geom.transformSimpleGeometry2D = + function(simpleGeometry, transform, opt_dest) { + var flatCoordinates = simpleGeometry.getFlatCoordinates(); + if (goog.isNull(flatCoordinates)) { + return null; + } else { + var stride = simpleGeometry.getStride(); + return ol.geom.flat.transform2D( + flatCoordinates, stride, transform, opt_dest); + } +}; diff --git a/src/ol/render/canvas/canvasimmediate.js b/src/ol/render/canvas/canvasimmediate.js index bdf1538b3e..dcf09919e3 100644 --- a/src/ol/render/canvas/canvasimmediate.js +++ b/src/ol/render/canvas/canvasimmediate.js @@ -113,7 +113,7 @@ ol.render.canvas.Immediate.prototype.drawImages_ = function(geometry) { goog.asserts.assert(goog.isDef(state.anchorY)); goog.asserts.assert(goog.isDef(state.height)); goog.asserts.assert(goog.isDef(state.width)); - var pixelCoordinates = ol.geom.transformGeometry2D( + var pixelCoordinates = ol.geom.transformSimpleGeometry2D( geometry, this.transform_, this.pixelCoordinates_); var i, ii; for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { @@ -144,7 +144,7 @@ ol.render.canvas.Immediate.prototype.drawText_ = function(geometry) { return; } this.setFillStrokeStyles_(); - var pixelCoordinates = ol.geom.transformGeometry2D( + var pixelCoordinates = ol.geom.transformSimpleGeometry2D( geometry, this.transform_, this.pixelCoordinates_); var i, ii; for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) { @@ -251,7 +251,7 @@ ol.render.canvas.Immediate.prototype.drawLineStringGeometry = } this.setFillStrokeStyles_(); var context = this.context_; - var pixelCoordinates = ol.geom.transformGeometry2D( + var pixelCoordinates = ol.geom.transformSimpleGeometry2D( lineStringGeometry, this.transform_, this.pixelCoordinates_); context.beginPath(); this.moveToLineTo_(pixelCoordinates, 0, pixelCoordinates.length, false); @@ -271,7 +271,7 @@ ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry = } this.setFillStrokeStyles_(); var context = this.context_; - var pixelCoordinates = ol.geom.transformGeometry2D( + var pixelCoordinates = ol.geom.transformSimpleGeometry2D( multiLineStringGeometry, this.transform_, this.pixelCoordinates_); context.beginPath(); var ends = multiLineStringGeometry.getEnds(); @@ -298,7 +298,7 @@ ol.render.canvas.Immediate.prototype.drawPolygonGeometry = } this.setFillStrokeStyles_(); var context = this.context_; - var pixelCoordinates = ol.geom.transformGeometry2D( + var pixelCoordinates = ol.geom.transformSimpleGeometry2D( polygonGeometry, this.transform_, this.pixelCoordinates_); var ends = polygonGeometry.getEnds(); context.beginPath(); @@ -327,7 +327,7 @@ ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry = } this.setFillStrokeStyles_(); var context = this.context_; - var pixelCoordinates = ol.geom.transformGeometry2D( + var pixelCoordinates = ol.geom.transformSimpleGeometry2D( multiPolygonGeometry, this.transform_, this.pixelCoordinates_); var endss = multiPolygonGeometry.getEndss(); var offset = 0; From 6295fa60889276c7612bb00110a077c3a436214d Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 15:03:44 +0100 Subject: [PATCH 2/9] Add ol.geom.Geometry#clone --- src/ol/geom/geometry.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ol/geom/geometry.js b/src/ol/geom/geometry.js index 40c7aec271..76ede57540 100644 --- a/src/ol/geom/geometry.js +++ b/src/ol/geom/geometry.js @@ -82,6 +82,12 @@ ol.geom.Geometry = function() { goog.inherits(ol.geom.Geometry, ol.Observable); +/** + * @return {ol.geom.Geometry} Clone. + */ +ol.geom.Geometry.prototype.clone = goog.abstractMethod; + + /** * @param {number} x X. * @param {number} y Y. From 802d1644bbcd752d32962ce49ab97a2eea0c6464 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 15:03:56 +0100 Subject: [PATCH 3/9] Implement clone for simple geometries --- src/ol/geom/linearring.exports | 1 + src/ol/geom/linearring.js | 10 ++++++++++ src/ol/geom/linestring.exports | 1 + src/ol/geom/linestring.js | 10 ++++++++++ src/ol/geom/multilinestring.exports | 1 + src/ol/geom/multilinestring.js | 11 +++++++++++ src/ol/geom/multipoint.exports | 1 + src/ol/geom/multipoint.js | 10 ++++++++++ src/ol/geom/multipolygon.exports | 1 + src/ol/geom/multipolygon.js | 11 +++++++++++ src/ol/geom/point.exports | 1 + src/ol/geom/point.js | 10 ++++++++++ src/ol/geom/polygon.exports | 1 + src/ol/geom/polygon.js | 11 +++++++++++ 14 files changed, 80 insertions(+) diff --git a/src/ol/geom/linearring.exports b/src/ol/geom/linearring.exports index ab788b38a3..568949b1bb 100644 --- a/src/ol/geom/linearring.exports +++ b/src/ol/geom/linearring.exports @@ -1,4 +1,5 @@ @exportSymbol ol.geom.LinearRing +@exportProperty ol.geom.LinearRing.prototype.clone @exportProperty ol.geom.LinearRing.prototype.getArea @exportProperty ol.geom.LinearRing.prototype.getCoordinates @exportProperty ol.geom.LinearRing.prototype.getType diff --git a/src/ol/geom/linearring.js b/src/ol/geom/linearring.js index 1407d5b74c..622e56776d 100644 --- a/src/ol/geom/linearring.js +++ b/src/ol/geom/linearring.js @@ -36,6 +36,16 @@ ol.geom.LinearRing = function(coordinates, opt_layout) { goog.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry); +/** + * @inheritDoc + */ +ol.geom.LinearRing.prototype.clone = function() { + var linearRing = new ol.geom.LinearRing(null); + linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return linearRing; +}; + + /** * @inheritDoc */ diff --git a/src/ol/geom/linestring.exports b/src/ol/geom/linestring.exports index 362c1b1042..8de2df528c 100644 --- a/src/ol/geom/linestring.exports +++ b/src/ol/geom/linestring.exports @@ -1,4 +1,5 @@ @exportSymbol ol.geom.LineString +@exportProperty ol.geom.LineString.prototype.clone @exportProperty ol.geom.LineString.prototype.getCoordinates @exportProperty ol.geom.LineString.prototype.getType @exportProperty ol.geom.LineString.prototype.setCoordinates diff --git a/src/ol/geom/linestring.js b/src/ol/geom/linestring.js index 74258465d9..ead7a2ad91 100644 --- a/src/ol/geom/linestring.js +++ b/src/ol/geom/linestring.js @@ -36,6 +36,16 @@ ol.geom.LineString = function(coordinates, opt_layout) { goog.inherits(ol.geom.LineString, ol.geom.SimpleGeometry); +/** + * @inheritDoc + */ +ol.geom.LineString.prototype.clone = function() { + var lineString = new ol.geom.LineString(null); + lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return lineString; +}; + + /** * @inheritDoc */ diff --git a/src/ol/geom/multilinestring.exports b/src/ol/geom/multilinestring.exports index 6cea01324c..47f28467da 100644 --- a/src/ol/geom/multilinestring.exports +++ b/src/ol/geom/multilinestring.exports @@ -1,4 +1,5 @@ @exportSymbol ol.geom.MultiLineString +@exportProperty ol.geom.MultiLineString.prototype.clone @exportProperty ol.geom.MultiLineString.prototype.getCoordinates @exportProperty ol.geom.MultiLineString.prototype.getLineStrings @exportProperty ol.geom.MultiLineString.prototype.getType diff --git a/src/ol/geom/multilinestring.js b/src/ol/geom/multilinestring.js index 9ab574574f..18b00c2eb6 100644 --- a/src/ol/geom/multilinestring.js +++ b/src/ol/geom/multilinestring.js @@ -43,6 +43,17 @@ ol.geom.MultiLineString = function(coordinates, opt_layout) { goog.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry); +/** + * @inheritDoc + */ +ol.geom.MultiLineString.prototype.clone = function() { + var multiLineString = new ol.geom.MultiLineString(null); + multiLineString.setFlatCoordinates( + this.layout, this.flatCoordinates.slice(), this.ends_.slice()); + return multiLineString; +}; + + /** * @inheritDoc */ diff --git a/src/ol/geom/multipoint.exports b/src/ol/geom/multipoint.exports index eb89fe7d5d..97dff56f42 100644 --- a/src/ol/geom/multipoint.exports +++ b/src/ol/geom/multipoint.exports @@ -1,4 +1,5 @@ @exportSymbol ol.geom.MultiPoint +@exportProperty ol.geom.MultiPoint.prototype.clone @exportProperty ol.geom.MultiPoint.prototype.getCoordinates @exportProperty ol.geom.MultiPoint.prototype.getPoints @exportProperty ol.geom.MultiPoint.prototype.getType diff --git a/src/ol/geom/multipoint.js b/src/ol/geom/multipoint.js index 5a8fd5282f..35185d244e 100644 --- a/src/ol/geom/multipoint.js +++ b/src/ol/geom/multipoint.js @@ -20,6 +20,16 @@ ol.geom.MultiPoint = function(coordinates, opt_layout) { goog.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry); +/** + * @inheritDoc + */ +ol.geom.MultiPoint.prototype.clone = function() { + var multiPoint = new ol.geom.MultiPoint(null); + multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return multiPoint; +}; + + /** * @inheritDoc */ diff --git a/src/ol/geom/multipolygon.exports b/src/ol/geom/multipolygon.exports index e8e244a0aa..3bc1d385c7 100644 --- a/src/ol/geom/multipolygon.exports +++ b/src/ol/geom/multipolygon.exports @@ -1,4 +1,5 @@ @exportSymbol ol.geom.MultiPolygon +@exportProperty ol.geom.MultiPolygon.prototype.clone @exportProperty ol.geom.MultiPolygon.prototype.getArea @exportProperty ol.geom.MultiPolygon.prototype.getCoordinates @exportProperty ol.geom.MultiPolygon.prototype.getPolygons diff --git a/src/ol/geom/multipolygon.js b/src/ol/geom/multipolygon.js index ac7554874a..74880c43e9 100644 --- a/src/ol/geom/multipolygon.js +++ b/src/ol/geom/multipolygon.js @@ -55,6 +55,17 @@ ol.geom.MultiPolygon = function(coordinates, opt_layout) { goog.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry); +/** + * @inheritDoc + */ +ol.geom.MultiPolygon.prototype.clone = function() { + var multiPolygon = new ol.geom.MultiPolygon(null); + multiPolygon.setFlatCoordinates( + this.layout, this.flatCoordinates.slice(), this.endss_.slice()); + return multiPolygon; +}; + + /** * @inheritDoc */ diff --git a/src/ol/geom/point.exports b/src/ol/geom/point.exports index 4125ad3ab1..f48a3b7a4d 100644 --- a/src/ol/geom/point.exports +++ b/src/ol/geom/point.exports @@ -1,4 +1,5 @@ @exportSymbol ol.geom.Point +@exportProperty ol.geom.Point.prototype.clone @exportProperty ol.geom.Point.prototype.getCoordinates @exportProperty ol.geom.Point.prototype.getType @exportProperty ol.geom.Point.prototype.setCoordinates diff --git a/src/ol/geom/point.js b/src/ol/geom/point.js index 6ae66ad28a..57e10e4fd5 100644 --- a/src/ol/geom/point.js +++ b/src/ol/geom/point.js @@ -20,6 +20,16 @@ ol.geom.Point = function(coordinates, opt_layout) { goog.inherits(ol.geom.Point, ol.geom.SimpleGeometry); +/** + * @inheritDoc + */ +ol.geom.Point.prototype.clone = function() { + var point = new ol.geom.Point(null); + point.setFlatCoordinates(this.layout, this.flatCoordinates.slice()); + return point; +}; + + /** * @inheritDoc */ diff --git a/src/ol/geom/polygon.exports b/src/ol/geom/polygon.exports index 1b2fa4f0aa..d950a3ae05 100644 --- a/src/ol/geom/polygon.exports +++ b/src/ol/geom/polygon.exports @@ -1,4 +1,5 @@ @exportSymbol ol.geom.Polygon +@exportProperty ol.geom.Polygon.prototype.clone @exportProperty ol.geom.Polygon.prototype.getArea @exportProperty ol.geom.Polygon.prototype.getCoordinates @exportProperty ol.geom.Polygon.prototype.getLinearRings diff --git a/src/ol/geom/polygon.js b/src/ol/geom/polygon.js index 601cc849d4..9300613f4b 100644 --- a/src/ol/geom/polygon.js +++ b/src/ol/geom/polygon.js @@ -55,6 +55,17 @@ ol.geom.Polygon = function(coordinates, opt_layout) { goog.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry); +/** + * @inheritDoc + */ +ol.geom.Polygon.prototype.clone = function() { + var polygon = new ol.geom.Polygon(null); + polygon.setFlatCoordinates( + this.layout, this.flatCoordinates.slice(), this.ends_.slice()); + return polygon; +}; + + /** * @inheritDoc */ From d7eb4db69e07f91205e842762c8034066f9b4470 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 15:54:29 +0100 Subject: [PATCH 4/9] Add ol.geom.GeometryCollection --- src/ol/geom/geometry.js | 5 +- src/ol/geom/geometrycollection.exports | 7 + src/ol/geom/geometrycollection.js | 204 +++++++++++++++++++ test/spec/ol/geom/geometrycollection.test.js | 110 ++++++++++ 4 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 src/ol/geom/geometrycollection.exports create mode 100644 src/ol/geom/geometrycollection.js create mode 100644 test/spec/ol/geom/geometrycollection.test.js diff --git a/src/ol/geom/geometry.js b/src/ol/geom/geometry.js index 76ede57540..ca079dd89c 100644 --- a/src/ol/geom/geometry.js +++ b/src/ol/geom/geometry.js @@ -1,5 +1,3 @@ -// FIXME add GeometryCollection - goog.provide('ol.geom.Geometry'); goog.require('goog.asserts'); @@ -18,7 +16,8 @@ ol.geom.GeometryType = { POLYGON: 'Polygon', MULTI_POINT: 'MultiPoint', MULTI_LINE_STRING: 'MultiLineString', - MULTI_POLYGON: 'MultiPolygon' + MULTI_POLYGON: 'MultiPolygon', + GEOMETRY_COLLECTION: 'GeometryCollection' }; diff --git a/src/ol/geom/geometrycollection.exports b/src/ol/geom/geometrycollection.exports new file mode 100644 index 0000000000..103ce2c40f --- /dev/null +++ b/src/ol/geom/geometrycollection.exports @@ -0,0 +1,7 @@ +@exportSymbol ol.geom.GeometryCollection +@exportProperty ol.geom.GeometryCollection.prototype.clone +@exportProperty ol.geom.GeometryCollection.prototype.getExtent +@exportProperty ol.geom.GeometryCollection.prototype.getGeometries +@exportProperty ol.geom.GeometryCollection.prototype.getSimplifiedGeometry +@exportProperty ol.geom.GeometryCollection.prototype.getType +@exportProperty ol.geom.GeometryCollection.prototype.setGeometries diff --git a/src/ol/geom/geometrycollection.js b/src/ol/geom/geometrycollection.js new file mode 100644 index 0000000000..7765699b0c --- /dev/null +++ b/src/ol/geom/geometrycollection.js @@ -0,0 +1,204 @@ +goog.provide('ol.geom.GeometryCollection'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.object'); +goog.require('ol.extent'); +goog.require('ol.geom.Geometry'); + + + +/** + * @constructor + * @extends {ol.geom.Geometry} + * @param {Array.=} opt_geometries Geometries. + */ +ol.geom.GeometryCollection = function(opt_geometries) { + + goog.base(this); + + /** + * @private + * @type {Array.} + */ + this.geometries_ = goog.isDef(opt_geometries) ? opt_geometries : null; + +}; +goog.inherits(ol.geom.GeometryCollection, ol.geom.Geometry); + + +/** + * @param {Array.} geometries Geometries. + * @private + * @return {Array.} Cloned geometries. + */ +ol.geom.GeometryCollection.cloneGeometries_ = function(geometries) { + var clonedGeometries = []; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + clonedGeometries.push(geometries[i].clone()); + } + return clonedGeometries; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.clone = function() { + var geometryCollection = new ol.geom.GeometryCollection(null); + geometryCollection.setGeometries(this.geometries_); + return geometryCollection; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.closestPointXY = + function(x, y, closestPoint, minSquaredDistance) { + if (minSquaredDistance < + ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) { + return minSquaredDistance; + } + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + minSquaredDistance = geometries[i].closestPointXY( + x, y, closestPoint, minSquaredDistance); + } + return minSquaredDistance; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.containsXY = function(x, y) { + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + if (geometries[i].containsXY(x, y)) { + return true; + } + } + return false; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.getExtent = function(opt_extent) { + if (this.extentRevision != this.revision) { + var extent = ol.extent.createOrUpdateEmpty(this.extent); + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + ol.extent.extend(extent, geometries[i].getExtent()); + } + this.extent = extent; + this.extentRevision = this.revision; + } + goog.asserts.assert(goog.isDef(this.extent)); + return ol.extent.returnOrUpdate(this.extent, opt_extent); +}; + + +/** + * @return {Array.} Geometries. + */ +ol.geom.GeometryCollection.prototype.getGeometries = function() { + return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_); +}; + + +/** + * @return {Array.} Geometries. + */ +ol.geom.GeometryCollection.prototype.getGeometriesArray = function() { + return this.geometries_; +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.getSimplifiedGeometry = + function(squaredTolerance) { + if (this.simplifiedGeometryRevision != this.revision) { + goog.object.clear(this.simplifiedGeometryCache); + this.simplifiedGeometryMaxMinSquaredTolerance = 0; + this.simplifiedGeometryRevision = this.revision; + } + if (squaredTolerance < 0 || + (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 && + squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) { + return this; + } + var key = squaredTolerance.toString(); + if (this.simplifiedGeometryCache.hasOwnProperty(key)) { + return this.simplifiedGeometryCache[key]; + } else { + var simplifiedGeometries = []; + var geometries = this.geometries_; + var simplified = false; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + var geometry = geometries[i]; + var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance); + simplifiedGeometries.push(simplifiedGeometry); + if (simplifiedGeometry !== geometry) { + simplified = true; + } + } + if (simplified) { + var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null); + simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries); + this.simplifiedGeometryCache[key] = simplifiedGeometryCollection; + return simplifiedGeometryCollection; + } else { + this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance; + return this; + } + } +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.getType = function() { + return ol.geom.GeometryType.GEOMETRY_COLLECTION; +}; + + +/** + * @param {Array.} geometries Geometries. + */ +ol.geom.GeometryCollection.prototype.setGeometries = function(geometries) { + this.setGeometriesArray( + ol.geom.GeometryCollection.cloneGeometries_(geometries)); +}; + + +/** + * @param {Array.} geometries Geometries. + */ +ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) { + this.geometries_ = geometries; + this.dispatchChangeEvent(); +}; + + +/** + * @inheritDoc + */ +ol.geom.GeometryCollection.prototype.transform = function(transformFn) { + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + geometries[i].transform(transformFn); + } + this.dispatchChangeEvent(); +}; diff --git a/test/spec/ol/geom/geometrycollection.test.js b/test/spec/ol/geom/geometrycollection.test.js new file mode 100644 index 0000000000..f409fbf7dd --- /dev/null +++ b/test/spec/ol/geom/geometrycollection.test.js @@ -0,0 +1,110 @@ +goog.provide('ol.test.geom.GeometryCollection'); + + +describe('ol.geom.GeometryCollection', function() { + + var outer = [[0, 0], [0, 10], [10, 10], [10, 0], [0, 0]], + inner1 = [[1, 1], [2, 1], [2, 2], [1, 2], [1, 1]], + inner2 = [[8, 8], [9, 8], [9, 9], [8, 9], [8, 8]]; + + describe('constructor', function() { + + it('creates a geometry collection from an array of geometries', function() { + var point = new ol.geom.Point([10, 20]); + var line = new ol.geom.LineString([[10, 20], [30, 40]]); + var poly = new ol.geom.Polygon([outer, inner1, inner2]); + var multi = new ol.geom.GeometryCollection([point, line, poly]); + expect(multi).to.be.a(ol.geom.GeometryCollection); + expect(multi).to.be.a(ol.geom.Geometry); + }); + + }); + + describe('#getGeometries', function() { + + it('returns a collection of geometries', function() { + var point = new ol.geom.Point([10, 20]); + var line = new ol.geom.LineString([[10, 20], [30, 40]]); + var poly = new ol.geom.Polygon([outer, inner1, inner2]); + var multi = new ol.geom.GeometryCollection([point, line, poly]); + + var geometries = multi.getGeometries(); + expect(geometries).to.be.an(Array); + expect(geometries).to.have.length(3); + expect(geometries[0]).to.be.a(ol.geom.Point); + expect(geometries[1]).to.be.a(ol.geom.LineString); + expect(geometries[2]).to.be.a(ol.geom.Polygon); + }); + + }); + + describe('#clone()', function() { + + it('has a working clone method', function() { + var point = new ol.geom.Point([10, 20]); + var line = new ol.geom.LineString([[10, 20], [30, 40]]); + var poly = new ol.geom.Polygon([outer, inner1, inner2]); + var multi = new ol.geom.GeometryCollection([point, line, poly]); + var clone = multi.clone(); + expect(clone).to.not.be(multi); + var geometries = clone.getGeometries(); + expect(geometries[0].getCoordinates()).to.eql([10, 20]); + expect(geometries[1].getCoordinates()).to.eql([[10, 20], [30, 40]]); + expect(geometries[2].getCoordinates()).to.eql([outer, inner1, inner2]); + }); + + }); + + describe('#getExtent()', function() { + + it('returns the bounding extent', function() { + var point = new ol.geom.Point([10, 2]); + var line = new ol.geom.LineString([[1, 20], [30, 40]]); + var multi = new ol.geom.GeometryCollection([point, line]); + var extent = multi.getExtent(); + expect(extent[0]).to.be(1); + expect(extent[2]).to.be(30); + expect(extent[1]).to.be(2); + expect(extent[3]).to.be(40); + }); + + }); + + describe('#setGeometries', function() { + + var line, multi, point, poly; + beforeEach(function() { + point = new ol.geom.Point([10, 20]); + line = new ol.geom.LineString([[10, 20], [30, 40]]); + poly = new ol.geom.Polygon([outer, inner1, inner2]); + multi = new ol.geom.GeometryCollection([point, line, poly]); + }); + + it('fires a change event', function() { + var listener = sinon.spy(); + multi.on('change', listener); + point.setCoordinates([15, 25]); + expect(listener.calledOnce).to.be(false); + multi.setGeometries([point, line, poly]); + expect(listener.calledOnce).to.be(true); + }); + + it('updates the extent', function() { + expect(multi.getExtent()).to.eql([0, 0, 30, 40]); + line.setCoordinates([[10, 20], [300, 400]]); + expect(multi.getExtent()).to.eql([0, 0, 30, 40]); + multi.setGeometries([point, line, poly]); + expect(multi.getExtent()).to.eql([0, 0, 300, 400]); + }); + + }); + +}); + + +goog.require('ol.Collection'); +goog.require('ol.geom.Geometry'); +goog.require('ol.geom.GeometryCollection'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); From 4205c01414f42029bfca700ffc174fae52c53c18 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 16:43:40 +0100 Subject: [PATCH 5/9] Add ol.geom.GeometryCollection rendering --- src/ol/render/canvas/canvasimmediate.js | 21 ++++++++++++++++++- src/ol/render/canvas/canvasreplay.js | 7 +++++++ src/ol/render/irender.js | 12 +++++++++++ src/ol/render/vector.js | 27 ++++++++++++++++++++++++- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/ol/render/canvas/canvasimmediate.js b/src/ol/render/canvas/canvasimmediate.js index dcf09919e3..f3aa2228b5 100644 --- a/src/ol/render/canvas/canvasimmediate.js +++ b/src/ol/render/canvas/canvasimmediate.js @@ -220,6 +220,23 @@ ol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) { }; +/** + * @inheritDoc + */ +ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry = + function(geometryCollectionGeometry, data) { + var geometries = geometryCollectionGeometry.getGeometriesArray(); + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + var geometry = geometries[i]; + var geometryRenderer = + ol.render.canvas.Immediate.GEOMETRY_RENDERES_[geometry.getType()]; + goog.asserts.assert(goog.isDef(geometryRenderer)); + geometryRenderer.call(this, geometry, data); + } +}; + + /** * @inheritDoc */ @@ -478,5 +495,7 @@ ol.render.canvas.Immediate.GEOMETRY_RENDERES_ = { 'MultiPoint': ol.render.canvas.Immediate.prototype.drawMultiPointGeometry, 'MultiLineString': ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry, - 'MultiPolygon': ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry + 'MultiPolygon': ol.render.canvas.Immediate.prototype.drawMultiPolygonGeometry, + 'GeometryCollection': + ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry }; diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index 1aeaf5f3be..1fe7d69e92 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -329,6 +329,13 @@ ol.render.canvas.Replay.prototype.reverseInstructions_ = function() { ol.render.canvas.Replay.prototype.drawFeature = goog.abstractMethod; +/** + * @inheritDoc + */ +ol.render.canvas.Replay.prototype.drawGeometryCollectionGeometry = + goog.abstractMethod; + + /** * @inheritDoc */ diff --git a/src/ol/render/irender.js b/src/ol/render/irender.js index 07c7ffee11..bbefdd7af5 100644 --- a/src/ol/render/irender.js +++ b/src/ol/render/irender.js @@ -1,3 +1,5 @@ +// FIXME remove trailing "Geometry" in method names + goog.provide('ol.render.IRender'); @@ -17,6 +19,16 @@ ol.render.IRender.prototype.drawFeature = function(feature, style) { }; +/** + * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry + * collection. + * @param {Object} data Opaque data object. + */ +ol.render.IRender.prototype.drawGeometryCollectionGeometry = + function(geometryCollectionGeometry, data) { +}; + + /** * @param {ol.geom.Point} pointGeometry Point geometry. * @param {Object} data Opaque data object. diff --git a/src/ol/render/vector.js b/src/ol/render/vector.js index 717490f8c6..6143a6080f 100644 --- a/src/ol/render/vector.js +++ b/src/ol/render/vector.js @@ -1,6 +1,7 @@ goog.provide('ol.renderer.vector'); goog.require('goog.asserts'); +goog.require('ol.geom.GeometryCollection'); goog.require('ol.geom.LineString'); goog.require('ol.geom.MultiLineString'); goog.require('ol.geom.MultiPoint'); @@ -28,6 +29,29 @@ ol.renderer.vector.renderFeature = function( }; +/** + * @param {ol.render.IReplayGroup} replayGroup Replay group. + * @param {ol.geom.Geometry} geometry Geometry. + * @param {ol.style.Style} style Style. + * @param {Object} data Opaque data object. + * @private + */ +ol.renderer.vector.renderGeometryCollectionGeometry_ = + function(replayGroup, geometry, style, data) { + goog.asserts.assertInstanceof(geometry, ol.geom.GeometryCollection); + var geometryCollectionGeometry = /** @type {ol.geom.GeometryCollection} */ ( + geometry); + var geometries = geometryCollectionGeometry.getGeometriesArray(); + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + var geometryRenderer = + ol.renderer.vector.GEOMETRY_RENDERERS_[geometries[i].getType()]; + goog.asserts.assert(goog.isDef(geometryRenderer)); + geometryRenderer(replayGroup, geometries[i], style, data); + } +}; + + /** * @param {ol.render.IReplayGroup} replayGroup Replay group. * @param {ol.geom.Geometry} geometry Geometry. @@ -167,5 +191,6 @@ ol.renderer.vector.GEOMETRY_RENDERERS_ = { 'Polygon': ol.renderer.vector.renderPolygonGeometry_, 'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_, 'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_, - 'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_ + 'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_, + 'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_ }; From bde17b2ac83a30561e502d9e623a5943bf58780b Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 17:28:00 +0100 Subject: [PATCH 6/9] Add ol.geom.GeometryCollection support to ol.format.GeoJSON --- src/ol/format/geojsonformat.js | 46 +++++++++++++++++++---- test/spec/ol/format/geojsonformat.test.js | 20 ++++++---- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/ol/format/geojsonformat.js b/src/ol/format/geojsonformat.js index 4e4b96ca66..ae5d9c76e8 100644 --- a/src/ol/format/geojsonformat.js +++ b/src/ol/format/geojsonformat.js @@ -1,13 +1,14 @@ // FIXME coordinate order // FIXME reprojection -// FIXME GeometryCollection goog.provide('ol.format.GeoJSON'); +goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.object'); goog.require('ol.Feature'); goog.require('ol.format.JSON'); +goog.require('ol.geom.GeometryCollection'); goog.require('ol.geom.LineString'); goog.require('ol.geom.MultiLineString'); goog.require('ol.geom.MultiPoint'); @@ -41,7 +42,7 @@ goog.inherits(ol.format.GeoJSON, ol.format.JSON); /** - * @param {GeoJSONGeometry} object Object. + * @param {GeoJSONObject} object Object. * @private * @return {ol.geom.Geometry} Geometry. */ @@ -52,6 +53,19 @@ ol.format.GeoJSON.readGeometry_ = function(object) { }; +/** + * @param {GeoJSONGeometryCollection} object Object. + * @private + * @return {ol.geom.GeometryCollection} Geometry collection. + */ +ol.format.GeoJSON.readGeometryCollectionGeometry_ = function(object) { + goog.asserts.assert(object.type == 'GeometryCollection'); + var geometries = goog.array.map( + object.geometries, ol.format.GeoJSON.readGeometry_); + return new ol.geom.GeometryCollection(geometries); +}; + + /** * @param {GeoJSONGeometry} object Object. * @private @@ -121,7 +135,7 @@ ol.format.GeoJSON.readPolygonGeometry_ = function(object) { /** * @param {ol.geom.Geometry} geometry Geometry. * @private - * @return {GeoJSONGeometry} GeoJSON geometry. + * @return {GeoJSONObject} GeoJSON geometry. */ ol.format.GeoJSON.writeGeometry_ = function(geometry) { var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()]; @@ -130,6 +144,22 @@ ol.format.GeoJSON.writeGeometry_ = function(geometry) { }; +/** + * @param {ol.geom.Geometry} geometry Geometry. + * @private + * @return {GeoJSONGeometryCollection} GeoJSON geometry collection. + */ +ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function(geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.GeometryCollection); + var geometries = goog.array.map( + geometry.getGeometriesArray(), ol.format.GeoJSON.writeGeometry_); + return /** @type {GeoJSONGeometryCollection} */ ({ + 'type': 'GeometryCollection', + 'geometries': geometries + }); +}; + + /** * @param {ol.geom.Geometry} geometry Geometry. * @private @@ -219,7 +249,7 @@ ol.format.GeoJSON.writePolygonGeometry_ = function(geometry) { /** * @const * @private - * @type {Object.} + * @type {Object.} */ ol.format.GeoJSON.GEOMETRY_READERS_ = { 'Point': ol.format.GeoJSON.readPointGeometry_, @@ -227,14 +257,15 @@ ol.format.GeoJSON.GEOMETRY_READERS_ = { 'Polygon': ol.format.GeoJSON.readPolygonGeometry_, 'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_, 'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_, - 'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_ + 'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_, + 'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_ }; /** * @const * @private - * @type {Object.} + * @type {Object.} */ ol.format.GeoJSON.GEOMETRY_WRITERS_ = { 'Point': ol.format.GeoJSON.writePointGeometry_, @@ -242,7 +273,8 @@ ol.format.GeoJSON.GEOMETRY_WRITERS_ = { 'Polygon': ol.format.GeoJSON.writePolygonGeometry_, 'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_, 'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_, - 'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_ + 'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_, + 'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_ }; diff --git a/test/spec/ol/format/geojsonformat.test.js b/test/spec/ol/format/geojsonformat.test.js index 1d40411c62..a6792d834f 100644 --- a/test/spec/ol/format/geojsonformat.test.js +++ b/test/spec/ol/format/geojsonformat.test.js @@ -279,7 +279,7 @@ describe('ol.format.GeoJSON', function() { expect(rings[2]).to.be.a(ol.geom.LinearRing); }); - it.skip('parses geometry collection', function() { + it('parses geometry collection', function() { var str = JSON.stringify({ type: 'GeometryCollection', geometries: [ @@ -288,7 +288,9 @@ describe('ol.format.GeoJSON', function() { ] }); - var array = format.readGeometry(str); + var geometryCollection = format.readGeometry(str); + expect(geometryCollection).to.be.an(ol.geom.GeometryCollection); + var array = geometryCollection.getGeometries(); expect(array.length).to.be(2); expect(array[0]).to.be.a(ol.geom.Point); expect(array[1]).to.be.a(ol.geom.LineString); @@ -441,17 +443,20 @@ describe('ol.format.GeoJSON', function() { format.readGeometry(geojson).getCoordinates()); }); - it.skip('encodes geometry collection', function() { + it('encodes geometry collection', function() { var collection = new ol.geom.GeometryCollection([ new ol.geom.Point([10, 20]), new ol.geom.LineString([[30, 40], [50, 60]]) ]); var geojson = format.writeGeometry(collection); var got = format.readGeometry(geojson); - var components = collection.getComponents(); - expect(components.length).to.equal(got.length); - for (var i = 0, ii = components.length; i < ii; ++i) { - expect(components[i].getCoordinates()).to.eql(got[i].getCoordinates()); + expect(got).to.be.an(ol.geom.GeometryCollection); + var gotGeometries = got.getGeometries(); + var geometries = collection.getGeometries(); + expect(geometries.length).to.equal(gotGeometries.length); + for (var i = 0, ii = geometries.length; i < ii; ++i) { + expect(geometries[i].getCoordinates()). + to.eql(gotGeometries[i].getCoordinates()); } }); @@ -463,6 +468,7 @@ describe('ol.format.GeoJSON', function() { goog.require('ol.Feature'); goog.require('ol.extent'); goog.require('ol.format.GeoJSON'); +goog.require('ol.geom.GeometryCollection'); goog.require('ol.geom.LineString'); goog.require('ol.geom.LinearRing'); goog.require('ol.geom.Point'); From 0943bbf0701ebe050d51c46520aa91b220f33040 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 17:44:12 +0100 Subject: [PATCH 7/9] Don't use postcompose in geojson example --- examples/geojson.js | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/examples/geojson.js b/examples/geojson.js index c081dc4067..70ae39bcc9 100644 --- a/examples/geojson.js +++ b/examples/geojson.js @@ -2,8 +2,6 @@ goog.require('ol.Feature'); goog.require('ol.Map'); goog.require('ol.RendererHint'); goog.require('ol.View2D'); -goog.require('ol.geom.LineString'); -goog.require('ol.geom.Point'); goog.require('ol.layer.Tile'); goog.require('ol.layer.Vector'); goog.require('ol.shape'); @@ -131,29 +129,6 @@ var vectorLayer = new ol.layer.Vector({ source: vectorSource, styleFunction: styleFunction }); -var tmpLineFeature = new ol.Feature( - new ol.geom.LineString([[-5e6, -5e6], [5e6, -5e6]])); -var tmpPointFeature = new ol.Feature( - new ol.geom.Point([0, 3e6])); -var tmpStyle = new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'magenta', - lineCap: 'round', - width: 5 - }), - image: ol.shape.renderCircle(5, - new ol.style.Fill({ - color: 'green' - }), - new ol.style.Stroke({ - color: 'blue' - })) -}); -vectorLayer.on('postcompose', function(event) { - var render = event.getRender(); - render.drawFeature(tmpLineFeature, tmpStyle); - render.drawFeature(tmpPointFeature, tmpStyle); -}); var map = new ol.Map({ layers: [ From a03bf6d44719e0ea45f30346b2c7957e92f2b7d2 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 17:44:28 +0100 Subject: [PATCH 8/9] Add GeometryCollection to geojson example --- examples/geojson.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/examples/geojson.js b/examples/geojson.js index 70ae39bcc9..911707926a 100644 --- a/examples/geojson.js +++ b/examples/geojson.js @@ -52,6 +52,18 @@ var styles = { fill: new ol.style.Fill({ color: 'rgba(0, 0, 255, 0.1)' }) + })], + 'GeometryCollection': [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'magenta', + width: 2 + }), + fill: new ol.style.Fill({ + color: 'magenta' + }), + image: ol.shape.renderCircle(10, null, new ol.style.Stroke({ + color: 'magenta' + })) })] }; @@ -120,6 +132,26 @@ var vectorSource = new ol.source.GeoJSON( [[[1e6, 6e6], [1e6, 8e6], [3e6, 8e6], [3e6, 6e6]]] ] } + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'GeometryCollection', + 'geometries': [ + { + 'type': 'LineString', + 'coordinates': [[-5e6, -5e6], [0e6, -5e6]] + }, + { + 'type': 'Point', + 'coordinates': [4e6, -5e6] + }, + { + 'type': 'Polygon', + 'coordinates': [[[1e6, -6e6], [2e6, -4e6], [3e6, -6e6]]] + } + ] + } } ] } From dd3c39bb12b6eff7af069197e8488157eab8ff5d Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 11 Dec 2013 22:05:33 +0100 Subject: [PATCH 9/9] Add deep clone test --- test/spec/ol/geom/geometrycollection.test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/spec/ol/geom/geometrycollection.test.js b/test/spec/ol/geom/geometrycollection.test.js index f409fbf7dd..1e86c640f5 100644 --- a/test/spec/ol/geom/geometrycollection.test.js +++ b/test/spec/ol/geom/geometrycollection.test.js @@ -53,6 +53,20 @@ describe('ol.geom.GeometryCollection', function() { expect(geometries[2].getCoordinates()).to.eql([outer, inner1, inner2]); }); + it('does a deep clone', function() { + var point = new ol.geom.Point([30, 40]); + var originalGeometries = [point]; + var multi = new ol.geom.GeometryCollection(originalGeometries); + var clone = multi.clone(); + var clonedGeometries = multi.getGeometries(); + expect(clonedGeometries).not.to.be(originalGeometries); + expect(clonedGeometries).to.have.length(originalGeometries.length); + expect(clonedGeometries).to.have.length(1); + expect(clonedGeometries[0]).not.to.be(originalGeometries[0]); + expect(clonedGeometries[0].getCoordinates()). + to.eql(originalGeometries[0].getCoordinates()); + }); + }); describe('#getExtent()', function() {