Ejemplo n.º 1
0
def calc_pos_and_size(size_animated, pos_animated, animated_1, animated_2,
                      orig_path, i, i1):
    """
    Between two frames, this function is called if either "only point1's
    interval is constant" or "only point2's interval is constant". It calculates
    the position and size property for lottie format. It also adds a new
    waypoint just before the end of the frame if required.
    param3: Can be param1 or param2 of rectangle layer
    param4: Can be param2 or param1 of rectangle layer, but opposite of param3

    Args:
        size_animated (lxml.etree._Element): Holds the size parameter of rectangle layer in Synfig format
        pos_animated  (lxml.etree._Element): Holds the position parameter of rectangle layer in Synfig format
        animated_1    (lxml.etree._Element): Holds the param3 in Synfig format
        animated_2    (lxml.etree._Element): Holds the param4 in Synfig format
        orig_path     (dict)               : Holds the param4 in Lottie format
        i             (int)                : Iterator for animated_2
        i1            (int)                : Iterator for pos_animated and size_animated
    Returns:
        (int, int)    : Updated iterators i and i1 are returned
    """
    pos_animated[i1].attrib["after"] = animated_2[i].attrib["after"]
    size_animated[i1].attrib["after"] = animated_2[i].attrib["after"]

    copy_tcb(pos_animated[i1], animated_2[i])
    copy_tcb(size_animated[i1], animated_2[i])

    get_average(pos_animated[i1], animated_1[i], animated_2[i])
    get_difference(size_animated[i1], animated_1[i], animated_2[i])
    # Inserting a waypoint just before the nextwaypoint
    # Only if a waypoint can be inserted
    t_next = get_frame(animated_2[i + 1])
    t_present = get_frame(animated_2[i])

    ######### Need to check if t_next - t_present < 2 #####
    if abs(t_next - t_present) >= 2:
        pos = get_vector_at_frame(orig_path, t_next - 1)
        pos = to_Synfig_axis(pos, "vector")
        new_waypoint = copy.deepcopy(pos_animated[i1])
        new_waypoint.attrib["before"] = new_waypoint.attrib["after"]
        new_waypoint.attrib["time"] = str(
            (t_next - 1) / settings.lottie_format["fr"]) + "s"
        new_waypoint[0][0].text, new_waypoint[0][1].text = str(pos[0]), str(
            pos[1])

        n_size_waypoint = copy.deepcopy(new_waypoint)
        get_average(new_waypoint, new_waypoint, animated_1[i])
        get_difference(n_size_waypoint, n_size_waypoint, animated_1[i])

        pos_animated.insert(i1 + 1, new_waypoint)
        size_animated.insert(i1 + 1, n_size_waypoint)
        i1 += 1
    i, i1 = i + 1, i1 + 1
    get_average(pos_animated[i1], animated_1[i], animated_2[i])
    get_difference(size_animated[i1], animated_1[i], animated_2[i])
    return i, i1
Ejemplo n.º 2
0
def gen_dummy_waypoint(non_animated, is_animate, anim_type):
    """
    Makes a non animated parameter to animated parameter by creating a new dummy
    waypoint with constant animation

    Args:
        non_animated (lxml.etree._Element): Holds the non-animated parameter in Synfig xml format
        is_animate   (int)                : Decides if a waypoint is animated
        anim_type    (str)                : Decides the animation type

    Returns:
        (lxml.etree._Element) : Updated non-animated parameter, which is now animated
    """
    if is_animate == 0:
        st = '<param name="anything"><animated type="{anim_type}"><waypoint time="0s" before="constant" after="constant"></waypoint></animated></param>'
        st = st.format(anim_type=anim_type)
        root = etree.fromstring(st)
        root[0][0].append(copy.deepcopy(non_animated[0]))
        non_animated = root
    elif is_animate == 1:
        non_animated[0][0].attrib["before"] = non_animated[0][0].attrib[
            "after"] = "constant"

    new_waypoint = copy.deepcopy(non_animated[0][0])
    frame = get_frame(non_animated[0][0])
    frame += 1
    time = frame / settings.lottie_format["fr"]
    time = str(time) + "s"
    new_waypoint.attrib["time"] = time
    non_animated[0].insert(1, new_waypoint)
    return non_animated
Ejemplo n.º 3
0
def get_cross_list(animation_1, animation_2, orig_path_1, orig_path_2):
    """
    This function will return a list('set' technically) at which the point1 and point2 of rectangle
    will cross each other.
    This set might contain frames at which waypoints are already present, hence
    this need to be taken care of

    Args:
        animation_1 (lxml.etree._Element): Stores the animation of `point1` parameter in Synfig format
        animation_2 (lxml.etree._Element): Stores the animation of `point2` parameter in Synfig format
        orig_path_1 (dict)               : Stores the animation of `point1` parameter in Lottie format
        orig_path_2 (dict)               : Stores the animation of `point2` parameter in Lottie format

    Returns:
        (set) : Contains the frames at which point1 and point2 cross each other
    """
    en_fr = max(get_frame(animation_1[-1]), get_frame(animation_2[-1]))
    # Function to determine the sign of a variable
    sign = lambda a: (1, -1)[a < 0]
    prev_1 = float(animation_1[0][0][0].text), float(animation_1[0][0][1].text)
    prev_2 = float(animation_2[0][0][0].text), float(animation_2[0][0][1].text)

    # The list to be returned
    ret_list = set()
    frame = 1
    # Loop for all the frames
    while frame <= en_fr:
        now_1 = get_vector_at_frame(orig_path_1, frame)
        now_1 = to_Synfig_axis(now_1, "vector")
        now_2 = get_vector_at_frame(orig_path_2, frame)
        now_2 = to_Synfig_axis(now_2, "vector")
        is_needed = False
        if sign(prev_1[0] - prev_2[0]) != sign(now_1[0] - now_2[0]):
            is_needed = True
        elif sign(prev_1[1] - prev_2[1]) != sign(now_1[1] - now_2[1]):
            is_needed = True
        if is_needed:
            ret_list.add(frame - 1)
            ret_list.add(frame)
        prev_1, prev_2 = now_1, now_2
        frame += 1
    return ret_list
Ejemplo n.º 4
0
def gen_image_scale(animated_1, animated_2, width, height):
    """
    In Synfig, no scale parameter is available for image layer, so it will be
    created here for Lottie conversion

    Args:
        animated_1 (lxml.etree._Element): point1 animation in Synfig format
        animated_2 (lxml.etree._Element): point2 animation in Synfig format
        width      (int)                : Width of the original image
        height     (int)                : Height of the original image

    Returns:
        (lxml.etree._Element) : Scale parameter in Synfig format
    """
    st = '<param name="image_scale"><real value="0.0000000000"/></param>'
    root = etree.fromstring(st)
    is_animate = is_animated(root)
    root = gen_dummy_waypoint(root, is_animate, "image_scale")

    anim1_path, anim2_path = {}, {}
    gen_properties_multi_dimensional_keyframed(anim1_path, animated_1, 0)
    gen_properties_multi_dimensional_keyframed(anim2_path, animated_2, 0)

    # Filling the first 2 frames with there original scale values
    fill_image_scale_at_frame(root[0], anim1_path, anim2_path, width, height,
                              0)
    fill_image_scale_at_frame(root[0], anim1_path, anim2_path, width, height,
                              1)

    mx_fr = max(get_frame(animated_1[-1]), get_frame(animated_2[-1]))
    fr = 2
    while fr <= mx_fr:
        new_waypoint = copy.deepcopy(root[0][0])
        time = fr / settings.lottie_format["fr"]
        time = str(time) + "s"
        new_waypoint.attrib["time"] = time
        root[0].append(new_waypoint)
        fill_image_scale_at_frame(root[0], anim1_path, anim2_path, width,
                                  height, fr)
        fr += 1
    return root
Ejemplo n.º 5
0
def insert_waypoint_at_frame(animated, orig_path, frame, animated_name):
    """
    This function will only insert a waypoint at 'frame' if no waypoint is
    present at that 'frame' already

    Args:
        animated      (lxml.etree._Element): Holds the animation in Synfig xml format
        orig_path     (dict)               : Holds the animation in Lottie format
        frame         (int)                : The frame at which the waypoint is to be inserted
        animated_name (str)                : The name/type of animation

    Returns:
        (None)
    """
    i = 0
    while i < len(animated):
        at_frame = get_frame(animated[i])
        if frame == at_frame:
            return
        elif frame < at_frame:
            break
        i += 1
    pos = get_vector_at_frame(orig_path, frame)
    pos = to_Synfig_axis(pos, animated_name)

    if i == len(animated):
        new_waypoint = copy.deepcopy(animated[i - 1])
    else:
        new_waypoint = copy.deepcopy(animated[i])
    if animated_name == "vector":
        new_waypoint[0][0].text = str(pos[0])
        new_waypoint[0][1].text = str(pos[1])
    else:
        new_waypoint[0].attrib["value"] = str(pos)

    new_waypoint.attrib["time"] = str(
        frame / settings.lottie_format["fr"]) + "s"
    if i == 0 or i == len(animated):
        # No need of tcb value copy as halt interpolation need to be copied here
        new_waypoint.attrib["before"] = new_waypoint.attrib[
            "after"] = "constant"
    else:
        copy_tcb_average(new_waypoint, animated[i], animated[i - 1])
        new_waypoint.attrib["before"] = animated[i - 1].attrib["after"]
        new_waypoint.attrib["after"] = animated[i].attrib["before"]
        # If the interval was constant before, then the whole interval should
        # remain constant now also
        if new_waypoint.attrib["before"] == "constant" or new_waypoint.attrib[
                "after"] == "constant":
            new_waypoint.attrib["before"] = new_waypoint.attrib[
                "after"] = "constant"
    animated.insert(i, new_waypoint)
Ejemplo n.º 6
0
def get_animated_time_list(child, time_list):
    """
    Appends all the frames corresponding to the waypoints in the
    animated(child[0]) list, in time_list

    Args:
        child     (lxml.etree._Element) : Parent Element of animation
        time_list (set)                 : Will store all the frames at which waypoints are present

    Returns:
        (None)
    """
    animated = child[0]
    is_animate = is_animated(animated)
    if is_animate in {0, 1}:
        return
    for waypoint in animated:
        frame = get_frame(waypoint)
        time_list.add(frame)
Ejemplo n.º 7
0
def both_points_animated(animated_1, animated_2, param_expand, lottie, index):
    """
    This function generates the lottie dictionary for position and size property
    of lottie(point1 and point2 are used from Synfig), when both point1 and
    point2 are animated

    Args:
        animated_1      (lxml.etree._Element): Holds the parameter `point1`'s animation in Synfig xml format
        animated_2      (lxml.etree._Element): Holds the parameter `point2`'s animation in Synfig xml format
        param_expand    (lxml.etree._Element): Holds the parameter `expand`'s animation in Synfig xml format
        lottie          (dict)               : Lottie format rectangle layer will be store in this
        index           (int)                : Stores the index of parameters in rectangle layer

    Returns:
        (None)
    """
    animated_1, animated_2 = animated_1[0], animated_2[0]
    orig_path_1, orig_path_2 = {}, {}
    expand_path = {}
    gen_value_Keyframed(expand_path, param_expand[0], 0)
    gen_properties_multi_dimensional_keyframed(orig_path_1, animated_1, 0)
    gen_properties_multi_dimensional_keyframed(orig_path_2, animated_2, 0)

    #################### SECTION 1 ###########################
    # Insert waypoints in the point1 and point2 parameter at the place where
    # expand parameter is animated
    time_list = set()
    get_animated_time_list(param_expand, time_list)
    for frame in time_list:
        insert_waypoint_at_frame(animated_1, orig_path_1, frame, "vector")
        insert_waypoint_at_frame(animated_2, orig_path_2, frame, "vector")

    #################### END OF SECTION 1 ####################

    ### SECTION TRY ###
    # Every frames value is precomputed in order to achieve maximum similarity
    # to that of Synfig
    en_fr = max(get_frame(animated_1[-1]), get_frame(animated_2[-1]))
    fra = 1
    while fra <= en_fr:
        insert_waypoint_at_frame(animated_1, orig_path_1, fra, "vector")
        insert_waypoint_at_frame(animated_2, orig_path_2, fra, "vector")
        fra += 1
    ### END SECTION ###

    ######################### SECTION 2 ##########################
    # Insert the waypoints at corresponding positions where point1 is animated
    # and point2 is animated
    for waypoint in animated_1:
        frame = get_frame(waypoint)
        insert_waypoint_at_frame(animated_2, orig_path_2, frame, "vector")

    for waypoint in animated_2:
        frame = get_frame(waypoint)
        insert_waypoint_at_frame(animated_1, orig_path_1, frame, "vector")
    ##################### END OF SECTION 2 #######################

    ##################### SECTION 3 ##############################
    # Add the impact of expand parameter amount towards point1 and point2
    # parameter
    assert len(animated_1) == len(animated_2)
    for waypoint1, waypoint2 in zip(animated_1, animated_2):
        frame = get_frame(waypoint1)
        assert frame == get_frame(waypoint2)
        expand_amount = get_vector_at_frame(expand_path, frame)
        expand_amount = to_Synfig_axis(expand_amount, "real")

        pos1, pos2 = get_vector(waypoint1), get_vector(waypoint2)
        # Comparing the x-coordinates
        if pos1.val1 > pos2.val1:
            pos1.val1 += expand_amount
            pos2.val1 -= expand_amount
        else:
            pos1.val1 -= expand_amount
            pos2.val1 += expand_amount
        # Comparing the y-coordinates
        if pos1.val2 > pos2.val2:
            pos1.val2 += expand_amount
            pos2.val2 -= expand_amount
        else:
            pos1.val2 -= expand_amount
            pos2.val2 += expand_amount
        set_vector(waypoint1, pos1)
        set_vector(waypoint2, pos2)
    ##################### END OF SECTION 3 #######################

    #################### SECTION 4 #############################
    # Place waypoints at which the x and y cross each other/cross the extremas
    cross_list = get_cross_list(animated_1, animated_2, orig_path_1,
                                orig_path_2)
    for frame in cross_list:
        insert_waypoint_at_frame(animated_1, orig_path_1, frame, "vector")
        insert_waypoint_at_frame(animated_2, orig_path_2, frame, "vector")
    #################### END SECTION 4 #########################

    ################## SECTION 5 ################################################
    # Store the position of rectangle according to the waypoints in pos_animated
    # Store the size of rectangle according to the waypoints in size_animated
    pos_animated = copy.deepcopy(animated_1)
    size_animated = copy.deepcopy(animated_1)
    size_animated.attrib["type"] = "rectangle_size"

    i, i1 = 0, 0
    while i < len(animated_1) - 1:
        cur_get_after_1, cur_get_after_2 = animated_1[i].attrib[
            "after"], animated_2[i].attrib["after"]
        next_get_before_1, next_get_before_2 = animated_1[
            i + 1].attrib["before"], animated_2[i + 1].attrib["before"]

        dic_1 = {"linear", "auto", "clamped", "halt"}
        dic_2 = {"constant"}
        constant_interval_1 = cur_get_after_1 in dic_2 or next_get_before_1 in dic_2
        constant_interval_2 = cur_get_after_2 in dic_2 or next_get_before_2 in dic_2

        # Case 1 no "constant" interval is present
        if (cur_get_after_1 in dic_1) and (cur_get_after_2 in dic_1) and (
                next_get_before_1 in dic_1) and (next_get_before_2 in dic_1):
            get_average(pos_animated[i1], animated_1[i], animated_2[i])
            copy_tcb_average(pos_animated[i1], animated_1[i], animated_2[i])

            get_difference(size_animated[i1], animated_1[i], animated_2[i])
            copy_tcb(size_animated[i1], pos_animated[i1])
            i, i1 = i + 1, i1 + 1
            get_average(pos_animated[i1], animated_1[i], animated_2[i])
            copy_tcb_average(pos_animated[i1], animated_1[i], animated_2[i])

            get_difference(size_animated[i1], animated_1[i], animated_2[i])
            copy_tcb(size_animated[i1], pos_animated[i1])

        # Case 2 only one "constant" interval: could mean two "constant"'s are present
        elif (constant_interval_1
              and not constant_interval_2) or (not constant_interval_1
                                               and constant_interval_2):
            if constant_interval_1:
                i, i1 = calc_pos_and_size(size_animated, pos_animated,
                                          animated_1, animated_2, orig_path_2,
                                          i, i1)
            elif constant_interval_2:
                i, i1 = calc_pos_and_size(size_animated, pos_animated,
                                          animated_2, animated_1, orig_path_1,
                                          i, i1)

        # Case 3 both are constant
        elif constant_interval_1 and constant_interval_2:
            # No need to copy tcb, as it's pos should be "constant"
            get_average(pos_animated[i1], animated_1[i], animated_2[i])
            get_difference(size_animated[i1], animated_1[i], animated_2[i])

            i, i1 = i + 1, i1 + 1
            get_difference(size_animated[i1], animated_1[i], animated_2[i])
            get_average(pos_animated[i1], animated_1[i], animated_2[i])
    ######################### SECTION 5 END ##############################

    ######################### SECTION 6 ##################################
    # Generate the position and size for lottie format
    gen_properties_multi_dimensional_keyframed(lottie["p"], pos_animated,
                                               index.inc())
    gen_value_Keyframed(lottie["s"], size_animated, index.inc())