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

Code before:

        for n in range(num_curves):
            yield self.get_nth_curve_function_with_length(n, **kwargs)

    def point_from_proportion(self, alpha: float) -> np.ndarray:
        """Get the bezier curve evaluated at a position P,
        where P is the point corresponding to the proportion defined by the given alpha.

        Parameters
        ----------
        alpha : float
            Proportion.

        Returns
        -------
        np.ndarray
            Point evaluated.
        """

        if alpha >= 1:
            return self.points[-1]

        target_length = alpha * self.get_arc_length()
        current_length = 0

        for curve, length in self.get_curve_functions_with_lengths():
            if current_length + length >= target_length:
                if length != 0:
                    residue = (target_length - current_length) / length
                else:
                    residue = 0

                return curve(residue)

            current_length += length

    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:

Review comment (suggestion):
Since `get_arc_length` uses `get_curve_functions_with_lengths` now, this will result in the lengths of the functions getting calculated twice in `point_from_proportion`, which is why I stored the curves and lengths in a list, since the lengths are needed to calculate the total length and to see when the accumulated length has reached the target length.

Code after:

        Returns
        -------
        typing.Iterable[typing.Tuple[typing.Callable[[float], np.ndarray], float]]
            The functions and lengths of the curves.
        """

        num_curves = self.get_num_curves()

        for n in range(num_curves):
            yield self.get_nth_curve_function_with_length(n, **kwargs)

    def point_from_proportion(self, alpha: float) -> np.ndarray:
        """Get the bezier curve evaluated at a position P,
        where P is the point corresponding to the proportion defined by the given alpha.

        Parameters
        ----------
        alpha : float
            Proportion.

        Returns
        -------
        np.ndarray
            Point evaluated.
        """

        if alpha == 1:
            return self.get_points()[-1]

        curves_and_lengths = tuple(self.get_curve_functions_with_lengths())

        target_length = alpha * np.sum(length for _, length in curves_and_lengths)
        current_length = 0

        for curve, length in curves_and_lengths:
            if current_length + length >= target_length:
                if length != 0:
                    residue = (target_length - current_length) / length
                else:
                    residue = 0

                return curve(residue)

            current_length += length

    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))