5

I'm working on a processing script that selects features by their spatial relationship. The result is a virtual layer:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# define interface
##Virtual Layers (QGIS 2.x)=group
##Select by spatial relationship=name
##Layer_to_select_from=vector
##Spatial_relationship=selection Intersects;Contains;Within;Touches;Overlaps;Equals
##Intersection_layer=vector
##True_or_false=selection True;False
##Snapping_tolerance=string 1e-5
##Output_layer=string vl_
##Output_unique_identifier_column=string gid
##Output_geometry_column=string geom

from qgis.core import QgsVectorLayer, QgsMapLayerRegistry

# get input parameters from GUI
inlayer_select = processing.getObject(Layer_to_select_from)

spatial_rs = Spatial_relationship
if spatial_rs == 0:
    spatial_rs = 'ST_Intersects'
elif spatial_rs == 1:
    spatial_rs = 'ST_Contains'
elif spatial_rs == 2:
    spatial_rs = 'ST_Within'
elif spatial_rs == 3:
    spatial_rs = 'ST_Touches'
elif spatial_rs == 4:
    spatial_rs = 'ST_Overlaps'
elif spatial_rs == 5:
    spatial_rs = 'ST_Equals'

inlayer_intersection = processing.getObject(Intersection_layer)

t_or_f = True_or_false
snaptolerance = Snapping_tolerance

outlayer = Output_layer
outuic = Output_unique_identifier_column
outgeom = Output_geometry_column

# get geometry type and coordinate reference system from input layer ('Layer to select from')
ingeomtype = inlayer_select.geometryType()
if ingeomtype == 0:
    ingeomtype = 'point'
elif ingeomtype == 1:
    ingeomtype = 'linestring'
elif ingeomtype == 2:
    ingeomtype = 'polygon'

incrs = inlayer_select.crs().authid()
incrs = incrs[5:]

# create query
query_t = """SELECT
    DISTINCT('{0}'.rowid) AS '{4}',
    '{0}'.geometry AS '{5}'/*:{6}:{7}*/
FROM '{0}', '{2}'
WHERE {1}(ST_Snap('{0}'.geometry, '{2}'.geometry, {3}), ST_Snap('{2}'.geometry, '{0}'.geometry, {3}));
""".format( inlayer_select.name(), spatial_rs, inlayer_intersection.name(), snaptolerance, outuic, outgeom, ingeomtype, incrs )

query_f = """SELECT
    '{0}'.rowid AS '{4}',
    '{0}'.geometry AS '{5}'/*:{6}:{7}*/
FROM '{0}' LEFT JOIN '{2}'
ON {1}(ST_Snap('{0}'.geometry, '{2}'.geometry, {3}), ST_Snap('{2}'.geometry, '{0}'.geometry, {3}))
WHERE '{2}'.rowid IS NULL;
""".format( inlayer_select.name(), spatial_rs, inlayer_intersection.name(), snaptolerance, outuic, outgeom, ingeomtype, incrs )

if t_or_f == 0:
    query = query_t
elif t_or_f == 1:
    query = query_f

# run query and add layer to map
vlayer = QgsVectorLayer( "?query={}".format(query), outlayer, "virtual" )
QgsMapLayerRegistry.instance().addMapLayer(vlayer)

enter image description here

Here is a short screencast if someone wants to see the script in action: http://hub.qgis.org/attachments/10767/select_by_spatial_relationship.mp4

At the moment the GUI misses an 'Attributes to keep' option. As far as I know there is no parameter type to list the attributes of an input layer as checkboxes (see http://docs.qgis.org/2.14/en/docs/user_manual/processing/scripts.html and http://hub.qgis.org/issues/16348). Would an input field (type string), that is designed to accept a comma separted list, do the job? Can anyone help me to implement an 'Attributes to keep' option in a smooth way?

  • 1
    Perhaps the answer from Germán Carrillo in this post might help: Geoprocessing LineIntersections QGIS Python where he made a script which allows you to keep a field from both layers. – Joseph Mar 20 '17 at 11:07
  • 1
    Implementing a 'Keep all fields' checkbox is a good idea, but a comma separated list would be more flexible (see 'PostGIS geoprocessing tools' plugin). – eclipsed_by_the_moon Mar 23 '17 at 18:15
1

Fields of the input layer

enter image description here

If you use field instead of string

##Layer_to_select_from=vector
##Output_unique_identifier_column= field Layer_to_select_from

You can choose one of the fields of the input layer (only one)

enter image description here

0

Perhaps this can be solved by some Python similar to this:

string = 'att-1, att_2, att3,'

# remove space
string = string.replace(' ', '')

# remove ',' at start/end
if string[:1] == ',':
    string = string[1:]

if string[len(string)-1] == ',':
    string = string[:-1]

# convert string in list
string = string.split(',')

# put attributes in quotes
string = ['\"' + string + '\"' for string in string]

# print attributes
print ',\n' + ',\n'.join(string)

#SQL: ... AS "geom"
,
"att-1",
"att_2",
"att3"
#SQL: FROM ...

Aliases are not supported yet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.