sudo apt get update
sudo apt get upgrade
sudo apt install python3-pip
pip install rio-rgbify
PATH="$PATH:/home/<user /.local/bin"
# The following two steps are only necessary when mounting an external hard drive or USB flash drive:
sudo mkdir /mnt/f
sudo mount -t drvfs D: /mnt/f
rio rgbify -b -10000 -i 0.1 wa_1arc_v3_merged_3857.tif wa_1arc_v3_merged_3857_rgb.tif
# The following steps are only necessary when unmounting an external hard drive or USB flash drive:
cd \~
sudo umount /mnt/f/
import logging
from wsgiref import headers
import azure.functions as func
import psycopg2
# Database to connect to
DATABASE = {
'user': 'postgres',
'password': '{password}',
'host': 'localhost',
'port': '5432',
'database': '{database}'
}
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
DATABASE_CONNECTION = None
# get url parameters http://localhost:7071/api/tileserver?zoom={z}&x={x}&y={y}
# http://localhost:7071/api/tileserver?zoom=16&x=10556&y=22870
zoom = int(req.params.get('zoom'))
x = int(req.params.get('x'))
y = int(req.params.get('y'))
table = req.params.get('table')
# calculate the envelope of the tile
# Width of world in EPSG:3857
worldMercMax = 20037508.3427892
worldMercMin = -1 * worldMercMax
worldMercSize = worldMercMax - worldMercMin
# Width in tiles
worldTileSize = 2 ** zoom
# Tile width in EPSG:3857
tileMercSize = worldMercSize / worldTileSize
# Calculate geographic bounds from tile coordinates
# XYZ tile coordinates are in "image space" so origin is
# top-left, not bottom right
xmin = worldMercMin + tileMercSize * x
xmax = worldMercMin + tileMercSize * (x + 1)
ymin = worldMercMax - tileMercSize * (y + 1)
ymax = worldMercMax - tileMercSize * y
# Generate SQL to materialize a query envelope in EPSG:3857.
# Densify the edges a little so the envelope can be
# safely converted to other coordinate systems.
DENSIFY_FACTOR = 4
segSize = (xmax - xmin)/DENSIFY_FACTOR
sql01 = 'ST_Segmentize(ST_MakeEnvelope(' + str(xmin) + ', ' + str(ymin) + ', ' + str(xmax) + ', ' + str(ymax) + ', 3857), ' + str(segSize) +')'
# Generate a SQL query to pull a tile worth of MVT data
# from the table of interest.
# Materialize the bounds
# Select the relevant geometry and clip to MVT bounds
# Convert to MVT format
sql02 = 'WITH bounds AS (SELECT ' + sql01 + ' AS geom, ' + sql01 + '::box2d AS b2d), mvtgeom AS (SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.b2d) AS geom, elev FROM contourlines_smooth t, bounds WHERE ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))) SELECT ST_AsMVT(mvtgeom.*) FROM mvtgeom'
# Run tile query SQL and return error on failure conditions
# Make and hold connection to database
if not DATABASE_CONNECTION:
try:
DATABASE_CONNECTION = psycopg2.connect(**DATABASE)
logging.info('Connected to database.')
except (Exception, psycopg2.Error) as error:
logging.error('ERROR: Cannot connect to database.')
# Query for MVT
with DATABASE_CONNECTION.cursor() as cur:
cur.execute(sql02)
if not cur:
logging.error('ERROR: SQL Query failed.')
pbf = cur.fetchone()[0]
logging.info('Queried database')
if zoom and x and y:
return func.HttpResponse(
# f"This HTTP triggered function executed successfully.\n\nzoom={zoom}\nx={x}\ny={y}\n\nxmin={xmin}\nxmax={xmax}\nymin={ymin}\nymax={ymax}\n\nsql01={sql01}\n\nsql02={sql02}",
bytes(pbf),
status_code=200,
headers={"Content-type": "application/vnd.mapbox-vector-tile","Access-Control-Allow-Origin": "*"}
)
else:
return func.HttpResponse(
"ERROR: Missing parameter!",
status_code=400
)