def data_from_keyframes(keyframe_points, frame_start, frame_end, for_acceleration):
    """
    Return imu (acceleration or rotational velocity) and location data for an fcurve
    """
    frame_start = int(ceil(frame_start))
    frame_end = int(floor(frame_end))

    def f_to_i(frame, is_ceil):
        f = min(max(frame, frame_start), frame_end) - frame_start
        return ceil(f) if is_ceil else floor(f)

    def i_to_f(index):
        return index + frame_start

    data = np.zeros(frame_end - frame_start + 1)
    locs = np.zeros(frame_end - frame_start + 1)
    locs[: f_to_i(keyframe_points[0].co[0], False)] = keyframe_points[0].co[1]
    locs[f_to_i(keyframe_points[-1].co[0], True) :] = keyframe_points[-1].co[1]

    for i in range(len(keyframe_points) - 1):
        kfs = keyframe_points[i].co[0]
        kfe = keyframe_points[i + 1].co[0]
        kls = keyframe_points[i].co[1]
        kle = keyframe_points[i + 1].co[1]

        if kfs > frame_end or kfe < frame_start:
            continue

        if keyframe_points[i].interpolation == "CONSTANT":
            locs[f_to_i(kfs, True) : f_to_i(kfe, False) + 1] = kls
            data[f_to_i(kfs, True) : f_to_i(kfe, False) + 1] = 0

        elif keyframe_points[i].interpolation == "LINEAR":
            slope = (kle - kls) / (kfe - kfs)
            for j in range(f_to_i(kfs, True), f_to_i(kfe, False) + 1):
                locs[j] = kls + (i_to_f(j) - kfs) * slope
                data[j] = 0 if for_acceleration else slope

        elif keyframe_points[i].interpolation == "BEZIER":
            # control points
            cx, cy = np.zeros(4), np.zeros(4)
            cx[0], cy[0] = kfs, kls
            cx[-1], cy[-1] = kfe, kle

            if keyframe_points[i].handle_right[0] > kfe:
                cx[1] = kfe
                cy[1] = kls + (kfe - kfs) * (
                    (keyframe_points[i].handle_right[1] - kls)
                    / (keyframe_points[i].handle_right[0] - kfs)
                )
            else:
                cx[1] = keyframe_points[i].handle_right[0]
                cy[1] = keyframe_points[i].handle_right[1]

            if keyframe_points[i + 1].handle_left[0] < kfs:
                cx[2] = kfs
                cy[2] = kle + (kfs - kfe) * (
                    (keyframe_points[i + 1].handle_left[1] - kle)
                    / (keyframe_points[i + 1].handle_left[0] - kfe)
                )
            else:
                cx[2] = keyframe_points[i + 1].handle_left[0]
                cy[2] = keyframe_points[i + 1].handle_left[1]

            for j in range(f_to_i(kfs, True), f_to_i(kfe, False) + 1):
                roots = bezier_zeros(i_to_f(j), cx[0], cx[1], cx[2], cx[3])
                if len(roots) == 0:
                    raise Exception(
                        "Bezier interpolation failed at frame {}".format(i_to_f(j))
                    )
                data[j] = (
                    a_of_bezier(roots[0], cx, cy)
                    if for_acceleration
                    else v_of_bezier(roots[0], cx, cy)
                )
                locs[j] = y_of_bezier(roots[0], cy)

        else:
            raise Exception(
                "Keyframe interpolation mode {} not a supported mode: constant, linear, bezier".format(
                    keyframe_points[i].interpolation
                )
            )

    return data, locs

    Return imu (acceleration or rotational velocity) and location data for an fcurve
    
infinigen/core/util/imu.py