mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Port Topocolor algorithm to new API
This commit is contained in:
parent
ec4df6c019
commit
7132faa974
@ -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(),
|
||||
|
@ -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())
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user