diff --git a/pygeoapi/api/maps.py b/pygeoapi/api/maps.py index 728177f52..6daff01cc 100644 --- a/pygeoapi/api/maps.py +++ b/pygeoapi/api/maps.py @@ -42,13 +42,12 @@ from http import HTTPStatus import logging from typing import Tuple - from pygeoapi.openapi import get_oas_30_parameters from pygeoapi.plugin import load_plugin from pygeoapi.provider.base import ProviderGenericError from pygeoapi.util import ( get_provider_by_type, to_json, filter_providers_by_type, - filter_dict_by_key_value + filter_dict_by_key_value, transform_bbox ) from . import APIRequest, API, validate_datetime @@ -102,7 +101,11 @@ def get_collection_map(api: API, request: APIRequest, query_args['format_'] = request.params.get('f', 'png') query_args['style'] = style - query_args['crs'] = request.params.get('bbox-crs', 4326) + epsg4326 = 'http://www.opengis.net/def/crs/EPSG/0/4326' + query_args['crs'] = collection_def.get('crs', epsg4326) + query_args['bbox_crs'] = request.params.get( + 'bbox-crs', epsg4326 + ) query_args['transparent'] = request.params.get('transparent', True) try: @@ -132,6 +135,11 @@ def get_collection_map(api: API, request: APIRequest, exception, api.pretty_print) except AttributeError: bbox = api.config['resources'][dataset]['extents']['spatial']['bbox'] # noqa + + LOGGER.debug('Reprojecting coordinates') + LOGGER.debug(f"Output bbox CRS: {query_args['crs']}") + bbox = transform_bbox(bbox, query_args['bbox_crs'], query_args['crs']) + try: query_args['bbox'] = [float(c) for c in bbox] except ValueError: diff --git a/pygeoapi/provider/wms_facade.py b/pygeoapi/provider/wms_facade.py index fa3ffd064..a31440d70 100644 --- a/pygeoapi/provider/wms_facade.py +++ b/pygeoapi/provider/wms_facade.py @@ -42,8 +42,9 @@ } CRS_CODES = { - 4326: 'EPSG:4326', - 'http://www.opengis.net/def/crs/EPSG/0/3857': 'EPSG:3857' + 4326: "EPSG:4326", + "http://www.opengis.net/def/crs/EPSG/0/3857": "EPSG:3857", + "http://www.opengis.net/def/crs/EPSG/0/4326": "EPSG:4326", } @@ -65,7 +66,7 @@ def __init__(self, provider_def): def query(self, style=None, bbox=[-180, -90, 180, 90], width=500, height=300, crs=4326, datetime_=None, transparent=True, - format_='png'): + bbox_crs=4326, format_='png'): """ Generate map @@ -86,35 +87,18 @@ def query(self, style=None, bbox=[-180, -90, 180, 90], width=500, version = self.options.get('version', '1.3.0') - if crs in [4326, 'CRS;84'] and version == '1.3.0': - LOGGER.debug('Swapping 4326 axis order to WMS 1.3 mode (yx)') - bbox2 = ','.join(str(c) for c in - [bbox[1], bbox[0], bbox[3], bbox[2]]) - else: - LOGGER.debug('Reprojecting coordinates') - LOGGER.debug(f'Output CRS: {CRS_CODES[crs]}') - - src_crs = pyproj.CRS.from_string('epsg:4326') - dest_crs = pyproj.CRS.from_string(CRS_CODES[crs]) - - transformer = pyproj.Transformer.from_crs(src_crs, dest_crs, - always_xy=True) - - minx, miny = transformer.transform(bbox[0], bbox[1]) - maxx, maxy = transformer.transform(bbox[2], bbox[3]) - - bbox2 = ','.join(str(c) for c in [minx, miny, maxx, maxy]) + if version == '1.3.0' and CRS_CODES[bbox_crs] == 'EPSG:4326': + bbox = [bbox[1], bbox[0], bbox[3], bbox[2]] if not transparent: self._transparent = 'FALSE' - crs_param = 'crs' if version == '1.3.0' else 'srs' params = { 'version': version, 'service': 'WMS', 'request': 'GetMap', - 'bbox': bbox2, + 'bbox': ",".join(map(str, bbox)), crs_param: CRS_CODES[crs], 'layers': self.options['layer'], 'styles': self.options.get('style', 'default'), diff --git a/tests/api/test_maps.py b/tests/api/test_maps.py index 3b284ac0a..fb043dfeb 100644 --- a/tests/api/test_maps.py +++ b/tests/api/test_maps.py @@ -50,3 +50,40 @@ def test_get_collection_map(config, api_): assert code == HTTPStatus.OK assert isinstance(response, bytes) assert response[1:4] == b'PNG' + + +def test_map_crs_transform(config, api_): + # Florida in EPSG:4326 + params = { + 'bbox': '-88.374023,24.826625,-78.112793,31.015279', + # crs is 4326 by implicit since it is the default + } + req = mock_api_request(params) + _, code, floridaIn4326 = get_collection_map( + api_, req, 'mapserver_world_map') + assert code == HTTPStatus.OK + + # Area that isn't florida in the ocean; used to make sure + # the same coords with different crs are not the same + params = { + 'bbox': '-88.374023,24.826625,-78.112793,31.015279', + 'bbox-crs': 'http://www.opengis.net/def/crs/EPSG/0/3857', + } + + req = mock_api_request(params) + _, code, florida4326InWrongCRS = get_collection_map( + api_, req, 'mapserver_world_map') + assert code == HTTPStatus.OK + + assert florida4326InWrongCRS != floridaIn4326 + + # Florida again, but this time in EPSG:3857 + params = { + 'bbox': '-9837751.2884,2854464.3843,-8695476.3377,3634733.5690', + 'bbox-crs': 'http://www.opengis.net/def/crs/EPSG/0/3857' + } + req = mock_api_request(params) + _, code, floridaProjectedIn3857 = get_collection_map( + api_, req, 'mapserver_world_map') + assert code == HTTPStatus.OK + assert floridaIn4326 == floridaProjectedIn3857