Skip to content

Commit facf7a2

Browse files
authored
Merge pull request #7007 from arnaud-morvan/server_filter_and_bbox
[server][wfs] Apply BBOX inside And using filterRect
2 parents a525b2d + 12a7be7 commit facf7a2

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

src/server/services/wfs/qgswfsutils.cpp

+41
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,47 @@ namespace QgsWfs
153153
request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags );
154154
return request;
155155
}
156+
// Apply BBOX through filterRect even inside an And to use spatial index
157+
else if ( filterElem.firstChildElement().tagName() == QLatin1String( "And" ) &&
158+
!filterElem.firstChildElement().firstChildElement( QLatin1String( "BBOX" ) ).isNull() )
159+
{
160+
QDomElement childElem = filterElem.firstChildElement().firstChildElement();
161+
while ( !childElem.isNull() )
162+
{
163+
QDomElement childFilterElement = filterElem.ownerDocument().createElement( QLatin1String( "Filter" ) );
164+
childFilterElement.appendChild( childElem.cloneNode( true ) );
165+
QgsFeatureRequest childRequest = parseFilterElement( typeName, childFilterElement );
166+
if ( childElem.tagName() == QLatin1String( "BBOX" ) )
167+
{
168+
if ( request.filterRect().isEmpty() )
169+
{
170+
request.setFilterRect( childRequest.filterRect() );
171+
}
172+
else
173+
{
174+
request.setFilterRect( request.filterRect().intersect( &childRequest.filterRect() ) );
175+
}
176+
}
177+
else
178+
{
179+
if ( !request.filterExpression() )
180+
{
181+
request.setFilterExpression( childRequest.filterExpression()->expression() );
182+
}
183+
else
184+
{
185+
QgsExpressionNode *opLeft = request.filterExpression()->rootNode()->clone();
186+
QgsExpressionNode *opRight = childRequest.filterExpression()->rootNode()->clone();
187+
std::unique_ptr<QgsExpressionNodeBinaryOperator> node = qgis::make_unique<QgsExpressionNodeBinaryOperator>( QgsExpressionNodeBinaryOperator::boAnd, opLeft, opRight );
188+
QgsExpression expr( node->dump() );
189+
request.setFilterExpression( expr );
190+
}
191+
}
192+
childElem = childElem.nextSiblingElement();
193+
}
194+
request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags );
195+
return request;
196+
}
156197
else
157198
{
158199
std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem ) );

tests/src/python/test_qgsserver_wfs.py

+27
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,33 @@ def test_getfeature_post(self):
252252
"""
253253
tests.append(('sortby_post', sortTemplate.format("")))
254254

255+
andBboxTemplate = """<?xml version="1.0" encoding="UTF-8"?>
256+
<wfs:GetFeature service="WFS" version="1.0.0" {} xmlns:wfs="http://www.opengis.net/wfs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
257+
<wfs:Query typeName="testlayer" srsName="EPSG:3857" xmlns:feature="http://www.qgis.org/gml">
258+
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
259+
<ogc:And>
260+
<ogc:BBOX>
261+
<ogc:PropertyName>geometry</ogc:PropertyName>
262+
<gml:Envelope xmlns:gml="http://www.opengis.net/gml">
263+
<gml:lowerCorner>890555.92634619 5465442.18332275</gml:lowerCorner>
264+
<gml:upperCorner>1001875.41713946 5621521.48619207</gml:upperCorner>
265+
</gml:Envelope>
266+
</ogc:BBOX>
267+
<ogc:PropertyIsGreaterThan>
268+
<ogc:PropertyName>id</ogc:PropertyName>
269+
<ogc:Literal>1</ogc:Literal>
270+
</ogc:PropertyIsGreaterThan>
271+
<ogc:PropertyIsLessThan>
272+
<ogc:PropertyName>id</ogc:PropertyName>
273+
<ogc:Literal>3</ogc:Literal>
274+
</ogc:PropertyIsLessThan>
275+
</ogc:And>
276+
</ogc:Filter>
277+
</wfs:Query>
278+
</wfs:GetFeature>
279+
"""
280+
tests.append(('bbox_inside_and_post', andBboxTemplate.format("")))
281+
255282
for id, req in tests:
256283
self.wfs_getfeature_post_compare(id, req)
257284

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Content-Type: text/xml; subtype=gml/2.1.2; charset=utf-8
2+
3+
<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:qgs="http://www.qgis.org/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://www.qgis.org/gml ?MAP=/home/dhont/3liz_dev/QGIS/qgis_rldhont/tests/testdata/qgis_server/test_project_wfs.qgs&amp;SRSNAME=EPSG:3857&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=testlayer&amp;OUTPUTFORMAT=XMLSCHEMA">
4+
<gml:boundedBy>
5+
<gml:Box srsName="EPSG:4326">
6+
<gml:coordinates cs="," ts=" ">8,44 9,45</gml:coordinates>
7+
</gml:Box>
8+
</gml:boundedBy>
9+
<gml:featureMember>
10+
<qgs:testlayer fid="testlayer.1">
11+
<gml:boundedBy>
12+
<gml:Box srsName="EPSG:3857">
13+
<gml:coordinates cs="," ts=" ">913214.67407005,5606017.87425818 913214.67407005,5606017.87425818</gml:coordinates>
14+
</gml:Box>
15+
</gml:boundedBy>
16+
<qgs:geometry>
17+
<Point xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
18+
<coordinates xmlns="http://www.opengis.net/gml" cs="," ts=" ">913214.67407005,5606017.87425818</coordinates>
19+
</Point>
20+
</qgs:geometry>
21+
<qgs:id>2</qgs:id>
22+
<qgs:name>two</qgs:name>
23+
<qgs:utf8nameè>two àò</qgs:utf8nameè>
24+
</qgs:testlayer>
25+
</gml:featureMember>
26+
</wfs:FeatureCollection>

0 commit comments

Comments
 (0)