
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "_auto_examples/plot_mesh.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download__auto_examples_plot_mesh.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr__auto_examples_plot_mesh.py:


Spline to mesh
==============
This guide demonstrates how to convert a 3D spline curve into various types of meshes using SplineBox.

.. GENERATED FROM PYTHON SOURCE LINES 6-13

.. code-block:: Python



    import numpy as np
    import pyvista
    import splinebox









.. GENERATED FROM PYTHON SOURCE LINES 15-18

1. Constructing a Spline
------------------------
We begin by creating a circular spline.

.. GENERATED FROM PYTHON SOURCE LINES 18-22

.. code-block:: Python

    M = 4
    spline = splinebox.Spline(M=M, basis_function=splinebox.Exponential(M), closed=True)
    spline.knots = np.array([[0, 0, 1], [0, 1, 0], [0, 0, -1], [0, -1, 0]])








.. GENERATED FROM PYTHON SOURCE LINES 23-27

2. Generating a Mesh Without Radius
-----------------------------------
The :code:`step_t` parameter determines the granularity of the resulting mesh, corresponding to the step size in the spline parameter space (t).
Setting the radius to None or 0 results in a line mesh.

.. GENERATED FROM PYTHON SOURCE LINES 27-38

.. code-block:: Python


    # Generate a simple line mesh
    points, connectivity = spline.mesh(step_t=0.1, radius=None)

    # Prepend the number of points in each element (2 for a line) for PyVista
    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 2), connectivity))

    # Create and plot the PyVista mesh
    mesh = pyvista.PolyData(points, lines=connectivity)
    mesh.plot()








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_001.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_001.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_001.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 39-43

3. Mesh with a Fixed Radius
---------------------------
Here, we generate a surface mesh (a "tube") using a fixed radius.
We employ the Frenet-Serret frame to avoid selecting an initial vector.

.. GENERATED FROM PYTHON SOURCE LINES 43-54

.. code-block:: Python


    # Generate a surface mesh with a fixed radius
    points, connectivity = spline.mesh(step_t=0.1, radius=0.2, frame="frenet")

    # Prepend the number of points in each element (3 for triangles) for PyVista
    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 3), connectivity))

    # Create and plot the PyVista mesh
    mesh = pyvista.PolyData(points, faces=connectivity)
    mesh.plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_002.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_002.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_002.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 55-60

4. Mesh with an Elliptical Cross-Section
----------------------------------------
You can define a custom cross-section shape by specifying the radius as a function of the spline parameter (:code:`t`) and the polar angle (:code:`phi`).
Example 1: Elliptical Cross-Section
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. GENERATED FROM PYTHON SOURCE LINES 60-77

.. code-block:: Python



    def elliptical_radius(t, phi):
        a = 0.1
        b = 0.05
        phi = np.deg2rad(phi)
        r = (a * b) / np.sqrt((b * np.cos(phi)) ** 2 + (a * np.sin(phi)) ** 2)
        return r


    points, connectivity = spline.mesh(step_t=0.1, step_angle=36, radius=elliptical_radius, frame="frenet")

    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 3), connectivity))

    mesh = pyvista.PolyData(points, faces=connectivity)
    mesh.plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_003.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_003.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_003.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 78-80

Example 2: Varying Radius Along the Spline
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. GENERATED FROM PYTHON SOURCE LINES 80-93

.. code-block:: Python



    def radius(t, phi):
        return 0.1 + 0.03 * np.sin(t / spline.M * 16 * np.pi)


    points, connectivity = spline.mesh(step_t=0.1, step_angle=36, radius=radius, frame="frenet")

    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 3), connectivity))

    mesh = pyvista.PolyData(points, faces=connectivity)
    mesh.plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_004.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_004.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_004.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 94-102

5. Bishop Frame for Mesh Generation
-----------------------------------
The Frenet-Serret frame is not defined on straight segments and at inflections point.
In those cases, we can use the Bishop frame instead. Another advantage of the Bishop frame
is that it does not twist around the spline.

Correcting Twists with the Bishop Frame
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. GENERATED FROM PYTHON SOURCE LINES 102-123

.. code-block:: Python


    # Create a spline with for which the Frenet frame twists
    spline = splinebox.Spline(M=M, basis_function=splinebox.B3(), closed=False)
    spline.control_points = np.array(
        [
            [0.0, 0.0, 0.0],
            [2.0, 0.0, 0.0],
            [2.0, 2.0, 0.0],
            [2.0, 2.0, 2.0],
            [0.0, 2.0, 2.0],
            [0.0, 0.0, 0.0],
        ]
    )

    points, connectivity = spline.mesh(step_t=0.1, step_angle=36, radius=elliptical_radius, frame="frenet")

    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 3), connectivity))

    mesh = pyvista.PolyData(points, faces=connectivity)
    mesh.plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_005.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_005.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_005.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 124-126

You can clearly see how the ellipse twists around the spline.
The Bishop frame eliminates this twist.

.. GENERATED FROM PYTHON SOURCE LINES 126-134

.. code-block:: Python


    points, connectivity = spline.mesh(step_t=0.1, step_angle=36, radius=elliptical_radius, frame="bishop")

    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 3), connectivity))

    mesh = pyvista.PolyData(points, faces=connectivity)
    mesh.plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_006.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_006.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_006.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 135-136

Changing the initial vector rotates the frame and therefore the ellipse.

.. GENERATED FROM PYTHON SOURCE LINES 136-148

.. code-block:: Python


    initial_vector = np.array([0.5, -0.5, 1])

    points, connectivity = spline.mesh(
        step_t=0.1, step_angle=36, radius=elliptical_radius, frame="bishop", initial_vector=initial_vector
    )

    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 3), connectivity))

    mesh = pyvista.PolyData(points, faces=connectivity)
    mesh.plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_007.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_007.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_007.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 149-152

6. Volume Mesh
--------------
Finally, you can generate a volumetric mesh by setting the :code:`mesh_type` to :code:`"volume"`.

.. GENERATED FROM PYTHON SOURCE LINES 152-163

.. code-block:: Python


    points, connectivity = spline.mesh(
        radius=radius, step_t=0.5, step_angle=72, initial_vector=initial_vector, mesh_type="volume"
    )

    connectivity = np.hstack((np.full((connectivity.shape[0], 1), 4), connectivity))
    cell_types = np.full(len(connectivity), fill_value=pyvista.CellType.TETRA, dtype=np.uint8)

    mesh = pyvista.UnstructuredGrid(connectivity, cell_types, points)
    mesh.plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_008.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_008.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_008.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 164-166

For a better understanding of the volume mesh we can explode it.
This allows us to see the individual tetrahedra.

.. GENERATED FROM PYTHON SOURCE LINES 166-168

.. code-block:: Python

    mesh.explode(factor=0.5).plot(show_edges=True)








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_009.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_009.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_009.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 169-172

7. Mesh with Capped Ends
------------------------
To create a closed surface mesh for an open spline, the ends can be capped.

.. GENERATED FROM PYTHON SOURCE LINES 172-176

.. code-block:: Python

    M = 4
    spline = splinebox.Spline(M=M, basis_function=splinebox.B3(), closed=False)
    spline.knots = np.array([[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 0, 3]])








.. GENERATED FROM PYTHON SOURCE LINES 177-180

SplineBox offers two different options to cap the end:
1. With an orthogonal flat plane
2. With a hemisphere

.. GENERATED FROM PYTHON SOURCE LINES 180-202

.. code-block:: Python

    points_open, connectivity_open = spline.mesh(radius=1, cap_ends=None)
    points_flat, connectivity_flat = spline.mesh(radius=1, cap_ends="flat")
    points_sphe, connectivity_sphe = spline.mesh(radius=1, cap_ends="sphere")

    connectivity_open = np.hstack((np.full((connectivity_open.shape[0], 1), 3), connectivity_open))
    connectivity_flat = np.hstack((np.full((connectivity_flat.shape[0], 1), 3), connectivity_flat))
    connectivity_sphe = np.hstack((np.full((connectivity_sphe.shape[0], 1), 3), connectivity_sphe))

    mesh_open = pyvista.PolyData(points_open, faces=connectivity_open)
    mesh_flat = pyvista.PolyData(points_flat, faces=connectivity_flat)
    mesh_sphe = pyvista.PolyData(points_sphe, faces=connectivity_sphe)

    plotter = pyvista.Plotter(shape=(1, 3), border=False)
    plotter.subplot(0, 0)
    plotter.add_mesh(mesh_open)
    plotter.subplot(0, 1)
    plotter.add_mesh(mesh_flat)
    plotter.subplot(0, 2)
    plotter.add_mesh(mesh_sphe)
    plotter.link_views()
    plotter.show()








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /_auto_examples/images/sphx_glr_plot_mesh_010.png
        :alt: plot mesh
        :srcset: /_auto_examples/images/sphx_glr_plot_mesh_010.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/stable/docs/_auto_examples/images/sphx_glr_plot_mesh_010.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 203-206

Tips
----
* Save meshes for visualization in ParaView using :code:`mesh.save("mesh.vtk")`.


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 1.714 seconds)


.. _sphx_glr_download__auto_examples_plot_mesh.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: plot_mesh.ipynb <plot_mesh.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: plot_mesh.py <plot_mesh.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: plot_mesh.zip <plot_mesh.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
