Merge pull request #3725 from arnaud-morvan/processing_geometry_predicate

[processing] Remove parameter geometry predicate
This commit is contained in:
volaya 2016-12-13 15:58:16 +01:00 committed by GitHub
commit 0035c97f5b
11 changed files with 103 additions and 246 deletions

View File

@ -426,7 +426,7 @@ class Grass7Algorithm(GeoAlgorithm):
command += ' ' + param.name
elif isinstance(param, ParameterSelection):
idx = int(param.value)
command += ' ' + param.name + '=' + str(param.options[idx])
command += ' ' + param.name + '=' + str(param.options[idx][1])
elif isinstance(param, ParameterString):
command += ' ' + param.name + '="' + str(param.value) + '"'
elif isinstance(param, ParameterPoint):

View File

@ -276,7 +276,7 @@ class OTBAlgorithm(GeoAlgorithm):
elif isinstance(param, ParameterSelection):
commands.append(param.name)
idx = int(param.value)
commands.append(str(param.options[idx]))
commands.append(str(param.options[idx][1]))
elif isinstance(param, ParameterBoolean):
if param.value:
commands.append(param.name)

View File

@ -29,7 +29,7 @@ __revision__ = '$Format:%H$'
from qgis.core import QgsFeatureRequest
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterGeometryPredicate
from processing.core.parameters import ParameterSelection
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector
@ -48,13 +48,24 @@ class ExtractByLocation(GeoAlgorithm):
self.group, self.i18n_group = self.trAlgorithm('Vector selection tools')
self.tags = self.tr('extract,filter,location,intersects,contains,within')
self.predicates = (
('intersects', self.tr('intersects')),
('contains', self.tr('contains')),
('disjoint', self.tr('disjoint')),
('equals', self.tr('equals')),
('touches', self.tr('touches')),
('overlaps', self.tr('overlaps')),
('within', self.tr('within')),
('crosses', self.tr('crosses')))
self.addParameter(ParameterVector(self.INPUT,
self.tr('Layer to select from')))
self.addParameter(ParameterVector(self.INTERSECT,
self.tr('Additional layer (intersection layer)')))
self.addParameter(ParameterGeometryPredicate(self.PREDICATE,
self.tr('Geometric predicate'),
left=self.INPUT, right=self.INTERSECT))
self.addParameter(ParameterSelection(self.PREDICATE,
self.tr('Geometric predicate'),
self.predicates,
multiple=True))
self.addParameter(ParameterNumber(self.PRECISION,
self.tr('Precision'),
0.0, None, 0.0))
@ -98,20 +109,7 @@ class ExtractByLocation(GeoAlgorithm):
except:
pass # already removed
else:
if predicate == 'intersects':
res = tmpGeom.intersects(geom)
elif predicate == 'contains':
res = tmpGeom.contains(geom)
elif predicate == 'equals':
res = tmpGeom.equals(geom)
elif predicate == 'touches':
res = tmpGeom.touches(geom)
elif predicate == 'overlaps':
res = tmpGeom.overlaps(geom)
elif predicate == 'within':
res = tmpGeom.within(geom)
elif predicate == 'crosses':
res = tmpGeom.crosses(geom)
res = getattr(tmpGeom, predicate)(geom)
if res:
selectedSet.append(feat.id())
break

View File

@ -35,7 +35,6 @@ from qgis.core import QgsGeometry, QgsFeatureRequest
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.parameters import ParameterSelection
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterGeometryPredicate
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector
@ -59,6 +58,16 @@ class SelectByLocation(GeoAlgorithm):
self.name, self.i18n_name = self.trAlgorithm('Select by location')
self.group, self.i18n_group = self.trAlgorithm('Vector selection tools')
self.predicates = (
('intersects', self.tr('intersects')),
('contains', self.tr('contains')),
('disjoint', self.tr('disjoint')),
('equals', self.tr('equals')),
('touches', self.tr('touches')),
('overlaps', self.tr('overlaps')),
('within', self.tr('within')),
('crosses', self.tr('crosses')))
self.methods = [self.tr('creating new selection'),
self.tr('adding to current selection'),
self.tr('removing from current selection')]
@ -67,9 +76,10 @@ class SelectByLocation(GeoAlgorithm):
self.tr('Layer to select from')))
self.addParameter(ParameterVector(self.INTERSECT,
self.tr('Additional layer (intersection layer)')))
self.addParameter(ParameterGeometryPredicate(self.PREDICATE,
self.tr('Geometric predicate'),
left=self.INPUT, right=self.INTERSECT))
self.addParameter(ParameterSelection(self.PREDICATE,
self.tr('Geometric predicate'),
self.predicates,
multiple=True))
self.addParameter(ParameterNumber(self.PRECISION,
self.tr('Precision'),
0.0, None, 0.0))
@ -118,20 +128,7 @@ class SelectByLocation(GeoAlgorithm):
except:
pass # already removed
else:
if predicate == 'intersects':
res = tmpGeom.intersects(geom)
elif predicate == 'contains':
res = tmpGeom.contains(geom)
elif predicate == 'equals':
res = tmpGeom.equals(geom)
elif predicate == 'touches':
res = tmpGeom.touches(geom)
elif predicate == 'overlaps':
res = tmpGeom.overlaps(geom)
elif predicate == 'within':
res = tmpGeom.within(geom)
elif predicate == 'crosses':
res = tmpGeom.crosses(geom)
res = getattr(tmpGeom, predicate)(geom)
if res:
selectedSet.append(feat.id())
break

View File

@ -37,7 +37,6 @@ from qgis.core import Qgis, QgsFields, QgsField, QgsFeature, QgsGeometry, NULL,
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterGeometryPredicate
from processing.core.parameters import ParameterNumber
from processing.core.parameters import ParameterSelection
from processing.core.parameters import ParameterString
@ -64,6 +63,15 @@ class SpatialJoin(GeoAlgorithm):
self.name, self.i18n_name = self.trAlgorithm('Join attributes by location')
self.group, self.i18n_group = self.trAlgorithm('Vector general tools')
self.predicates = (
('intersects', self.tr('intersects')),
('contains', self.tr('contains')),
('equals', self.tr('equals')),
('touches', self.tr('touches')),
('overlaps', self.tr('overlaps')),
('within', self.tr('within')),
('crosses', self.tr('crosses')))
self.summarys = [
self.tr('Take attributes of the first located feature'),
self.tr('Take summary of intersecting features')
@ -78,12 +86,10 @@ class SpatialJoin(GeoAlgorithm):
self.tr('Target vector layer')))
self.addParameter(ParameterVector(self.JOIN,
self.tr('Join vector layer')))
predicates = list(ParameterGeometryPredicate.predicates)
predicates.remove('disjoint')
self.addParameter(ParameterGeometryPredicate(self.PREDICATE,
self.tr('Geometric predicate'),
left=self.TARGET, right=self.JOIN,
enabledPredicates=predicates))
self.addParameter(ParameterSelection(self.PREDICATE,
self.tr('Geometric predicate'),
self.predicates,
multiple=True))
self.addParameter(ParameterNumber(self.PRECISION,
self.tr('Precision'),
0.0, None, 0.0))
@ -174,20 +180,7 @@ class SpatialJoin(GeoAlgorithm):
res = False
for predicate in predicates:
if predicate == 'intersects':
res = inGeom.intersects(inGeomB)
elif predicate == 'contains':
res = inGeom.contains(inGeomB)
elif predicate == 'equals':
res = inGeom.equals(inGeomB)
elif predicate == 'touches':
res = inGeom.touches(inGeomB)
elif predicate == 'overlaps':
res = inGeom.overlaps(inGeomB)
elif predicate == 'within':
res = inGeom.within(inGeomB)
elif predicate == 'crosses':
res = inGeom.crosses(inGeomB)
res= getattr(inGeom, predicate)(inGeomB)
if res:
break

View File

@ -1063,18 +1063,25 @@ class ParameterSelection(Parameter):
elif isinstance(self.options, str):
self.options = self.options.split(";")
# compute options as (value, text)
options = []
for i, option in enumerate(self.options):
if option is None or isinstance(option, basestring):
options.append((i, option))
else:
options.append((option[0], option[1]))
self.options = options
self.values = [option[0] for option in options]
self.value = None
if default is not None:
try:
self.default = int(default)
except:
self.default = 0
self.value = self.default
self.setValue(self.default)
def setValue(self, value):
if value is None:
if not self.optional:
return False
self.value = 0
self.value = None
return True
if isinstance(value, list):
@ -1082,22 +1089,32 @@ class ParameterSelection(Parameter):
return False
values = []
for v in value:
if v in self.values:
values.append(v)
continue
try:
n = int(v)
values.append(n)
v = int(v)
except:
pass
if not v in self.values:
return False
values.append(v)
if not self.optional and len(values) == 0:
return False
self.value = values
return True
else:
try:
n = int(value)
self.value = n
if value in self.values:
self.value = value
return True
try:
value = int(value)
except:
pass
if not value in self.values:
return False
self.value = value
return True
@classmethod
def fromScriptCode(self, line):
@ -1510,46 +1527,6 @@ class ParameterVector(ParameterDataObject):
[dataobjects.TYPE_VECTOR_POLYGON], isOptional)
class ParameterGeometryPredicate(Parameter):
predicates = ('intersects',
'contains',
'disjoint',
'equals',
'touches',
'overlaps',
'within',
'crosses')
def __init__(self, name='', description='', left=None, right=None,
optional=False, enabledPredicates=None):
Parameter.__init__(self, name, description, None, optional)
self.left = left
self.right = right
self.value = None
self.enabledPredicates = enabledPredicates
if self.enabledPredicates is None:
self.enabledPredicates = self.predicates
def getValueAsCommandLineParameter(self):
return str(self.value)
def setValue(self, value):
if value is None:
if not self.optional:
return False
self.value = None
return True
elif len(value) == 0 and not self.optional:
return False
if isinstance(value, str):
self.value = value.split(';') # relates to ModelerAlgorithm.resolveValue
else:
self.value = value
return True
paramClasses = [c for c in list(sys.modules[__name__].__dict__.values()) if isclass(c) and issubclass(c, Parameter)]

View File

@ -38,7 +38,6 @@ from qgis.core import QgsApplication
from qgis.gui import QgsMessageBar
from processing.gui.BatchOutputSelectionPanel import BatchOutputSelectionPanel
from processing.gui.GeometryPredicateSelectionPanel import GeometryPredicateSelectionPanel
from processing.core.parameters import ParameterFile
from processing.core.parameters import ParameterRaster
@ -50,7 +49,6 @@ from processing.core.parameters import ParameterPoint
from processing.core.parameters import ParameterSelection
from processing.core.parameters import ParameterFixedTable
from processing.core.parameters import ParameterMultipleInput
from processing.core.parameters import ParameterGeometryPredicate
pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(

View File

@ -1,123 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
PredicatePanel.py
---------------------
Date : January 2015
Copyright : (C) 2015 by Arnaud Morvan
Email : arnaud dot morvan at camptocamp dot com
Contributors : Arnaud Morvan
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
from builtins import range
__author__ = 'Arnaud Morvan'
__date__ = 'January 2015'
__copyright__ = '(C) 2015, Arnaud Morvan'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from qgis.PyQt import uic
from qgis.PyQt.QtWidgets import QCheckBox
from qgis.core import Qgis, QgsVectorLayer, QgsWkbTypes, QgsWkbTypes
from processing.core.parameters import ParameterGeometryPredicate
pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
os.path.join(pluginPath, 'ui', 'widgetGeometryPredicateSelector.ui'))
class GeometryPredicateSelectionPanel(BASE, WIDGET):
unusablePredicates = {
QgsWkbTypes.PointGeometry: {
QgsWkbTypes.PointGeometry: ('touches', 'crosses'),
QgsWkbTypes.LineGeometry: ('equals', 'contains', 'overlaps'),
QgsWkbTypes.PolygonGeometry: ('equals', 'contains', 'overlaps')
},
QgsWkbTypes.LineGeometry: {
QgsWkbTypes.PointGeometry: ('equals', 'within', 'overlaps'),
QgsWkbTypes.LineGeometry: [],
QgsWkbTypes.PolygonGeometry: ('equals', 'contains', 'overlaps')
},
QgsWkbTypes.PolygonGeometry: {
QgsWkbTypes.PointGeometry: ('equals', 'within', 'overlaps'),
QgsWkbTypes.LineGeometry: ('equals', 'within', 'overlaps'),
QgsWkbTypes.PolygonGeometry: ('crosses')
}
}
def __init__(self,
enabledPredicated=ParameterGeometryPredicate.predicates,
rows=4):
super(GeometryPredicateSelectionPanel, self).__init__(None)
self.setupUi(self)
self.enabledPredicated = enabledPredicated
self.leftLayer = None
self.rightLayer = None
self.setRows(rows)
self.updatePredicates()
def onLeftLayerChange(self):
sender = self.sender()
self.leftLayer = sender.itemData(sender.currentIndex())
self.updatePredicates()
def onRightLayerChange(self):
sender = self.sender()
self.rightLayer = sender.itemData(sender.currentIndex())
self.updatePredicates()
def updatePredicates(self):
if (isinstance(self.leftLayer, QgsVectorLayer)
and isinstance(self.rightLayer, QgsVectorLayer)):
leftType = self.leftLayer.geometryType()
rightType = self.rightLayer.geometryType()
unusablePredicates = self.unusablePredicates[leftType][rightType]
else:
unusablePredicates = []
for predicate in ParameterGeometryPredicate.predicates:
widget = self.getWidget(predicate)
widget.setEnabled(predicate in self.enabledPredicated
and predicate not in unusablePredicates)
def setRows(self, rows):
widgets = []
for predicate in ParameterGeometryPredicate.predicates:
widget = self.getWidget(predicate)
self.gridLayout.removeWidget(widget)
widgets.append(widget)
for i in range(0, len(widgets)):
widget = widgets[i]
self.gridLayout.addWidget(widget, i % rows, i / rows)
def getWidget(self, predicate):
return self.findChild(QCheckBox, predicate + 'Box')
def value(self):
values = []
for predicate in ParameterGeometryPredicate.predicates:
widget = self.getWidget(predicate)
if widget.isEnabled() and widget.isChecked():
values.append(predicate)
return values
def setValue(self, values):
if values:
for predicate in ParameterGeometryPredicate.predicates:
widget = self.getWidget(predicate)
widget.setChecked(predicate in values)
return True

View File

@ -68,9 +68,10 @@ class MultipleInputDialog(BASE, WIDGET):
def populateList(self):
model = QStandardItemModel()
for i, option in enumerate(self.options):
item = QStandardItem(option)
item.setCheckState(Qt.Checked if i in self.selectedoptions else Qt.Unchecked)
for value, text in self.options:
item = QStandardItem(text)
item.setData(value, Qt.UserRole)
item.setCheckState(Qt.Checked if value in self.selectedoptions else Qt.Unchecked)
item.setCheckable(True)
model.appendRow(item)
@ -82,7 +83,7 @@ class MultipleInputDialog(BASE, WIDGET):
for i in range(model.rowCount()):
item = model.item(i)
if item.checkState() == Qt.Checked:
self.selectedoptions.append(i)
self.selectedoptions.append(item.data(Qt.UserRole))
QDialog.accept(self)
def reject(self):

View File

@ -73,7 +73,6 @@ from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel
from processing.gui.FixedTablePanel import FixedTablePanel
from processing.gui.ExtentSelectionPanel import ExtentSelectionPanel
from processing.gui.StringInputPanel import StringInputPanel
from processing.gui.GeometryPredicateSelectionPanel import GeometryPredicateSelectionPanel
DIALOG_STANDARD = 'standard'
@ -662,22 +661,23 @@ class SelectionWidgetWrapper(WidgetWrapper):
return MultipleInputPanel(options=self.param.options)
else:
widget = QComboBox()
widget.addItems(self.param.options)
for option in self.param.options:
widget.addItem(option[1], option[0])
if self.param.default:
widget.setCurrentIndex(self.param.default)
widget.setCurrentIndex(widget.findData(self.param.default))
return widget
def setValue(self, value):
if self.param.multiple:
self.widget.setSelectedItems(value)
else:
self.widget.setCurrentIndex(int(value))
self.widget.setCurrentIndex(self.widget.findData(value))
def value(self):
if self.param.multiple:
return self.widget.selectedoptions
else:
return self.widget.currentIndex()
return self.widget.currentData()
class VectorWidgetWrapper(WidgetWrapper):

View File

@ -272,7 +272,7 @@ class ParameterSelectionTest(unittest.TestCase):
parameter = ParameterSelection('myName', 'myDesc', ['option1', 'option2', 'option3'], default=0.0)
self.assertEqual(parameter.value, 0)
parameter = ParameterSelection('myName', 'myDesc', ['option1', 'option2', 'option3'], default='a')
self.assertEqual(parameter.value, 0)
self.assertEqual(parameter.value, None)
def testOptional(self):
optionalParameter = ParameterSelection('myName', 'myDesc', ['option1', 'option2', 'option3'], default=0, optional=True)
@ -280,7 +280,7 @@ class ParameterSelectionTest(unittest.TestCase):
optionalParameter.setValue(1)
self.assertEqual(optionalParameter.value, 1)
self.assertTrue(optionalParameter.setValue(None))
self.assertEqual(optionalParameter.value, 0)
self.assertEqual(optionalParameter.value, None)
requiredParameter = ParameterSelection('myName', 'myDesc', ['option1', 'option2', 'option3'], default=0, optional=False)
self.assertEqual(requiredParameter.value, 0)
@ -289,6 +289,22 @@ class ParameterSelectionTest(unittest.TestCase):
self.assertFalse(requiredParameter.setValue(None))
self.assertEqual(requiredParameter.value, 1)
def testTupleOptions(self):
options = (
('o1', 'option1'),
('o2', 'option2'),
('o3', 'option3'))
optionalParameter = ParameterSelection('myName', 'myDesc', options, default='o1')
self.assertEqual(optionalParameter.value, 'o1')
optionalParameter.setValue('o2')
self.assertEqual(optionalParameter.value, 'o2')
optionalParameter = ParameterSelection('myName', 'myDesc', options, default=['o1', 'o2'], multiple=True)
self.assertEqual(optionalParameter.value, ['o1', 'o2'])
optionalParameter.setValue(['o2'])
self.assertEqual(optionalParameter.value, ['o2'])
class ParameterFileTest(unittest.TestCase):