From 275c5bd0f3317854a00a3cacea4d7d63ac1bce1b Mon Sep 17 00:00:00 2001 From: Luke Parkinson Date: Mon, 25 Nov 2024 13:22:32 +1300 Subject: [PATCH] Create bounding box area calculation process --- environment.yml | 3 ++- otakaro/area.py | 55 +++++++++++++++++++++++++++++++++++++++++++ otakaro/blueprint.py | 4 +++- terriajs/catalog.json | 7 ++++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 otakaro/area.py diff --git a/environment.yml b/environment.yml index 7f5a9a0e4..026f0d840 100644 --- a/environment.yml +++ b/environment.yml @@ -30,7 +30,6 @@ dependencies: - botocore>=1.33.10 # Minimum version that is compatible with python >= 3.10 is botocore>=1.13.0 - scrapy==2.11.1 - gevent==23.9.1 - - pywps==4.6.0 - pip: - flask_swagger_ui==4.11.1 - geovoronoi==0.4.0 @@ -38,5 +37,7 @@ dependencies: - celery==5.2.7 - gunicorn==20.1.0 - git+https://github.com/LukeParky/NewZeaLiDAR.git@v0.3 + - pywps==4.6.0 # pywps is available in conda but our fork of OWSLib is required for bounding boxes + - git+https://github.com/GeospatialResearch/OWSLib.git prefix: diff --git a/otakaro/area.py b/otakaro/area.py new file mode 100644 index 000000000..a461fb2a5 --- /dev/null +++ b/otakaro/area.py @@ -0,0 +1,55 @@ +# # -*- coding: utf-8 -*- +"""Defines PyWPS WebProcessingService processes for calculating area of geometries.""" + +from geopandas import GeoDataFrame +from pywps import BoundingBoxInput, Process, LiteralOutput, WPSRequest +from pywps.response.execute import ExecuteResponse +from shapely import box + + +class BoundingBoxAreaProcess(Process): + """Class representing a WebProcessingService process for calculating area of a bounding box""" + + def __init__(self) -> None: + """Define inputs and outputs of the WPS process, and assogm process handler.""" + # Create bounding box WPS inputs. + inputs = [BoundingBoxInput('bboxin', 'box in', crss=['epsg:4326'])] + # Create area WPS outputs. + outputs = [LiteralOutput('area', 'Area', data_type='string')] + + # Initialise the process. + super().__init__( + self._handler, + identifier='area', + title="Calculate the area of the polygon.", + inputs=inputs, + outputs=outputs, + ) + + @staticmethod + def _handler(request: WPSRequest, response: ExecuteResponse) -> None: + """ + Process handler for calculating bounding box area. + + Parameters + ---------- + request : WPSRequest + The WPS request, containing input parameters. + response : ExecuteResponse + The WPS response, containing output data. + """ + # Get coordinates from bounding box input + bounding_box_input = request.inputs['bboxin'][0] + ymin, xmin = bounding_box_input.ll # lower left + ymax, xmax = bounding_box_input.ur # upper right + + # Form bounding box into standard shapely.box + bounding_box = box(xmin, ymin, xmax, ymax) + # Create GeoDataFrame with unit of measurement in metres. + gdf = GeoDataFrame(index=[0], crs="epsg:4326", geometry=[bounding_box]).to_crs(epsg=2193) + + # Calculate area in square metres + area = gdf.geometry[0].area + # Format area + display_area = f"{area:.0f} m²" + response.outputs['area'].data = display_area diff --git a/otakaro/blueprint.py b/otakaro/blueprint.py index e45dac10a..409a59aca 100644 --- a/otakaro/blueprint.py +++ b/otakaro/blueprint.py @@ -8,12 +8,14 @@ from src.check_celery_alive import check_celery_alive from otakaro import tasks +from otakaro.area import BoundingBoxAreaProcess from otakaro.pollution_model.medusa_process_service import MedusaProcessService otakaro_blueprint = Blueprint('otakaro', __name__) processes = [ - MedusaProcessService() + MedusaProcessService(), + BoundingBoxAreaProcess(), ] process_descriptor = {process.identifier: process.abstract for process in processes} diff --git a/terriajs/catalog.json b/terriajs/catalog.json index ecf452882..3f1e36ceb 100644 --- a/terriajs/catalog.json +++ b/terriajs/catalog.json @@ -195,6 +195,13 @@ "url": "$BACKEND_URL/wps", "identifier": "medusa", "storeSupported": true + }, + { + "type": "wps", + "name": "Area", + "description": "Calculate the area of the polygon.", + "url": "$BACKEND_URL/wps", + "identifier": "area" } ] }