Source code for dazpy.poses

"""Domain-level pose convenience wrappers built on the DazPose/DazNode/DazSkeleton primitives.

Provides :func:`apply_pose`, :func:`zero_figure`, and :func:`reset_transforms`
so common pose operations don't require hand-assembling :class:`~dazpy.DazPose`
objects or knowing which primitive combination zeroes a figure or resets a
node's transform.
"""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from ._pose import DazPose

if TYPE_CHECKING:
    from ._node import DazNode
    from ._skeleton import DazSkeleton


[docs] def apply_pose(skeleton: "DazSkeleton", pose: "DazPose | str | Path") -> None: """Apply *pose* to *skeleton* in a single HTTP call. Args: skeleton: The figure to pose. pose: A :class:`~dazpy.DazPose` instance, or a path to a pose JSON file (loaded via :meth:`~dazpy.DazPose.load` first). """ if isinstance(pose, (str, Path)): pose = DazPose.load(pose) pose.apply(skeleton)
[docs] def reset_transforms(node: "DazNode") -> None: """Reset *node*'s local position and rotation to zero, and scale to 1.0. Works on any :class:`~dazpy.DazNode` — camera, prop, or figure root. Uses a single DazScript evaluation via :meth:`~dazpy.DazNode.set_transform`. Args: node: The node to reset. """ node.set_transform( position=(0.0, 0.0, 0.0), rotation=(0.0, 0.0, 0.0), scale=(1.0, 1.0, 1.0), )
[docs] def zero_figure(skeleton: "DazSkeleton", *, include_props: bool = False) -> None: """Drive every bone rotation and morph on *skeleton* to zero. The default (``include_props=False``) is what guarantees this function never touches the figure's root position/rotation/scale — use :func:`reset_transforms` for that instead. Args: skeleton: The figure to zero. include_props: When ``True``, node-level numeric properties are also zeroed, via :meth:`~dazpy.DazPose.apply_full`. This is **opt-in**, not the default: ``apply_full`` writes 0 for every property returned by the figure's node-property enumeration that is *absent* from the pose it's given, and every other caller passes a captured pose whose ``props`` dict already contains those values. ``zero_figure`` instead passes an empty ``props={}``, so with ``include_props=True`` that "absent → 0" fallback can drive built-in transform-adjacent dials — e.g. the figure's general Scale property (see the DzERCLink comment in ``dazpy/_pose.py`` around line 117-125) — to 0, contradicting the "does not touch root transform" guarantee. Only pass ``True`` if you know your rig doesn't route transforms through its node-property list. The two modes also differ in how they write ERC-driven channels: the ``True`` path goes through :meth:`~dazpy.DazPose.apply_full`, which prefers ``setRawValue()`` writes to avoid double-applying :class:`DzERCLink` controller contributions (see the comment in ``dazpy/_pose.py`` around line 117-125). The ``False`` path uses :meth:`~dazpy.DazSkeleton.set_bone_rotations` / :meth:`~dazpy.DazSkeleton.set_morph_values`, which use plain ``setValue()`` writes. On ERC-driven channels the two modes can therefore leave the figure in different end states. """ if include_props: pose = DazPose(figure=skeleton._identifier.value, bones={}, morphs={}, props={}) pose.apply_full(skeleton) return skeleton._zero_bones_and_morphs()