Metadata-Version: 2.4
Name: pycanopy
Version: 0.1.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Requires-Dist: pyarrow>=12.0
Requires-Dist: numpy>=1.24
License-File: LICENSE
Summary: Geospatial query engine with dynamic index selection
Keywords: geospatial,spatial-index,rtree,kdtree,knn,geoarrow
Author-email: Pranav Walimbe <pranav1077@gmail.com>
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Issues, https://github.com/pranavwalimbe/pycanopy/issues
Project-URL: Repository, https://github.com/pranavwalimbe/pycanopy

# PyCanopy

A geospatial query engine with automatic index selection. Written in Rust, callable from Python.

PyCanopy accepts point datasets and answers spatial queries (k-nearest neighbours, bounding-box range, point-in-polygon) by automatically choosing the fastest index — R-tree, KD-tree, uniform grid, or brute force — based on dataset size, geometry kind, and spatial distribution.

## Installation

```bash
pip install pycanopy
```

> **Note:** Pre-built wheels are provided for Linux, macOS, and Windows. No Rust toolchain required.

## Quick start

```python
import numpy as np
from pycanopy import Engine

coords = np.random.uniform(0, 100, size=(50_000, 2))
engine = Engine(coords)

indices = engine.knn(x=42.0, y=37.0, k=10)
indices = engine.range_query(min_x=10.0, min_y=10.0, max_x=50.0, max_y=50.0)
indices = engine.contains(x=25.0, y=25.0)
```

## Accepted input formats

| Format | Example |
|---|---|
| numpy `(N, 2)` array | `np.array([[x, y], ...])` |
| GeoArrow PyArrow array | `pa.StructArray` or `FixedSizeList<2>` |
| geopandas `GeoSeries` | `gdf.geometry` |
| list of shapely Points | `[Point(x, y), ...]` |
| list of `(x, y)` tuples | `[(x, y), ...]` |
| Separate coordinate lists | `Engine.from_coords(xs, ys)` |

## How index selection works

| Condition | Index chosen |
|---|---|
| N < 500 or selectivity > 50% | Brute force |
| Points + kNN | KD-tree |
| Points + uniform + range | Uniform grid |
| Points + clustered + range | KD-tree |
| Polygons or mixed geometries | R-tree |

## Development setup

Requires Python >= 3.9 and a Rust toolchain ([rustup.rs](https://rustup.rs)).

```bash
git clone https://github.com/pranavwalimbe/pycanopy
cd pycanopy
uv sync --group dev
uv run maturin develop
uv run pytest
cargo test
```

## License

MIT

