Dynamics
Reference for DynamicScene, LinearTrajectory, RigidMotion, DeformationState and the Trajectory and Deformation protocols for time-varying scenes.
The motion classes live in witwin.core.dynamics and are exported from witwin.core (both import paths work). For examples, see Animate a scene.
from witwin.core import Deformation, DeformationState, DynamicScene, LinearTrajectory, RigidMotion, TrajectoryDynamicScene#
class DynamicScene(
scene: Scene,
*,
structure_trajectories: Mapping[StructureId | int, Trajectory] | None = None,
structure_deformations: Mapping[StructureId | int, Deformation] | None = None,
endpoint_trajectories: Mapping[AntennaId | int, Trajectory] | None = None,
dynamic_revision: int = 0,
)A static scene plus motion descriptors. It does not compile anything; it produces snapshots. Immutable.
The static scene. Other types raise TypeError.
NoneRigid motion per structure ID.
NoneVertex deformation per structure ID.
NoneRigid motion per antenna ID.
0A counter you raise when the motion descriptors change in a way Core cannot see. Part of the snapshot's geometry_version. Must be at least 0.
Raises KeyError for a structure or antenna ID that is not in the scene, and TypeError for a value that does not implement the protocol.
The mappings are stored as read-only mappings keyed by StructureId and AntennaId under the attribute names above.
DynamicScene.at#
at(time_s: ScalarLike) -> SceneSnapshotReturns the snapshot at time_s seconds. Each structure's StructureState carries trajectory.at(time_s) and deformation.at(time_s) where defined, else None; each endpoint's EndpointState carries its trajectory's motion. A tensor time_s must be 0-d (ValueError) and is passed to the descriptors as is.
RigidMotion#
class RigidMotion(*, translation=None, rotation=None, velocity=None, angular_velocity=None)Rigid state added after the authored pose. All arguments are optional and keyword-only. Sequences become float32 tensors. Immutable.
NoneWorld-frame displacement in metres, added last.
NoneLocal-to-world rotation composed on the left of the authored rotation. Euler (yaw, pitch, roll) or quaternion (w, x, y, z).
NoneLinear velocity in m/s, for solvers (for example Doppler).
NoneAngular velocity, for solvers.
Raises ValueError when the tensors differ in device or dtype or have the wrong trailing shape, and TypeError for non-floating dtypes.
DeformationState#
class DeformationState(*, vertices=None, offsets=None)Topology-preserving vertex state, in the structure's local frame. Give exactly one argument, otherwise ValueError.
NoneAbsolute local vertices that replace the authored ones.
NoneOffsets added to the authored local vertices.
The deformation is applied before the authored transform and before any RigidMotion.
Trajectory and Deformation#
@runtime_checkable
class Trajectory(Protocol):
def at(self, time_s: ScalarLike) -> RigidMotion: ...
@runtime_checkable
class Deformation(Protocol):
def at(self, time_s: ScalarLike) -> DeformationState: ...Any object with a matching at method. Core calls at once per snapshot.
LinearTrajectory#
@dataclass(frozen=True)
class LinearTrajectory:
origin: torch.Tensor
velocity: torch.Tensor
rotation: torch.Tensor | None = None
angular_velocity: torch.Tensor | None = None
reference_time_s: float = 0.0Constant-velocity motion: at(t) returns a RigidMotion with translation = origin + velocity * (t - reference_time_s), and velocity, rotation and angular_velocity copied as given.
Translation at reference_time_s, in metres.
Velocity in m/s.
NoneA constant rotation, antenna convention.
NoneStored and passed through; not integrated.
0.0The time at which the translation equals origin.
All tensors must share one device and one dtype. A tensor time_s passed to at must match them, otherwise ValueError.
from witwin.core import LinearTrajectory
walk = LinearTrajectory(origin=(0.0, 0.0, 0.0), velocity=(1.2, 0.0, 0.0), reference_time_s=1.0)
print(walk.at(3.0).translation)tensor([2.4000, 0.0000, 0.0000])