diff --git a/src/modules/sbstudio/model/yaw.py b/src/modules/sbstudio/model/yaw.py index 0897d30..018a491 100644 --- a/src/modules/sbstudio/model/yaw.py +++ b/src/modules/sbstudio/model/yaw.py @@ -123,3 +123,16 @@ def simplify(self: C) -> C: self.setpoints = new_setpoints return self + + def unwrap(self: C, *, threshold: float = 180, full_cycle: float = 360) -> C: + """Unwraps the yaw angles of the setpoint list "in-place" and ensures + that consecutive sampled angles never have a difference of more than + 180 degrees. + """ + for prev, curr in zip(self.setpoints, self.setpoints[1:]): + diff = curr.angle - prev.angle + if diff > threshold or diff < -threshold: + num_cycles = -round(diff / full_cycle) + curr.angle += num_cycles * full_cycle + + return self diff --git a/src/modules/sbstudio/plugin/utils/sampling.py b/src/modules/sbstudio/plugin/utils/sampling.py index 358e1e5..fc9e4f7 100644 --- a/src/modules/sbstudio/plugin/utils/sampling.py +++ b/src/modules/sbstudio/plugin/utils/sampling.py @@ -144,6 +144,11 @@ def sample_positions_and_yaw_of_objects( YawSetpoint(time, get_xyz_euler_rotation_of_object(obj)[2]) ) + # Ensure that the yaw curve makes sense even if the extracted yaw angles + # "wrap around" the boundary between -180 and 180 degrees + for yaw in yaw_setpoints.values(): + yaw.unwrap() + if simplify: return { key: ( @@ -315,6 +320,11 @@ def sample_positions_colors_and_yaw_of_objects( ) yaw_setpoints[key].append(YawSetpoint(time, rotation[2])) + # Ensure that the yaw curve makes sense even if the extracted yaw angles + # "wrap around" the boundary between -180 and 180 degrees + for yaw in yaw_setpoints.values(): + yaw.unwrap() + if simplify: return { key: (