I propose an approach that only recurs to a geometry generator and a custom function.
Context
Let's assume to start from this situation (hopefully very close to yours), where the several parking restrictions are stored in the "Condition"
field:
I also assume that you know how the QGIS custom functions work, otherwise this post might be helpful: How to create custom functions in QGIS using the function editor.
Preliminary task - Creating the custom function
After having loaded your layers in QGIS, open the Field Calculator
and click on the Function Editor
tab.
Then, click on New file
and type curb_lines
as the name of the new function:
You will see that a new function has been created and it is listed on the left side of the dialog. Now, click on the name of the function and replace the default @qgsfunction
with the following code:
from qgis.core import *
from qgis.gui import *
@qgsfunction(args='auto', group='Custom')
def curb_lines(restrictions_layer_name, roads_layer_name, feature, parent):
def segments(polyline):
for x in range(0, len(polyline)-1):
first_point = polyline[x]
second_point = polyline[x +1]
seg = QgsGeometry.fromPolyline([first_point, second_point])
idsList = index.intersects(seg.boundingBox())
for id in idsList:
tmp_geom = all_feats[id].geometry()
if seg.touches(tmp_geom):
num.append(seg)
return num
layer = QgsMapLayerRegistry.instance().mapLayersByName(restrictions_layer_name)[0]
ro_layer = QgsMapLayerRegistry.instance().mapLayersByName(roads_layer_name)[0]
all_feats = {}
index = QgsSpatialIndex()
for ft in ro_layer.getFeatures():
index.insertFeature(ft)
all_feats[ft.id()] = ft
input_geometry = QgsGeometry(feature.geometry())
line_geom = QgsGeometry(input_geometry.geometry().boundary())
polyline = line_geom.asPolyline()
num = []
res = segments(polyline)
first = True
for h in num:
if first:
geom = QgsGeometry(h)
first = False
else:
geom = geom.combine(h)
return geom
Once you have done this, click on the Load
button and you will be able to see the function from the Custom
Menu of the Expression
dialog.
Solution
Firstly, go to Layer Properties | Style
and then choose the Rule-based
renderer.
Create two different rules (if you have only two categories, otherwise adapt it to your case): I will show you how to get a working solution only for the first category because the procedure is the same for all the others.
Double-click on the first rule and set the filter expression (step 1, see the image below):
"Condition" = 'Residential only'
From the Symbol selector
dialog, choose a Geometry generator
as symbol layer type (step 2) and Linestring / MultiLinestring
as geometry type (step 3).
Now, type this expression (step 4):
curb_lines('restr', 'roads')
where 'restr'
and 'roads'
are the layer names for the restrictions and roads layers, respectively (adapt them to your case).
If you want to set a different style for each category, go to step 5 and set Color
, Pen width
, Offset
and so on (the answer won't cover this part).
Click on the OK
button and repeat the previous steps for the other categories.
Finally, click on the Apply
button for applying the changes.
You will see something like this: