diff --git a/manim/mobject/geometry/arc.py b/manim/mobject/geometry/arc.py index 2923239944..b01dd7ce8d 100644 --- a/manim/mobject/geometry/arc.py +++ b/manim/mobject/geometry/arc.py @@ -183,7 +183,7 @@ def position_tip(self, tip: tips.ArrowTip, at_start: bool = False) -> tips.Arrow else: handle = self.get_last_handle() anchor = self.get_end() - angles = cartesian_to_spherical((handle - anchor).tolist()) + angles = cartesian_to_spherical(handle - anchor) tip.rotate( angles[1] - PI - tip.tip_angle, ) # Rotates the tip along the azimuthal diff --git a/manim/mobject/geometry/boolean_ops.py b/manim/mobject/geometry/boolean_ops.py index f02b4f7be6..8de14d348f 100644 --- a/manim/mobject/geometry/boolean_ops.py +++ b/manim/mobject/geometry/boolean_ops.py @@ -59,7 +59,7 @@ def _convert_2d_to_3d_array( list_of_points = list(points) for i, point in enumerate(list_of_points): if len(point) == 2: - list_of_points[i] = np.array(list(point) + [z_dim]) + list_of_points[i] = np.append(point, z_dim) return np.asarray(list_of_points) def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: @@ -78,10 +78,10 @@ def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: """ path = SkiaPath() - if not np.all(np.isfinite(vmobject.points)): - points = np.zeros((1, 3)) # point invalid? - else: + if np.all(np.isfinite(vmobject.points)): points = vmobject.points + else: + points = np.zeros((1, 3)) # point invalid? if len(points) == 0: # what? No points so return empty path return path diff --git a/manim/mobject/graphing/scale.py b/manim/mobject/graphing/scale.py index 78ffa2308b..5f9484b7f6 100644 --- a/manim/mobject/graphing/scale.py +++ b/manim/mobject/graphing/scale.py @@ -163,7 +163,7 @@ def get_custom_labels( self, val_range: Iterable[float], unit_decimal_places: int = 0, - **base_config: dict[str, Any], + **base_config: Any, ) -> list[Mobject]: """Produces custom :class:`~.Integer` labels in the form of ``10^2``. diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index 6ad3ece777..705e6a677d 100644 --- a/manim/mobject/mobject.py +++ b/manim/mobject/mobject.py @@ -51,6 +51,7 @@ PathFuncType, PixelArray, Point3D, + Point3D_Array, Point3DLike, Point3DLike_Array, Vector3D, @@ -1225,7 +1226,13 @@ def shift(self, *vectors: Vector3D) -> Self: return self - def scale(self, scale_factor: float, **kwargs) -> Self: + def scale( + self, + scale_factor: float, + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, + ) -> Self: r"""Scale the size by a factor. Default behavior is to scale about the center of the mobject. @@ -1236,9 +1243,10 @@ def scale(self, scale_factor: float, **kwargs) -> Self: The scaling factor :math:`\alpha`. If :math:`0 < |\alpha| < 1`, the mobject will shrink, and for :math:`|\alpha| > 1` it will grow. Furthermore, if :math:`\alpha < 0`, the mobject is also flipped. - kwargs - Additional keyword arguments passed to - :meth:`apply_points_function_about_point`. + about_point + The point about which to apply the scaling. + about_edge + The edge about which to apply the scaling. Returns ------- @@ -1267,7 +1275,7 @@ def construct(self): """ self.apply_points_function_about_point( - lambda points: scale_factor * points, **kwargs + lambda points: scale_factor * points, about_point, about_edge ) return self @@ -1280,16 +1288,23 @@ def rotate( angle: float, axis: Vector3D = OUT, about_point: Point3DLike | None = None, - **kwargs, + *, + about_edge: Vector3D | None = None, ) -> Self: """Rotates the :class:`~.Mobject` about a certain point.""" rot_matrix = rotation_matrix(angle, axis) self.apply_points_function_about_point( - lambda points: np.dot(points, rot_matrix.T), about_point, **kwargs + lambda points: np.dot(points, rot_matrix.T), about_point, about_edge ) return self - def flip(self, axis: Vector3D = UP, **kwargs) -> Self: + def flip( + self, + axis: Vector3D = UP, + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, + ) -> Self: """Flips/Mirrors an mobject about its center. Examples @@ -1306,26 +1321,43 @@ def construct(self): self.add(s2) """ - return self.rotate(TAU / 2, axis, **kwargs) + return self.rotate( + TAU / 2, axis, about_point=about_point, about_edge=about_edge + ) - def stretch(self, factor: float, dim: int, **kwargs) -> Self: + def stretch( + self, + factor: float, + dim: int, + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, + ) -> Self: def func(points: Point3D_Array) -> Point3D_Array: points[:, dim] *= factor return points - self.apply_points_function_about_point(func, **kwargs) + self.apply_points_function_about_point(func, about_point, about_edge) return self - def apply_function(self, function: MappingFunction, **kwargs) -> Self: + def apply_function( + self, + function: MappingFunction, + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, + ) -> Self: # Default to applying matrix about the origin, not mobjects center - if len(kwargs) == 0: - kwargs["about_point"] = ORIGIN + if about_point is None and about_edge is None: + about_point = ORIGIN def multi_mapping_function(points: Point3D_Array) -> Point3D_Array: result: Point3D_Array = np.apply_along_axis(function, 1, points) return result - self.apply_points_function_about_point(multi_mapping_function, **kwargs) + self.apply_points_function_about_point( + multi_mapping_function, about_point, about_edge + ) return self def apply_function_to_position(self, function: MappingFunction) -> Self: @@ -1337,20 +1369,30 @@ def apply_function_to_submobject_positions(self, function: MappingFunction) -> S submob.apply_function_to_position(function) return self - def apply_matrix(self, matrix, **kwargs) -> Self: + def apply_matrix( + self, + matrix, + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, + ) -> Self: # Default to applying matrix about the origin, not mobjects center - if ("about_point" not in kwargs) and ("about_edge" not in kwargs): - kwargs["about_point"] = ORIGIN + if about_point is None and about_edge is None: + about_point = ORIGIN full_matrix = np.identity(self.dim) matrix = np.array(matrix) full_matrix[: matrix.shape[0], : matrix.shape[1]] = matrix self.apply_points_function_about_point( - lambda points: np.dot(points, full_matrix.T), **kwargs + lambda points: np.dot(points, full_matrix.T), about_point, about_edge ) return self def apply_complex_function( - self, function: Callable[[complex], complex], **kwargs + self, + function: Callable[[complex], complex], + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, ) -> Self: """Applies a complex function to a :class:`Mobject`. The x and y Point3Ds correspond to the real and imaginary parts respectively. @@ -1383,7 +1425,9 @@ def R3_func(point): xy_complex = function(complex(x, y)) return [xy_complex.real, xy_complex.imag, z] - return self.apply_function(R3_func) + return self.apply_function( + R3_func, about_point=about_point, about_edge=about_edge + ) def reverse_points(self) -> Self: for mob in self.family_members_with_points(): diff --git a/manim/mobject/types/vectorized_mobject.py b/manim/mobject/types/vectorized_mobject.py index 321fe4287b..72ba4732b9 100644 --- a/manim/mobject/types/vectorized_mobject.py +++ b/manim/mobject/types/vectorized_mobject.py @@ -472,7 +472,14 @@ def set_opacity(self, opacity: float, family: bool = True) -> Self: self.set_stroke(opacity=opacity, family=family, background=True) return self - def scale(self, scale_factor: float, scale_stroke: bool = False, **kwargs) -> Self: + def scale( + self, + scale_factor: float, + scale_stroke: bool = False, + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, + ) -> Self: r"""Scale the size by a factor. Default behavior is to scale about the center of the vmobject. @@ -527,7 +534,7 @@ def construct(self): width=abs(scale_factor) * self.get_stroke_width(background=True), background=True, ) - super().scale(scale_factor, **kwargs) + super().scale(scale_factor, about_point=about_point, about_edge=about_edge) return self def fade(self, darkness: float = 0.5, family: bool = True) -> Self: @@ -1178,7 +1185,13 @@ def append_vectorized_mobject(self, vectorized_mobject: VMobject) -> None: self.points = self.points[:-1] self.append_points(vectorized_mobject.points) - def apply_function(self, function: MappingFunction) -> Self: + def apply_function( + self, + function: MappingFunction, + *, + about_point: Point3DLike | None = None, + about_edge: Vector3D | None = None, + ) -> Self: factor = self.pre_function_handle_to_anchor_scale_factor self.scale_handle_to_anchor_distances(factor) super().apply_function(function) @@ -1192,10 +1205,11 @@ def rotate( angle: float, axis: Vector3D = OUT, about_point: Point3DLike | None = None, - **kwargs, + *, + about_edge: Vector3D | None = None, ) -> Self: self.rotate_sheen_direction(angle, axis) - super().rotate(angle, axis, about_point, **kwargs) + super().rotate(angle, axis, about_point, about_edge=about_edge) return self def scale_handle_to_anchor_distances(self, factor: float) -> Self: diff --git a/manim/utils/bezier.py b/manim/utils/bezier.py index 28958309a5..060164fd12 100644 --- a/manim/utils/bezier.py +++ b/manim/utils/bezier.py @@ -915,10 +915,10 @@ def subdivide_bezier(points: BezierPointsLike, n_divisions: int) -> Spline: :class:`~.Spline` An array containing the points defining the new :math:`n` subcurves. """ + points = np.asarray(points) if n_divisions == 1: return points - points = np.asarray(points) N, dim = points.shape if N <= 4: @@ -1754,10 +1754,10 @@ def get_quadratic_approximation_of_cubic( def get_quadratic_approximation_of_cubic( - a0: Point3D | Point3D_Array, - h0: Point3D | Point3D_Array, - h1: Point3D | Point3D_Array, - a1: Point3D | Point3D_Array, + a0: Point3DLike | Point3DLike_Array, + h0: Point3DLike | Point3DLike_Array, + h1: Point3DLike | Point3DLike_Array, + a1: Point3DLike | Point3DLike_Array, ) -> QuadraticSpline | QuadraticBezierPath: r"""If ``a0``, ``h0``, ``h1`` and ``a1`` are the control points of a cubic Bézier curve, approximate the curve with two quadratic Bézier curves and diff --git a/manim/utils/images.py b/manim/utils/images.py index dd5c57858e..9d96edab09 100644 --- a/manim/utils/images.py +++ b/manim/utils/images.py @@ -40,16 +40,16 @@ def get_full_vector_image_path(image_file_name: str | PurePath) -> Path: ) -def drag_pixels(frames: list[np.array]) -> list[np.array]: +def drag_pixels(frames: list[np.ndarray]) -> list[np.ndarray]: curr = frames[0] - new_frames = [] + new_frames: list[np.ndarray] = [] for frame in frames: curr += (curr == 0) * np.array(frame) new_frames.append(np.array(curr)) return new_frames -def invert_image(image: np.array) -> Image: +def invert_image(image: np.ndarray) -> Image.Image: arr = np.array(image) arr = (255 * np.ones(arr.shape)).astype(arr.dtype) - arr return Image.fromarray(arr) diff --git a/manim/utils/space_ops.py b/manim/utils/space_ops.py index 963c0811ee..6036ee28d1 100644 --- a/manim/utils/space_ops.py +++ b/manim/utils/space_ops.py @@ -802,14 +802,16 @@ def earclip_triangulation(verts: np.ndarray, ring_ends: list) -> list: return [indices[mi] for mi in meta_indices] -def cartesian_to_spherical(vec: Sequence[float]) -> np.ndarray: +def cartesian_to_spherical( + vec: np.ndarray | Sequence[float], +) -> np.ndarray | Sequence[float]: """Returns an array of numbers corresponding to each polar coordinate value (distance, phi, theta). Parameters ---------- vec - A numpy array ``[x, y, z]``. + A numpy array or a sequence of floats ``[x, y, z]``. """ norm = np.linalg.norm(vec) if norm == 0: diff --git a/mypy.ini b/mypy.ini index 80571869be..6c5e05cb90 100644 --- a/mypy.ini +++ b/mypy.ini @@ -74,7 +74,7 @@ ignore_errors = True ignore_errors = False [mypy-manim.mobject.geometry.*] -ignore_errors = True +ignore_errors = False [mypy-manim.renderer.*] ignore_errors = True