Skip to content

Commit 8111d83

Browse files
C-Loftuswebb-ben
andauthored
Fix bbox crs for OAMaps (#1999)
* Fix bbox crs for wms_face - project the bbox in the API code, not the provider - add tests * fix flake8 (#4) * fix quote syntax for old python versions to pass flake8 * Small stylistic changes --------- Co-authored-by: Benjamin Webb <benjamin.miller.webb@gmail.com>
1 parent 643bcc9 commit 8111d83

File tree

3 files changed

+57
-23
lines changed

3 files changed

+57
-23
lines changed

pygeoapi/api/maps.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
from pygeoapi.provider.base import ProviderGenericError
4949
from pygeoapi.util import (
5050
get_provider_by_type, to_json, filter_providers_by_type,
51-
filter_dict_by_key_value
51+
filter_dict_by_key_value, transform_bbox
5252
)
5353

5454
from . import APIRequest, API, validate_datetime
@@ -60,6 +60,9 @@
6060
]
6161

6262

63+
DEFAULT_CRS = 'http://www.opengis.net/def/crs/EPSG/0/4326'
64+
65+
6366
def get_collection_map(api: API, request: APIRequest,
6467
dataset, style=None) -> Tuple[dict, int, str]:
6568
"""
@@ -102,7 +105,10 @@ def get_collection_map(api: API, request: APIRequest,
102105

103106
query_args['format_'] = request.params.get('f', 'png')
104107
query_args['style'] = style
105-
query_args['crs'] = request.params.get('bbox-crs', 4326)
108+
query_args['crs'] = collection_def.get('crs', DEFAULT_CRS)
109+
query_args['bbox_crs'] = request.params.get(
110+
'bbox-crs', DEFAULT_CRS
111+
)
106112
query_args['transparent'] = request.params.get('transparent', True)
107113

108114
try:
@@ -133,7 +139,7 @@ def get_collection_map(api: API, request: APIRequest,
133139
except AttributeError:
134140
bbox = api.config['resources'][dataset]['extents']['spatial']['bbox'] # noqa
135141
try:
136-
query_args['bbox'] = [float(c) for c in bbox]
142+
bbox = [float(c) for c in bbox]
137143
except ValueError:
138144
exception = {
139145
'code': 'InvalidParameterValue',
@@ -144,6 +150,12 @@ def get_collection_map(api: API, request: APIRequest,
144150
return headers, HTTPStatus.BAD_REQUEST, to_json(
145151
exception, api.pretty_print)
146152

153+
if query_args['bbox_crs'] != query_args['crs']:
154+
LOGGER.debug(f'Reprojecting bbox CRS: {query_args["crs"]}')
155+
bbox = transform_bbox(bbox, query_args['bbox_crs'], query_args['crs'])
156+
157+
query_args['bbox'] = bbox
158+
147159
LOGGER.debug('Processing datetime parameter')
148160
datetime_ = request.params.get('datetime')
149161
try:

pygeoapi/provider/wms_facade.py

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
CRS_CODES = {
4545
4326: 'EPSG:4326',
46+
'http://www.opengis.net/def/crs/EPSG/0/4326': 'EPSG:4326',
4647
'http://www.opengis.net/def/crs/EPSG/0/3857': 'EPSG:3857'
4748
}
4849

@@ -65,7 +66,7 @@ def __init__(self, provider_def):
6566

6667
def query(self, style=None, bbox=[-180, -90, 180, 90], width=500,
6768
height=300, crs=4326, datetime_=None, transparent=True,
68-
format_='png'):
69+
bbox_crs=4326, format_='png'):
6970
"""
7071
Generate map
7172
@@ -86,28 +87,12 @@ def query(self, style=None, bbox=[-180, -90, 180, 90], width=500,
8687

8788
version = self.options.get('version', '1.3.0')
8889

89-
if crs in [4326, 'CRS;84'] and version == '1.3.0':
90-
LOGGER.debug('Swapping 4326 axis order to WMS 1.3 mode (yx)')
91-
bbox2 = ','.join(str(c) for c in
92-
[bbox[1], bbox[0], bbox[3], bbox[2]])
93-
else:
94-
LOGGER.debug('Reprojecting coordinates')
95-
LOGGER.debug(f'Output CRS: {CRS_CODES[crs]}')
96-
97-
src_crs = pyproj.CRS.from_string('epsg:4326')
98-
dest_crs = pyproj.CRS.from_string(CRS_CODES[crs])
99-
100-
transformer = pyproj.Transformer.from_crs(src_crs, dest_crs,
101-
always_xy=True)
102-
103-
minx, miny = transformer.transform(bbox[0], bbox[1])
104-
maxx, maxy = transformer.transform(bbox[2], bbox[3])
105-
106-
bbox2 = ','.join(str(c) for c in [minx, miny, maxx, maxy])
90+
if version == '1.3.0' and CRS_CODES[bbox_crs] == 'EPSG:4326':
91+
bbox = [bbox[1], bbox[0], bbox[3], bbox[2]]
92+
bbox2 = ','.join(map(str, bbox))
10793

10894
if not transparent:
10995
self._transparent = 'FALSE'
110-
11196
crs_param = 'crs' if version == '1.3.0' else 'srs'
11297

11398
params = {

tests/api/test_maps.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,40 @@ def test_get_collection_map(config, api_):
5050
assert code == HTTPStatus.OK
5151
assert isinstance(response, bytes)
5252
assert response[1:4] == b'PNG'
53+
54+
55+
def test_map_crs_transform(config, api_):
56+
# Florida in EPSG:4326
57+
params = {
58+
'bbox': '-88.374023,24.826625,-78.112793,31.015279',
59+
# crs is 4326 by implicit since it is the default
60+
}
61+
req = mock_api_request(params)
62+
_, code, floridaIn4326 = get_collection_map(
63+
api_, req, 'mapserver_world_map')
64+
assert code == HTTPStatus.OK
65+
66+
# Area that isn't florida in the ocean; used to make sure
67+
# the same coords with different crs are not the same
68+
params = {
69+
'bbox': '-88.374023,24.826625,-78.112793,31.015279',
70+
'bbox-crs': 'http://www.opengis.net/def/crs/EPSG/0/3857',
71+
}
72+
73+
req = mock_api_request(params)
74+
_, code, florida4326InWrongCRS = get_collection_map(
75+
api_, req, 'mapserver_world_map')
76+
assert code == HTTPStatus.OK
77+
78+
assert florida4326InWrongCRS != floridaIn4326
79+
80+
# Florida again, but this time in EPSG:3857
81+
params = {
82+
'bbox': '-9837751.2884,2854464.3843,-8695476.3377,3634733.5690',
83+
'bbox-crs': 'http://www.opengis.net/def/crs/EPSG/0/3857'
84+
}
85+
req = mock_api_request(params)
86+
_, code, floridaProjectedIn3857 = get_collection_map(
87+
api_, req, 'mapserver_world_map')
88+
assert code == HTTPStatus.OK
89+
assert floridaIn4326 == floridaProjectedIn3857

0 commit comments

Comments
 (0)