7

I wrote a processing scrip for QGIS 2.18 to create a multi-distance buffer rings using the haversine formula. Unfortunately, it no longer works after I updated to QGIS 3.4.5. I've tried updating the script wherever I can but I can't figure out how to fix the part of the code where it writes the buffers to a shapefile.

Here's my code:

from math import *
from qgis.core import *
from qgis.utils import iface
from PyQt5.QtCore import *
from PyQt5.QtGui import *

layer = iface.activeLayer() for feat in layer.selectedFeatures(): geom = feat.geometry()

start_x = geom.asPoint().x() start_y = geom.asPoint().y() sides = 64 radius = 6378137.0 # meters

create layer

vl = QgsVectorLayer("Polygon", "Distance Buffers", "memory") pr = vl.dataProvider()

changes are only possible when editing the layer

vl.startEditing()

add fields

pr.addAttributes([QgsField("Distance", QVariant.Int), QgsField("Label", QVariant.String)])

distance = [250, 500, 1000, 2000, 3000, 4000, 5000, 10000, 15000, 20000, 25000, 30000, 40000, 50000] for i in range(len(distance)): points = [] dist = distance[i] degrees = 0 while degrees <= 360: degrees = degrees + 360 / sides

    start_lon = start_x * pi / 180
    start_lat = start_y * pi / 180
    bearing = degrees * pi / 180

    end_lat = asin((sin(start_lat) * cos(dist / radius)) + (cos(start_lat) * sin(dist / radius) * cos(bearing)))
    end_lon = start_lon + atan2(sin(bearing) * sin(dist / radius) * cos(start_lat),
                                cos(dist / radius) - (sin(start_lat) * sin(end_lat)))

    points.append(QgsPointXY(end_lon * 180 / pi, end_lat * 180 / pi))

    fet_name = str(distance[i])
    if distance[i] &lt; 1000:
        label = str(distance[i]) + &quot;m&quot;
    else:
        label = str(distance[i]/1000) + &quot;km&quot;

# add a feature
fet = QgsFeature()
geometry = QgsGeometry.fromPolygonXY([points])
fet.setGeometry(geometry)
fet.setAttributes([fet_name,label])
pr.addFeatures([fet])

commit to stop editing the layer

vl.commitChanges()

update layer's extent when new features have been added

because change of extent in provider is not propagated to the layer

vl.updateExtents()

myDir = QgsProject.instance().readPath("./") file_name = 'Distance Buffers' + '.shp' ShapefileDir = myDir + "/Shapefiles/" + file_name

_writer = QgsVectorFileWriter.writeAsVectorFormat(vl, ShapefileDir, "utf-8", None, "ESRI Shapefile")

At the last line of the code I get this error:

Traceback (most recent call last): File "C:/PROGRA~1/QGIS3~1.4/apps/qgis-ltr/./python/plugins\processing\script\ScriptEditorDialog.py", line 227, in runAlgorithm exec(self.editor.text(), d) File "", line 68, in TypeError: QgsVectorFileWriter.writeAsVectorFormat(): arguments did not match any overloaded call: overload 1: argument 4 has unexpected type 'NoneType' overload 2: argument 4 has unexpected type 'NoneType' overload 3: argument 3 has unexpected type 'str'

Based on the QGIS 3.0 documentation, I think writeAsVectorFormat now takes the following arguments: writeAsVectorFormat(layer: QgsVectorLayer, fileName: str, options: QgsVectorFileWriter.SaveVectorOptions, newFilename: str = ‘’) but I can't figure out how to set the SaveVectorOptions.

Can someone show me how this is done with this script, or with any other working examples?

Taras
  • 32,823
  • 4
  • 66
  • 137
sjp_1989
  • 569
  • 3
  • 11
  • Related to your comment "# changes are only possible when editing the layer", this is not true. You are using the dataProvider, so you don't need to use startEditing and commitChanges. – etrimaille Feb 26 '19 at 13:28

1 Answers1

5

As it happens, I have just finished updating the documentation on vector layers. The big change is that you can't pass in None as the CRS any longer, so either use an explicit one or leave it out altogether.

You now need something like:

writer = QgsVectorFileWriter("my_shapes", "UTF-8", driverName="ESRI Shapefile")

The latest docs are available which give the full list of parameters.

Ian Turton
  • 81,417
  • 6
  • 84
  • 185