sphereql-index 0.3.0

Spatial indexing and queries for sphereQL
Documentation
# sphereql-index

Spatial indexing for the [sphereQL](https://github.com/bkahan/sphereQL) project.

Partitions S² into a two-tier index — radial shells × angular sectors
— so spatial queries scan only the buckets that overlap the query
region instead of the whole point set.

## What's here

- **`SectorIndex<T>`** — angular sector grid (`theta_divisions ×
  phi_divisions`) for fast in-region lookups (`Cone`, `Cap`, `Band`,
  `Wedge`, …) defined in `sphereql-core`.
- **`ShellIndex<T>`** — radial shell partitioning for r-range
  filtering. Composes with `SectorIndex` via `SpatialIndex`.
- **`SpatialIndex<T>`** — composite of shell + sector. Built through
  `SpatialIndexBuilder` (chained config: shell boundaries, theta /
  phi divisions, then `.build()`).
- **`CachedIndex<T>`** — wraps `SpatialIndex` with an LRU cache
  (IndexMap-backed, O(1) touch and evict) over recent query keys,
  invalidated by a generation counter on mutation. `CachedIndexBuilder`
  exposes `.cache_capacity(n)`.
- **k-NN** — uses precomputed unit Cartesian vectors and `1 − dot`
  as a cosine proxy instead of full Vincenty per pair, so the inner
  loop is 3 muls + 2 adds per item.

The `SpatialItem` trait is the integration point: implement it on your
record type to plug into any of the indexes above.

## Example

```rust
use sphereql_core::SphericalPoint;
use sphereql_index::{SpatialIndex, SpatialItem};

#[derive(Debug, Clone)]
struct Star { id: u64, pos: SphericalPoint }

impl SpatialItem for Star {
    type Id = u64;
    fn id(&self) -> &u64 { &self.id }
    fn position(&self) -> &SphericalPoint { &self.pos }
}

let mut idx = SpatialIndex::<Star>::builder()
    .uniform_shells(3, 10.0)
    .theta_divisions(8)
    .phi_divisions(4)
    .build();

idx.insert(Star { id: 1, pos: SphericalPoint::new_unchecked(1.0, 0.5, 0.8) });
idx.insert(Star { id: 2, pos: SphericalPoint::new_unchecked(1.0, 3.0, 2.0) });

let hits = idx.nearest(&SphericalPoint::new_unchecked(1.0, 0.6, 0.9), 1);
assert_eq!(*hits[0].item.id(), 1);
```

## Versioning

Part of the sphereQL workspace, currently `0.3.0`; API may change
before 1.0. `IndexError` is `#[non_exhaustive]`. Builder types are
`#[must_use]` — forgetting `.build()` warns at the use site.

## Documentation

See the workspace
[architecture.md](https://github.com/bkahan/sphereQL/blob/main/docs/architecture.md)
and
[performance.md](https://github.com/bkahan/sphereQL/blob/main/docs/performance.md).