Skip to content

Commit

Permalink
feat(distance): add Radial neighborhood impls
Browse files Browse the repository at this point in the history
- add radial/2/3/N() factories
  • Loading branch information
postspectacular committed May 28, 2023
1 parent 26a171d commit 667fed9
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 1 deletion.
3 changes: 3 additions & 0 deletions packages/distance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@
"./nearest": {
"default": "./nearest.js"
},
"./radial": {
"default": "./radial.js"
},
"./squared": {
"default": "./squared.js"
}
Expand Down
1 change: 1 addition & 0 deletions packages/distance/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from "./haversine.js";
export * from "./knearest.js";
export * from "./manhattan.js";
export * from "./nearest.js";
export * from "./radial.js";
export * from "./squared.js";
3 changes: 2 additions & 1 deletion packages/distance/src/knearest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { DIST_SQ, DIST_SQ1, DIST_SQ2, DIST_SQ3 } from "./squared.js";
/**
* A {@link INeighborhood} implementation for K-nearest neighbor queries around
* a given target location, initial query radius and {@link IDistance} metric to
* determine proximity.
* determine proximity. See {@link Radial} for an unbounded and unsorted
* version.
*
* @remarks
* The K-nearest neighbors will be accumulated via an internal
Expand Down
138 changes: 138 additions & 0 deletions packages/distance/src/radial.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import type { IDeref } from "@thi.ng/api";
import { clamp0 } from "@thi.ng/math/interval";
import type { ReadonlyVec } from "@thi.ng/vectors";
import type { IDistance, INeighborhood, Neighbor } from "./api.js";
import { DIST_SQ, DIST_SQ1, DIST_SQ2, DIST_SQ3 } from "./squared.js";

/**
* A {@link INeighborhood} implementation for radial neighbor queries around a
* given target location, initial query radius and {@link IDistance} metric to
* determine proximity. Unbounded and unsorted version of {@link KNearest}.
*
* @remarks
* Qualifying neighbors will be accumulated in order of processing via an
* internal array and can be obtained via {@link Radial.deref} or
* {@link Radial.values}.
*
* @typeParam D - spatial position for distance metric
* @typeParam T - indexed value
*/
export class Radial<D, T>
implements INeighborhood<D, T>, IDeref<Neighbor<T>[]>
{
protected _r!: number;
protected _items!: [number, T][];

constructor(
public readonly dist: IDistance<D>,
public target: D,
public radius = Infinity
) {
this.setRadius(radius);
}

/**
* Clears current results.
*/
reset() {
this._items = [];
return this;
}

/**
* Resets search/reference position and clears current results.
*
* @param target
*/
setTarget(target: D) {
this.target = target;
this.reset();
}

/**
* Resets search/query radius and clears current results.
*
* @param r
*/
setRadius(r: number) {
this.radius = clamp0(r);
this._r = this.dist.to(this.radius);
this.reset();
}

/**
* Returns an array of current neighbor result tuples (each `[dist, val]`).
*
* @remarks
* Use {@link Radial.values} to obtain result values **without** their
* distance metrics.
*/
deref() {
return this._items;
}

/**
* Similar to {@link Radial.deref}, but returns array of result values **without**
* their distance metrics.
*/
values() {
return this._items.map((x) => x[1]);
}

includesDistance(d: number, eucledian = true) {
return (eucledian ? this.dist.to(d) : d) <= this._r;
}

consider(pos: D, val: T) {
const d = this.dist.metric(this.target, pos);
if (d <= this._r) {
this._items.push([d, val]);
}
return d;
}
}

/**
* Defines a {@link Radial} instance for arbitrary length vector positions
* and, by default, using an infinite region radius and {@link DIST_SQ} distance
* metric.
*
* @param p -
* @param r -
* @param dist -
*/
export const radial = <T>(p: ReadonlyVec, r?: number, dist = DIST_SQ) =>
new Radial<ReadonlyVec, T>(dist, p, r);

/**
* Defines a {@link Radial} instance for 2D vector positions and, by default,
* using an infinite region radius and {@link DIST_SQ2} distance metric.
*
* @param p -
* @param r -
* @param dist -
*/
export const radial2 = <T>(p: ReadonlyVec, r?: number, dist = DIST_SQ2) =>
new Radial<ReadonlyVec, T>(dist, p, r);

/**
* Defines a {@link Radial} instance for 3D vector positions, by default,
* using an infinite region radius and {@link DIST_SQ3} distance metric.
*
* @param p -
* @param r -
* @param dist -
*/
export const radial3 = <T>(p: ReadonlyVec, r?: number, dist = DIST_SQ3) =>
new Radial<ReadonlyVec, T>(dist, p, r);

/**
* Defines a {@link Radial} instance for numeric positions and, by default,
* using an infinite region radius and {@link DIST_SQ1} distance metric.
*
* @param p -
* @param r -
* @param dist -
*/
export const radialN = <T>(p: number, r?: number, dist = DIST_SQ1) =>
new Radial<number, T>(dist, p, r);

0 comments on commit 667fed9

Please sign in to comment.