Skip to content

Commit

Permalink
Port Offset line, Orthogonalize and Pole of Inaccessibility to new API
Browse files Browse the repository at this point in the history
Improvements:
- Fix handling of multiline outputs for Offset Line algorithm
  • Loading branch information
nyalldawson committed Jul 16, 2017
1 parent 261391d commit 9cbc8cc
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 235 deletions.
76 changes: 41 additions & 35 deletions python/plugins/processing/algs/qgis/OffsetLine.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,22 @@

import os

from qgis.core import (QgsApplication,
QgsWkbTypes,
QgsFeatureSink,
QgsProcessingUtils)
from qgis.core import (QgsFeatureSink,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber,
QgsProcessingParameterEnum,
QgsProcessingParameterFeatureSink)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
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 OffsetLine(QgisAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
OUTPUT_LAYER = 'OUTPUT_LAYER'
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
DISTANCE = 'DISTANCE'
SEGMENTS = 'SEGMENTS'
JOIN_STYLE = 'JOIN_STYLE'
Expand All @@ -57,23 +55,29 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(ParameterNumber(self.DISTANCE,
self.tr('Distance'), default=10.0))
self.addParameter(ParameterNumber(self.SEGMENTS,
self.tr('Segments'), 1, default=8))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
[QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterNumber(self.DISTANCE,
self.tr('Distance'),
type=QgsProcessingParameterNumber.Double,
defaultValue=10.0))
self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS,
self.tr('Segments'),
type=QgsProcessingParameterNumber.Integer,
minValue=1, defaultValue=8))
self.join_styles = [self.tr('Round'),
'Mitre',
'Bevel']
self.addParameter(ParameterSelection(
self.addParameter(QgsProcessingParameterEnum(
self.JOIN_STYLE,
self.tr('Join style'),
self.join_styles))
self.addParameter(ParameterNumber(self.MITRE_LIMIT,
self.tr('Mitre limit'), 1, default=2))
options=self.join_styles))
self.addParameter(QgsProcessingParameterNumber(self.MITRE_LIMIT,
self.tr('Mitre limit'), type=QgsProcessingParameterNumber.Double,
minValue=1, defaultValue=2))

self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Offset'), datatype=[dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Offset'), QgsProcessing.TypeVectorLine))

def name(self):
return 'offsetline'
Expand All @@ -82,31 +86,33 @@ def displayName(self):
return self.tr('Offset line')

def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)

writer = self.getOutputFromName(
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), QgsWkbTypes.LineString, layer.crs(), context)
source = self.parameterAsSource(parameters, self.INPUT, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())

distance = self.getParameterValue(self.DISTANCE)
segments = int(self.getParameterValue(self.SEGMENTS))
join_style = self.getParameterValue(self.JOIN_STYLE) + 1
miter_limit = self.getParameterValue(self.MITRE_LIMIT)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
segments = self.parameterAsInt(parameters, self.SEGMENTS, context)
join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1
miter_limit = self.parameterAsDouble(parameters, self.MITRE_LIMIT, context)

features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0

for current, input_feature in enumerate(features):
if feedback.isCanceled():
break

output_feature = input_feature
input_geometry = input_feature.geometry()
if input_geometry:
output_geometry = input_geometry.offsetCurve(distance, segments, join_style, miter_limit)
if not output_geometry:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Error calculating line offset'))

output_feature.setGeometry(output_geometry)

writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))

del writer
return {self.OUTPUT: dest_id}
70 changes: 38 additions & 32 deletions python/plugins/processing/algs/qgis/Orthogonalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,19 @@

__revision__ = '$Format:%H$'

from qgis.core import (QgsApplication,
QgsFeatureSink,
QgsProcessingUtils,
QgsProcessingParameterDefinition)
from qgis.core import (QgsFeatureSink,
QgsProcessingException,
QgsProcessing,
QgsProcessingParameterDefinition,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSink)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector, ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects


class Orthogonalize(QgisAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
OUTPUT_LAYER = 'OUTPUT_LAYER'
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
MAX_ITERATIONS = 'MAX_ITERATIONS'
DISTANCE_THRESHOLD = 'DISTANCE_THRESHOLD'
ANGLE_TOLERANCE = 'ANGLE_TOLERANCE'
Expand All @@ -54,20 +52,24 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE,
dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(ParameterNumber(self.ANGLE_TOLERANCE,
self.tr('Maximum angle tolerance (degrees)'),
0.0, 45.0, 15.0))

max_iterations = ParameterNumber(self.MAX_ITERATIONS,
self.tr('Maximum algorithm iterations'),
1, 10000, 1000)
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
[QgsProcessing.TypeVectorLine,
QgsProcessing.TypeVectorPolygon]))

self.addParameter(QgsProcessingParameterNumber(self.ANGLE_TOLERANCE,
self.tr('Maximum angle tolerance (degrees)'),
type=QgsProcessingParameterNumber.Double,
minValue=0.0, maxValue=45.0, defaultValue=15.0))

max_iterations = QgsProcessingParameterNumber(self.MAX_ITERATIONS,
self.tr('Maximum algorithm iterations'),
type=QgsProcessingParameterNumber.Integer,
minValue=1, maxValue=10000, defaultValue=1000)
max_iterations.setFlags(max_iterations.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(max_iterations)

self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Orthogonalized')))
self.addParameter(
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Orthogonalized')))

def name(self):
return 'orthogonalize'
Expand All @@ -76,27 +78,31 @@ def displayName(self):
return self.tr('Orthogonalize')

def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
max_iterations = self.getParameterValue(self.MAX_ITERATIONS)
angle_tolerance = self.getParameterValue(self.ANGLE_TOLERANCE)
writer = self.getOutputFromName(
self.OUTPUT_LAYER).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context)
source = self.parameterAsSource(parameters, self.INPUT, context)
max_iterations = self.parameterAsInt(parameters, self.MAX_ITERATIONS, context)
angle_tolerance = self.parameterAsDouble(parameters, self.ANGLE_TOLERANCE, context)

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

features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0

for current, input_feature in enumerate(features):
if feedback.isCanceled():
break

output_feature = input_feature
input_geometry = input_feature.geometry()
if input_geometry:
output_geometry = input_geometry.orthogonalize(1.0e-8, max_iterations, angle_tolerance)
if not output_geometry:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Error orthogonalizing geometry'))

output_feature.setGeometry(output_geometry)

writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))

del writer
return {self.OUTPUT: dest_id}
57 changes: 33 additions & 24 deletions python/plugins/processing/algs/qgis/PoleOfInaccessibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,29 @@

import os

from qgis.core import QgsWkbTypes, QgsField, NULL, QgsFeatureSink, QgsProcessingUtils
from qgis.core import (QgsWkbTypes,
QgsField,
NULL,
QgsFeatureSink,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSink)

from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtGui import QIcon

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector, 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 PoleOfInaccessibility(QgisAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
INPUT = 'INPUT'
TOLERANCE = 'TOLERANCE'
OUTPUT_LAYER = 'OUTPUT_LAYER'
OUTPUT = 'OUTPUT'

def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'centroids.png'))
Expand All @@ -60,12 +64,15 @@ 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.TOLERANCE,
self.tr('Tolerance (layer units)'), default=1.0, minValue=0.0))
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Point'), datatype=[dataobjects.TYPE_VECTOR_POINT]))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'),
[QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterNumber(self.TOLERANCE,
self.tr('Tolerance (layer units)'),
type=QgsProcessingParameterNumber.Double,
defaultValue=1.0, minValue=0.0))

self.addParameter(
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Point'), QgsProcessing.TypeVectorPoint))

def name(self):
return 'poleofinaccessibility'
Expand All @@ -74,25 +81,27 @@ def displayName(self):
return self.tr('Pole of Inaccessibility')

def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
tolerance = self.getParameterValue(self.TOLERANCE)
source = self.parameterAsSource(parameters, self.INPUT, context)
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)

fields = layer.fields()
fields = source.fields()
fields.append(QgsField('dist_pole', QVariant.Double))
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Point, source.sourceCrs())

writer = self.getOutputFromName(
self.OUTPUT_LAYER).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context)

features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0

for current, input_feature in enumerate(features):
if feedback.isCanceled():
break

output_feature = input_feature
input_geometry = input_feature.geometry()
if input_geometry:
output_geometry, distance = input_geometry.poleOfInaccessibility(tolerance)
if not output_geometry:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Error calculating pole of inaccessibility'))
attrs = input_feature.attributes()
attrs.append(distance)
Expand All @@ -104,7 +113,7 @@ def processAlgorithm(self, parameters, context, feedback):
attrs.append(NULL)
output_feature.setAttributes(attrs)

writer.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))

del writer
return {self.OUTPUT: dest_id}
Loading

0 comments on commit 9cbc8cc

Please sign in to comment.