29
29
from processing .core .GeoAlgorithm import GeoAlgorithm
30
30
from processing .core .parameters import ParameterSelection
31
31
from processing .core .parameters import ParameterVector
32
- from processing .core .parameters import ParameterBoolean
32
+ from processing .core .parameters import ParameterGeometryPredicate
33
33
from processing .core .outputs import OutputVector
34
34
from processing .tools import dataobjects , vector
35
35
@@ -38,83 +38,47 @@ class SelectByLocation(GeoAlgorithm):
38
38
39
39
INPUT = 'INPUT'
40
40
INTERSECT = 'INTERSECT'
41
- TOUCHES = 'TOUCHES'
42
- OVERLAPS = 'OVERLAPS'
43
- WITHIN = 'WITHIN'
41
+ PREDICATE = 'PREDICATE'
44
42
METHOD = 'METHOD'
45
43
OUTPUT = 'OUTPUT'
46
44
47
- METHODS = ['creating new selection' , 'adding to current selection' ,
45
+ METHODS = ['creating new selection' ,
46
+ 'adding to current selection' ,
48
47
'removing from current selection' ]
49
- opFlags = 0
50
- operators = {'TOUCHES' :1 ,'OVERLAPS' :2 ,'WITHIN' :4 }
51
-
52
48
53
49
def defineCharacteristics (self ):
54
50
self .name = 'Select by location'
55
51
self .group = 'Vector selection tools'
56
- self .addParameter (ParameterVector (self .INPUT , 'Layer to select from' ,
57
- [ParameterVector .VECTOR_TYPE_ANY ]))
52
+ self .addParameter (ParameterVector (self .INPUT ,
53
+ self .tr ('Layer to select from' ),
54
+ [ParameterVector .VECTOR_TYPE_ANY ]))
58
55
self .addParameter (ParameterVector (self .INTERSECT ,
59
- 'Additional layer (intersection layer)' ,
60
- [ParameterVector .VECTOR_TYPE_ANY ]))
61
- self .addParameter (ParameterBoolean (self .TOUCHES ,
62
- 'Include input features that touch the selection features' ,
63
- [True ]))
64
- self .addParameter (ParameterBoolean (self .OVERLAPS ,
65
- 'Include input features that overlap/cross the selection features' ,
66
- [True ]))
67
- self .addParameter (ParameterBoolean (self .WITHIN ,
68
- 'Include input features completely within the selection features' ,
69
- [True ]))
56
+ self .tr ('Additional layer (intersection layer)' ),
57
+ [ParameterVector .VECTOR_TYPE_ANY ]))
58
+ self .addParameter (ParameterGeometryPredicate (self .PREDICATE ,
59
+ self .tr ('Geometric predicate' ),
60
+ left = self .INPUT , right = self .INTERSECT ))
70
61
self .addParameter (ParameterSelection (self .METHOD ,
71
- 'Modify current selection by' , self .METHODS , 0 ))
72
- self .addOutput (OutputVector (self .OUTPUT , 'Selection' , True ))
62
+ self .tr ('Modify current selection by' ),
63
+ self .METHODS , 0 ))
64
+ self .addOutput (OutputVector (self .OUTPUT , self .tr ('Selection' ), True ))
73
65
74
66
def processAlgorithm (self , progress ):
75
67
filename = self .getParameterValue (self .INPUT )
76
68
inputLayer = dataobjects .getObjectFromUri (filename )
77
69
method = self .getParameterValue (self .METHOD )
78
70
filename = self .getParameterValue (self .INTERSECT )
79
71
selectLayer = dataobjects .getObjectFromUri (filename )
72
+ predicates = self .getParameterValue (self .PREDICATE )
80
73
81
74
oldSelection = set (inputLayer .selectedFeaturesIds ())
82
75
inputLayer .removeSelection ()
83
76
index = vector .spatialindex (inputLayer )
84
77
85
- def _points_op (geomA ,geomB ):
86
- return geomA .intersects (geomB )
87
-
88
- def _poly_lines_op (geomA ,geomB ):
89
- if geomA .disjoint (geomB ):
90
- return False
91
- intersects = False
92
- if self .opFlags & self .operators ['TOUCHES' ]:
93
- intersects |= geomA .touches (geomB )
94
- if not intersects and (self .opFlags & self .operators ['OVERLAPS' ]):
95
- if geomB .type () == QGis .Line or geomA .type () == QGis .Line :
96
- intersects |= geomA .crosses (geomB )
97
- else :
98
- intersects |= geomA .overlaps (geomB )
99
- if not intersects and (self .opFlags & self .operators ['WITHIN' ]):
100
- intersects |= geomA .contains (geomB )
101
- return intersects
102
-
103
- def _sp_operator ():
104
- if inputLayer .geometryType () == QGis .Point :
105
- return _points_op
106
- else :
107
- return _poly_lines_op
108
-
109
- self .opFlags = 0
110
- if self .getParameterValue (self .TOUCHES ):
111
- self .opFlags |= self .operators ['TOUCHES' ]
112
- if self .getParameterValue (self .OVERLAPS ):
113
- self .opFlags |= self .operators ['OVERLAPS' ]
114
- if self .getParameterValue (self .WITHIN ):
115
- self .opFlags |= self .operators ['WITHIN' ]
116
-
117
- sp_operator = _sp_operator ()
78
+ if 'disjoint' in predicates :
79
+ disjoinSet = []
80
+ for feat in vector .features (inputLayer ):
81
+ disjoinSet .append (feat .id ())
118
82
119
83
geom = QgsGeometry ()
120
84
selectedSet = []
@@ -123,16 +87,45 @@ def _sp_operator():
123
87
total = 100.0 / float (len (features ))
124
88
for f in features :
125
89
geom = QgsGeometry (f .geometry ())
90
+
126
91
intersects = index .intersects (geom .boundingBox ())
127
92
for i in intersects :
128
93
request = QgsFeatureRequest ().setFilterFid (i )
129
94
feat = inputLayer .getFeatures (request ).next ()
130
95
tmpGeom = QgsGeometry (feat .geometry ())
131
- if sp_operator (geom ,tmpGeom ):
132
- selectedSet .append (feat .id ())
96
+ res = False
97
+ for predicate in predicates :
98
+ if predicate == 'disjoint' :
99
+ if tmpGeom .intersects (geom ):
100
+ try :
101
+ disjoinSet .remove (feat .id ())
102
+ except :
103
+ pass # already removed
104
+ else :
105
+ if predicate == 'intersects' :
106
+ res = tmpGeom .intersects ()
107
+ elif predicate == 'contains' :
108
+ res = tmpGeom .contains (geom )
109
+ elif predicate == 'equals' :
110
+ res = tmpGeom .equals (geom )
111
+ elif predicate == 'touches' :
112
+ res = tmpGeom .touches (geom )
113
+ elif predicate == 'overlaps' :
114
+ res = tmpGeom .overlaps (geom )
115
+ elif predicate == 'within' :
116
+ res = tmpGeom .within (geom )
117
+ elif predicate == 'crosses' :
118
+ res = tmpGeom .crosses (geom )
119
+ if res :
120
+ selectedSet .append (feat .id ())
121
+ break
122
+
133
123
current += 1
134
124
progress .setPercentage (int (current * total ))
135
125
126
+ if 'disjoint' in predicates :
127
+ selectedSet = selectedSet + disjoinSet
128
+
136
129
if method == 1 :
137
130
selectedSet = list (oldSelection .union (selectedSet ))
138
131
elif method == 2 :
0 commit comments