I want to make a buffer on the start or end point of the line and not the line itself.
Is there some thing in QGIS python plugin development that can get me the points?
pyqgisqgis-processing
I want to make a buffer on the start or end point of the line and not the line itself.
Is there some thing in QGIS python plugin development that can get me the points?
NOTE I edited the code because the questioner preferred to choose the track and the points he wanted to measure. The update in the code is the possibility to create a number of point output layers equal to the number of the line features but, if selected in the main dialog, this number could be lower.
I propose a solution using PyQGIS. My idea was creating a certain number of temporary points along the line and then using the nearest neighbor of them from each point of the input points (i.e. your Blackpoints) for measuring the distance from the start/end of the line.
Before posting the code, I need to do some remarks:
step
, which is simply the spatial interval for the creation of the temporary points (remember that the accuracy of the result heavily depend from this parameter!);The code will return a point memory layer which stores the same geometries and attributes of the input layer, plus two additional fields:
"DIST_START"
, which stores the distance from the start of the line;"DIST_END"
, which stores the distance from the end of the line.This is the code:
##Points=vector point
##Only_use_selected_points=boolean False
##Line=vector line
##Only_use_selected_lines=boolean False
##step=number 1
from qgis.core import *
from qgis.PyQt.QtCore import QVariant
layer1 = processing.getObject(Points)
crs = layer1.crs().toWkt()
layer2 = processing.getObject(Line)
if Only_use_selected_lines:
line_feats = layer2.selectedFeatures()
else:
line_feats = layer2.getFeatures()
for ft in line_feats:
index = QgsSpatialIndex()
tmp_points = {}
line_geom = ft.geometry()
len = line_geom.length()
current = 0
# This layer contains all the points created along the line (it isn't an output)
temp_pts = QgsVectorLayer('Point?crs='+ crs, 'temp_pts' , 'memory')
prov = temp_pts.dataProvider()
# Uncomment the next line if you want to see the 'temp_pts' layer
#QgsMapLayerRegistry.instance().addMapLayer(temp_pts)
while current < len:
point = line_geom.interpolate(current) # Create a point along the line at the current distance
fet = QgsFeature()
fet.setGeometry(point)
(result, feat) = prov.addFeatures([fet])
tmp_points[feat[0].id()] = current
index.insertFeature(feat[0])
current += step # Increase the distance by the step provided
# This layer is the final output which stores the distances from the closest point along the line and the start/end of the line
out = 'output_%s' % (ft.id())
output = QgsVectorLayer('Point?crs='+ crs, out, 'memory')
prov2 = output.dataProvider()
fields = layer1.pendingFields() # Fields from the input layer
fields.append(QgsField('DIST_START', QVariant.Double, '', 10, 3)) # Name for the new field in the output layer
fields.append(QgsField('DIST_END', QVariant.Double, '', 10, 3)) # Name for the new field in the output layer
prov2.addAttributes(fields) # Add input layer fields to the outLayer
output.updateFields()
if Only_use_selected_points:
point_feats = layer1.selectedFeatures()
else:
point_feats = layer1.getFeatures()
for feat in point_feats:
geom = feat.geometry()
attrs = feat.attributes()
nearest = index.nearestNeighbor(geom.asPoint(), 1)
dist_start = tmp_points[nearest[0]]
attrs.append(dist_start)
dist_end = len - tmp_points[nearest[0]]
attrs.append(dist_end)
outGeom = QgsFeature()
outGeom.setGeometry(geom)
outGeom.setAttributes(attrs)
prov2.addFeatures([outGeom])
# Add the 'output' layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(output)
Now let's give an example. Starting from these sample layers (14 points, the line has a length of about 16 km) and using a step
of 1 m:
I obtain this point layer:
with this Attribute Table (the values are expressed in meters):
I believe QgsCircularString.fromTwoPointsAndCenter()
is a method that could help you construct those arcs.
It creates a circular string consisting of a single arc which represents the curve from one point to another with a specified center point.
I've updated your example using the mentioned method and also addressed your problem of converting the exterior line to a polygon.
# coord for curved section
start_lat, start_lon = 39.08626748, -2.66563606
end_lat, end_lon = 39.20366816, -2.51489454
# coord for squared section
point3_lat, point3_lon = 39.11293834, -2.41907255
point4_lat, point4_lon = 38.98554723, -2.55822285
# center coord
centre_lat, centre_lon = 39.13921171, -2.58290392
# Create the arc segment
arc = QgsCircularString.fromTwoPointsAndCenter(
QgsPoint(start_lon, start_lat),
QgsPoint(end_lon, end_lat),
QgsPoint(centre_lon, centre_lat)
)
# Creates the polygon segment
line = QgsLineString(
[QgsPoint(end_lon, end_lat), QgsPoint(point3_lon, point3_lat),
QgsPoint(point4_lon, point4_lat), QgsPoint(start_lon, start_lat)]
)
# join both segments together
curve = line.toCurveType()
curve.addCurve(arc)
# create polygon geometry from exterior line
polygon = QgsPolygon()
polygon.setExteriorRing(curve)
geom = QgsGeometry(polygon)
# Create polygon feature
poly_feat = QgsFeature()
poly_feat.setGeometry(polygon)
# Create a memory layer
layer = QgsVectorLayer(
"Polygon?crs=epsg:4326&field=id:integer&field=name:string(20)&index=yes",
"temporary_points",
"memory"
)
# Add the layer
QgsProject.instance().addMapLayer(layer)
# Add the feature to the layer provider
pr = layer.dataProvider()
pr.addFeatures([poly_feat])
# Update extent
layer.updateExtents()
# Zoom to extent
iface.mapCanvas().setExtent(layer.extent())
iface.mapCanvas().refresh()
Best Answer
You can use the following code to get the start and end points of your line layer and loads this as a memory point layer:
Result:
You can then use this memory layer to create buffers around the points.