# Module gplately.geometry

Tools for converting PyGPlates or GPlately geometries to Shapely geometries for mapping (and vice versa).

Supported PyGPlates geometries inherit from the following classes:

Note: GPlately geometries derive from the GeometryOnSphere and pygplates.GeometryOnSphere base classes.

Supported Shapely geometric objects include:

• Point: a single point in 2D space with coordinate tuple (x,y) or 3D space with coordinate tuple (x,y,z).
• LineString: a sequence of points joined together to form a line (a list of point coordinate tuples).
• Polygon: a sequence of points joined together to form the outer ring of a filled area, or a hole (a list of at least three point coordinate tuples).

Also supported are collections of geometric objects, such as:

• MultiPoint: a list of Point objects (a list of point coordinate tuples).
• MultiLineString: a list of LineString objects (a list containing lists of point coordinate tuples).
• MultiPolygon: a list of Polygon objects (a list containing lists of point coordinate tuples that define exterior rings and/or holes).

Converting PyGPlates geometries into Shapely geometries involves:

• wrapping geometries at the dateline: this involves splitting a polygon, MultiPolygon, line segment or MultiLine segment between connecting points at the dateline. This is to ensure the geometry's points are joined along the short path rather than the long path horizontally across the 2D map projection display.
• ordering geometries counter-clockwise

Input PyGPlates geometries are converted to the following Shapely geometries:

• PointOnSphere or LatLonPoint: Point
• MultiPointOnSphere: MultiPoint
• PolylineOnSphere: LineString or MultiLineString
• PolygonOnSphere: Polygon or MultiPolygon

Converting Shapely geometries into PyGPlates geometries: Input Shapely geometries are converted to the following PyGPlates geometries:

• Point: PointOnSphere
• MultiPoint: MultiPointOnSphere
• LineString: PolylineOnSphere
• LinearRing or Polygon: PolygonOnSphere
Expand source code
"""Tools for converting PyGPlates or GPlately geometries to Shapely geometries for mapping (and vice versa).

Supported PyGPlates geometries inherit from the following classes:

* [pygplates.GeometryOnSphere](https://www.gplates.org/docs/pygplates/generated/pygplates.geometryonsphere): This
class has the following derived GeometryOnSphere classes:
* [pygplates.PointOnSphere](https://www.gplates.org/docs/pygplates/generated/pygplates.pointonsphere#pygplates.PointOnSphere)
* [pygplates.MultiPointOnSphere](https://www.gplates.org/docs/pygplates/generated/pygplates.multipointonsphere#pygplates.MultiPointOnSphere)
* [pygplates.PolylineOnSphere](https://www.gplates.org/docs/pygplates/generated/pygplates.polylineonsphere#pygplates.PolylineOnSphere)
* [pygplates.PolygonOnSphere](https://www.gplates.org/docs/pygplates/generated/pygplates.polygononsphere#pygplates.PolygonOnSphere)

* [pygplates.LatLonPoint](https://www.gplates.org/docs/pygplates/generated/pygplates.latlonpoint)
* [pygplates.ReconstructedFeatureGeometry](https://www.gplates.org/docs/pygplates/generated/pygplates.reconstructedfeaturegeometry)
* [pygplates.ResolvedTopologicalLine](https://www.gplates.org/docs/pygplates/generated/pygplates.resolvedtopologicalline)
* [pygplates.ResolvedTopologicalBoundary](https://www.gplates.org/docs/pygplates/generated/pygplates.resolvedtopologicalboundary)
* [pygplates.ResolvedTopologicalNetwork](https://www.gplates.org/docs/pygplates/generated/pygplates.resolvedtopologicalnetwork)

Note: GPlately geometries derive from the GeometryOnSphere and pygplates.GeometryOnSphere base classes.

Supported Shapely geometric objects include:

* __Point__: a single point in 2D space with coordinate tuple (x,y) or 3D space with coordinate tuple (x,y,z).
* __LineString__: a sequence of points joined together to form a line (a list of point coordinate tuples).
* __Polygon__: a sequence of points joined together to form the outer ring of a filled area, or a hole (a list of at least
three point coordinate tuples).

Also supported are collections of geometric objects, such as:

* __MultiPoint__: a list of __Point__ objects (a list of point coordinate tuples).
* __MultiLineString__: a list of __LineString__ objects (a list containing lists of point coordinate tuples).
* __MultiPolygon__:  a list of __Polygon__ objects (a list containing lists of point coordinate tuples that define exterior rings and/or holes).

__Converting PyGPlates geometries into Shapely geometries__ involves:

* __wrapping geometries at the dateline__: this involves splitting a polygon, MultiPolygon, line segment or MultiLine segment between
connecting points at the dateline. This is to ensure the geometry's points are joined along the short path rather than
the long path horizontally across the 2D map projection display.
* __ordering geometries counter-clockwise__

Input PyGPlates geometries are converted to the following Shapely geometries:

- PointOnSphere or LatLonPoint: Point
- MultiPointOnSphere: MultiPoint
- PolylineOnSphere: LineString or MultiLineString
- PolygonOnSphere: Polygon or MultiPolygon

__Converting Shapely geometries into PyGPlates geometries__:
Input Shapely geometries are converted to the following PyGPlates geometries:

- Point: PointOnSphere
- MultiPoint: MultiPointOnSphere
- LineString: PolylineOnSphere
- LinearRing or Polygon: PolygonOnSphere

"""
import numpy as np
import pygplates
from shapely.geometry import (
LinearRing as _LinearRing,
LineString as _LineString,
MultiLineString as _MultiLineString,
MultiPoint as _MultiPoint,
MultiPolygon as _MultiPolygon,
Point as _Point,
Polygon as _Polygon,
)
from shapely.geometry.base import (
BaseGeometry as _BaseGeometry,
BaseMultipartGeometry as _BaseMultipartGeometry,
)

__all__ = [
"GeometryOnSphere",
"LatLonPoint",
"MultiPointOnSphere",
"PointOnSphere",
"PolygonOnSphere",
"PolylineOnSphere",
"pygplates_to_shapely",
"shapely_to_pygplates",
"wrap_geometries",
]

class GeometryOnSphere(pygplates.GeometryOnSphere):
"""Class to mix in to_shapely method to all GPlately geometry classes.

All GPlately geometry classes inherit from this class, in addition
to their PyGPlates base class.
"""

def to_shapely(
self,
central_meridian=0.0,
tessellate_degrees=None,
validate=False,
force_ccw=False,
explode=False,
):
"""Convert to Shapely geometry.

--------
pygplates_to_shapely : Equivalent function.
"""
return pygplates_to_shapely(
self,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)

@classmethod
def from_shapely(cls, geom):
converted = shapely_to_pygplates(geom)
return cls(converted)

class PointOnSphere(pygplates.PointOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.PointOnSphere, incorporating
to_shapely method
"""

pass

class MultiPointOnSphere(pygplates.MultiPointOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.MultiPointOnSphere, incorporating
to_shapely method
"""

pass

class PolylineOnSphere(pygplates.PolylineOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.PolylineOnSphere, incorporating
to_shapely method
"""

pass

class PolygonOnSphere(pygplates.PolygonOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.PolygonOnSphere, incorporating
to_shapely method
"""

pass

class LatLonPoint(pygplates.LatLonPoint):
"""GPlately equivalent of pygplates.LatLonPoint, incorporating
to_shapely method
"""

def to_shapely(self, central_meridian=0.0, tessellate_degrees=None):
return pygplates_to_shapely(
self,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
)

def pygplates_to_shapely(
geometry,
central_meridian=0.0,
tessellate_degrees=None,
validate=False,
force_ccw=False,
explode=False
):
"""Convert one or more PyGPlates or GPlately geometries to Shapely format.

Parameters
----------
geometry : pygplates.GeometryOnSphere or pygplates.LatLonPoint or list
The geometry or geometries to convert.
central_meridian : float, default: 0.0
The central meridian around which to wrap geometries;
geometries will be split at the antimeridian.
tessellate_degrees : float, optional
If provided, the geometry will be tessellated to this
resolution prior to conversion.
validate : bool, default: False
Attempt to ensure output geometry is valid by applying a buffer of 0.
force_ccw : bool, default: False
Ensure the coordinates of the output geometry are counter-clockwise
(only applies to polygons).
explode : bool, default: False
Convert multi-part output geometries to multiple single-part
geometries.

Returns
-------
output_geometry : shapely.geometry.base.BaseGeometry or list
Converted Shapely geometry or geometries.

Notes
-----
If a single input geometry was passed, output_geometry will be a
subclass of shapely.geometry.base.BaseGeometry. Otherwise,
output_geometry will be a list of the same length as the input.

Input geometries that were split while wrapping around
central_meridian will produce multi-part output geometries, unless
explode=True is specified.

Input geometry types are converted as follows:
- PointOnSphere or LatLonPoint:
Point
- MultiPointOnSphere:
MultiPoint
- PolylineOnSphere:
LineString or
MultiLineString
- PolygonOnSphere:
Polygon or
MultiPolygon
"""
if _contains_pygplates_geometries(geometry):
return [
pygplates_to_shapely(
i,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
)
for i in geometry
]

if isinstance(geometry, pygplates.LatLonPoint):
geometry = geometry.to_point_on_sphere()
if isinstance(geometry, pygplates.ReconstructedFeatureGeometry):
geometry = geometry.get_reconstructed_geometry()
if isinstance(
geometry,
(
pygplates.ResolvedTopologicalLine,
pygplates.ResolvedTopologicalBoundary,
pygplates.ResolvedTopologicalNetwork,
),
):
geometry = geometry.get_resolved_geometry()
if not isinstance(geometry, pygplates.GeometryOnSphere):
raise TypeError("Invalid geometry type: " + str(type(geometry)))

wrapper = pygplates.DateLineWrapper(central_meridian=central_meridian)
wrapped = wrapper.wrap(geometry, tessellate_degrees=tessellate_degrees)

if isinstance(wrapped, pygplates.LatLonPoint):
return _Point(wrapped.to_lat_lon()[::-1])
if isinstance(wrapped, pygplates.DateLineWrapper.LatLonMultiPoint):
points = wrapped.get_points()
return _MultiPoint([i.to_lat_lon()[::-1] for i in points])

output_geoms = []
output_type = None
for i in wrapped:
if isinstance(i, pygplates.DateLineWrapper.LatLonPolyline):
tmp = _LineString([j.to_lat_lon()[::-1] for j in i.get_points()])
output_geoms.append(tmp)
output_type = _MultiLineString
elif isinstance(i, pygplates.DateLineWrapper.LatLonPolygon):
tmp = np.array([j.to_lat_lon()[::-1] for j in i.get_exterior_points()])
# tmp[:,1] = np.clip(tmp[:,1], -89, 89) # clip polygons near poles
tmp = _Polygon(tmp)
if (
force_ccw
and tmp.exterior is not None
and not tmp.exterior.is_ccw
):
tmp = _Polygon(list(tmp.exterior.coords)[::-1])
# tmp.exterior.coords = list(tmp.exterior.coords)[::-1]
if validate:
tmp = tmp.buffer(0.0)
# this is for pole-clipped polygons turned into MultiPolygons
if isinstance(tmp, _MultiPolygon):
#for geom in list(tmp):
for geom in tmp.geoms:
output_geoms.append(geom)
else:
output_geoms.append(tmp)
output_type = _MultiPolygon
else:
raise TypeError(
"Unrecognised output from pygplates.DateLineWrapper.wrap: "
+ str(type(i))
)
if output_type is None:
raise TypeError(
"Unrecognised output from pygplates.DateLineWrapper.wrap: "
+ str(type(wrapped))
)
# Empty geometries can sometimes occur by this point, causing nearly all
# subsequent geometric operations to fail
output_geoms = [i for i in output_geoms if not i.is_empty]
if force_ccw:
output_geoms = [_ensure_ccw(i) for i in output_geoms]
if len(output_geoms) == 1:
return output_geoms
if explode:
return output_geoms
return output_type(output_geoms)

def _ensure_ccw(geometry):
if (
isinstance(geometry, _Polygon)
and geometry.exterior is not None
and not geometry.exterior.is_ccw
):
return _Polygon(list(geometry.exterior.coords)[::-1])
return geometry

def shapely_to_pygplates(geometry):
"""Convert one or more Shapely geometries to gplately format.

Parameters
----------
geometry : shapely.geometry.base.BaseGeometry or list
The geometry or geometries to convert.

Returns
-------
output_geometry : GeometryOnSphere or list
Converted gplately geometry or geometries.

Notes
-----
If a single input geometry was passed, output_geometry will be a
subclass of GeometryOnSphere. Otherwise, output_geometry
will be a list of GeometryOnSphere, of the same length as
the input.

Input geometry types are converted as follows:
- Point: PointOnSphere
- MultiPoint: MultiPointOnSphere
- LineString: PolylineOnSphere
- LinearRing or Polygon: PolygonOnSphere

Multi-part input geometry types other than MultiPoint will be treated
as an iterable of their component single-part geometries.
"""
pygplates_conversion = {
_Point: PointOnSphere,
_MultiPoint: MultiPointOnSphere,
_LineString: PolylineOnSphere,
_LinearRing: PolygonOnSphere,
_Polygon: PolygonOnSphere,
}

if isinstance(geometry, _BaseMultipartGeometry) and not isinstance(
geometry, _MultiPoint
):
return [shapely_to_pygplates(i) for i in geometry.geoms]
if _contains_shapely_geometries(geometry):
# Recursively convert all elements in iterable of geometries
out = []
for i in geometry:
tmp = shapely_to_pygplates(i)
if isinstance(tmp, pygplates.GeometryOnSphere):
# Output is a single geometry
out.append(tmp)
else:
# Output should be a list of geometries
out.extend(tmp)
return out

for input_type in pygplates_conversion:
if isinstance(geometry, input_type):
output_type = pygplates_conversion[input_type]
break
else:
raise TypeError("Invalid geometry type: " + str(type(geometry)))
if isinstance(geometry, _MultiPoint):
coords = np.array([i.coords for i in geometry.geoms]).squeeze()
elif isinstance(geometry, _Polygon):
if geometry.exterior is None:
raise AttributeError("Polygon geometry has no exterior")
coords = np.array(geometry.exterior.coords).squeeze()[:-1, ...]
elif hasattr(geometry, "coords"):
coords = np.array(geometry.coords).squeeze()
else:
raise TypeError("Invalid geometry type: " + str(type(geometry)))
if coords.ndim > 1:
coords = np.fliplr(coords)
else:
coords = np.flip(coords)
return output_type(coords)

def wrap_geometries(
geometries,
central_meridian=0.0,
tessellate_degrees=None,
validate=False,
force_ccw=False,
explode=False,
):
"""Wrap one or more Shapely geometries around a central meridian.

Wrapped geometries will be split at the antimeridian.

Parameters
----------
geometry : shapely.geometry.base.BaseGeometry or list
The geometry or geometries to wrap.
central_meridian : float, default: 0.0
The central meridian around which to wrap geometries;
geometries will be split at the antimeridian.
tessellate_degrees : float, optional
If provided, the geometry will be tessellated to this
resolution prior to wrapping.
validate : bool, default: False
Attempt to ensure output geometry is valid by applying a buffer of 0.
force_ccw : bool, default: False
Ensure the coordinates of the output geometry are counter-clockwise
(only applies to polygons).
explode : bool, default: False
Convert multi-part output geometries to multiple single-part
geometries.

Returns
-------
output_geometries : shapely.geometry.base.BaseGeometry or list
Wrapped Shapely geometry or geometries.

Notes
-----
If a single input geometry was passed, output_geometry will be a
subclass of shapely.geometry.base.BaseGeometry. Otherwise,
output_geometry will be a list of the same length as the input,
unless explode=True is specified.

Input geometries that were split while wrapping around
central_meridian will produce multi-part output geometries, unless
explode=True is specified.
"""
if isinstance(geometries, _BaseGeometry):
return _wrap_geometry(
geometry=geometries,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)
else:
out = []
for i in geometries:
tmp = _wrap_geometry(
geometry=i,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)
if isinstance(tmp, _BaseGeometry):
out.append(tmp)
else:
out.extend(tmp)
return out

def _wrap_geometry(
geometry,
central_meridian=0.0,
tessellate_degrees=None,
validate=False,
force_ccw=False,
explode=False,
):
if not isinstance(geometry, _BaseGeometry):
raise TypeError("Invalid geometry type: " + str(type(geometry)))

converted = shapely_to_pygplates(geometry)
if isinstance(converted, pygplates.GeometryOnSphere):
out = [converted]
else:
out = []
for i in converted:
if isinstance(i, pygplates.GeometryOnSphere):
out.append(i)
else:
out.extend(i)
if explode:
out_tmp = []
for i in out:
tmp = pygplates_to_shapely(
geometry=i,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)
if isinstance(tmp, _BaseGeometry):
out_tmp.append(tmp)
else:
out_tmp.extend(tmp)
out = out_tmp
else:
out = [
pygplates_to_shapely(
geometry=i,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)
for i in out
]
if len(out) == 1:
return out
if explode:
return out
if isinstance(geometry, (_Point, _MultiPoint)):
return _MultiPoint(out)
if isinstance(geometry, (_LineString, _MultiLineString)):
return _MultiLineString(out)
if isinstance(geometry, (_LinearRing, _Polygon, _MultiPolygon)):
return _MultiPolygon(out)

def _contains_shapely_geometries(i):
"""Check if input is an iterable containing only Shapely geometries."""
if isinstance(i, _BaseGeometry):
return False
try:
# Check all elements in i are Shapely geometries
for j in i:
if not isinstance(j, _BaseGeometry):
break
else:
return True
except TypeError:  # i is not iterable
pass
return False

def _is_pygplates_geometry(geom):
return isinstance(
geom,
(
pygplates.GeometryOnSphere,
pygplates.LatLonPoint,
pygplates.ReconstructedFeatureGeometry,
pygplates.ResolvedTopologicalLine,
pygplates.ResolvedTopologicalBoundary,
pygplates.ResolvedTopologicalNetwork,
),
)

def _contains_pygplates_geometries(i):
"""Check if input is an iterable containing only PyGPlates geometries."""
if _is_pygplates_geometry(i):
return False
try:
# Check all elements in i are PyGPlates geometries
for j in i:
if not _is_pygplates_geometry(j):
break
else:
return True
except TypeError:  # i is not iterable
pass
return False

## Functions

 def pygplates_to_shapely(geometry, central_meridian=0.0, tessellate_degrees=None, validate=False, force_ccw=False, explode=False) 

Convert one or more PyGPlates or GPlately geometries to Shapely format.

## Parameters

geometry : pygplates.GeometryOnSphere or pygplates.LatLonPoint or list
The geometry or geometries to convert.
central_meridian : float, default: 0.0
The central meridian around which to wrap geometries; geometries will be split at the antimeridian.
tessellate_degrees : float, optional
If provided, the geometry will be tessellated to this resolution prior to conversion.
validate : bool, default: False
Attempt to ensure output geometry is valid by applying a buffer of 0.
force_ccw : bool, default: False
Ensure the coordinates of the output geometry are counter-clockwise (only applies to polygons).
explode : bool, default: False
Convert multi-part output geometries to multiple single-part geometries.

## Returns

output_geometry : shapely.geometry.base.BaseGeometry or list
Converted Shapely geometry or geometries.

If a single input geometry was passed, output_geometry will be a subclass of shapely.geometry.base.BaseGeometry. Otherwise, output_geometry will be a list of the same length as the input.

Input geometries that were split while wrapping around central_meridian will produce multi-part output geometries, unless explode=True is specified.

Input geometry types are converted as follows: - PointOnSphere or LatLonPoint: Point - MultiPointOnSphere: MultiPoint - PolylineOnSphere: LineString or MultiLineString - PolygonOnSphere: Polygon or MultiPolygon

 def shapely_to_pygplates(geometry) 

Convert one or more Shapely geometries to gplately format.

## Parameters

geometry : shapely.geometry.base.BaseGeometry or list
The geometry or geometries to convert.

## Returns

output_geometry : GeometryOnSphere or list
Converted gplately geometry or geometries.

## Notes

If a single input geometry was passed, output_geometry will be a subclass of GeometryOnSphere. Otherwise, output_geometry will be a list of GeometryOnSphere, of the same length as the input.

Input geometry types are converted as follows: - Point: PointOnSphere - MultiPoint: MultiPointOnSphere - LineString: PolylineOnSphere - LinearRing or Polygon: PolygonOnSphere

Multi-part input geometry types other than MultiPoint will be treated as an iterable of their component single-part geometries.

Expand source code
def shapely_to_pygplates(geometry):
"""Convert one or more Shapely geometries to gplately format.

Parameters
----------
geometry : shapely.geometry.base.BaseGeometry or list
The geometry or geometries to convert.

Returns
-------
output_geometry : GeometryOnSphere or list
Converted gplately geometry or geometries.

Notes
-----
If a single input geometry was passed, output_geometry will be a
subclass of GeometryOnSphere. Otherwise, output_geometry
will be a list of GeometryOnSphere, of the same length as
the input.

Input geometry types are converted as follows:
- Point: PointOnSphere
- MultiPoint: MultiPointOnSphere
- LineString: PolylineOnSphere
- LinearRing or Polygon: PolygonOnSphere

Multi-part input geometry types other than MultiPoint will be treated
as an iterable of their component single-part geometries.
"""
pygplates_conversion = {
_Point: PointOnSphere,
_MultiPoint: MultiPointOnSphere,
_LineString: PolylineOnSphere,
_LinearRing: PolygonOnSphere,
_Polygon: PolygonOnSphere,
}

if isinstance(geometry, _BaseMultipartGeometry) and not isinstance(
geometry, _MultiPoint
):
return [shapely_to_pygplates(i) for i in geometry.geoms]
if _contains_shapely_geometries(geometry):
# Recursively convert all elements in iterable of geometries
out = []
for i in geometry:
tmp = shapely_to_pygplates(i)
if isinstance(tmp, pygplates.GeometryOnSphere):
# Output is a single geometry
out.append(tmp)
else:
# Output should be a list of geometries
out.extend(tmp)
return out

for input_type in pygplates_conversion:
if isinstance(geometry, input_type):
output_type = pygplates_conversion[input_type]
break
else:
raise TypeError("Invalid geometry type: " + str(type(geometry)))
if isinstance(geometry, _MultiPoint):
coords = np.array([i.coords for i in geometry.geoms]).squeeze()
elif isinstance(geometry, _Polygon):
if geometry.exterior is None:
raise AttributeError("Polygon geometry has no exterior")
coords = np.array(geometry.exterior.coords).squeeze()[:-1, ...]
elif hasattr(geometry, "coords"):
coords = np.array(geometry.coords).squeeze()
else:
raise TypeError("Invalid geometry type: " + str(type(geometry)))
if coords.ndim > 1:
coords = np.fliplr(coords)
else:
coords = np.flip(coords)
return output_type(coords)
 def wrap_geometries(geometries, central_meridian=0.0, tessellate_degrees=None, validate=False, force_ccw=False, explode=False) 

Wrap one or more Shapely geometries around a central meridian.

Wrapped geometries will be split at the antimeridian.

## Parameters

geometry : shapely.geometry.base.BaseGeometry or list
The geometry or geometries to wrap.
central_meridian : float, default: 0.0
The central meridian around which to wrap geometries; geometries will be split at the antimeridian.
tessellate_degrees : float, optional
If provided, the geometry will be tessellated to this resolution prior to wrapping.
validate : bool, default: False
Attempt to ensure output geometry is valid by applying a buffer of 0.
force_ccw : bool, default: False
Ensure the coordinates of the output geometry are counter-clockwise (only applies to polygons).
explode : bool, default: False
Convert multi-part output geometries to multiple single-part geometries.

## Returns

output_geometries : shapely.geometry.base.BaseGeometry or list
Wrapped Shapely geometry or geometries.

## Notes

If a single input geometry was passed, output_geometry will be a subclass of shapely.geometry.base.BaseGeometry. Otherwise, output_geometry will be a list of the same length as the input, unless explode=True is specified.

Input geometries that were split while wrapping around central_meridian will produce multi-part output geometries, unless explode=True is specified.

Expand source code
def wrap_geometries(
geometries,
central_meridian=0.0,
tessellate_degrees=None,
validate=False,
force_ccw=False,
explode=False,
):
"""Wrap one or more Shapely geometries around a central meridian.

Wrapped geometries will be split at the antimeridian.

Parameters
----------
geometry : shapely.geometry.base.BaseGeometry or list
The geometry or geometries to wrap.
central_meridian : float, default: 0.0
The central meridian around which to wrap geometries;
geometries will be split at the antimeridian.
tessellate_degrees : float, optional
If provided, the geometry will be tessellated to this
resolution prior to wrapping.
validate : bool, default: False
Attempt to ensure output geometry is valid by applying a buffer of 0.
force_ccw : bool, default: False
Ensure the coordinates of the output geometry are counter-clockwise
(only applies to polygons).
explode : bool, default: False
Convert multi-part output geometries to multiple single-part
geometries.

Returns
-------
output_geometries : shapely.geometry.base.BaseGeometry or list
Wrapped Shapely geometry or geometries.

Notes
-----
If a single input geometry was passed, output_geometry will be a
subclass of shapely.geometry.base.BaseGeometry. Otherwise,
output_geometry will be a list of the same length as the input,
unless explode=True is specified.

Input geometries that were split while wrapping around
central_meridian will produce multi-part output geometries, unless
explode=True is specified.
"""
if isinstance(geometries, _BaseGeometry):
return _wrap_geometry(
geometry=geometries,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)
else:
out = []
for i in geometries:
tmp = _wrap_geometry(
geometry=i,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)
if isinstance(tmp, _BaseGeometry):
out.append(tmp)
else:
out.extend(tmp)
return out

## Classes

 class GeometryOnSphere (...) 

Class to mix in to_shapely method to all GPlately geometry classes.

All GPlately geometry classes inherit from this class, in addition to their PyGPlates base class.

Raises an exception This class cannot be instantiated from Python

Expand source code
class GeometryOnSphere(pygplates.GeometryOnSphere):
"""Class to mix in to_shapely method to all GPlately geometry classes.

All GPlately geometry classes inherit from this class, in addition
to their PyGPlates base class.
"""

def to_shapely(
self,
central_meridian=0.0,
tessellate_degrees=None,
validate=False,
force_ccw=False,
explode=False,
):
"""Convert to Shapely geometry.

--------
pygplates_to_shapely : Equivalent function.
"""
return pygplates_to_shapely(
self,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)

@classmethod
def from_shapely(cls, geom):
converted = shapely_to_pygplates(geom)
return cls(converted)

### Ancestors

• pygplates.GeometryOnSphere
• Boost.Python.instance

### Static methods

 def from_shapely(geom) 
Expand source code
@classmethod
def from_shapely(cls, geom):
converted = shapely_to_pygplates(geom)
return cls(converted)

### Methods

 def to_shapely(self, central_meridian=0.0, tessellate_degrees=None, validate=False, force_ccw=False, explode=False) 

Convert to Shapely geometry.

pygplates_to_shapely()
Equivalent function.
Expand source code
def to_shapely(
self,
central_meridian=0.0,
tessellate_degrees=None,
validate=False,
force_ccw=False,
explode=False,
):
"""Convert to Shapely geometry.

--------
pygplates_to_shapely : Equivalent function.
"""
return pygplates_to_shapely(
self,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
validate=validate,
force_ccw=force_ccw,
explode=explode,
)
 class LatLonPoint (...) 

GPlately equivalent of pygplates.LatLonPoint, incorporating to_shapely method

init(latitude, longitude) Create a LatLonPoint instance from a latitude and longitude.

:param latitude: the latitude (in degrees) :type latitude: float :param longitude: the longitude (in degrees) :type longitude: float :raises: InvalidLatLonError if latitude or longitude is invalid

::

point = pygplates.LatLonPoint(latitude, longitude)


!!! note "Note: latitude must satisfy :meth:is_valid_latitude and longitude must satisfy :meth:is_valid_longitude, otherwise InvalidLatLonError will be raised."

Expand source code
class LatLonPoint(pygplates.LatLonPoint):
"""GPlately equivalent of pygplates.LatLonPoint, incorporating
to_shapely method
"""

def to_shapely(self, central_meridian=0.0, tessellate_degrees=None):
return pygplates_to_shapely(
self,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
)

### Ancestors

• pygplates.LatLonPoint
• Boost.Python.instance

### Methods

 def to_shapely(self, central_meridian=0.0, tessellate_degrees=None) 
Expand source code
def to_shapely(self, central_meridian=0.0, tessellate_degrees=None):
return pygplates_to_shapely(
self,
central_meridian=central_meridian,
tessellate_degrees=tessellate_degrees,
)
 class MultiPointOnSphere (...) 

GPlately equivalent of pygplates.MultiPointOnSphere, incorporating to_shapely method

init(…) A MultiPointOnSphere object can be constructed in more than one way…

init(points) Create a multi-point 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 :class:PointOnSphere or :class: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: InsufficientPointsForMultiPointConstructionError if point sequence is empty

!!! note "Note: The sequence must contain at least one point, otherwise InsufficientPointsForMultiPointConstructionError will be raised."

The following example shows a few different ways to create a :class:multi-point<MultiPointOnSphere>: ::

points = []
points.append(pygplates.PointOnSphere(...))
points.append(pygplates.PointOnSphere(...))
points.append(pygplates.PointOnSphere(...))
multi_point = pygplates.MultiPointOnSphere(points)

points = []
points.append((lat1,lon1))
points.append((lat2,lon2))
points.append((lat3,lon3))
multi_point = pygplates.MultiPointOnSphere(points)

points = []
points.append([x1,y1,z1])
points.append([x2,y2,z2])
points.append([x3,y3,z3])
multi_point = pygplates.MultiPointOnSphere(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])
multi_point = pygplates.MultiPointOnSphere(zip(points[::2],points[1::2]))

# Flat lon/lat list (ie, different latitude/longitude order).
points = [lon1, lat1, lon2, lat2, lon3, lat3]
multi_point = pygplates.MultiPointOnSphere(zip(points[1::2],points[::2]))

# Separate lat/lon arrays.
lats = numpy.array([lat1, lat2, lat3])
lons = numpy.array([lon1, lon2, lon3])
multi_point = pygplates.MultiPointOnSphere(zip(lats,lons))

# Lon/lat list of tuples (ie, different latitude/longitude order).
points = [(lon1, lat1), (lon2, lat2), (lon3, lat3)]
multi_point = pygplates.MultiPointOnSphere([(lat,lon) for lon, lat in points])


init(geometry) Create a multipoint from a :class:GeometryOnSphere.

:param geometry: The point, multi-point, polyline or polygon geometry to convert from. :type geometry: :class:GeometryOnSphere

To create a MultiPointOnSphere from any geometry type: ::

multipoint = pygplates.MultiPointOnSphere(geometry)

Expand source code
class MultiPointOnSphere(pygplates.MultiPointOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.MultiPointOnSphere, incorporating
to_shapely method
"""

pass

### Ancestors

• pygplates.MultiPointOnSphere
• GeometryOnSphere
• pygplates.GeometryOnSphere
• Boost.Python.instance

### Inherited members

• GeometryOnSphere:
• to_shapely
 class PointOnSphere (...) 

GPlately equivalent of pygplates.PointOnSphere, incorporating to_shapely method

init(…) A PointOnSphere object can be constructed in more than one way…

init(point) Create a PointOnSphere instance from a (x,y,z) or (latitude,longitude) point.

:param point: (x,y,z) point, or (latitude,longitude) point (in degrees) :type point: :class:PointOnSphere or :class:LatLonPoint or tuple (float,float,float) or tuple (float,float) :raises: InvalidLatLonError if latitude or longitude is invalid :raises: ViolatedUnitVectorInvariantError if (x,y,z) is not unit magnitude

The following example shows a few different ways to use this method: ::

point = pygplates.PointOnSphere((x,y,z))
point = pygplates.PointOnSphere([x,y,z])
point = pygplates.PointOnSphere(numpy.array([x,y,z]))
point = pygplates.PointOnSphere(pygplates.LatLonPoint(latitude,longitude))
point = pygplates.PointOnSphere((latitude,longitude))
point = pygplates.PointOnSphere([latitude,longitude])
point = pygplates.PointOnSphere(numpy.array([latitude,longitude]))
point = pygplates.PointOnSphere(pygplates.PointOnSphere(x,y,z))


init(latitude, longitude) Create a PointOnSphere instance from a latitude and longitude.

:param latitude: the latitude (in degrees) :type latitude: float :param longitude: the longitude (in degrees) :type longitude: float :raises: InvalidLatLonError if latitude or longitude is invalid

!!! note "Note: latitude must satisfy :meth:LatLonPoint.is_valid_latitude and longitude must satisfy :meth:LatLonPoint.is_valid_longitude, otherwise InvalidLatLonError will be raised."

::

point = pygplates.PointOnSphere(latitude, longitude)


init(x, y, z, [normalise=False]) Create a PointOnSphere instance from a 3D cartesian coordinate consisting of floating-point coordinates x, y and z.

:param x: the x component of the 3D unit vector :type x: float :param y: the y component of the 3D unit vector :type y: float :param z: the z component of the 3D unit vector :type z: float :param normalise: whether to normalise (to unit-length magnitude) the vector (x,y,z) - defaults to False :type normalise: bool :raises: ViolatedUnitVectorInvariantError if normalise is False and the resulting vector does not have unit magnitude :raises: UnableToNormaliseZeroVectorError if normalise is True and the resulting vector is (0,0,0) (ie, has zero magnitude)

NOTE: If the length of the 3D vector (x,y,z) is not 1.0 then you should set normalise to True (to normalise the vector components such that the 3D vector has unit magnitude). Otherwise if (x,y,z) is not unit magnitude then ViolatedUnitVectorInvariantError is raised. ::

# If you know that (x,y,z) has unit magnitude (is on the unit globe).
point = pygplates.PointOnSphere(x, y, z)

# If (x,y,z) might not be on the unit globe.
point = pygplates.PointOnSphere(x, y, z, normalise=True)

Expand source code
class PointOnSphere(pygplates.PointOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.PointOnSphere, incorporating
to_shapely method
"""

pass

### Ancestors

• pygplates.PointOnSphere
• GeometryOnSphere
• pygplates.GeometryOnSphere
• Boost.Python.instance

### Inherited members

• GeometryOnSphere:
• to_shapely
 class PolygonOnSphere (...) 

GPlately equivalent of pygplates.PolygonOnSphere, incorporating to_shapely method

init(…) A PolygonOnSphere object can be constructed in more than one way…

init(points) 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 :class:PointOnSphere or :class: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 "Note: The sequence must contain at least three points in order to be a valid polygon, otherwise InvalidPointsForPolygonConstructionError will be raised."

During creation, a :class:GreatCircleArc is created between each adjacent pair of of points in points - see :meth: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 :class:GreatCircleArc between two such adjacent points will have zero length (:meth:GreatCircleArc.is_zero_length will return True) and will have no rotation axis (:meth:GreatCircleArc.get_rotation_axis will raise an error).

The following example shows a few different ways to create a :class:polygon<PolygonOnSphere>: ::

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])


init(geometry, [allow_one_or_two_points=True]) Create a polygon from a :class:GeometryOnSphere.

:param geometry: The point, multi-point, polyline or polygon geometry to convert from. :type geometry: :class:GeometryOnSphere :param allow_one_or_two_points: Whether geometry is allowed to be a :class:PointOnSphere or a :class: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 :class:PointOnSphere, or a :class:MultiPointOnSphere with one or two points (and allow_one_or_two_points is False), or if any two consecutive points in a :class:MultiPointOnSphere are antipodal to each other (on opposite sides of the globe)

If allow_one_or_two_points is True then geometry can be :class:PointOnSphere, :class:MultiPointOnSphere, :class:PolylineOnSphere or :class:PolygonOnSphere. However if allow_one_or_two_points is False then geometry must be a :class:PolygonOnSphere, or a :class:MultiPointOnSphere or :class:PolylineOnSphere containing at least three points to avoid raising InvalidPointsForPolygonConstructionError.

During creation, a :class:GreatCircleArc is created between each adjacent pair of geometry points - see :meth:get_segments.

It is not an error for adjacent points in a geometry sequence to be coincident. In this case each :class:GreatCircleArc between two such adjacent points will have zero length (:meth:GreatCircleArc.is_zero_length will return True) and will have no rotation axis (:meth: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.

Expand source code
class PolygonOnSphere(pygplates.PolygonOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.PolygonOnSphere, incorporating
to_shapely method
"""

pass

### Ancestors

• pygplates.PolygonOnSphere
• GeometryOnSphere
• pygplates.GeometryOnSphere
• Boost.Python.instance

### Inherited members

• GeometryOnSphere:
• to_shapely
 class PolylineOnSphere (...) 

GPlately equivalent of pygplates.PolylineOnSphere, incorporating to_shapely method

init(…) A PolylineOnSphere object can be constructed in more than one way…

init(points) Create a polyline 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 :class:PointOnSphere or :class: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: InvalidPointsForPolylineConstructionError if sequence has less than two points or if any two points (adjacent in the points sequence) are antipodal to each other (on opposite sides of the globe)

!!! note "Note: The sequence must contain at least two points in order to be a valid polyline, otherwise InvalidPointsForPolylineConstructionError will be raised."

During creation, a :class:GreatCircleArc is created between each adjacent pair of points in points - see :meth:get_segments.

It is not an error for adjacent points in the sequence to be coincident. In this case each :class:GreatCircleArc between two such adjacent points will have zero length (:meth:GreatCircleArc.is_zero_length will return True) and will have no rotation axis (:meth:GreatCircleArc.get_rotation_axis will raise an error). However if two such adjacent points are antipodal (on opposite sides of the globe) then InvalidPointsForPolylineConstructionError will be raised.

The following example shows a few different ways to create a :class:polyline<PolylineOnSphere>: ::

points = []
points.append(pygplates.PointOnSphere(...))
points.append(pygplates.PointOnSphere(...))
points.append(pygplates.PointOnSphere(...))
polyline = pygplates.PolylineOnSphere(points)

points = []
points.append((lat1,lon1))
points.append((lat2,lon2))
points.append((lat3,lon3))
polyline = pygplates.PolylineOnSphere(points)

points = []
points.append([x1,y1,z1])
points.append([x2,y2,z2])
points.append([x3,y3,z3])
polyline = pygplates.PolylineOnSphere(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])
polyline = pygplates.PolylineOnSphere(zip(points[::2],points[1::2]))

# Flat lon/lat list (ie, different latitude/longitude order).
points = [lon1, lat1, lon2, lat2, lon3, lat3]
polyline = pygplates.PolylineOnSphere(zip(points[1::2],points[::2]))

# Separate lat/lon arrays.
lats = numpy.array([lat1, lat2, lat3])
lons = numpy.array([lon1, lon2, lon3])
polyline = pygplates.PolylineOnSphere(zip(lats,lons))

# Lon/lat list of tuples (ie, different latitude/longitude order).
points = [(lon1, lat1), (lon2, lat2), (lon3, lat3)]
polyline = pygplates.PolylineOnSphere([(lat,lon) for lon, lat in points])


init(geometry, [allow_one_point=True]) Create a polyline from a :class:GeometryOnSphere.

:param geometry: The point, multi-point, polyline or polygon geometry to convert from. :type geometry: :class:GeometryOnSphere :param allow_one_point: Whether geometry is allowed to be a :class:PointOnSphere or a :class:MultiPointOnSphere containing only a single point - if allowed then that single point is duplicated since a PolylineOnSphere requires at least two points - default is True. :type allow_one_point: bool :raises: InvalidPointsForPolylineConstructionError if geometry is a :class:PointOnSphere (and allow_one_point is False), or a :class:MultiPointOnSphere with one point (and allow_one_point is False), or if any two consecutive points in a :class:MultiPointOnSphere are antipodal to each other (on opposite sides of the globe)

If allow_one_point is True then geometry can be :class:PointOnSphere, :class:MultiPointOnSphere, :class:PolylineOnSphere or :class:PolygonOnSphere. However if allow_one_point is False then geometry must be a :class:PolylineOnSphere, or a :class:PolygonOnSphere, or a :class:MultiPointOnSphere containing at least two points to avoid raising InvalidPointsForPolylineConstructionError.

During creation, a :class:GreatCircleArc is created between each adjacent pair of geometry points - see :meth:get_segments.

It is not an error for adjacent points in a geometry sequence to be coincident. In this case each :class:GreatCircleArc between two such adjacent points will have zero length (:meth:GreatCircleArc.is_zero_length will return True) and will have no rotation axis (:meth:GreatCircleArc.get_rotation_axis will raise an error). However if two such adjacent points are antipodal (on opposite sides of the globe) then InvalidPointsForPolylineConstructionError will be raised

To create a PolylineOnSphere from any geometry type: ::

polyline = pygplates.PolylineOnSphere(geometry)


To create a PolylineOnSphere from any geometry containing at least two points: ::

try:
polyline = pygplates.PolylineOnSphere(geometry, allow_one_point=False)
except pygplates.InvalidPointsForPolylineConstructionError:
... # Handle failure to convert 'geometry' to a PolylineOnSphere.

Expand source code
class PolylineOnSphere(pygplates.PolylineOnSphere, GeometryOnSphere):
"""GPlately equivalent of pygplates.PolylineOnSphere, incorporating
to_shapely method
"""

pass

### Ancestors

• pygplates.PolylineOnSphere
• GeometryOnSphere
• pygplates.GeometryOnSphere
• Boost.Python.instance

### Inherited members

• GeometryOnSphere:
• to_shapely