Skip to content
Permalink
Browse files

Port Offset line, Orthogonalize and Pole of Inaccessibility to new API

Improvements:
- Fix handling of multiline outputs for Offset Line algorithm
  • Loading branch information
nyalldawson committed Jul 16, 2017
1 parent 261391d commit 9cbc8cc20f9ccb800a05fb5729ca6e24f4d23936
@@ -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'
@@ -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'
@@ -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}
@@ -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'
@@ -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'
@@ -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}
@@ -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'))
@@ -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'
@@ -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)
@@ -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}

0 comments on commit 9cbc8cc

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