mirror of
https://github.com/CopterExpress/clever-show.git
synced 2026-05-26 15:13:26 +00:00
Addon: property and land\takeoff detection
This commit is contained in:
@@ -50,19 +50,19 @@ class CleverShowProperties(PropertyGroup):
|
||||
options=set(), # not animateable
|
||||
)
|
||||
|
||||
# takeoff_frames: IntProperty(
|
||||
# name="Takeoff duration",
|
||||
# description="Duration of takeoff in frames",
|
||||
# default=70,
|
||||
# min=1,
|
||||
# )
|
||||
#
|
||||
# land_frames: IntProperty(
|
||||
# name="Land duration",
|
||||
# description="Duration of landing in frames",
|
||||
# default=100,
|
||||
# min=1,
|
||||
# )
|
||||
takeoff_frames: IntProperty(
|
||||
name="Takeoff duration",
|
||||
description="Duration of takeoff in frames",
|
||||
default=70,
|
||||
min=1,
|
||||
)
|
||||
|
||||
land_frames: IntProperty(
|
||||
name="Land duration",
|
||||
description="Duration of landing in frames",
|
||||
default=100,
|
||||
min=1,
|
||||
)
|
||||
|
||||
filter_obj: EnumProperty(
|
||||
name="Filter objects:",
|
||||
|
||||
@@ -16,8 +16,19 @@ def create_dir(folder_path):
|
||||
os.mkdir(folder_path)
|
||||
|
||||
|
||||
def iter_pairs(obj):
|
||||
return zip(obj[::2], obj[1::2])
|
||||
# def iter_pairs(obj):
|
||||
# return zip(obj[::2], obj[1::2])
|
||||
|
||||
def neighbour_pairs(sequence):
|
||||
iterable = iter(sequence)
|
||||
try:
|
||||
prev = next(iterable)
|
||||
except StopIteration:
|
||||
return ()
|
||||
for item in iterable:
|
||||
yield prev, item
|
||||
prev = item
|
||||
|
||||
|
||||
|
||||
def get_rgb(drone_obj):
|
||||
@@ -79,6 +90,7 @@ class ExportSwarmAnimation(Operator, ExportHelper):
|
||||
pass
|
||||
|
||||
def _generate_animation(self, drone_obj, context):
|
||||
# todo yield?
|
||||
animation = list()
|
||||
|
||||
scene = context.scene
|
||||
@@ -88,14 +100,13 @@ class ExportSwarmAnimation(Operator, ExportHelper):
|
||||
frame_end = context.scene.frame_end
|
||||
# Add frame with animation parameters
|
||||
scene.frame_set(frame_start)
|
||||
# animation.append({"set_fps": context.scene.render.fps,
|
||||
# "drone_name": drone_obj.name,
|
||||
# })
|
||||
|
||||
if clever_show.add_takeoff:
|
||||
animation.append({"takeoff": {}})
|
||||
animation.append({"set_fps": context.scene.render.fps,
|
||||
"drone_name": drone_obj.name,
|
||||
})
|
||||
|
||||
# Add flight and
|
||||
# Add flight
|
||||
previous_frame = dict()
|
||||
for frame_num in range(frame_start, frame_end + 1):
|
||||
scene.frame_set(frame_start)
|
||||
position = [round(x, 3) for x in drone_obj.matrix_world.to_translation()]
|
||||
@@ -103,11 +114,14 @@ class ExportSwarmAnimation(Operator, ExportHelper):
|
||||
frame = dict()
|
||||
|
||||
# check to not update position or yaw if they are same as previous frame
|
||||
if animation[-1]["fly"] != position:
|
||||
if previous_frame.get("fly", None) != position:
|
||||
frame.update({"fly": position})
|
||||
if animation[-1]["yaw"] != yaw:
|
||||
if previous_frame.get("yaw", None) != yaw:
|
||||
frame.update({"yaw": yaw})
|
||||
|
||||
if clever_show.use_armed and previous_frame.get("armed") != drone_obj.armed:
|
||||
frame.update({"armed": drone_obj.armed})
|
||||
|
||||
try:
|
||||
led_color = get_rgb(drone_obj) # TODO!!!!!!
|
||||
frame.update({"led_color": led_color})
|
||||
@@ -115,6 +129,10 @@ class ExportSwarmAnimation(Operator, ExportHelper):
|
||||
pass
|
||||
|
||||
animation.append(frame)
|
||||
previous_frame = frame
|
||||
|
||||
if clever_show.add_takeoff:
|
||||
animation.insert(0, {"takeoff": {}})
|
||||
|
||||
if clever_show.add_land:
|
||||
animation.append({"land": {}})
|
||||
@@ -124,28 +142,36 @@ class ExportSwarmAnimation(Operator, ExportHelper):
|
||||
|
||||
return animation
|
||||
|
||||
def _detect_armed_states(self, drone_obj, animation, context):
|
||||
@staticmethod
|
||||
def find_intervals(values):
|
||||
j = None
|
||||
vals = itertools.chain((-1, ), values) # to ensure detection from first element
|
||||
for i, items in enumerate(neighbour_pairs(vals)):
|
||||
item1, item2 = items
|
||||
if item2 > item1:
|
||||
j = i
|
||||
elif j is not None and item2 < item1:
|
||||
yield (j, i) # j+1, i+1
|
||||
j = None
|
||||
|
||||
if j is not None:
|
||||
yield (j, j) # j+1, j+1
|
||||
|
||||
@staticmethod
|
||||
def pop_func(animation, func):
|
||||
state = False
|
||||
for frame in animation:
|
||||
current = frame.pop(func, None)
|
||||
state = current if current is not None else state
|
||||
yield state
|
||||
|
||||
@classmethod
|
||||
def _detect_states(cls, drone_obj, animation, context):
|
||||
# clever_show = context.scene.clever_show
|
||||
intervals = cls.find_intervals(cls.pop_func(animation, "armed"))
|
||||
|
||||
tracks = drone_obj.animation_data
|
||||
if not tracks:
|
||||
return animation
|
||||
|
||||
fcurve = next((fcurve for fcurve in tracks if fcurve.data_path == "drone.armed"), None)
|
||||
if fcurve is None:
|
||||
return animation
|
||||
|
||||
keyframes = fcurve.keyframe_points
|
||||
if len(keyframes) % 2 != 0:
|
||||
raise RuntimeError("Incorrect armed state keyframes!")
|
||||
|
||||
for frame1, frame2 in iter_pairs(keyframes):
|
||||
if frame1 == frame2: # equal: wrong order
|
||||
raise RuntimeError("Incorrect armed state keyframes!")
|
||||
|
||||
start_frame = frame1.co[0]
|
||||
duration = frame2.co[0] - start_frame
|
||||
# todo height?
|
||||
for start, end in intervals:
|
||||
# duration = max(end-start, 1)
|
||||
|
||||
if frame1 < frame2: # not armed -> armed: takeoff
|
||||
func = "takeoff"
|
||||
@@ -154,30 +180,47 @@ class ExportSwarmAnimation(Operator, ExportHelper):
|
||||
|
||||
animation[start_frame].update({func: {"duration": duration}})
|
||||
|
||||
@classmethod
|
||||
def _detect_armed_states(cls, animation):
|
||||
for i, items in enumerate(neighbour_pairs(vals)):
|
||||
item1, item2 = items
|
||||
if item2 > item1:
|
||||
j = i
|
||||
elif j is not None and item2 < item1:
|
||||
yield (j, i) # j+1, i+1
|
||||
j = None
|
||||
|
||||
|
||||
return animation
|
||||
|
||||
def _detect_animation_takeoff_land(self, drone_obj, animation, context):
|
||||
takeoff = False
|
||||
land = False
|
||||
floor_level = 0
|
||||
start_frame = 0
|
||||
for i, frames in enumerate(neighbour_pairs(animation)):
|
||||
frame1, frame2 = frames
|
||||
if frame1 == floor_level and frame2 > frame1: # takeoff start
|
||||
pass
|
||||
elif frame2 == floor_level and frame1 > frame2: # land start
|
||||
pass
|
||||
|
||||
# previous_z = 0
|
||||
def find(animation):
|
||||
|
||||
def get_z(index, default=float('nan')):
|
||||
return animation[index].get("fly", None)[2] or default
|
||||
|
||||
i = 0
|
||||
previous_z = animation[i]["fly"][2] # height of the first frame
|
||||
previous_z = get_z(i) # height of the first frame
|
||||
while i < len(animation):
|
||||
z = animation[i]["fly"][2]
|
||||
|
||||
|
||||
|
||||
|
||||
for frame in animation:
|
||||
z = frame["fly"][2]
|
||||
if previous_z == 0 and z > previous_z:
|
||||
takeoff = True
|
||||
#if p
|
||||
|
||||
current_z = get_z(i, previous_z)
|
||||
|
||||
if previous_z == 0:
|
||||
while current_z > previous_z:
|
||||
i += 1
|
||||
previous_z = current_z
|
||||
current_z = get_z(i, previous_z)
|
||||
|
||||
i += 1
|
||||
previous_z = current_z
|
||||
|
||||
def _process_animation(self, animation, context): #delete unnececary flight functions while copter landed
|
||||
# clever_show = context.scene.clever_show
|
||||
|
||||
@@ -27,10 +27,7 @@ class ExportCsv(Operator, ExportHelper):
|
||||
filename_ext = ''
|
||||
use_filter_folder = True
|
||||
|
||||
use_namefilter: bpy.props.BoolProperty(
|
||||
name="Use name filter for objects",
|
||||
default=False,
|
||||
)
|
||||
use_namefilter: bpy.props.BoolProperty(name="Use name filter for objects", default=False)
|
||||
|
||||
drones_name: bpy.props.StringProperty(
|
||||
name="Name identifier",
|
||||
@@ -38,10 +35,7 @@ class ExportCsv(Operator, ExportHelper):
|
||||
default="clever"
|
||||
)
|
||||
|
||||
show_warnings: bpy.props.BoolProperty(
|
||||
name="Show detailed animation warnings",
|
||||
default=False,
|
||||
)
|
||||
show_warnings: bpy.props.BoolProperty(name="Show detailed animation warnings", default=False)
|
||||
|
||||
speed_warning_limit: bpy.props.FloatProperty(
|
||||
name="Speed limit",
|
||||
|
||||
Reference in New Issue
Block a user