diff --git a/tests/test_api.py b/tests/test_api.py index e59dcbf..53b9f66 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,5 +1,6 @@ import sys import json +import pprint import pytest @@ -20,7 +21,11 @@ def _assert_result(entry, expected_json_output): """ Check that a given API resource return the expected result. """ + print(entry) decoded_response = _get_and_decode_response(entry) + pprint.pprint(decoded_response) + print("-----") + pprint.pprint(expected_json_output) assert decoded_response == expected_json_output @@ -95,7 +100,9 @@ def test_crs_that_doesnt_exist(api_all): """ errmsg = f"'unknowncrs' not available. You have requested this URI " - errmsg += f"[/{api_all}/crs/unknowncrs] but did you mean /{api_all}/crs/" + errmsg += ( + f"[/{api_all}/crs/unknowncrs] but did you mean /{api_all}/crs/" + ) response = _get_and_decode_response(f"/{api_all}/crs/unknowncrs") assert response["message"].startswith(errmsg) @@ -148,9 +155,7 @@ def test_sys34(api_all): Test that system 34 is handled correctly. In this case we transform from S34J to EPSG:25832 and vice versa. """ - api_entry_fwd = ( - f"/{api_all}/trans/DK:S34J/EPSG:25832/295799.3977,175252.0903" - ) + api_entry_fwd = f"/{api_all}/trans/DK:S34J/EPSG:25832/295799.3977,175252.0903" exp_fwd = { "v1": 499999.99999808666, "v2": 6206079.587029327, @@ -168,7 +173,9 @@ def test_sys34(api_all): } _assert_coordinate(api_entry_inv, exp_inv) - api_entry_js = f"/{api_all}/trans/DK:S34J/DK:S34S/138040.74248674404,63621.728972878314" + api_entry_js = ( + f"/{api_all}/trans/DK:S34J/DK:S34S/138040.74248674404,63621.728972878314" + ) exp_js = { "v1": 138010.86611871765, "v2": 63644.234364821285, @@ -212,7 +219,9 @@ def test_transformation_between_global_and_regional_crs(api_all): CRS's are compatible. """ # first test the case from a global CRS to a regional CRS - api_entry = f"/{api_all}/trans/EPSG:4326/EPSG:25832/55.68950140789923,12.58696909994519" + api_entry = ( + f"/{api_all}/trans/EPSG:4326/EPSG:25832/55.68950140789923,12.58696909994519" + ) expected = {"v1": 725448.0, "v2": 6177354.999999999, "v3": None, "v4": None} _assert_coordinate(api_entry, expected) @@ -289,3 +298,63 @@ def test_combined_epsg_codes(api_all): "v4": None, } _assert_coordinate(api_entry, expected, tolerance=0.01) + + +def test_crs_return_srid(api_from_v1_1): + """ + Test that CRS routes return the calling srid + """ + testdata = { + "EPSG:25832": { + "country": "DK", + "title": "ETRS89 / UTM Zone 32 Nord", + "title_short": "ETRS89/UTM32N", + "v1": "Easting", + "v1_short": "x", + "v2": "Northing", + "v2_short": "y", + "v3": "Ellipsoidehøjde", + "v3_short": "h", + "v4": None, + "v4_short": None, + "srid": "EPSG:25832", + "area_of_use": "Europe between 6°E and 12°E: Austria; Belgium; Denmark - onshore and offshore; Germany - onshore and offshore; Norway including - onshore and offshore; Spain - offshore.", + "bounding_box": [6.0, 38.76, 12.0, 84.33], + }, + "EPSG:23032+5733": { + "country": "DK", + "title": "ED50 / UTM Zone 32 Nord + Dansk Normal Nul", + "title_short": "ED50/UTM32N + DNN", + "v1": "Easting", + "v1_short": "x", + "v2": "Northing", + "v2_short": "y", + "v3": "Ellipsoidehøjde", + "v3_short": "h", + "v4": None, + "v4_short": None, + "srid": "EPSG:23032+5733", + "area_of_use": "Denmark - onshore.", + "bounding_box": [8.0, 54.51, 15.24, 57.8], + }, + "DK:S34S": { + "country": "DK", + "title": "System 34 Sjælland", + "title_short": "S34S", + "v1": "Westing", + "v1_short": "x", + "v2": "Northing", + "v2_short": "y", + "v3": None, + "v3_short": None, + "v4": None, + "v4_short": None, + "srid": "DK:S34S", + "area_of_use": "Denmark - Sealand onshore", + "bounding_box": [11.0, 54.5, 12.8, 56.5], + }, + } + + for srid, crsinfo in testdata.items(): + api_entry = f"/{api_from_v1_1}/crs/{srid}" + _assert_result(api_entry, crsinfo) diff --git a/webproj/api.py b/webproj/api.py index 5f2d2f6..8d84d65 100644 --- a/webproj/api.py +++ b/webproj/api.py @@ -1,10 +1,11 @@ +from cmath import inf import os import json from pathlib import Path from flask import Flask from flask_cors import CORS -from flask_restx import Api, Resource, fields, abort +from flask_restx import Api, Resource, abort import pyproj from pyproj.transformer import Transformer, AreaOfInterest @@ -190,7 +191,6 @@ def get(self): @api.route("/v1.0/crs/") -@api.route("/v1.1/crs/") class CRS(Resource): def get(self, crs): """ @@ -202,6 +202,50 @@ def get(self, crs): abort(404, message=f"'{crs}' not available") +@api.route("/v1.1/crs/") +class CRSv1_1(CRS): + def get(self, crs): + """ + Retrieve information about a given coordinate reference system + + Version 1.1 includes the SRID, area of use and bounding box in + the CRS info. + """ + + output = super().get(crs) + output["srid"] = crs + + # determine area of use and bounding box + try: + crs_from_db = pyproj.CRS.from_user_input(crs.upper()) + if crs_from_db.is_compound: + area = inf + for subcrs in crs_from_db.sub_crs_list: + aou = subcrs.area_of_use + bbox_area = aou.east - aou.west * aou.north - aou.south + if bbox_area < area: + output["area_of_use"] = subcrs.area_of_use.name + output["bounding_box"] = list(subcrs.area_of_use.bounds) + else: + output["area_of_use"] = crs_from_db.area_of_use.name + output["bounding_box"] = list(crs_from_db.area_of_use.bounds) + except pyproj.exceptions.CRSError: + # special cases not in proj.db + if crs == "DK:S34J": + output["area_of_use"] = "Denmark - Jutland onshore" + output["bounding_box"] = [8.0, 54.5, 11.0, 57.75] + elif crs == "DK:S34S": + output["area_of_use"] = "Denmark - Sealand onshore" + output["bounding_box"] = [11.0, 54.5, 12.8, 56.5] + elif crs == "DK:S45B": + output["area_of_use"] = "Denmark - Bornholm onshore" + output["bounding_box"] = [14.6, 54.9, 15.2, 55.3] + else: + abort(404, message=f"'{crs}' not available") + + return output + + @api.route("/v1.0/trans///,") @api.route("/v1.1/trans///,") class Transformation2D(Resource):