Geometry primitives in NYC State Plane (EPSG:2263)
Browse filesNYC's empirical flood layers (Sandy, DEP, Ida HWMs) are published in
EPSG:2263 (US survey feet). Reprojecting on every spatial query is
wasteful, so the convention here is: load once, reproject to 2263 at
ingest, do all distance/buffer math in feet. WGS84 is reserved for
inputs (lat/lon from the geocoder) and outputs (GeoJSON for the map).
- app/spatial.py +22 -0
app/spatial.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Spatial helpers. NYC works in EPSG:2263 (NY state plane, feet)."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import geopandas as gpd
|
| 7 |
+
|
| 8 |
+
NYC_CRS = "EPSG:2263" # ft
|
| 9 |
+
WGS84 = "EPSG:4326"
|
| 10 |
+
|
| 11 |
+
DATA = Path(__file__).resolve().parent.parent / "data"
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def to_nyc(g: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
|
| 15 |
+
if g.crs is None:
|
| 16 |
+
raise ValueError("layer has no CRS")
|
| 17 |
+
return g.to_crs(NYC_CRS) if g.crs.to_string() != NYC_CRS else g
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def load_layer(path: str | Path, layer: str | None = None) -> gpd.GeoDataFrame:
|
| 21 |
+
g = gpd.read_file(path, layer=layer) if layer else gpd.read_file(path)
|
| 22 |
+
return to_nyc(g)
|