def animate_radial_composite(radial_composite, window): """ Animates the radial composite and updates the window of frame if radial composite's parameters are already animated Also generate the Lottie path and stores in radial_composite Args: radial_composite (lxml.etree._Element) : Synfig format radial composite-> stores radius and angle window (dict) : max and min frame of overall animations stored in this Returns: (None) """ for child in radial_composite: if child.tag == "radius": radius = child elif child.tag == "theta": theta = child update_frame_window(radius[0], window) update_frame_window(theta[0], window) radius = gen_dummy_waypoint(radius, "radius", "real") theta = gen_dummy_waypoint(theta, "theta", "region_angle") # Update the newly computed radius and theta update_child_at_parent(radial_composite, radius, "radius") update_child_at_parent(radial_composite, theta, "theta") append_path(radius[0], radial_composite, "radius_path") append_path(theta[0], radial_composite, "theta_path")
def gen_time_remap(lottie, time_offset, time_dilation, idx): """ Time offset will be converted to time remap here Currently time remapping will be done for each frame, but this function can be intelligently written only for some particular frames,hence reducing the space Args: lottie (dict) : Time remapping in Lottie format time_offset (lxml.etree._Element) : Offset for time in Synfig format time_dilation (lxml.etree._Element) : Speed/dilation for time in Synfig format idx (itr) : Index of this property in the layer Returns: (None) """ offset_dict = {} time_offset = gen_dummy_waypoint(time_offset, "param", "time") gen_value_Keyframed(offset_dict, time_offset[0], 0) dilation_dict = {} time_dilation = gen_dummy_waypoint(time_dilation, "param", "real") gen_value_Keyframed(dilation_dict, time_dilation[0], 0) fr, lst = settings.lottie_format["ip"], settings.lottie_format["op"] lottie["a"] = 1 # Animated lottie["ix"] = idx lottie["k"] = [] while fr <= lst: lottie["k"].append({}) gen_dict(lottie["k"][-1], offset_dict, dilation_dict, fr) fr += 1
def gen_layer_rotate(lottie, layer): """ Help generate transform properties of a rotate layer Args: lottie (dict) : Will store the transform properties in lottie format layer (lxml.etree._Element) : Tranform properties in Synfig format Returns: (None) """ scale = settings.DEFAULT_SCALE for child in layer: if child.tag == "param": if child.attrib["name"] == "origin": anchor = gen_dummy_waypoint(child, "param", "vector") pos = anchor elif child.attrib["name"] == "amount": # This is rotation rotation = gen_dummy_waypoint(child, "param", "rotate_layer_angle") #print_animation(anchor, pos, rotation) anchor = copy.deepcopy(anchor) group.update_pos(anchor) if settings.INSIDE_PRECOMP: group.update_pos(pos) gen_helpers_transform(lottie, layer, pos[0], anchor[0], scale, rotation[0])
def gen_layer_translate(lottie, layer): """ Help generate transform properties of translate layer Args: lottie (dict) : Transform properties in lottie format layer (lxml.etree._Element) : Transform properties in Synfig format Returns: (None) """ for child in layer: if child.tag == "param": if child.attrib["name"] == "origin": anchor = gen_dummy_waypoint(child, "param", "vector") pos = anchor anchor = copy.deepcopy(anchor) for waypoint in anchor[0]: waypoint[0][0].text = str(0) waypoint[0][1].text = str(0) group.update_pos(anchor) if settings.INSIDE_PRECOMP: group.update_pos(pos) gen_helpers_transform(lottie, layer, pos[0], anchor[0])
def change_opacity_switch(layer, lottie): """ Will make the opacity of underlying layers 0 according to the active layer Args: layer (lxml.etree._Element) : Synfig format layer lottie (dict) : Lottie format layer Returns: (None) """ for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "layer_name": layer_name = chld elif chld.attrib["name"] == "canvas": canvas = chld layer_name = gen_dummy_waypoint(layer_name, "param", "string", "layer_name") for assets in settings.lottie_format["assets"]: if assets["id"] == lottie["refId"]: root = assets break it = 0 for c_layer in reversed(canvas[0]): active_time = set() description = root["layers"][it]["nm"] waypoint_itr = 0 while waypoint_itr < len(layer_name[0]): waypoint = layer_name[0][waypoint_itr] l_name = waypoint[0].text if (l_name == description) or (l_name is None and it == 0): update_time(active_time, layer_name[0], waypoint_itr) waypoint_itr += 1 active_time = sorted(active_time) deactive_time = sorted(flip_time(active_time)) if c_layer.attrib["type"] in set.union(settings.SHAPE_SOLID_LAYER, settings.SOLID_LAYER): anim_type = "effects_opacity" dic = root["layers"][it]["ef"][0]["ef"][-1]["v"] elif c_layer.attrib["type"] in set.union(settings.PRE_COMP_LAYER, settings.GROUP_LAYER, settings.IMAGE_LAYER): anim_type = "opacity" dic = root["layers"][it]["ks"]["o"] elif c_layer.attrib["type"] in settings.SHAPE_LAYER: anim_type = "opacity" dic = root["layers"][it]["shapes"][1]["o"] animation = gen_hold_waypoints(deactive_time, c_layer, anim_type) gen_value_Keyframed(dic, animation[0], 0) it += 1
def gen_layer_scale(lottie, layer): """ Help generate transform properties of a scale layer Args: lottie (dict) : Store transform properties in lottie format layer (lxml.etree._Element) Transform properties in Synfig format Returns: (None) """ for child in layer: if child.tag == "param": if child.attrib["name"] == "center": anchor = gen_dummy_waypoint(child, "param", "vector") pos = anchor elif child.attrib["name"] == "amount": # This is scale scale = gen_dummy_waypoint(child, "param", "scale_layer_zoom") anchor = copy.deepcopy(anchor) group.update_pos(anchor) if settings.INSIDE_PRECOMP: group.update_pos(pos) gen_helpers_transform(lottie, layer, pos[0], anchor[0], scale[0])
def gen_hold_waypoints(deactive_time, layer, anim_type): """ Will only be used to modify opacity waypoints, and set zero values where the layer is deactive Args: deactive_time (set) : Range of time when the layer will be deactive layer (lxml.etree._Element) : Synfig format layer anim_type (str) : Specifies whether it is effects_opacity or opacity (it will effect a factor of 100) Returns: (lxml.etree._Element) : Modified opacity animation is returned """ for chld in layer: if chld.tag == "param" and chld.attrib["name"] == "amount": opacity = chld opacity = gen_dummy_waypoint(opacity, "param", anim_type, "amount") opacity_dict = {} gen_value_Keyframed(opacity_dict, opacity[0], 0) for it in deactive_time: # First add waypoints at both points, make it constant interval # then remove any in-between waypoints first = round(it[0] * settings.lottie_format["fr"]) second = round(it[1] * settings.lottie_format["fr"]) insert_waypoint_at_frame(opacity[0], opacity_dict, first, anim_type) insert_waypoint_at_frame(opacity[0], opacity_dict, second, anim_type) # Making it a constant interval for waypoint in opacity[0]: if approximate_equal(get_frame(waypoint), first): st_waypoint = waypoint break st_waypoint.attrib["after"] = "constant" st_waypoint[0].attrib["value"] = str(0) # removing the in between waypoints for waypoint in opacity[0]: this_frame = get_frame(waypoint) if (not approximate_equal(this_frame, first)) and \ (not approximate_equal(this_frame, second)) and \ (this_frame > first and this_frame < second): waypoint.getparent().remove(waypoint) return opacity
def gen_layer_group(lottie, layer, idx): """ Will generate a pre composition but has small differences than pre-comp layer used in layers/preComp.py This function will be used for group layer as well as switch group layer Args: lottie (dict) : Lottie format layer will be stored here layer (lxml.etree._Element) : Synfig format group/switch layer idx (int) : Index of the layer Returns: (None) """ lottie["ddd"] = settings.DEFAULT_3D lottie["ind"] = idx lottie["ty"] = settings.LAYER_PRECOMP_TYPE lottie["sr"] = settings.LAYER_DEFAULT_STRETCH lottie["ks"] = {} # Transform properties to be filled set_layer_desc(layer, settings.LAYER_PRECOMP_NAME + str(idx), lottie) index = Count() for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "canvas": canvas = chld elif chld.attrib["name"] == "transformation": transform = chld[0] for child in transform: if child.tag == "scale": scale = child elif child.tag == "offset": pos = child elif child.tag == "angle": angle = child elif chld.attrib["name"] == "origin": origin = chld elif chld.attrib["name"] == "amount": opacity = chld elif chld.attrib["name"] == "outline_grow": outline_grow = chld elif chld.attrib["name"] == "time_offset": time_offset = chld elif chld.attrib["name"] == "time_dilation": time_dilation = chld outline_grow = gen_dummy_waypoint(outline_grow, "param", "real") append_path(outline_grow[0], outline_grow, "outline_grow_path") origin = gen_dummy_waypoint(origin, "param", "vector") anchor = origin group.update_pos(anchor) angle = gen_dummy_waypoint(angle, "angle", "rotate_layer_angle") pos = gen_dummy_waypoint(pos, "offset", "vector") if settings.INSIDE_PRECOMP: group.update_pos(pos) scale = gen_dummy_waypoint(scale, "scale", "group_layer_scale") # Generate the transform properties here gen_helpers_transform(lottie["ks"], layer, pos[0], anchor[0], scale[0], angle[0], opacity[0]) # Store previous states, to be recovered at the end of group layer prev_state = settings.INSIDE_PRECOMP settings.OUTLINE_GROW.append(outline_grow) settings.INSIDE_PRECOMP = True settings.lottie_format["assets"].append({}) asset = add_precomp_asset(settings.lottie_format["assets"][-1], canvas[0], len(canvas[0])) lottie["refId"] = asset lottie["w"] = settings.lottie_format[ "w"] + settings.ADDITIONAL_PRECOMP_WIDTH # Experimental increase in width and height of precomposition lottie[ "h"] = settings.lottie_format["h"] + settings.ADDITIONAL_PRECOMP_HEIGHT lottie["ao"] = settings.LAYER_DEFAULT_AUTO_ORIENT lottie["ip"] = settings.lottie_format["ip"] lottie["op"] = settings.lottie_format["op"] lottie["st"] = 0 # Don't know yet get_blend(lottie, layer) # Time offset and speed lottie["tm"] = {} gen_time_remap(lottie["tm"], time_offset, time_dilation, index.inc()) # Change opacity of layers for switch-group layers if layer.attrib["type"] == "switch": change_opacity_switch(layer, lottie) # Change opacity of layers for group layers elif layer.attrib["type"] == "group": change_opacity_group(layer, lottie) # Return to previous state, when we go outside the group layer settings.INSIDE_PRECOMP = prev_state settings.OUTLINE_GROW.pop()
def change_opacity_group(layer, lottie): """ Will make the opacity of underlying layers 0 according to the layers lying inside z range(if it is active)[z-range is non-animatable] Args: layer (lxml.etree._Element) : Synfig format layer lottie (dict) : Lottie format layer Returns: (None) """ for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "z_range": z_range = chld elif chld.attrib["name"] == "z_range_position": z_range_pos = chld elif chld.attrib["name"] == "z_range_depth": z_range_depth = chld elif chld.attrib["name"] == "canvas": canvas = chld for assets in settings.lottie_format["assets"]: if assets["id"] == lottie["refId"]: root = assets break # If z-range is non-active (static value) if z_range[0].attrib["value"] == "false": return pos = gen_dummy_waypoint(z_range_pos, "param", "real", "z_range_position") depth = gen_dummy_waypoint(z_range_depth, "param", "real", "z_range_depth") pos_dict, depth_dict = {}, {} gen_value_Keyframed(pos_dict, pos[0], 0) gen_value_Keyframed(depth_dict, depth[0], 0) z_st, z_en = float('-inf'), float('-inf') active_range = [] # Stores the time and change of layers in z-range fr = settings.lottie_format["ip"] while fr <= settings.lottie_format["op"]: pos_val = to_Synfig_axis(get_vector_at_frame(pos_dict, fr), "real") depth_val = to_Synfig_axis(get_vector_at_frame(depth_dict, fr), "real") st, en = math.ceil(pos_val), math.floor(pos_val + depth_val) if st > en or en < 0: if (fr == settings.lottie_format["ip"]) or (z_st != -1 and z_en != -1): z_st, z_en = -1, -1 active_range.append([fr, z_st, z_en]) elif (st != z_st) or (en != z_en): z_st, z_en = st, en active_range.append([fr, z_st, z_en]) fr += 1 z_value = 0 for c_layer in reversed(canvas[0]): active_time = set() itr = 0 while itr < len(active_range): st, en = active_range[itr][1], active_range[itr][2] if z_value <= en and z_value >= st: now = active_range[itr][0] / settings.lottie_format["fr"] later = get_time_bound("op") if itr + 1 < len(active_range): later = active_range[itr + 1][0] / settings.lottie_format["fr"] active_time.add((now, later)) itr += 1 active_time = sorted(active_time) deactive_time = sorted(flip_time(active_time)) if c_layer.attrib["type"] in set.union(settings.SHAPE_SOLID_LAYER, settings.SOLID_LAYER): anim_type = "effects_opacity" dic = root["layers"][z_value]["ef"][0]["ef"][-1]["v"] elif c_layer.attrib["type"] in set.union(settings.PRE_COMP_LAYER, settings.GROUP_LAYER, settings.IMAGE_LAYER): anim_type = "opacity" dic = root["layers"][z_value]["ks"]["o"] elif c_layer.attrib["type"] in settings.SHAPE_LAYER: anim_type = "opacity" dic = root["layers"][z_value]["shapes"][1]["o"] animation = gen_hold_waypoints(deactive_time, c_layer, anim_type) gen_value_Keyframed(dic, animation[0], 0) z_value += 1
def gen_shapes_rectangle(lottie, layer, idx): """ Generates the dictionary corresponding to shapes/rect.json Args: lottie (dict) : The lottie generated rectangle layer will be stored in it layer (lxml.etree._Element): Synfig format rectangle layer idx (int) : Stores the index of the rectangle layer Returns: (None) """ index = Count() lottie["ty"] = "rc" # Type: rectangle lottie["p"] = {} # Position of rectangle lottie["d"] = settings.DEFAULT_DIRECTION lottie["s"] = {} # Size of rectangle lottie["ix"] = idx # setting the index lottie["r"] = {} # Rounded corners of rectangle points = {} bevel_found = False expand_found = False # For filled rectangle layers for child in layer: if child.tag == "param": if child.attrib["name"] == "point1": points["1"] = child # Store address of child here elif child.attrib["name"] == "point2": points["2"] = child # Store address of child here elif child.attrib["name"] == "expand": expand_found = True param_expand = child elif child.attrib["name"] == "bevel": bevel_found = True is_animate = is_animated(child[0]) if is_animate == 2: gen_value_Keyframed(lottie["r"], child[0], index.inc()) else: bevel = get_child_value(is_animate, child, "value") bevel *= settings.PIX_PER_UNIT gen_properties_value(lottie["r"], bevel, index.inc(), settings.DEFAULT_ANIMATED, settings.NO_INFO) if not bevel_found: # For rectangle layer in stable version 1.2.2 bevel = 0 gen_properties_value(lottie["r"], bevel, index.inc(), settings.DEFAULT_ANIMATED, settings.NO_INFO) if not expand_found: # Means filled rectangle layer, gen expand param st = "<param name='expand'><real value='0.0'/></param>" param_expand = etree.fromstring(st) # If expand parameter is not animated param_expand = gen_dummy_waypoint(param_expand, "param", "real") # expand parameter needs to be positive: required by Synfig make_positive_valued(param_expand) # If p1 not animated points["1"] = gen_dummy_waypoint(points["1"], "param", "vector") # If p2 not animated points["2"] = gen_dummy_waypoint(points["2"], "param", "vector") both_points_animated(points["1"], points["2"], param_expand, lottie, index)
def gen_dynamic_list_polygon(lottie, dynamic_list): """ Generates the bline corresponding to polygon layer Args: lottie (dict) : Lottie format polygon layer will be stored here dynamic_list (lxml.etree._Element) : Synfig format points of polygon Returns: (None) """ ################## SECTION 1 ################ # Inserting the waypoints if not animated, finding the first and last frame # Calculating the path after this window = {} window["first"] = sys.maxsize window["last"] = -1 count = 0 for entry in dynamic_list: pos = entry update_frame_window(pos[0], window) new_pos = gen_dummy_waypoint(pos, "entry", "vector") pos.getparent().remove(pos) dynamic_list.insert(count, new_pos) append_path(new_pos[0], dynamic_list[count], "pos_path", "vector") count += 1 layer = dynamic_list.getparent().getparent() for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "origin": origin = chld # Animating the origin update_frame_window(origin[0], window) origin_parent = origin.getparent() origin = gen_dummy_waypoint(origin, "param", "vector", "origin") update_child_at_parent(origin_parent, origin, "param", "origin") # Generate path for the origin component origin_dict = {} origin[0].attrib["transform_axis"] = "true" gen_properties_multi_dimensional_keyframed(origin_dict, origin[0], 0) if window["first"] == sys.maxsize and window["last"] == -1: window["first"] = window["last"] = 0 ################ END OF SECTION 1 ############## ################ SECTION 2 ##################### # Generating values for all the frames in the window fr = window["first"] while fr <= window["last"]: st_val, en_val = insert_dict_at(lottie, -1, fr, False) for entry in dynamic_list: # Only two childs, one should be animated, other one is path for child in entry: if child.tag == "pos_path": dictionary = ast.literal_eval(child.text) pos_cur = get_vector_at_frame(dictionary, fr) pos_next = get_vector_at_frame(dictionary, fr + 1) tangent1_cur, tangent2_cur = Vector(0, 0), Vector(0, 0) tangent1_next, tangent2_next = Vector(0, 0), Vector(0, 0) # Adding origin to each vertex origin_cur = get_vector_at_frame(origin_dict, fr) origin_next = get_vector_at_frame(origin_dict, fr + 1) for i in range(len(pos_cur)): pos_cur[i] += origin_cur[i] for i in range(len(pos_next)): pos_next[i] += origin_next[i] # Store values in dictionary st_val["i"].append(tangent1_cur.get_list()) st_val["o"].append(tangent2_cur.get_list()) st_val["v"].append(pos_cur) en_val["i"].append(tangent1_next.get_list()) en_val["o"].append(tangent2_next.get_list()) en_val["v"].append(pos_next) fr += 1 # Setting the final time lottie.append({}) lottie[-1]["t"] = fr
def gen_bline_outline(lottie, bline_point): """ Generates the bline corresponding to outline layer by adding some vertices to bline and converting it to region layer Some parts are common with gen_bline_shapePropKeyframe(), which will be placed in a common function latter Args: lottie (dict) : Lottie format outline layer will be stored in this bline_point (lxml.etree._Element) : Synfig format bline points Returns: (None) """ ################### SECTION 1 ######################### # Inserting waypoints if not animated and finding the first and last frame # AFter that, there path will be calculated in lottie format which can # latter be used in get_vector_at_frame() function window = {} window["first"] = sys.maxsize window["last"] = -1 for entry in bline_point: composite = entry[0] for child in composite: if child.tag == "point": pos = child elif child.tag == "width": width = child elif child.tag == "t1": t1 = child elif child.tag == "t2": t2 = child elif child.tag == "split_radius": split_r = child elif child.tag == "split_angle": split_a = child # Necassary to update this before inserting new waypoints, as new # waypoints might include there on time: 0 seconds update_frame_window(pos[0], window) # Empty the pos and fill in the new animated pos pos = gen_dummy_waypoint(pos, "point", "vector") update_child_at_parent(composite, pos, "point") # Empty the width and fill in the new animated width update_frame_window(width[0], window) width = gen_dummy_waypoint(width, "width", "real") update_child_at_parent(composite, width, "width") update_frame_window(split_r[0], window) split_r = gen_dummy_waypoint(split_r, "split_radius", "bool") update_child_at_parent(composite, split_r, "split_radius") update_frame_window(split_a[0], window) split_a = gen_dummy_waypoint(split_a, "split_angle", "bool") update_child_at_parent(composite, split_a, "split_angle") append_path(pos[0], composite, "point_path", "vector") append_path(width[0], composite, "width_path") animate_radial_composite(t1[0], window) animate_radial_composite(t2[0], window) layer = bline_point.getparent().getparent() for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "width": outer_width = chld elif chld.attrib["name"] == "sharp_cusps": sharp_cusps = chld elif chld.attrib["name"] == "expand": expand = chld elif chld.attrib["name"] == "round_tip[0]": r_tip0 = chld elif chld.attrib["name"] == "round_tip[1]": r_tip1 = chld elif chld.attrib["name"] == "homogeneous_width": homo_width = chld elif chld.attrib["name"] == "origin": origin = chld # Animating the origin update_frame_window(origin[0], window) origin_parent = origin.getparent() origin = gen_dummy_waypoint(origin, "param", "vector", "origin") update_child_at_parent(origin_parent, origin, "param", "origin") # Generate path for the origin component origin_dict = {} origin[0].attrib["transform_axis"] = "true" gen_properties_multi_dimensional_keyframed(origin_dict, origin[0], 0) update_frame_window(outer_width[0], window) outer_width = gen_dummy_waypoint(outer_width, "param", "real", "width") # Update the layer with this animated outline width update_child_at_parent(layer, outer_width, "param", "width") # Generate outline width for Lottie format # No need to store this dictionary in lxml element, as it will be used in this function and will not be rewritten outer_width_dict = {} gen_value_Keyframed(outer_width_dict, outer_width[0], 0) # Animating the sharp_cusps update_frame_window(sharp_cusps[0], window) sharp_cusps = gen_dummy_waypoint(sharp_cusps, "param", "bool", "sharp_cusps") # Update the layer with this animated outline sharp cusps update_child_at_parent(layer, sharp_cusps, "param", "sharp_cusps") update_frame_window(expand[0], window) expand = gen_dummy_waypoint(expand, "param", "real", "expand") update_child_at_parent(layer, expand, "param", "expand") expand_dict = {} gen_value_Keyframed(expand_dict, expand[0], 0) update_frame_window(r_tip0[0], window) r_tip0 = gen_dummy_waypoint(r_tip0, "param", "bool", "round_tip[0]") update_child_at_parent(layer, r_tip0, "param", "round_tip[0]") update_frame_window(r_tip1[0], window) r_tip1 = gen_dummy_waypoint(r_tip1, "param", "bool", "round_tip[1]") update_child_at_parent(layer, r_tip1, "param", "round_tip[1]") update_frame_window(homo_width[0], window) homo_width = gen_dummy_waypoint(homo_width, "param", "bool", "homogeneous_width") update_child_at_parent(layer, homo_width, "param", "homogeneous_width") # Minimizing the window size if window["first"] == sys.maxsize and window["last"] == -1: window["first"] = window["last"] = 0 ################# END OF SECTION 1 ################### ################ SECTION 2 ########################### # Generating values for all the frames in the window fr = window["first"] while fr <= window["last"]: st_val, en_val = insert_dict_at( lottie, -1, fr, False) # This loop needs to be considered somewhere down synfig_outline(bline_point, st_val, origin_dict, outer_width_dict, sharp_cusps, expand_dict, r_tip0, r_tip1, homo_width, fr) synfig_outline(bline_point, en_val, origin_dict, outer_width_dict, sharp_cusps, expand_dict, r_tip0, r_tip1, homo_width, fr + 1) fr += 1 # Setting the final time lottie.append({}) lottie[-1]["t"] = fr
def gen_bline_region(lottie, bline_point): """ Generates the dictionary corresponding to properties/shapePropKeyframe.json, given a bline/spline Args: lottie (dict) : Lottie generated keyframes will be stored here for shape/path bline_path (lxml.etree._Element) : shape/path store in Synfig format Returns: (None) """ ################### SECTION 1 ######################### # Inserting waypoints if not animated and finding the first and last frame # AFter that, there path will be calculated in lottie format which can # latter be used in get_vector_at_frame() function window = {} window["first"] = sys.maxsize window["last"] = -1 loop = False if "loop" in bline_point.keys(): val = bline_point.attrib["loop"] if val == "false": loop = False else: loop = True for entry in bline_point: composite = entry[0] for child in composite: if child.tag == "point": pos = child elif child.tag == "t1": t1 = child elif child.tag == "t2": t2 = child elif child.tag == "split_radius": split_r = child elif child.tag == "split_angle": split_a = child # Necassary to update this before inserting new waypoints, as new # waypoints might include there on time: 0 seconds update_frame_window(pos[0], window) # Empty the pos and fill in the new animated pos pos = gen_dummy_waypoint(pos, "point", "vector") update_child_at_parent(composite, pos, "point") update_frame_window(split_r[0], window) split_r = gen_dummy_waypoint(split_r, "split_radius", "bool") update_child_at_parent(composite, split_r, "split_radius") update_frame_window(split_a[0], window) split_a = gen_dummy_waypoint(split_a, "split_angle", "bool") update_child_at_parent(composite, split_a, "split_angle") append_path(pos[0], composite, "point_path", "vector") animate_radial_composite(t1[0], window) animate_radial_composite(t2[0], window) layer = bline_point.getparent().getparent() for chld in layer: if chld.tag == "param" and chld.attrib["name"] == "origin": origin = chld # Animating the origin update_frame_window(origin[0], window) origin_parent = origin.getparent() origin = gen_dummy_waypoint(origin, "param", "vector", "origin") update_child_at_parent(origin_parent, origin, "param", "origin") # Generate path for the origin component origin_dict = {} origin[0].attrib["transform_axis"] = "true" gen_properties_multi_dimensional_keyframed(origin_dict, origin[0], 0) # Minimizing the window size if window["first"] == sys.maxsize and window["last"] == -1: window["first"] = window["last"] = 0 ################# END OF SECTION 1 ################### ################ SECTION 2 ########################### # Generating values for all the frames in the window fr = window["first"] while fr <= window["last"]: st_val, en_val = insert_dict_at(lottie, -1, fr, loop) for entry in bline_point: composite = entry[0] for child in composite: if child.tag == "point_path": dictionary = ast.literal_eval(child.text) pos_cur = get_vector_at_frame(dictionary, fr) pos_next = get_vector_at_frame(dictionary, fr + 1) elif child.tag == "t1": t1 = child[0] elif child.tag == "t2": t2 = child[0] elif child.tag == "split_radius": split_r = child elif child.tag == "split_angle": split_a = child tangent1_cur, tangent2_cur = get_tangent_at_frame( t1, t2, split_r, split_a, fr) tangent1_next, tangent2_next = get_tangent_at_frame( t1, t2, split_r, split_a, fr) tangent1_cur, tangent2_cur = convert_tangent_to_lottie( tangent1_cur, tangent2_cur) tangent1_next, tangent2_next = convert_tangent_to_lottie( tangent1_next, tangent2_next) # Adding origin to each vertex origin_cur = get_vector_at_frame(origin_dict, fr) origin_next = get_vector_at_frame(origin_dict, fr + 1) for i in range(len(pos_cur)): pos_cur[i] += origin_cur[i] for i in range(len(pos_next)): pos_next[i] += origin_next[i] # Store values in dictionary st_val["i"].append(tangent1_cur.get_list()) st_val["o"].append(tangent2_cur.get_list()) st_val["v"].append(pos_cur) en_val["i"].append(tangent1_next.get_list()) en_val["o"].append(tangent2_next.get_list()) en_val["v"].append(pos_next) fr += 1 # Setting final time lottie.append({}) lottie[-1]["t"] = fr
def gen_list_circle(lottie, layer): """ Generates a shape layer corresponding to circle layer by manipulating the origin and radius of the circle Args: lottie (dict) : Lottie format circle layer will be stored in this layer (lxml.etree._Element) : Synfig format circle layer Returns: (None) """ ################### SECTION 1 ######################### # Inserting waypoints if not animated and finding the first and last frame # AFter that, there path will be calculated in lottie format which can # latter be used in get_vector_at_frame() function window = {} window["first"] = sys.maxsize window["last"] = -1 for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "origin": origin = chld elif chld.attrib["name"] == "radius": radius = chld # Animating the origin update_frame_window(origin[0], window) origin = gen_dummy_waypoint(origin, "param", "vector", "origin") update_child_at_parent(layer, origin, "param", "origin") # Generate path for the origin component origin_dict = {} origin[0].attrib["transform_axis"] = "true" gen_properties_multi_dimensional_keyframed(origin_dict, origin[0], 0) update_frame_window(radius[0], window) radius = gen_dummy_waypoint(radius, "param", "real", "radius") update_child_at_parent(layer, radius, "param", "width") # Generate radius for Lottie format radius_dict = {} gen_value_Keyframed(radius_dict, radius[0], 0) # Minimizing the window size if window["first"] == sys.maxsize and window["last"] == -1: window["first"] = window["last"] = 0 ################# END OF SECTION 1 ################### ################ SECTION 2 ########################### # Generating values for all the frames in the window fr = window["first"] while fr <= window["last"]: st_val, en_val = insert_dict_at( lottie, -1, fr, False) # This loop needs to be considered somewhere down synfig_circle(st_val, origin_dict, radius_dict, fr) synfig_circle(en_val, origin_dict, radius_dict, fr + 1) fr += 1 # Setting the final time lottie.append({}) lottie[-1]["t"] = fr
def gen_list_rectangle(lottie, layer): """ Generates a shape layer corresponding to rectangle layer by manipulating the parameters of the rectangle Args: lottie (dict) : Lottie format rectangle layer will be stored in this layer (lxml.etree._Element) : Synfig format rectangle layer Returns: (None) """ ################### SECTION 1 ######################### # Inserting waypoints if not animated and finding the first and last frame # AFter that, there path will be calculated in lottie format which can # latter be used in get_vector_at_frame() function window = {} window["first"] = sys.maxsize window["last"] = -1 bevel_found = False expand_found = False for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "point1": point1 = chld elif chld.attrib["name"] == "point2": point2 = chld elif chld.attrib["name"] == "expand": expand_found = True expand = chld elif chld.attrib["name"] == "bevel": bevel_found = True bevel = chld elif chld.attrib["name"] == "bevCircle": bevCircle = chld if not expand_found: # Means filled rectangle layer st = "<param name='expand'><real value='0.0'/></param>" expand = etree.fromstring(st) if not bevel_found: # For rectangle layer in stable version 1.2.2 st = "<param name='bevel'><real value='0.0'/></param>" bevel = etree.fromstring(st) st = "<param name='bevCircle'><bool value='false'/></param>" bevCircle = etree.fromstring(st) # Animating point1 update_frame_window(point1[0], window) point1 = gen_dummy_waypoint(point1, "param", "vector", "point1") update_child_at_parent(layer, point1, "param", "point1") # Generate path for the point1 component p1_dict = {} #point1[0].attrib["transform_axis"] = "true" gen_properties_multi_dimensional_keyframed(p1_dict, point1[0], 0) # Animating point2 update_frame_window(point2[0], window) point2 = gen_dummy_waypoint(point2, "param", "vector", "point2") update_child_at_parent(layer, point2, "param", "point2") # Generate path for the point2 component p2_dict = {} gen_properties_multi_dimensional_keyframed(p2_dict, point2[0], 0) # Animating expand update_frame_window(expand[0], window) expand = gen_dummy_waypoint(expand, "param", "real", "expand") update_child_at_parent(layer, expand, "param", "expand") # Generate expand param for Lottie format expand_dict = {} gen_value_Keyframed(expand_dict, expand[0], 0) # Animating bevel update_frame_window(bevel[0], window) bevel = gen_dummy_waypoint(bevel, "param", "real", "bevel") update_child_at_parent(layer, bevel, "param", "bevel") # Generate bevel param for Lottie format bevel_dict = {} gen_value_Keyframed(bevel_dict, bevel[0], 0) # Animating bevCircle update_frame_window(bevCircle[0], window) bevCircle = gen_dummy_waypoint(bevCircle, "param", "bool", "bevCircle") update_child_at_parent(layer, bevCircle, "param", "bevCircle") # Minimizing the window size if window["first"] == sys.maxsize and window["last"] == -1: window["first"] = window["last"] = 0 ################# END OF SECTION 1 ################### ################ SECTION 2 ########################### # Generating values for all the frames in the window fr = window["first"] while fr <= window["last"]: st_val, en_val = insert_dict_at(lottie, -1, fr, False) synfig_rectangle(st_val, p1_dict, p2_dict, expand_dict, bevel_dict, bevCircle, fr) synfig_rectangle(en_val, p1_dict, p2_dict, expand_dict, bevel_dict, bevCircle, fr + 1) fr += 1 # Setting the final time lottie.append({}) lottie[-1]["t"] = fr
def gen_list_star(lottie, layer): """ Generates a shape layer corresponding to star layer by manipulating the parameters of the star Args: lottie (dict) : Lottie format rectangle layer will be stored in this layer (lxml.etree._Element) : Synfig format rectangle layer Returns: (None) """ ################### SECTION 1 ######################### # Inserting waypoints if not animated and finding the first and last frame # AFter that, there path will be calculated in lottie format which can # latter be used in get_vector_at_frame() function window = {} window["first"] = sys.maxsize window["last"] = -1 for chld in layer: if chld.tag == "param": if chld.attrib["name"] == "origin": origin = chld elif chld.attrib["name"] == "radius1": radius1 = chld elif chld.attrib["name"] == "radius2": radius2 = chld elif chld.attrib["name"] == "angle": angle = chld elif chld.attrib["name"] == "points": points = chld elif chld.attrib["name"] == "regular_polygon": regular_polygon = chld # Animating origin update_frame_window(origin[0], window) origin = gen_dummy_waypoint(origin, "param", "vector", "origin") update_child_at_parent(layer, origin, "param", "origin") # Generate path for the origin component origin_dict = {} origin[0].attrib["transform_axis"] = "true" gen_properties_multi_dimensional_keyframed(origin_dict, origin[0], 0) # Animating radius1 update_frame_window(radius1[0], window) radius1 = gen_dummy_waypoint(radius1, "param", "real", "radius1") update_child_at_parent(layer, radius1, "param", "radius1") # Generate expand param for Lottie format radius1_dict = {} gen_value_Keyframed(radius1_dict, radius1[0], 0) # Animating radius2 update_frame_window(radius2[0], window) radius2 = gen_dummy_waypoint(radius2, "param", "real", "radius2") update_child_at_parent(layer, radius2, "param", "radius2") # Generate expand param for Lottie format radius2_dict = {} gen_value_Keyframed(radius2_dict, radius2[0], 0) # Animating angle update_frame_window(angle[0], window) angle = gen_dummy_waypoint(angle, "param", "star_angle_new", "angle") update_child_at_parent(layer, angle, "param", "angle") # Generate expand param for Lottie format angle_dict = {} gen_value_Keyframed(angle_dict, angle[0], 0) # Animating points update_frame_window(points[0], window) points = gen_dummy_waypoint(points, "param", "real", "points") update_child_at_parent(layer, points, "param", "points") # Generate expand param for Lottie format points_dict = {} gen_value_Keyframed(points_dict, points[0], 0) mx_points = get_max_points(points) # Animating regular_polygon update_frame_window(regular_polygon[0], window) regular_polygon = gen_dummy_waypoint(regular_polygon, "param", "bool", "regular_polygon") update_child_at_parent(layer, regular_polygon, "param", "regular_polygon") # Minimizing the window size if window["first"] == sys.maxsize and window["last"] == -1: window["first"] = window["last"] = 0 ################# END OF SECTION 1 ################### ################ SECTION 2 ########################### # Generating values for all the frames in the window fr = window["first"] while fr <= window["last"]: st_val, en_val = insert_dict_at(lottie, -1, fr, False) synfig_star(st_val, mx_points, origin_dict, radius1_dict, radius2_dict, angle_dict, points_dict, regular_polygon, fr) synfig_star(en_val, mx_points, origin_dict, radius1_dict, radius2_dict, angle_dict, points_dict, regular_polygon, fr + 1) fr += 1 # Setting the final time lottie.append({}) lottie[-1]["t"] = fr