diff --git a/api/geospatial.py b/api/geospatial.py index f718b41ed..3c5173c71 100644 --- a/api/geospatial.py +++ b/api/geospatial.py @@ -101,9 +101,13 @@ def get_feature_collection( things = get_thing_features(session, thing_type, group) - def make_feature_dict(thing, geometry, elevation, *other): - geometry = json.loads(geometry) - geometry["coordinates"].append(elevation) + def make_feature_dict(thing): + current_location = thing.current_location + x = current_location.latlon[1] + y = current_location.latlon[0] + elevation = current_location.elevation + coordinates = [x, y, elevation] + return { "type": "Feature", "properties": { @@ -112,10 +116,13 @@ def make_feature_dict(thing, geometry, elevation, *other): "name": thing.name, "group": group, }, - "geometry": geometry, + "geometry": { + "type": "Point", + "coordinates": coordinates, + }, } - features = [make_feature_dict(*item) for item in things] + features = [make_feature_dict(thing) for thing in things] return { "type": "FeatureCollection", diff --git a/services/geospatial_helper.py b/services/geospatial_helper.py index 356c55634..fbececabc 100644 --- a/services/geospatial_helper.py +++ b/services/geospatial_helper.py @@ -20,55 +20,18 @@ import constants from db.thing import Thing from db.group import GroupThingAssociation, Group -from db.location import Location, LocationThingAssociation -from geoalchemy2.functions import ST_GeomFromText, ST_Within, ST_AsGeoJSON +from db.location import Location +from geoalchemy2.functions import ST_GeomFromText, ST_Within from geoalchemy2.shape import to_shape from shapely.wkt import loads as wkt_loads -from sqlalchemy import Select, select -from sqlalchemy.orm import aliased -from sqlalchemy import func +from sqlalchemy import Select def get_thing_features( session, thing_type: list | str | None, group: str | int | None ) -> list: - # sql = ( - # select(Thing, ST_AsGeoJSON(Location.point).label("geojson")) - # .join(LocationThingAssociation, Thing.id == LocationThingAssociation.thing_id) - # .join(Location, LocationThingAssociation.location_id == Location.id) - # ) - # selection_args = [Thing, ST_AsGeoJSON(Location.point).label("geojson")] - # if thing_type == "well": - # selection_args.append(WellThing) - # elif thing_type == "spring": - # selection_args.append(SpringThing) - - # Subquery: get the latest association for each thing (optionally only active) - lta_alias = aliased(LocationThingAssociation) - - latest_assoc = ( - select( - LocationThingAssociation.thing_id, - func.max(LocationThingAssociation.effective_start).label("max_start"), - ) - .where( - LocationThingAssociation.effective_end == None - ) # Only active, remove if you want most recent regardless of end - .group_by(LocationThingAssociation.thing_id) - .subquery() - ) - - sql = ( - select(Thing, ST_AsGeoJSON(Location.point).label("geojson"), Location.elevation) - .join(lta_alias, Thing.id == lta_alias.thing_id) - .join(Location, lta_alias.location_id == Location.id) - .join( - latest_assoc, - (latest_assoc.c.thing_id == lta_alias.thing_id) - & (latest_assoc.c.max_start == lta_alias.effective_start), - ) - ) + sql = session.query(Thing) if thing_type: if isinstance(thing_type, str): @@ -88,7 +51,7 @@ def get_thing_features( sql = sql.where(Group.id == group) # unique needs to be invoked to prevent duplicates from eager loading - return session.execute(sql).unique().all() + return sql.distinct().all() def create_shapefile(things: list, filename: str = "things.shp") -> None: @@ -97,7 +60,9 @@ def create_shapefile(things: list, filename: str = "things.shp") -> None: shp.field("id", "L") shp.field("name", "C") - for thing, point, elevation in things: + for thing in things: + point = thing.current_location.point + elevation = thing.current_location.elevation # Assume loc.point is WKT or a Shapely geometry or GeoJSON if isinstance(point, str): try: