I got a line shapefile and a point shapefile (or a CSV file containing coordinates of the point), and I want to clip this line feature by those point in the 'nearest' way.
So far, I have always used edit
function in QGIS GUI to clip line feature manually:
I am wondering are there QGIS built-in functions could handle this problem (for example, input line feature and point feature, output cut line feature (new file is even better).)? or could I cut line feature in this way using PYQGIS command or user-written python function (even better)?
Update#1
I used PyQGIS code from @xunilk to split line feature showed in figure above, and named my input line and point shapefile as 'my_border' and 'my_point' respectively, but the results looked like:
The result is not what I expect.
Besides, I followed the way in the answer provided by @Micha in splitting a lines layer using points, trying to split line by GRASS.
Because my point is not on the line, I have to run the following module to get 'error point':
v.distance
v.patch
v.clean
I think there are no problem use the first 2 module, but after I used v.clean
:
v.clean --overwrite input=tcall@nl output=tcerrpoint tool=break
I just got a line feature, not error points:
Were there something I missed or did wrong in the procedure?
Update#2
I used the updated code provided by @xunilk, which trying to handle multiple cut points. I still used my line and point shapefile as input layers, and the following figures are their attribute tables.
The output is:
Still not what I expected, I am wondering that maybe it outputted strange line feature because the input line has too many segments.
If the PyQGIS script being modified to capable of handling selected feature of input line shapefile, and before run the script we select the nearest line segment to one point, maybe the output can be right?
Update#3
This time I edited input line shapefile 'my_border' to a line with only one attribute:
and used PyQGIS code in the edited answer of @xunilk:
registry = QgsMapLayerRegistry.instance()
my_border = registry.mapLayersByName('my_border')
my_point = registry.mapLayersByName('my_point')
feats_my_border = [ feat for feat in my_border[0].getFeatures() ]
feats_my_points = [ feat for feat in my_point[0].getFeatures() ]
points = [ feat.geometry().asPoint() for feat in feats_my_points ]
my_tuplas = []
for point in points:
tupla = feats_my_border[0].geometry().closestSegmentWithContext(point)
my_tuplas.append(tupla)
my_line = [ feat.geometry().asPolyline() for feat in feats_my_border ]
new_line = []
k = 0
try:
for i, line in enumerate(my_line):
for j, point in enumerate(line):
new_line.append(point)
if j == my_tuplas[k][2] - 1:
new_line.append(my_tuplas[k][1])
k += 1
except IndexError:
pass
k = 0
lines = [ [] for i in range(len(points) + 1) ]
epsg = my_border[0].crs().postgisSrid()
uri = "LineString?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"
mem_layer = QgsVectorLayer(uri,
'split_line',
'memory')
prov = mem_layer.dataProvider()
try:
for point in new_line:
lines[k].append(point)
if point == my_tuplas[k][1]:
k += 1
lines[k].append(point)
except IndexError:
pass
for i, line in enumerate(lines):
feat = QgsFeature()
feat.setAttributes([i])
feat.setGeometry(QgsGeometry.fromPolyline(line))
prov.addFeatures([feat])
QgsMapLayerRegistry.instance().addMapLayer(mem_layer)
This time the attribute of output 'split_line' looked rational because I inputted 8 point to cut line:
But no matter what I tried including set layer CRS
, zoom to layer
, show in overview
, etc., I could not see this output file. Besides, I saved this output file as a new ESRI shapefile and checked its size, which was 208 kb (input 'my_border.shp' is 21 kb), all seemed to be rational, but I just can't see the output.