Skip to content

Commit

Permalink
Explicitly set bounding box in GeoServer
Browse files Browse the repository at this point in the history
  • Loading branch information
index-git authored and jirik committed Apr 30, 2021
1 parent cb66388 commit 4b55ccd
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#### Data migrations
- Rename filesystem directory containing workspaces from `users` to `workspaces`
### Changes
- [#159] (https://github.com/jirik/layman/issues/159) Bounding box is send explicitly to GeoServer for every layer.
- Filesystem directory containing workspaces was renamed from `users` to `workspaces`

## v1.12.0
Expand Down
2 changes: 1 addition & 1 deletion src/layman/layer/filesystem/thumbnail.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def generate_layer_thumbnail(workspace, layername):
wms_url = layer_info['_wms']['url']
raw_bbox = layer_info['bounding_box'] if not bbox_util.is_empty(layer_info['bounding_box']) \
else settings.LAYMAN_DEFAULT_OUTPUT_BBOX
bbox = bbox_util.ensure_bbox_with_area(raw_bbox, settings.NO_AREA_BBOX_PADDING_FOR_THUMBNAIL)
bbox = bbox_util.ensure_bbox_with_area(raw_bbox, settings.NO_AREA_BBOX_PADDING)
tn_bbox = gs_util.get_square_bbox(bbox)
# TODO https://github.com/geopython/OWSLib/issues/709
# tn_img = wms.getmap(
Expand Down
35 changes: 18 additions & 17 deletions src/layman/layer/geoserver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,27 @@ def set_security_rules(workspace, layer, access_rights, auth, geoserver_workspac
gs_util.ensure_layer_security_roles(geoserver_workspace, layer, security_write_roles, 'w', auth)


def get_default_native_bbox():
def bbox_to_native_bbox(bbox):
return {
"minx": settings.LAYMAN_DEFAULT_OUTPUT_BBOX[0],
"miny": settings.LAYMAN_DEFAULT_OUTPUT_BBOX[1],
"maxx": settings.LAYMAN_DEFAULT_OUTPUT_BBOX[2],
"maxy": settings.LAYMAN_DEFAULT_OUTPUT_BBOX[3],
"minx": bbox[0],
"miny": bbox[1],
"maxx": bbox[2],
"maxy": bbox[3],
"crs": "EPSG:3857",
}


def get_default_native_bbox():
return bbox_to_native_bbox(settings.LAYMAN_DEFAULT_OUTPUT_BBOX)


def get_layer_native_bbox(workspace, layer):
db_bbox = layman_util.get_publication_info(workspace, LAYER_TYPE, layer, context={'keys': ['bounding_box']})['bounding_box']
# GeoServer is not working good with degradeted bbox
bbox = bbox_util.ensure_bbox_with_area(db_bbox, settings.NO_AREA_BBOX_PADDING) if not bbox_util.is_empty(db_bbox) else settings.LAYMAN_DEFAULT_OUTPUT_BBOX
return bbox_to_native_bbox(bbox)


def publish_layer_from_db(workspace, layername, description, title, access_rights, geoserver_workspace=None):
geoserver_workspace = geoserver_workspace or workspace
keywords = [
Expand All @@ -140,11 +151,8 @@ def publish_layer_from_db(workspace, layername, description, title, access_right
"@class": "dataStore",
"name": geoserver_workspace + ":postgresql",
},
'nativeBoundingBox': get_layer_native_bbox(workspace, layername),
}
db_bbox = db_source.get_bbox(workspace, layername)
if bbox_util.is_empty(db_bbox):
# world
feature_type_def['nativeBoundingBox'] = get_default_native_bbox()
r = requests.post(urljoin(GS_REST_WORKSPACES,
geoserver_workspace + '/datastores/postgresql/featuretypes/'),
data=json.dumps({
Expand Down Expand Up @@ -189,14 +197,7 @@ def publish_layer_from_qgis(workspace, layer, description, title, access_rights,
"@class": "wmsStore",
"name": geoserver_workspace + f":{store_name}",
},
}
db_bbox = db_source.get_bbox(workspace, layer)
wms_layer_def['nativeBoundingBox'] = get_default_native_bbox() if bbox_util.is_empty(db_bbox) else {
"minx": db_bbox[0],
"miny": db_bbox[1],
"maxx": db_bbox[2],
"maxy": db_bbox[3],
"crs": "EPSG:3857",
'nativeBoundingBox': get_layer_native_bbox(workspace, layer),
}
r = requests.post(urljoin(GS_REST_WORKSPACES,
geoserver_workspace + '/wmslayers/'),
Expand Down
84 changes: 82 additions & 2 deletions src/layman/layer/geoserver/geoserver_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from test import process_client
from test import process_client, util as test_util, data as test_data
import pytest

from layman import settings
from layman import app, settings
from layman.common import bbox as bbox_util
from layman.common.prime_db_schema import publications
from layman.http import LaymanError
from . import wfs, wms
from .. import geoserver


@pytest.mark.usefixtures('ensure_layman')
Expand All @@ -25,3 +29,79 @@ def test_check_user_wms():
assert exc_info.value.http_code == 400
assert exc_info.value.code == 45
assert exc_info.value.data['workspace_name'] == user


def assert_wfs_bbox(workspace, layer, expected_bbox):
wfs_layer = f"{workspace}:{layer}"
wfs_get_capabilities = wfs.get_wfs_proxy(workspace)
wfs_bbox_4326 = wfs_get_capabilities.contents[wfs_layer].boundingBoxWGS84
wfs_bbox_3857 = bbox_util.transform(wfs_bbox_4326, 4326, 3857, )
test_util.assert_same_bboxes(expected_bbox, wfs_bbox_3857, 0.00001)


def assert_wms_bbox(workspace, layer, expected_bbox):
wms_get_capabilities = wms.get_wms_proxy(workspace)
wms_bboxes = wms_get_capabilities.contents[layer].crs_list
wms_bbox_3857 = next(bbox[:4] for bbox in wms_bboxes if bbox[4] == 'EPSG:3857')
test_util.assert_same_bboxes(expected_bbox, wms_bbox_3857, 0.00001)


@pytest.mark.usefixtures('ensure_layman')
def test_geoserver_bbox():
workspace = 'test_geoserver_bbox_workspace'
layer = 'test_geoserver_bbox_layer'
geoserver_workspace = wms.get_geoserver_workspace(workspace)
expected_bbox_1 = test_data.SMALL_LAYER_BBOX
expected_bboxes = [((1571203, 6268895, 1572589, 6269864), (1571203, 6268895, 1572589, 6269864)),
((1571203, 6268895, 1571203, 6269864), (1571203 - settings.NO_AREA_BBOX_PADDING, 6268895,
1571203 + settings.NO_AREA_BBOX_PADDING, 6269864)), # line
((1571203, 6268895, 1571203, 6268895), (1571203 - settings.NO_AREA_BBOX_PADDING,
6268895 - settings.NO_AREA_BBOX_PADDING,
1571203 + settings.NO_AREA_BBOX_PADDING,
6268895 + settings.NO_AREA_BBOX_PADDING)), # point
((None, None, None, None), settings.LAYMAN_DEFAULT_OUTPUT_BBOX),
]

process_client.publish_workspace_layer(workspace, layer, style_file='sample/style/small_layer.qml')

with app.app_context():
assert_wfs_bbox(workspace, layer, expected_bbox_1)
assert_wms_bbox(workspace, layer, expected_bbox_1)

# test WFS
for bbox, expected_bbox in expected_bboxes:
publications.set_bbox(workspace, process_client.LAYER_TYPE, layer, bbox)
wfs.delete_layer(workspace, layer)
geoserver.publish_layer_from_db(workspace, layer, layer, layer, access_rights=None)
wfs.clear_cache(workspace)
assert_wfs_bbox(workspace, layer, expected_bbox)

# test WMS
for bbox, expected_bbox in expected_bboxes:
publications.set_bbox(workspace, process_client.LAYER_TYPE, layer, bbox)
wms.delete_layer(workspace, layer)
geoserver.publish_layer_from_db(workspace,
layer,
layer,
layer,
access_rights=None,
geoserver_workspace=geoserver_workspace,
)
wms.clear_cache(workspace)
assert_wms_bbox(workspace, layer, expected_bbox)

# test cascade WMS from QGIS
for bbox, expected_bbox in expected_bboxes:
publications.set_bbox(workspace, process_client.LAYER_TYPE, layer, bbox)
wms.delete_layer(workspace, layer)
geoserver.publish_layer_from_qgis(workspace,
layer,
layer,
layer,
access_rights=None,
geoserver_workspace=geoserver_workspace,
)
wms.clear_cache(workspace)
assert_wms_bbox(workspace, layer, expected_bbox)

process_client.delete_workspace_layer(workspace, layer)
7 changes: 4 additions & 3 deletions src/layman_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@
)

# If bounding box of layman.layer has no area in at least one dimension,
# this padding in meters will be added to all dimensions whose coordinates equal for thumbnail rendering.
# E.g. if bbox is [5, 100, 5, 200] and NO_AREA_BBOX_PADDING_FOR_THUMBNAIL = 10,
# this padding in meters will be added to all dimensions whose coordinates equal
# for GeoServer feature type definiton and thumbnail rendering.
# E.g. if bbox is [5, 100, 5, 200] and NO_AREA_BBOX_PADDING = 10,
# thumbnail will be rendered with bbox [-5, 100, 15, 200].
NO_AREA_BBOX_PADDING_FOR_THUMBNAIL = 10
NO_AREA_BBOX_PADDING = 10

0 comments on commit 4b55ccd

Please sign in to comment.