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

Code before:
        # 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.
    roots = [
        r.real
        for r in reduce(
            np.intersect1d,
            [
                [
                    np.around(j, int(np.log10(1 / CLOSED_THRESHOLD))).tolist()
                    for j in i
                    if j.imag == 0
                ]
                for i in roots
            ],
        )
    ]
    return roots


def point_lies_on_bezier(
    point: typing.Iterable[typing.Union[float, int]],
    control_points: typing.Iterable[typing.Iterable[typing.Union[float, int]]],

Review comment (suggestion):
```suggestion
        polynom_roots = bezier_polynom.roots()
        if len(polynom_roots) > 0:
            roots.append(polynom_roots)
```

Code after:
    ------
    :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)))
        if all(term == 0 for term in terms):
            # Then both Bezier curve and Point lie on the same plane.
            # Roots will be none, but in this specific instance, we don't need to consider that.
            continue
        bezier_polynom = np.polynomial.Polynomial(terms[::-1])
        polynom_roots = bezier_polynom.roots()
        if len(polynom_roots) > 0:
            polynom_roots = np.around(polynom_roots, int(np.log10(1 / round_to)))
        roots.append(polynom_roots)

    roots = [[root for root in rootlist if root.imag == 0] for rootlist in roots]
    roots = reduce(np.intersect1d, roots)  # Get common roots.
    roots = np.array([r.real for r in roots])
    return roots


def point_lies_on_bezier(
    point: typing.Iterable[typing.Union[float, int]],
    control_points: typing.Iterable[typing.Iterable[typing.Union[float, int]]],
    round_to: typing.Optional[typing.Union[float, int]] = 1e-6,