mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
Merge branch 'master' of github.com:3b1b/manim into video-work
This commit is contained in:
commit
da0605a5f3
7 changed files with 75 additions and 30 deletions
|
@ -174,6 +174,7 @@ def parse_cli():
|
|||
parser.add_argument(
|
||||
"--fps",
|
||||
help="Frame rate, as an integer",
|
||||
type=int,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c", "--color",
|
||||
|
|
|
@ -770,13 +770,6 @@ class ComplexPlane(NumberPlane):
|
|||
axis = self.get_x_axis()
|
||||
value = z.real
|
||||
number_mob = axis.get_number_mobject(value, font_size=font_size, **kwargs)
|
||||
# For -i, remove the "1"
|
||||
if z.imag == -1:
|
||||
number_mob.remove(number_mob[1])
|
||||
number_mob[0].next_to(
|
||||
number_mob[1], LEFT,
|
||||
buff=number_mob[0].get_width() / 4
|
||||
)
|
||||
self.coordinate_labels.add(number_mob)
|
||||
self.add(self.coordinate_labels)
|
||||
return self
|
||||
|
|
|
@ -52,7 +52,7 @@ SubmobjectType = TypeVar('SubmobjectType', bound='Mobject')
|
|||
if TYPE_CHECKING:
|
||||
from typing import Callable, Iterator, Union, Tuple, Optional, Any
|
||||
import numpy.typing as npt
|
||||
from manimlib.typing import ManimColor, Vect3, Vect4, Vect3Array, UniformDict, Self
|
||||
from manimlib.typing import ManimColor, Vect3, Vect4Array, Vect3Array, UniformDict, Self
|
||||
from moderngl.context import Context
|
||||
|
||||
T = TypeVar('T')
|
||||
|
@ -163,7 +163,7 @@ class Mobject(object):
|
|||
def animate(self) -> _AnimationBuilder:
|
||||
"""
|
||||
Methods called with Mobject.animate.method() can be passed
|
||||
into a Scene.play call, as if you were calling
|
||||
into a Scene.play call, as if you were calling
|
||||
ApplyMethod(mobject.method)
|
||||
|
||||
Borrowed from https://github.com/ManimCommunity/manim/
|
||||
|
@ -287,10 +287,7 @@ class Mobject(object):
|
|||
about_point = self.get_bounding_box_point(about_edge)
|
||||
|
||||
for mob in self.get_family():
|
||||
arrs = []
|
||||
if mob.has_points():
|
||||
for key in mob.pointlike_data_keys:
|
||||
arrs.append(mob.data[key])
|
||||
arrs = [mob.data[key] for key in mob.pointlike_data_keys if mob.has_points()]
|
||||
if works_on_bounding_box:
|
||||
arrs.append(mob.get_bounding_box())
|
||||
|
||||
|
@ -1323,20 +1320,19 @@ class Mobject(object):
|
|||
|
||||
def set_color_by_rgba_func(
|
||||
self,
|
||||
func: Callable[[Vect3], Vect4],
|
||||
func: Callable[[Vect3Array], Vect4Array],
|
||||
recurse: bool = True
|
||||
) -> Self:
|
||||
"""
|
||||
Func should take in a point in R3 and output an rgba value
|
||||
"""
|
||||
for mob in self.get_family(recurse):
|
||||
rgba_array = [func(point) for point in mob.get_points()]
|
||||
mob.set_rgba_array(rgba_array)
|
||||
mob.set_rgba_array(func(mob.get_points()))
|
||||
return self
|
||||
|
||||
def set_color_by_rgb_func(
|
||||
self,
|
||||
func: Callable[[Vect3], Vect3],
|
||||
func: Callable[[Vect3Array], Vect3Array],
|
||||
opacity: float = 1,
|
||||
recurse: bool = True
|
||||
) -> Self:
|
||||
|
@ -1344,8 +1340,9 @@ class Mobject(object):
|
|||
Func should take in a point in R3 and output an rgb value
|
||||
"""
|
||||
for mob in self.get_family(recurse):
|
||||
rgba_array = [[*func(point), opacity] for point in mob.get_points()]
|
||||
mob.set_rgba_array(rgba_array)
|
||||
points = mob.get_points()
|
||||
opacity = np.ones((points.shape[0], 1)) * opacity
|
||||
mob.set_rgba_array(np.hstack((func(points), opacity)))
|
||||
return self
|
||||
|
||||
@affects_family_data
|
||||
|
|
|
@ -164,7 +164,7 @@ class NumberLine(Line):
|
|||
**number_config
|
||||
) -> DecimalNumber:
|
||||
number_config = merge_dicts_recursively(
|
||||
self.decimal_number_config, number_config,
|
||||
number_config, self.decimal_number_config,
|
||||
)
|
||||
if direction is None:
|
||||
direction = self.line_to_number_direction
|
||||
|
@ -182,9 +182,13 @@ class NumberLine(Line):
|
|||
if x < 0 and direction[0] == 0:
|
||||
# Align without the minus sign
|
||||
num_mob.shift(num_mob[0].get_width() * LEFT / 2)
|
||||
if x == unit and unit_tex:
|
||||
if abs(x) == unit and unit_tex:
|
||||
center = num_mob.get_center()
|
||||
num_mob.remove(num_mob[0])
|
||||
if x > 0:
|
||||
num_mob.remove(num_mob[0])
|
||||
else:
|
||||
num_mob.remove(num_mob[1])
|
||||
num_mob[0].next_to(num_mob[1], LEFT, buff=num_mob[0].get_width() / 4)
|
||||
num_mob.move_to(center)
|
||||
return num_mob
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import io
|
|||
from pathlib import Path
|
||||
|
||||
from manimlib.constants import RIGHT
|
||||
from manimlib.constants import TAU
|
||||
from manimlib.logger import log
|
||||
from manimlib.mobject.geometry import Circle
|
||||
from manimlib.mobject.geometry import Line
|
||||
|
@ -16,8 +17,10 @@ from manimlib.mobject.geometry import Polyline
|
|||
from manimlib.mobject.geometry import Rectangle
|
||||
from manimlib.mobject.geometry import RoundedRectangle
|
||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||
from manimlib.utils.bezier import quadratic_bezier_points_for_arc
|
||||
from manimlib.utils.images import get_full_vector_image_path
|
||||
from manimlib.utils.iterables import hash_obj
|
||||
from manimlib.utils.space_ops import rotation_about_z
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
|
@ -300,8 +303,9 @@ class VMobjectFromSVGPath(VMobject):
|
|||
path_obj: se.Path,
|
||||
**kwargs
|
||||
):
|
||||
# Get rid of arcs
|
||||
path_obj.approximate_arcs_with_quads()
|
||||
# caches (transform.inverse(), rot, shift)
|
||||
self.transform_cache: tuple[se.Matrix, np.ndarray, np.ndarray] | None = None
|
||||
|
||||
self.path_obj = path_obj
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
@ -328,13 +332,55 @@ class VMobjectFromSVGPath(VMobject):
|
|||
}
|
||||
for segment in self.path_obj:
|
||||
segment_class = segment.__class__
|
||||
func, attr_names = segment_class_to_func_map[segment_class]
|
||||
points = [
|
||||
_convert_point_to_3d(*segment.__getattribute__(attr_name))
|
||||
for attr_name in attr_names
|
||||
]
|
||||
func(*points)
|
||||
if segment_class is se.Arc:
|
||||
self.handle_arc(segment)
|
||||
else:
|
||||
func, attr_names = segment_class_to_func_map[segment_class]
|
||||
points = [
|
||||
_convert_point_to_3d(*segment.__getattribute__(attr_name))
|
||||
for attr_name in attr_names
|
||||
]
|
||||
func(*points)
|
||||
|
||||
# Get rid of the side effect of trailing "Z M" commands.
|
||||
if self.has_new_path_started():
|
||||
self.resize_points(self.get_num_points() - 2)
|
||||
|
||||
def handle_arc(self, arc: se.Arc) -> None:
|
||||
if self.transform_cache is not None:
|
||||
transform, rot, shift = self.transform_cache
|
||||
else:
|
||||
# The transform obtained in this way considers the combined effect
|
||||
# of all parent group transforms in the SVG.
|
||||
# Therefore, the arc can be transformed inversely using this transform
|
||||
# to correctly compute the arc path before transforming it back.
|
||||
transform = se.Matrix(self.path_obj.values.get('transform', ''))
|
||||
rot = np.array([
|
||||
[transform.a, transform.c],
|
||||
[transform.b, transform.d]
|
||||
])
|
||||
shift = np.array([transform.e, transform.f, 0])
|
||||
transform.inverse()
|
||||
self.transform_cache = (transform, rot, shift)
|
||||
|
||||
# Apply inverse transformation to the arc so that its path can be correctly computed
|
||||
arc *= transform
|
||||
|
||||
# The value of n_components is chosen based on the implementation of VMobject.arc_to
|
||||
n_components = int(np.ceil(8 * abs(arc.sweep) / TAU))
|
||||
|
||||
# Obtain the required angular segments on the unit circle
|
||||
arc_points = quadratic_bezier_points_for_arc(arc.sweep, n_components)
|
||||
arc_points @= np.array(rotation_about_z(arc.get_start_t())).T
|
||||
|
||||
# Transform to an ellipse, considering rotation and translating the ellipse center
|
||||
arc_points[:, 0] *= arc.rx
|
||||
arc_points[:, 1] *= arc.ry
|
||||
arc_points @= np.array(rotation_about_z(arc.get_rotation().as_radians)).T
|
||||
arc_points += [*arc.center, 0]
|
||||
|
||||
# Transform back
|
||||
arc_points[:, :2] @= rot.T
|
||||
arc_points += shift
|
||||
|
||||
self.append_points(arc_points[1:])
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
addict
|
||||
appdirs
|
||||
audioop-lts
|
||||
colour
|
||||
diskcache
|
||||
ipython>=8.18.0
|
||||
|
@ -20,6 +21,7 @@ pyyaml
|
|||
rich
|
||||
scipy
|
||||
screeninfo
|
||||
setuptools
|
||||
skia-pathops
|
||||
svgelements>=1.8.1
|
||||
sympy
|
||||
|
|
|
@ -31,6 +31,7 @@ include_package_data = True
|
|||
install_requires =
|
||||
addict
|
||||
appdirs
|
||||
audioop-lts
|
||||
colour
|
||||
diskcache
|
||||
ipython>=8.18.0
|
||||
|
@ -51,6 +52,7 @@ install_requires =
|
|||
rich
|
||||
scipy
|
||||
screeninfo
|
||||
setuptools
|
||||
skia-pathops
|
||||
svgelements>=1.8.1
|
||||
sympy
|
||||
|
|
Loading…
Add table
Reference in a new issue