@@ -1505,6 +1505,94 @@ def testWFSGetOnlyFeaturesInViewExtent(self):
1505
1505
vl_extent = QgsGeometry .fromRect (vl .extent ())
1506
1506
assert QgsGeometry .compare (vl_extent .asPolygon ()[0 ], reference .asPolygon ()[0 ], 0.00001 ), 'Expected {}, got {}' .format (reference .asWkt (), vl_extent .asWkt ())
1507
1507
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
+
1508
1596
def testWFS20TruncatedResponse (self ):
1509
1597
"""Test WFS 2.0 truncatedResponse"""
1510
1598
0 commit comments