Merge pull request #4684 from nyalldawson/processing_pt3

Add sourceExtent method to QgsFeatureSource
This commit is contained in:
Nyall Dawson 2017-06-06 21:50:45 +10:00 committed by GitHub
commit de9e70e6ba
13 changed files with 94 additions and 42 deletions

View File

@ -78,6 +78,14 @@ class QgsFeatureSource
:rtype: set of QVariant
%End
virtual QgsRectangle sourceExtent() const;
%Docstring
Returns the extent of all geometries from the source.
The base class implementation uses a non-optimised approach of looping through
all features in the source.
:rtype: QgsRectangle
%End
};

View File

@ -126,6 +126,8 @@ Bitmask of all provider's editing capabilities
virtual QgsCoordinateReferenceSystem sourceCrs() const;
virtual QgsRectangle sourceExtent() const;
virtual QString dataComment() const;
%Docstring

View File

@ -1103,10 +1103,8 @@ Synchronises with changes in the datasource
virtual QgsRectangle extent() const;
%Docstring
Return the extent of the layer
:rtype: QgsRectangle
%End
virtual QgsRectangle sourceExtent() const;
virtual QgsFields fields() const;
%Docstring

View File

@ -36,6 +36,11 @@ from qgis.core import (QgsField,
QgsFeature,
QgsWkbTypes,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputVectorLayer,
QgsProcessingParameterBoolean,
QgsProcessingParameterDefinition,
QgsFields)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@ -65,12 +70,13 @@ class ExtentFromLayer(QgisAlgorithm):
def __init__(self):
super().__init__()
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer')))
self.addParameter(ParameterBoolean(self.BY_FEATURE,
self.tr('Calculate extent for each feature separately'), False))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Extent'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer')))
self.addParameter(QgsProcessingParameterBoolean(self.BY_FEATURE,
self.tr('Calculate extent for each feature separately'), False))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extent')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Extent"), QgsProcessingParameterDefinition.TypeVectorPolygon))
def name(self):
return 'polygonfromlayerextent'
@ -79,8 +85,8 @@ class ExtentFromLayer(QgisAlgorithm):
return self.tr('Polygon from layer extent')
def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
byFeature = self.getParameterValue(self.BY_FEATURE)
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context)
fields = QgsFields()
fields.append(QgsField('MINX', QVariant.Double))
@ -94,17 +100,19 @@ class ExtentFromLayer(QgisAlgorithm):
fields.append(QgsField('HEIGHT', QVariant.Double))
fields.append(QgsField('WIDTH', QVariant.Double))
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Polygon, layer.crs(), context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, source.sourceCrs())
if byFeature:
self.featureExtent(layer, context, writer, feedback)
self.featureExtent(source, context, sink, feedback)
else:
self.layerExtent(layer, writer, feedback)
self.layerExtent(source, sink, feedback)
del writer
return {self.OUTPUT: dest_id}
def layerExtent(self, layer, writer, feedback):
rect = layer.extent()
def layerExtent(self, source, sink, feedback):
rect = source.sourceExtent()
geometry = QgsGeometry.fromRect(rect)
minx = rect.xMinimum()
miny = rect.yMinimum()
maxx = rect.xMaximum()
@ -116,9 +124,6 @@ class ExtentFromLayer(QgisAlgorithm):
area = width * height
perim = 2 * width + 2 * height
rect = [QgsPointXY(minx, miny), QgsPointXY(minx, maxy), QgsPointXY(maxx,
maxy), QgsPointXY(maxx, miny), QgsPointXY(minx, miny)]
geometry = QgsGeometry().fromPolygon([rect])
feat = QgsFeature()
feat.setGeometry(geometry)
attrs = [
@ -134,13 +139,16 @@ class ExtentFromLayer(QgisAlgorithm):
width,
]
feat.setAttributes(attrs)
writer.addFeature(feat)
sink.addFeature(feat)
def featureExtent(self, layer, context, writer, feedback):
features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
def featureExtent(self, source, context, sink, feedback):
features = source.getFeatures()
total = 100.0 / source.featureCount()
feat = QgsFeature()
for current, f in enumerate(features):
if feedback.isCanceled():
break
rect = f.geometry().boundingBox()
minx = rect.xMinimum()
miny = rect.yMinimum()
@ -171,5 +179,5 @@ class ExtentFromLayer(QgisAlgorithm):
]
feat.setAttributes(attrs)
writer.addFeature(feat)
sink.addFeature(feat)
feedback.setProgress(int(current * total))

View File

@ -79,7 +79,7 @@ from .Clip import Clip
# from .Difference import Difference
# from .Dissolve import Dissolve
# from .Intersection import Intersection
# from .ExtentFromLayer import ExtentFromLayer
from .ExtentFromLayer import ExtentFromLayer
# from .RandomSelection import RandomSelection
# from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets
# from .SelectByLocation import SelectByLocation
@ -210,7 +210,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# PolygonsToLines(), LinesToPolygons(), ExtractNodes(),
# ConvexHull(), FixedDistanceBuffer(),
# VariableDistanceBuffer(), Dissolve(), Difference(),
# Intersection(), Union(), ExtentFromLayer(),
# Intersection(), Union(),
# RandomSelection(), RandomSelectionWithinSubsets(),
# SelectByLocation(), RandomExtract(), DeleteHoles(),
# RandomExtractWithinSubsets(), ExtractByLocation(),
@ -265,7 +265,8 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
Boundary(),
BoundingBox(),
Clip(),
DeleteColumn()
DeleteColumn(),
ExtentFromLayer()
]
if hasPlotly:

View File

@ -13,7 +13,7 @@
<gml:featureMember>
<ogr:polygon_from_extent fid="polygon_from_extent.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-3 -1,6 10,6 10,-3 -1,-3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-3 10,-3 10,6 -1,6 -1,-3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:MINX>-1</ogr:MINX>
<ogr:MINY>-3</ogr:MINY>
<ogr:MAXX>10</ogr:MAXX>

View File

@ -2342,18 +2342,18 @@ tests:
# name: expected/find_projection.html
# type: file
#
# - algorithm: qgis:polygonfromlayerextent
# name: Standard polygon from layer extent
# params:
# BY_FEATURE: false
# INPUT_LAYER:
# name: polys.gml
# type: vector
# results:
# OUTPUT:
# name: expected/polygon_from_extent.gml
# type: vector
#
- algorithm: qgis:polygonfromlayerextent
name: Standard polygon from layer extent
params:
BY_FEATURE: false
INPUT_LAYER:
name: polys.gml
type: vector
results:
OUTPUT:
name: expected/polygon_from_extent.gml
type: vector
# - algorithm: qgis:topologicalcoloring
# name: Topological coloring
# params:

View File

@ -40,3 +40,20 @@ QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
return values;
}
QgsRectangle QgsFeatureSource::sourceExtent() const
{
QgsRectangle r;
QgsFeatureRequest req;
req.setSubsetOfAttributes( QgsAttributeList() );
QgsFeatureIterator it = getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
if ( f.hasGeometry() )
r.combineExtentWith( f.geometry().boundingBox() );
}
return r;
}

View File

@ -87,6 +87,13 @@ class CORE_EXPORT QgsFeatureSource
*/
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
/**
* Returns the extent of all geometries from the source.
* The base class implementation uses a non-optimised approach of looping through
* all features in the source.
*/
virtual QgsRectangle sourceExtent() const;
};
Q_DECLARE_METATYPE( QgsFeatureSource * )

View File

@ -52,6 +52,11 @@ QgsCoordinateReferenceSystem QgsVectorDataProvider::sourceCrs() const
return crs();
}
QgsRectangle QgsVectorDataProvider::sourceExtent() const
{
return extent();
}
QString QgsVectorDataProvider::dataComment() const
{
return QString();

View File

@ -159,6 +159,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
virtual QgsFields fields() const override = 0;
QgsCoordinateReferenceSystem sourceCrs() const override;
QgsRectangle sourceExtent() const override;
/**
* Return a short comment for the data that this provider is

View File

@ -879,6 +879,11 @@ QgsRectangle QgsVectorLayer::extent() const
return rect;
}
QgsRectangle QgsVectorLayer::sourceExtent() const
{
return extent();
}
QString QgsVectorLayer::subsetString() const
{
if ( !mValid || !mDataProvider )

View File

@ -1077,8 +1077,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) override SIP_FACTORY;
//! Return the extent of the layer
QgsRectangle extent() const override;
QgsRectangle sourceExtent() const override;
/**
* Returns the list of fields of this layer.