Skip to content
Permalink
Browse files

Port Topocolor algorithm to new API

  • Loading branch information
nyalldawson committed Aug 3, 2017
1 parent ec4df6c commit 7132faa97470866baf09759bb17a2ecc005c5680
@@ -133,6 +133,7 @@
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 .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 @@ def getAlgs(self):
# IdwInterpolation(), TinInterpolation(),
# RasterCalculator(),
# ExecuteSQL(), FindProjection(),
# TopoColor(), EliminateSelection()
# EliminateSelection()
# ]
algs = [AddTableField(),
Aspect(),
@@ -301,6 +301,7 @@ def getAlgs(self):
SumLines(),
SymmetricalDifference(),
TextToFloat(),
TopoColor(),
Translate(),
TruncateTable(),
Union(),
@@ -31,33 +31,31 @@

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 @@ def __init__(self):
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 @@ def displayName(self):
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 @@ def processAlgorithm(self, parameters, context, feedback):
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 @@ def processAlgorithm(self, parameters, context, feedback):
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 @@ def compute_graph(features, feedback, create_id_graph=False, min_distance=0):

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 @@ def compute_graph(features, feedback, create_id_graph=False, min_distance=0):
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 @@ def balanced(features, graph, feedback, balance=0, min_colors=4):
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 @@ def balanced(features, graph, feedback, balance=0, min_colors=4):
# 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())

@@ -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>
@@ -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:

0 comments on commit 7132faa

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