mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-08-26 17:31:37 +00:00
* MVUM Layer 0: spatial index foundation Additive only — no routing logic, no response-format, no Valhalla changes. - mvum.py: add MVUMSpatialIndex. Loads mvum_roads + mvum_trails from navi.db (read-only), decodes the pure-WKB shape blobs with shapely, builds a shapely.strtree.STRtree, and keeps a parallel list of full feature records (all columns minus the blob, plus the parsed geometry) with a by_id lookup. Exposes query_bbox(min_lat,min_lon,max_lat,max_lon) and query_buffered_line(coords, tolerance_m) returning candidate records (coarse bbox + buffer; full parallelism filter is a TODO for PR-B). Reports road_count, trail_count, bbox, build_time_seconds, memory_estimate_mb (RSS delta). - app.py: build the index once per process (singleton) at service init; stored on app.config[MVUM_SPATIAL_INDEX]. Failure is logged and degrades to None. - admin.py: GET /api/admin/mvum-spatial/info (Authentik-gated, read-only) returning the counts/bbox/build-time/memory stats. - tests/test_mvum_spatial.py: index loads, query_bbox returns Boise-area features, query_buffered_line returns a feature, admin endpoint returns counts. Diagnostic before coding (read-only): roads_with_shape=150568/null=68, trails_with_shape=21995/null=6746 (green), shape blobs are pure WKB MultiLineString. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Fix lat-aware buffer + count WKB parse failures - query_buffered_line: replace the static _DEG_PER_M with _buffer_degrees_for_meters(), which scales longitude degrees by cos(lat) and uses the larger lat/lon equivalent; buffer at the polyline avg latitude. Early-return [] for empty coords. - _load_table: count WKB parse failures and logger.warning once per table when > 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Matt <mj@k7zvx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
49 lines
1.8 KiB
Python
49 lines
1.8 KiB
Python
"""MVUM spatial index foundation (Layer 0) tests.
|
|
|
|
Exercises MVUMSpatialIndex against the real navi.db on this host (read-only) and the
|
|
admin-info endpoint. Pure spatial lookup — no routing or response-format coverage.
|
|
"""
|
|
import pytest
|
|
|
|
from services.navi_offroute.mvum import MVUMSpatialIndex
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def index():
|
|
return MVUMSpatialIndex()
|
|
|
|
|
|
def test_index_loads_without_error(index):
|
|
assert index.road_count > 0
|
|
assert index.trail_count > 0
|
|
assert len(index.by_id) == index.road_count + index.trail_count
|
|
assert len(index.bbox) == 4
|
|
|
|
|
|
def test_query_bbox_returns_features(index):
|
|
# Generous Boise National Forest area bbox.
|
|
feats = index.query_bbox(43.8, -116.3, 44.4, -115.5)
|
|
assert len(feats) > 0
|
|
assert all("geometry" in f and "feature_id" in f for f in feats)
|
|
|
|
|
|
def test_query_buffered_line_returns_features(index):
|
|
# Take a point on an actual indexed feature and query a small buffer around it.
|
|
sample = next(iter(index.by_id.values()))
|
|
pt = sample["geometry"].representative_point()
|
|
feats = index.query_buffered_line([(pt.y, pt.x)], tolerance_m=50)
|
|
assert len(feats) >= 1
|
|
|
|
|
|
def test_admin_info_endpoint_returns_counts(index, monkeypatch):
|
|
import services.navi_offroute.app as app_mod
|
|
# Reuse the already-built fixture index instead of rebuilding in create_app.
|
|
monkeypatch.setattr(app_mod, "MVUMSpatialIndex", lambda *a, **k: index)
|
|
client = app_mod.create_app().test_client()
|
|
resp = client.get("/api/admin/mvum-spatial/info",
|
|
headers={"X-Authentik-Username": "matt"})
|
|
assert resp.status_code == 200
|
|
d = resp.get_json()
|
|
assert d["road_count"] > 0 and d["trail_count"] > 0
|
|
assert len(d["bbox"]) == 4
|
|
assert "build_time_seconds" in d and "memory_estimate_mb" in d
|