lookup endpoint, better tag filtering
This commit is contained in:
parent
be5938ffb0
commit
9168a7cbb8
3 changed files with 102 additions and 10 deletions
65
api.py
65
api.py
|
|
@ -1,9 +1,13 @@
|
|||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import Response, FileResponse
|
||||
from fastapi import FastAPI, HTTPException, Query
|
||||
from fastapi.responses import Response, FileResponse, JSONResponse
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
import geopandas as gpd
|
||||
import cbor2
|
||||
from pathlib import Path
|
||||
import pygeohash as pgh
|
||||
from shapely.geometry import Point, LineString, MultiLineString
|
||||
from pyproj import Geod
|
||||
import json
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
|
@ -44,4 +48,59 @@ async def get_geodata(geohash: str, format: str = "cbor"):
|
|||
return Response(content=cbor_data, media_type="application/cbor",
|
||||
headers={"Content-Disposition": f"attachment; filename={base_geohash}.cbor"})
|
||||
|
||||
raise HTTPException(status_code=400, detail="Invalid format. Use 'parquet', 'geojson', or 'cbor'.")
|
||||
raise HTTPException(status_code=400, detail="Invalid format. Use 'parquet', 'geojson', or 'cbor'.")
|
||||
|
||||
@app.get("/lookup/")
|
||||
async def lookup(
|
||||
latitude: float = Query(..., description="Latitude of the point"),
|
||||
longitude: float = Query(..., description="Longitude of the point"),
|
||||
distance: float = Query(10, description="Distance threshold in meters for nearby lines")
|
||||
):
|
||||
"""
|
||||
Finds polygons containing the given point and lines within a threshold (in meters).
|
||||
"""
|
||||
# Compute geohash (precision can be adjusted)
|
||||
geohash = pgh.encode(latitude, longitude, precision=4) # Adjust precision as needed
|
||||
parquet_file = GEOHASH_FOLDER / f"{geohash}.parquet"
|
||||
|
||||
if not parquet_file.exists():
|
||||
raise HTTPException(status_code=404, detail=f"No data found for geohash '{geohash}'.")
|
||||
|
||||
try:
|
||||
# Load the Parquet file into a GeoDataFrame
|
||||
gdf = gpd.read_parquet(parquet_file)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to read Parquet file: {str(e)}")
|
||||
|
||||
point = Point(longitude, latitude)
|
||||
geod = Geod(ellps="WGS84") # Accurate geodetic distance calculations
|
||||
|
||||
found_geometries = []
|
||||
|
||||
# Process each row
|
||||
for _, row in gdf.iterrows():
|
||||
geom = row.geometry # Directly use the Shapely geometry object
|
||||
|
||||
metadata = {}
|
||||
if isinstance(row.get("tags"), dict):
|
||||
metadata = {k: v for k, v in row["tags"].items() if v is not None} # Remove empty values
|
||||
|
||||
if geom.contains(point):
|
||||
found_geometries.append({"type": "polygon", **metadata})
|
||||
elif isinstance(geom, (LineString, MultiLineString)):
|
||||
try:
|
||||
if isinstance(geom, LineString):
|
||||
min_distance = min(geod.inv(point.x, point.y, p[0], p[1])[2] for p in geom.coords)
|
||||
elif isinstance(geom, MultiLineString):
|
||||
min_distance = min(
|
||||
min(geod.inv(point.x, point.y, p[0], p[1])[2] for p in line.coords)
|
||||
for line in geom.geoms
|
||||
)
|
||||
|
||||
if min_distance <= distance:
|
||||
found_geometries.append({"type": "line" if isinstance(geom, LineString) else "multi_line", **metadata})
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed distance calculation: {str(e)}")
|
||||
|
||||
# Return JSON result
|
||||
return JSONResponse(content=found_geometries)
|
||||
Loading…
Add table
Add a link
Reference in a new issue