5

What is the PyQGIS equivalent of the Extract Nodes tool in QGIS?

I cannot seem to find it in the API documentation.

2 Answers 2

5

You can take the extractPoints() function from the fTools plugin by Carson Farmer:

# Generate list of QgsPoints from input geometry ( can be point, line, or polygon )
def extractPoints( geom ):
    multi_geom = QgsGeometry()
    temp_geom = []
    if geom.type() == 0: # it's a point
        if geom.isMultipart():
            temp_geom = geom.asMultiPoint()
        else:
            temp_geom.append(geom.asPoint())
    elif geom.type() == 1: # it's a line
        if geom.isMultipart():
            multi_geom = geom.asMultiPolyline() #multi_geog is a multiline
            for i in multi_geom: #i is a line
                temp_geom.extend( i )
        else:
            temp_geom = geom.asPolyline()
    elif geom.type() == 2: # it's a polygon
        if geom.isMultipart():
            multi_geom = geom.asMultiPolygon() #multi_geom is a multipolygon
            for i in multi_geom: #i is a polygon
                for j in i: #j is a line
                    temp_geom.extend( j )
        else:
            multi_geom = geom.asPolygon() #multi_geom is a polygon
            for i in multi_geom: #i is a line
                temp_geom.extend( i )
    # FIXME - if there is none of know geoms (point, line, polygon) show an warning message
    return temp_geom

Then just pass your geometry as argument:

points = extractPoints( feature.geometry() )

points will contain a Python list of points (pairs of coordinates). You could access, for example, the Y coordinate of the first point like this:

print points[0][1] 

I've tested it on QGIS 2.6.1, using the QGIS Python Console.

In general, for vector geoprocessing tools, you have the Python source code at hand. In my computer, fTools is located at /usr/share/qgis/python/plugins/fTools/

0
3

If you are comfortable with Python you only need classic Python, list comprehensions and the understanding of PyQGIS: Geometry Handling:

  • A Point in PyQGIS is built with QgsPoint(x,y);
  • A LineString with QgsGeometry.fromPolyline([QgsPoint(x1,y1),QgsPoint(x2,y2)]))
  • A Polygon with QgsGeometry.fromPolygon([[QgsPoint(x1,y1),QgsPoint(x2,y2), QgsPoint(x3,y3),QgsPoint(x1,y1)]])

So the the LinearRing/boundary of a a polygon is [[QgsPoint(x1,y1),QgsPoint(x2,y2), QgsPoint(x3,y3),QgsPoint(x1,y1)]][0] = [QgsPoint(x1,y1),QgsPoint(x2,y2), QgsPoint(x3,y3),QgsPoint(x1,y1)].

With a Polygon Layer as example:

enter image description here

layer = qgis.utils.iface.activeLayer()
# examine the first element
elem = layer.getFeatures().next()
geom = elem.geometry()
# or elem = layer.getFeatures().next().geometry()
first_poly = geom.asPolygon()
print first_poly
[[(6.97738,53.361), (7.18994,52.8886), (6.70577,52.5698), (7.16632,52.2509), (6.59948,51.8258), (6.04445,51.8258), (5.87913,50.763), (5.70199,50.8575), (5.89093,51.2708), (5.31229,51.2472), (5.08791,51.4125), (4.69821,51.4833), (4.22584,51.3416), (3.49368,51.3534), (4.02509,52.062), (4.82811,52.9241), (5.18239,52.4399), (5.61932,52.5934), (5.59571,52.8532), (5.40676,52.9004), (5.43038,53.2547), (6.39873,53.4555), (6.74119,53.4791), (6.97738,53.361)]]

Now, if you want the LinearRing of this polygon:

enter image description here

ring = first_poly[0])
print ring # = a list of coordinates of the points
[(6.97738,53.361), (7.18994,52.8886), (6.70577,52.5698), (7.16632,52.2509), (6.59948,51.8258), (6.04445,51.8258), (5.87913,50.763), (5.70199,50.8575), (5.89093,51.2708), (5.31229,51.2472), (5.08791,51.4125), (4.69821,51.4833), (4.22584,51.3416), (3.49368,51.3534), (4.02509,52.062), (4.82811,52.9241), (5.18239,52.4399), (5.61932,52.5934), (5.59571,52.8532), (5.40676,52.9004), (5.43038,53.2547), (6.39873,53.4555), (6.74119,53.4791), (6.97738,53.361)]

And the nodes/points:

enter image description here

for pt in ring:
     print QgsPoint(pt)
(6.97738,53.361)
(7.18994,52.8886)
(6.70577,52.5698)
....

or

ring = QgsGeometry.fromPolyline(first_poly[0])
for point in ring.asPolyline():
     print point

So the list of nodes is given by:

nodes = [point for point in ring.asPolyline()] = [point for point in geometry[0].asPolygon()[0]] 

And you can extract all the nodes of a Polygon layer with :

for elem in layer.getFeatures():
    for point in elem.geometry().asPolygon()[0]:
         print point

You can try with a double list comprehension but PyQGIS not like them very much...

nodes = [point for point in elem.geometry().asPolygon()[0] for elem in layer.getFeatures()]
print nodes
[(6.97738,53.361), (6.97738,53.361), (6.97738,53.361), (7.18994,52.8886), (7.18994,52.8886), (7.18994,52.8886), (6.70577,52.5698), (6.70577,52.5698), (6.70577,52.5698), (7.16632,52.2509), (7.16632,52.2509), (7.16632,52.2509), (6.59948,51.8258), (6.59948,51.8258), (6.59948,51.8258), (6.04445,51.8258), (6.04445,51.8258), (6.04445,51.8258), (5.87913,50.763), (5.87913,50.763), (5.87913,50.763), (5.70199,50.8575), (5.70199,50.8575), (5.70199,50.8575), (5.89093,51.2708), (5.89093,51.2708), (5.89093,51.2708), (5.31229,51.2472), (5.31229,51.2472), (5.31229,51.2472), (5.08791,51.4125), (5.08791,51.4125), (5.08791,51.4125), (4.69821,51.4833), (4.69821,51.4833), (4.69821,51.4833), (4.22584,51.3416), (4.22584,51.3416), (4.22584,51.3416), (3.49368,51.3534), (3.49368,51.3534), (3.49368,51.3534), (4.02509,52.062), (4.02509,52.062), (4.02509,52.062), (4.82811,52.9241), (4.82811,52.9241), (4.82811,52.9241), (5.18239,52.4399), (5.18239,52.4399), (5.18239,52.4399), (5.61932,52.5934), (5.61932,52.5934), (5.61932,52.5934), (5.59571,52.8532), (5.59571,52.8532), (5.59571,52.8532), (5.40676,52.9004), (5.40676,52.9004), (5.40676,52.9004), (5.43038,53.2547), (5.43038,53.2547), (5.43038,53.2547), (6.39873,53.4555), (6.39873,53.4555), (6.39873,53.4555), (6.74119,53.4791), (6.74119,53.4791), (6.74119,53.4791), (6.97738,53.361), (6.97738,53.361), (6.97738,53.361)]

and the nodes of a LineStrings layer:

 for elem in layer.getFeatures():
    for point in elem.geometry().asPolyline():
         print point

or with the same restrictions:

nodes = [point for point in elem.geometry().asPolyline() for elem in layer.getFeatures()]

It is the same for MultiGeometries, add a for loop/

0

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.