Following the declaration of my PolygonPointSampler’s base class in the previous post, I will now start to implement multiple classes each representing a different method to derive sample points for a given polygon.
Centroid sampling
Let’s start with the simplest polygon-to-point sampling method available: the creation of a centroid point. The centroid represents the geometric center of a polygon. If we’re looking at a triangle it emerges as the intersection of the triangle’s median lines, hence it is sometimes also called the median point. Shapely allows to derive a polygon’s centroid by querying the corresponding attribute:
>>> from shapely.geometry import Polygon >>> polygon = Polygon([(0,0), (6,0), (0,6)]) >>> centroid = polygon.centroid >>> print centroid POINT (2 2)
Applying this method to some real-word data will often lead to the phenomenon visible below: The centroid comes to lie outside of the original polygon’s interior.
Representative point sampling
To deal with this problem, Shapely equips geometry objects with a method called representative_point()
that – as the documentation reads – “returns a cheaply computed point that is guaranteed to be within the geometric object”. Judging from the Shapely source code this method goes back to the PointOnSurface function provided by GEOS. I haven’t been able to find out how exactly it is guaranteed that the sample point is an interior point, but from the looks of it, it is most likely that the algorithm described in a fitting thread at gis.stackexchange.com has been applied to it. In any way for our Python example the code would look like the following:
>>> representative_point = polygon.representative_point() >>> print representative_point POINT (1.5 3)
Please note that querying for the representative point of a polygon actually calls a Python function – as indicated by the brackets following the according declaration – while the centroid is a property of the Shapely polygon object. Using real-world data we arrive at the situation displayed below:
It is also possible to apply the sampler on multi-part polygons:
Putting it all together
Based on the knowledge laid out above, it is now possible to furnish the previously created PolygonPointSampler
base object with extensions that create sample points by either using the centroid or representative point method. I have called them CentroidSampler
and RepresentativePointSampler
, respectively:
class CentroidSampler(PolygonPointSampler): def perform_sampling(self): u""" Perform sampling by reprensenting each source polygon with its centroid. """ if not self.prepared: self.prepare_sampling() for src in self.src: self.samples.append(src.centroid)
class RepresentativePointSampler(PolygonPointSampler): def perform_sampling(self): u""" Perform sampling by representing each source polygon with a representative point whose coordinates are guaranteed to be within the polygon's geometry. """ if not self.prepared: self.prepare_sampling() for src in self.src: self.samples.append(src.representative_point())