From 91afcd7954e0573381768c96a2cfc29b35a07400 Mon Sep 17 00:00:00 2001 From: Daven Quinn Date: Wed, 10 Jul 2024 17:42:53 -0500 Subject: [PATCH] Created a skeletal layer for map boundaries --- .gitignore | 3 +- macrostrat_tileserver/main.py | 3 + macrostrat_tileserver/map_bounds/__init__.py | 62 +++++++++++++++++++ .../map_bounds/queries/rgeom.sql | 15 +++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 macrostrat_tileserver/map_bounds/__init__.py create mode 100644 macrostrat_tileserver/map_bounds/queries/rgeom.sql diff --git a/.gitignore b/.gitignore index 8505119..38fdd2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .env .venv __pycache__ -.pytest_cache \ No newline at end of file +.pytest_cache +.idea diff --git a/macrostrat_tileserver/main.py b/macrostrat_tileserver/main.py index 3a46591..35298ed 100644 --- a/macrostrat_tileserver/main.py +++ b/macrostrat_tileserver/main.py @@ -117,6 +117,9 @@ async def shutdown_event(): app.include_router(filterable_router, tags=["Filterable"], prefix="/v2") +from .map_bounds import router as map_bounds_router +app.include_router(map_bounds_router, tags=["Map Bounds"], prefix="/v2") + @app.get("/carto/rotation-models") async def rotation_models(): diff --git a/macrostrat_tileserver/map_bounds/__init__.py b/macrostrat_tileserver/map_bounds/__init__.py new file mode 100644 index 0000000..aefea58 --- /dev/null +++ b/macrostrat_tileserver/map_bounds/__init__.py @@ -0,0 +1,62 @@ +from pathlib import Path + +from buildpg import render +from fastapi import APIRouter, Request, Response +from timvt.resources.enums import MimeTypes + +router = APIRouter() + +__here__ = Path(__file__).parent + + +@router.get("/rgeom/{z}/{x}/{y}") +async def rgeom( + request: Request, + compilation: Compilation, + z: int, + x: int, + y: int, +): + """Get a tile from the tileserver.""" + pool = request.app.state.pool + + async with pool.acquire() as con: + data = await run_layer_query( + con, + "rgeom", + z=z, + x=x, + y=y, + ) + data = join_layers([units_, lines_]) + kwargs = {} + kwargs.setdefault("media_type", MimeTypes.pbf.value) + return Response(data, **kwargs) + + +async def run_layer_query(con, layer_name, **params): + query = get_layer_sql(layer_name) + q, p = render(query, layer_name=layer_name, **params) + + # Overcomes a shortcoming in buildpg that deems casting to an array as unsafe + # https://github.com/samuelcolvin/buildpg/blob/e2a16abea5c7607b53c501dbae74a5765ba66e15/buildpg/components.py#L21 + q = q.replace("textarray", "text[]") + + print(q,p) + + return await con.fetchval(q, *p) + + +def get_layer_sql(layer: str): + query = __here__ / "queries" / (layer + ".sql") + + q = query.read_text() + q = q.strip() + if q.endswith(";"): + q = q[:-1] + + # Replace the envelope with the function call. Kind of awkward. + q = q.replace(":envelope", "tile_utils.envelope(:x, :y, :z)") + + # Wrap with MVT creation + return f"WITH feature_query AS ({q}) SELECT ST_AsMVT(feature_query, :layer_name) FROM feature_query" diff --git a/macrostrat_tileserver/map_bounds/queries/rgeom.sql b/macrostrat_tileserver/map_bounds/queries/rgeom.sql new file mode 100644 index 0000000..88dfb9d --- /dev/null +++ b/macrostrat_tileserver/map_bounds/queries/rgeom.sql @@ -0,0 +1,15 @@ +WITH mvt_features AS ( + SELECT + source_id, + rgeom geom + FROM maps.sources + WHERE + rgeom is NOT NULL + AND status_code = 'active' + AND ST_Intersects(geom, ST_Transform(:envelope, 4326)) + +) +SELECT + source_id, + tile_layers.tile_geom(z.geom, :envelope) AS geom +FROM mvt_features z