diff --git a/build.py b/build.py
index 80441a6121..ed7b7a4b14 100755
--- a/build.py
+++ b/build.py
@@ -270,6 +270,7 @@ def examples_star_json(name, match):
"exports": [],
"src": [
"src/**/*.js",
+ "build/ol.ext/*.js",
"examples/%(id)s.js" % match.groupdict()],
"compile": {
"js": [
diff --git a/config/examples-all.json b/config/examples-all.json
index b3983b9673..f5b300e3ca 100644
--- a/config/examples-all.json
+++ b/config/examples-all.json
@@ -2,6 +2,7 @@
"exports": [],
"src": [
"src/**/*.js",
+ "build/ol.ext/*.js",
"build/examples/all.js"
],
"compile": {
diff --git a/package.json b/package.json
index 93174fe4c4..33c143b78f 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
],
"homepage": "http://openlayers.org/",
"scripts": {
- "install": "node tasks/parse-examples.js",
+ "install": "node tasks/install.js",
"postinstall": "closure-util update",
"start": "node tasks/serve.js",
"test": "node tasks/test.js"
@@ -30,6 +30,7 @@
"htmlparser2": "3.7.3",
"jsdoc": "3.3.0-alpha9",
"nomnom": "1.8.0",
+ "rbush": "1.3.4",
"temp": "0.8.1",
"walk": "2.3.4"
},
@@ -43,5 +44,8 @@
"phantomjs": "1.9.10",
"proj4": "2.3.3",
"sinon": "1.10.3"
- }
+ },
+ "ext": [
+ "rbush"
+ ]
}
diff --git a/src/ol/structs/rbush.js b/src/ol/structs/rbush.js
index 61ffd549bb..e7092bc516 100644
--- a/src/ol/structs/rbush.js
+++ b/src/ol/structs/rbush.js
@@ -1,199 +1,17 @@
-// Based on rbush https://github.com/mourner/rbush
-// Copyright (c) 2013 Vladimir Agafonkin
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
// FIXME bulk inserts
-// FIXME is level argument needed to insert_?
goog.provide('ol.structs.RBush');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.object');
-goog.require('ol.extent');
-
-
-
-/**
- * @constructor
- * @param {ol.Extent} extent Extent.
- * @param {number} height Height.
- * @param {Array.
>} children Children.
- * @param {?T} value Value.
- * @struct
- * @template T
- */
-ol.structs.RBushNode = function(extent, height, children, value) {
-
- if (height === 0) {
- goog.asserts.assert(goog.isNull(children));
- goog.asserts.assert(!goog.isNull(value));
- } else {
- goog.asserts.assert(!goog.isNull(children));
- goog.asserts.assert(goog.isNull(value));
- }
-
- /**
- * @type {ol.Extent}
- */
- this.extent = extent;
-
- /**
- * @type {number}
- */
- this.height = height;
-
- /**
- * @type {Array.>}
- */
- this.children = children;
-
- /**
- * @type {?T}
- */
- this.value = value;
-
-};
-
-
-/**
- * @param {ol.structs.RBushNode.} node1 Node 1.
- * @param {ol.structs.RBushNode.} node2 Node 2.
- * @return {number} Compare minimum X.
- * @template T
- */
-ol.structs.RBushNode.compareMinX = function(node1, node2) {
- return node1.extent[0] - node2.extent[0];
-};
-
-
-/**
- * @param {ol.structs.RBushNode.} node1 Node 1.
- * @param {ol.structs.RBushNode.} node2 Node 2.
- * @return {number} Compare minimum Y.
- * @template T
- */
-ol.structs.RBushNode.compareMinY = function(node1, node2) {
- return node1.extent[1] - node2.extent[1];
-};
-
-
-/**
- * @param {number} maxEntries Max entries.
- */
-ol.structs.RBushNode.prototype.assertValid = function(maxEntries) {
- if (this.height === 0) {
- goog.asserts.assert(goog.isNull(this.children));
- goog.asserts.assert(!goog.isNull(this.value));
- } else {
- goog.asserts.assert(!goog.isNull(this.children));
- goog.asserts.assert(goog.isNull(this.value));
- goog.asserts.assert(this.children.length <= maxEntries);
- var i, ii;
- for (i = 0, ii = this.children.length; i < ii; ++i) {
- var child = this.children[i];
- goog.asserts.assert(ol.extent.containsExtent(this.extent, child.extent));
- child.assertValid(maxEntries);
- }
- }
-};
-
-
-/**
- * @param {number} start Start.
- * @param {number} stop Stop.
- * @param {ol.Extent=} opt_extent Extent.
- * @return {ol.Extent} Extent.
- */
-ol.structs.RBushNode.prototype.getChildrenExtent =
- function(start, stop, opt_extent) {
- goog.asserts.assert(!this.isLeaf());
- var children = this.children;
- var extent = ol.extent.createOrUpdateEmpty(opt_extent);
- var i;
- for (i = start; i < stop; ++i) {
- ol.extent.extend(extent, children[i].extent);
- }
- return extent;
-};
-
-
-/**
- * @param {ol.Extent} extent Extent.
- * @param {T} value Value.
- * @param {Array.>} path Path.
- * @return {boolean} Removed.
- */
-ol.structs.RBushNode.prototype.remove = function(extent, value, path) {
- var children = this.children;
- var ii = children.length;
- var child, i;
- if (this.height == 1) {
- for (i = 0; i < ii; ++i) {
- child = children[i];
- if (child.value === value) {
- goog.array.removeAt(children, i);
- return true;
- }
- }
- } else {
- goog.asserts.assert(this.height > 1);
- for (i = 0; i < ii; ++i) {
- child = children[i];
- if (ol.extent.containsExtent(child.extent, extent)) {
- path.push(child);
- if (child.remove(extent, value, path)) {
- return true;
- }
- path.pop();
- }
- }
- }
- return false;
-};
-
-
-/**
- * FIXME empty description for jsdoc
- */
-ol.structs.RBushNode.prototype.updateExtent = function() {
- goog.asserts.assert(!this.isLeaf());
- var extent = ol.extent.createOrUpdateEmpty(this.extent);
- var children = this.children;
- var i, ii;
- for (i = 0, ii = children.length; i < ii; ++i) {
- ol.extent.extend(extent, children[i].extent);
- }
-};
-
-
-/**
- * @return {boolean} Is leaf.
- */
-ol.structs.RBushNode.prototype.isLeaf = function() {
- return goog.isNull(this.children);
-};
+goog.require('ol.ext.rbush');
/**
+ * Wrapper around the RBush by Vladimir Agafonkin.
+ *
* @constructor
* @param {number=} opt_maxEntries Max entries.
* @see https://github.com/mourner/rbush
@@ -204,28 +22,16 @@ ol.structs.RBush = function(opt_maxEntries) {
/**
* @private
- * @type {number}
*/
- this.maxEntries_ =
- Math.max(4, goog.isDef(opt_maxEntries) ? opt_maxEntries : 9);
+ this.rbush_ = ol.ext.rbush(opt_maxEntries);
/**
+ * A mapping between the objects added to this rbush wrapper
+ * and the objects that are actually added to the internal rbush.
* @private
- * @type {number}
+ * @type {Object.}
*/
- this.minEntries_ = Math.max(2, Math.ceil(0.4 * this.maxEntries_));
-
- /**
- * @private
- * @type {ol.structs.RBushNode.}
- */
- this.root_ = new ol.structs.RBushNode(ol.extent.createEmpty(), 1, [], null);
-
- /**
- * @private
- * @type {Object.}
- */
- this.valueExtent_ = {};
+ this.items_ = {};
if (goog.DEBUG) {
/**
@@ -234,167 +40,89 @@ ol.structs.RBush = function(opt_maxEntries) {
*/
this.readers_ = 0;
}
-
-};
-
-
-/**
- * @param {ol.structs.RBushNode.} node Node.
- * @param {function(ol.structs.RBushNode., ol.structs.RBushNode.): number}
- * compare Compare.
- * @private
- * @return {number} All distance margin.
- */
-ol.structs.RBush.prototype.allDistMargin_ = function(node, compare) {
- var children = node.children;
- var m = this.minEntries_;
- var M = children.length;
- var i;
- goog.array.sort(children, compare);
- var leftExtent = node.getChildrenExtent(0, m);
- var rightExtent = node.getChildrenExtent(M - m, M);
- var margin =
- ol.extent.getMargin(leftExtent) + ol.extent.getMargin(rightExtent);
- for (i = m; i < M - m; ++i) {
- ol.extent.extend(leftExtent, children[i].extent);
- margin += ol.extent.getMargin(leftExtent);
- }
- for (i = M - m - 1; i >= m; --i) {
- ol.extent.extend(rightExtent, children[i].extent);
- margin += ol.extent.getMargin(rightExtent);
- }
- return margin;
-};
-
-
-/**
- * FIXME empty description for jsdoc
- */
-ol.structs.RBush.prototype.assertValid = function() {
- this.root_.assertValid(this.maxEntries_);
-};
-
-
-/**
- * @param {ol.structs.RBushNode.} node Node.
- * @private
- */
-ol.structs.RBush.prototype.chooseSplitAxis_ = function(node) {
- var xMargin = this.allDistMargin_(node, ol.structs.RBushNode.compareMinX);
- var yMargin = this.allDistMargin_(node, ol.structs.RBushNode.compareMinY);
- if (xMargin < yMargin) {
- goog.array.sort(node.children, ol.structs.RBushNode.compareMinX);
- }
-};
-
-
-/**
- * @param {ol.structs.RBushNode.} node Node.
- * @private
- * @return {number} Split index.
- */
-ol.structs.RBush.prototype.chooseSplitIndex_ = function(node) {
- var children = node.children;
- var m = this.minEntries_;
- var M = children.length;
- var minOverlap = Infinity;
- var minArea = Infinity;
- var extent1 = ol.extent.createEmpty();
- var extent2 = ol.extent.createEmpty();
- var index = 0;
- var i;
- for (i = m; i <= M - m; ++i) {
- extent1 = node.getChildrenExtent(0, i, extent1);
- extent2 = node.getChildrenExtent(i, M, extent2);
- var overlap = ol.extent.getIntersectionArea(extent1, extent2);
- var area = ol.extent.getArea(extent1) + ol.extent.getArea(extent2);
- if (overlap < minOverlap) {
- minOverlap = overlap;
- minArea = Math.min(area, minArea);
- index = i;
- } else if (overlap == minOverlap && area < minArea) {
- minArea = area;
- index = i;
- }
- }
- return index;
};
/**
+ * Insert a value into the RBush.
* @param {ol.Extent} extent Extent.
- * @param {ol.structs.RBushNode.} node Node.
- * @param {number} level Level.
- * @param {Array.>} path Path.
- * @private
- * @return {ol.structs.RBushNode.} Node.
+ * @param {T} value Value.
*/
-ol.structs.RBush.prototype.chooseSubtree_ =
- function(extent, node, level, path) {
- while (!node.isLeaf() && path.length - 1 != level) {
- var minArea = Infinity;
- var minEnlargement = Infinity;
- var children = node.children;
- var bestChild = null;
- var i, ii;
- for (i = 0, ii = children.length; i < ii; ++i) {
- var child = children[i];
- var area = ol.extent.getArea(child.extent);
- var enlargement = ol.extent.getEnlargedArea(child.extent, extent) - area;
- if (enlargement < minEnlargement) {
- minEnlargement = enlargement;
- minArea = Math.min(area, minArea);
- bestChild = child;
- } else if (enlargement == minEnlargement && area < minArea) {
- minArea = area;
- bestChild = child;
- }
- }
- goog.asserts.assert(!goog.isNull(bestChild));
- node = bestChild;
- path.push(node);
+ol.structs.RBush.prototype.insert = function(extent, value) {
+ if (goog.DEBUG && this.readers_) {
+ throw new Error('Can not insert value while reading');
}
- return node;
+ var item = [
+ extent[0],
+ extent[1],
+ extent[2],
+ extent[3],
+ value
+ ];
+ this.rbush_.insert(item);
+ // remember the object that was added to the internal rbush
+ goog.object.add(this.items_, goog.getUid(value).toString(), item);
};
/**
- * FIXME empty description for jsdoc
+ * Remove a value from the RBush.
+ * @param {T} value Value.
+ * @return {boolean} Removed.
*/
-ol.structs.RBush.prototype.clear = function() {
- var node = this.root_;
- node.extent = ol.extent.createOrUpdateEmpty(this.root_.extent);
- node.height = 1;
- node.children.length = 0;
- node.value = null;
- goog.object.clear(this.valueExtent_);
-};
-
-
-/**
- * @param {Array.>} path Path.
- * @private
- */
-ol.structs.RBush.prototype.condense_ = function(path) {
- var i;
- for (i = path.length - 1; i >= 0; --i) {
- var node = path[i];
- if (node.children.length === 0) {
- if (i > 0) {
- goog.array.remove(path[i - 1].children, node);
- } else {
- this.clear();
- }
- } else {
- node.updateExtent();
- }
+ol.structs.RBush.prototype.remove = function(value) {
+ if (goog.DEBUG && this.readers_) {
+ throw new Error('Can not remove value while reading');
}
+ var uid = goog.getUid(value).toString();
+ goog.asserts.assert(goog.object.containsKey(this.items_, uid));
+
+ // get the object in which the value was wrapped when adding to the
+ // internal rbush. then use that object to do the removal.
+ var item = goog.object.get(this.items_, uid);
+ goog.object.remove(this.items_, uid);
+ return this.rbush_.remove(item) !== null;
};
/**
- * Calls a callback function with each node in the tree. Inside the callback,
- * no tree modifications (insert, update, remove) can be made.
+ * Update the extent of a value in the RBush.
+ * @param {ol.Extent} extent Extent.
+ * @param {T} value Value.
+ */
+ol.structs.RBush.prototype.update = function(extent, value) {
+ this.remove(value);
+ this.insert(extent, value);
+};
+
+
+/**
+ * Return all values in the RBush.
+ * @return {Array.} All.
+ */
+ol.structs.RBush.prototype.getAll = function() {
+ var items = this.rbush_.all();
+ return goog.array.map(items, function(item) {
+ return item[4];
+ });
+};
+
+
+/**
+ * Return all values in the given extent.
+ * @param {ol.Extent} extent Extent.
+ * @return {Array.} All in extent.
+ */
+ol.structs.RBush.prototype.getInExtent = function(extent) {
+ var items = this.rbush_.search(extent);
+ return goog.array.map(items, function(item) {
+ return item[4];
+ });
+};
+
+
+/**
+ * Calls a callback function with each value in the tree.
* If the callback returns a truthy value, this value is returned without
* checking the rest of the tree.
* @param {function(this: S, T): *} callback Callback.
@@ -406,49 +134,18 @@ ol.structs.RBush.prototype.forEach = function(callback, opt_this) {
if (goog.DEBUG) {
++this.readers_;
try {
- return this.forEach_(this.root_, callback, opt_this);
+ return this.forEach_(this.getAll(), callback, opt_this);
} finally {
--this.readers_;
}
} else {
- return this.forEach_(this.root_, callback, opt_this);
+ return this.forEach_(this.getAll(), callback, opt_this);
}
};
/**
- * @param {ol.structs.RBushNode.} node Node.
- * @param {function(this: S, T): *} callback Callback.
- * @param {S=} opt_this The object to use as `this` in `callback`.
- * @private
- * @return {*} Callback return value.
- * @template S
- */
-ol.structs.RBush.prototype.forEach_ = function(node, callback, opt_this) {
- goog.asserts.assert(!node.isLeaf());
- /** @type {Array.>} */
- var toVisit = [node];
- var children, i, ii, result;
- while (toVisit.length > 0) {
- node = toVisit.pop();
- children = node.children;
- if (node.height == 1) {
- for (i = 0, ii = children.length; i < ii; ++i) {
- result = callback.call(opt_this, children[i].value);
- if (result) {
- return result;
- }
- }
- } else {
- toVisit.push.apply(toVisit, children);
- }
- }
-};
-
-
-/**
- * Calls a callback function with each node in the provided extent. Inside the
- * callback, no tree modifications (insert, update, remove) can be made.
+ * Calls a callback function with each value in the provided extent.
* @param {ol.Extent} extent Extent.
* @param {function(this: S, T): *} callback Callback.
* @param {S=} opt_this The object to use as `this` in `callback`.
@@ -460,81 +157,50 @@ ol.structs.RBush.prototype.forEachInExtent =
if (goog.DEBUG) {
++this.readers_;
try {
- return this.forEachInExtent_(extent, callback, opt_this);
+ return this.forEach_(this.getInExtent(extent), callback, opt_this);
} finally {
--this.readers_;
}
} else {
- return this.forEachInExtent_(extent, callback, opt_this);
+ return this.forEach_(this.getInExtent(extent), callback, opt_this);
}
};
/**
- * @param {ol.Extent} extent Extent.
+ * @param {Array.} values Values.
* @param {function(this: S, T): *} callback Callback.
* @param {S=} opt_this The object to use as `this` in `callback`.
* @private
* @return {*} Callback return value.
* @template S
*/
-ol.structs.RBush.prototype.forEachInExtent_ =
- function(extent, callback, opt_this) {
- /** @type {Array.>} */
- var toVisit = [this.root_];
+ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) {
var result;
- while (toVisit.length > 0) {
- var node = toVisit.pop();
- if (ol.extent.intersects(extent, node.extent)) {
- if (node.isLeaf()) {
- result = callback.call(opt_this, node.value);
- if (result) {
- return result;
- }
- } else if (ol.extent.containsExtent(extent, node.extent)) {
- result = this.forEach_(node, callback, opt_this);
- if (result) {
- return result;
- }
- } else {
- toVisit.push.apply(toVisit, node.children);
- }
+ for (var i = 0, l = values.length; i < l; i++) {
+ result = callback.call(opt_this, values[i]);
+ if (result) {
+ return result;
}
}
- return undefined;
+ return result;
};
/**
- * @return {Array.} All.
+ * @return {boolean} Is empty.
*/
-ol.structs.RBush.prototype.getAll = function() {
- var values = [];
- this.forEach(
- /**
- * @param {T} value Value.
- */
- function(value) {
- values.push(value);
- });
- return values;
+ol.structs.RBush.prototype.isEmpty = function() {
+ return goog.object.isEmpty(this.items_);
};
/**
- * @param {ol.Extent} extent Extent.
- * @return {Array.} All in extent.
+ * Remove all values from the RBush.
*/
-ol.structs.RBush.prototype.getInExtent = function(extent) {
- var values = [];
- this.forEachInExtent(extent,
- /**
- * @param {T} value Value.
- */
- function(value) {
- values.push(value);
- });
- return values;
+ol.structs.RBush.prototype.clear = function() {
+ this.rbush_.clear();
+ goog.object.clear(this.items_);
};
@@ -543,160 +209,6 @@ ol.structs.RBush.prototype.getInExtent = function(extent) {
* @return {ol.Extent} Extent.
*/
ol.structs.RBush.prototype.getExtent = function(opt_extent) {
- return ol.extent.returnOrUpdate(this.root_.extent, opt_extent);
-};
-
-
-/**
- * @param {T} value Value.
- * @private
- * @return {string} Key.
- */
-ol.structs.RBush.prototype.getKey_ = function(value) {
- goog.asserts.assert(goog.isObject(value));
- return goog.getUid(value).toString();
-};
-
-
-/**
- * @param {ol.Extent} extent Extent.
- * @param {T} value Value.
- */
-ol.structs.RBush.prototype.insert = function(extent, value) {
- if (goog.DEBUG && this.readers_) {
- throw new Error('cannot insert value while reading');
- }
- var key = this.getKey_(value);
- goog.asserts.assert(!this.valueExtent_.hasOwnProperty(key));
- this.insert_(extent, value, this.root_.height - 1);
- this.valueExtent_[key] = ol.extent.clone(extent);
-};
-
-
-/**
- * @param {ol.Extent} extent Extent.
- * @param {T} value Value.
- * @param {number} level Level.
- * @private
- * @return {ol.structs.RBushNode.} Node.
- */
-ol.structs.RBush.prototype.insert_ = function(extent, value, level) {
- /** @type {Array.>} */
- var path = [this.root_];
- var node = this.chooseSubtree_(extent, this.root_, level, path);
- node.children.push(new ol.structs.RBushNode(extent, 0, null, value));
- ol.extent.extend(node.extent, extent);
- var i;
- for (i = path.length - 1; i >= 0; --i) {
- if (path[i].children.length > this.maxEntries_) {
- this.split_(path, i);
- } else {
- break;
- }
- }
- for (; i >= 0; --i) {
- ol.extent.extend(path[i].extent, extent);
- }
- return node;
-};
-
-
-/**
- * @return {boolean} Is empty.
- */
-ol.structs.RBush.prototype.isEmpty = function() {
- return this.root_.children.length === 0;
-};
-
-
-/**
- * @param {T} value Value.
- * @return {boolean} Removed.
- */
-ol.structs.RBush.prototype.remove = function(value) {
- if (goog.DEBUG && this.readers_) {
- throw new Error('cannot remove value while reading');
- }
- var key = this.getKey_(value);
- goog.asserts.assert(this.valueExtent_.hasOwnProperty(key));
- var extent = this.valueExtent_[key];
- delete this.valueExtent_[key];
- return this.remove_(extent, value);
-};
-
-
-/**
- * @param {ol.Extent} extent Extent.
- * @param {T} value Value.
- * @private
- * @return {boolean} Removed.
- */
-ol.structs.RBush.prototype.remove_ = function(extent, value) {
- var root = this.root_;
- var path = [root];
- var removed = root.remove(extent, value, path);
- if (removed) {
- this.condense_(path);
- } else {
- goog.asserts.assert(path.length == 1);
- goog.asserts.assert(path[0] === root);
- }
- return removed;
-};
-
-
-/**
- * @param {Array.>} path Path.
- * @param {number} level Level.
- * @private
- */
-ol.structs.RBush.prototype.split_ = function(path, level) {
- var node = path[level];
- this.chooseSplitAxis_(node);
- var splitIndex = this.chooseSplitIndex_(node);
- // FIXME too few arguments to splice here
- var newChildren = node.children.splice(splitIndex);
- var newNode = new ol.structs.RBushNode(
- ol.extent.createEmpty(), node.height, newChildren, null);
- node.updateExtent();
- newNode.updateExtent();
- if (level) {
- path[level - 1].children.push(newNode);
- } else {
- this.splitRoot_(node, newNode);
- }
-};
-
-
-/**
- * @param {ol.structs.RBushNode.} node1 Node 1.
- * @param {ol.structs.RBushNode.} node2 Node 2.
- * @private
- */
-ol.structs.RBush.prototype.splitRoot_ = function(node1, node2) {
- goog.asserts.assert(node1 === this.root_);
- var height = node1.height + 1;
- var extent = ol.extent.extend(node1.extent.slice(), node2.extent);
- var children = [node1, node2];
- this.root_ = new ol.structs.RBushNode(extent, height, children, null);
-};
-
-
-/**
- * @param {ol.Extent} extent Extent.
- * @param {T} value Value.
- */
-ol.structs.RBush.prototype.update = function(extent, value) {
- var key = this.getKey_(value);
- var currentExtent = this.valueExtent_[key];
- goog.asserts.assert(goog.isDef(currentExtent));
- if (!ol.extent.equals(currentExtent, extent)) {
- if (goog.DEBUG && this.readers_) {
- throw new Error('cannot update extent while reading');
- }
- var removed = this.remove_(currentExtent, value);
- goog.asserts.assert(removed);
- this.insert_(extent, value, this.root_.height - 1);
- this.valueExtent_[key] = ol.extent.clone(extent, currentExtent);
- }
+ // FIXME add getExtent() to rbush
+ return this.rbush_.data.bbox;
};
diff --git a/tasks/build-ext.js b/tasks/build-ext.js
new file mode 100644
index 0000000000..d7b4ae9f2e
--- /dev/null
+++ b/tasks/build-ext.js
@@ -0,0 +1,97 @@
+var fs = require('fs');
+var path = require('path');
+
+var async = require('async');
+var fse = require('fs-extra');
+
+var pkg = require('../package.json');
+
+var root = path.join(__dirname, '..');
+var buildDir = path.join(root, 'build', 'ol.ext');
+
+
+/**
+ * Get external module metadata.
+ * @return {Array.