You can use the fact that all lines are parallel and calculate the angle of the lines. Define a main angle (e.g. from the first line), and if a line does not fit that main angle draw the buffer on the otherside.
lines = iface.activeLayer()
interval = 250
for i,line in enumerate(lines.getFeatures()):
if i == 0:
myangle = line.geometry().angleAtVertex(0)
if line.geometry().angleAtVertex(0) == myangle:
buffer = line.geometry().singleSidedBuffer(interval, 1, Qgis.BufferSide.Left)
else:
buffer = line.geometry().singleSidedBuffer(interval, 1, Qgis.BufferSide.Right)
You could add a tolerance if they are not perfectly parallel. E.g. by using math.isclose()
with a relative or absolute tolerance:
import math
lines = iface.activeLayer()
interval = 250
tolerance = 11 # absolute, degrees for easier use
# you can also use a relative tolerance, e.g. math.isclose(a,b,rel_tol = tolerance)
for i,line in enumerate(lines.getFeatures()):
if i == 0:
myangle = math.degrees(line.geometry().angleAtVertex(0))
if math.isclose(math.degrees(line.geometry().angleAtVertex(0)), myangle, abs_tol = tolerance):
buffer = line.geometry().singleSidedBuffer(interval, 1, Qgis.BufferSide.Left)
else:
buffer = line.geometry().singleSidedBuffer(interval, 1, Qgis.BufferSide.Right)
Or do some more fancy stuff like:
import math
import random
lines = iface.activeLayer()
buffers = QgsVectorLayer('Polygon?crs={}'.format(lines.crs().authid()), 'Buffers' , "memory")
buffers.dataProvider().addAttributes([QgsField("sourcefeatid", QVariant.Int), QgsField("lineangle", QVariant.Double), QgsField("mainaingle", QVariant.Double), QgsField("parallel", QVariant.String), QgsField("bufferside", QVariant.String)])
buffersize = 250 # in CRS units
tolerance = 22.5 # absolute; degrees for easier use; you can also use a relative tolerance, e.g. math.isclose(a,b,rel_tol = tolerance)
mainangle = None # define your mainangle here
bufferdirection = None # define a main-direction
# or do some fancy stuff to determine the bufferside
if not bufferdirection or bufferdirection not in ['west','east']:
bufferdirection = random.choice(['west','east'])
for i,line in enumerate(lines.getFeatures()):
polyline = line.geometry().asPolyline()
startpoint, endpoint = QgsPoint(polyline[0]), QgsPoint(polyline[-1])
if i == 0:
if mainangle is None:
mainangle = math.degrees(QgsGeometryUtils.lineAngle(startpoint.x(), startpoint.y(), endpoint.x(), endpoint.y()))
reversemainangle = (mainangle+180)%360
lineangle = math.degrees(QgsGeometryUtils.lineAngle(startpoint.x(), startpoint.y(), endpoint.x(), endpoint.y()))
print(lineangle)
if bufferdirection == 'west':
if 0 < lineangle <= 180:
print('Buffer left')
bufferside = Qgis.BufferSide.Left
else:
print('Buffer right')
bufferside = Qgis.BufferSide.Right
elif bufferdirection == 'east':
if 0 < lineangle <= 180:
print('Buffer right')
bufferside = Qgis.BufferSide.Right
else:
print('Buffer left')
bufferside = Qgis.BufferSide.Left
drawbuffer = True
if math.isclose(mainangle,lineangle,abs_tol=tolerance):
parallelattr = 'parallel'
print(parallelattr)
buffer = line.geometry().singleSidedBuffer(buffersize, 1, bufferside)
elif math.isclose(reversemainangle,lineangle,abs_tol=tolerance):
parallelattr = 'reverse parallel'
print(parallelattr)
buffer = line.geometry().singleSidedBuffer(buffersize, 1, bufferside)
else:
parallelattr = 'not parallel'
print(parallelattr)
buffer = line.geometry().singleSidedBuffer(buffersize, 1, bufferside)
drawbuffer = False
if drawbuffer:
with edit(buffers):
newbuffer = QgsFeature()
newbuffer.setAttributes([line.id(),lineangle,mainangle,parallelattr,str(bufferside)])
newbuffer.setGeometry(buffer)
buffers.dataProvider().addFeature(newbuffer)
QgsProject.instance().addMapLayer(buffers)