
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "auto_examples/plot_frame.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_frame.py>`
        to download the full example code.

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

.. _sphx_glr_auto_examples_plot_frame.py:


Moving Frames
=============

`Moving frames`_ provide a local coordinate system along a curve. This system can be used to analyze the space around points on the curve, such as extracting orthogonal images from a volume. An example of this application is the Dendrite-Centric Coordinate System.

SplineBox implements two types of moving frames:

1. `Frenet-Serret Frame`_: Defined by the curve's tangent, normal, and binormal vectors. To compute all three vectors, the curve cannot have any straight segments and no inflection points. Additionally, the frame may rotate around the curve.
2. `Bishop Frame`_: A twist-free alternative that eliminates rotations around the curve and is defined on straight segments and at inflections points [Bishop1975]_.

.. _Moving frames: https://en.wikipedia.org/wiki/Moving_frame
.. _Frenet-Serret Frame: https://en.wikipedia.org/wiki/Frenet-Serret_formulas
.. _Bishop Frame: https://www.jstor.org/stable/2319846

.. GENERATED FROM PYTHON SOURCE LINES 16-21

.. code-block:: Python


    import numpy as np
    import pyvista
    import splinebox








.. GENERATED FROM PYTHON SOURCE LINES 22-24

1. Create a Spline
^^^^^^^^^^^^^^^^^^

.. GENERATED FROM PYTHON SOURCE LINES 24-39

.. code-block:: Python


    spline = splinebox.Spline(M=4, basis_function=splinebox.B3(), closed=False)
    spline.control_points = np.array(
        [
            [0.0, 0.0, 0.0],
            [1.0, 0.0, 0.0],
            [1.0, 1.0, 0.0],
            [1.0, 1.0, 1.0],
            [0.0, 1.0, 1.0],
            [0.0, 0.0, 0.0],
        ]
    )

    t = np.linspace(0, spline.M - 1, spline.M * 3)








.. GENERATED FROM PYTHON SOURCE LINES 40-42

2. Compute the Frenet-Serret Frame
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. GENERATED FROM PYTHON SOURCE LINES 42-45

.. code-block:: Python


    frenet_frame = spline.moving_frame(t, method="frenet")








.. GENERATED FROM PYTHON SOURCE LINES 46-48

3. Compute the Bishop Frame
^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. GENERATED FROM PYTHON SOURCE LINES 48-51

.. code-block:: Python


    bishop_frame = spline.moving_frame(t, method="bishop")








.. GENERATED FROM PYTHON SOURCE LINES 52-57

4. Visualize the Frames
^^^^^^^^^^^^^^^^^^^^^^^
We can visualize the Frenet-Serret and Bishop frames using PyVista.
The following code plots the two frames side-by-side to highlight their differences.
The Frenet-Serret frame (left) visibly twists along the curve, while the Bishop frame (right) avoids this twist.

.. GENERATED FROM PYTHON SOURCE LINES 57-95

.. code-block:: Python


    # Create a PyVista mesh for the curve
    spline_mesh = pyvista.MultipleLines(points=spline(t))

    # Add vectors to the mesh for visualization
    spline_mesh["frenet0"] = frenet_frame[:, 0] * 0.2
    spline_mesh["frenet1"] = frenet_frame[:, 1] * 0.2
    spline_mesh["frenet2"] = frenet_frame[:, 2] * 0.2
    spline_mesh["bishop0"] = bishop_frame[:, 0] * 0.2
    spline_mesh["bishop1"] = bishop_frame[:, 1] * 0.2
    spline_mesh["bishop2"] = bishop_frame[:, 2] * 0.2

    # Initialize a PyVista plotter
    plotter = pyvista.Plotter(shape=(1, 2), border=False)

    # Plot the Frenet-Serret frame
    plotter.subplot(0, 0)
    spline_mesh.set_active_vectors("frenet0")
    plotter.add_mesh(spline_mesh.arrows, lighting=False, color="blue")
    spline_mesh.set_active_vectors("frenet1")
    plotter.add_mesh(spline_mesh.arrows, lighting=False, color="red")
    spline_mesh.set_active_vectors("frenet2")
    plotter.add_mesh(spline_mesh.arrows, lighting=False, color="green")
    plotter.add_mesh(spline_mesh, line_width=10, color="black")

    # Plot the Bishop frame
    plotter.subplot(0, 1)
    spline_mesh.set_active_vectors("bishop0")
    plotter.add_mesh(spline_mesh.arrows, lighting=False, color="blue")
    spline_mesh.set_active_vectors("bishop1")
    plotter.add_mesh(spline_mesh.arrows, lighting=False, color="red")
    spline_mesh.set_active_vectors("bishop2")
    plotter.add_mesh(spline_mesh.arrows, lighting=False, color="green")
    plotter.add_mesh(spline_mesh, line_width=10, color="black", copy_mesh=True)

    plotter.link_views()
    plotter.show()








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /auto_examples/images/sphx_glr_plot_frame_001.png
        :alt: plot frame
        :srcset: /auto_examples/images/sphx_glr_plot_frame_001.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/docs/checkouts/readthedocs.org/user_builds/splinebox/checkouts/v0.5.1/docs/auto_examples/images/sphx_glr_plot_frame_001.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 96-98

If we want the Bishop frame to start in a specific orientation, we can specify
an :code:`initial_vector` in :meth:`splinebox.spline_curves.Spline.moving_frame()`.


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

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


.. _sphx_glr_download_auto_examples_plot_frame.py:

.. only:: html

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

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

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

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

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

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

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


.. only:: html

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

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