Repository: ManimCommunity/manim
File: manim/mobject/types/vectorized_mobject.py (Python)

Code before:
        Returns
        -------
        float
            The proportion along the path of the :class:`VMobject`.

        Raises
        ------
        :exc:`ValueError`
            If ``point`` does not lie on the curve.
        :exc:`Exception`
            If the :class:`VMobject` has no points.
        """
        self.throw_error_if_no_points()

        nc = self.get_num_curves()
        vmob_length = sum(self.get_nth_curve_length(i) for i in range(nc))
        total_length = 0
        for n in range(nc):
            control_points = self.get_nth_curve_points(n)
            length = self.get_nth_curve_length(n)
            if point_lies_on_bezier(point, control_points):
                t = max(bez_params_from_point(point, control_points))
                total_length += length * t
                break
            else:
                total_length += length
        else:
            raise ValueError(f"Point {point} does not lie on this curve.")
        alpha = total_length / vmob_length

        return alpha

    def get_anchors_and_handles(self) -> typing.Iterable[np.ndarray]:
        """Returns anchors1, handles1, handles2, anchors2,
        where (anchors1[i], handles1[i], handles2[i], anchors2[i])
        will be four points defining a cubic bezier curve
        for any i in range(0, len(anchors1))

        Returns
        -------
        typing.Iterable[np.ndarray]
            Iterable of the anchors and handles.
        """
        nppcc = self.n_points_per_cubic_curve
        return [self.points[i::nppcc] for i in range(nppcc)]

    def get_start_anchors(self) -> np.ndarray:
        """Returns the start anchors of the bezier curves.

        Returns
        -------

Review comment (suggestion):
The `break` means the code below won't get executed anyways, making the `else` redundant
```suggestion

            if point_lies_on_bezier(point, control_points):
                t = max(bez_params_from_point(point, control_points))
                total_length += length * t
                break

            total_length += length
```

Code after:
        n
            The index of the desired curve.
        sample_points
            The number of points to sample to find the length.

        Returns
        -------
        curve : typing.Callable[[float], np.ndarray]
            The function for the nth curve.
        length : :class:`float`
            The length of the nth curve.
        """

        if sample_points is None:
            sample_points = 10

        curve = self.get_nth_curve_function(n)

        points = np.array([curve(a) for a in np.linspace(0, 1, sample_points)])
        diffs = points[1:] - points[:-1]
        norms = np.apply_along_axis(np.linalg.norm, 1, diffs)

        length = np.sum(norms)

        return curve, length

    def get_num_curves(self) -> int:
        """Returns the number of curves of the vmobject.

        Returns
        -------
        int
            number of curves. of the vmobject.
        """
        nppcc = self.n_points_per_cubic_curve
        return len(self.points) // nppcc

    def get_curve_functions(
        self,
    ) -> typing.Iterable[typing.Callable[[float], np.ndarray]]:
        """Gets the functions for the curves of the mobject.

        Returns
        -------
        typing.Iterable[typing.Callable[[float], np.ndarray]]
            The functions for the curves.
        """

        num_curves = self.get_num_curves()

        for n in range(num_curves):