merge exporting zones from "exports" page

This commit is contained in:
gluap 2024-01-25 22:11:11 +01:00
parent c41aa3f6a0
commit 6d35001f8d
No known key found for this signature in database
3 changed files with 29 additions and 14 deletions

View file

@ -4,6 +4,7 @@ from contextlib import contextmanager
import zipfile import zipfile
import io import io
import re import re
import math
from sqlite3 import connect from sqlite3 import connect
import shapefile import shapefile
@ -15,6 +16,9 @@ from sanic.exceptions import InvalidUsage
from obs.api.app import api, json as json_response from obs.api.app import api, json as json_response
from obs.api.utils import use_request_semaphore from obs.api.utils import use_request_semaphore
import logging
log = logging.getLogger(__name__)
class ExportFormat(str, Enum): class ExportFormat(str, Enum):
SHAPEFILE = "shapefile" SHAPEFILE = "shapefile"
@ -64,13 +68,13 @@ def shapefile_zip(shape_type=shapefile.POINT, basename="events"):
async def export_events(req): async def export_events(req):
async with use_request_semaphore(req, "export_semaphore", timeout=30): async with use_request_semaphore(req, "export_semaphore", timeout=30):
bbox = req.ctx.get_single_arg( bbox = req.ctx.get_single_arg(
"bbox", default="-180,-90,180,90", convert=parse_bounding_box "bbox", default="-180,-90,180,90"
) )
fmt = req.ctx.get_single_arg("fmt", convert=ExportFormat) fmt = req.ctx.get_single_arg("fmt", convert=ExportFormat)
events = await req.ctx.db.stream_scalars( events = await req.ctx.db.stream(
select(OvertakingEvent).where( text(
OvertakingEvent.geometry.bool_op("&&")(func.ST_Transform(bbox, 3857)) f"select ST_AsGeoJSON(ST_Transform(geometry,4326)) AS geometry,distance_overtaker,distance_stationary,way_id,direction,speed,time_stamp,course,zone from layer_obs_events(ST_Transform(ST_MakeEnvelope({bbox},4326),3857),19,NULL,'1900-01-01'::timestamp,'2100-01-01'::timestamp) "
) )
) )
@ -82,16 +86,19 @@ async def export_events(req):
writer.field("direction", "N", decimal=0) writer.field("direction", "N", decimal=0)
writer.field("course", "N", decimal=4) writer.field("course", "N", decimal=4)
writer.field("speed", "N", decimal=4) writer.field("speed", "N", decimal=4)
writer.field("zone", "C")
async for event in events: async for event in events:
writer.point(event.longitude, event.latitude) coords = json.loads(event.geometry)['coordinates']
writer.point(*coords)
writer.record( writer.record(
distance_overtaker=event.distance_overtaker, distance_overtaker=event.distance_overtaker,
distance_stationary=event.distance_stationary, distance_stationary=event.distance_stationary,
direction=-1 if event.direction_reversed else 1, direction=event.direction,
way_id=event.way_id, way_id=event.way_id,
course=event.course, course=event.course,
speed=event.speed, speed=event.speed,
zone=event.zone
# "time"=event.time, # "time"=event.time,
) )
@ -100,19 +107,22 @@ async def export_events(req):
if fmt == ExportFormat.GEOJSON: if fmt == ExportFormat.GEOJSON:
features = [] features = []
async for event in events: async for event in events:
geom = json.loads(event.geometry)
features.append( features.append(
{ {
"type": "Feature", "type": "Feature",
"geometry": json.loads(event.geometry), "geometry": geom,
"properties": { "properties": {
"distance_overtaker": event.distance_overtaker, "distance_overtaker": event.distance_overtaker if event.distance_overtaker is not None and not math.isnan(event.distance_overtaker) else None,
"distance_stationary": event.distance_stationary, "distance_stationary": event.distance_stationary if event.distance_stationary is not None and not math.isnan(event.distance_stationary) else None,
"direction": -1 if event.direction_reversed else 1, "direction": event.direction if event.direction is not None and not math.isnan(event.direction) else None,
"way_id": event.way_id, "way_id": event.way_id,
"course": event.course, "course": event.course if event.course is not None and not math.isnan(event.course) else None,
"speed": event.speed, "speed": event.speed if event.speed is not None and not math.isnan(event.speed) else None,
"time": event.time, "time": event.time_stamp,
"zone": event.zone
}, },
} }
) )

View file

@ -1,5 +1,7 @@
DROP FUNCTION IF EXISTS layer_obs_events;
CREATE OR REPLACE FUNCTION layer_obs_events(bbox geometry, zoom_level int, user_id integer, min_time timestamp, max_time timestamp) CREATE OR REPLACE FUNCTION layer_obs_events(bbox geometry, zoom_level int, user_id integer, min_time timestamp, max_time timestamp)
RETURNS TABLE(event_id bigint, geometry geometry, distance_overtaker float, distance_stationary float, direction int, course float, speed float, zone zone_type, way_id bigint) AS $$ RETURNS TABLE(event_id bigint, geometry geometry, distance_overtaker float, distance_stationary float, direction int, course float, speed float, time_stamp timestamp, zone zone_type, way_id bigint) AS $$
SELECT SELECT
overtaking_event.id::bigint as event_id, overtaking_event.id::bigint as event_id,
@ -9,6 +11,7 @@ RETURNS TABLE(event_id bigint, geometry geometry, distance_overtaker float, dist
(case when direction_reversed then -1 else 1 end)::int as direction, (case when direction_reversed then -1 else 1 end)::int as direction,
course, course,
speed, speed,
time as time_stamp,
CASE WHEN road.zone IS NULL THEN 'urban' else road.zone END as zone, CASE WHEN road.zone IS NULL THEN 'urban' else road.zone END as zone,
overtaking_event.way_id::bigint as way_id overtaking_event.way_id::bigint as way_id
FROM overtaking_event FROM overtaking_event

View file

@ -16,6 +16,8 @@ layer:
Direction of travel, as reported by GPS, in degree from North. Direction of travel, as reported by GPS, in degree from North.
speed: | speed: |
Speed of travel, as reported by GPS, in meters per second (?). Speed of travel, as reported by GPS, in meters per second (?).
time_stamp: |
the time of the overtaking
zone: | zone: |
rural or urban rural or urban
defaults: defaults: