If you change your program to read the file name from the command line and split up your input file in smaller chunks, you can do something like this using GNU Parallel:
parallel my_processing.py {} /path/to/polygon_file.shp ::: input_files*.shp
This will run 1 job per core.
All new computers have multiple cores, but most programs are serial in nature and will therefore not use the multiple cores. However, many tasks are extremely parallelizeable:
- Run the same program on many files
- Run the same program for every line in a file
- Run the same program for every block in a file
GNU Parallel is a general parallelizer and makes is easy to run jobs in parallel on the same machine or on multiple machines you have ssh access to.
If you have 32 different jobs you want to run on 4 CPUs, a straight forward way to parallelize is to run 8 jobs on each CPU:
GNU Parallel instead spawns a new process when one finishes - keeping the CPUs active and thus saving time:
Installation
If GNU Parallel is not packaged for your distribution, you can do a personal installation, which does not require root access. It can be done in 10 seconds by doing this:
(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
For other installation options see http://git.savannah.gnu.org/cgit/parallel.git/tree/README
Learn more
See more examples: http://www.gnu.org/software/parallel/man.html
Watch the intro videos: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Walk through the tutorial: http://www.gnu.org/software/parallel/parallel_tutorial.html
Sign up for the email list to get support: https://lists.gnu.org/mailman/listinfo/parallel
Here are three solutions. You can either
- Get a list, array or concatenated string of all x and y coordinates of each MultiPoint
- Get the x and y coordinate of the centroid of each MultiPoint
- Get the x and y coordinates of the first point of each MultiPoint
If not using the centroid, you need to loop through the vertices of each MultiPoint-Feature just as you would do it with a MultiLineString or a MultiPolygon.
#multiPointLayer = QgsProject.instance().mapLayersByName('Dissolved')[0] # get a layer
pr = multiPointLayer.dataProvider()
# Note the change of fieldtypes:
pr.addAttributes([
# Will store the concatenated string of all x and y coordinates of each MultiPoint:
QgsField("x_coords", QVariant.String),
QgsField("y_coords", QVariant.String),
# Will store the x and y coordinate of the centroid of each MultiPoint:
QgsField("x_coord_centroid", QVariant.Double),
QgsField("y_coord_centroid", QVariant.Double),
# Will store the x and y coordinates of the first point of each MultiPoint:
QgsField("x_coord_firstpoint", QVariant.Double),
QgsField("y_coord_firstpoint", QVariant.Double)
])
multiPointLayer.updateFields()
with edit(multiPointLayer):
for feature in multiPointLayer.getFeatures():
geom = feature.geometry() # get the geometry of the current feature
x_arr = [] # create an empty list
y_arr = [] # create an empty list
for part in geom.parts(): # loop through the parts of each multipoint feature
for p in part.vertices(): # now "loop through" each vertex of each part (actually a loop isnt really needed but easier to implement, since each part always has exact one vertex)
x_arr.append(p.x()) # get the x coordinate of that vertex (p.x()) and append it to the list
y_arr.append(p.y()) # get the y coordinate of that vertex (p.y()) and append it to the list
# Same as array_to_string(array_foreach(generate_series(0,num_points($geometry)-1),x_at(@element)),','):
feature['x_coords'] = ','.join(str(x) for x in x_arr) # turn the list of x coordinates into a comma spearated string. Therefore we need to iterate over the list and convert each double value to a string
feature['y_coords'] = ','.join(str(y) for y in y_arr) # turn the list of y coordinates into a comma spearated string. Therefore we need to iterate over the list and convert each double value to a string
# Same as x($geometry) and y($geometry):
feature['x_coord_centroid'] = geom.centroid().asPoint().x() # get the x coordinate of the multipoint features centroid
feature['y_coord_centroid'] = geom.centroid().asPoint().y() # get the y coordinate of the multipoint features centroid
# Same as $x and $y:
feature['x_coord_firstpoint'] = x_arr[0] # get the x coordinate of the first point of each MultiPoint
feature['y_coord_firstpoint'] = y_arr[0] # get the y coordinate of the first point of each MultiPoint
multiPointLayer.updateFeature(feature)
QgsProject.instance().addMapLayer(multiPointLayer)
A side note on your expressions, not PyQGIS related:
If you type $x
or $y
in fieldcaluclator on a MultiPoint-layer, you will always get the coordinate of the "first" point. This is mentioned in the function description.
If you use x($geometry)
or y($geometry)
, you will get the centroid for each MultiPoint.
If you want another coordinate than the one from the first point, you can use x_at()
or y_at()
, e.g. x_at(2)
to return the x coordinate of the 3rd point of a MultiPoint.
You can also use x_at()
and y_at()
to return an array of all x and y coordinates of a MultiPoint by combining it with num_points()
, generate_series()
and array_foreach()
, e.g. by using array_foreach(generate_series(0,num_points($geometry)-1),x_at(@element))
to get an array of all x coordinates of each MultiPoint or array_foreach(generate_series(0,num_points($geometry)-1),y_at(@element))
to get an array of all y coordinates of each MultiPoint.
Best Answer
I think that the
intersection()
method ofQgsGeometry
is what you are after.From the docs:
So the analogue to your pseudocode is:
i.e. the new geometry object stored in the return value
clipped_result
representsgeom1
clipped withgeom2
.A simple example of usage:
Screencast:
If you want to edit a feature's geometry in-place (clip a feature), you can do it at the layer level like:
There is also
difference()
method whichE.g.