Karana.KUtils.vizutils
======================

.. py:module:: Karana.KUtils.vizutils

.. autoapi-nested-parse::

   Classes and functions associated with visualizing forces.



Classes
-------

.. autoapisummary::

   Karana.KUtils.vizutils.NodeForceVisualizer
   Karana.KUtils.vizutils.SpringForceVisualizer
   Karana.KUtils.vizutils.SpringModelProtocol
   Karana.KUtils.vizutils.Axes3d
   Karana.KUtils.vizutils.ContactForceVisualizer
   Karana.KUtils.vizutils.FrameToFrameRateType
   Karana.KUtils.vizutils.FrameToFrameVectorVisualizer
   Karana.KUtils.vizutils.ScaledVectorVisualizer
   Karana.KUtils.vizutils.VectorVisualizer


Functions
---------

.. autoapisummary::

   Karana.KUtils.vizutils.computeSphereSweptHull
   Karana.KUtils.vizutils.createBodyHullPartSpec
   Karana.KUtils.vizutils.visualizeFrameToFrameRates
   Karana.KUtils.vizutils.visualizeInterBodyForce
   Karana.KUtils.vizutils.visualizeInterBodyTorque
   Karana.KUtils.vizutils.visualizeNodeForce
   Karana.KUtils.vizutils.visualizeNodeTorque


Package Contents
----------------

.. py:class:: NodeForceVisualizer(name: str, scene: Karana.Scene.ProxyScene, force_scale: float | collections.abc.Callable[[float], float] = 0.01, radius: float = 0.01, color: Karana.Scene.Color = Color.WHITE, auto_update: bool = True)

   Helper to visualize the force on a Node.

   The force is visualized as an arrow emanating from the point where
   the force is applied. The arrow's length scales based on the
   magnitude of the force.

   Unless constructed with auto_update=True, the update
   method must be called periodically to update the arrow.



   .. py:attribute:: name


   .. py:method:: setNode(node: Karana.Dynamics.Node | None, update: bool = True)

      Set the external force node to visualize.

      :param node: The node to visualize the force of, or None to disable
      :type node: Node | None
      :param update: If True, immediately update the force visualization
      :type update: bool



   .. py:method:: update()

      Update the force visualization.

      Unless constructed with auto_update=True, this needs
      to be called whenever the force changes in order to
      see the effect in the visualization.




.. py:class:: SpringForceVisualizer(name: str, mdl: SpringModelProtocol, scene: Karana.Scene.ProxyScene, *, colors: tuple[Karana.Scene.Color, Karana.Scene.Color] = (Color.YELLOW, Color.BLUE), force_scale: float | collections.abc.Callable = 0.01, radius: float = 0.01, auto_update: bool = True)

   Helper to visualize forces generated by contact.

   The force is visualized as a pair of arrows emanating from the
   point where the force is applied. The arrow's length scales based
   on the magnitude of the force.

   Unless constructed with auto_update=True, the update
   method must be called periodically to update the arrows.



   .. py:method:: update(*args)

      Update the force visualization.

      Unless constructed with auto_update=True, this needs to be called
      whenever to the force changes in order to see the effect in the
      visualization.




.. py:class:: SpringModelProtocol

   Bases: :py:obj:`Protocol`


   A protocol for classes representing a spring model between a pair of nodes.


   .. py:method:: sourceNode() -> Karana.Dynamics.Node

      Return the starting node of the spring.



   .. py:method:: targetNode() -> Karana.Dynamics.Node

      Return the ending node of the spring.



.. py:function:: computeSphereSweptHull(positions, *, sphere_radius: float = 0.03, points_per_sphere: int = 20)

   Compute a sphere-swept convex hull.

   :param positions: An Nx3 array of vertex positions to form a hull over.
   :param sphere_radius: Radius of the sphere to sweep over the hull. Defaults to 0.03.
   :type sphere_radius: float
   :param points_per_sphere: Number of points on the sphere surface approximation. Defaults
                             to 20.
   :type points_per_sphere: int

   :returns: A StaticMeshGeometry for the sphere-swept convex hull
   :rtype: StaticMeshGeometry


.. py:function:: createBodyHullPartSpec(body: Karana.Dynamics.PhysicalBody, *, sphere_radius: float = 0.03, points_per_sphere: int = 20, material: Karana.Scene.PhysicalMaterial | Karana.Scene.PhongMaterial | None = None) -> Karana.Scene.ScenePartSpec

   Create a ScenePartSpec for a convex hull over a body's nodes.

   The resulting ScenePartSpec should be added to the body by calling
   PhysicalBody.addScenePartSpec.

   :param body: The body of interest
   :type body: PhysicalBody
   :param sphere_radius: Radius of the sphere swept through the hull. Defaults to 0.03.
   :type sphere_radius: float
   :param points_per_sphere: Number of points on the sphere surface approximation. Defaults
                             to 20.
   :type points_per_sphere: int
   :param material: Material to apply. If None, uses a default material.
   :type material: PhysicalMaterial | PhongMaterial | None

   :returns: A ScenePartSpec for the hull
   :rtype: ScenePartSpec


.. py:class:: Axes3d(name: str, scene: Karana.Scene.ProxyScene, length: float = 1.0, radius: float = 0.1)

   Create a 3d axes visualization.


   .. py:property:: name
      :type: str


      Get the name of the Axes3d.

      :returns: The name
      :rtype: str


   .. py:property:: node
      :type: Karana.Scene.ProxySceneNode


      Get the base node of the axes.

      :returns: The node
      :rtype: ks.ProxySceneNode


.. py:class:: ContactForceVisualizer(name: str, frame: Karana.Frame.Frame, scene: Karana.Scene.ProxyScene, fn: Karana.Models.PenaltyContact)

   Bases: :py:obj:`Karana.Core.Base`


   Visualize the contact forces created by a PenaltyContact KModel.

   The frame provided is the frame the vectors will be drawn in.


   .. py:method:: create(name: str, frame: Karana.Frame.Frame, scene: Karana.Scene.ProxyScene, fn: Karana.Models.PenaltyContact) -> ContactForceVisualizer
      :staticmethod:


      Create a new instance of ContactForceVisualizer.

      :param name: Name of the visualizer.
      :param frame: The Frame where the vectors will be drawn in.
      :param scene: The ProxyScene to add the vectors to.
      :param penalty_contact: The PenaltyContact model to get the contact
                              vectors from.

      :returns: A pointer to the newly created ContactForceVisualizer.



   .. py:method:: getColor() -> Karana.Scene.Color

      Get the color of the vectors.

      :returns: The color of the vectors.



   .. py:method:: getRadius() -> float

      Get the radius of the vectors.

      :returns: The radius of the vectors.



   .. py:method:: getScale() -> float

      Get the current scale.

      :returns: The current scale.



   .. py:method:: registerCallback() -> None

      Register the callback with the scene.



   .. py:method:: setColor(color: Karana.Scene.Color) -> None

      Set the color of the vectors.

      :param color: The new color of the vectors.



   .. py:method:: setRadius(radius: SupportsFloat | SupportsIndex) -> None

      Set the radius of the vectors.

      :param radius: The new radius of the vectors.



   .. py:method:: setScale(scale: SupportsFloat | SupportsIndex) -> None

      Set the current scale.

      :param scale: The current scale.



   .. py:method:: unregisterCallback() -> None

      Unregister the callback with the scene.



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

   Bases: :py:obj:`enum.Enum`


   Enums for the frame to frame rate vector types for visualization


   .. py:attribute:: ACCEL_ANGULAR
      :type:  ClassVar[FrameToFrameRateType]


   .. py:attribute:: ACCEL_LINEAR
      :type:  ClassVar[FrameToFrameRateType]


   .. py:attribute:: VEL_ANGULAR
      :type:  ClassVar[FrameToFrameRateType]


   .. py:attribute:: VEL_LINEAR
      :type:  ClassVar[FrameToFrameRateType]


.. py:class:: FrameToFrameVectorVisualizer(name: str, frame_to_frame: Karana.Frame.FrameToFrame, scene: Karana.Scene.ProxyScene)

   Bases: :py:obj:`Karana.Core.Base`


   Visualize a vector that spans the two frames in a FrameToFrame.

   The origin of the vector is at the o-frame of the FrameToFrame, and
   the end of the vector is at the p-frame of the FrameToFrame.


   .. py:method:: create(name: str, frame_to_frame: Karana.Frame.FrameToFrame, scene: Karana.Scene.ProxyScene) -> FrameToFrameVectorVisualizer
      :staticmethod:


      Create a new instance of VectorVisualizer.

      :param name: Name of the visualizer.
      :param frame_to_frame: The FrameToFrame for the vector.
      :param scene: The ProxyScene to add the vector to.

      :returns: A pointer to the newly created FrameToFrameVectorVisualizer.



   .. py:method:: getEndOffset() -> Annotated[numpy.typing.NDArray[numpy.float64], [3, 1]]

      Get the ending offset of the vector.

      This is the offset between the p-frame of the frame to frame  and the
      end of the vector.

      :returns: The start offset of the vector.



   .. py:method:: setEndOffset(offset: Annotated[numpy.typing.ArrayLike, numpy.float64, [3, 1]]) -> None

      Set the end offset of the vector.

      This is the offset between the p-frame of the frame to frame  and the
      end of the vector.

      :param offset: The new end offset of the vector.



.. py:class:: ScaledVectorVisualizer(name: str, frame: Karana.Frame.Frame, scene: Karana.Scene.ProxyScene, fn: collections.abc.Callable[[], Annotated[numpy.typing.NDArray[numpy.float64], [3, 1]]])

   Bases: :py:obj:`VectorVisualizer`


   A scaled version of VectorVisualizer.

   This is like the VectorVisualizer class (see that class for more
   details) but the length of the vector can be scaled using
   get/setScale.


   .. py:method:: create(name: str, frame: Karana.Frame.Frame, scene: Karana.Scene.ProxyScene, fn: collections.abc.Callable[[], Annotated[numpy.typing.NDArray[numpy.float64], [3, 1]]]) -> ScaledVectorVisualizer
      :staticmethod:


      Create a new instance of VectorVisualizer.

      :param name: Name of the visualizer.
      :param frame: The Frame where the vector starts.
      :param scene: The ProxyScene to add the vector to.
      :param fn: The function used to update the vector.

      :returns: A pointer to the newly created ScaledVectorVisualizer.



   .. py:method:: getScale() -> float

      Get the current scale.

      :returns: The current scale.



   .. py:method:: setScale(scale: SupportsFloat | SupportsIndex) -> None

      Set the current scale.

      :param scale: The current scale.



.. py:class:: VectorVisualizer(name: str, frame: Karana.Frame.Frame, scene: Karana.Scene.ProxyScene, fn: collections.abc.Callable[[], Annotated[numpy.typing.NDArray[numpy.float64], [3, 1]]])

   Bases: :py:obj:`Karana.Core.Base`


   Visualize a vector using a frame and a function.

   The frame is origin of the vector, and the function provides the
   length/direction for the vector.


   .. py:method:: create(name: str, frame: Karana.Frame.Frame, scene: Karana.Scene.ProxyScene, fn: collections.abc.Callable[[], Annotated[numpy.typing.NDArray[numpy.float64], [3, 1]]]) -> VectorVisualizer
      :staticmethod:


      Create a new instance of VectorVisualizer.

      :param name: Name of the visualizer.
      :param frame: The Frame where the vector starts.
      :param scene: The ProxyScene to add the vector to.
      :param fn: The function used to update the vector.

      :returns: A pointer to the newly created VectorVisualizer.



   .. py:method:: getColor() -> Karana.Scene.Color

      Get the color of the vector.

      :returns: The color of the vector.



   .. py:method:: getRadius() -> float

      Get the radius of the vector.

      :returns: The radius of the vector.



   .. py:method:: getStartOffset() -> Annotated[numpy.typing.NDArray[numpy.float64], [3, 1]]

      Get the starting offset of the vector.

      This is the offset between the frame origin and the start of the
      vector.

      :returns: The start offset of the vector.



   .. py:method:: registerCallback() -> None

      Register the callback with the scene.



   .. py:method:: setColor(color: Karana.Scene.Color) -> None

      Set the color of the vector.

      :param color: The new color of the vector.



   .. py:method:: setRadius(radius: SupportsFloat | SupportsIndex) -> None

      Set the radius of the vector.

      :param radius: The new radius of the vector.



   .. py:method:: setStartOffset(offset: Annotated[numpy.typing.ArrayLike, numpy.float64, [3, 1]]) -> None

      Set the start offset of the vector.

      This is the offset between the frame origin and the start of the
      vector.

      :param offset: The new start offset of the vector.



   .. py:method:: unregisterCallback() -> None

      Unregister the callback with the scene.



.. py:function:: visualizeFrameToFrameRates(frame_to_frame: Karana.Frame.FrameToFrame, scene: Karana.Scene.ProxyScene, rate_type: FrameToFrameRateType) -> ScaledVectorVisualizer

   Visualize the frame_to_frame vel/accel values

   Visualize the relative velocity/acceleration (as specified by the type
   argument) for the frame_to_frame as a vector originating from the
   pframe and whose size and direction is proportional to the selected
   relative rate. The orientation of the vector is in the oframe.

   :param frame_to_frame: Visualize the vector for the frame_to_frame's
                          rates.
   :param scene: The ProxyScene to use for visualizing.
   :param rate_type: The type of rate to visualize

   :returns: A ScaledVectorVisualizer for visualizing the frame-to-frame rates.


.. py:function:: visualizeInterBodyForce(onode: Karana.Dynamics.HingeOnode, scene: Karana.Scene.ProxyScene, use_ta: bool) -> ScaledVectorVisualizer

   Visualize the interbody force on a node.

   :param onode: The Onode to visualize the force for.
   :param scene: The ProxyScene to use for visualizing.
   :param use_ta: If true, use TA getInterBodyForceTAFwdDyn to calculate the
                  force. Otherwise, use getInterBodyForceTreeFwdDyn.

   :returns: A ScaledVectorVisualizer for visualizing the interbody force on
             the node.


.. py:function:: visualizeInterBodyTorque(onode: Karana.Dynamics.HingeOnode, scene: Karana.Scene.ProxyScene, use_ta: bool) -> ScaledVectorVisualizer

   Visualize the interbody torque on a node.

   :param onode: The Onode to visualize the torque for.
   :param scene: The ProxyScene to use for visualizing.
   :param use_ta: If true, use TA getInterBodyForceTAFwdDyn to calculate the
                  torque. Otherwise, use getInterBodyForceTreeFwdDyn.

   :returns: A ScaledVectorVisualizer for visualizing the interbody torque on
             the node.


.. py:function:: visualizeNodeForce(node: Karana.Dynamics.Node, scene: Karana.Scene.ProxyScene) -> ScaledVectorVisualizer

   Visualize the force of a node.

   :param node: The node to visualize the force for.
   :param scene: The ProxyScene to use for visualizing.

   :returns: A ScaledVectorVisualizer for visualizing the node force.


.. py:function:: visualizeNodeTorque(node: Karana.Dynamics.Node, scene: Karana.Scene.ProxyScene) -> ScaledVectorVisualizer

   Visualize the torque on a node.

   :param node: The node to visualize the torque for.
   :param scene: The ProxyScene to use for visualizing.

   :returns: A ScaledVectorVisualizer for visualizing the node force.


