diff --git a/src/server/services/wms/qgswmsrenderer.cpp b/src/server/services/wms/qgswmsrenderer.cpp index a7ddcc61a95..317bc29e36a 100644 --- a/src/server/services/wms/qgswmsrenderer.cpp +++ b/src/server/services/wms/qgswmsrenderer.cpp @@ -3153,6 +3153,9 @@ namespace QgsWms } } + // Make sure the map unit tolerance is at least 1 pixel + mapUnitTolerance = std::max( mapUnitTolerance, 1.0 * rct.mapToPixel().mapUnitsPerPixel() ); + QgsRectangle mapRectangle( infoPoint.x() - mapUnitTolerance, infoPoint.y() - mapUnitTolerance, infoPoint.x() + mapUnitTolerance, infoPoint.y() + mapUnitTolerance ); return ( mapSettings.mapToLayerCoordinates( ml, mapRectangle ) ); } diff --git a/tests/src/python/test_qgsserver_wms_getfeatureinfo.py b/tests/src/python/test_qgsserver_wms_getfeatureinfo.py index 080d85eda13..18040a8ca82 100644 --- a/tests/src/python/test_qgsserver_wms_getfeatureinfo.py +++ b/tests/src/python/test_qgsserver_wms_getfeatureinfo.py @@ -37,9 +37,15 @@ from qgis.core import ( QgsMemoryProviderUtils, QgsProject, QgsWkbTypes, + QgsPointXY, +) +from qgis.PyQt.QtCore import QVariant, QUrl +from qgis.server import ( + QgsBufferServerRequest, + QgsBufferServerResponse, + QgsServer, + QgsServerRequest, ) -from qgis.PyQt.QtCore import QVariant -from qgis.server import QgsBufferServerRequest, QgsBufferServerResponse from qgis.testing import unittest, QgisTestCase from test_qgsserver_wms import TestQgsServerWMSTestBase @@ -1357,6 +1363,61 @@ class TestQgsServerWMSGetFeatureInfo(TestQgsServerWMSTestBase): "test_project_values.qgz", ) + def test_getfeatureinfo_sub_px_tolerance(self): + + # create a memory layer with points + fields = QgsFields() + fields.append(QgsField("id", QVariant.Int)) + fields.append(QgsField("name", QVariant.String)) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "points", + fields, + QgsWkbTypes.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + + provider = layer.dataProvider() + self.assertTrue(layer.isValid()) + + # add some features + f = QgsFeature(fields) + f.setAttribute("id", 1) + f.setAttribute("name", "point1") + f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(0, 0))) + provider.addFeature(f) + + f = QgsFeature(fields) + f.setAttribute("id", 2) + f.setAttribute("name", "point2") + f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 1))) + provider.addFeature(f) + + f = QgsFeature(fields) + f.setAttribute("id", 2) + f.setAttribute("name", "point2") + f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-1, -1))) + provider.addFeature(f) + + project = QgsProject() + project.addMapLayer(layer) + + # set up the WMS server + server = QgsServer() + request = QgsServerRequest() + # Choose a small extent to trigger the sub-pixel tolerance adjustment + w = 10 + w2 = int(w / 2) + request.setUrl( + QUrl( + f"?SERVICE=WMS&REQUEST=GetFeatureInfo&LAYERS=points&QUERY_LAYERS=points&INFO_FORMAT=application/json&FEATURE_COUNT=1&WIDTH={w}&HEIGHT={w}&CRS=EPSG:4326&STYLES=&BBOX=-1,-1,1,1&X={w2}&Y={w2}&VERSION=1.3.0" + ) + ) + response = QgsBufferServerResponse() + + server.handleRequest(request, response, project) + body = response.body().data().decode("utf8").replace("\n", "") + self.assertEqual(len(json.loads(body)["features"]), 1) + if __name__ == "__main__": unittest.main()