Skip to content
Permalink
Browse files

[server] Apply BBOX inside And using filterRect

In case of a WFS GetFeature request,
if BBOX is not a direct child of the Filter element,
it is applyed through an intersects_bbox function in the QgsFeatureRequest filterExpression.
This is not compiled by providers like PostgreSQL, causing the whole filter to be interpreted on QGIS side.

When interpreted on QGIS side, the srsname given in the request is not handled properly as geom_from_gml return a geometry object, projection agnostic.
This result in a very long request returning no results.

This is a workaround for this performance and srs issue in the case the BBOX is direct child of an And operator,
itself at first level in Filter element.

This is a bug fix and huge optimisation for the case we have a And with a BBOX and another condition.
  • Loading branch information
arnaud-morvan committed May 15, 2018
1 parent e6c9498 commit 12a7be799c4236fd754d0cf337322e4993aa98c5
@@ -153,6 +153,47 @@ namespace QgsWfs
request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags );
return request;
}
// Apply BBOX through filterRect even inside an And to use spatial index
else if ( filterElem.firstChildElement().tagName() == QLatin1String( "And" ) &&
!filterElem.firstChildElement().firstChildElement( QLatin1String( "BBOX" ) ).isNull() )
{
QDomElement childElem = filterElem.firstChildElement().firstChildElement();
while ( !childElem.isNull() )
{
QDomElement childFilterElement = filterElem.ownerDocument().createElement( QLatin1String( "Filter" ) );
childFilterElement.appendChild( childElem.cloneNode( true ) );
QgsFeatureRequest childRequest = parseFilterElement( typeName, childFilterElement );
if ( childElem.tagName() == QLatin1String( "BBOX" ) )
{
if ( request.filterRect().isEmpty() )
{
request.setFilterRect( childRequest.filterRect() );
}
else
{
request.setFilterRect( request.filterRect().intersect( &childRequest.filterRect() ) );
}
}
else
{
if ( !request.filterExpression() )
{
request.setFilterExpression( childRequest.filterExpression()->expression() );
}
else
{
QgsExpressionNode *opLeft = request.filterExpression()->rootNode()->clone();
QgsExpressionNode *opRight = childRequest.filterExpression()->rootNode()->clone();
std::unique_ptr<QgsExpressionNodeBinaryOperator> node = qgis::make_unique<QgsExpressionNodeBinaryOperator>( QgsExpressionNodeBinaryOperator::boAnd, opLeft, opRight );
QgsExpression expr( node->dump() );
request.setFilterExpression( expr );
}
}
childElem = childElem.nextSiblingElement();
}
request.setFlags( QgsFeatureRequest::ExactIntersect | QgsFeatureRequest::NoFlags );
return request;
}
else
{
std::shared_ptr<QgsExpression> filter( QgsOgcUtils::expressionFromOgcFilter( filterElem ) );
@@ -252,6 +252,33 @@ def test_getfeature_post(self):
"""
tests.append(('sortby_post', sortTemplate.format("")))

andBboxTemplate = """<?xml version="1.0" encoding="UTF-8"?>
<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">
<wfs:Query typeName="testlayer" srsName="EPSG:3857" xmlns:feature="http://www.qgis.org/gml">
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:BBOX>
<ogc:PropertyName>geometry</ogc:PropertyName>
<gml:Envelope xmlns:gml="http://www.opengis.net/gml">
<gml:lowerCorner>890555.92634619 5465442.18332275</gml:lowerCorner>
<gml:upperCorner>1001875.41713946 5621521.48619207</gml:upperCorner>
</gml:Envelope>
</ogc:BBOX>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
"""
tests.append(('bbox_inside_and_post', andBboxTemplate.format("")))

for id, req in tests:
self.wfs_getfeature_post_compare(id, req)

@@ -0,0 +1,26 @@
Content-Type: text/xml; subtype=gml/2.1.2; charset=utf-8

<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">
<gml:boundedBy>
<gml:Box srsName="EPSG:4326">
<gml:coordinates cs="," ts=" ">8,44 9,45</gml:coordinates>
</gml:Box>
</gml:boundedBy>
<gml:featureMember>
<qgs:testlayer fid="testlayer.1">
<gml:boundedBy>
<gml:Box srsName="EPSG:3857">
<gml:coordinates cs="," ts=" ">913214.67407005,5606017.87425818 913214.67407005,5606017.87425818</gml:coordinates>
</gml:Box>
</gml:boundedBy>
<qgs:geometry>
<Point xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
<coordinates xmlns="http://www.opengis.net/gml" cs="," ts=" ">913214.67407005,5606017.87425818</coordinates>
</Point>
</qgs:geometry>
<qgs:id>2</qgs:id>
<qgs:name>two</qgs:name>
<qgs:utf8nameè>two àò</qgs:utf8nameè>
</qgs:testlayer>
</gml:featureMember>
</wfs:FeatureCollection>

0 comments on commit 12a7be7

Please sign in to comment.
You can’t perform that action at this time.