示例#1
0
def make_cycle_data(
        foot_positions: limb.Property,
        times: dict
) -> limb.Property:
    """
    Trial report pages contain a duty-cycle diagram, which is created using the
    data generated in this method. The returned limb.Property contains a list
    for each limb of the duty cycle regions for that limb where a region is a
    list with elements:
        - 0: The time at which this cycle ends
        - 1: The enumerated annotation for this cycle

    :param foot_positions:
        Simulation results
    :param times:
        Time step information
    """

    gait_cycles = limb.Property().assign([], [], [], [])

    for i in range(times['count']):
        for key in limb.KEYS:
            cycles = gait_cycles.get(key)
            pos = foot_positions.get(key)[i]
            if not cycles or cycles[-1][1] != pos.annotation:
                cycles.append([1, pos.annotation])
            else:
                cycles[-1][0] += 1

    return gait_cycles
示例#2
0
def unused_foot_prints(
        print_positions: limb.Property,
        foot_positions: limb.Property
):
    """
    Trims the print positions lists to include only those positions found in
    the foot positions lists and the positions just before and after to provide
    context

    :param print_positions:
    :param foot_positions:
    :return:
    """

    was_pruned = False

    def is_in(uid: str, items: list) -> bool:
        for item in items:
            if item.uid == uid:
                return True
        return False

    for limb_key, foot_prints in print_positions.items():

        index = len(foot_prints) - 1
        while index > 0:
            index -= 1
            if is_in(foot_prints[index].uid, foot_positions.get(limb_key)):
                break
            foot_prints.pop()
            was_pruned = True

        while len(foot_prints) > 1:
            if is_in(foot_prints[1].uid, foot_positions.get(limb_key)):
                break
            foot_prints.pop(0)
            was_pruned = True

    return was_pruned
def create_tangents(foot_positions: limb.Property) -> limb.Property:
    """

    :param foot_positions:
    :return:
    """

    def find_next_position(_positions, _i):
        reference_pos = _positions[_i]
        for pos in _positions[(i + 1) :]:
            identical = (
                mstats.value.equivalent(pos.x.raw, reference_pos.x.raw, 0.1),
                mstats.value.equivalent(pos.y.raw, reference_pos.y.raw, 0.1),
            )
            if not identical[0] or not identical[1]:
                return pos
        return None

    tangents = limb.Property().assign([], [], [], [])

    for key in limb.KEYS:
        positions = foot_positions.get(key)

        for i in range(len(positions)):
            p = positions[i]
            next_pos = find_next_position(positions, i)

            if not next_pos or i >= (len(positions) - 1):
                try:
                    tan = tangents.get(key)[-1]
                except IndexError as err:
                    print("Index:", i)
                    print("Positions:", len(positions))
                    print("Next:", next_pos)
                    raise err
            else:
                tan = geometry.LineSegment2D(p, next_pos)
                tan.post_extend_line(4)
                tan.pre_extend_line(4)

            tangents.get(key).append(tan)

    return tangents
示例#4
0
def save_positions_file(trackway_positions: limb.Property, path):
    """
    Saves a limb positions property object to the specified path as a CSV
    file with columns:

        lp_x, lp_dx, lp_y, lp_dy, [lp_assumed], [lp_name], [lp_uid]
        rp_x, rp_dx, rp_y, rp_dy, [rp_assumed], [rp_name], [rp_uid]
        lm_x, lm_dx, lm_y, lm_dy, [lm_assumed], [lm_name], [lm_uid]
        rm_x, rm_dx, rm_y, rm_dy, [rm_assumed], [rm_name], [rm_uid]

    :param trackway_positions:
        The trackway positions to be saved
    :param path:
        The path to the positions file to be saved
    """

    df = []

    for prefix, limb_key in limb.LIMB_KEY_LOOKUP.items():
        for index, position in enumerate(trackway_positions.get(limb_key)):
            while index >= len(df):
                df.append(dict())

            row = df[index]
            row['{}_x'.format(prefix)] = position.x.value
            row['{}_dx'.format(prefix)] = position.x.uncertainty
            row['{}_y'.format(prefix)] = position.y.value
            row['{}_dy'.format(prefix)] = position.y.uncertainty
            row['{}_name'.format(prefix)] = position.name
            row['{}_uid'.format(prefix)] = position.uid
            row['{}_assumed'.format(prefix)] = 'x' if position.assumed else None

    df = pd.DataFrame(df)
    df.to_csv(path)

    return df
示例#5
0
def make_animation_frame_data(
        foot_positions: limb.Property,
        times: dict,
        coupling_data: dict,
        tangent_data: dict
) -> typing.List[dict]:
    """
    Creates a list of animation frame data from the results, which is used by
    the JavaScript report to animate the feet within the trackway. Each frame
    in the returned list contains:

    - time: The simulation time for the frame
    - positions: An ordered list of position dictionaries for each limb, where
        the order is defined by the limb.KEYS order. Each dictionary contains:
            - x: A list where x[0] is the position and x[1] is the uncertainty
            - y: A list where y[0] is the position and y[1] is the uncertainty
            - f: The enumerated annotation for the position

    :param coupling_data:
    :param tangent_data:
    :param foot_positions:
        The simulation results
    :param times:
        Time step information
    """

    frames = []

    for i in range(times['count']):
        positions = []
        tangents = []
        for key in limb.KEYS:
            pos = foot_positions.get(key)[i]
            tan = tangent_data['tangents'].get(key)[i]
            positions.append({
                'x': [pos.x.value, pos.x.uncertainty, pos.x.raw],
                'y': [pos.y.value, pos.y.uncertainty, pos.y.raw],
                'f': pos.annotation,
                'tx0': [tan.start.x.raw, tan.start.x.uncertainty],
                'ty0': [tan.start.y.raw, tan.start.y.uncertainty],
                'tx1': [tan.end.x.raw, tan.end.x.uncertainty],
                'ty1': [tan.end.y.raw, tan.end.y.uncertainty],
            })

        rear = coupling_data['rear'][i]
        forward = coupling_data['forward'][i]
        midpoint = coupling_data['midpoints'][i]

        rear_box = tangent_data['rear_boxes'][i]
        forward_box = tangent_data['forward_boxes'][i]

        frames.append(dict(
            time=times['cycles'][i],
            support_time=times['support_cycles'][i],
            positions=positions,
            rear_coupler={
                'x': [rear.x.value, rear.x.uncertainty, rear.x.raw],
                'y': [rear.y.value, rear.y.uncertainty, rear.y.raw]
            },
            forward_coupler={
                'x': [forward.x.value, forward.x.uncertainty, forward.x.raw],
                'y': [forward.y.value, forward.y.uncertainty, forward.y.raw]
            },
            midpoint={
                'x': [midpoint.x.value, midpoint.x.uncertainty, midpoint.x.raw],
                'y': [midpoint.y.value, midpoint.y.uncertainty, midpoint.y.raw]
            },
            rear_support_box=[
                { 'x': rear_box[0].x.raw, 'y': rear_box[0].y.raw },
                { 'x': rear_box[1].x.raw, 'y': rear_box[1].y.raw },
                { 'x': rear_box[2].x.raw, 'y': rear_box[2].y.raw },
                { 'x': rear_box[3].x.raw, 'y': rear_box[3].y.raw }
            ],
            forward_support_box=[
                { 'x': forward_box[0].x.raw, 'y': forward_box[0].y.raw },
                { 'x': forward_box[1].x.raw, 'y': forward_box[1].y.raw },
                { 'x': forward_box[2].x.raw, 'y': forward_box[2].y.raw },
                { 'x': forward_box[3].x.raw, 'y': forward_box[3].y.raw }
            ]
        ))

    return frames