Port Topocolor algorithm to new API

This commit is contained in:
Nyall Dawson 2017-08-04 00:03:41 +10:00
parent ec4df6c019
commit 7132faa974
4 changed files with 76 additions and 59 deletions

View File

@ -133,6 +133,7 @@ from .SplitWithLines import SplitWithLines
from .SumLines import SumLines
from .SymmetricalDifference import SymmetricalDifference
from .TextToFloat import TextToFloat
from .TopoColors import TopoColor
from .Translate import Translate
from .TruncateTable import TruncateTable
from .Union import Union
@ -169,7 +170,6 @@ from .ZonalStatistics import ZonalStatistics
# from .RasterCalculator import RasterCalculator
# from .ExecuteSQL import ExecuteSQL
# from .FindProjection import FindProjection
# from .TopoColors import TopoColor
# from .EliminateSelection import EliminateSelection
pluginPath = os.path.normpath(os.path.join(
@ -206,7 +206,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# IdwInterpolation(), TinInterpolation(),
# RasterCalculator(),
# ExecuteSQL(), FindProjection(),
# TopoColor(), EliminateSelection()
# EliminateSelection()
# ]
algs = [AddTableField(),
Aspect(),
@ -301,6 +301,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
SumLines(),
SymmetricalDifference(),
TextToFloat(),
TopoColor(),
Translate(),
TruncateTable(),
Union(),

View File

@ -31,33 +31,31 @@ import sys
from collections import defaultdict
from qgis.core import (QgsApplication,
QgsField,
from qgis.core import (QgsField,
QgsFeatureSink,
QgsGeometry,
QgsSpatialIndex,
QgsPointXY,
NULL,
QgsProcessingUtils)
QgsProcessing,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber,
QgsProcessingParameterEnum,
QgsProcessingParameterFeatureSink)
from qgis.PyQt.QtCore import (QVariant)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import (ParameterVector,
ParameterSelection,
ParameterNumber)
from processing.core.outputs import OutputVector
from processing.tools import dataobjects
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class TopoColor(QgisAlgorithm):
INPUT_LAYER = 'INPUT_LAYER'
INPUT = 'INPUT'
MIN_COLORS = 'MIN_COLORS'
MIN_DISTANCE = 'MIN_DISTANCE'
BALANCE = 'BALANCE'
OUTPUT_LAYER = 'OUTPUT_LAYER'
OUTPUT = 'OUTPUT'
def tags(self):
return self.tr('topocolor,colors,graph,adjacent,assign').split(',')
@ -69,21 +67,23 @@ class TopoColor(QgisAlgorithm):
super().__init__()
def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(ParameterNumber(self.MIN_COLORS,
self.tr('Minimum number of colors'), 1, 1000, 4))
self.addParameter(ParameterNumber(self.MIN_DISTANCE,
self.tr('Minimum distance between features'), 0.0, 999999999.0, 0.0))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterNumber(self.MIN_COLORS,
self.tr('Minimum number of colors'), minValue=1, maxValue=1000, defaultValue=4))
self.addParameter(QgsProcessingParameterNumber(self.MIN_DISTANCE,
self.tr('Minimum distance between features'), type=QgsProcessingParameterNumber.Double,
minValue=0.0, maxValue=999999999.0, defaultValue=0.0))
balance_by = [self.tr('By feature count'),
self.tr('By assigned area'),
self.tr('By distance between colors')]
self.addParameter(ParameterSelection(
self.addParameter(QgsProcessingParameterEnum(
self.BALANCE,
self.tr('Balance color assignment'),
balance_by, default=0))
options=balance_by, defaultValue=0))
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Colored'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Colored'), QgsProcessing.TypeVectorPolygon))
def name(self):
return 'topologicalcoloring'
@ -92,18 +92,18 @@ class TopoColor(QgisAlgorithm):
return self.tr('Topological coloring')
def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
min_colors = self.getParameterValue(self.MIN_COLORS)
balance_by = self.getParameterValue(self.BALANCE)
min_distance = self.getParameterValue(self.MIN_DISTANCE)
source = self.parameterAsSource(parameters, self.INPUT, context)
min_colors = self.parameterAsInt(parameters, self.MIN_COLORS, context)
balance_by = self.parameterAsEnum(parameters, self.BALANCE, context)
min_distance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
fields = layer.fields()
fields = source.fields()
fields.append(QgsField('color_id', QVariant.Int))
writer = self.getOutputFromName(
self.OUTPUT_LAYER).getVectorWriter(fields, layer.wkbType(), layer.crs(), context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, source.wkbType(), source.sourceCrs())
features = {f.id(): f for f in QgsProcessingUtils.getFeatures(layer, context)}
features = {f.id(): f for f in source.getFeatures()}
topology, id_graph = self.compute_graph(features, feedback, min_distance=min_distance)
feature_colors = ColoringAlgorithm.balanced(features,
@ -118,6 +118,9 @@ class TopoColor(QgisAlgorithm):
total = 20.0 / len(features)
current = 0
for feature_id, input_feature in features.items():
if feedback.isCanceled():
break
output_feature = input_feature
attributes = input_feature.attributes()
if feature_id in feature_colors:
@ -126,11 +129,11 @@ class TopoColor(QgisAlgorithm):
attributes.append(NULL)
output_feature.setAttributes(attributes)
writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
current += 1
feedback.setProgress(80 + int(current * total))
del writer
return {self.OUTPUT: dest_id}
@staticmethod
def compute_graph(features, feedback, create_id_graph=False, min_distance=0):
@ -148,6 +151,9 @@ class TopoColor(QgisAlgorithm):
i = 0
for feature_id, f in features_with_geometry.items():
if feedback.isCanceled():
break
g = f.geometry()
if min_distance > 0:
g = g.buffer(min_distance, 5)
@ -172,6 +178,9 @@ class TopoColor(QgisAlgorithm):
feedback.setProgress(int(i * total))
for feature_id, f in features_with_geometry.items():
if feedback.isCanceled():
break
if feature_id not in s.node_edge:
s.add_edge(feature_id, None)
@ -206,6 +215,9 @@ class ColoringAlgorithm:
i = 0
for (feature_id, n) in sorted_by_count:
if feedback.isCanceled():
break
# first work out which already assigned colors are adjacent to this feature
adjacent_colors = set()
for neighbour in graph.node_edge[feature_id]:
@ -240,6 +252,9 @@ class ColoringAlgorithm:
# loop through these, and calculate the minimum distance from this feature to the nearest
# feature with each assigned color
for other_feature_id, c in other_features.items():
if feedback.isCanceled():
break
other_geometry = features[other_feature_id].geometry()
other_centroid = QgsPointXY(other_geometry.centroid().geometry())

View File

@ -41,7 +41,7 @@
<ogr:right>8.23935</ogr:right>
<ogr:bottom>-3.11331</ogr:bottom>
<ogr:id>11</ogr:id>
<ogr:color_id>4</ogr:color_id>
<ogr:color_id>5</ogr:color_id>
</ogr:topocolor_polys>
</gml:featureMember>
<gml:featureMember>
@ -52,7 +52,7 @@
<ogr:right>8.23935</ogr:right>
<ogr:bottom>-6.11331</ogr:bottom>
<ogr:id>12</ogr:id>
<ogr:color_id>5</ogr:color_id>
<ogr:color_id>4</ogr:color_id>
</ogr:topocolor_polys>
</gml:featureMember>
<gml:featureMember>

View File

@ -2598,32 +2598,33 @@ tests:
name: expected/polygon_from_extent.gml
type: vector
# - algorithm: qgis:topologicalcoloring
# name: Topological coloring
# params:
# INPUT_LAYER:
# name: custom/adjacent_polys.gml
# type: vector
# MIN_COLORS: 4
# results:
# OUTPUT_LAYER:
# name: expected/topocolor_polys.gml
# type: vector
#
# - algorithm: qgis:topologicalcoloring
# name: Topological coloring w/ min distance
# params:
# BALANCE: '0'
# INPUT_LAYER:
# name: custom/adjacent_polys.gml
# type: vector
# MIN_COLORS: 4
# MIN_DISTANCE: 4.0
# results:
# OUTPUT_LAYER:
# name: expected/topocolor_polys_min_dist.gml
# type: vector
#
- algorithm: qgis:topologicalcoloring
name: Topological coloring
params:
BALANCE: 0
INPUT:
name: custom/adjacent_polys.gml
type: vector
MIN_COLORS: 4
results:
OUTPUT:
name: expected/topocolor_polys.gml
type: vector
- algorithm: qgis:topologicalcoloring
name: Topological coloring w/ min distance
params:
BALANCE: 0
INPUT:
name: custom/adjacent_polys.gml
type: vector
MIN_COLORS: 4
MIN_DISTANCE: 4.0
results:
OUTPUT:
name: expected/topocolor_polys_min_dist.gml
type: vector
- algorithm: qgis:regularpoints
name: Regular point with standard extent
params: