Skip to content
Permalink
Browse files
Remove 'precision' option from spatial relation processing algs
Rationale:
- the correct use for this option is unclear, and users are
mistakenly using it as a 'tolerance' option
- it's very likely to generate invalid geometries as a result
of the snapping, causing unreliable results

Given these substantial issues, it's safer to remove this
option and require that users who need the snap to grid
precision change explicitly do this via an extra model
step before running the algorithm.
  • Loading branch information
nyalldawson committed Sep 8, 2017
1 parent 24a4ab7 commit a9f4540
Show file tree
Hide file tree
Showing 4 changed files with 4 additions and 40 deletions.
@@ -42,7 +42,6 @@ class ExtractByLocation(QgisAlgorithm):
INPUT = 'INPUT'
INTERSECT = 'INTERSECT'
PREDICATE = 'PREDICATE'
PRECISION = 'PRECISION'
OUTPUT = 'OUTPUT'

def tags(self):
@@ -73,9 +72,6 @@ def initAlgorithm(self, config=None):
self.tr('Geometric predicate'),
self.predicates,
multiple=True))
self.addParameter(ParameterNumber(self.PRECISION,
self.tr('Precision'),
0.0, None, 0.0))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Extracted (location)')))

def name(self):
@@ -90,7 +86,6 @@ def processAlgorithm(self, parameters, context, feedback):
filename = self.getParameterValue(self.INTERSECT)
selectLayer = QgsProcessingUtils.mapLayerFromString(filename, context)
predicates = self.getParameterValue(self.PREDICATE)
precision = self.getParameterValue(self.PRECISION)

index = QgsProcessingUtils.createSpatialIndex(layer, context)

@@ -106,13 +101,12 @@ def processAlgorithm(self, parameters, context, feedback):
features = QgsProcessingUtils.getFeatures(selectLayer, context)
total = 100.0 / selectLayer.featureCount() if selectLayer.featureCount() else 0
for current, f in enumerate(features):
geom = vector.snapToPrecision(f.geometry(), precision)
geom = f.geometry()
bbox = geom.boundingBox()
bbox.grow(0.51 * precision)
intersects = index.intersects(bbox)
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for feat in layer.getFeatures(request):
tmpGeom = vector.snapToPrecision(feat.geometry(), precision)
tmpGeom = feat.geometry()
res = False
for predicate in predicates:
if predicate == 'disjoint':
@@ -31,12 +31,10 @@

from qgis.core import (QgsGeometry,
QgsFeatureRequest,
QgsProcessingUtils,
QgsProcessing,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
QgsProcessingParameterNumber,
QgsProcessingOutputVectorLayer,
QgsVectorLayer)

@@ -52,7 +50,6 @@ class SelectByLocation(QgisAlgorithm):
INPUT = 'INPUT'
INTERSECT = 'INTERSECT'
PREDICATE = 'PREDICATE'
PRECISION = 'PRECISION'
METHOD = 'METHOD'
OUTPUT = 'OUTPUT'

@@ -98,9 +95,6 @@ def initAlgorithm(self, config=None):
allowMultiple=True, defaultValue=[0]))
self.addParameter(QgsProcessingParameterFeatureSource(self.INTERSECT,
self.tr('By comparing to the features from'), types=[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterNumber(self.PRECISION,
self.tr('Precision'), type=QgsProcessingParameterNumber.Double,
minValue=0.0, defaultValue=0.0))
self.addParameter(QgsProcessingParameterEnum(self.METHOD,
self.tr('Modify current selection by'),
options=self.methods, defaultValue=0))
@@ -121,7 +115,6 @@ def processAlgorithm(self, parameters, context, feedback):
# we actually test the reverse of what the user wants (allowing us
# to prepare geometries and optimise the algorithm)
predicates = [self.reversed_predicates[self.predicates[i][0]] for i in self.parameterAsEnums(parameters, self.PREDICATE, context)]
precision = self.parameterAsDouble(parameters, self.PRECISION, context)

if 'disjoint' in predicates:
disjoint_set = select_layer.allFeatureIds()
@@ -142,7 +135,6 @@ def processAlgorithm(self, parameters, context, feedback):
engine = QgsGeometry.createGeometryEngine(f.geometry().geometry())
engine.prepareGeometry()
bbox = f.geometry().boundingBox()
bbox.grow(0.51 * precision)

request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setFilterRect(bbox).setSubsetOfAttributes([])
for test_feat in select_layer.getFeatures(request):
@@ -50,7 +50,6 @@ class SpatialJoin(QgisAlgorithm):
TARGET = "TARGET"
JOIN = "JOIN"
PREDICATE = "PREDICATE"
PRECISION = 'PRECISION'
SUMMARY = "SUMMARY"
STATS = "STATS"
KEEP = "KEEP"
@@ -93,9 +92,6 @@ def initAlgorithm(self, config=None):
self.tr('Geometric predicate'),
self.predicates,
multiple=True))
self.addParameter(ParameterNumber(self.PRECISION,
self.tr('Precision'),
0.0, None, 0.0))
self.addParameter(ParameterSelection(self.SUMMARY,
self.tr('Attribute summary'), self.summarys))
self.addParameter(ParameterString(self.STATS,
@@ -115,7 +111,6 @@ def processAlgorithm(self, parameters, context, feedback):
target = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.TARGET), context)
join = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.JOIN), context)
predicates = self.getParameterValue(self.PREDICATE)
precision = self.getParameterValue(self.PRECISION)

summary = self.getParameterValue(self.SUMMARY) == 1
keep = self.getParameterValue(self.KEEP) == 1
@@ -169,20 +164,19 @@ def processAlgorithm(self, parameters, context, feedback):
for c, f in enumerate(features):
atMap1 = f.attributes()
outFeat.setGeometry(f.geometry())
inGeom = vector.snapToPrecision(f.geometry(), precision)
inGeom = f.geometry()
none = True
joinList = []
if inGeom.type() == QgsWkbTypes.PointGeometry:
bbox = inGeom.buffer(10, 2).boundingBox()
else:
bbox = inGeom.boundingBox()
bbox.grow(0.51 * precision)
joinList = index.intersects(bbox)
if len(joinList) > 0:
count = 0
for i in joinList:
inFeatB = mapP2[i]
inGeomB = vector.snapToPrecision(inFeatB.geometry(), precision)
inGeomB = inFeatB.geometry()

res = False
for predicate in predicates:
@@ -216,22 +216,6 @@ def checkMinDistance(point, index, distance, points):
return True


def snapToPrecision(geom, precision):
snapped = QgsGeometry(geom)
if precision == 0.0:
return snapped

i = 0
p = snapped.vertexAt(i)
while p.x() != 0.0 and p.y() != 0.0:
x = round(p.x() / precision, 0) * precision
y = round(p.y() / precision, 0) * precision
snapped.moveVertex(x, y, i)
i = i + 1
p = snapped.vertexAt(i)
return QgsPointXY(snapped.x(), snapped.y())


NOGEOMETRY_EXTENSIONS = [
u'csv',
u'dbf',

0 comments on commit a9f4540

Please sign in to comment.