I'm trying to make a line pattern fill in QGis using the geometry generator and a python function.

The code is inspired from this answer : Save line geometry as points geometry in QGIS (pyqgis)

from qgis.core import *
from qgis.gui import *

@qgsfunction(args='auto', group='Custom')
def fill_line_pattern(x, feature, parent):

#create a base line that is 45 degrees
base_xmin = 2285865.0
base_xmax = 2669093.0
base_ymin = 1017594.0
base_ymax = 1399851.0

#calculating interval between parrallels
countX = int((2800000.0-2285865.0) / xInterval)
#empty list
pts = []
intersected_lines = []
#raw lines creation
for xOff in range(countX+1):
    ptXmin = base_xmin + xOff*(xInterval)
    ptXmax = base_xmax + xOff*(xInterval)
    ptmin = QgsPoint(ptXmin,base_ymin)
    ptmax = QgsPoint(ptXmax,base_ymax)
    pt = ([ptmin, ptmax])
#intersect lines with polygons
#for f in feat :
for p in pts :
    rawlines = QgsGeometry.fromPolyline(p)
    if feature.geometry().intersects(rawlines):
        geom = feature.geometry().intersection(rawlines)
#create lines
for line_ok in intersected_lines:
    return QgsGeometry.fromPolylineXY(line_ok)

The issue is that the first line only is crossing the polygon...

enter image description here

How can I have all the lines crossing the polygons?

In comparaison to the inspirational code above, there's no loop for the polygon features.

In the function, the feature called is a QgsFeature which can't use getQgsFeatures().

If a for loop is used :

for f in feature :
    for p in pts :
    rawlines = QgsGeometry.fromPolyline(p)
        if f.geometry().intersects(rawlines):
            geom = f.geometry().intersection(rawlines)

This error message appears:

Evaluation error: 'int' object has no attribute 'geometry'


The code below does almost what I want, it seems a little bit buggy because not all the intersections appear... The other disavantage is the long time QGIS takes to render it on the canvas and in the composer.

On the other hand, the pdf output size is so light and is competitive with other software.

Maps are made to be shared: QGIS biggest issue is PDF output file size

The inspiration of the source : https://www.lutraconsulting.co.uk/blog/2015/06/05/qgis-function-editor/

Lutra Consulting uses a cache but I didn't find the way to do it...

from qgis.core import *
from qgis.gui import *

def _layer_intersection(layer, xInterval):
#make 45 degrees lines from layer extent
    ext = layer.extent()
    xmax = ext.xMaximum()
    ymax = ext.yMaximum()
    xmin = ext.xMinimum()
    ymin = ext.yMinimum()

    pts_hash_box = []
    line_in_polygon = []

    x_base_min = xmin - (ymax-ymin)
    countX = int(((xmax-xmin)+(ymax-ymin)) / xInterval)

    for xOff in range(countX+1):
        ptXmin = x_base_min + xOff*(xInterval)
        ptXmax = xmin + xOff*(xInterval)

        ptmin_hash_box = QgsPointXY(ptXmin,ymin)
        ptmax_hash_box = QgsPointXY(ptXmax,ymax)

        pt_hash_box = ([ptmin_hash_box, ptmax_hash_box])

    multipolylines = QgsGeometry.fromMultiPolylineXY(pts_hash_box)

    #intersection between 45 degrees virtual lines and the polygon features
    for layer_feature in layer.getFeatures() :
        if layer_feature.geometry().intersects(multipolylines):
            pts = layer_feature.geometry().intersection(multipolylines).asMultiPolyline()
            for pt in pts :

return QgsGeometry.fromMultiPolylineXY(line_in_polygon)

@qgsfunction(args='auto', group='Custom')
def line_pattern_fill(layer_name, xInterval, feature, parent):
for layer in QgsProject.instance().mapLayers().values():
    if layer.name() == layer_name :
        return _layer_intersection(layer, xInterval)
  • Must the lines be true geometry or could you use the QgsLinePatternFillSymbolLayer() instead? – Matt Needle Apr 26 at 5:52
  • The lines doesn't have to be true geometry. QgsLinePatternFillSymbolLayer() is rasterized when exported in PDF. The consequence is that the PDF size increase considerably... So I was thinking about a new methodology to keep vectorized line pattern to preserve the size of my PDFs with QGIS. – geavcon Apr 29 at 13:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.