That's a good question, which has also been on my mind for the last few days (see Create coverage layer for atlas).
As @Matt has already mentioned, we can save the parameters in QgsSettings variables. But we always have to update the inputs property of the AlgWrapper instance to keep the new default values.
Here is the code of my example algorithm algRectAlongLines (places rectangles along lines):
"""
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
* Created: 19-06-2025 by Christoph Candido ([email protected]) *
* *
* This algorithm creates a polygon layer with rectangles along the lines *
* of the "Input layer". It demonstrates the use of the @alg decorator and *
* shows how to store the input parameters for later use. *
* *
* Due to the use of the @alg decorator, this algorithm is only supported *
* by QGIS >= 3.6. *
* *
***************************************************************************
"""
from qgis.PyQt.QtCore import QVariant
from qgis import processing
from qgis.processing import alg
from qgis.core import (QgsProcessing,
QgsGeometry,
QgsFeature,
QgsWkbTypes,
QgsFeatureSink,
QgsFields,
QgsField,
QgsPointXY,
QgsSettings,
QgsApplication,
QgsProcessingAlgorithm)
@alg(name="algRectAlongLines", label="Generate rectangles along lines", group="", group_label="")
@alg.input(type=alg.SOURCE, name="INPUT", label="Select Line layer", types= [QgsProcessing.TypeVectorLine])
@alg.input(type=alg.NUMBER, name="WIDTH", label="Enter Rectangle Width", default=QgsSettings().value("algRectAlongLines/WIDTH"))
@alg.input(type=alg.NUMBER, name="HEIGHT", label="Enter Rectangle Height", default=QgsSettings().value("algRectAlongLines/HEIGHT"))
@alg.input(type=alg.NUMBER, name="OVERLAP", label="Enter Rectangle Overlap [%]", default=QgsSettings().value("algRectAlongLines/OVERLAP"))
@alg.input(type=alg.NUMBER, name="TOLERANCE", label="Enter Tolerance for Line Simplification", default=QgsSettings().value("algRectAlongLines/TOLERANCE",0))
@alg.input(type=alg.BOOL, name="ALIGN", label="Align Rectangles with Line Features", default=QgsSettings().value("algRectAlongLines/ALIGN",True))
@alg.input(type=alg.SINK, name="OUTPUT", label="Output layer")
def algRectAlongLines(self, parameters, context, feedback, inputs):
"""
This algorithm creates a polygon layer with rectangles along the lines of the "Input layer".
We can adjust the width and height of the rectangles, define an overlap factor and set a tolerance value if we want to simplify the line geometries.
With the "Align Rectangles with Line Features" check box, we can align all rectangles to the line geometries.
Each rectangle created contains the ID of the source line feature, the rotation angle and a sort value.
In addition, the algorithm saves the input parameters in global QGIS variables for repeated use.
"""
def setDefaultValue(dict, param, val):
s = QgsSettings()
s.setValue("algRectAlongLines/"+param, val)
dict[param].setGuiDefaultValueOverride(val)
return dict[param]
width = self.parameterAsDouble(parameters, 'WIDTH', context)
height = self.parameterAsDouble(parameters, 'HEIGHT', context)
overlap = self.parameterAsDouble(parameters, 'OVERLAP', context)
if overlap > 0:
overlap = overlap / 100.0
tolerance = self.parameterAsDouble(parameters, 'TOLERANCE', context)
align = self.parameterAsBool(parameters, 'ALIGN', context)
sortOrder = None
i = 1
# refresh the inputs property of the AlgWrapper instance to update the default parameters
inp = self.inputs
newInputs = { 'WIDTH': setDefaultValue(inp, 'WIDTH', width),
'HEIGHT': setDefaultValue(inp, 'HEIGHT', height),
'OVERLAP': setDefaultValue(inp, 'OVERLAP', overlap * 100.0),
'TOLERANCE': setDefaultValue(inp, 'TOLERANCE', tolerance),
'ALIGN': setDefaultValue(inp, 'ALIGN', align) }
inp.update(newInputs)
source = self.parameterAsSource(parameters, 'INPUT', context)
fields = QgsFields()
fields.append(QgsField('src_fid', QVariant.Int))
fields.append(QgsField('angle', QVariant.Double))
fields.append(QgsField('sort_order', QVariant.Int))
(sink, dest_id) = self.parameterAsSink(parameters, 'OUTPUT',
context, fields, QgsWkbTypes.Polygon , source.sourceCrs())
features = source.getFeatures()
for feature in features:
if feature.hasGeometry():
geom = feature.geometry().extendLine(width*0.1,width*0.1)
if tolerance != 0:
geom = geom.simplify(tolerance)
curs = 0
numpages = geom.length()/width
if numpages > 1:
step = 1.0/numpages
stepnudge = (1.0-overlap) * step
else:
step = 1
stepnudge = 1
currangle = 0
while curs < 1:
startpoint = geom.interpolate(curs*geom.length())
endpoint = geom.interpolate((curs+step)*geom.length())
if not endpoint:
endpoint = geom.interpolate(geom.length())
x_start = startpoint.asPoint().x()
y_start = startpoint.asPoint().y()
x_end = endpoint.asPoint().x()
y_end = endpoint.asPoint().y()
x_mid = (x_start + x_end)/2
y_mid = (y_start + y_end)/2
w2 = width/2.0
h2 = height/2.0
minx = -w2
miny = -h2
maxx = w2
maxy = h2
poly = QgsGeometry().fromWkt(f'POLYGON(({minx} {miny}, {minx} {maxy},{maxx} {maxy}, {maxx} {miny}, {minx} {miny}))')
feat = QgsFeature()
feat.setFields(fields)
if align:
azimuth = startpoint.asPoint().azimuth(endpoint.asPoint())
currangle = (startpoint.asPoint().azimuth(endpoint.asPoint())+270)%360
poly.rotate(currangle, QgsPointXY(0,0))
feat['angle'] = currangle
else:
feat['angle'] = 0
#poly.translate(-width*overlap,0)
poly.translate(x_mid, y_mid)
poly.asPolygon()
curs = curs + stepnudge
feat['src_fid'] = feature.id()
feat['sort_order'] = i
feat.setGeometry(poly)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
i += 1
results = {}
results['OUTPUT'] = dest_id
return results
QgsSettings().