Skip to content

Commit

Permalink
refactor: store storyboard entry mapping as JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
ntamas committed Jul 11, 2023
1 parent 79d14e6 commit c1a521f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 22 deletions.
2 changes: 0 additions & 2 deletions src/addons/ui_skybrush_studio.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
LEDControlPanelProperties,
LightEffect,
LightEffectCollection,
MappingType,
SafetyCheckProperties,
ScheduleOverride,
StoryboardEntry,
Expand Down Expand Up @@ -147,7 +146,6 @@
FormationsPanelProperties,
LightEffect,
LightEffectCollection,
MappingType,
ScheduleOverride,
StoryboardEntry,
Storyboard,
Expand Down
3 changes: 1 addition & 2 deletions src/modules/sbstudio/plugin/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .safety_check import SafetyCheckProperties
from .settings import DroneShowAddonFileSpecificSettings
from .show import DroneShowAddonProperties
from .storyboard import MappingType, ScheduleOverride, StoryboardEntry, Storyboard
from .storyboard import ScheduleOverride, StoryboardEntry, Storyboard

__all__ = (
"DroneShowAddonFileSpecificSettings",
Expand All @@ -17,7 +17,6 @@
"LEDControlPanelProperties",
"LightEffect",
"LightEffectCollection",
"MappingType",
"SafetyCheckProperties",
"ScheduleOverride",
"StoryboardEntry",
Expand Down
56 changes: 47 additions & 9 deletions src/modules/sbstudio/plugin/model/storyboard.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import bpy
import json

from bpy.props import (
BoolProperty,
Expand All @@ -25,7 +26,7 @@
from .formation import count_markers_in_formation
from .mixins import ListMixin

__all__ = ("MappingType", "ScheduleOverride", "StoryboardEntry", "Storyboard")
__all__ = ("ScheduleOverride", "StoryboardEntry", "Storyboard")


class ScheduleOverride(PropertyGroup):
Expand Down Expand Up @@ -84,17 +85,11 @@ def _handle_formation_change(operator, context):
operator.name = operator.formation.name if operator.formation else ""


class MappingType(bpy.types.PropertyGroup):
target = bpy.props.IntProperty()


class StoryboardEntry(PropertyGroup):
"""Blender property group representing a single entry in the storyboard
of the drone show.
"""

mapping = CollectionProperty(type=MappingType)

maybe_uuid_do_not_use = StringProperty(
name="Identifier",
description=(
Expand Down Expand Up @@ -201,6 +196,20 @@ class StoryboardEntry(PropertyGroup):
),
)

# mapping is stored as a string so we don't need to maintain a separate
# Blender collection as it would not be efficient

_mapping = StringProperty(
name="Mapping",
description=(
"Mapping where the i-th element is the index of the drone that "
"marker i was matched to in the storyboard entry, or -1 if the "
"marker is unmatched."
),
default="",
options={"HIDDEN"},
)

#: Sorting key for storyboard entries
sort_key = attrgetter("frame_start", "frame_end")

Expand Down Expand Up @@ -295,6 +304,21 @@ def get_enabled_schedule_override_map(self) -> Dict[int, ScheduleOverride]:

return result

def get_mapping(self) -> Optional[List[int]]:
"""Returns the mapping of the markers in the storyboard entry to drone
indices, or ``None`` if there is no mapping yet.
"""
encoded_mapping = self._mapping.strip()
if (
not encoded_mapping
or len(encoded_mapping) < 2
or encoded_mapping[0] != "["
or encoded_mapping[-1] != "]"
):
return None
else:
return json.loads(encoded_mapping)

def remove_active_schedule_override_entry(self) -> None:
"""Removes the active schedule override entry from the collection and
adjusts the active entry index as needed.
Expand All @@ -309,6 +333,20 @@ def remove_active_schedule_override_entry(self) -> None:
max(0, index), len(self.schedule_overrides)
)

def update_mapping(self, mapping: Optional[List[int]]) -> None:
"""Updates the mapping of the markers in the storyboard entry to drone
indices.
Arguments:
mapping: mapping where the i-th item contains the index of the drone
that the i-th marker was mapped to, or -1 if the marker is
unmapped. You can also pass ``None`` to clear the entire mapping.
"""
if mapping is None:
self._mapping = ""
else:
self._mapping = json.dumps(mapping)


class Storyboard(PropertyGroup, ListMixin):
"""Blender property group representing the entire storyboard of the
Expand Down Expand Up @@ -558,11 +596,11 @@ def get_mapping_at_frame(self, frame: int):
"""
index = self.get_index_of_entry_containing_frame(frame)
if index >= 0:
return self.entries[index].mapping
return self.entries[index].get_mapping()

index = self.get_index_of_entry_before_frame(frame)
if index >= 0:
return self.entries[index].mapping
return self.entries[index].get_mapping()

return None

Expand Down
22 changes: 13 additions & 9 deletions src/modules/sbstudio/plugin/operators/recalculate_transitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,15 +468,19 @@ def update_transition_for_storyboard_entry(
num_targets=num_markers,
)

# store mapping in Blender-compatible format for later use
entry.mapping.clear()
for i in range(len(mapping)):
try:
j = mapping.index(i)
entry.mapping.add()
entry.mapping[-1].target = j
except ValueError:
break
# Store mapping in Blender-compatible format for later use
#
# 'mapping' is a list where the i-th element contains the index of the
# target point that the i-th drone was matched to, or ``None`` if the drone
# was left unmatched; we need to invert that so we get a vector where the
# i-th element is the index of the drone that marker i was matched to or
# -1 if the marker is unmatched
inv_mapping: List[int] = []
for drone_index, marker_index in enumerate(inv_mapping):
if len(inv_mapping) <= marker_index:
inv_mapping.extend([-1] * (marker_index - len(inv_mapping) + 1))
inv_mapping[marker_index] = drone_index
entry.update_mapping(inv_mapping)

# Calculate how many drones will participate in the transition
num_drones_transitioning = sum(
Expand Down

0 comments on commit c1a521f

Please sign in to comment.