# kdtree

A generic K-D tree for spatial nearest-neighbour and range queries. A single `KDTree<T>` class accepts `getPoint` and `distanceTo` as constructor options — no subclassing required.

---

## `KDTree<T>`

```typescript
new KDTree<T>(options: {
    k: number;                                          // dimensionality
    data: T[];                                          // items to index
    getPoint: (item: T) => number[];                   // position of an item
    distanceTo: (item: T, query: number[]) => number;  // distance from item to a query point
    qualifier?: (item: T, splitDim: number, splitVal: number) => [boolean, boolean];
    // Optional: controls which subtree each item goes to during build.
    // Defaults to left < splitVal, right >= splitVal.
})
```

### Methods

#### `kNN(k, query): Array<[index, distance]>`

Find the `k` nearest items to `query`. Returns an array of `[dataIndex, distance]` pairs sorted by distance ascending (nearest first).

#### `rangeQuery(bounds): number[]`

Find all data indices whose point lies within `bounds = [minCoords, maxCoords]`.

---

## Factory Functions

### `kdPointTree(points: Point[]): KDTree<Point>`

Build a K-D tree over an array of `n`-dimensional points.

```typescript
const tree = kdPointTree([[0,0],[1,0],[0,1],[1,1]]);
tree.kNN(1, [0.1, 0.1]);     // [[0, 0.14...]]  (index 0, distance ~0.14)
tree.rangeQuery([[0,0],[1,0.5]]); // [0, 1]
```

### `kdSegmentTree(segments: Segment[]): KDTree<Segment>`

Build a K-D tree over an array of line segments. Distance is measured from the query point to the **nearest point on the segment**.

```typescript
const tree = kdSegmentTree([
    [[0,0],[2,0]],
    [[0,5],[2,5]],
]);
tree.kNN(1, [1, 1]);  // [[0, 1]]  (index 0, distance 1 — segment along y=0)
```

---

## Example — custom data type

```typescript
interface City { name: string; lng: number; lat: number; }

const cities: City[] = [
    { name: "A", lng: 0, lat: 0 },
    { name: "B", lng: 1, lat: 1 },
];

const tree = new KDTree<City>({
    k: 2,
    data: cities,
    getPoint: (c) => [c.lng, c.lat],
    distanceTo: (c, q) => Math.hypot(c.lng - q[0], c.lat - q[1]),
});

tree.kNN(1, [0.4, 0.4]);  // nearest city to [0.4, 0.4]
```
