first commit

This commit is contained in:
Vladimir Agafonkin 2018-02-27 10:56:03 +02:00
commit fc8d6cfbbd
2 changed files with 206 additions and 0 deletions

31
debug.js Normal file
View File

@ -0,0 +1,31 @@
var flatbush = require('./');
var N = 1000000;
var hilbertOrder = 16;
console.time('gen data');
var coords = [];
var spaceSize = 100;
var boxSize = 1;
for (var i = 0; i < N; i++) {
var x = Math.random() * (spaceSize - boxSize);
var y = Math.random() * (spaceSize - boxSize);
var x2 = x + Math.random() * boxSize;
var y2 = y + Math.random() * boxSize;
coords.push(x, y, x2, y2);
}
console.timeEnd('gen data');
console.time('flatbush');
var index = flatbush(N);
for (var i = 0; i < coords.length; i += 4) {
index.add(
coords[i],
coords[i + 1],
coords[i + 2],
coords[i + 3]);
}
index.finish();
// console.log(index.data);
console.timeEnd('flatbush');

175
index.js Normal file
View File

@ -0,0 +1,175 @@
'use strict';
module.exports = flatbush;
function flatbush(numItems, nodeSize, hilbertOrder) {
return new Flatbush(numItems, nodeSize, hilbertOrder);
}
function Flatbush(numItems, nodeSize, hilbertOrder) {
this._numItems = numItems;
this._nodeSize = nodeSize || 16;
this._hilbertOrder = hilbertOrder || 16;
// calculate the total number of nodes in the R-tree to allocate space for
var n = numItems;
var numNodes = n;
do {
n = Math.ceil(n / this._nodeSize);
numNodes += n;
} while (n !== 1);
this.data = new Float64Array(numNodes * 5);
this._hilbertValues = new Uint32Array(numItems);
this._numAdded = 0;
this._pos = 0;
this._minX = Infinity;
this._minY = Infinity;
this._maxX = -Infinity;
this._maxY = -Infinity;
}
Flatbush.prototype = {
add: function (minX, minY, maxX, maxY) {
this.data[this._pos++] = this._numAdded++;
this.data[this._pos++] = minX;
this.data[this._pos++] = minY;
this.data[this._pos++] = maxX;
this.data[this._pos++] = maxY;
if (minX < this._minX) this._minX = minX;
if (minY < this._minY) this._minY = minY;
if (maxX > this._maxX) this._maxX = maxX;
if (maxY > this._maxY) this._maxY = maxY;
},
finish: function () {
if (this._numAdded !== this._numItems) {
throw new Error('The number of items added does not match the number in the constructor.')
}
var width = this._maxX - this._minX;
var height = this._maxY - this._minY;
var hilbertMax = Math.pow(2, this._hilbertOrder) - 1;
for (var i = 0; i < this._numItems; i++) {
var x = Math.floor(hilbertMax * this.data[5 * i + 1] / width);
var y = Math.floor(hilbertMax * this.data[5 * i + 2] / height);
this._hilbertValues[i] = hilbert(this._hilbertOrder, x, y);
}
// sort boxes by hilbert value
sort(this._hilbertValues, this.data, 0, this._numItems - 1);
// TODO generate remaining nodes
}
};
function sort(values, boxes, left, right) {
if (left >= right) return;
var i = left + 1;
var j = right;
swap(values, boxes, (left + right) >> 1, i);
if (values[left] > values[right]) swap(values, boxes, left, right);
if (values[i] > values[right]) swap(values, boxes, i, right);
if (values[left] > values[i]) swap(values, boxes, left, i);
var temp = values[i];
while (true) {
do i++; while (values[i] < temp);
do j--; while (values[j] > temp);
if (j < i) break;
swap(values, boxes, i, j);
}
values[left + 1] = values[j];
values[j] = temp;
if (right - i + 1 >= j - left) {
sort(values, boxes, i, right);
sort(values, boxes, left, j - 1);
} else {
sort(values, boxes, left, j - 1);
sort(values, boxes, i, right);
}
}
function swap(values, boxes, i, j) {
var temp = values[i];
values[i] = values[j];
values[j] = temp;
var k = 5 * i;
var m = 5 * j;
var a = boxes[k];
var b = boxes[k + 1];
var c = boxes[k + 2];
var d = boxes[k + 3];
var e = boxes[k + 4];
boxes[k] = boxes[m];
boxes[k + 1] = boxes[m + 1];
boxes[k + 2] = boxes[m + 2];
boxes[k + 3] = boxes[m + 3];
boxes[k + 4] = boxes[m + 4];
boxes[m] = a;
boxes[m + 1] = b;
boxes[m + 2] = c;
boxes[m + 3] = d;
boxes[m + 4] = e;
}
// Fast Hilbert curve algorithm by http://threadlocalmutex.com/
// Ported from C++ https://github.com/rawrunprotected/hilbert_curves (public domain)
function hilbert(n, x, y) {
x = x << (16 - n);
y = y << (16 - n);
var a = x ^ y;
var b = 0xFFFF ^ a;
var c = 0xFFFF ^ (x | y);
var d = x & (y ^ 0xFFFF);
var A = a | (b >> 1);
var B = (a >> 1) ^ a;
var C = ((c >> 1) ^ (b & (d >> 1))) ^ c;
var D = ((a & (c >> 1)) ^ (d >> 1)) ^ d;
a = A; b = B; c = C; d = D;
A = ((a & (a >> 2)) ^ (b & (b >> 2)));
B = ((a & (b >> 2)) ^ (b & ((a ^ b) >> 2)));
C ^= ((a & (c >> 2)) ^ (b & (d >> 2)));
D ^= ((b & (c >> 2)) ^ ((a ^ b) & (d >> 2)));
a = A; b = B; c = C; d = D;
A = ((a & (a >> 4)) ^ (b & (b >> 4)));
B = ((a & (b >> 4)) ^ (b & ((a ^ b) >> 4)));
C ^= ((a & (c >> 4)) ^ (b & (d >> 4)));
D ^= ((b & (c >> 4)) ^ ((a ^ b) & (d >> 4)));
a = A; b = B; c = C; d = D;
C ^= ((a & (c >> 8)) ^ (b & (d >> 8)));
D ^= ((b & (c >> 8)) ^ ((a ^ b) & (d >> 8)));
a = C ^ (C >> 1);
b = D ^ (D >> 1);
var i0 = x ^ y;
var i1 = b | (0xFFFF ^ (i0 | a));
i0 = (i0 | (i0 << 8)) & 0x00FF00FF;
i0 = (i0 | (i0 << 4)) & 0x0F0F0F0F;
i0 = (i0 | (i0 << 2)) & 0x33333333;
i0 = (i0 | (i0 << 1)) & 0x55555555;
i1 = (i1 | (i1 << 8)) & 0x00FF00FF;
i1 = (i1 | (i1 << 4)) & 0x0F0F0F0F;
i1 = (i1 | (i1 << 2)) & 0x33333333;
i1 = (i1 | (i1 << 1)) & 0x55555555;
return (((i1 << 1) | i0) >> (32 - 2 * n)) >>> 0;
}