helimap
Version:
map heliware
221 lines (200 loc) • 5.38 kB
JavaScript
/**
* @module ol/structs/RBush
*/
import RBush_ from 'rbush';
import {createOrUpdate, equals} from '../extent.js';
import {getUid} from '../util.js';
import {isEmpty} from '../obj.js';
/**
* @typedef {Object} Entry
* @property {number} minX MinX.
* @property {number} minY MinY.
* @property {number} maxX MaxX.
* @property {number} maxY MaxY.
* @property {Object} [value] Value.
*/
/**
* @classdesc
* Wrapper around the RBush by Vladimir Agafonkin.
* See https://github.com/mourner/rbush.
*
* @template T
*/
class RBush {
/**
* @param {number} [maxEntries] Max entries.
*/
constructor(maxEntries) {
/**
* @private
*/
this.rbush_ = new RBush_(maxEntries);
/**
* A mapping between the objects added to this rbush wrapper
* and the objects that are actually added to the internal rbush.
* @private
* @type {Object<string, Entry>}
*/
this.items_ = {};
}
/**
* Insert a value into the RBush.
* @param {import("../extent.js").Extent} extent Extent.
* @param {T} value Value.
*/
insert(extent, value) {
/** @type {Entry} */
const item = {
minX: extent[0],
minY: extent[1],
maxX: extent[2],
maxY: extent[3],
value: value,
};
this.rbush_.insert(item);
this.items_[getUid(value)] = item;
}
/**
* Bulk-insert values into the RBush.
* @param {Array<import("../extent.js").Extent>} extents Extents.
* @param {Array<T>} values Values.
*/
load(extents, values) {
const items = new Array(values.length);
for (let i = 0, l = values.length; i < l; i++) {
const extent = extents[i];
const value = values[i];
/** @type {Entry} */
const item = {
minX: extent[0],
minY: extent[1],
maxX: extent[2],
maxY: extent[3],
value: value,
};
items[i] = item;
this.items_[getUid(value)] = item;
}
this.rbush_.load(items);
}
/**
* Remove a value from the RBush.
* @param {T} value Value.
* @return {boolean} Removed.
*/
remove(value) {
const uid = getUid(value);
// get the object in which the value was wrapped when adding to the
// internal rbush. then use that object to do the removal.
const item = this.items_[uid];
delete this.items_[uid];
return this.rbush_.remove(item) !== null;
}
/**
* Update the extent of a value in the RBush.
* @param {import("../extent.js").Extent} extent Extent.
* @param {T} value Value.
*/
update(extent, value) {
const item = this.items_[getUid(value)];
const bbox = [item.minX, item.minY, item.maxX, item.maxY];
if (!equals(bbox, extent)) {
this.remove(value);
this.insert(extent, value);
}
}
/**
* Return all values in the RBush.
* @return {Array<T>} All.
*/
getAll() {
const items = this.rbush_.all();
return items.map(function (item) {
return item.value;
});
}
/**
* Return all values in the given extent.
* @param {import("../extent.js").Extent} extent Extent.
* @return {Array<T>} All in extent.
*/
getInExtent(extent) {
/** @type {Entry} */
const bbox = {
minX: extent[0],
minY: extent[1],
maxX: extent[2],
maxY: extent[3],
};
const items = this.rbush_.search(bbox);
return items.map(function (item) {
return item.value;
});
}
/**
* 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(T): *} callback Callback.
* @return {*} Callback return value.
*/
forEach(callback) {
return this.forEach_(this.getAll(), callback);
}
/**
* Calls a callback function with each value in the provided extent.
* @param {import("../extent.js").Extent} extent Extent.
* @param {function(T): *} callback Callback.
* @return {*} Callback return value.
*/
forEachInExtent(extent, callback) {
return this.forEach_(this.getInExtent(extent), callback);
}
/**
* @param {Array<T>} values Values.
* @param {function(T): *} callback Callback.
* @private
* @return {*} Callback return value.
*/
forEach_(values, callback) {
let result;
for (let i = 0, l = values.length; i < l; i++) {
result = callback(values[i]);
if (result) {
return result;
}
}
return result;
}
/**
* @return {boolean} Is empty.
*/
isEmpty() {
return isEmpty(this.items_);
}
/**
* Remove all values from the RBush.
*/
clear() {
this.rbush_.clear();
this.items_ = {};
}
/**
* @param {import("../extent.js").Extent} [extent] Extent.
* @return {import("../extent.js").Extent} Extent.
*/
getExtent(extent) {
const data = this.rbush_.toJSON();
return createOrUpdate(data.minX, data.minY, data.maxX, data.maxY, extent);
}
/**
* @param {RBush} rbush R-Tree.
*/
concat(rbush) {
this.rbush_.load(rbush.rbush_.all());
for (const i in rbush.items_) {
this.items_[i] = rbush.items_[i];
}
}
}
export default RBush;