Repository: ManimCommunity/manim
File: manim/utils/bezier.py (Python)

Code before:
    control_points (typing.Iterable[typing.Iterable[float]])
        The Cartesian Coordinates of the ordered control
        points of the bezier curve on which the point may
        or may not lie.

    Returns
    -------
        list[float]
            List containing possible parameters for the given point on
            the given bezier curve.
            This usually only contains one or zero elements, but if the
            point is, say, at the beginning/end of a closed loop, may return
            a list with more than 1 value, corresponding to the beginning and
            end etc. of the loop.
    """
    assert all(np.shape(point) == np.shape(c_p) for c_p in control_points)

    roots = []
    for i in range(len(point)):
        p = point[i]
        # For now, we only deal with quadratic or cubic.
        if len(control_points) == 3:
            p0, p1, p2 = control_points
            p0 = p0[i]
            p1 = p1[i]
            p2 = p2[i]
            bezier_polynom = np.polynomial.Polynomial(
                [p0 - (2 * p1) + p2, 2 * (p1 - p0), p0 - p][::-1]
            )
        elif len(control_points) == 4:
            p0, p1, p2, p3 = control_points
            p0 = p0[i]
            p1 = p1[i]
            p2 = p2[i]
            p3 = p3[i]
            bezier_polynom = np.polynomial.Polynomial(
                [
                    p3 - 3 * p2 + 3 * p1 - p0,  # t**3
                    3 * (p0 - (2 * p1) + p2),  # t**2
                    3 * (p1 - p0),  # t
                    p0 - p,  # Constant
                ][::-1]
            )

        if len(bezier_polynom.roots()) > 0:
            roots.append(bezier_polynom.roots())

    # Of the roots found, remove all imaginary ones, and
    # round all roots to the number of decimal places of CLOSED_THRESHOLD
    # Then, get the common roots for the solved bezier equations in all the
    # supplied dimensions.

Review comment (suggestion):
This logic can be simplified by doing `control_points = np.array(control_points)` at the start of the function and then doing `p0, p1, p2 = control_points[:, i]`. Though I'd probably prefer doing `control_coords = control_points[:, i]` (or instead of `i`, `dim` as mentioned earlier) and then accessing them with `control_coords[0]` etc. instead of having a bunch of loose variables.

Code after:
        should be obtained.
    control_points
        The Cartesian Coordinates of the ordered control
        points of the bezier curve on which the point may
        or may not lie.
    round_to
        A float whose number of decimal places all values
        such as coordinates of points will be rounded.

    Returns
    -------
        np.ndarray[float]
            List containing possible parameters (the proportions along the bezier curve)
            for the given point on the given bezier curve.
            This usually only contains one or zero elements, but if the
            point is, say, at the beginning/end of a closed loop, may return
            a list with more than 1 value, corresponding to the beginning and
            end etc. of the loop.

    Raises
    ------
    :class:`ValueError`
        When ``point`` and the control points have different shapes.
    """
    # Method taken from
    # http://polymathprogrammer.com/2012/04/03/does-point-lie-on-bezier-curve/

    if not all(np.shape(point) == np.shape(c_p) for c_p in control_points):
        raise ValueError(
            f"Point {point} and Control Points {control_points} have different shapes."
        )

    control_points = np.array(control_points)
    n = len(control_points) - 1

    roots = []
    for dim, coord in enumerate(point):
        control_coords = control_points[:, dim]
        terms = []
        for term_power in range(n, -1, -1):
            outercoeff = choose(n, term_power)
            term = []
            sign = 1
            for subterm_num in range(term_power, -1, -1):
                innercoeff = choose(term_power, subterm_num) * sign
                subterm = innercoeff * control_coords[subterm_num]
                if term_power == 0:
                    subterm -= coord
                term.append(subterm)
                sign *= -1
            terms.append(outercoeff * sum(np.array(term)))