robust attribute copy for duplicate frames
parent
6dbf666ee3
commit
edfefa874a
163
utils.py
163
utils.py
|
@ -590,8 +590,9 @@ def copy_stroke_to_frame(s, frame, select=True):
|
|||
ns.points.update()
|
||||
return ns
|
||||
|
||||
def bulk_copy_attributes(source_attr, target_attr):
|
||||
# Get the data as flat numpy array based on attribute type and domain
|
||||
"""## Works, but do not copy all attributes type (probably ok for GP though)
|
||||
def bulk_frame_copy_attributes(source_attr, target_attr):
|
||||
'''Get and apply data as flat numpy array based on attribute type'''
|
||||
if source_attr.data_type == 'INT':
|
||||
data = np.empty(len(source_attr.data), dtype=np.int32)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
|
@ -617,62 +618,105 @@ def bulk_copy_attributes(source_attr, target_attr):
|
|||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
|
||||
## Filter by domain ? (not needed it seem, dtypes are the same)
|
||||
'''
|
||||
if source_attr.domain == 'POINT':
|
||||
if source_attr.data_type == 'FLOAT':
|
||||
data = np.empty(len(source_attr.data), dtype=np.float32)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'FLOAT_VECTOR':
|
||||
data = np.empty(len(source_attr.data) * 3, dtype=np.float32)
|
||||
source_attr.data.foreach_get('vector', data)
|
||||
target_attr.data.foreach_set('vector', data)
|
||||
elif source_attr.data_type == 'FLOAT_COLOR':
|
||||
data = np.empty(len(source_attr.data) * 4, dtype=np.float32)
|
||||
source_attr.data.foreach_get('color', data)
|
||||
target_attr.data.foreach_set('color', data)
|
||||
## No Boolean by defaut on points domain
|
||||
elif source_attr.domain == 'CURVE':
|
||||
if source_attr.data_type == 'INT':
|
||||
data = np.empty(len(source_attr.data), dtype=np.int32)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'INT8':
|
||||
data = np.empty(len(source_attr.data), dtype=np.int8)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
elif source_attr.data_type == 'FLOAT_COLOR':
|
||||
data = np.empty(len(source_attr.data) * 4, dtype=np.float32)
|
||||
source_attr.data.foreach_get('color', data)
|
||||
target_attr.data.foreach_set('color', data)
|
||||
elif source_attr.data_type == 'BOOLEAN':
|
||||
data = np.empty(len(source_attr.data), dtype=bool)
|
||||
source_attr.data.foreach_get('value', data)
|
||||
target_attr.data.foreach_set('value', data)
|
||||
'''
|
||||
## works in slowmotion (keep as reference for testing)
|
||||
# def copy_attribute_values(src_dr, dst_dr, source_attr, dest_attr, data_size):
|
||||
# ## Zip method to copy one by one
|
||||
# val_type = {'FLOAT_COLOR': 'color','FLOAT_VECTOR': 'vector'}.get(source_attr.data_type, 'value')
|
||||
# src_start = src_dr.curve_offsets[0].value
|
||||
# src_end = src_start + data_size
|
||||
# dst_start = dst_dr.curve_offsets[0].value
|
||||
# dst_end = dst_start + data_size
|
||||
# for src_idx, dest_idx in zip(range(src_start, src_end),range(dst_start, dst_end)):
|
||||
# setattr(dest_attr.data[dest_idx], val_type, getattr(source_attr.data[src_idx], val_type))
|
||||
"""
|
||||
|
||||
attribute_value_string = {
|
||||
'FLOAT': "value",
|
||||
'INT': "value",
|
||||
'FLOAT_VECTOR': "vector",
|
||||
'FLOAT_COLOR': "color",
|
||||
'BYTE_COLOR': "color",
|
||||
'STRING': "value",
|
||||
'BOOLEAN': "value",
|
||||
'FLOAT2': "value",
|
||||
'INT8': "value",
|
||||
'INT32_2D': "value",
|
||||
'QUATERNION': "value",
|
||||
'FLOAT4X4': "value",
|
||||
}
|
||||
|
||||
attribute_value_dtype = {
|
||||
'FLOAT': np.float32,
|
||||
'INT': np.dtype('int'),
|
||||
'FLOAT_VECTOR': np.float32,
|
||||
'FLOAT_COLOR': np.float32,
|
||||
'BYTE_COLOR': np.int8,
|
||||
'STRING': np.dtype('str'),
|
||||
'BOOLEAN': np.dtype('bool'),
|
||||
'FLOAT2': np.float32,
|
||||
'INT8': np.int8,
|
||||
'INT32_2D': np.dtype('int'),
|
||||
'QUATERNION': np.float32,
|
||||
'FLOAT4X4': np.float32,
|
||||
}
|
||||
|
||||
attribute_value_shape = {
|
||||
'FLOAT': (),
|
||||
'INT': (),
|
||||
'FLOAT_VECTOR': (3,),
|
||||
'FLOAT_COLOR': (4,),
|
||||
'BYTE_COLOR': (4,),
|
||||
'STRING': (),
|
||||
'BOOLEAN': (),
|
||||
'FLOAT2':(2,),
|
||||
'INT8': (),
|
||||
'INT32_2D': (2,),
|
||||
'QUATERNION': (4,),
|
||||
'FLOAT4X4': (4,4),
|
||||
}
|
||||
|
||||
|
||||
def copy_attribute_values(src_dr, dst_dr, source_attr, dest_attr):
|
||||
## Zip method to copy one by one
|
||||
## One liner
|
||||
# val_type = {'FLOAT_COLOR': 'color','FLOAT_VECTOR': 'vector'}.get(source_attr.data_type, 'value')
|
||||
if source_attr.data_type == 'FLOAT_COLOR':
|
||||
val_type = 'color'
|
||||
elif source_attr.data_type == 'FLOAT_VECTOR':
|
||||
val_type = 'vector'
|
||||
else:
|
||||
val_type = 'value'
|
||||
## /!\ DOESN'T WORK. index is wrong
|
||||
for src_idx, dest_idx in zip(
|
||||
range(src_dr.curve_offsets[0].value, src_dr.curve_offsets[-1].value),
|
||||
range(dst_dr.curve_offsets[0].value, dst_dr.curve_offsets[-1].value)):
|
||||
setattr(dest_attr.data[dest_idx], val_type, getattr(source_attr.data[src_idx], val_type))
|
||||
def bulk_copy_attributes(source_attr, target_attr):
|
||||
'''Get and apply data as flat numpy array based on attribute type'''
|
||||
value_string = attribute_value_string[source_attr.data_type]
|
||||
dtype = attribute_value_dtype[source_attr.data_type]
|
||||
shape = attribute_value_shape[source_attr.data_type]
|
||||
|
||||
domain_size = len(source_attr.data)
|
||||
## Need to pass attributes to get domain size
|
||||
# domain_size = attributes.domain_size(source_attr.domain)
|
||||
|
||||
# start = time()
|
||||
data = np.empty((domain_size, *shape), dtype=dtype).ravel()
|
||||
source_attr.data.foreach_get(value_string, data)
|
||||
target_attr.data.foreach_set(value_string, data)
|
||||
# end = time()
|
||||
# np_empty = end - start
|
||||
|
||||
## np.prod (works, supposedly faster but tested slower)
|
||||
# data = np.empty(int(domain_size * np.prod(shape)), dtype=dtype)
|
||||
# source_attr.data.foreach_get(value_string, data)
|
||||
# target_attr.data.foreach_set(value_string, data)
|
||||
|
||||
|
||||
## np.zeros (works, sometimes faster on big set of attributes)
|
||||
# start = time()
|
||||
# data = np.zeros((domain_size, *shape), dtype=dtype)
|
||||
# source_attr.data.foreach_get(value_string, np.ravel(data))
|
||||
# target_attr.data.foreach_set(value_string, np.ravel(data))
|
||||
# end = time()
|
||||
# np_zero = end - start
|
||||
|
||||
# print('np EMPTY faster' if np_empty < np_zero else 'np ZERO faster', source_attr.domain, source_attr.data_type, domain_size)
|
||||
# print('np_zero', np_zero)
|
||||
# print('np_empty', np_empty)
|
||||
# print()
|
||||
|
||||
def copy_frame_at(source_frame, layer, frame_number):
|
||||
'''Copy a frame (source_frame) to a layer at given frame_number'''
|
||||
source_drawing = source_frame.drawing
|
||||
|
||||
# frame_copy_start = time() # time_dbg
|
||||
frame = layer.frames.new(frame_number)
|
||||
dr = frame.drawing
|
||||
dr.add_strokes([len(s.points) for s in source_drawing.strokes])
|
||||
|
@ -682,13 +726,18 @@ def copy_frame_at(source_frame, layer, frame_number):
|
|||
dr.attributes.new(
|
||||
name=attr_name, type=source_attr.data_type, domain=source_attr.domain)
|
||||
target_attr = dr.attributes[attr_name]
|
||||
bulk_copy_attributes(source_attr, target_attr)
|
||||
|
||||
## Broken
|
||||
# start_time = time()
|
||||
# copy_attribute_values(source_drawing, dr, source_attr, target_attr)
|
||||
# end_time = time()
|
||||
# print(f"copy_attribute_values execution time: {end_time - start_time} seconds")
|
||||
# start_time = time() # time_dbg-per-attrib
|
||||
|
||||
# bulk_frame_copy_attributes(source_attr, target_attr) # only some attributes
|
||||
bulk_copy_attributes(source_attr, target_attr)
|
||||
# copy_attribute_values(source_drawing, dr, source_attr, target_attr, source_drawing.attributes.domain_size(source_attr.domain)) # super slow
|
||||
|
||||
# end_time = time() # time_dbg-per-attrib
|
||||
# print(f"copy_attribute '{attr_name}' execution time: {end_time - start_time} seconds") # time_dbg-per-attrib
|
||||
|
||||
# frame_copy_end = time() # time_dbg
|
||||
# print(f"frame copy execution time: {frame_copy_end - frame_copy_start} seconds") # time_dbg
|
||||
|
||||
# -----------------
|
||||
### Vector utils 3d
|
||||
|
|
Loading…
Reference in New Issue