# PyQGIS Geometry manipulation

While trying to round out my answer to Geometry Generator using polygon boundary expression only returning Exterior Ring QGIS I am trying to determine if the geometry passed into the function is a Polygon or a MultiPolygon and then to extract it's rings to pass to the zigzag drawing code.

My first attempt was to use the solution to Remove inner rings from QgsGeometry polygon in QGIS Python gives me `'list' object has no attribute 'interpolatePoint'` as an error with my code looking like:

``````geoms = []
if geom.isMultipart() is False: # if only simple polygon, calculate only for this
polyg = geom.asPolygon() # transform to list of points
for ring in polyg:
geoms.append(ring)
else: # is multipart
multi = geom.asMultiPolygon()
for polyg in multi:
for ring in polyg:
geoms.append(ring)
# interpolate points on linestring
for gx in geoms:
points2d = [(lambda g: (g.x(), g.y()))(gx.interpolatePoint(d)) for d in distances]
vertices = gx.points()
``````

So one of the `asX` methods returned an empty list instead of a Polygon, I think?

So next I tried to go from basics with:

``````geoms = []

# assume it is a polygon
if geom.wkbType() == QgsWkbTypes.Polygon:
poly = geom.asPolygon()
geoms.append(poly.exteriorRing())
else:
geoms.append(geom.boundary())
``````

Which gives the same error message when applied to polygon features. So then I tried:

``````geoms = []

geoms.append(geom.exteriorRing())
for i in range(0,geom.getNumInteriorRings()):
geoms.append(geom.getInteriorRingN(i))
``````

But it says, `Eval Error: 'QgsGeometry' object has no attribute 'exteriorRing'` so I thought it needed changing to a polygon. Finally, I tried:

geoms = []

``````poly = geom.asPolygon()
geoms.append(poly.exteriorRing())
for i in range(0,poly.getNumInteriorRings()):
geoms.append(poly.getInteriorRingN(i))
``````

But that just says `'list' object has no attribute 'exteriorRing'` My test features are:

``````Polygon ((513366.96000000002095476 102956.35000000000582077, 513355.33000000001629815 102954.64999999999417923, 513356.32000000000698492 102947.89999999999417923, 513367.95000000001164153 102949.60000000000582077, 513366.96000000002095476 102956.35000000000582077))
Polygon ((513392.47999999998137355 102973.47999999999592546, 513401.75 102916.32000000000698492, 513424.30999999999767169 102919.85000000000582077, 513415.40000000002328306 102977.08000000000174623, 513392.47999999998137355 102973.47999999999592546),(513408.89000000001396984 102967.58999999999650754, 513415.45000000001164153 102926.5, 513407.88000000000465661 102925.28999999999359716, 513401.32000000000698492 102966.38000000000465661, 513408.89000000001396984 102967.58999999999650754))
``````

So (currently) there is no problem with a multipolygon or anything complicated.

• I'd like to help, but I don't really get the question here. Do you need a list of rings (as line strings) from an input geometry, regardless of if it is multi/single-part and if it has interior rings or not? If so, I have a function for that. Commented Aug 1, 2020 at 0:48
• that's exactly what I need Commented Aug 1, 2020 at 8:26

The following function (adapted from here) receives a polygon geometry and gives you a `QgsMultiLineString` with all polygon rings. It takes into account single and multi-parts.

``````def get_polygon_rings_as_lines(polygon):
# Input polygon can be multi or single part
# and could have interior rings

def get_rings_from_polygon_part(part_polygon):
part_rings = list()
part_rings.append(part_polygon.exteriorRing().clone())
for i in range(part_polygon.numInteriorRings()):
part_rings.append(part_polygon.interiorRing(i).clone())

return part_rings

abs_polygon = polygon.get()
ring_list = list()

if polygon.isMultipart():
for part in range(abs_polygon.numGeometries()):
ring_list.extend(get_rings_from_polygon_part(abs_polygon.geometryN(part)))
else:
ring_list.extend(get_rings_from_polygon_part(abs_polygon))

rings = QgsMultiLineString()
for ring in ring_list:
Note that when dealing with PyQGIS geometries, sometimes you might need the `QgsGeometry` (which is defined as a container in the docs) and sometimes you might need the real geometry primitive (`QgsAbstractGeometry`).