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

Code before:

        return length

    def get_nth_curve_function_with_length(
        self, n: int, sample_points: Optional[int] = None
    ) -> typing.Tuple[typing.Callable[[float], np.ndarray], float]:
        """Returns the expression of the nth curve along with its (approximate) length.

        Parameters
        ----------
        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.
        """

        curve = self.get_nth_curve_function(n)

        length = self.get_nth_curve_length(n, sample_points)

        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.
        """


Review comment (performance):
This is less efficient than the previous implementation because to get the length of the curve you need to get the function anyways, which is the reason why I joined the returns, because `point_from_proportion` needed both.

Code after:
        Returns
        -------
        typing.Tuple
            Bezier control points.
        """
        nppcc = self.n_points_per_cubic_curve
        remainder = len(points) % nppcc
        points = points[: len(points) - remainder]
        # Basically take every nppcc element.
        return (points[i : i + nppcc] for i in range(0, len(points), nppcc))

    def get_cubic_bezier_tuples(self):
        return self.get_cubic_bezier_tuples_from_points(self.points)

    def _gen_subpaths_from_points(
        self, points: np.ndarray, filter_func: typing.Callable[[int], bool]
    ) -> typing.Tuple:
        """Given an array of points defining the bezier curves of the vmobject, return subpaths formed by these points.
        Here, Two bezier curves form a path if at least two of their anchors are evaluated True by the relation defined by filter_func.

        The algorithm every bezier tuple (anchors and handles) in ``self.points`` (by regrouping each n elements, where
        n is the number of points per cubic curve)), and evaluate the relation between two anchors with filter_func.
        NOTE : The filter_func takes an int n as parameter, and will evaluate the relation between points[n] and points[n - 1]. This should probably be changed so
        the function takes two points as parameters.

        Parameters
        ----------
        points : np.ndarray
            points defining the bezier curve.
        filter_func : typing.Callable[int, bool]
            Filter-func defining the relation.

        Returns
        -------
        typing.Tuple
            subpaths formed by the points.
        """
        nppcc = self.n_points_per_cubic_curve
        filtered = filter(filter_func, range(nppcc, len(points), nppcc))
        split_indices = [0] + list(filtered) + [len(points)]
        return (
            points[i1:i2]
            for i1, i2 in zip(split_indices, split_indices[1:])
            if (i2 - i1) >= nppcc
        )

    def get_subpaths_from_points(self, points):
        return list(
            self._gen_subpaths_from_points(
                points,
                lambda n: not self.consider_points_equals(points[n - 1], points[n]),