3

I am trying to split polygons into equally sized pieces using a grid. The polygons are all image segments derived from 2.4 meter satellite imagery. So each polygon is a grouping of 2.4m x 2.4m squares. I want to produce a QGIS processing tool to simplify my current workflow of individually running the "Create Grid" and "Split with Lines" QGIS processing tools. The workflow should also edit the selected polygon in the existing layer, not create a new layer.

Example input polygon (with the polygon to be split selected):enter image description here

Expected output from processing tool: enter image description here

from qgis.core import *
from qgis.gui import *
import qgis.utils
import processing
import re
from PyQt5.QtCore import *
#the spacing of the cut grid
cell_size = 2.4
#get current layer, selection, CRS from QGIS map canvas
layer = qgis.utils.iface.activeLayer()
selected = layer.selectedFeatures()
crs = qgis.utils.iface.activeLayer().crs().authid()
for lay in selected:
 #get the ID of the feature we've selected in QGIS map canvas
 id = lay.id
 print("working on: " + str(id))
 #get the extent of the selected feature
 x_max, y_max, x_min, y_min = re.split(":|,", lay.geometry().boundingBox().toString().replace(" ", ""))
 extent = x_min + "," + x_max + "," + y_min + "," + y_max
 print(extent)
 #create our grid in memory
 grid_parameters = {"TYPE": 1,
 "EXTENT": extent,
 "HSPACING": cell_size,
 "VSPACING":cell_size,
 "HOVERLAY": 0,
 "VOVERLAY": 0,
 "CRS": crs,
 "OUTPUT": "memory_grid"}
 grid = processing.run("qgis:creategrid", grid_parameters)
 #split the selected feature, store the results in memory
 split_parameters = {"INPUT": layer.getFeature(id),
 "LINES": grid["OUTPUT"],
 "OUTPUT": "memory_split"}
 split = processing.run("qgis:splitwithlines", split_parameters)
 #delete the original feature, add the split results to the original layer
with edit(layer):
 layer.deleteFeature(id)
 layer.addFeatures(split["OUTPUT"])

When I run this code I get an error on line 39 (split parameters dictionary) that reads: "TypeError: QgsVectorLayer.getFeature: argument 1 has unexpected type 'builtin_function_or_method"

I have tried several different approaches, including directly feeding my selection, the entire layer, layer.getFeatures(), etc. but nothing has been an acceptable input for the Split with Lines tool.

asked Apr 18, 2018 at 23:31
4
  • What do you mean 'automate'? Automate for all features in a layer or for all shapefiles in a folder? Commented Apr 19, 2018 at 0:13
  • I clarified "automate" in my post above. Commented Apr 19, 2018 at 2:05
  • To get rid of "unexpected type 'builtin_function_or_method" error, you should replace id = lay.id with id = lay.id() Commented Apr 19, 2018 at 2:11
  • Good catch! I am now getting "TypeError: reportError() missing 1 required positional argument: 'fatal error'" in the same location as before. Commented Apr 19, 2018 at 2:16

2 Answers 2

3

If you don't need a script, "Create Grid" and "Intersection" tool are enough to solve your problem.

"Create Grid" tool: For CRS, select your layer CRS. (In this case, CRS must be projected, not geographic)

enter image description here

Result of "Create Grid":

enter image description here

"Intersection" tool:

enter image description here

Final Result:

enter image description here

Output Attribute Table: ('Segment_x' comes from polygons and expresses that which segment/polygon the grid is in)

enter image description here

If pixel size is 2.4, result will be as you need.

answered Apr 19, 2018 at 0:41
2
  • Thanks for taking a look. This is essentially the approach I am currently using and attempting to implement in the script. However, I am performing this workflow 1000s of times, and hand-entering the parameters and executing the workflow is tedious. Also, I would like the approach to edit the existing layer, not produce a new layer. Commented Apr 19, 2018 at 2:03
  • Have you tried using the Graphical Modeler to automate your process? Commented Apr 23, 2018 at 19:09
2

Final, working code. I mimplemented this in QGIS 2.18.19 since there is more material on PyQGIS and it still suits my workflows.

from qgis.core import *
from qgis.gui import *
import qgis.utils
import processing
import re
from PyQt4.QtCore import *
cell_size = 2.4
layer = qgis.utils.iface.activeLayer()
selected = layer.selectedFeatures()
crs = qgis.utils.iface.activeLayer().crs().authid()
ids = []
x_maxs = []
x_mins = []
y_maxs = []
y_mins = []
for lay in selected:
 id = lay.id()
 ids.append(id)
 print("working on: " + str(id))
 x_min, y_min, x_max, y_max = re.split(":|,", lay.geometry().boundingBox().toString().replace(" ", ""))
 x_mins.append(float(x_min))
 x_maxs.append(float(x_max))
 y_mins.append(float(y_min))
 y_maxs.append(float(y_max))
extent = str(min(x_mins)) + "," + str(max(x_maxs)) + "," + str(min(y_mins)) + "," + str(max(y_maxs))
print(extent)
grid_parameters = {"TYPE": 1,
 "EXTENT": extent,
 "HSPACING": cell_size,
 "VSPACING":cell_size,
 #"HOVERLAY": 0,
 #"VOVERLAY": 0,
 "CRS": crs,
 "OUTPUT": None}
grid = processing.runalg("qgis:creategrid", grid_parameters)
intersection_parameters = {"INPUT": layer,
 "INPUT2": grid["OUTPUT"],
 "IGNORE_NULL": True,
 "OUTPUT": None}
intersect = processing.runalg("qgis:intersection", intersection_parameters)
mem_intersect = QgsVectorLayer(intersect["OUTPUT"], "lyr_intersect", "ogr")
fields_to_delete = []
fieldnames = set(["left", "right", "top", "bottom"])
for field in mem_intersect.fields():
 if field.name() in fieldnames:
 fields_to_delete.append(mem_intersect.fieldNameIndex(field.name()))
mem_intersect.dataProvider().deleteAttributes(fields_to_delete)
mem_intersect.updateFields()
features = []
for feat in mem_intersect.getFeatures():
 features.append(feat)
with edit(layer):
 layer.deleteFeatures(ids)
 layer.dataProvider().addFeatures(features)
answered Apr 24, 2018 at 2:22

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.