3

I'm currently trying to use the OGR python bindings to process some shapefiles. I want to obtain the number of interior rings in a polygon feature. Unfortunately I'm unable to use the documented function to get that information.

Here is my code:

from osgeo import ogr
field = ogr.Open("testExtract.shp")
lyr = field.GetLayer("testExtract")
feat = lyr.GetNextFeature()

geom = feat.GetGeometryRef()
featName = geom.GetGeometryName()
print featName
geoCount = geom.GetGeometryCount()
print "geoCount: " + str(geoCount)

print geom.getNumInteriorRings()
print geom.GetNumInteriorRings()
print geom.getNumInteriorRing()
print geom.GetNumInteriorRing()

This is what those print commands output:

POLYGON
geoCount: 6

AttributeError: 'Geometry' object has no attribute 'getNumInteriorRings'
AttributeError: 'Geometry' object has no attribute 'GetNumInteriorRings'
AttributeError: 'Geometry' object has no attribute 'getNumInteriorRing'
AttributeError: 'Geometry' object has no attribute 'GetNumInteriorRing'

Now, the only polygon in that shapefile has interior rings. And the python code is telling me that geom is a polygon with 6 interior and exterior rings, which is correct. And the documentation, http://www.gdal.org/ogr/classOGRPolygon.html#a3b996195adcf9fcd4f33570a37753dde, is saying getNumInteriorRings() is a valid function for an OGRPolygon.

So is the problem that GetNumInteriorRings() is not accessible through the python API? The python documention doesn't mention OGRPolygon as a class, just Geometry. http://gdal.org/python/osgeo.ogr.Geometry-class.html

Edit: I realize that each polygon only has one exterior polygon, so I can get that information. But I'm also interested in a couple of the other functions in OGRPolygon such as getInteriorRing (int) and getExteriorRing () so I am curious if those public member functions for OGRPolygon are accessible in Python.

7

When you start with a Python module, there are several solutions to find the available functions. One of them is dir:

geom = feat.GetGeometryRef()
print dir(geom)
['AddGeometry', 'AddGeometryDirectly', 'AddPoint', 'AddPoint_2D', 'Area', 'AssignSpatialReference', 'Boundary', 'Buffer', 'Centroid', 'Clone', 'CloseRings', 'Contains', 'ConvexHull', 'Crosses', 'Destroy', 'Difference', 'Disjoint', 'Distance', 'Empty', 'Equal', 'Equals', 'ExportToGML', 'ExportToJson', 'ExportToKML', 'ExportToWkb', 'ExportToWkt', 'FlattenTo2D', 'GetArea', 'GetBoundary', 'GetCoordinateDimension', 'GetDimension', 'GetEnvelope', 'GetEnvelope3D', 'GetGeometryCount', 'GetGeometryName', 'GetGeometryRef', 'GetGeometryType', 'GetPoint', 'GetPointCount', 'GetPoint_2D', 'GetPoints', 'GetSpatialReference', 'GetX', 'GetY', 'GetZ', 'Intersect', 'Intersection', 'Intersects', 'IsEmpty', 'IsRing', 'IsSimple', 'IsValid', 'Length', 'Overlaps', 'PointOnSurface', 'Segmentize', 'SetCoordinateDimension', 'SetPoint', 'SetPoint_2D', 'Simplify', 'SimplifyPreserveTopology', 'SymDifference', 'SymmetricDifference', 'Touches', 'Transform', 'TransformTo', 'Union', 'UnionCascaded', 'Within', 'WkbSize', '__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__iter__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__swig_destroy__', '__swig_getmethods__', '__swig_setmethods__', '__weakref__', 'next', 'this']

and no getNumInteriorRings: apparently this method is not exposed in the python bindings.
But if you look at [gdal-dev] Polygon topology:

In fact you have to use the Geometry.GetGeometryCount() that returns 1 (the exterior ring) + the number of interior rings. So polygon.GetGeometryCount() - 1 should return the number of interior rings

So a polygon only:

geom.GetGeometryCount() 
1

For a polygon whith one hole:

enter image description here

geom.GetGeometryCount()
2 # -> one hole

and

geom.GetGeometryRef(0) # -> exterior ring = LinearRing, in red
geom.GetGeometryRef(1) # -> interior ring = LinearRing

enter image description here

exterior = Geometry(ogr.wkbPolygon)
exterior.AddGeometry(geom.GetGeometryRef(0))

enter image description here

interior = Geometry(ogr.wkbPolygon)
exterior.AddGeometry(geom.GetGeometryRef(1))

enter image description here

But if you look at the geo_interface protocol (a python object property that returns a geojson dictionary, look at Python Geo_interface applications):

 print geom.ExportToJson()
 { "type": "Polygon", "coordinates": [ [ [ 1149490.109727980103344, 691044.609108003089204 ], [ 1191579.109752570046112, 691044.609108003089204 ], [ 1191579.109752570046112, 648030.576115839648992 ], [ 1149490.109727980103344, 648030.576115839648992 ], [ 1149490.109727980103344, 691044.609108003089204 ] ], [ [ 1154115.274565846892074, 686419.444270136067644 ], [ 1154115.274565846892074, 653118.257437493419275 ], [ 1165678.186660513980314, 653118.257437493419275 ], [ 1165678.186660513980314, 686419.444270136067644 ], [ 1154115.274565846892074, 686419.444270136067644 ] ] ] }

it is easier with fiona (also based on GDAL/OGR)

import fiona
layer = fiona.open("myshape.shp")
feat = layer.next()
print feat
{'geometry': {'type': 'Polygon', 'coordinates': [[(1149490.1097279801, 691044.60910800309), (1191579.10975257, 691044.60910800309), (1191579.10975257, 648030.57611583965), (1149490.1097279801, 648030.57611583965), (1149490.1097279801, 691044.60910800309)], [(1154115.2745658469, 686419.44427013607), (1154115.2745658469, 653118.25743749342), (1165678.186660514, 653118.25743749342), (1165678.186660514, 686419.44427013607), (1154115.2745658469, 686419.44427013607)]]}, 'type': 'Feature', 'id': '0', 'properties': OrderedDict([(u'FID', 0.0)])}
print feat['geometry']['type'])
Polygon
print len(feat['geometry']['coordinates']
2
# outer ring
print feat['geometry']['coordinates'][0]
[(1149490.1097279801, 691044.60910800309), (1191579.10975257, 691044.60910800309), (1191579.10975257, 648030.57611583965), (1149490.1097279801, 648030.57611583965), (1149490.1097279801, 691044.60910800309)]
# inner ring
print feat['geometry']['coordinates'][1]
[(1154115.2745658469, 686419.44427013607), (1154115.2745658469, 653118.25743749342), (1165678.186660514, 653118.25743749342), (1165678.186660514, 686419.44427013607), (1154115.2745658469, 686419.44427013607)]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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