mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
resolve conflict
This commit is contained in:
commit
a0ed9edb42
17 changed files with 134 additions and 60 deletions
|
@ -1,7 +1,6 @@
|
|||
from manimlib.animation.animation import Animation
|
||||
from manimlib.animation.composition import Succession
|
||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||
from manimlib.mobject.mobject import Group
|
||||
from manimlib.utils.bezier import integer_interpolate
|
||||
from manimlib.utils.config_ops import digest_config
|
||||
from manimlib.utils.rate_functions import linear
|
||||
|
@ -147,7 +146,7 @@ class Write(DrawBorderThenFill):
|
|||
else:
|
||||
self.run_time = 2
|
||||
if self.lag_ratio is None:
|
||||
self.lag_ratio = min(4.0 / length, 0.2)
|
||||
self.lag_ratio = min(4.0 / (length + 1.0), 0.2)
|
||||
|
||||
|
||||
class ShowIncreasingSubsets(Animation):
|
||||
|
|
|
@ -17,7 +17,6 @@ class Broadcast(LaggedStart):
|
|||
"remover": True,
|
||||
"lag_ratio": 0.2,
|
||||
"run_time": 3,
|
||||
"remover": True,
|
||||
}
|
||||
|
||||
def __init__(self, focal_point, **kwargs):
|
||||
|
|
|
@ -65,6 +65,12 @@ def parse_cli():
|
|||
action="store_true",
|
||||
help="Show window in full screen",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p", "--presenter_mode",
|
||||
action="store_true",
|
||||
help="scene will stay paused during wait calls until "
|
||||
"space bar or right arrow is hit, like a slide show"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-g", "--save_pngs",
|
||||
action="store_true",
|
||||
|
@ -306,6 +312,7 @@ def get_configuration(args):
|
|||
"start_at_animation_number": args.start_at_animation_number,
|
||||
"end_at_animation_number": None,
|
||||
"preview": not write_file,
|
||||
"presenter_mode": args.presenter_mode,
|
||||
"leave_progress_bars": args.leave_progress_bars,
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ def get_scene_config(config):
|
|||
"end_at_animation_number",
|
||||
"leave_progress_bars",
|
||||
"preview",
|
||||
"presenter_mode",
|
||||
]
|
||||
])
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ class CoordinateSystem():
|
|||
class Axes(VGroup, CoordinateSystem):
|
||||
CONFIG = {
|
||||
"axis_config": {
|
||||
"include_tip": True,
|
||||
"include_tip": False,
|
||||
"numbers_to_exclude": [0],
|
||||
},
|
||||
"x_axis_config": {},
|
||||
|
|
|
@ -44,6 +44,8 @@ class ParametricCurve(VMobject):
|
|||
self.add_points_as_corners(points[1:])
|
||||
if self.use_smoothing:
|
||||
self.make_approximately_smooth()
|
||||
if not self.has_points():
|
||||
self.set_points([self.t_func(t_min)])
|
||||
return self
|
||||
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ class Matrix(VMobject):
|
|||
"\\left[",
|
||||
"\\begin{array}{c}",
|
||||
*height * ["\\quad \\\\"],
|
||||
"\\end{array}"
|
||||
"\\end{array}",
|
||||
"\\right]",
|
||||
]))[0]
|
||||
bracket_pair.set_height(
|
||||
|
|
|
@ -899,6 +899,21 @@ class Mobject(object):
|
|||
self.set_depth(max_depth, **kwargs)
|
||||
return self
|
||||
|
||||
def set_min_width(self, min_width: float, **kwargs):
|
||||
if self.get_width() < min_width:
|
||||
self.set_width(min_width, **kwargs)
|
||||
return self
|
||||
|
||||
def set_min_height(self, min_height: float, **kwargs):
|
||||
if self.get_height() < min_height:
|
||||
self.set_height(min_height, **kwargs)
|
||||
return self
|
||||
|
||||
def set_min_depth(self, min_depth: float, **kwargs):
|
||||
if self.get_depth() < min_depth:
|
||||
self.set_depth(min_depth, **kwargs)
|
||||
return self
|
||||
|
||||
def set_coord(self, value: float, dim: int, direction: np.ndarray = ORIGIN):
|
||||
curr = self.get_coord(dim, direction)
|
||||
shift_vect = np.zeros(self.dim)
|
||||
|
@ -1295,21 +1310,38 @@ class Mobject(object):
|
|||
def match_depth(self, mobject: "Mobject", **kwargs):
|
||||
return self.match_dim_size(mobject, 2, **kwargs)
|
||||
|
||||
def match_coord(self, mobject: "Mobject", dim: int, direction: np.ndarray = ORIGIN):
|
||||
return self.set_coord(
|
||||
mobject.get_coord(dim, direction),
|
||||
dim=dim,
|
||||
direction=direction,
|
||||
)
|
||||
def match_coord(
|
||||
self,
|
||||
mobject_or_point: "Mobject" | np.ndarray,
|
||||
dim: int,
|
||||
direction: np.ndarray = ORIGIN
|
||||
):
|
||||
if isinstance(mobject_or_point, Mobject):
|
||||
coord = mobject_or_point.get_coord(dim, direction)
|
||||
else:
|
||||
coord = mobject_or_point[dim]
|
||||
return self.set_coord(coord, dim=dim, direction=direction)
|
||||
|
||||
def match_x(self, mobject: "Mobject", direction: np.ndarray = ORIGIN):
|
||||
return self.match_coord(mobject, 0, direction)
|
||||
def match_x(
|
||||
self,
|
||||
mobject_or_point: "Mobject" | np.ndarray,
|
||||
direction: np.ndarray = ORIGIN
|
||||
):
|
||||
return self.match_coord(mobject_or_point, 0, direction)
|
||||
|
||||
def match_y(self, mobject: "Mobject", direction: np.ndarray = ORIGIN):
|
||||
return self.match_coord(mobject, 1, direction)
|
||||
def match_y(
|
||||
self,
|
||||
mobject_or_point: "Mobject" | np.ndarray,
|
||||
direction: np.ndarray = ORIGIN
|
||||
):
|
||||
return self.match_coord(mobject_or_point, 1, direction)
|
||||
|
||||
def match_z(self, mobject: "Mobject", direction: np.ndarray = ORIGIN):
|
||||
return self.match_coord(mobject, 2, direction)
|
||||
def match_z(
|
||||
self,
|
||||
mobject_or_point: "Mobject" | np.ndarray,
|
||||
direction: np.ndarray = ORIGIN
|
||||
):
|
||||
return self.match_coord(mobject_or_point, 2, direction)
|
||||
|
||||
def align_to(
|
||||
self,
|
||||
|
|
|
@ -318,6 +318,9 @@ class Bubble(SVGMobject):
|
|||
self.content = Mobject()
|
||||
self.refresh_triangulation()
|
||||
|
||||
def init_colors(self):
|
||||
VMobject.init_colors(self)
|
||||
|
||||
def get_tip(self):
|
||||
# TODO, find a better way
|
||||
return self.get_corner(DOWN + self.direction) - 0.6 * self.direction
|
||||
|
|
|
@ -13,7 +13,6 @@ from manimlib.mobject.geometry import Polygon
|
|||
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 VGroup
|
||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||
from manimlib.utils.config_ops import digest_config
|
||||
from manimlib.utils.directories import get_mobject_data_dir
|
||||
|
@ -321,4 +320,4 @@ class VMobjectFromSVGPath(VMobject):
|
|||
_convert_point_to_3d(*segment.__getattribute__(attr_name))
|
||||
for attr_name in attr_names
|
||||
]
|
||||
func(*points)
|
||||
func(*points)
|
|
@ -36,20 +36,19 @@ class SingleStringTex(VMobject):
|
|||
assert(isinstance(tex_string, str))
|
||||
self.tex_string = tex_string
|
||||
if tex_string not in tex_string_with_color_to_mob_map:
|
||||
with display_during_execution(f" Writing \"{tex_string}\""):
|
||||
full_tex = self.get_tex_file_body(tex_string)
|
||||
filename = tex_to_svg_file(full_tex)
|
||||
svg_mob = SVGMobject(
|
||||
filename,
|
||||
height=None,
|
||||
color=self.color,
|
||||
stroke_width=self.stroke_width,
|
||||
path_string_config={
|
||||
"should_subdivide_sharp_curves": True,
|
||||
"should_remove_null_curves": True,
|
||||
}
|
||||
)
|
||||
tex_string_with_color_to_mob_map[(self.color, tex_string)] = svg_mob
|
||||
full_tex = self.get_tex_file_body(tex_string)
|
||||
filename = tex_to_svg_file(full_tex)
|
||||
svg_mob = SVGMobject(
|
||||
filename,
|
||||
height=None,
|
||||
color=self.color,
|
||||
stroke_width=self.stroke_width,
|
||||
path_string_config={
|
||||
"should_subdivide_sharp_curves": True,
|
||||
"should_remove_null_curves": True,
|
||||
}
|
||||
)
|
||||
tex_string_with_color_to_mob_map[(self.color, tex_string)] = svg_mob
|
||||
self.add(*(
|
||||
sm.copy()
|
||||
for sm in tex_string_with_color_to_mob_map[(self.color, tex_string)]
|
||||
|
@ -140,7 +139,11 @@ class SingleStringTex(VMobject):
|
|||
Makes Tex resiliant to unmatched braces
|
||||
"""
|
||||
num_unclosed_brackets = 0
|
||||
for char in tex:
|
||||
for i in range(len(tex)):
|
||||
if i > 0 and tex[i - 1] == "\\":
|
||||
# So as to not count '\{' type expressions
|
||||
continue
|
||||
char = tex[i]
|
||||
if char == "{":
|
||||
num_unclosed_brackets += 1
|
||||
elif char == "}":
|
||||
|
|
|
@ -35,6 +35,8 @@ class PMobject(Mobject):
|
|||
return self
|
||||
|
||||
def set_points(self, points: npt.ArrayLike):
|
||||
if len(points) == 0:
|
||||
points = np.zeros((0, 3))
|
||||
super().set_points(points)
|
||||
self.resize_points(len(points))
|
||||
return self
|
||||
|
@ -54,14 +56,18 @@ class PMobject(Mobject):
|
|||
if color is not None:
|
||||
if opacity is None:
|
||||
opacity = self.data["rgbas"][-1, 3]
|
||||
new_rgbas = np.repeat(
|
||||
rgbas = np.repeat(
|
||||
[color_to_rgba(color, opacity)],
|
||||
len(points),
|
||||
axis=0
|
||||
)
|
||||
elif rgbas is not None:
|
||||
new_rgbas = rgbas
|
||||
self.data["rgbas"][-len(new_rgbas):] = new_rgbas
|
||||
if rgbas is not None:
|
||||
self.data["rgbas"][-len(rgbas):] = rgbas
|
||||
return self
|
||||
|
||||
def add_point(self, point, rgba=None, color=None, opacity=None):
|
||||
rgbas = None if rgba is None else [rgba]
|
||||
self.add_points([point], rgbas, color, opacity)
|
||||
return self
|
||||
|
||||
def set_color_by_gradient(self, *colors: ManimColor):
|
||||
|
|
|
@ -277,7 +277,6 @@ class DiscreteGraphScene(Scene):
|
|||
def trace_cycle(self, cycle=None, color="yellow", run_time=2.0):
|
||||
if cycle is None:
|
||||
cycle = self.graph.region_cycles[0]
|
||||
time_per_edge = run_time / len(cycle)
|
||||
next_in_cycle = it.cycle(cycle)
|
||||
next(next_in_cycle) # jump one ahead
|
||||
self.traced_cycle = Mobject(*[
|
||||
|
|
|
@ -36,6 +36,7 @@ class Scene(object):
|
|||
"end_at_animation_number": None,
|
||||
"leave_progress_bars": False,
|
||||
"preview": True,
|
||||
"presenter_mode": False,
|
||||
"linger_after_completion": True,
|
||||
}
|
||||
|
||||
|
@ -62,6 +63,7 @@ class Scene(object):
|
|||
# Items associated with interaction
|
||||
self.mouse_point = Point()
|
||||
self.mouse_drag_point = Point()
|
||||
self.hold_on_wait = not self.presenter_mode
|
||||
|
||||
# Much nicer to work with deterministic scenes
|
||||
if self.random_seed is not None:
|
||||
|
@ -114,7 +116,7 @@ class Scene(object):
|
|||
if self.quit_interaction:
|
||||
self.unlock_mobject_data()
|
||||
|
||||
def embed(self):
|
||||
def embed(self, close_scene_on_exit=True):
|
||||
if not self.preview:
|
||||
# If the scene is just being
|
||||
# written, ignore embed calls
|
||||
|
@ -139,8 +141,9 @@ class Scene(object):
|
|||
log.info("Tips: Now the embed iPython terminal is open. But you can't interact with"
|
||||
" the window directly. To do so, you need to type `touch()` or `self.interact()`")
|
||||
shell(local_ns=local_ns, stack_depth=2)
|
||||
# End scene when exiting an embed.
|
||||
raise EndSceneEarlyException()
|
||||
# End scene when exiting an embed
|
||||
if close_scene_on_exit:
|
||||
raise EndSceneEarlyException()
|
||||
|
||||
def __str__(self):
|
||||
return self.__class__.__name__
|
||||
|
@ -432,6 +435,11 @@ class Scene(object):
|
|||
def unlock_mobject_data(self):
|
||||
self.camera.release_static_mobjects()
|
||||
|
||||
def refresh_locked_data(self):
|
||||
self.unlock_mobject_data()
|
||||
self.lock_static_mobject_data()
|
||||
return self
|
||||
|
||||
def begin_animations(self, animations):
|
||||
for animation in animations:
|
||||
animation.begin()
|
||||
|
@ -477,19 +485,30 @@ class Scene(object):
|
|||
self.unlock_mobject_data()
|
||||
|
||||
@handle_play_like_call
|
||||
def wait(self, duration=DEFAULT_WAIT_TIME, stop_condition=None):
|
||||
def wait(self,
|
||||
duration=DEFAULT_WAIT_TIME,
|
||||
stop_condition=None,
|
||||
note=None,
|
||||
ignore_presenter_mode=False):
|
||||
if note:
|
||||
log.info(note)
|
||||
self.update_mobjects(dt=0) # Any problems with this?
|
||||
self.lock_static_mobject_data()
|
||||
time_progression = self.get_wait_time_progression(duration, stop_condition)
|
||||
last_t = 0
|
||||
for t in time_progression:
|
||||
dt = t - last_t
|
||||
last_t = t
|
||||
self.update_frame(dt)
|
||||
self.emit_frame()
|
||||
if stop_condition is not None and stop_condition():
|
||||
time_progression.close()
|
||||
break
|
||||
if self.presenter_mode and not self.skip_animations and not ignore_presenter_mode:
|
||||
while self.hold_on_wait:
|
||||
self.update_frame(dt=1 / self.camera.frame_rate)
|
||||
self.hold_on_wait = True
|
||||
else:
|
||||
time_progression = self.get_wait_time_progression(duration, stop_condition)
|
||||
last_t = 0
|
||||
for t in time_progression:
|
||||
dt = t - last_t
|
||||
last_t = t
|
||||
self.update_frame(dt)
|
||||
self.emit_frame()
|
||||
if stop_condition is not None and stop_condition():
|
||||
time_progression.close()
|
||||
break
|
||||
self.unlock_mobject_data()
|
||||
return self
|
||||
|
||||
|
@ -610,6 +629,10 @@ class Scene(object):
|
|||
self.camera.frame.to_default_state()
|
||||
elif char == "q":
|
||||
self.quit_interaction = True
|
||||
elif char == " ":
|
||||
self.hold_on_wait = False
|
||||
elif char == "e":
|
||||
self.embed(close_scene_on_exit=False)
|
||||
|
||||
def on_resize(self, width: int, height: int):
|
||||
self.camera.reset_pixel_shape(width, height)
|
||||
|
|
|
@ -287,9 +287,6 @@ class LinearTransformationScene(VectorScene):
|
|||
},
|
||||
"background_plane_kwargs": {
|
||||
"color": GREY,
|
||||
"axis_config": {
|
||||
"stroke_color": GREY_B,
|
||||
},
|
||||
"axis_config": {
|
||||
"color": GREY,
|
||||
},
|
||||
|
|
|
@ -21,10 +21,10 @@ def bezier(
|
|||
n = len(points) - 1
|
||||
|
||||
def result(t):
|
||||
return sum([
|
||||
return sum(
|
||||
((1 - t)**(n - k)) * (t**k) * choose(n, k) * point
|
||||
for k, point in enumerate(points)
|
||||
])
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import inspect
|
||||
import numpy as np
|
||||
from scipy import special
|
||||
import math
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
|
@ -10,7 +10,11 @@ def sigmoid(x):
|
|||
|
||||
@lru_cache(maxsize=10)
|
||||
def choose(n, k):
|
||||
return special.comb(n, k, exact=True)
|
||||
return math.comb(n, k)
|
||||
|
||||
|
||||
def gen_choose(n, r):
|
||||
return np.prod(np.arange(n, n - r, -1)) / math.factorial(r)
|
||||
|
||||
|
||||
def get_num_args(function):
|
||||
|
|
Loading…
Add table
Reference in a new issue