Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[processing] replace alg Eliminate with new alg EliminateSelection
* [processing] replace alg Eliminate with new alg EliminateSelection

* Deprecate Eliminate algorithm

* Expose new EliminateSelection algorithm in GUI

* Rename ouput layer

* Reflect algorithm changes in help

* Remove superfluous init method

* Simplify code, thanks Nyall

* Improve transfer of selection to processLayer

* Remove deprecated Eliminate algorithm

* Remove test for Eliminate

* Fix indentation
  • Loading branch information
Bernhard Ströbl authored and m-kuhn committed Feb 23, 2017
1 parent f45c19c commit 115ede6
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 380 deletions.
5 changes: 3 additions & 2 deletions python/plugins/processing/algs/help/qgis.yaml
Expand Up @@ -160,8 +160,9 @@ qgis:distancetonearesthub: >
qgis:dropgeometries: >
This algorithm removes any geometries from an input layer and returns a layer containing only the feature attributes.

qgis:eliminatesliverpolygons: >
This algorithm combines selected polygons of the input layer with certain adjacent polygons by erasing their common boundary. Eliminate can either use an existing selection or a logical query based on one of the layer's fields to make the selection itself. The adjacent polygon can be either the one with the largest or smallest area or the one sharing the largest common boundary with the polygon to be eliminated. Eliminate is normally used to get rid of sliver polygons, i.e. tiny polygons that are a result of polygon intersection processes where boundaries of the inputs are similar but not identical.
qgis:eliminateselectedpolygons: >
This algorithm combines selected polygons of the input layer with certain adjacent polygons by erasing their common boundary. The adjacent polygon can be either the one with the largest or smallest area or the one sharing the largest common boundary with the polygon to be eliminated. The selected features will always be eliminated whether the option "Use only selected features" is set or not.
Eliminate is normally used to get rid of sliver polygons, i.e. tiny polygons that are a result of polygon intersection processes where boundaries of the inputs are similar but not identical.

qgis:explodelines: >
This algorithm takes a lines layer and creates a new one in which each line is replaced is replaced by a set of lines representing the segments in the original line. Each line in the resulting layer contains only a start and an end point, with no intermediate nodes between them.
Expand Down
Expand Up @@ -2,10 +2,10 @@

"""
***************************************************************************
Eliminate.py
EliminateSelection.py
---------------------
Date : August 2012
Copyright : (C) 2013 by Bernhard Ströbl
Date : January 2017
Copyright : (C) 2017 by Bernhard Ströbl
Email : bernhard.stroebl@jena.de
***************************************************************************
* *
Expand All @@ -20,8 +20,8 @@
from builtins import range

__author__ = 'Bernhard Ströbl'
__date__ = 'September 2013'
__copyright__ = '(C) 2013, Bernhard Ströbl'
__date__ = 'January 2017'
__copyright__ = '(C) 2017, Bernhard Ströbl'

# This will get replaced with a git SHA1 when you do a git archive

Expand All @@ -30,33 +30,25 @@
import os

from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QLocale, QDate, QVariant

from qgis.core import QgsFeatureRequest, QgsFeature, QgsGeometry

from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.ProcessingLog import ProcessingLog
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterBoolean
from processing.core.parameters import ParameterTableField
from processing.core.parameters import ParameterString
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]


class Eliminate(GeoAlgorithm):
class EliminateSelection(GeoAlgorithm):

INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
MODE = 'MODE'
KEEPSELECTION = 'KEEPSELECTION'
ATTRIBUTE = 'ATTRIBUTE'
COMPARISONVALUE = 'COMPARISONVALUE'
COMPARISON = 'COMPARISON'

MODE_LARGEST_AREA = 0
MODE_SMALLEST_AREA = 1
Expand All @@ -66,7 +58,7 @@ def getIcon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'eliminate.png'))

def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Eliminate sliver polygons')
self.name, self.i18n_name = self.trAlgorithm('Eliminate selected polygons')
self.group, self.i18n_group = self.trAlgorithm('Vector geometry tools')

self.modes = [self.tr('Largest area'),
Expand All @@ -75,153 +67,37 @@ def defineCharacteristics(self):

self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(ParameterBoolean(self.KEEPSELECTION,
self.tr('Use current selection in input layer (works only if called from toolbox)'), False))
self.addParameter(ParameterTableField(self.ATTRIBUTE,
self.tr('Selection attribute'), self.INPUT))
self.comparisons = [
'==',
'!=',
'>',
'>=',
'<',
'<=',
'begins with',
'contains',
]
self.addParameter(ParameterSelection(self.COMPARISON,
self.tr('Comparison'), self.comparisons, default=0))
self.addParameter(ParameterString(self.COMPARISONVALUE,
self.tr('Value'), default='0'))
self.addParameter(ParameterSelection(self.MODE,
self.tr('Merge selection with the neighbouring polygon with the'),
self.modes))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Cleaned'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Eliminated'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))

def processAlgorithm(self, feedback):
inLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
boundary = self.getParameterValue(self.MODE) == self.MODE_BOUNDARY
smallestArea = self.getParameterValue(self.MODE) == self.MODE_SMALLEST_AREA
keepSelection = self.getParameterValue(self.KEEPSELECTION)
processLayer = vector.duplicateInMemory(inLayer)

if not keepSelection:
# Make a selection with the values provided
attribute = self.getParameterValue(self.ATTRIBUTE)
comparison = self.comparisons[self.getParameterValue(self.COMPARISON)]
comparisonvalue = self.getParameterValue(self.COMPARISONVALUE)

selectindex = vector.resolveFieldIndex(processLayer, attribute)
selectType = processLayer.fields()[selectindex].type()
selectionError = False

if selectType in [QVariant.Int, QVariant.LongLong, QVariant.UInt, QVariant.ULongLong]:
try:
y = int(comparisonvalue)
except ValueError:
selectionError = True
msg = self.tr('Cannot convert "%s" to integer' % str(comparisonvalue))
elif selectType == QVariant.Double:
try:
y = float(comparisonvalue)
except ValueError:
selectionError = True
msg = self.tr('Cannot convert "%s" to float' % str(comparisonvalue))
elif selectType == QVariant.String:
# 10: string, boolean
try:
y = str(comparisonvalue)
except ValueError:
selectionError = True
msg = self.tr('Cannot convert "%s" to Unicode' % str(comparisonvalue))
elif selectType == QVariant.Date:
# date
dateAndFormat = comparisonvalue.split(' ')

if len(dateAndFormat) == 1:
# QDate object
y = QLocale.system().toDate(dateAndFormat[0])

if y.isNull():
msg = self.tr('Cannot convert "%s" to date with system date format %s' % (str(dateAndFormat), QLocale.system().dateFormat()))
elif len(dateAndFormat) == 2:
y = QDate.fromString(dateAndFormat[0], dateAndFormat[1])

if y.isNull():
msg = self.tr('Cannot convert "%s" to date with format string "%s"' % (str(dateAndFormat[0]), dateAndFormat[1]))
else:
y = QDate()
msg = ''

if y.isNull():
# Conversion was unsuccessful
selectionError = True
msg += self.tr('Enter the date and the date format, e.g. "07.26.2011" "MM.dd.yyyy".')

if (comparison == 'begins with' or comparison == 'contains') \
and selectType != QVariant.String:
selectionError = True
msg = self.tr('"%s" can only be used with string fields' % comparison)

selected = []

if selectionError:
raise GeoAlgorithmExecutionException(
self.tr('Error in selection input: %s' % msg))
else:
for feature in processLayer.getFeatures():
aValue = feature.attributes()[selectindex]

if aValue is None:
continue

if selectType in [QVariant.Int, QVariant.LongLong, QVariant.UInt, QVariant.ULongLong]:
x = int(aValue)
elif selectType == QVariant.Double:
x = float(aValue)
elif selectType == QVariant.String:
# 10: string, boolean
x = str(aValue)
elif selectType == QVariant.Date:
# date
x = aValue # should be date

match = False

if comparison == '==':
match = x == y
elif comparison == '!=':
match = x != y
elif comparison == '>':
match = x > y
elif comparison == '>=':
match = x >= y
elif comparison == '<':
match = x < y
elif comparison == '<=':
match = x <= y
elif comparison == 'begins with':
match = x.startswith(y)
elif comparison == 'contains':
match = x.find(y) >= 0

if match:
selected.append(feature.id())

processLayer.selectByIds(selected)

if processLayer.selectedFeatureCount() == 0:
if inLayer.selectedFeatureCount() == 0:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('%s: (No selection in input layer "%s")' % (self.commandLineName(), self.getParameterValue(self.INPUT))))

# Keep references to the features to eliminate
featToEliminate = []
for aFeat in processLayer.selectedFeatures():
featToEliminate.append(aFeat)
selFeatIds = inLayer.selectedFeatureIds()
output = self.getOutputFromName(self.OUTPUT)
writer = output.getVectorWriter(inLayer.fields(),
inLayer.wkbType(), inLayer.crs())

# Delete all features to eliminate in processLayer (we won't save this)
for aFeat in inLayer.getFeatures():
if aFeat.id() in selFeatIds:
# Keep references to the features to eliminate
featToEliminate.append(aFeat)
else:
# write the others to output
writer.addFeature(aFeat)

# Delete all features to eliminate in processLayer
processLayer = output.layer
processLayer.startEditing()
processLayer.deleteSelectedFeatures()

# ANALYZE
if len(featToEliminate) > 0: # Prevent zero division
Expand Down Expand Up @@ -319,19 +195,8 @@ def processAlgorithm(self, feedback):
featToEliminate = featNotEliminated

# End while

# Create output
output = self.getOutputFromName(self.OUTPUT)
writer = output.getVectorWriter(processLayer.fields(),
processLayer.wkbType(), processLayer.crs())

# Write all features that are left over to output layer
iterator = processLayer.getFeatures()
for feature in iterator:
writer.addFeature(feature)

# Leave processLayer untouched
processLayer.rollBack()
if not processLayer.commitChanges():
raise GeoAlgorithmExecutionException(self.tr('Could not commit changes'))

for feature in featNotEliminated:
writer.addFeature(feature)
6 changes: 3 additions & 3 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Expand Up @@ -87,7 +87,6 @@
from .SelectByLocation import SelectByLocation
from .Union import Union
from .DensifyGeometriesInterval import DensifyGeometriesInterval
from .Eliminate import Eliminate
from .SpatialJoin import SpatialJoin
from .DeleteColumn import DeleteColumn
from .DeleteHoles import DeleteHoles
Expand Down Expand Up @@ -187,6 +186,7 @@
from .ExecuteSQL import ExecuteSQL
from .FindProjection import FindProjection
from .TopoColors import TopoColor
from .EliminateSelection import EliminateSelection

pluginPath = os.path.normpath(os.path.join(
os.path.split(os.path.dirname(__file__))[0], os.pardir))
Expand All @@ -208,7 +208,7 @@ def __init__(self):
DensifyGeometries(), DensifyGeometriesInterval(),
MultipartToSingleparts(), SinglePartsToMultiparts(),
PolygonsToLines(), LinesToPolygons(), ExtractNodes(),
Eliminate(), ConvexHull(), FixedDistanceBuffer(),
ConvexHull(), FixedDistanceBuffer(),
VariableDistanceBuffer(), Dissolve(), Difference(),
Intersection(), Union(), Clip(), ExtentFromLayer(),
RandomSelection(), RandomSelectionWithinSubsets(),
Expand Down Expand Up @@ -257,7 +257,7 @@ def __init__(self):
ShortestPathLayerToPoint(), ServiceAreaFromPoint(),
ServiceAreaFromLayer(), TruncateTable(), Polygonize(),
FixGeometry(), ExecuteSQL(), FindProjection(),
TopoColor()
TopoColor(), EliminateSelection()
]

if hasPlotly:
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/gui/menus.py
Expand Up @@ -51,7 +51,7 @@
'qgis:clip': geoprocessingToolsMenu,
'qgis:difference': geoprocessingToolsMenu,
'qgis:dissolve': geoprocessingToolsMenu,
'qgis:eliminatesliverpolygons': geoprocessingToolsMenu})
'qgis:eliminateselectedpolygons': geoprocessingToolsMenu})
geometryToolsMenu = vectorMenu + "/" + Processing.tr('G&eometry Tools')
defaultMenuEntries.update({'qgis:checkvalidity': geometryToolsMenu,
'qgis:exportaddgeometrycolumns': geometryToolsMenu,
Expand Down

This file was deleted.

This file was deleted.

0 comments on commit 115ede6

Please sign in to comment.