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:
-
pygplates.GeometryOnSphere: This class has the following derived GeometryOnSphere classes:
- pygplates.ReconstructedFeatureGeometry
- pygplates.ResolvedTopologicalLine
- pygplates.ResolvedTopologicalBoundary
- 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
orLatLonPoint
:Point
MultiPointOnSphere
:MultiPoint
PolylineOnSphere
:LineString
orMultiLineString
PolygonOnSphere
:Polygon
orMultiPolygon
Converting Shapely geometries into PyGPlates geometries: Input Shapely geometries are converted to the following PyGPlates geometries:
Point
:PointOnSphere
MultiPoint
:MultiPointOnSphere
LineString
:PolylineOnSphere
LinearRing
orPolygon
: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.
See Also
--------
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[0]))
)
# 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[0]
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[0]
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
orpygplates.LatLonPoint
orlist
- 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
orlist
- Converted Shapely geometry or geometries.
Notes
If a single input geometry was passed,
output_geometry
will be a subclass ofshapely.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, unlessexplode=True
is specified.Input geometry types are converted as follows: -
PointOnSphere
orLatLonPoint
:Point
-MultiPointOnSphere
:MultiPoint
-PolylineOnSphere
:LineString
orMultiLineString
-PolygonOnSphere
:Polygon
orMultiPolygon
Expand source code
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[0])) ) # 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[0] if explode: return output_geoms return output_type(output_geoms)
def shapely_to_pygplates(geometry)
-
Convert one or more Shapely geometries to gplately format.
Parameters
geometry
:shapely.geometry.base.BaseGeometry
orlist
- The geometry or geometries to convert.
Returns
output_geometry
:GeometryOnSphere
orlist
- Converted gplately geometry or geometries.
Notes
If a single input geometry was passed,
output_geometry
will be a subclass ofGeometryOnSphere
. Otherwise,output_geometry
will be a list ofGeometryOnSphere
, of the same length as the input.Input geometry types are converted as follows: -
Point
:PointOnSphere
-MultiPoint
:MultiPointOnSphere
-LineString
:PolylineOnSphere
-LinearRing
orPolygon
: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
orlist
- 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
orlist
- Wrapped Shapely geometry or geometries.
Notes
If a single input geometry was passed,
output_geometry
will be a subclass ofshapely.geometry.base.BaseGeometry
. Otherwise,output_geometry
will be a list of the same length as the input, unlessexplode=True
is specified.Input geometries that were split while wrapping around
central_meridian
will produce multi-part output geometries, unlessexplode=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. See Also -------- 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.pygplates.GeometryOnSphere
- Boost.Python.instance
Subclasses
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)
-
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. See Also -------- 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
, incorporatingto_shapely
methodinit(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.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
, incorporatingto_shapely
methodinit(…) 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)
!!! note "Note: If geometry is a polygon then points from both its exterior and interior rings are added to the multipoint."
Expand source code
class MultiPointOnSphere(pygplates.MultiPointOnSphere, GeometryOnSphere): """GPlately equivalent of `pygplates.MultiPointOnSphere`, incorporating `to_shapely` method """ pass
Ancestors
- pygplates.pygplates.MultiPointOnSphere
- GeometryOnSphere
- pygplates.pygplates.GeometryOnSphere
- Boost.Python.instance
Inherited members
class PointOnSphere (...)
-
GPlately equivalent of
pygplates.PointOnSphere
, incorporatingto_shapely
methodinit(…) 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 magnitudeThe 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 isFalse
and the resulting vector does not have unit magnitude :raises: UnableToNormaliseZeroVectorError if normalise isTrue
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.pygplates.PointOnSphere
- GeometryOnSphere
- pygplates.pygplates.GeometryOnSphere
- Boost.Python.instance
Inherited members
class PolygonOnSphere (...)
-
GPlately equivalent of
pygplates.PolygonOnSphere
, incorporatingto_shapely
methodinit(…) A PolygonOnSphere object can be constructed in more than one way…
init(exterior_ring, [interior_rings]) Create a polygon from an exterior ring and optional interior rings, where each ring is a sequence of (x,y,z) or (latitude,longitude) points.
:param exterior_ring: Exterior ring sequence of (x,y,z) points, or (latitude,longitude) points (in degrees). :type exterior_ring: Any sequence of :class:
PointOnSphere
or :class:LatLonPoint
or tuple (float,float,float) or tuple (float,float). :param interior_rings: Optional sequence of interior rings where each ring is a sequence of (x,y,z) points, or (latitude,longitude) points (in degrees). :type interior_rings: Any sequence of rings (where ring is any sequence of :class:PointOnSphere
or :class:LatLonPoint
or tuple (float,float,float) or tuple (float,float)), or None. :raises: InvalidLatLonError if any latitude or longitude is invalid :raises: ViolatedUnitVectorInvariantError if any (x,y,z) is not unit magnitude :raises: InvalidPointsForPolygonConstructionError if any ring has less than three points or if any two points (adjacent in a ring) are antipodal to each other (on opposite sides of the globe)!!! note "Note: Each ring must contain at least three points in order for the polygon to be valid, otherwise InvalidPointsForPolygonConstructionError will be raised."
During creation, a :class:
GreatCircleArc
is created between each adjacent pair of of points in a ring - see :meth:get_segments
. The last arc in each ring is created between the last and first points in that ring to close the loop of the ring. For this reason you do not need to ensure that the first and last points in a ring have the same position (although it's not an error if this is the case because the final arc in the ring will then just have a zero length).It is not an error for adjacent points in a ring to be coincident. In this case each :class:
GreatCircleArc
between two such adjacent points will have zero length (:meth:GreatCircleArc.is_zero_length
will returnTrue
) 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>
: ::# Polygon with only an exterior ring. points = [] points.append(pygplates.PointOnSphere(...)) points.append(pygplates.PointOnSphere(...)) points.append(pygplates.PointOnSphere(...)) polygon = pygplates.PolygonOnSphere(points) # Polygon with only an exterior ring. points = [] points.append((lat1,lon1)) points.append((lat2,lon2)) points.append((lat3,lon3)) polygon = pygplates.PolygonOnSphere(points) # Polygon with only an exterior ring. points = [] points.append([x1,y1,z1]) points.append([x2,y2,z2]) points.append([x3,y3,z3]) polygon = pygplates.PolygonOnSphere(points) # Polygon with an exterior ring and interior rings. exterior_ring = [] exterior_ring.append(pygplates.PointOnSphere(...)) ... interior_rings = [] first_interior_ring = [] first_interior_ring.append(pygplates.PointOnSphere(...)) ... interior_rings.append(first_interior_ring) second_interior_ring = [] second_interior_ring.append(pygplates.PointOnSphere(...)) ... interior_rings.append(second_interior_ring) polygon = pygplates.PolygonOnSphere(exterior_ring, interior_rings)
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])
!!! versionchanged "Changed in version: 0.36" Can now optionally specify interior rings (in addition to the exterior ring).
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 isTrue
. :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 isFalse
), 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 isFalse
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 returnTrue
) 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 raisedTo 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.
!!! note "Note: The created polygon will have no interior rings unless geometry is also a :class:
PolygonOnSphere
and has interior rings."Expand source code
class PolygonOnSphere(pygplates.PolygonOnSphere, GeometryOnSphere): """GPlately equivalent of `pygplates.PolygonOnSphere`, incorporating `to_shapely` method """ pass
Ancestors
- pygplates.pygplates.PolygonOnSphere
- GeometryOnSphere
- pygplates.pygplates.GeometryOnSphere
- Boost.Python.instance
Inherited members
class PolylineOnSphere (...)
-
GPlately equivalent of
pygplates.PolylineOnSphere
, incorporatingto_shapely
methodinit(…) 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 returnTrue
) 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 isTrue
. :type allow_one_point: bool :raises: InvalidPointsForPolylineConstructionError if geometry is a :class:PointOnSphere
(and allow_one_point isFalse
), or a :class:MultiPointOnSphere
with one point (and allow_one_point isFalse
), 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 isFalse
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 returnTrue
) 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 raisedTo 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.
!!! note "Note: If geometry is a polygon then only its exterior ring is converted (interior rings are ignored)."
Expand source code
class PolylineOnSphere(pygplates.PolylineOnSphere, GeometryOnSphere): """GPlately equivalent of `pygplates.PolylineOnSphere`, incorporating `to_shapely` method """ pass
Ancestors
- pygplates.pygplates.PolylineOnSphere
- GeometryOnSphere
- pygplates.pygplates.GeometryOnSphere
- Boost.Python.instance
Inherited members