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)