3

I want to select lines (bahnstrecken) within a polygon (bundesland). My goal is a selection shown in the following screenshot, which I did manually. Before I used two tools: I converted the polygons to lines and splitted the linies (bahnstrecken) with the new line-layer which was formerly a polygon. The result is a lines layer, which geoemtries end exactly at the polygon borders.

enter image description here

The problem is this: When I use different spatial query methods (intersects, contains, touches, fully contains) I never get the result I want. How can I reach the selection result shown in the first screenshot above? I think I should use the WITHIN method, but the results of the spatial selection tool appear quite strange to me:

INTERSECT:

enter image description here

TOUCHES:

enter image description here

OVERLAPS:

enter image description here

WITHIN:

enter image description here

1 Answer 1

1

I surmise from your comments and your layer names that you want to calculate the total length of railway lines in each State, so if you are open to a pyqgis solution I can suggest the following approach which does not require splitting or trying to create selections of your line features. This will simply calculate the parts of the line geometries which intersect each polygon region and sum their length.

You can run this this code directly with a polygon layer of States and a line layer of railway lines with out modifying or splitting either one.

A few notes:

  • It is important that both layers are in a projected CRS (which I see that both of yours already are).
  • I tested this with some data which looks similar to yours. A polygon layer with 17 regions and a line layer of roads with 3043 features. The code took around 25 seconds to complete so it's not instantaneous. I have used a spatial index to speed up the querying, but calculating the geometry intersection seems to be the computationally heavy part.

Paste the following code into an editor in the Python console and run. Make sure that the layer names match yours (I used layer names 'staaten' for states and 'bahnstrecken' for railways but if yours are different you will just need to change the first 2 lines of the script). Also please forgive my rusty German in the print statement at the end of the script.

line_layer = QgsProject().instance().mapLayersByName('bahnstrecken')[0]
polygon_layer = QgsProject().instance().mapLayersByName('staaten')[0]

line_feats = [f for f in line_layer.getFeatures()]

idx = QgsSpatialIndex(line_layer.getFeatures())

for p in polygon_layer.getFeatures():
    total_line_length = 0
    candidates = idx.intersects(p.geometry().boundingBox())
    candidate_feats = [f for f in line_feats if f.id() in candidates]
    for l in candidate_feats:
        intersect = l.geometry().intersection(p.geometry())
        total_line_length += intersect.length()
    length_km = round((total_line_length/1000), 2)
    print('Staat {}: enthält {}km Bahnstrecke'.format(p.id(), length_km))

My test data looks like this:

enter image description here

Example of output:

enter image description here

1
  • Thank you Ben! This works perfectly and the result makes sense. Commented Sep 22, 2020 at 8:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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