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 pt=[] 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]) pts.append(pt) #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) intersected_lines.append(geom.asPolyline()) #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...
How can I have all the lines crossing the polygons?
In comparison 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) intersected_lines.append(geom.asPolyline()) This error message appears:
Evaluation error: 'int' object has no attribute 'geometry'
EDIT
The code below does almost what I want, it seems a little bit buggy because not all the intersections appear... The other disadvantage 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]) pts_hash_box.append(pt_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 : line_in_polygon.append(y) 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) 