Skip to content
Permalink
Browse files

Merge pull request #4950 from nyalldawson/algs

Port some more algs to new API
  • Loading branch information
nyalldawson committed Aug 5, 2017
2 parents ca1abdc + 470afbe commit a5ddab6cc8e7d587f478875b731aeffd23a01d43
Showing with 2,141 additions and 675 deletions.
  1. +4 −0 python/plugins/processing/algs/help/qgis.yaml
  2. +41 −27 python/plugins/processing/algs/qgis/EliminateSelection.py
  3. +46 −35 python/plugins/processing/algs/qgis/GridLine.py
  4. +40 −52 python/plugins/processing/algs/qgis/Gridify.py
  5. +54 −54 python/plugins/processing/algs/qgis/HubDistanceLines.py
  6. +54 −56 python/plugins/processing/algs/qgis/HubDistancePoints.py
  7. +67 −46 python/plugins/processing/algs/qgis/HubLines.py
  8. +42 −39 python/plugins/processing/algs/qgis/JoinAttributes.py
  9. +108 −79 python/plugins/processing/algs/qgis/PointsToPaths.py
  10. +26 −19 python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
  11. +23 −22 python/plugins/processing/algs/qgis/RandomSelection.py
  12. +48 −54 python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py
  13. +50 −30 python/plugins/processing/algs/qgis/StatisticsByCategories.py
  14. +44 −29 python/plugins/processing/algs/qgis/TopoColors.py
  15. +4 −4 python/plugins/processing/gui/AlgorithmDialog.py
  16. +1 −1 python/plugins/processing/gui/AlgorithmDialogBase.py
  17. +8 −0 python/plugins/processing/gui/MultipleFileInputDialog.py
  18. +9 −0 python/plugins/processing/gui/MultipleInputDialog.py
  19. +14 −7 python/plugins/processing/gui/ParameterGuiUtils.py
  20. +1 −2 python/plugins/processing/gui/wrappers.py
  21. +33 −4 python/plugins/processing/tests/AlgorithmsTestBase.py
  22. +22 −0 python/plugins/processing/tests/testdata/custom/hub_points.gfs
  23. +32 −0 python/plugins/processing/tests/testdata/custom/hub_points.gml
  24. +27 −0 python/plugins/processing/tests/testdata/custom/spoke_points.gfs
  25. +63 −0 python/plugins/processing/tests/testdata/custom/spoke_points.gml
  26. +16 −0 python/plugins/processing/tests/testdata/expected/gridify_lines.gfs
  27. +46 −0 python/plugins/processing/tests/testdata/expected/gridify_lines.gml
  28. +32 −0 python/plugins/processing/tests/testdata/expected/gridify_polys.gfs
  29. +57 −0 python/plugins/processing/tests/testdata/expected/gridify_polys.gml
  30. +37 −0 python/plugins/processing/tests/testdata/expected/hub_distance_lines.gfs
  31. +95 −0 python/plugins/processing/tests/testdata/expected/hub_distance_lines.gml
  32. +37 −0 python/plugins/processing/tests/testdata/expected/hub_distance_points.gfs
  33. +95 −0 python/plugins/processing/tests/testdata/expected/hub_distance_points.gml
  34. +43 −0 python/plugins/processing/tests/testdata/expected/hub_lines.gfs
  35. +84 −0 python/plugins/processing/tests/testdata/expected/hub_lines.gml
  36. +26 −0 python/plugins/processing/tests/testdata/expected/points_to_path.gfs
  37. +21 −0 python/plugins/processing/tests/testdata/expected/points_to_path.gml
  38. +31 −0 python/plugins/processing/tests/testdata/expected/points_to_path_grouped.gfs
  39. +38 −0 python/plugins/processing/tests/testdata/expected/points_to_path_grouped.gml
  40. +31 −0 python/plugins/processing/tests/testdata/expected/points_to_path_grouped2.gfs
  41. +39 −0 python/plugins/processing/tests/testdata/expected/points_to_path_grouped2.gml
  42. +45 −0 python/plugins/processing/tests/testdata/expected/stats_by_category.gfs
  43. +42 −0 python/plugins/processing/tests/testdata/expected/stats_by_category.gml
  44. +46 −0 python/plugins/processing/tests/testdata/expected/topocolor_polys2.gfs
  45. +133 −0 python/plugins/processing/tests/testdata/expected/topocolor_polys2.gml
  46. +215 −88 python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
  47. +70 −27 python/testing/__init__.py
  48. +1 −0 src/core/qgsapplication.cpp
@@ -242,7 +242,9 @@ qgis:generatepointspixelcentroidsinsidepolygons:


qgis:hublines:
This algorithm creates hub and spoke diagrams with lines drawn from points on the Spoke Point layer to matching points in the Hub Point layer.

Determination of which hub goes with each point is based on a match between the Hub ID field on the hub points and the Spoke ID field on the spoke points.

qgis:hypsometriccurves: >
This algorithm computes hypsometric curves for an input Digital Elevation Model. Curves are produced as table files in an output folder specified by the user.
@@ -368,7 +370,9 @@ qgis:pointslayerfromtable: >
The attributes table of the resulting layer will be the input table.

qgis:pointstopath:
Converts a point layer to a line layer, by joining points in a defined order.

Points can be grouped by a field to output individual line features per group.

qgis:polarplot: >
This algorithm generates a polar plot based on the value of an input vector layer.
@@ -34,15 +34,14 @@
QgsFeature,
QgsFeatureSink,
QgsGeometry,
QgsMessageLog,
QgsProcessingUtils)
QgsProcessingException,
QgsProcessingUtils,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterEnum,
QgsProcessing,
QgsProcessingParameterFeatureSink)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector
from processing.tools import dataobjects

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]

@@ -67,16 +66,17 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.modes = [self.tr('Largest area'),
self.modes = [self.tr('Largest Area'),
self.tr('Smallest Area'),
self.tr('Largest common boundary')]
self.tr('Largest Common Boundary')]

self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(ParameterSelection(self.MODE,
self.tr('Merge selection with the neighbouring polygon with the'),
self.modes))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Eliminated'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterEnum(self.MODE,
self.tr('Merge selection with the neighbouring polygon with the'),
options=self.modes))

self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Eliminated'), QgsProcessing.TypeVectorPolygon))

def name(self):
return 'eliminateselectedpolygons'
@@ -85,29 +85,32 @@ def displayName(self):
return self.tr('Eliminate selected polygons')

def processAlgorithm(self, parameters, context, feedback):
inLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
boundary = self.getParameterValue(self.MODE) == self.MODE_BOUNDARY
smallestArea = self.getParameterValue(self.MODE) == self.MODE_SMALLEST_AREA
inLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
boundary = self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_BOUNDARY
smallestArea = self.parameterAsEnum(parameters, self.MODE, context) == self.MODE_SMALLEST_AREA

if inLayer.selectedFeatureCount() == 0:
QgsMessageLog.logMessage(self.tr('{0}: (No selection in input layer "{1}")').format(self.displayName(), self.getParameterValue(self.INPUT)),
self.tr('Processing'), QgsMessageLog.WARNING)
feedback.reportError(self.tr('{0}: (No selection in input layer "{1}")').format(self.displayName(), parameters[self.INPUT]))

featToEliminate = []
selFeatIds = inLayer.selectedFeatureIds()
output = self.getOutputFromName(self.OUTPUT)
writer = output.getVectorWriter(inLayer.fields(), inLayer.wkbType(), inLayer.crs(), context)

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
inLayer.fields(), inLayer.wkbType(), inLayer.sourceCrs())

for aFeat in inLayer.getFeatures():
if feedback.isCanceled():
break

if aFeat.id() in selFeatIds:
# Keep references to the features to eliminate
featToEliminate.append(aFeat)
else:
# write the others to output
writer.addFeature(aFeat, QgsFeatureSink.FastInsert)
sink.addFeature(aFeat, QgsFeatureSink.FastInsert)

# Delete all features to eliminate in processLayer
processLayer = output.layer
processLayer = QgsProcessingUtils.mapLayerFromString(dest_id, context)
processLayer.startEditing()

# ANALYZE
@@ -129,6 +132,9 @@ def processAlgorithm(self, parameters, context, feedback):

# Iterate over the polygons to eliminate
for i in range(len(featToEliminate)):
if feedback.isCanceled():
break

feat = featToEliminate.pop()
geom2Eliminate = feat.geometry()
bbox = geom2Eliminate.boundingBox()
@@ -145,6 +151,9 @@ def processAlgorithm(self, parameters, context, feedback):
engine.prepareGeometry()

while fit.nextFeature(selFeat):
if feedback.isCanceled():
break

selGeom = selFeat.geometry()

if engine.intersects(selGeom.geometry()):
@@ -193,7 +202,7 @@ def processAlgorithm(self, parameters, context, feedback):
if processLayer.changeGeometry(mergeWithFid, newGeom):
madeProgress = True
else:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Could not replace geometry of feature with id {0}').format(mergeWithFid))

start = start + add
@@ -207,7 +216,12 @@ def processAlgorithm(self, parameters, context, feedback):

# End while
if not processLayer.commitChanges():
raise GeoAlgorithmExecutionException(self.tr('Could not commit changes'))
raise QgsProcessingException(self.tr('Could not commit changes'))

for feature in featNotEliminated:
writer.addFeature(feature, QgsFeatureSink.FastInsert)
if feedback.isCanceled():
break

sink.addFeature(feature, QgsFeatureSink.FastInsert)

return {self.OUTPUT: dest_id}
@@ -39,14 +39,15 @@
QgsPoint,
QgsLineString,
QgsWkbTypes,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterEnum,
QgsProcessingParameterExtent,
QgsProcessingParameterNumber,
QgsProcessingParameterCrs,
QgsProcessingParameterFeatureSink,
QgsFields)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterExtent
from processing.core.parameters import ParameterNumber
from processing.core.parameters import ParameterCrs
from processing.core.outputs import OutputVector
from processing.tools import dataobjects

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]

@@ -73,19 +74,24 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterExtent(self.EXTENT,
self.tr('Grid extent'), optional=False))
self.addParameter(ParameterNumber(self.HSPACING,
self.tr('Horizontal spacing'), 0.0, 1000000000.0, default=0.0001))
self.addParameter(ParameterNumber(self.VSPACING,
self.tr('Vertical spacing'), 0.0, 1000000000.0, default=0.0001))
self.addParameter(ParameterNumber(self.HOVERLAY,
self.tr('Horizontal overlay'), 0.0, 1000000000.0, default=0.0))
self.addParameter(ParameterNumber(self.VOVERLAY,
self.tr('Vertical overlay'), 0.0, 1000000000.0, default=0.0))
self.addParameter(ParameterCrs(self.CRS, 'Grid CRS', 'EPSG:4326'))

self.addOutput(OutputVector(self.OUTPUT, self.tr('Grid'), datatype=[dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(QgsProcessingParameterExtent(self.EXTENT, self.tr('Grid extent')))

self.addParameter(QgsProcessingParameterNumber(self.HSPACING,
self.tr('Horizontal spacing'), QgsProcessingParameterNumber.Double,
0.0001, False, 0, 1000000000.0))
self.addParameter(QgsProcessingParameterNumber(self.VSPACING,
self.tr('Vertical spacing'), QgsProcessingParameterNumber.Double,
0.0001, False, 0, 1000000000.0))
self.addParameter(QgsProcessingParameterNumber(self.HOVERLAY,
self.tr('Horizontal overlay'), QgsProcessingParameterNumber.Double,
0.0, False, 0, 1000000000.0))
self.addParameter(QgsProcessingParameterNumber(self.VOVERLAY,
self.tr('Vertical overlay'), QgsProcessingParameterNumber.Double,
0.0, False, 0, 1000000000.0))

self.addParameter(QgsProcessingParameterCrs(self.CRS, 'Grid CRS', 'ProjectCrs'))

self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Grid'), type=QgsProcessing.TypeVectorLine))

def name(self):
return 'creategridlines'
@@ -94,33 +100,31 @@ def displayName(self):
return self.tr('Create grid (lines)')

def processAlgorithm(self, parameters, context, feedback):
extent = self.getParameterValue(self.EXTENT).split(',')
hSpacing = self.getParameterValue(self.HSPACING)
vSpacing = self.getParameterValue(self.VSPACING)
hOverlay = self.getParameterValue(self.HOVERLAY)
vOverlay = self.getParameterValue(self.VOVERLAY)
crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.CRS))
hSpacing = self.parameterAsDouble(parameters, self.HSPACING, context)
vSpacing = self.parameterAsDouble(parameters, self.VSPACING, context)
hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context)
vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context)

bbox = QgsRectangle(float(extent[0]), float(extent[2]),
float(extent[1]), float(extent[3]))
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
crs = self.parameterAsCrs(parameters, self.CRS, context)

width = bbox.width()
height = bbox.height()

if hSpacing <= 0 or vSpacing <= 0:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Invalid grid spacing: {0}/{1}').format(hSpacing, vSpacing))

if hSpacing <= hOverlay or vSpacing <= vOverlay:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay))

if width < hSpacing:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Horizontal spacing is too small for the covered area'))

if height < vSpacing:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Vertical spacing is too small for the covered area'))

fields = QgsFields()
@@ -131,7 +135,8 @@ def processAlgorithm(self, parameters, context, feedback):
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
fields.append(QgsField('coord', QVariant.Double, '', 24, 15))

writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.LineString, crs, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.LineString, crs)

if hOverlay > 0:
hSpace = [hSpacing - hOverlay, hOverlay]
@@ -154,6 +159,9 @@ def processAlgorithm(self, parameters, context, feedback):
count_update = count_max * 0.10
y = bbox.yMaximum()
while y >= bbox.yMinimum():
if feedback.isCanceled():
break

pt1 = QgsPoint(bbox.xMinimum(), y)
pt2 = QgsPoint(bbox.xMaximum(), y)
line = QgsLineString()
@@ -165,7 +173,7 @@ def processAlgorithm(self, parameters, context, feedback):
y,
id,
y])
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
y = y - vSpace[count % 2]
id += 1
count += 1
@@ -181,6 +189,9 @@ def processAlgorithm(self, parameters, context, feedback):
count_update = count_max * 0.10
x = bbox.xMinimum()
while x <= bbox.xMaximum():
if feedback.isCanceled():
break

pt1 = QgsPoint(x, bbox.yMaximum())
pt2 = QgsPoint(x, bbox.yMinimum())
line = QgsLineString()
@@ -192,11 +203,11 @@ def processAlgorithm(self, parameters, context, feedback):
bbox.yMinimum(),
id,
x])
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
x = x + hSpace[count % 2]
id += 1
count += 1
if int(math.fmod(count, count_update)) == 0:
feedback.setProgress(50 + int(count / count_max * 50))

del writer
return {self.OUTPUT: dest_id}

0 comments on commit a5ddab6

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