mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Incremental
This commit is contained in:
parent
d24eab9979
commit
6365de0b81
2 changed files with 77 additions and 25 deletions
|
@ -33,6 +33,9 @@ from topics.graph_scene import *
|
||||||
# (and it will be done, but first I'll figure out what I'm doing with all this...)
|
# (and it will be done, but first I'll figure out what I'm doing with all this...)
|
||||||
# -SR
|
# -SR
|
||||||
|
|
||||||
|
# This turns counterclockwise revs into their color. Beware, we use CCW angles
|
||||||
|
# in all display code, but generally think in this video's script in terms of
|
||||||
|
# CW angles
|
||||||
def rev_to_rgba(alpha):
|
def rev_to_rgba(alpha):
|
||||||
alpha = (0.5 - alpha) % 1 # For convenience, to go CW from red on left instead of CCW from right
|
alpha = (0.5 - alpha) % 1 # For convenience, to go CW from red on left instead of CCW from right
|
||||||
# 0 is red, 1/6 is yellow, 1/3 is green, 2/3 is blue
|
# 0 is red, 1/6 is yellow, 1/3 is green, 2/3 is blue
|
||||||
|
@ -76,7 +79,7 @@ def point_to_rgba(point):
|
||||||
rgba = rev_to_rgba(rev)
|
rgba = rev_to_rgba(rev)
|
||||||
base_size = np.sqrt(point[0]**2 + point[1]**2)
|
base_size = np.sqrt(point[0]**2 + point[1]**2)
|
||||||
rescaled_size = np.sqrt(base_size/(base_size + 1))
|
rescaled_size = np.sqrt(base_size/(base_size + 1))
|
||||||
return rgba * rescaled_size
|
return rgba * [rescaled_size, rescaled_size, rescaled_size, 1] # Preserve alpha
|
||||||
|
|
||||||
positive_color = rev_to_color(0)
|
positive_color = rev_to_color(0)
|
||||||
negative_color = rev_to_color(0.5)
|
negative_color = rev_to_color(0.5)
|
||||||
|
@ -541,8 +544,16 @@ class ColorMappedByFuncScene(Scene):
|
||||||
self.pos_to_color_func = self.func
|
self.pos_to_color_func = self.func
|
||||||
|
|
||||||
# func_hash hashes the function at some random points
|
# func_hash hashes the function at some random points
|
||||||
func_hash_points = [(-0.93, 1), (1.3, -2.7), (20.5, 4)]
|
jitter_val = 0.1
|
||||||
to_hash = tuple((self.func(p)[0], self.func(p)[1]) for p in func_hash_points)
|
line_coords = np.linspace(-10, 10) + jitter_val
|
||||||
|
func_hash_points = it.product(line_coords, line_coords)
|
||||||
|
def mini_hasher(p):
|
||||||
|
func_val = self.func(p)
|
||||||
|
color_func_val = point_to_rgba(p)
|
||||||
|
if color_func_val[3] != 1.0:
|
||||||
|
print "Warning! point_to_rgba assigns fractional alpha", color_func_val[3]
|
||||||
|
return tuple(func_val), tuple(color_func_val)
|
||||||
|
to_hash = tuple(mini_hasher(p) for p in func_hash_points)
|
||||||
func_hash = hash(to_hash)
|
func_hash = hash(to_hash)
|
||||||
full_hash = hash((func_hash, self.camera.pixel_shape))
|
full_hash = hash((func_hash, self.camera.pixel_shape))
|
||||||
self.background_image_file = os.path.join(
|
self.background_image_file = os.path.join(
|
||||||
|
@ -584,11 +595,23 @@ class PureColorMap(ColorMappedByFuncScene):
|
||||||
"show_num_plane" : False
|
"show_num_plane" : False
|
||||||
}
|
}
|
||||||
|
|
||||||
class ColorMappedByFuncStill(ColorMappedByFuncScene):
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
ColorMappedByFuncScene.construct(self)
|
ColorMappedByFuncScene.construct(self)
|
||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
|
# This sets self.background_image_file, but does not display it as the background
|
||||||
|
class ColorMappedObjectsScene(ColorMappedByFuncScene):
|
||||||
|
CONFIG = {
|
||||||
|
"show_num_plane" : False
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
ColorMappedByFuncScene.construct(self)
|
||||||
|
|
||||||
|
# Clearing background
|
||||||
|
self.camera.background_image = None
|
||||||
|
self.camera.init_background()
|
||||||
|
|
||||||
class PiWalker(ColorMappedByFuncScene):
|
class PiWalker(ColorMappedByFuncScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"walk_coords" : [],
|
"walk_coords" : [],
|
||||||
|
@ -655,7 +678,7 @@ class PiWalkerCircle(PiWalker):
|
||||||
PiWalker.setup(self)
|
PiWalker.setup(self)
|
||||||
|
|
||||||
# TODO: Give drawn lines a bit of buffer, so that the rectangle's corners are filled in
|
# TODO: Give drawn lines a bit of buffer, so that the rectangle's corners are filled in
|
||||||
class EquationSolver2d(ColorMappedByFuncScene):
|
class EquationSolver2d(ColorMappedObjectsScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"camera_config" : {"use_z_coordinate_for_display_order": True},
|
"camera_config" : {"use_z_coordinate_for_display_order": True},
|
||||||
"initial_lower_x" : -5.1,
|
"initial_lower_x" : -5.1,
|
||||||
|
@ -671,15 +694,8 @@ class EquationSolver2d(ColorMappedByFuncScene):
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
print "Z order enabled?", self.camera.use_z_coordinate_for_display_order
|
ColorMappedObjectsScene.construct(self)
|
||||||
|
|
||||||
ColorMappedByFuncScene.construct(self)
|
|
||||||
num_plane = self.num_plane
|
num_plane = self.num_plane
|
||||||
self.remove(num_plane)
|
|
||||||
|
|
||||||
# Clearing background
|
|
||||||
self.camera.background_image = None
|
|
||||||
self.camera.init_background()
|
|
||||||
|
|
||||||
rev_func = lambda p : point_to_rev(self.func(p))
|
rev_func = lambda p : point_to_rev(self.func(p))
|
||||||
clockwise_rev_func = lambda p : -rev_func(p)
|
clockwise_rev_func = lambda p : -rev_func(p)
|
||||||
|
@ -906,10 +922,9 @@ class FuncRotater(Animation):
|
||||||
|
|
||||||
def update_mobject(self, alpha):
|
def update_mobject(self, alpha):
|
||||||
Animation.update_mobject(self, alpha)
|
Animation.update_mobject(self, alpha)
|
||||||
angle_revs = self.rotate_func(alpha)
|
angle_revs = -self.rotate_func(alpha) # Negated so we interpret this clockwise
|
||||||
# We do a clockwise rotation
|
|
||||||
self.mobject.rotate(
|
self.mobject.rotate(
|
||||||
-angle_revs * TAU,
|
angle_revs * TAU,
|
||||||
about_point = ORIGIN
|
about_point = ORIGIN
|
||||||
)
|
)
|
||||||
self.mobject.set_color(rev_to_color(angle_revs))
|
self.mobject.set_color(rev_to_color(angle_revs))
|
||||||
|
@ -924,8 +939,9 @@ class TestRotater(Scene):
|
||||||
|
|
||||||
# TODO: Be careful about clockwise vs. counterclockwise convention throughout!
|
# TODO: Be careful about clockwise vs. counterclockwise convention throughout!
|
||||||
# Make sure this is correct everywhere in resulting video.
|
# Make sure this is correct everywhere in resulting video.
|
||||||
class OdometerScene(Scene):
|
class OdometerScene(ColorMappedObjectsScene):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
|
# "func" : lambda p : 100 * p # Full coloring, essentially
|
||||||
"rotate_func" : lambda x : np.sin(x * TAU),
|
"rotate_func" : lambda x : np.sin(x * TAU),
|
||||||
"run_time" : 5,
|
"run_time" : 5,
|
||||||
"dashed_line_angle" : None,
|
"dashed_line_angle" : None,
|
||||||
|
@ -933,8 +949,11 @@ class OdometerScene(Scene):
|
||||||
}
|
}
|
||||||
|
|
||||||
def construct(self):
|
def construct(self):
|
||||||
|
ColorMappedObjectsScene.construct(self)
|
||||||
|
|
||||||
radius = 1.3
|
radius = 1.3
|
||||||
circle = Circle(center = ORIGIN, radius = radius)
|
circle = Circle(center = ORIGIN, radius = radius)
|
||||||
|
circle.color_using_background_image(self.background_image_file)
|
||||||
self.add(circle)
|
self.add(circle)
|
||||||
|
|
||||||
if self.dashed_line_angle:
|
if self.dashed_line_angle:
|
||||||
|
@ -943,9 +962,13 @@ class OdometerScene(Scene):
|
||||||
dashed_line.rotate(-self.dashed_line_angle * TAU, about_point = ORIGIN)
|
dashed_line.rotate(-self.dashed_line_angle * TAU, about_point = ORIGIN)
|
||||||
self.add(dashed_line)
|
self.add(dashed_line)
|
||||||
|
|
||||||
num_display = DecimalNumber(0, include_background_rectangle = False).set_stroke(1)
|
num_display = DecimalNumber(0, include_background_rectangle = False)
|
||||||
num_display.move_to(2 * DOWN)
|
num_display.move_to(2 * DOWN)
|
||||||
|
|
||||||
|
caption = TextMobject("turns clockwise")
|
||||||
|
caption.next_to(num_display, DOWN)
|
||||||
|
self.add(caption)
|
||||||
|
|
||||||
display_val_bias = 0
|
display_val_bias = 0
|
||||||
if self.biased_display_start != None:
|
if self.biased_display_start != None:
|
||||||
display_val_bias = self.biased_display_start - self.rotate_func(0)
|
display_val_bias = self.biased_display_start - self.rotate_func(0)
|
||||||
|
@ -1139,6 +1162,7 @@ class HasItsLimitations(Scene):
|
||||||
curved_arrow.generate_points()
|
curved_arrow.generate_points()
|
||||||
curved_arrow.add_tip()
|
curved_arrow.add_tip()
|
||||||
curved_arrow.move_arc_center_to(base_point + RIGHT)
|
curved_arrow.move_arc_center_to(base_point + RIGHT)
|
||||||
|
# Could do something smoother, with arrowhead moving along partial arc?
|
||||||
self.play(ShowCreation(curved_arrow))
|
self.play(ShowCreation(curved_arrow))
|
||||||
|
|
||||||
output_dot = Dot(base_point + 2 * RIGHT, color = dot_color)
|
output_dot = Dot(base_point + 2 * RIGHT, color = dot_color)
|
||||||
|
@ -1326,6 +1350,33 @@ class Initial2dFuncSceneWithoutMorphing(Scene):
|
||||||
line = Line(points[i], points[i + 1], color = RED)
|
line = Line(points[i], points[i + 1], color = RED)
|
||||||
self.play(ShowCreation(line))
|
self.play(ShowCreation(line))
|
||||||
|
|
||||||
|
class DemonstrateColorMapping(ColorMappedObjectsScene):
|
||||||
|
CONFIG = {
|
||||||
|
"show_num_plane" : False
|
||||||
|
}
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
ColorMappedObjectsScene.construct(self)
|
||||||
|
|
||||||
|
circle = Circle()
|
||||||
|
circle.color_using_background_image(self.background_image_file)
|
||||||
|
|
||||||
|
ray = Line(ORIGIN, 10 * RIGHT)
|
||||||
|
ray.color_using_background_image(self.background_image_file)
|
||||||
|
|
||||||
|
self.play(ShowCreation(circle))
|
||||||
|
|
||||||
|
self.play(ShowCreation(ray))
|
||||||
|
|
||||||
|
scale_factor = 5
|
||||||
|
self.play(ApplyMethod(circle.scale, scale_factor))
|
||||||
|
|
||||||
|
self.play(ApplyMethod(circle.scale, fdiv(1, scale_factor**2)))
|
||||||
|
|
||||||
|
self.play(ApplyMethod(circle.scale, scale_factor))
|
||||||
|
|
||||||
|
self.play(Rotating(ray, about_point = ORIGIN))
|
||||||
|
|
||||||
# TODO: Illustrations for introducing domain coloring
|
# TODO: Illustrations for introducing domain coloring
|
||||||
|
|
||||||
# TODO: Bunch of Pi walker scenes
|
# TODO: Bunch of Pi walker scenes
|
||||||
|
|
|
@ -464,21 +464,22 @@ class Succession(Animation):
|
||||||
self.current_alpha = alpha
|
self.current_alpha = alpha
|
||||||
return
|
return
|
||||||
|
|
||||||
gt_alpha_list = filter(
|
gt_alpha_iter = it.ifilter(
|
||||||
lambda i : self.critical_alphas[i+1] >= alpha,
|
lambda i : self.critical_alphas[i+1] >= alpha,
|
||||||
range(len(self.critical_alphas)-1)
|
range(self.num_anims)
|
||||||
)
|
)
|
||||||
if gt_alpha_list:
|
i = next(gt_alpha_iter, None)
|
||||||
i = gt_alpha_list[0]
|
if i == None:
|
||||||
else:
|
# In this case, we assume what is happening is that alpha is 1.0,
|
||||||
|
# but that rounding error is causing us to overshoot the end of
|
||||||
|
# self.critical_alphas (which is also 1.0)
|
||||||
if not abs(alpha - 1) < 0.001:
|
if not abs(alpha - 1) < 0.001:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Rounding error not near alpha=1 in Succession.update_mobject," + \
|
"Rounding error not near alpha=1 in Succession.update_mobject," + \
|
||||||
"instead alpha = %f"%alpha
|
"instead alpha = %f"%alpha
|
||||||
)
|
)
|
||||||
print self.critical_alphas, alpha
|
print self.critical_alphas, alpha
|
||||||
i = len(self.critical_alphas) - 2
|
i = self.num_anims - 1
|
||||||
#
|
|
||||||
|
|
||||||
# At this point, we should have self.critical_alphas[i] <= alpha <= self.critical_alphas[i +1]
|
# At this point, we should have self.critical_alphas[i] <= alpha <= self.critical_alphas[i +1]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue