Trajectory Editor

Low-level trajectory manipulation for scene edition.

The TrajectoryEditor provides comprehensive trajectory manipulation capabilities and is used internally by EgoEditor and ActorEditor. It can also be accessed directly for advanced use cases requiring fine-grained control over trajectory modifications.

Example

>>> from mimic_scene_edition.editors.trajectory_editor import TrajectoryEditor
>>> te = TrajectoryEditor(original_traj)
>>> te.translate(forward=5)
>>> te.rotate(yaw=15)
>>> modified_traj = te.traj  # Access the result
mimic_scene_edition.editors.trajectory_editor.Referential

"local" or "world".

Type:

Coordinate frame for transformations

alias of Literal[‘local’, ‘world’]

mimic_scene_edition.editors.trajectory_editor.Axis

"x" (forward), "y" (left), or "z" (up).

Type:

Rotation/motion axis

alias of Literal[‘x’, ‘y’, ‘z’]

class mimic_scene_edition.editors.trajectory_editor.TrajectoryEditor(traj, *, recompute_on_mutation=True, limited_mode=False, value_limits=None, editions=None)[source]

Bases: object

Low-level trajectory manipulation editor.

Provides comprehensive methods for editing WorldTrajectory objects, including SE(3) transformations, temporal operations, motion strategies, and utility functions.

Parameters:
  • traj (WorldTrajectory) – The trajectory to edit. This object is modified in place.

  • recompute_on_mutation (bool, optional) – If True (default), automatically recompute velocities after trajectory modifications that affect motion.

  • limited_mode (bool, optional) – If True, enable parameter value limit checking. Default is False.

  • value_limits (dict[str, tuple[float, float]] | None, optional) – Dictionary mapping parameter names to (min, max) bounds. Used when limited_mode is True.

  • editions (list[dict] | None, optional) – List to append edition records to. If None, creates a new list.

Variables:
  • traj (WorldTrajectory) – The trajectory being edited.

  • recompute_on_mutation (bool) – Whether to auto-recompute velocities after modifications.

  • limited_mode (bool) – Whether parameter limit checking is enabled.

  • value_limits (dict) – Parameter value limits for validation.

Notes

The TrajectoryEditor uses a fluent interface pattern - most methods return self to enable method chaining.

After editing, access the modified trajectory via the traj attribute.

Examples

Basic transformation:

>>> te = TrajectoryEditor(original_traj)
>>> te.translate(forward=5).rotate(yaw=15)
>>> modified = te.traj

Complex manipulation with chaining:

>>> te = TrajectoryEditor(traj)
>>> te.displace(forward=10) \
...   .lane_change(start_idx=20, duration=30, lateral=3.5) \
...   .freeze_from(100)
__init__(traj, *, recompute_on_mutation=True, limited_mode=False, value_limits=None, editions=None)[source]
translate(referential='world', **xyz)[source]

Translate the trajectory using semantic direction components.

Applies a translation to all poses in the trajectory using intuitive direction names instead of raw XYZ values.

Parameters:
  • referential ({"local", "world"}, optional) –

    Coordinate frame for the translation:

    • "local": Translation in the object’s local frame (x=forward, y=left, z=up). Applied as post-multiplication.

    • "world": Translation in world coordinates. Applied as pre-multiplication.

    Default is "world".

  • **xyz (float) –

    Named translation components:

    • forward: Distance forward (positive X) in meters

    • backward: Distance backward (negative X) in meters

    • left: Distance left (positive Y) in meters

    • right: Distance right (negative Y) in meters

    • up: Distance up (positive Z) in meters

    • down: Distance down (negative Z) in meters

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.translate(forward=5, left=2)  # World frame
>>> te.translate(forward=3, referential="local")  # Local frame

See also

transform

Combined translation and rotation.

rotate(*, roll=0.0, pitch=0.0, yaw=0.0, referential='world', start_idx=None, end_idx=None)[source]

Rotate the trajectory using Euler angles.

Applies a rotation to poses in the specified frame range using roll-pitch-yaw Euler angles in degrees.

Parameters:
  • roll (float, optional) – Rotation around the X (forward) axis in degrees. Default is 0.

  • pitch (float, optional) – Rotation around the Y (left) axis in degrees. Default is 0.

  • yaw (float, optional) – Rotation around the Z (up) axis in degrees. Default is 0.

  • referential ({"local", "world"}, optional) –

    Coordinate frame for the rotation:

    • "local": Rotation in object’s local frame (post-multiply).

    • "world": Rotation in world frame (pre-multiply).

    Default is "world".

  • start_idx (int | None, optional) – First frame to rotate (inclusive). None means 0.

  • end_idx (int | None, optional) – Last frame to rotate (exclusive). None means end.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.rotate(yaw=90)  # Turn 90° left
>>> te.rotate(pitch=5, start_idx=10, end_idx=50)  # Pitch up in range

See also

transform

Combined translation and rotation.

transform(*, left=0.0, right=0.0, up=0.0, down=0.0, forward=0.0, backward=0.0, roll=0.0, pitch=0.0, yaw=0.0, referential='world', start_idx=None, end_idx=None)[source]

Apply combined translation and rotation.

Combines translation and rotation into a single SE(3) transformation applied to the specified frame range.

Parameters:
  • left (float, optional) – Distance left (positive Y) in meters. Default is 0.

  • right (float, optional) – Distance right (negative Y) in meters. Default is 0.

  • up (float, optional) – Distance up (positive Z) in meters. Default is 0.

  • down (float, optional) – Distance down (negative Z) in meters. Default is 0.

  • forward (float, optional) – Distance forward (positive X) in meters. Default is 0.

  • backward (float, optional) – Distance backward (negative X) in meters. Default is 0.

  • roll (float, optional) – Rotation around X axis in degrees. Default is 0.

  • pitch (float, optional) – Rotation around Y axis in degrees. Default is 0.

  • yaw (float, optional) – Rotation around Z axis in degrees. Default is 0.

  • referential ({"local", "world"}, optional) –

    Coordinate frame for the transformation:

    • "local": Transform in local axes; post-multiply.

    • "world": Transform in world axes; pre-multiply.

    Default is "world".

  • start_idx (int | None, optional) – First frame to transform (inclusive). None means 0.

  • end_idx (int | None, optional) – Last frame to transform (exclusive). None means end.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.transform(forward=5, left=2, yaw=15)
>>> te.transform(up=1, pitch=5, referential="local", start_idx=10)

See also

translate

Translation only.

rotate

Rotation only.

apply_T_sequence

Raw transformation matrix application.

apply_T_sequence(T_seq, *, start_idx=None, end_idx=None, referential='world')[source]

Apply a sequence of 4x4 transformation matrices.

Applies SE(3) transformation matrices to poses in the specified frame range. Can apply a single matrix to all frames or a sequence of per-frame matrices.

Parameters:
  • T_seq (np.ndarray) – Transformation matrices with shape (4, 4) for a single transform applied to all frames, or (N, 4, 4) for per-frame transforms where N matches the frame range size.

  • start_idx (int | None, optional) – First frame to transform (inclusive). None means 0.

  • end_idx (int | None, optional) – Last frame to transform (exclusive). None means end.

  • referential ({"local", "world"}, optional) –

    How to apply the transformation:

    • "world": Left-multiply (T @ pose).

    • "local": Right-multiply (pose @ T).

    Default is "world".

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> # Apply single transform to all frames
>>> te.apply_T_sequence(T_4x4, referential="world")
>>> # Apply per-frame transforms
>>> T_seq = np.zeros((100, 4, 4))
>>> # ... fill T_seq ...
>>> te.apply_T_sequence(T_seq, start_idx=10, end_idx=110)
resample_to_rate(hz)[source]

Resample the trajectory to a target frame rate.

Interpolates the trajectory to produce poses at a uniform temporal spacing determined by the specified frequency.

Parameters:

hz (float) – Target frame rate in Hz (frames per second). Must be positive.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Raises:

ValueError – If hz is not positive.

Examples

>>> te.resample_to_rate(10.0)  # Resample to 10 Hz
>>> te.resample_to_rate(30.0)  # Resample to 30 Hz

See also

resample_to_times

Resample to specific timestamps.

resample_to_times(new_t)[source]

Resample the trajectory to specific timestamps.

Interpolates poses to the specified query timestamps using SE(3) interpolation for smooth results.

Parameters:

new_t (np.ndarray) – Array of target timestamps to sample at.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> new_times = np.linspace(0, 10, 100)
>>> te.resample_to_times(new_times)

See also

resample_to_rate

Resample to a uniform frame rate.

offset_frames(k)[source]

Circular shift the trajectory by k frames.

Shifts all poses and timestamps by k frames in a circular manner, wrapping around at the boundaries.

Parameters:

k (int) – Number of frames to shift. Positive values shift forward in time, negative values shift backward.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.offset_frames(5)   # Shift forward 5 frames
>>> te.offset_frames(-3)  # Shift backward 3 frames
slice(start_idx, end_idx)[source]

Keep only frames in the specified range.

Truncates the trajectory to contain only poses within the specified index range.

Parameters:
  • start_idx (int) – First frame to keep (inclusive).

  • end_idx (int) – Last frame to keep (exclusive).

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.slice(10, 50)  # Keep frames 10-49
freeze(start_idx, end_idx=None, *, persist_tail=True)[source]

Freeze poses in a range to a static position.

Makes the object stationary by repeating the pose at start_idx for the specified range. Velocities are zeroed in the frozen region.

Parameters:
  • start_idx (int) – Index of the frame to freeze at.

  • end_idx (int | None, optional) – End of freeze range (exclusive). If None, freeze to the end of the trajectory.

  • persist_tail (bool, optional) – If True (default) and end_idx is specified, maintain continuity with poses after the frozen region.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.freeze(50)  # Freeze from frame 50 to end
>>> te.freeze(30, 60)  # Freeze frames 30-59 only

See also

freeze_from

Shortcut for freezing to end.

freeze_window

Freeze a specific window.

freeze_from(idx)[source]

Freeze the trajectory from an index to the end.

Convenience method equivalent to freeze(idx, None).

Parameters:

idx (int) – Index to start freezing from.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.freeze_from(50)  # Freeze from frame 50 onwards

See also

freeze

Full freeze functionality.

freeze_window(start_idx, end_idx, *, persist_tail=True)[source]

Freeze a specific window of frames.

Convenience method equivalent to freeze(start_idx, end_idx).

Parameters:
  • start_idx (int) – First frame to freeze (inclusive).

  • end_idx (int) – Last frame to freeze (exclusive).

  • persist_tail (bool, optional) – If True (default), maintain continuity after the frozen region.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.freeze_window(30, 60)  # Freeze frames 30-59

See also

freeze

Full freeze functionality.

spin(*, period_s=None, rpm=None, axis='z', start_idx=None, end_idx=None)[source]

Apply continuous rotation (spinning) to the trajectory.

Makes the object rotate continuously around the specified axis at a constant rate defined by either period or RPM.

Parameters:
  • period_s (float | None, optional) – Seconds per full revolution. Mutually exclusive with rpm.

  • rpm (float | None, optional) – Revolutions per minute. Mutually exclusive with period_s.

  • axis ({"x", "y", "z"}, optional) – Rotation axis. Default is "z" (vertical).

  • start_idx (int | None, optional) – First frame to apply spin (inclusive). None means 0.

  • end_idx (int | None, optional) – Last frame to apply spin (exclusive). None means end.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.spin(rpm=60, axis="z")  # 60 RPM around vertical axis
>>> te.spin(period_s=2.0)  # One revolution per 2 seconds
displace_along_forward(meters, *, start_idx=None, end_idx=None)[source]

Displace the trajectory along its path by arc-length.

Moves poses along the trajectory path (not in a straight line) by the specified distance.

Parameters:
  • meters (float) – Distance to displace in meters. Positive moves forward, negative moves backward along the path.

  • start_idx (int | None, optional) – First frame to displace (inclusive). None means 0.

  • end_idx (int | None, optional) – Last frame to displace (exclusive). None means end.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.displace_along_forward(10.0)  # Move 10m forward on path
>>> te.displace_along_forward(-5.0)  # Move 5m backward on path

See also

displace

Displacement with named direction parameters.

displace(*, forward=0.0, backward=0.0, start_idx=None, end_idx=None)[source]

Displace poses along the trajectory path by arc-length.

Unlike translate(), this moves the object along the path it’s already following, not in a straight line. This is useful for positioning actors relative to their motion path.

Parameters:
  • forward (float, optional) – Distance to move forward along path in meters. Default is 0.

  • backward (float, optional) – Distance to move backward along path in meters. Default is 0.

  • start_idx (int | None, optional) – First frame to displace (inclusive). None means 0.

  • end_idx (int | None, optional) – Last frame to displace (exclusive). None means end.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.displace(forward=10)  # Place 10m ahead on path
>>> te.displace(backward=5)  # Place 5m behind on path

Notes

For lateral offset, chain with transform():

>>> te.displace(forward=10).transform(left=2)

See also

displace_along_forward

Shortcut with single distance parameter.

translate

Straight-line translation.

move_local_with_speed(*, start_idx, speed, axis='x')[source]

Build a constant-speed motion transformation sequence.

Creates transformation matrices that move the object at constant speed along a local axis from the specified frame.

Parameters:
  • start_idx (int) – Frame index to start the motion.

  • speed (float) – Speed in meters per second.

  • axis ({"x", "y", "z"}, optional) – Local axis to move along. Default is "x" (forward).

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.move_local_with_speed(start_idx=10, speed=5.0)  # 5 m/s forward
scale_speed(*, multiplier, anchor='start')[source]

Change apparent speed by retiming timestamps.

Adjusts the trajectory’s timestamps to change the perceived speed without modifying the spatial path. Frame count and poses remain unchanged.

Parameters:
  • multiplier (float) –

    Speed scaling factor:

    • > 1: Faster (shorter time between frames)

    • < 1: Slower (longer time between frames)

    Must be positive.

  • anchor ({"start", "first"}, optional) – Time reference point that remains fixed. Default is "start".

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Raises:

ValueError – If multiplier is not positive.

Examples

>>> te.scale_speed(multiplier=2.0)  # Double speed
>>> te.scale_speed(multiplier=0.5)  # Half speed
lane_change(start_idx, duration, lateral, kind='smooth')[source]

Build a lateral lane change maneuver.

Applies a smooth lateral displacement to simulate a lane change, with optional tail offset persistence.

Parameters:
  • start_idx (int) – Frame index to start the maneuver.

  • duration (int) – Number of frames for the maneuver.

  • lateral (float) – Lateral distance in meters. Positive is left.

  • kind ({"smooth", "abrupt", "evasive"}, optional) –

    Type of lane change:

    • "smooth": Gradual transition to new lane (step function).

    • "abrupt": Quick transition.

    • "evasive": Swerve and return to original lane (bump).

    Default is "smooth".

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.lane_change(start_idx=10, duration=30, lateral=3.5)  # Left lane change
>>> te.lane_change(start_idx=20, duration=40, lateral=-3.5)  # Right lane change
>>> te.lane_change(start_idx=30, duration=50, lateral=2.0, kind="evasive")
make_static_from_reference(reference, *, at_idx=0, forward=0.0, backward=0.0, left=0.0, right=0.0, up=0.0, down=0.0, yaw_deg=0.0, timestamps=None)[source]

Create a static trajectory positioned relative to a reference.

Builds a trajectory where the object remains stationary at a position determined by offsets from a reference trajectory at a specific frame.

Parameters:
  • reference (WorldTrajectory) – Reference trajectory for positioning.

  • at_idx (int, optional) – Frame index in reference trajectory to use. Default is 0.

  • forward (float, optional) – Forward offset from reference in meters. Default is 0.

  • backward (float, optional) – Backward offset from reference in meters. Default is 0.

  • left (float, optional) – Left offset from reference in meters. Default is 0.

  • right (float, optional) – Right offset from reference in meters. Default is 0.

  • up (float, optional) – Up offset from reference in meters. Default is 0.

  • down (float, optional) – Down offset from reference in meters. Default is 0.

  • yaw_deg (float, optional) – Yaw rotation relative to reference in degrees. Default is 0.

  • timestamps (np.ndarray | None, optional) – Timestamps for the static trajectory. If None, uses reference timestamps.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.make_static_from_reference(
...     ego_traj,
...     at_idx=0,
...     forward=20,
...     left=3.5
... )
smooth(*, method='savgol', window=11, polyorder=3)[source]

Smooth the trajectory positions using filtering.

Applies a smoothing filter to reduce noise in the position components of the trajectory.

Parameters:
  • method ({"savgol"}, optional) – Smoothing method. Currently only Savitzky-Golay is supported. Default is "savgol".

  • window (int, optional) – Window size for the filter. Must be odd. Default is 11.

  • polyorder (int, optional) – Polynomial order for Savitzky-Golay. Default is 3.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.smooth()  # Default parameters
>>> te.smooth(window=21, polyorder=5)  # Custom smoothing
recompute_velocities()[source]

Recompute linear and angular velocities from poses.

Recalculates velocity arrays based on the current pose sequence and timestamps. Useful after external modifications.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.recompute_velocities()
replace(traj)[source]

Replace the underlying trajectory.

Substitutes the trajectory being edited with a new one. If recompute_on_mutation is True, velocities are recomputed for the new trajectory.

Parameters:

traj (WorldTrajectory) – The new trajectory to edit.

Returns:

Self for method chaining.

Return type:

TrajectoryEditor

Examples

>>> te.replace(new_trajectory)