@@ -1505,6 +1505,94 @@ def testWFSGetOnlyFeaturesInViewExtent(self):
15051505 vl_extent = QgsGeometry .fromRect (vl .extent ())
15061506 assert QgsGeometry .compare (vl_extent .asPolygon ()[0 ], reference .asPolygon ()[0 ], 0.00001 ), 'Expected {}, got {}' .format (reference .asWkt (), vl_extent .asWkt ())
15071507
1508+ def testWFSGetOnlyFeaturesInViewExtentZoomOut (self ):
1509+ """Test zoom out outside of declare extent in metadata (#20742) """
1510+
1511+ endpoint = self .__class__ .basetestpath + '/fake_qgis_http_endpoint_20742'
1512+
1513+ with open (sanitize (endpoint , '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0' ), 'wb' ) as f :
1514+ f .write ("""
1515+ <wfs:WFS_Capabilities version="1.1.0" xmlns="http://www.opengis.net/wfs" xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:ows="http://www.opengis.net/ows" xmlns:gml="http://schemas.opengis.net/gml">
1516+ <OperationsMetadata>
1517+ <Operation name="GetFeature">
1518+ <Parameter name="resultType">
1519+ <Value>results</Value>
1520+ <Value>hits</Value>
1521+ </Parameter>
1522+ </Operation>
1523+ </OperationsMetadata>
1524+ <FeatureTypeList>
1525+ <FeatureType>
1526+ <Name>my:typename</Name>
1527+ <Title>Title</Title>
1528+ <Abstract>Abstract</Abstract>
1529+ <DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
1530+ <WGS84BoundingBox>
1531+ <LowerCorner>-80 60</LowerCorner>
1532+ <UpperCorner>-50 80</UpperCorner>
1533+ </WGS84BoundingBox>
1534+ </FeatureType>
1535+ </FeatureTypeList>
1536+ </wfs:WFS_Capabilities>""" .encode ('UTF-8' ))
1537+
1538+ with open (sanitize (endpoint , '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename' ), 'wb' ) as f :
1539+ f .write ("""
1540+ <xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
1541+ <xsd:import namespace="http://www.opengis.net/gml"/>
1542+ <xsd:complexType name="typenameType">
1543+ <xsd:complexContent>
1544+ <xsd:extension base="gml:AbstractFeatureType">
1545+ <xsd:sequence>
1546+ <xsd:element maxOccurs="1" minOccurs="0" name="fid" nillable="true" type="xsd:int"/>
1547+ <xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
1548+ </xsd:sequence>
1549+ </xsd:extension>
1550+ </xsd:complexContent>
1551+ </xsd:complexType>
1552+ <xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
1553+ </xsd:schema>
1554+ """ .encode ('UTF-8' ))
1555+
1556+ last_url = sanitize (endpoint , '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=60,-80,80,-50,urn:ogc:def:crs:EPSG::4326' )
1557+ getfeature_response = """
1558+ <wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs"
1559+ xmlns:gml="http://www.opengis.net/gml"
1560+ xmlns:my="http://my"
1561+ numberOfFeatures="2" timeStamp="2016-03-25T14:51:48.998Z">
1562+ <gml:featureMembers>
1563+ <my:typename gml:id="typename.200">
1564+ <my:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos>70 -65</gml:pos></gml:Point></my:geometryProperty>
1565+ <my:fid>2</my:fid>
1566+ </my:typename>
1567+ <my:typename gml:id="typename.400">
1568+ <my:geometryProperty><gml:Point srsName="urn:ogc:def:crs:EPSG::4326"><gml:pos>71 -64</gml:pos></gml:Point></my:geometryProperty>
1569+ <my:fid>4</my:fid>
1570+ </my:typename>
1571+ </gml:featureMembers>
1572+ </wfs:FeatureCollection>""" .encode ('UTF-8' )
1573+ with open (last_url , 'wb' ) as f :
1574+ f .write (getfeature_response )
1575+
1576+ last_url = sanitize (endpoint , '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326&BBOX=50,-90,90,-40,urn:ogc:def:crs:EPSG::4326' )
1577+ with open (last_url , 'wb' ) as f :
1578+ f .write (getfeature_response )
1579+
1580+ vl = QgsVectorLayer ("url='http://" + endpoint + "' typename='my:typename' restrictToRequestBBOX=1" , 'test' , 'WFS' )
1581+ # First request with declared extent in metadata
1582+ extent = QgsRectangle (- 80 , 60 , - 50 , 80 )
1583+ request = QgsFeatureRequest ().setFilterRect (extent )
1584+ self .assertEqual (len ([f for f in vl .getFeatures (request )]), 2 )
1585+ reference = QgsGeometry .fromRect (QgsRectangle (- 65 , 70 , - 64 , 71 ))
1586+ vl_extent = QgsGeometry .fromRect (vl .extent ())
1587+ assert QgsGeometry .compare (vl_extent .asPolygon ()[0 ], reference .asPolygon ()[0 ], 0.00001 ), 'Expected {}, got {}' .format (reference .asWkt (), vl_extent .asWkt ())
1588+
1589+ # Second request: zoomed out
1590+ extent = QgsRectangle (- 90 , 50 , - 40 , 90 )
1591+ request = QgsFeatureRequest ().setFilterRect (extent )
1592+ self .assertEqual (len ([f for f in vl .getFeatures (request )]), 2 )
1593+ vl_extent = QgsGeometry .fromRect (vl .extent ())
1594+ assert QgsGeometry .compare (vl_extent .asPolygon ()[0 ], reference .asPolygon ()[0 ], 0.00001 ), 'Expected {}, got {}' .format (reference .asWkt (), vl_extent .asWkt ())
1595+
15081596 def testWFS20TruncatedResponse (self ):
15091597 """Test WFS 2.0 truncatedResponse"""
15101598
0 commit comments