Two sided buffer for line subsets
Based in azimuths and rectangular rotated buffers for each feature, I developed a code that produces a buffer for entire layer with desired characteristics.
from math import fabs, cos, sin, pi
registry = QgsProject.instance()
line = registry.mapLayersByName('line4')
feats_line = [ feat for feat in line[0].getFeatures() ]
n = len(feats_line)
points_line = [ feat.geometry().asMultiPolyline()[0][0] for feat in feats_line ]
points_line.append(feats_line[n-1].geometry().asMultiPolyline()[0][1])
points_line2 = [ QgsPointXY((points_line[i].x()+points_line[i+1].x())/2,
(points_line[i].y()+points_line[i+1].y())/2) for i in range(n) ]
epsg = line[0].crs().postgisSrid()
uri = "Polygon?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"
mem_layer = QgsVectorLayer(uri,
'buffer',
'memory')
prov = mem_layer.dataProvider()
az = [ points_line[i].azimuth(points_line[i+1]) for i in range(n) ]
for i in range(len(az)-1):
if fabs(az[i] - az[i+1]) > 1e-6:
ver = az[i+1]
break
idx = az.index(ver)
geoms = []
for i, point in enumerate(points_line2):
new_feat = QgsFeature()
new_feat.setAttributes([i])
bbox = QgsGeometry.fromPointXY(point).buffer(10, -1).boundingBox()
tmp_feat = bbox.asWktPolygon()
xmin1,ymin1,xmax1,ymax1 = bbox.toRectF().getCoords()
xmin2,ymin2,xmax2,ymax2 = QgsGeometry.fromPointXY(point).buffer(5, -1).boundingBox().toRectF().getCoords()
p1 = QgsPointXY(xmin1, ymax2)
p2 = QgsPointXY(xmax1, ymin2)
new_ext = QgsRectangle(p1,p2)
new_tmp_feat = new_ext.asWktPolygon()
geom = QgsGeometry.fromWkt(new_tmp_feat)
geoms.append(geom)
geom.rotate(az[i]-90, point)
new_feat.setGeometry(geom)
if i != idx:
prov.addFeatures([new_feat])
pol1 = geoms[idx-1]
pol2 = geoms[idx+1]
#lines 3 and 4
d = 20
delta_x = d*cos((90 - az[idx-1])*pi/180)
delta_y = d*sin((90 - az[idx-1])*pi/180)
new_x3 = pol1.asPolygon()[0][1].x() + delta_x
new_y3 = pol1.asPolygon()[0][1].y() + delta_y
new_x4 = pol1.asPolygon()[0][2].x() + delta_x
new_y4 = pol1.asPolygon()[0][2].y() + delta_y
new_pt3 = QgsPointXY(new_x3, new_y3)
new_pt4 = QgsPointXY(new_x4, new_y4)
line3 = [ pol1.asPolygon()[0][1], new_pt3 ]
new_line3 = QgsGeometry.fromPolylineXY(line3)
line4 = [ pol1.asPolygon()[0][2], new_pt4 ]
new_line4 = QgsGeometry.fromPolylineXY(line4)
#lines 5 and 6
d = -20
delta_x = d*cos((90 - az[idx+1])*pi/180)
delta_y = d*sin((90 - az[idx+1])*pi/180)
new_x5 = pol2.asPolygon()[0][0].x() + delta_x
new_y5 = pol2.asPolygon()[0][0].y() + delta_y
new_pt5 = QgsPointXY(new_x5, new_y5)
new_x6 = pol2.asPolygon()[0][3].x() + delta_x
new_y6 = pol2.asPolygon()[0][3].y() + delta_y
new_pt6 = QgsPointXY(new_x6, new_y6)
line5 = [ pol2.asPolygon()[0][0], new_pt5 ]
new_line5 = QgsGeometry.fromPolylineXY(line5)
line6 = [ pol2.asPolygon()[0][3], new_pt6 ]
new_line6 = QgsGeometry.fromPolylineXY(line6)
#intersection lines(3, 5), lines(4, 6)
new_pt1 = new_line3.intersection(new_line5).asPoint()
new_pt2 = new_line4.intersection(new_line6).asPoint()
new_pol = [[ pol1.asPolygon()[0][1], new_pt1, pol2.asPolygon()[0][0],
pol2.asPolygon()[0][3], new_pt2, pol1.asPolygon()[0][2]] ]
new_geom = QgsGeometry.fromPolygonXY(new_pol)
new_feat.setAttributes([n])
new_feat.setGeometry(new_geom)
prov.addFeatures([new_feat])
QgsProject.instance().addMapLayer(mem_layer)
I tried it out with line layer of following image:
After running above code in Python Console of QGIS, it was produced a layer as expected: