Further to relet's answer on how to get individual polygons, you can then run an intersection on all the polygons to create the holes. If your dataset contains overlapping polygons though you're out of luck.
Explain again what is wrong with existing shapefile readers?
Would it not be easier to export feature IDs and M values from the shapefile and then join them back to the polygons after using an existing shapefile reader?
For multipatches you can use the same technique of assigning polygon IDs to a "patch ID" and then adding this attribute back to the features.
Edit: Whilst you say you don't want to use OGR, just in case you change your mind..
import ogr
# Get the driver
driver = ogr.GetDriverByName('ESRI Shapefile')
# Open a shapefile
shapefileName = "D:/temp/myshapefile.shp"
dataset = driver.Open(shapefileName, 0)
layer = dataset.GetLayer()
for index in xrange(layer.GetFeatureCount()):
feature = layer.GetFeature(index)
geometry = feature.GetGeometryRef()
#geometry for polygon as WKT, inner rings, outer rings etc.
print geometry
The geometry should be output as follows:
POLYGON ((79285 57742,78741 54273...),(76087 55694,78511 55088,..))
The first bracket contains the coords of the exterior ring, subsequent brackets the coords of interior rings.
If you have Z values points should be in the format 79285 57742 10 (where the last coord is a height).
Otherwise you could use the Shapely Contains and Within functions to assess every polygon with each other and apply a spatial index beforehand - http://pypi.python.org/pypi/Rtree/ to speed up processing.
A multipolygon is a different type of geometry than a polygon. So feature.getGeomtryRef() will give you the Multipolygon.
Multipolygon itself inherits from MultiSurface, which inherits from GeometryCollection, which inherits from Geometry.
Polygon inherits from CurvePolygon, then from Surface, then from Geometry.
So all you have to do is "go one level deeper". Use getNumGeometries() or GetGeometryCount()
- depending on what ogr implementation you use - to get the number of geometries in a GeometryCollection, which is the number of polygons inside the multipolygon.
In the case of a Multipolygon, calling getGeometryRef(i) will return a Polygon, which you then treat exactly as you already do in your example to retrieve the single outer ring and zero or more inner rings.
This also answers the second part of your question: As each Polygon is still distinctly separate, each of them still has an outer and 0+ inner rings, which you can treat separately.
This also means it doesn't matter how these polygons are situated inside the multipolygon: Each of them has to be a valid polygon itself and adhere to the rules of multipolygons to be valid, which makes any problems like nested polygons (islands inside a hole of an outer polygon) perfectly possible, as long as no invalid line intersections occur.
Multiple inner rings for a single polygon are meant to be used when there are multiple holes inside it.
Example:
A multipolygon "park" consists of:
- One polygon defines the landmass. There are multiple lakes, which are represented by holes, each of those being an inner ring.
- If there are islands in those lakes, those will be their own polygons. But still part of the same multipolygon!
- These islands could then have their own lakes/holes, and so on.
This should work, then (no guarantees, I rarely work with C# these days):
Feature feat;
while ((feat = layer.GetNextFeature()) != null)
{
// Get GeometryCollection/Multipolygon
var gc = feat.GetGeometryRef();
// Let's see how many child geometries this has
for (var i = 0; i < gc.GetGeometryCount(); i++)
{
// So this must be our polygon
var geometry = gc.getGeometryRef(i);
for (var j = 0; j < geometry.GetGeometryCount(); j++)
{
//And here we have the rings. First one is the outer, all others are inner, defining holes
var ring = geometry.GetGeometryRef(j);
}
}
This only works if you already know it's a multipolygon. Unless this is an entirely static script where you know the inputs, you'll need to add type checks (GetGeometryType()) to ensure the GeometryCollection is what you expect it to be.
If you check the main API page for OGRGeometry, you can nicely see how the different types of geometry are "related" and inherit from each other.
Best Answer
I can see to ways of doing this:
Method 1:
Use add ring to cut the holes you need;
In the Settings > snapping options check the avoid intersection for that particular layer;
Use add feature, and draw a polygon around your ring or rings;
The new feature will take the shape of the hole.
Method 2:
This tool will automatically cut and fill the holes.