|
@@ -1,291 +0,0 @@
|
|
|
-// /*
|
|
|
-// * Copyright (c) 2017 MolQL contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
-// *
|
|
|
-// * @author David Sehnal <david.sehnal@gmail.com>
|
|
|
-// * @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
|
-// */
|
|
|
-
|
|
|
-// // TODO: 3d grid lookup (use single cell for small sets), make bounding sphere part of the structure
|
|
|
-// // TODO: assign radius to points?
|
|
|
-
|
|
|
-// /**
|
|
|
-// * A "masked" 3D spatial lookup structure.
|
|
|
-// */
|
|
|
-
|
|
|
-// import Mask from 'mol-util/mask'
|
|
|
-
|
|
|
-// export type FindFunc = (x: number, y: number, z: number, radius: number) => Result
|
|
|
-// export type CheckFunc = (x: number, y: number, z: number, radius: number) => boolean
|
|
|
-
|
|
|
-// export interface Result {
|
|
|
-// readonly count: number,
|
|
|
-// readonly indices: number[],
|
|
|
-// readonly squaredDistances: number[]
|
|
|
-// }
|
|
|
-
|
|
|
-// export interface Positions { x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number> }
|
|
|
-
|
|
|
-// interface GridLookup { find: (mask: Mask) => FindFunc, check: (mask: Mask) => CheckFunc }
|
|
|
-
|
|
|
-// function GridLookup(positions: Positions): GridLookup {
|
|
|
-// const tree = build(createInputData(positions));
|
|
|
-// return {
|
|
|
-// find(mask) {
|
|
|
-// const ctx = QueryContext.create(tree, mask, false);
|
|
|
-// return function (x: number, y: number, z: number, radius: number) {
|
|
|
-// QueryContext.update(ctx, x, y, z, radius);
|
|
|
-// nearest(ctx);
|
|
|
-// return ctx.buffer;
|
|
|
-// }
|
|
|
-// },
|
|
|
-// check(mask) {
|
|
|
-// const ctx = QueryContext.create(tree, mask, true);
|
|
|
-// return function (x: number, y: number, z: number, radius: number) {
|
|
|
-// QueryContext.update(ctx, x, y, z, radius);
|
|
|
-// return nearest(ctx);
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// interface InputData {
|
|
|
-// bounds: Box3D,
|
|
|
-// count: number,
|
|
|
-// positions: Positions
|
|
|
-// }
|
|
|
-
|
|
|
-// interface Box3D {
|
|
|
-// min: number[],
|
|
|
-// max: number[]
|
|
|
-// }
|
|
|
-
|
|
|
-// namespace Box3D {
|
|
|
-// export function createInfinite(): Box3D {
|
|
|
-// return {
|
|
|
-// min: [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE],
|
|
|
-// max: [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE]
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// /**
|
|
|
-// * Query context. Handles the actual querying.
|
|
|
-// */
|
|
|
-// interface QueryContext<T> {
|
|
|
-// structure: T,
|
|
|
-// pivot: number[],
|
|
|
-// radius: number,
|
|
|
-// radiusSq: number,
|
|
|
-// buffer: QueryContext.Buffer,
|
|
|
-// mask: Mask,
|
|
|
-// isCheck: boolean
|
|
|
-// }
|
|
|
-
|
|
|
-// namespace QueryContext {
|
|
|
-// export interface Buffer extends Result {
|
|
|
-// count: number;
|
|
|
-// indices: any[];
|
|
|
-// squaredDistances: number[];
|
|
|
-// }
|
|
|
-
|
|
|
-// export function add<T>(ctx: QueryContext<T>, distSq: number, index: number) {
|
|
|
-// const buffer = ctx.buffer;
|
|
|
-// buffer.squaredDistances[buffer.count] = distSq;
|
|
|
-// buffer.indices[buffer.count++] = index;
|
|
|
-// }
|
|
|
-
|
|
|
-// function resetBuffer(buffer: Buffer) { buffer.count = 0; }
|
|
|
-
|
|
|
-// function createBuffer(): Buffer {
|
|
|
-// return {
|
|
|
-// indices: [],
|
|
|
-// count: 0,
|
|
|
-// squaredDistances: []
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// /**
|
|
|
-// * Query the tree and store the result to this.buffer. Overwrites the old result.
|
|
|
-// */
|
|
|
-// export function update<T>(ctx: QueryContext<T>, x: number, y: number, z: number, radius: number) {
|
|
|
-// ctx.pivot[0] = x;
|
|
|
-// ctx.pivot[1] = y;
|
|
|
-// ctx.pivot[2] = z;
|
|
|
-// ctx.radius = radius;
|
|
|
-// ctx.radiusSq = radius * radius;
|
|
|
-// resetBuffer(ctx.buffer);
|
|
|
-// }
|
|
|
-
|
|
|
-// export function create<T>(structure: T, mask: Mask, isCheck: boolean): QueryContext<T> {
|
|
|
-// return {
|
|
|
-// structure,
|
|
|
-// buffer: createBuffer(),
|
|
|
-// pivot: [0.1, 0.1, 0.1],
|
|
|
-// radius: 1.1,
|
|
|
-// radiusSq: 1.1 * 1.1,
|
|
|
-// mask,
|
|
|
-// isCheck
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// function createInputData(positions: { x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number> }): InputData {
|
|
|
-// const { x, y, z } = positions;
|
|
|
-// const bounds = Box3D.createInfinite();
|
|
|
-// const count = x.length;
|
|
|
-// const { min, max } = bounds;
|
|
|
-
|
|
|
-// for (let i = 0; i < count; i++) {
|
|
|
-// min[0] = Math.min(x[i], min[0]);
|
|
|
-// min[1] = Math.min(y[i], min[1]);
|
|
|
-// min[2] = Math.min(z[i], min[2]);
|
|
|
-// max[0] = Math.max(x[i], max[0]);
|
|
|
-// max[1] = Math.max(y[i], max[1]);
|
|
|
-// max[2] = Math.max(z[i], max[2]);
|
|
|
-// }
|
|
|
-
|
|
|
-// return { positions, bounds, count };
|
|
|
-// }
|
|
|
-
|
|
|
-// /**
|
|
|
-// * Adapted from https://github.com/arose/ngl
|
|
|
-// * MIT License Copyright (C) 2014+ Alexander Rose
|
|
|
-// */
|
|
|
-
|
|
|
-// interface SpatialHash {
|
|
|
-// size: number[],
|
|
|
-// min: number[],
|
|
|
-// grid: Uint32Array,
|
|
|
-// bucketOffset: Uint32Array,
|
|
|
-// bucketCounts: Int32Array,
|
|
|
-// bucketArray: Int32Array,
|
|
|
-// positions: Positions
|
|
|
-// }
|
|
|
-
|
|
|
-// interface State {
|
|
|
-// size: number[],
|
|
|
-// positions: Positions,
|
|
|
-// bounds: Box3D,
|
|
|
-// count: number
|
|
|
-// }
|
|
|
-
|
|
|
-// const enum Constants { Exp = 3 }
|
|
|
-
|
|
|
-// function nearest(ctx: QueryContext<SpatialHash>): boolean {
|
|
|
-// const { min: [minX, minY, minZ], size: [sX, sY, sZ], bucketOffset, bucketCounts, bucketArray, grid, positions: { x: px, y: py, z: pz } } = ctx.structure;
|
|
|
-// const { radius: r, radiusSq: rSq, pivot: [x, y, z], isCheck, mask } = ctx;
|
|
|
-
|
|
|
-// const loX = Math.max(0, (x - r - minX) >> Constants.Exp);
|
|
|
-// const loY = Math.max(0, (y - r - minY) >> Constants.Exp);
|
|
|
-// const loZ = Math.max(0, (z - r - minZ) >> Constants.Exp);
|
|
|
-
|
|
|
-// const hiX = Math.min(sX, (x + r - minX) >> Constants.Exp);
|
|
|
-// const hiY = Math.min(sY, (y + r - minY) >> Constants.Exp);
|
|
|
-// const hiZ = Math.min(sZ, (z + r - minZ) >> Constants.Exp);
|
|
|
-
|
|
|
-// for (let ix = loX; ix <= hiX; ix++) {
|
|
|
-// for (let iy = loY; iy <= hiY; iy++) {
|
|
|
-// for (let iz = loZ; iz <= hiZ; iz++) {
|
|
|
-// const bucketIdx = grid[(((ix * sY) + iy) * sZ) + iz];
|
|
|
-
|
|
|
-// if (bucketIdx > 0) {
|
|
|
-// const k = bucketIdx - 1;
|
|
|
-// const offset = bucketOffset[k];
|
|
|
-// const count = bucketCounts[k];
|
|
|
-// const end = offset + count;
|
|
|
-
|
|
|
-// for (let i = offset; i < end; i++) {
|
|
|
-// const idx = bucketArray[i];
|
|
|
-// if (!mask.has(idx)) continue;
|
|
|
-
|
|
|
-// const dx = px[idx] - x;
|
|
|
-// const dy = py[idx] - y;
|
|
|
-// const dz = pz[idx] - z;
|
|
|
-// const distSq = dx * dx + dy * dy + dz * dz;
|
|
|
-
|
|
|
-// if (distSq <= rSq) {
|
|
|
-// if (isCheck) return true;
|
|
|
-// QueryContext.add(ctx, distSq, idx)
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-// return ctx.buffer.count > 0;
|
|
|
-// }
|
|
|
-
|
|
|
-// function _build(state: State): SpatialHash {
|
|
|
-// const { bounds, size: [sX, sY, sZ], positions: { x: px, y: py, z: pz }, count } = state;
|
|
|
-// const n = sX * sY * sZ;
|
|
|
-// const { min: [minX, minY, minZ] } = bounds;
|
|
|
-
|
|
|
-// let bucketCount = 0;
|
|
|
-// const grid = new Uint32Array(n);
|
|
|
-// const bucketIndex = new Int32Array(count);
|
|
|
-// for (let i = 0; i < count; i++) {
|
|
|
-// const x = (px[i] - minX) >> Constants.Exp;
|
|
|
-// const y = (py[i] - minY) >> Constants.Exp;
|
|
|
-// const z = (pz[i] - minZ) >> Constants.Exp;
|
|
|
-// const idx = (((x * sY) + y) * sZ) + z;
|
|
|
-// if ((grid[idx] += 1) === 1) {
|
|
|
-// bucketCount += 1
|
|
|
-// }
|
|
|
-// bucketIndex[i] = idx;
|
|
|
-// }
|
|
|
-
|
|
|
-// const bucketCounts = new Int32Array(bucketCount);
|
|
|
-// for (let i = 0, j = 0; i < n; i++) {
|
|
|
-// const c = grid[i];
|
|
|
-// if (c > 0) {
|
|
|
-// grid[i] = j + 1;
|
|
|
-// bucketCounts[j] = c;
|
|
|
-// j += 1;
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// const bucketOffset = new Uint32Array(count);
|
|
|
-// for (let i = 1; i < count; ++i) {
|
|
|
-// bucketOffset[i] += bucketOffset[i - 1] + bucketCounts[i - 1];
|
|
|
-// }
|
|
|
-
|
|
|
-// const bucketFill = new Int32Array(bucketCount);
|
|
|
-// const bucketArray = new Int32Array(count);
|
|
|
-// for (let i = 0; i < count; i++) {
|
|
|
-// const bucketIdx = grid[bucketIndex[i]]
|
|
|
-// if (bucketIdx > 0) {
|
|
|
-// const k = bucketIdx - 1;
|
|
|
-// bucketArray[bucketOffset[k] + bucketFill[k]] = i;
|
|
|
-// bucketFill[k] += 1;
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// return {
|
|
|
-// size: state.size,
|
|
|
-// bucketArray,
|
|
|
-// bucketCounts,
|
|
|
-// bucketOffset,
|
|
|
-// grid,
|
|
|
-// min: state.bounds.min,
|
|
|
-// positions: state.positions
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// function build({ positions, bounds, count }: InputData): SpatialHash {
|
|
|
-// const size = [
|
|
|
-// ((bounds.max[0] - bounds.min[0]) >> Constants.Exp) + 1,
|
|
|
-// ((bounds.max[1] - bounds.min[1]) >> Constants.Exp) + 1,
|
|
|
-// ((bounds.max[2] - bounds.min[2]) >> Constants.Exp) + 1
|
|
|
-// ];
|
|
|
-
|
|
|
-// const state: State = {
|
|
|
-// size,
|
|
|
-// positions,
|
|
|
-// bounds,
|
|
|
-// count
|
|
|
-// }
|
|
|
-
|
|
|
-// return _build(state);
|
|
|
-// }
|
|
|
-
|
|
|
-// export default GridLookup;
|