:py:mod:`geovista.geodesic`
===========================

.. py:module:: geovista.geodesic

.. autoapi-nested-parse::

   Provide geodesic operators for geolocated meshes.

   Notes
   -----
   .. versionadded:: 0.1.0

   ..
       !! processed by numpydoc !!


Module Contents
---------------

Classes
~~~~~~~

.. autoapisummary::

   geovista.geodesic.BBox
   geovista.geodesic.EnclosedPreference



Functions
~~~~~~~~~

.. autoapisummary::

   geovista.geodesic.line
   geovista.geodesic.npoints
   geovista.geodesic.npoints_by_idx
   geovista.geodesic.panel
   geovista.geodesic.wedge



Attributes
~~~~~~~~~~

.. autoapisummary::

   geovista.geodesic.BBOX_C
   geovista.geodesic.BBOX_RADIUS_RATIO
   geovista.geodesic.BBOX_TOLERANCE
   geovista.geodesic.Corners
   geovista.geodesic.ELLIPSE
   geovista.geodesic.GEODESIC_NPTS
   geovista.geodesic.N_PANELS
   geovista.geodesic.PANEL_BBOX_BY_IDX
   geovista.geodesic.PANEL_IDX_BY_NAME
   geovista.geodesic.PANEL_NAME_BY_IDX
   geovista.geodesic.PREFERENCE


.. py:class:: BBox(lons, lats, ellps = ELLIPSE, c = BBOX_C, triangulate = False)

   A 3-D bounding-box constructed from geodesic lines or great circles.


   Create 3-D geodesic bounding-box to extract enclosed mesh, lines or point.

   The bounding-box region is specified in terms of its four corners, in
   degrees of longitude and latitude. As the bounding-box is a geodesic, it
   can only ever at most enclose half of an ellipsoid.

   The geometry of the bounding-box may be specified as either an open or
   closed longitude/latitude geometry i.e., 4 or 5 longitude/latitude values.

   :Parameters:

       **lons** : :obj:`ArrayLike <numpy.typing.ArrayLike>`
           The longitudes (degrees) of the bounding-box, in the half-closed interval
           ``[-180, 180)``. Note that, longitudes will be wrapped to this interval.

       **lats** : :obj:`ArrayLike <numpy.typing.ArrayLike>`
           The latitudes (degrees) of the bounding-box, in the closed interval
           ``[-90, 90]``.

       **ellps** : :class:`python:str`, optional
           The ellipsoid for geodesic calculations. See
           :func:`pyproj.list.get_ellps_map`. Defaults to :data:`ELLIPSE`.

       **c** : :class:`python:float`, optional
           The bounding-box face geometry will contain ``c**2`` cells.
           Defaults to :data:`BBOX_C`.

       **triangulate** : :class:`python:bool`, optional
           Specify whether the bounding-box faces are triangulated. Defaults to
           ``False``.











   .. rubric:: Notes

   .. versionadded:: 0.1.0



   ..
       !! processed by numpydoc !!


   .. py:method:: boundary(surface = None, radius = None)

      
      Footprint of bounding-box intersecting on the provided mesh surface.

      The region of the bounding-box that intersects on the surface of the mesh
      that will be enclosed.

      :Parameters:

          **surface** : :obj:`PolyData <pyvista.PolyData>`, optional
              The :class:`pyvista.PolyData` mesh that will be enclosed by the
              bounding-box boundary.

          **radius** : :class:`python:float`, optional
              The radius of the spherical mesh that will be enclosed by the
              bounding-box
              boundary. Note that, the `radius` is only used when the `surface`
              is not provided. Defaults to :data:`geovista.common.RADIUS`.



      :Returns:

          :obj:`PolyData <pyvista.PolyData>`
              The boundary of the bounding-box.








      .. rubric:: Notes

      .. versionadded:: 0.1.0


      .. rubric:: Examples

      .. pyvista-plot::

         Add the boundary of a ``C32`` bounding-box to the plotter for a region
         around the Gulf of Guinea. The geodesic bounding-box is generated by
         defining 4 longitude-latitude corners.

         The boundary is generated from where the bounding-box intersects with the
         surface of the C48 Sea Surface Temperature (SST) cubed-sphere mesh.

         >>> import geovista
         >>> from geovista.geodesic import BBox
         >>> from geovista.pantry.meshes import lfric_sst
         >>> plotter = geovista.GeoPlotter()
         >>> mesh = lfric_sst()
         >>> _ = plotter.add_mesh(mesh, cmap="balance")
         >>> bbox = BBox(lons=[-15, 20, 25, -15], lats=[-25, -20, 15, 10], c=32)
         >>> _ = plotter.add_mesh(bbox.boundary(mesh), color="orange", line_width=3)
         >>> plotter.view_yz()
         >>> plotter.show()

         ..
             !! processed by numpydoc !!


   .. py:method:: enclosed(surface, tolerance = BBOX_TOLERANCE, outside = False, preference = None)

      
      Extract region of the `surface` contained within the bounding-box.

      Note that, points that are on the surface of the bounding-box manifold are not
      considered within the bounding-box. See the `preference` and `tolerance`
      options.

      :Parameters:

          **surface** : :obj:`PolyData <pyvista.PolyData>`
              The :class:`pyvista.PolyData` mesh to be checked for containment.

          **tolerance** : :class:`python:float`, optional
              The tolerance on the intersection operation with the `surface`,
              expressed as a fraction of the diagonal of the bounding-box.
              See PyVista's
              :meth:`~pyvista.DataSetFilters.select_enclosed_points` for more.
              Defaults to :data:`BBOX_TOLERANCE`.

          **outside** : :class:`python:bool`, optional
              By default, select those points of the `surface` that are inside
              the bounding-box. Otherwise, select those points that are outside
              the bounding-box. Defaults to ``False``.

          **preference** : :class:`python:str` or :obj:`EnclosedPreference`, optional
              Criteria for defining whether a face of a `surface` mesh is
              deemed to be enclosed by the bounding-box. A `preference` of
              ``cell`` requires all points defining the face to be within the
              bounding-box. A `preference` of ``center`` requires that only the
              face cell center is within the bounding-box. A `preference` of
              ``point`` requires at least one point that defines the face to be
              within the bounding-box. Defaults to :data:`PREFERENCE`.



      :Returns:

          :obj:`PolyData <pyvista.PolyData>`
              The :class:`pyvista.PolyData` representing those parts of
              the provided `surface` enclosed by the bounding-box. This behaviour
              may be inverted with the `outside` parameter.








      .. rubric:: Notes

      .. versionadded:: 0.1.0


      .. rubric:: Examples

      .. pyvista-plot::

         Add the boundary of a ``C32`` bounding-box to the plotter for a region
         around the Gulf of Guinea. The geodesic bounding-box is generated by
         defining 4 longitude-latitude corners.

         Add the region enclosed by a ``C32`` bounding-box manifold to the
         plotter for a region around the ``0`` meridian. The geodesic
         bounding-box is generated by defining 4 longitude-latitude corners.

         The region is generated from all cells of the C48 Sea Surface Temperature
         (SST) cubed-sphere mesh that have their cell ``center`` enclosed by the
         bounding-box manifold.

         >>> import geovista
         >>> from geovista.geodesic import BBox
         >>> from geovista.pantry.meshes import lfric_sst
         >>> plotter = geovista.GeoPlotter()
         >>> _ = plotter.add_base_layer(texture=geovista.natural_earth_hypsometric())
         >>> mesh = lfric_sst()
         >>> bbox = BBox(lons=[-15, 20, 25, -15], lats=[-25, -20, 15, 10], c=32)
         >>> region = bbox.enclosed(mesh)
         >>> _ = plotter.add_mesh(region, cmap="balance")
         >>> plotter.view_yz()
         >>> plotter.show()

         The same ``region`` is rendered again, but with the land mask cells removed
         using the :meth:`pyvista.DataSetFilters.threshold` filter.

         >>> plotter = geovista.GeoPlotter()
         >>> _ = plotter.add_base_layer(texture=geovista.natural_earth_hypsometric())
         >>> _ = plotter.add_mesh(region.threshold(), cmap="balance")
         >>> plotter.view_yz()
         >>> plotter.show()

         ..
             !! processed by numpydoc !!


   .. py:attribute:: c


   .. py:attribute:: ellps


   .. py:attribute:: lats


   .. py:attribute:: lons


   .. py:property:: mesh
      :type: pyvista.PolyData

      
      The manifold bounding-box mesh.





      :Returns:

          :obj:`PolyData <pyvista.PolyData>`
              The bounding-box mesh.








      .. rubric:: Notes

      .. versionadded:: 0.1.0


      .. rubric:: Examples

      .. pyvista-plot::

         Add a ``C32`` bounding-box around the Gulf of Guinea.
         The geodesic bounding-box is generated by defining 4 longitude-latitude
         corners. Natural Earth coastlines are also rendered along
         with a texture mapped Natural Earth base layer.

         >>> import geovista
         >>> from geovista.geodesic import BBox
         >>> plotter = geovista.GeoPlotter()
         >>> _ = plotter.add_base_layer(
         ...     texture=geovista.natural_earth_hypsometric(), style="wireframe"
         ... )
         >>> bbox = BBox(lons=[-15, 20, 25, -15], lats=[-25, -20, 15, 10], c=32)
         >>> _ = plotter.add_mesh(bbox.mesh, color="white")
         >>> plotter.camera.zoom(1.5)
         >>> plotter.show()

         ..
             !! processed by numpydoc !!


   .. py:attribute:: triangulate


.. py:class:: EnclosedPreference(*args, **kwds)

   Bases: :py:obj:`geovista.common.MixinStrEnum`, :py:obj:`enum.Enum`


   
   Enumeration of mesh geometry enclosed preferences.













   .. rubric:: Notes

   .. versionadded:: 0.3.0



   ..
       !! processed by numpydoc !!

   .. py:attribute:: CELL
      :value: 'cell'



   .. py:attribute:: CENTER
      :value: 'center'



   .. py:attribute:: POINT
      :value: 'point'



.. py:function:: line(lons, lats, surface = None, radius = None, npts = None, ellps = None, close = False, zlevel = None, zscale = None)

   
   Geodesic line consisting of one or more connected geodesic line segments.

   Note that, as a convenience, if a single value is provided for `lons` and ``N``
   values are provided for `lats`, then the longitude value will be automatically
   repeated ``N`` times, and vice versa, providing ``N >= 2``.

   :Parameters:

       **lons** : :obj:`ArrayLike <numpy.typing.ArrayLike>`
           The longitudes (degrees) of the geodesic line segments, in the half-closed
           interval ``[-180, 180)``. Note that, longitudes will be wrapped to this
           interval.

       **lats** : :obj:`ArrayLike <numpy.typing.ArrayLike>`
           The latitudes (degrees) of the geodesic line segments, in the closed
           interval ``[-90, 90]``.

       **surface** : :obj:`PolyData <pyvista.PolyData>`, optional
           The surface that the geodesic line will be rendered over.

       **radius** : :class:`python:float`, optional
           The radius of the spherical surface that the geodesic line will be
           rendered over.
           Note that, the `radius` is only used when the `surface` is not
           provided. Defaults to :data:`geovista.common.RADIUS`.

       **npts** : :class:`python:float`, optional
           The number of equally spaced geodesic points in a line segment, excluding
           the segment end-point, but including the segment start-point i.e., `npts`
           must be at least 2. Defaults to :data:`GEODESIC_NPTS`.

       **ellps** : :class:`python:str`, optional
           The ellipsoid for geodesic calculations. See :func:`pyproj.list.get_ellps_map`.
           Defaults to :data:`ELLIPSE`.

       **close** : :class:`python:bool`, optional
           Whether to close the geodesic line segments into a loop i.e., the last
           point is connected to the first point. Defaults to ``False``.

       **zlevel** : :class:`python:int`, optional
           The z-axis level. Used in combination with the `zscale` to offset the
           `radius` by a proportional amount i.e., ``radius * zlevel * zscale``.
           Defaults to ``1``.

       **zscale** : :class:`python:float`, optional
           The proportional multiplier for z-axis `zlevel`. Defaults to
           :data:`geovista.common.ZLEVEL_SCALE`.



   :Returns:

       :obj:`PolyData <pyvista.PolyData>`
           The geodesic line.








   .. rubric:: Notes

   .. versionadded:: 0.1.0


   .. rubric:: Examples

   .. pyvista-plot::

      Add the anti-meridian great circle to the plotter. A texture mapped Natural Earth
      base layer is also rendered.

      >>> import geovista
      >>> from geovista.geodesic import line
      >>> plotter = geovista.GeoPlotter()
      >>> _ = plotter.add_base_layer(texture=geovista.natural_earth_1())
      >>> meridian = line(-180, [90, 0, -90])
      >>> _ = plotter.add_mesh(meridian, color="orange", line_width=3)
      >>> plotter.view_yz(negative=True)
      >>> plotter.show()

      ..
          !! processed by numpydoc !!

.. py:function:: npoints(start_lon, start_lat, end_lon, end_lat, npts = GEODESIC_NPTS, radians = False, include_start = False, include_end = False, geod = None)

   
   Calculate geodesic mid-points between provided start and end points.

   Given a single start-point and end-point, calculate the equally spaced
   intermediate longitude and latitude `npts` points along the geodesic line
   that spans between the start and end points.

   Note that, longitudes (degrees) will be wrapped to the half-closed interval
   ``[-180, 180)``.

   :Parameters:

       **start_lon** : :class:`python:float`
           The longitude of the start-point for the geodesic line.

       **start_lat** : :class:`python:float`
           The latitude of the start-point for the geodesic line.

       **end_lon** : :class:`python:float`
           The longitude of the end-point for the geodesic line.

       **end_lat** : :class:`python:float`
           The latitude of the end-point for the geodesic line.

       **npts** : :class:`python:int`, optional
           The number of points to be returned, which may include the start-point
           and/or the end-point, if required. Defaults to :data:`GEODESIC_NPTS`.

       **radians** : :class:`python:bool`, optional
           If ``True``, the start and end points are assumed to be in radians,
           otherwise degrees. Defaults to ``False``.

       **include_start** : :class:`python:bool`, optional
           Whether to include the start-point in the geodesic points returned. Defaults to
           ``False``.

       **include_end** : :class:`python:bool`, optional
           Whether to include the end-point in the geodesic points returned. Defaults to
           ``False``.

       **geod** : :obj:`Geod <pyproj.geod.Geod>`, optional
           Definition of the ellipsoid for geodesic calculations. Defaults to
           :data:`ELLIPSE`.



   :Returns:

       :class:`python:tuple`
           Tuple of longitude points and latitude points along the geodesic line
           between the start-point and the end-point.








   .. rubric:: Notes

   .. versionadded:: 0.1.0


   .. rubric:: Examples

   .. pyvista-plot::

      >>> from geovista.geodesic import npoints
      >>> import numpy as np
      >>> points = npoints(start_lon=-10, start_lat=20, end_lon=10, end_lat=30, npts=5)
      >>> np.array(points, dtype=np.float16)
      array([[-6.887, -3.69 , -0.41 ,  2.963,  6.43 ],
             [21.84 , 23.62 , 25.34 , 26.98 , 28.53 ]], dtype=float16)

      ..
          !! processed by numpydoc !!

.. py:function:: npoints_by_idx(lons, lats, start_idx, end_idx, npts = GEODESIC_NPTS, radians = False, include_start = False, include_end = False, geod = None)

   
   Calculate geodesic mid-points between provided start and end indices.

   Given a single start-point index and end-point index, calculate the equally
   spaced intermediate longitude and latitude `npts` points along the geodesic
   line that spans between the start and end points.

   Note that, longitudes (degrees) will be wrapped to the half-closed interval
   ``[-180, 180)``.

   :Parameters:

       **lons** : :obj:`ArrayLike <numpy.typing.ArrayLike>`
           The longitudes to be sampled by the provided indices.

       **lats** : :obj:`ArrayLike <numpy.typing.ArrayLike>`
           The latitudes to be sampled by the provided indices.

       **start_idx** : :class:`python:int`
           The index of the start-point.

       **end_idx** : :class:`python:int`
           The index of the end-point.

       **npts** : :class:`python:int`, optional
           The number of points to be returned, which may include the start-point
           and/or the end-point, if required. Defaults to :data:`GEODESIC_NPTS`.

       **radians** : :class:`python:bool`, optional
           If ``True``, the `lons` and `lats` are assumed to be in radians,
           otherwise degrees. Defaults to ``False``.

       **include_start** : :class:`python:bool`, optional
           Whether to include the start-point in the geodesic points returned. Defaults
           to ``False``.

       **include_end** : :class:`python:bool`, optional
           Whether to include the end-point in the geodesic points returned. Defaults to
           ``False``.

       **geod** : :obj:`Geod <pyproj.geod.Geod>`, optional
           Definition of the ellipsoid for geodesic calculations. Defaults to
           :data:`ELLIPSE`.



   :Returns:

       :class:`python:tuple`
           Tuple of longitude points and latitude points along the geodesic line
           between the start-point and the end-point.








   .. rubric:: Notes

   .. versionadded:: 0.1.0


   .. rubric:: Examples

   .. pyvista-plot::

      >>> from geovista.geodesic import npoints_by_idx
      >>> import numpy as np
      >>> points = npoints_by_idx(
      ...     lons=[-10, 0, 10], lats=[20, 25, 30], start_idx=0, end_idx=1, npts=5
      ... )
      >>> np.array(points, dtype=np.float16)
      array([[-8.38 , -6.746, -5.09 , -3.414, -1.718],
             [20.88 , 21.73 , 22.58 , 23.4  , 24.22 ]], dtype=float16)

      ..
          !! processed by numpydoc !!

.. py:function:: panel(name, ellps = ELLIPSE, c = BBOX_C, triangulate = False)

   
   Create boundary-box for specific cubed-sphere panel.


   :Parameters:

       **name** : :class:`python:int` or :class:`python:str`
           The cubed-sphere index, see :data:`PANEL_NAME_BY_IDX`, or name, see
           :data:`PANEL_IDX_BY_NAME`, which specifies the panel bounding-box,
           see :data:`PANEL_BBOX_BY_IDX`.

       **ellps** : :class:`python:str`, optional
           The ellipsoid for geodesic calculations. See :func:`pyproj.list.get_ellps_map`.
           Defaults to :data:`ELLIPSE`.

       **c** : :class:`python:float`, optional
           The bounding-box face geometry will contain ``c**2`` cells. Defaults to
           :data:`BBOX_C`.

       **triangulate** : :class:`python:bool`, optional
           Specify whether the panel bounding-box faces are triangulated. Defaults to
           ``False``.



   :Returns:

       :obj:`BBox`
           The bounding-box that encloses the required cubed-sphere panel.








   .. rubric:: Notes

   .. versionadded:: 0.1.0


   .. rubric:: Examples

   .. pyvista-plot::

      Add a ``wireframe`` bounding-box to the plotter for the ``americas`` panel of a
      cubed-sphere. The geodesic bounding-box is generated from the 4 corners of the
      cubed-sphere panel located over Americas.  A texture mapped Natural Earth base
      layer is also rendered.

      >>> import geovista
      >>> from geovista.geodesic import panel
      >>> plotter = geovista.GeoPlotter()
      >>> _ = plotter.add_base_layer(
      ...     texture=geovista.natural_earth_hypsometric(), opacity=0.5
      ... )
      >>> bbox = panel("americas", c=8)
      >>> _ = plotter.add_mesh(bbox.mesh, color="orange", style="wireframe")
      >>> plotter.view_xz()
      >>> plotter.show()

      ..
          !! processed by numpydoc !!

.. py:function:: wedge(lon1, lon2, ellps = ELLIPSE, c = BBOX_C, triangulate = False)

   
   Create geodesic bounding-box manifold wedge from the north to the south pole.


   :Parameters:

       **lon1** : :class:`python:float`
           The first longitude (degrees) defining the geodesic wedge region.

       **lon2** : :class:`python:float`
           The second longitude (degrees) defining the geodesic wedge region.

       **ellps** : :class:`python:str`, optional
           The ellipsoid for geodesic calculations. See :func:`pyproj.list.get_ellps_map`.
           Defaults to :data:`ELLIPSE`.

       **c** : :class:`python:float`, optional
           The bounding-box face geometry will contain ``c**2`` cells. Defaults to
           :data:`BBOX_C`.

       **triangulate** : :class:`python:bool`, optional
           Specify whether the wedge bounding-box faces are triangulated. Defaults to
           ``False``.



   :Returns:

       :obj:`BBox`
           The bounding-box that encloses the required geodesic wedge.








   .. rubric:: Notes

   .. versionadded:: 0.1.0


   .. rubric:: Examples

   .. pyvista-plot::

      Add a ``C8`` sixty-degree wide ``wireframe`` bounding-box wedge to the plotter. A
      texture mapped NASA Blue Marble base layer is also rendered.

      >>> import geovista
      >>> from geovista.geodesic import wedge
      >>> plotter = geovista.GeoPlotter()
      >>> _ = plotter.add_base_layer(texture=geovista.blue_marble(), opacity=0.5)
      >>> bbox = wedge(-30, 30, c=8)
      >>> _ = plotter.add_mesh(bbox.mesh, color="orange", style="wireframe")
      >>> plotter.view_yz()
      >>> plotter.show()

      ..
          !! processed by numpydoc !!

.. py:data:: BBOX_C
   :type:  int
   :value: 256


   
   The bounding-box face geometry will contain ``BBOX_C**2`` cells.
















   ..
       !! processed by numpydoc !!

.. py:data:: BBOX_RADIUS_RATIO
   :value: 0.1


   
   Ratio the bounding-box inner and outer faces are offset from the surface mesh.
















   ..
       !! processed by numpydoc !!

.. py:data:: BBOX_TOLERANCE
   :value: 1e-06


   
   The bounding-box tolerance on intersection.
















   ..
       !! processed by numpydoc !!

.. py:data:: Corners
   :type:  TypeAlias
   :value: tuple[float, float, float, float]


   
   Type alias for the corners of a bounding-box.
















   ..
       !! processed by numpydoc !!

.. py:data:: ELLIPSE
   :type:  str
   :value: 'WGS84'


   
   Default geodesic ellipse. See :func:`pyproj.list.get_ellps_map`.
















   ..
       !! processed by numpydoc !!

.. py:data:: GEODESIC_NPTS
   :type:  int
   :value: 64


   
   Number of equally spaced geodesic points between/including end-point/s.
















   ..
       !! processed by numpydoc !!

.. py:data:: N_PANELS
   :type:  int

   
   The number of cubed-sphere panels.
















   ..
       !! processed by numpydoc !!

.. py:data:: PANEL_BBOX_BY_IDX
   :type:  dict[int, tuple[Corners, Corners]]

   
   Cubed-sphere panel bounding-box longitudes and latitudes.
















   ..
       !! processed by numpydoc !!

.. py:data:: PANEL_IDX_BY_NAME
   :type:  dict[str, int]

   
   Lookup table for cubed-sphere panel index by panel name.
















   ..
       !! processed by numpydoc !!

.. py:data:: PANEL_NAME_BY_IDX
   :type:  dict[int, str]

   
   Lookup table for cubed-sphere panel name by panel index.
















   ..
       !! processed by numpydoc !!

.. py:data:: PREFERENCE
   :type:  str
   :value: 'center'


   
   The default bounding-box preference.
















   ..
       !! processed by numpydoc !!

