Bases: pygplates.GeometryOnSphere
Represents a polygon on the surface of the unit length sphere. Polygons are equality (==, !=) comparable (but not hashable  cannot be used as a key in a dict). See PointOnSphere for an overview of equality in the presence of limited floatingpoint precision.
A polygon instance is both:
In addition a polygon instance is directly iterable over its points (without having to use get_points()):
polygon = pygplates.PolygonOnSphere(points)
for point in polygon:
...
...and so the following operations for accessing the points are supported:
Operation  Result 

len(polygon)  number of vertices in polygon 
for p in polygon  iterates over the vertices p of polygon 
p in polygon  True if p is equal to a vertex of polygon 
p not in polygon  False if p is equal to a vertex of polygon 
polygon[i]  the vertex of polygon at index i 
polygon[i:j]  slice of polygon from i to j 
polygon[i:j:k]  slice of polygon from i to j with step k 
Note
if p in polygon does not test whether a point p is inside the the interior of a polygon  use is_point_in_polygon() for that instead.
# Get a list of points from an existing 'polygon'.
points = list(polygon)
# Modify the points list somehow.
points[0] = pygplates.PointOnSphere(...)
points.append(pygplates.PointOnSphere(...))
# 'polygon' now references a new PolygonOnSphere instance.
polygon = pygplates.PolygonOnSphere(points)
The following example demonstrates creating a PolygonOnSphere from a PolylineOnSphere:
polygon = pygplates.PolygonOnSphere(polyline)
Note
A polygon closes the loop between its last and first points so there’s no need to make the first and last points equal.
A PolygonOnSphere object can be constructed in more than one way...
Create a polygon from a sequence of (x,y,z) or (latitude,longitude) points.
param points:  A sequence of (x,y,z) points, or (latitude,longitude) points (in degrees). 

type points:  Any sequence of PointOnSphere or LatLonPoint or tuple (float,float,float) or tuple (float,float) 
raises:  InvalidLatLonError if any latitude or longitude is invalid 
raises:  ViolatedUnitVectorInvariantError if any (x,y,z) is not unit magnitude 
raises:  InvalidPointsForPolygonConstructionError if sequence has less than three points or if any two points (adjacent in the points sequence) are antipodal to each other (on opposite sides of the globe) 
Note
The sequence must contain at least three points in order to be a valid polygon, otherwise InvalidPointsForPolygonConstructionError will be raised.
During creation, a GreatCircleArc is created between each adjacent pair of of points in points  see get_segments(). The last arc is created between the last and first points to close the loop of the polygon. For this reason you do not need to ensure that the first and last points have the same position (although it’s not an error if this is the case because the final arc will then just have a zero length).
It is not an error for adjacent points in the sequence to be coincident. In this case each GreatCircleArc between two such adjacent points will have zero length (GreatCircleArc.is_zero_length() will return True) and will have no rotation axis (GreatCircleArc.get_rotation_axis() will raise an error).
The following example shows a few different ways to create a polygon:
points = []
points.append(pygplates.PointOnSphere(...))
points.append(pygplates.PointOnSphere(...))
points.append(pygplates.PointOnSphere(...))
polygon = pygplates.PolygonOnSphere(points)
points = []
points.append((lat1,lon1))
points.append((lat2,lon2))
points.append((lat3,lon3))
polygon = pygplates.PolygonOnSphere(points)
points = []
points.append([x1,y1,z1])
points.append([x2,y2,z2])
points.append([x3,y3,z3])
polygon = pygplates.PolygonOnSphere(points)
If you have latitude/longitude values but they are not a sequence of tuples or if the latitude/longitude order is swapped then the following examples demonstrate how you could restructure them:
# Flat lat/lon array.
points = numpy.array([lat1, lon1, lat2, lon2, lat3, lon3])
polygon = pygplates.PolygonOnSphere(zip(points[::2],points[1::2]))
# Flat lon/lat list (ie, different latitude/longitude order).
points = [lon1, lat1, lon2, lat2, lon3, lat3]
polygon = pygplates.PolygonOnSphere(zip(points[1::2],points[::2]))
# Separate lat/lon arrays.
lats = numpy.array([lat1, lat2, lat3])
lons = numpy.array([lon1, lon2, lon3])
polygon = pygplates.PolygonOnSphere(zip(lats,lons))
# Lon/lat list of tuples (ie, different latitude/longitude order).
points = [(lon1, lat1), (lon2, lat2), (lon3, lat3)]
polygon = pygplates.PolygonOnSphere([(lat,lon) for lon, lat in points])
Create a polygon from a GeometryOnSphere.
param geometry:  The point, multipoint, polyline or polygon geometry to convert from. 

type geometry:  GeometryOnSphere 
param allow_one_or_two_points:  
Whether geometry is allowed to be a PointOnSphere or a MultiPointOnSphere containing only one or two points  if allowed then one of those points is duplicated since a PolygonOnSphere requires at least three points  default is True.  
type allow_one_or_two_points:  
bool  
raises:  InvalidPointsForPolygonConstructionError if geometry is a PointOnSphere, or a MultiPointOnSphere with one or two points (and allow_one_or_two_points is False), or if any two consecutive points in a MultiPointOnSphere are antipodal to each other (on opposite sides of the globe) 
If allow_one_or_two_points is True then geometry can be PointOnSphere, MultiPointOnSphere, PolylineOnSphere or PolygonOnSphere. However if allow_one_or_two_points is False then geometry must be a PolygonOnSphere, or a MultiPointOnSphere or PolylineOnSphere containing at least three points to avoid raising InvalidPointsForPolygonConstructionError.
During creation, a GreatCircleArc is created between each adjacent pair of geometry points  see get_segments().
It is not an error for adjacent points in a geometry sequence to be coincident. In this case each GreatCircleArc between two such adjacent points will have zero length (GreatCircleArc.is_zero_length() will return True) and will have no rotation axis (GreatCircleArc.get_rotation_axis() will raise an error). However if two such adjacent points are antipodal (on opposite sides of the globe) then InvalidPointsForPolygonConstructionError will be raised
To create a PolygonOnSphere from any geometry type:
polygon = pygplates.PolygonOnSphere(geometry)
To create a PolygonOnSphere from any geometry containing at least three points:
try:
polygon = pygplates.PolygonOnSphere(geometry, allow_one_or_two_points=False)
except pygplates.InvalidPointsForPolygonConstructionError:
... # Handle failure to convert 'geometry' to a PolygonOnSphere.
Methods
__init__(...)  A PolygonOnSphere object can be constructed in more than one way... 
clone()  Create a duplicate of this geometry (derived) instance. 
distance(geometry1, geometry2, ...)  [staticmethod] Returns the (minimum) distance between two geometries (in radians). 
get_arc_length()  Returns the total arc length of this polygon (in radians). 
get_area()  Returns the area of this polygon (on a sphere of unit radius). 
get_boundary_centroid()  Returns the boundary centroid of this polygon. 
get_interior_centroid()  Returns the interior centroid of this polygon. 
get_orientation()  Returns whether this polygon is clockwise or counterclockwise. 
get_points()  Returns a readonly sequence of points in this geometry. 
get_segments()  Returns a readonly sequence of segments in this polyline. 
get_signed_area()  Returns the signed area of this polygon (on a sphere of unit radius). 
is_point_in_polygon(point)  Determines whether the specified point lies within the interior of this polygon. 
partition(geometry, ...)  Partition a geometry into optional inside/outside lists of partitioned geometry pieces. 
to_lat_lon_array()  Returns the sequence of points, in this geometry, as a numpy array of (latitude,longitude) pairs (in degrees). 
to_lat_lon_list()  Returns the sequence of points, in this geometry, as (latitude,longitude) tuples (in degrees). 
to_lat_lon_point_list()  Returns the sequence of points, in this geometry, as lat lon points. 
to_tessellated(tessellate_radians)  Returns a new polygon that is tessellated version of this polygon. 
to_xyz_array()  Returns the sequence of points, in this geometry, as a numpy array of (x,y,z) triplets. 
to_xyz_list()  Returns the sequence of points, in this geometry, as (x,y,z) cartesian coordinate tuples. 
Create a duplicate of this geometry (derived) instance.
Return type:  GeometryOnSphere 

[staticmethod] Returns the (minimum) distance between two geometries (in radians).
Parameters: 


Returns:  distance (in radians), or a tuple containing distance and the closest point on each geometry if return_closest_positions is True, or a tuple containing distance and the indices of the closest point (for multipoints) or segment (for polylines and polygons) on each geometry if return_closest_indices is True, or a tuple containing distance and the closest point on each geometry and the indices of the closest point (for multipoints) or segment (for polylines and polygons) on each geometry if both return_closest_positions and return_closest_indices are True, or None if distance_threshold_radians is specified and exceeded 
Return type:  float, or tuple (float, PointOnSphere, PointOnSphere) if return_closest_positions is True, or tuple (float, int, int) if return_closest_indices is True, or tuple (float, PointOnSphere, PointOnSphere, int, int) if both return_closest_positions and return_closest_indices are True, or None 
The returned distance is the shortest path between geometry1 and geometry2 along the surface of the sphere (great circle arc path). To convert the distance from radians (distance on a unit radius sphere) to real distance you will need to multiply it by the Earth’s radius (see Earth).
Each geometry (geometry1 and geometry2) can be any of the four geometry types (PointOnSphere, MultiPointOnSphere, PolylineOnSphere and PolygonOnSphere) allowing all combinations of distance calculations:
distance_radians = pygplates.GeometryOnSphere.distance(point1, point2)
distance_radians = pygplates.GeometryOnSphere.distance(point1, multi_point2)
distance_radians = pygplates.GeometryOnSphere.distance(point1, polyline2)
distance_radians = pygplates.GeometryOnSphere.distance(point1, polygon2)
distance_radians = pygplates.GeometryOnSphere.distance(multi_point1, point2)
distance_radians = pygplates.GeometryOnSphere.distance(multi_point1, multi_point2)
distance_radians = pygplates.GeometryOnSphere.distance(multi_point1, polyline2)
distance_radians = pygplates.GeometryOnSphere.distance(multi_point1, polygon2)
distance_radians = pygplates.GeometryOnSphere.distance(polyline1, point2)
distance_radians = pygplates.GeometryOnSphere.distance(polyline1, multi_point2)
distance_radians = pygplates.GeometryOnSphere.distance(polyline1, polyline2)
distance_radians = pygplates.GeometryOnSphere.distance(polyline1, polygon2)
distance_radians = pygplates.GeometryOnSphere.distance(polygon1, point2)
distance_radians = pygplates.GeometryOnSphere.distance(polygon1, multi_point2)
distance_radians = pygplates.GeometryOnSphere.distance(polygon1, polyline2)
distance_radians = pygplates.GeometryOnSphere.distance(polygon1, polygon2)
If distance_threshold_radians is specified and the (minimum) distance between the two geometries exceeds this threshold then None is returned.
# Perform a regionofinterest query between two geometries to see if
# they are within 1 degree of each other.
#
# Note that we explicitly test against None because a distance of zero is equilavent to False.
if pygplates.GeometryOnSphere.distance(geometry1, geometry2, math.radians(1)) is not None:
...
Note that it is more efficient to specify a distance threshold parameter (as shown in the above example) than it is to explicitly compare the returned distance to a threshold yourself. This is because internally each polyline/polygon geometry has an inbuilt spatial tree that optimises distance queries.
The minimum distance between two geometries is zero (and hence does not exceed any distance threshold) if:
If return_closest_positions is True then the closest point on each geometry is returned (unless the distance threshold is exceeded, if specified). Note that for polygons the closest point is always on the polygon boundary regardless of whether the polygon is solid or not (see geometry1_is_solid and geometry2_is_solid). Also note that the closest position on a polyline/polygon can be anywhere along any of its segments. In other words it’s not the nearest vertex of the polyline/polygon  it’s the nearest point on the polyline/polygon itself. If both geometries are polyline/polygon and they intersect then the intersection point is returned (same point for both geometries). If both geometries are polyline/polygon and they intersect more than once then any intersection point can be returned (but the same point is returned for both geometries). If one geometry is a solid PolygonOnSphere and the other geometry is a MultiPointOnSphere with more than one of its points inside the interior of the polygon then the closest point in the multipoint could be any of those inside points.
distance_radians, closest_point_on_geometry1, closest_point_on_geometry2 = \
pygplates.GeometryOnSphere.distance(geometry1, geometry2, return_closest_positions=True)
If return_closest_indices is True then the index of the closest point (for multipoints) or the index of the closest segment (for polylines and polygons) is returned (unless the threshold is exceeded, if specified). Note that for point geometries the index will always be zero. The point indices can be used to index directly into MultiPointOnSphere and the segment indices can be used with PolylineOnSphere.get_segments() or PolygonOnSphere.get_segments() as shown in the following example:
distance_radians, closest_point_index_on_multipoint, closest_segment_index_on_polyline = \
pygplates.GeometryOnSphere.distance(multipoint, polyline, return_closest_indices=True)
closest_point_on_multipoint = multipoint[closest_point_index_on_multipoint]
closest_segment_on_polyline = polyline.get_segments()[closest_segment_index_on_polyline]
closest_segment_normal_vector = closest_segment_on_polyline.get_great_circle_normal()
If both return_closest_positions and return_closest_indices are True:
# Distance between a polyline and a solid polygon.
distance_radians, polyline_point, polygon_point, polyline_segment_index, polygon_segment_index = \
pygplates.GeometryOnSphere.distance(
polyline,
polygon,
return_closest_positions=True,
return_closest_indices=True,
geometry2_is_solid=True)
Returns the total arc length of this polygon (in radians).
Return type:  float 

Returns the area of this polygon (on a sphere of unit radius).
Return type:  float 

The area is essentially the absolute value of the signed area.
To convert to area on the Earth’s surface, multiply the result by the Earth radius squared (see Earth).
Returns the boundary centroid of this polygon.
Return type:  PointOnSphere 

The boundary centroid is calculated as a weighted average of the midpoints of the great circle arcs of this polygon with weighting proportional to the individual arc lengths.
Note that if you want a centroid closer to the centreofmass of the polygon interior then use get_interior_centroid() instead.
Returns the interior centroid of this polygon.
Return type:  PointOnSphere 

The interior centroid is calculated as a weighted average of the centroids of spherical triangles formed by the great circle arcs of this polygon and its (boundary) centroid with weighting proportional to the signed area of each individual spherical triangle. The three vertices of each spherical triangle consist of the polygon (boundary) centroid and the two end points of a great circle arc.
This centroid is useful when the centreofmass of the polygon interior is desired. For example, the interior centroid of a bottomheavy, pearshaped polygon will be closer to the bottom of the polygon. This centroid is not exactly at the centreofmass, but it will be a lot closer to the real centreofmass than get_boundary_centroid().
Returns whether this polygon is clockwise or counterclockwise.
Return type:  PolygonOnSphere.Orientation 

If this polygon is clockwise (when viewed from above the surface of the sphere) then PolygonOnSphere.Orientation.clockwise is returned, otherwise PolygonOnSphere.Orientation.counter_clockwise is returned.
if polygon.get_orientation() == pygplates.PolygonOnSphere.Orientation.clockwise:
print 'Orientation is clockwise'
else:
print 'Orientation is counterclockwise'
Returns a readonly sequence of points in this geometry.
Return type:  a readonly sequence of PointOnSphere 

The following operations for accessing the points in the returned readonly sequence are supported:
Operation  Result 

len(seq)  length of seq 
for p in seq  iterates over the points p of seq 
p in seq  True if p is equal to a point in seq 
p not in seq  False if p is equal to a point in seq 
seq[i]  the point of seq at index i 
seq[i:j]  slice of seq from i to j 
seq[i:j:k]  slice of seq from i to j with step k 
Note
The returned sequence is readonly and cannot be modified.
Note
If you want a modifiable sequence consider wrapping the returned sequence in a list using something like points = list(geometry.get_points()) but note that modifying the list (eg, inserting a new point) will not modify the original geometry.
If this geometry is a PointOnSphere then the returned sequence has length one. For other geometry types (MultiPointOnSphere, PolylineOnSphere and PolygonOnSphere) the length will equal the number of points contained within.
The following example demonstrates some uses of the above operations:
points = geometry.get_points()
for point in points:
print point
first_point = points[0]
last_point = points[1]
for point in polyline:
print point
first_point = polyline[0]
last_point = polyline[1]
Note
There are also methods that return the sequence of points as (latitude,longitude) values and (x,y,z) values contained in lists and numpy arrays (to_lat_lon_list(), to_lat_lon_array(), to_xyz_list() and to_xyz_array()).
Returns a readonly sequence of segments in this polyline.
Return type:  a readonly sequence of GreatCircleArc 

The following operations for accessing the great circle arcs in the returned readonly sequence are supported:
Operation  Result 

len(seq)  number of segments of the polygon 
for s in seq  iterates over the segments s of the polygon 
s in seq  True if s is an segment of the polygon 
s not in seq  False if s is an segment of the polygon 
seq[i]  the segment of the polygon at index i 
seq[i:j]  slice of segments of the polygon from i to j 
seq[i:j:k]  slice of segments of the polygon from i to j with step k 
Note
Between each adjacent pair of points there is an segment such that the number of points equals the number of segments.
The following example demonstrates some uses of the above operations:
polygon = pygplates.PolygonOnSphere(points)
...
segments = polygon.get_segments()
for segment in segments:
if not segment.is_zero_length():
segment_midpoint_direction = segment.get_arc_direction(0.5)
first_segment = segments[0]
last_segment = segments[1]
Note
The end point of the last segment is equal to the start point of the first segment.
Note
The returned sequence is readonly and cannot be modified.
Note
If you want a modifiable sequence consider wrapping the returned sequence in a list using something like segments = list(polygon.get_segments()) but note that modifying the list (eg, appending a new segment) will not modify the original polygon.
Returns the signed area of this polygon (on a sphere of unit radius).
Return type:  float 

If this polygon is clockwise (when viewed from above the surface of the sphere) then the returned area will be negative, otherwise it will be positive. However if you only want to determine the orientation of this polygon then get_orientation() is more efficient than comparing the sign of the area.
To convert to signed area on the Earth’s surface, multiply the result by the Earth radius squared (see Earth).
See also
Determines whether the specified point lies within the interior of this polygon.
Parameters:  point (PointOnSphere or LatLonPoint or (latitude,longitude), in degrees, or (x,y,z)) – the point to be tested 

Return type:  bool 
Test if a (latitude, longitude) point is inside a polygon:
if polygon.is_point_in_polygon((latitude, longitude)):
...
Partition a geometry into optional inside/outside lists of partitioned geometry pieces.
Parameters: 


Return type:  PolygonOnSphere.PartitionResult 
The returned result is:
If partitioned_geometries_inside is specified then it must be a list and any part of geometry inside this polygon is added to it. So if PolygonOnSphere.PartitionResult.inside is returned this means geometry is added and if PolygonOnSphere.PartitionResult.intersecting is returned this means the partitioned parts of geometry inside this polygon are added.
If partitioned_geometries_outside is specified then if must be a list and any part of geometry outside this polygon is added to it. So if PolygonOnSphere.PartitionResult.outside is returned this means geometry is added and if PolygonOnSphere.PartitionResult.intersecting is returned this means the partitioned parts of geometry outside this polygon are added.
Note
Partitioning point geometries returns only PolygonOnSphere.PartitionResult.inside or PolygonOnSphere.PartitionResult.outside.
If a partitioned multipoint contains points both inside and outside this polygon then PolygonOnSphere.PartitionResult.intersecting is returned. In this case the points inside are added as a single MultiPointOnSphere to partitioned_geometries_inside (if specified) and the points outside are added as a single MultiPointOnSphere to partitioned_geometries_outside (if specified).
Warning
Test if a polyline is entirely inside a polygon:
if polygon.partition(polyline) == pygplates.PolygonOnSphere.PartitionResult.inside:
...
Find the bits of a polyline that are outside a group of continental polygons:
# Start with the original polyline to partition.
oceanic_polylines = [polyline]
for continental_polygon in continental_polygons:
# Iterate over the polylines that are outside the continental polygons processed so far.
current_oceanic_polylines = oceanic_polylines
# The new list of polylines will also be outside the current continental polygon.
oceanic_polylines = []
for current_oceanic_polyline in current_oceanic_polylines:
continental_polygon.partition(current_oceanic_polyline, partitioned_geometries_outside=oceanic_polylines)
# The final result is in 'oceanic_polylines'.
Returns the sequence of points, in this geometry, as a numpy array of (latitude,longitude) pairs (in degrees).
Returns:  an array of (latitude,longitude) pairs (in degrees) 

Return type:  2D numpy array with number of points as outer dimension and an inner dimension of two 
Warning
This method should only be called if the numpy module is available.
If this geometry is a PointOnSphere then the returned sequence has length one. For other geometry types (MultiPointOnSphere, PolylineOnSphere and PolygonOnSphere) the length will equal the number of points contained within.
If you want the latitude/longitude order swapped in the returned tuples then the following is one way to achieve this:
# Convert (latitude,longitude) to (longitude,latitude).
geometry.to_lat_lon_array()[:, (1,0)]
If you need a flat 1D numpy array then you can do something like:
geometry.to_lat_lon_array().flatten()
Returns the sequence of points, in this geometry, as (latitude,longitude) tuples (in degrees).
Returns:  a list of (latitude,longitude) tuples (in degrees) 

Return type:  list of (float,float) tuples 
If this geometry is a PointOnSphere then the returned sequence has length one. For other geometry types (MultiPointOnSphere, PolylineOnSphere and PolygonOnSphere) the length will equal the number of points contained within.
If you want the latitude/longitude order swapped in the returned tuples then the following is one way to achieve this:
# Convert (latitude,longitude) to (longitude,latitude).
[(lon,lat) for lat, lon in geometry.to_lat_lon_list()]
Returns the sequence of points, in this geometry, as lat lon points.
Return type:  list of LatLonPoint 

If this geometry is a PointOnSphere then the returned sequence has length one. For other geometry types (MultiPointOnSphere, PolylineOnSphere and PolygonOnSphere) the length will equal the number of points contained within.
Returns a new polygon that is tessellated version of this polygon.
Parameters:  tessellate_radians (float) – maximum tessellation angle (in radians) 

Return type:  PolygonOnSphere 
Adjacent points (in the returned tessellated polygon) are separated by no more than tessellate_radians on the globe.
Create a polygon tessellated to 2 degrees:
tessellated_polygon = polygon.to_tessellated(math.radians(2))
Note
Since a PolygonOnSphere is immutable it cannot be modified. Which is why a new (tessellated) PolygonOnSphere is returned.
Note
The distance between adjacent points (in the tessellated polygon) will not be exactly uniform. This is because each segment in the original polygon is tessellated to the nearest integer number of points (that keeps that segment under the threshold) and hence each original segment will have a slightly different tessellation angle.
See also
Returns the sequence of points, in this geometry, as a numpy array of (x,y,z) triplets.
Returns:  an array of (x,y,z) triplets 

Return type:  2D numpy array with number of points as outer dimension and an inner dimension of three 
Warning
This method should only be called if the numpy module is available.
If you need a flat 1D numpy array then you can do something like:
geometry.to_xyz_array().flatten()
If this geometry is a PointOnSphere then the returned sequence has length one. For other geometry types (MultiPointOnSphere, PolylineOnSphere and PolygonOnSphere) the length will equal the number of points contained within.
Returns the sequence of points, in this geometry, as (x,y,z) cartesian coordinate tuples.
Returns:  a list of (x,y,z) tuples 

Return type:  list of (float,float,float) tuples 
If this geometry is a PointOnSphere then the returned sequence has length one. For other geometry types (MultiPointOnSphere, PolylineOnSphere and PolygonOnSphere) the length will equal the number of points contained within.