UNPKG

@thi.ng/distance

Version:

N-dimensional distance metrics & K-nearest neighborhoods for point queries

101 lines (100 loc) 2.68 kB
import { assert } from "@thi.ng/errors/assert"; import { Heap } from "@thi.ng/heaps/heap"; import { clamp0 } from "@thi.ng/math/interval"; import { DIST_SQ, DIST_SQ1, DIST_SQ2, DIST_SQ3 } from "./squared.js"; class KNearest { constructor(dist, target, k, radius = Infinity, sorted = false) { this.dist = dist; this.target = target; this.k = k; this.radius = radius; this.sorted = sorted; this.radius = clamp0(radius); this.setK(k); } _currR; _heap = new Heap(null, { compare: (a, b) => b[0] - a[0] }); reset() { this._currR = this.dist.to(this.radius); this._heap.clear(); return this; } /** * Resets search/reference position. * * @param target */ setTarget(target) { this.target = target; } /** * Resets max. search/query radius and clears current results. * * @param r */ setRadius(r) { this.radius = clamp0(r); this.reset(); } /** * Resets `k-nearest` limit and clears current results. * * @param k */ setK(k) { assert(k > 0, `invalid k (must be > 0)`); this.k = k; this.reset(); } /** * Returns an array of current nearest neighbor result tuples (each `[dist, * val]`). The array will contain at most `k` items and if the `sorted` ctor * arg was true, will be sorted by distance. * * @remarks * Use {@link KNearest.values} to obtain result values **without** their distance * metrics. */ deref() { return this.sorted ? this._heap.max() : this._heap.values; } /** * Similar to {@link KNearest.deref}, but returns array of result values **without** * their distance metrics. */ values() { return this.deref().map((x) => x[1]); } includesDistance(d, eucledian = true) { return (eucledian ? this.dist.to(d) : d) <= this._currR; } includesPosition(pos) { return this.dist.metric(this.target, pos) < this._currR; } consider(pos, val) { const d = this.dist.metric(this.target, pos); if (d <= this._currR) { const heap = this._heap; if (heap.length === this.k) { heap.pushPop([d, val]); this._currR = heap.peek()[0]; } else { heap.push([d, val]); } } return d; } } const knearest = (p, k, r, dist = DIST_SQ, sorted) => new KNearest(dist, p, k, r, sorted); const knearest2 = (p, k, r, dist = DIST_SQ2, sorted) => new KNearest(dist, p, k, r, sorted); const knearest3 = (p, k, r, dist = DIST_SQ3, sorted) => new KNearest(dist, p, k, r, sorted); const knearestN = (p, k, r, dist = DIST_SQ1, sorted) => new KNearest(dist, p, k, r, sorted); export { KNearest, knearest, knearest2, knearest3, knearestN };