@bokeh/bokehjs
Version:
Interactive, novel data visualization
141 lines • 4.36 kB
JavaScript
import FlatBush from "flatbush";
import { Indices } from "../types";
import { empty } from "./bbox";
function upperBound(value, arr) {
let i = 0;
let j = arr.length - 1;
while (i < j) {
const m = (i + j) >> 1;
if (arr[m] > value) {
j = m;
}
else {
i = m + 1;
}
}
return arr[i];
}
class _FlatBush extends FlatBush {
static __name__ = "_FlatBush";
search_apply(minX, minY, maxX, maxY, nodeFunction) {
if (this._pos !== this._boxes.length) {
throw new Error("Data not yet indexed - call index.finish().");
}
let nodeIndex = this._boxes.length - 4;
const queue = [];
while (nodeIndex !== undefined) {
// find the end index of the node
const end = Math.min(nodeIndex + this.nodeSize * 4, upperBound(nodeIndex, this._levelBounds));
// search through child nodes
for (let pos = nodeIndex; pos < end; pos += 4) {
const nodeMinX = this._boxes[pos + 0];
const nodeMinY = this._boxes[pos + 1];
const nodeMaxX = this._boxes[pos + 2];
const nodeMaxY = this._boxes[pos + 3];
if (maxX < nodeMinX || maxY < nodeMinY || minX > nodeMaxX || minY > nodeMaxY) {
continue;
}
const index = this._indices[pos >> 2] | 0;
if (nodeIndex < this.numItems * 4) {
nodeFunction(index, { x0: nodeMinX, y0: nodeMinY, x1: nodeMaxX, y1: nodeMaxY });
}
else {
queue.push(index); // node; add it to the search queue
}
}
nodeIndex = queue.pop();
}
}
search_indices(minX, minY, maxX, maxY) {
const result = new Indices(this.numItems);
this.search_apply(minX, minY, maxX, maxY, (index) => result.set(index));
return result;
}
search_bounds(minX, minY, maxX, maxY) {
const result = empty();
this.search_apply(minX, minY, maxX, maxY, (_index, node) => {
if (node.x0 >= minX && node.x0 < result.x0) {
result.x0 = node.x0;
}
if (node.x1 <= maxX && node.x1 > result.x1) {
result.x1 = node.x1;
}
if (node.y0 >= minY && node.y0 < result.y0) {
result.y0 = node.y0;
}
if (node.y1 <= maxY && node.y1 > result.y1) {
result.y1 = node.y1;
}
});
return result;
}
}
export class SpatialIndex {
static __name__ = "SpatialIndex";
index = null;
constructor(size) {
if (size > 0) {
this.index = new _FlatBush(size);
}
}
add_rect(x0, y0, x1, y1) {
if (!isFinite(x0 + y0 + x1 + y1)) {
this.add_empty();
}
else {
this.index?.add(x0, y0, x1, y1);
}
}
add_point(x, y) {
if (!isFinite(x + y)) {
this.add_empty();
}
else {
this.index?.add(x, y, x, y);
}
}
add_empty() {
this.index?.add(Infinity, Infinity, -Infinity, -Infinity);
}
finish() {
this.index?.finish();
}
_normalize(rect) {
let { x0, y0, x1, y1 } = rect;
if ((x0 > x1) && isFinite(x0 + x1)) {
[x0, x1] = [x1, x0];
}
if ((y0 > y1) && isFinite(y0 + y1)) {
[y0, y1] = [y1, y0];
}
return { x0, y0, x1, y1 };
}
get bbox() {
if (this.index == null) {
return empty();
}
else {
const { minX, minY, maxX, maxY } = this.index;
return { x0: minX, y0: minY, x1: maxX, y1: maxY };
}
}
indices(rect) {
if (this.index == null) {
return new Indices(0);
}
else {
const { x0, y0, x1, y1 } = this._normalize(rect);
return this.index.search_indices(x0, y0, x1, y1);
}
}
bounds(rect) {
if (this.index == null) {
return empty();
}
else {
const { x0, y0, x1, y1 } = this._normalize(rect);
return this.index.search_bounds(x0, y0, x1, y1);
}
}
}
//# sourceMappingURL=spatial.js.map