mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
Farther along EoLA chapter 3
This commit is contained in:
parent
b16695b6f3
commit
627f16b057
12 changed files with 408 additions and 168 deletions
|
@ -30,6 +30,12 @@ class Animation(object):
|
|||
self.name = self.__class__.__name__ + str(self.mobject)
|
||||
self.update(0)
|
||||
|
||||
def update_config(self, **kwargs):
|
||||
if "path_arc" in kwargs:
|
||||
kwargs["path_arc"]
|
||||
digest_config(self, kwargs)
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
@ -65,7 +71,7 @@ class Animation(object):
|
|||
|
||||
def set_name(self, name):
|
||||
self.name = name
|
||||
return self
|
||||
return self
|
||||
|
||||
def update_mobject(self, alpha):
|
||||
#Typically ipmlemented by subclass
|
||||
|
|
|
@ -26,6 +26,11 @@ class Transform(Animation):
|
|||
self.name += "To" + str(ending_mobject)
|
||||
self.mobject.stroke_width = ending_mobject.stroke_width
|
||||
|
||||
def update_config(self, **kwargs):
|
||||
Animation.update_config(self, **kwargs)
|
||||
if "path_arc" in kwargs:
|
||||
self.path_func = path_along_arc(kwargs["path_arc"])
|
||||
|
||||
def init_path_func(self):
|
||||
if self.path_func is not None:
|
||||
return
|
||||
|
|
|
@ -57,7 +57,7 @@ class CoordinatesAsScalars(VectorScene):
|
|||
}
|
||||
|
||||
def construct(self):
|
||||
self.lock_in_dim_grid()
|
||||
self.lock_in_faded_grid()
|
||||
|
||||
vector = self.add_vector(self.vector_coords)
|
||||
array, x_line, y_line = self.vector_to_coords(vector)
|
||||
|
@ -194,7 +194,7 @@ class CoordinatesAsScalarsExample2(CoordinatesAsScalars):
|
|||
}
|
||||
|
||||
def construct(self):
|
||||
self.lock_in_dim_grid()
|
||||
self.lock_in_faded_grid()
|
||||
|
||||
basis_vectors = self.get_basis_vectors()
|
||||
labels = self.get_basis_vector_labels()
|
||||
|
@ -246,7 +246,7 @@ class ShowVaryingLinearCombinations(VectorScene):
|
|||
"finish_by_drawing_lines" : False,
|
||||
}
|
||||
def construct(self):
|
||||
self.lock_in_dim_grid()
|
||||
self.lock_in_faded_grid()
|
||||
v1 = self.add_vector(self.vector1, color = self.vector1_color)
|
||||
v2 = self.add_vector(self.vector2, color = self.vector2_color)
|
||||
v1_label = self.label_vector(
|
||||
|
@ -651,7 +651,7 @@ class VectorsToDotsScene(VectorScene):
|
|||
"end_color" : BLUE_E,
|
||||
}
|
||||
def construct(self):
|
||||
self.lock_in_dim_grid()
|
||||
self.lock_in_faded_grid()
|
||||
|
||||
vectors = self.get_vectors()
|
||||
colors = Color(self.start_color).range_to(
|
||||
|
@ -761,9 +761,6 @@ class VectorsInThePlane(VectorsToDotsScene):
|
|||
)
|
||||
self.remove(*vectors)
|
||||
self.dither()
|
||||
self.play(Homotopy(plane_wave_homotopy, plane, run_time = 3))
|
||||
self.play(Transform(plane, NumberPlane(), rate_func = rush_from))
|
||||
self.dither()
|
||||
|
||||
|
||||
class HowToThinkVectorsVsPoint(Scene):
|
||||
|
@ -1238,7 +1235,6 @@ class CheckYourUnderstanding(TeacherStudentsScene):
|
|||
self.random_blink()
|
||||
|
||||
|
||||
|
||||
class TechnicalDefinitionOfBasis(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Technical definition of basis:")
|
||||
|
@ -1288,4 +1284,3 @@ class NextVideo(Scene):
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
230
eola/chapter3.py
230
eola/chapter3.py
|
@ -75,32 +75,226 @@ class Introduction(TeacherStudentsScene):
|
|||
class ShowGridCreation(Scene):
|
||||
def construct(self):
|
||||
plane = NumberPlane()
|
||||
coords = plane.get_coordinate_labels()
|
||||
self.play(ShowCreation(plane))
|
||||
self.play(Write(coords, run_time = 5))
|
||||
coords = VMobject(*plane.get_coordinate_labels())
|
||||
self.play(ShowCreation(plane, run_time = 3))
|
||||
self.play(Write(coords, run_time = 3))
|
||||
self.dither()
|
||||
|
||||
class IntroduceLinearTransformations(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
"include_background_plane" : False
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.dither()
|
||||
self.apply_transposed_matrix([[2, 1], [1, 2]])
|
||||
self.dither()
|
||||
|
||||
lines_rule = TextMobject("Lines remain lines")
|
||||
lines_rule.shift(2*UP).to_edge(LEFT)
|
||||
origin_rule = TextMobject("Origin remains fixed")
|
||||
origin_rule.shift(2*UP).to_edge(RIGHT)
|
||||
arrow = Arrow(origin_rule, ORIGIN)
|
||||
dot = Dot(ORIGIN, radius = 0.1, color = RED)
|
||||
|
||||
for rule in lines_rule, origin_rule:
|
||||
rule.add_background_rectangle()
|
||||
|
||||
self.play(
|
||||
# FadeIn(lines_rule_rect),
|
||||
Write(lines_rule, run_time = 2),
|
||||
)
|
||||
self.dither()
|
||||
self.play(
|
||||
# FadeIn(origin_rule_rect),
|
||||
Write(origin_rule, run_time = 2),
|
||||
ShowCreation(arrow),
|
||||
GrowFromCenter(dot)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
|
||||
class SimpleLinearTransformationScene(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
"transposed_matrix" : [[2, 1], [1, 2]]
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.dither()
|
||||
self.apply_transposed_matrix(self.transposed_matrix)
|
||||
self.dither()
|
||||
|
||||
class SimpleNonlinearTransformationScene(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
"words" : "Not linear: some lines get curved"
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.dither()
|
||||
self.apply_nonlinear_transformation(self.func)
|
||||
words = TextMobject(self.words)
|
||||
words.to_corner(UP+RIGHT)
|
||||
words.highlight(RED)
|
||||
words.add_background_rectangle()
|
||||
self.play(Write(words))
|
||||
self.dither()
|
||||
|
||||
def func(self, point):
|
||||
x, y, z = point
|
||||
return (x+np.cos(y))*RIGHT + (y+np.sin(x))*UP
|
||||
|
||||
class MovingOrigin(SimpleNonlinearTransformationScene):
|
||||
CONFIG = {
|
||||
"words" : "Not linear: Origin moves"
|
||||
}
|
||||
def setup(self):
|
||||
LinearTransformationScene.setup(self)
|
||||
dot = Dot(ORIGIN, color = RED)
|
||||
self.add_transformable_mobject(dot)
|
||||
|
||||
def func(self, point):
|
||||
matrix_transform = self.get_matrix_transformation([[2, 0], [1, 1]])
|
||||
return matrix_transform(point) + 2*UP+3*LEFT
|
||||
|
||||
class SneakyNonlinearTransformation(SimpleNonlinearTransformationScene):
|
||||
CONFIG = {
|
||||
"words" : "\\dots"
|
||||
}
|
||||
def func(self, point):
|
||||
x, y, z = point
|
||||
new_x = np.sign(x)*SPACE_WIDTH*smooth(abs(x) / SPACE_WIDTH)
|
||||
new_y = np.sign(y)*SPACE_HEIGHT*smooth(abs(y) / SPACE_HEIGHT)
|
||||
return [new_x, new_y, 0]
|
||||
|
||||
class SneakyNonlinearTransformationExplained(SneakyNonlinearTransformation):
|
||||
CONFIG = {
|
||||
"words" : "Not linear: diagonal lines get curved"
|
||||
}
|
||||
def setup(self):
|
||||
LinearTransformationScene.setup(self)
|
||||
diag = Line(
|
||||
SPACE_HEIGHT*LEFT+SPACE_HEIGHT*DOWN,
|
||||
SPACE_HEIGHT*RIGHT + SPACE_HEIGHT*UP
|
||||
)
|
||||
diag.insert_n_anchor_points(20)
|
||||
diag.change_anchor_mode("smooth")
|
||||
diag.highlight(YELLOW)
|
||||
self.play(ShowCreation(diag))
|
||||
self.add_transformable_mobject(diag)
|
||||
|
||||
|
||||
class AnotherLinearTransformation(SimpleLinearTransformationScene):
|
||||
CONFIG = {
|
||||
"transposed_matrix" : [
|
||||
[3, 0],
|
||||
[1, 2]
|
||||
]
|
||||
}
|
||||
def construct(self):
|
||||
SimpleLinearTransformationScene.construct(self)
|
||||
text = TextMobject([
|
||||
"Grid lines remain",
|
||||
"parallel",
|
||||
"and",
|
||||
"evenly spaced",
|
||||
])
|
||||
glr, p, a, es = text.split()
|
||||
p.highlight(YELLOW)
|
||||
es.highlight(GREEN)
|
||||
text.add_background_rectangle()
|
||||
text.shift(-text.get_bottom())
|
||||
self.play(Write(text))
|
||||
self.dither()
|
||||
|
||||
|
||||
class Rotation(SimpleLinearTransformationScene):
|
||||
CONFIG = {
|
||||
"angle" : np.pi/3,
|
||||
}
|
||||
def construct(self):
|
||||
self.transposed_matrix = [
|
||||
[np.cos(self.angle), np.sin(self.angle)],
|
||||
[-np.sin(self.angle), np.cos(self.angle)]
|
||||
]
|
||||
SimpleLinearTransformationScene.construct(self)
|
||||
|
||||
|
||||
|
||||
class YetAnotherLinearTransformation(SimpleLinearTransformationScene):
|
||||
CONFIG = {
|
||||
"transposed_matrix" : [
|
||||
[-1, 1],
|
||||
[3, 2],
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class MoveAroundAllVectors(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
"focus_on_one_vector" : False,
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
vectors = VMobject(*[
|
||||
Vector([x, y])
|
||||
for x in np.arange(-int(SPACE_WIDTH)+0.5, int(SPACE_WIDTH)+0.5)
|
||||
for y in np.arange(-int(SPACE_HEIGHT)+0.5, int(SPACE_HEIGHT)+0.5)
|
||||
])
|
||||
vectors.submobject_gradient_highlight(PINK, BLUE_E)
|
||||
dots = VMobject(*[
|
||||
Dot(v.get_end(), color = v.get_color())
|
||||
for v in vectors.split()
|
||||
])
|
||||
|
||||
self.dither()
|
||||
self.play(ShowCreation(dots))
|
||||
self.dither()
|
||||
self.play(Transform(dots, vectors))
|
||||
self.dither()
|
||||
self.remove(dots)
|
||||
if self.focus_on_one_vector:
|
||||
vector = vectors.split()[43]#yeah, great coding Grant
|
||||
self.remove(vectors)
|
||||
self.add_vector(vector)
|
||||
self.play(*[
|
||||
FadeOut(v)
|
||||
for v in vectors.split()
|
||||
if v is not vector
|
||||
])
|
||||
self.dither()
|
||||
self.add(vector.copy().highlight(DARK_GREY))
|
||||
else:
|
||||
for vector in vectors.split():
|
||||
self.add_vector(vector)
|
||||
self.apply_transposed_matrix([[3, 0], [1, 2]])
|
||||
self.dither()
|
||||
|
||||
|
||||
class MoveAroundJustOneVector(MoveAroundAllVectors):
|
||||
CONFIG = {
|
||||
"focus_on_one_vector" : True,
|
||||
}
|
||||
|
||||
|
||||
class RotateIHat(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
i_hat, j_hat = self.get_basis_vectors()
|
||||
i_label, j_label = self.get_basis_vector_labels()
|
||||
self.play(ShowCreation(i_hat))
|
||||
self.play(Write(i_label, run_time = 1))
|
||||
self.dither()
|
||||
self.play(FadeOut(i_label))
|
||||
self.apply_transposed_matrix([[0, 1], [-1, 0]])
|
||||
self.play(Write(j_label, run_time = 1))
|
||||
self.dither()
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19,99 +19,6 @@ Y_COLOR = RED_C
|
|||
Z_COLOR = BLUE_D
|
||||
|
||||
|
||||
class LinearTransformationScene(Scene):
|
||||
CONFIG = {
|
||||
"include_background_plane" : True,
|
||||
"include_foreground_plane" : True,
|
||||
"foreground_plane_kwargs" : {
|
||||
"x_radius" : 2*SPACE_WIDTH,
|
||||
"y_radius" : 2*SPACE_HEIGHT,
|
||||
"secondary_line_ratio" : 0
|
||||
},
|
||||
"background_plane_kwargs" : {
|
||||
"color" : GREY,
|
||||
"secondary_color" : DARK_GREY,
|
||||
"axes_color" : GREY,
|
||||
},
|
||||
"show_coordinates" : False,
|
||||
"show_basis_vectors" : True,
|
||||
"i_hat_color" : X_COLOR,
|
||||
"j_hat_color" : Y_COLOR,
|
||||
}
|
||||
def setup(self):
|
||||
self.background_mobjects = []
|
||||
self.transformable_mobject = []
|
||||
self.moving_vectors = []
|
||||
|
||||
self.background_plane = NumberPlane(
|
||||
**self.background_plane_kwargs
|
||||
)
|
||||
|
||||
if self.show_coordinates:
|
||||
self.background_plane.add_coordinates()
|
||||
if self.include_background_plane:
|
||||
self.add_background_mobject(self.background_plane)
|
||||
if self.include_foreground_plane:
|
||||
self.plane = NumberPlane(**self.foreground_plane_kwargs)
|
||||
self.add_transformable_mobject(self.plane)
|
||||
if self.show_basis_vectors:
|
||||
self.add_vector((1, 0), self.i_hat_color)
|
||||
self.add_vector((0, 1), self.j_hat_color)
|
||||
|
||||
def add_background_mobject(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if mobject not in self.background_mobjects:
|
||||
self.background_mobjects.append(mobject)
|
||||
self.add(mobject)
|
||||
|
||||
def add_transformable_mobject(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if mobject not in self.transformable_mobject:
|
||||
self.transformable_mobject.append(mobject)
|
||||
self.add(mobject)
|
||||
|
||||
def add_vector(self, coords, color = YELLOW):
|
||||
vector = Vector(self.background_plane.num_pair_to_point(coords))
|
||||
vector.highlight(color)
|
||||
self.moving_vectors.append(vector)
|
||||
return vector
|
||||
|
||||
def apply_matrix(self, matrix, **kwargs):
|
||||
matrix = np.array(matrix)
|
||||
if matrix.shape == (2, 2):
|
||||
new_matrix = np.identity(3)
|
||||
new_matrix[:2, :2] = matrix
|
||||
matrix = new_matrix
|
||||
elif matrix.shape != (3, 3):
|
||||
raise "Matrix has bad dimensions"
|
||||
transpose = np.transpose(matrix)
|
||||
|
||||
def func(point):
|
||||
return np.dot(point, transpose)
|
||||
|
||||
new_vectors = [
|
||||
Vector(func(v.get_end()), color = v.get_stroke_color())
|
||||
for v in self.moving_vectors
|
||||
]
|
||||
self.play(
|
||||
ApplyPointwiseFunction(
|
||||
func,
|
||||
VMobject(*self.transformable_mobject),
|
||||
**kwargs
|
||||
),
|
||||
Transform(
|
||||
VMobject(*self.moving_vectors),
|
||||
VMobject(*new_vectors),
|
||||
**kwargs
|
||||
)
|
||||
)
|
||||
|
||||
def apply_nonlinear_transformation(self, function, **kwargs):
|
||||
pass #TODO
|
||||
|
||||
|
||||
|
||||
|
||||
class VectorScene(Scene):
|
||||
CONFIG = {
|
||||
"basis_vector_stroke_width" : 6
|
||||
|
@ -130,7 +37,7 @@ class VectorScene(Scene):
|
|||
self.add(axes)
|
||||
return axes
|
||||
|
||||
def lock_in_dim_grid(self, dimness = 0.7, axes_dimness = 0.5):
|
||||
def lock_in_faded_grid(self, dimness = 0.7, axes_dimness = 0.5):
|
||||
plane = self.add_plane()
|
||||
axes = plane.get_axes()
|
||||
plane.fade(dimness)
|
||||
|
@ -324,6 +231,112 @@ class VectorScene(Scene):
|
|||
|
||||
|
||||
|
||||
class LinearTransformationScene(VectorScene):
|
||||
CONFIG = {
|
||||
"include_background_plane" : True,
|
||||
"include_foreground_plane" : True,
|
||||
"foreground_plane_kwargs" : {
|
||||
"x_radius" : 2*SPACE_WIDTH,
|
||||
"y_radius" : 2*SPACE_HEIGHT,
|
||||
"secondary_line_ratio" : 0
|
||||
},
|
||||
"background_plane_kwargs" : {
|
||||
"color" : GREY,
|
||||
"secondary_color" : DARK_GREY,
|
||||
"axes_color" : GREY,
|
||||
"stroke_width" : 2,
|
||||
},
|
||||
"show_coordinates" : False,
|
||||
"show_basis_vectors" : True,
|
||||
"i_hat_color" : X_COLOR,
|
||||
"j_hat_color" : Y_COLOR,
|
||||
}
|
||||
def setup(self):
|
||||
self.background_mobjects = []
|
||||
self.transformable_mobject = []
|
||||
self.moving_vectors = []
|
||||
|
||||
self.background_plane = NumberPlane(
|
||||
**self.background_plane_kwargs
|
||||
)
|
||||
|
||||
if self.show_coordinates:
|
||||
self.background_plane.add_coordinates()
|
||||
if self.include_background_plane:
|
||||
self.add_background_mobject(self.background_plane)
|
||||
if self.include_foreground_plane:
|
||||
self.plane = NumberPlane(**self.foreground_plane_kwargs)
|
||||
self.add_transformable_mobject(self.plane)
|
||||
if self.show_basis_vectors:
|
||||
self.add_vector((1, 0), self.i_hat_color)
|
||||
self.add_vector((0, 1), self.j_hat_color)
|
||||
|
||||
def add_background_mobject(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if mobject not in self.background_mobjects:
|
||||
self.background_mobjects.append(mobject)
|
||||
self.add(mobject)
|
||||
|
||||
def add_transformable_mobject(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if mobject not in self.transformable_mobject:
|
||||
self.transformable_mobject.append(mobject)
|
||||
self.add(mobject)
|
||||
|
||||
def add_vector(self, vector, color = YELLOW, animate = False):
|
||||
vector = VectorScene.add_vector(
|
||||
self, vector, color = color, animate = animate
|
||||
)
|
||||
self.moving_vectors.append(vector)
|
||||
return vector
|
||||
|
||||
def get_matrix_transformation(self, transposed_matrix):
|
||||
transposed_matrix = np.array(transposed_matrix)
|
||||
if transposed_matrix.shape == (2, 2):
|
||||
new_matrix = np.identity(3)
|
||||
new_matrix[:2, :2] = transposed_matrix
|
||||
transposed_matrix = new_matrix
|
||||
elif transposed_matrix.shape != (3, 3):
|
||||
raise "Matrix has bad dimensions"
|
||||
return lambda point: np.dot(point, transposed_matrix)
|
||||
|
||||
|
||||
def get_vector_movement(self, func):
|
||||
start = VMobject(*self.moving_vectors)
|
||||
target = VMobject(*[
|
||||
Vector(func(v.get_end()), color = v.get_color())
|
||||
for v in self.moving_vectors
|
||||
])
|
||||
return Transform(start, target)
|
||||
|
||||
def apply_transposed_matrix(self, transposed_matrix, **kwargs):
|
||||
func = self.get_matrix_transformation(transposed_matrix)
|
||||
if "path_arc" not in kwargs:
|
||||
net_rotation = np.mean([
|
||||
angle_of_vector(func(RIGHT)),
|
||||
angle_of_vector(func(UP))-np.pi/2
|
||||
])
|
||||
kwargs["path_arc"] = net_rotation
|
||||
self.apply_function(func, **kwargs)
|
||||
|
||||
def apply_nonlinear_transformation(self, function, **kwargs):
|
||||
self.plane.prepare_for_nonlinear_transform(100)
|
||||
self.apply_function(function, **kwargs)
|
||||
|
||||
def apply_function(self, function, **kwargs):
|
||||
if "run_time" not in kwargs:
|
||||
kwargs["run_time"] = 3
|
||||
self.play(
|
||||
ApplyPointwiseFunction(
|
||||
function,
|
||||
VMobject(*self.transformable_mobject),
|
||||
),
|
||||
self.get_vector_movement(function),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -22,8 +22,10 @@ class Mobject(object):
|
|||
"name" : None,
|
||||
"dim" : 3,
|
||||
"target" : None,
|
||||
#Options are lagged_start, one_at_a_time, all_at_once
|
||||
#Options are lagged_start, smoothed_lagged_start,
|
||||
#one_at_a_time, all_at_once
|
||||
"submobject_partial_creation_mode" : "lagged_start",
|
||||
#TODO, probably make this Animations's responsibility?
|
||||
}
|
||||
def __init__(self, *submobjects, **kwargs):
|
||||
digest_config(self, kwargs)
|
||||
|
@ -286,14 +288,21 @@ class Mobject(object):
|
|||
|
||||
## Color functions
|
||||
|
||||
def highlight(self, color = YELLOW_C, condition = None):
|
||||
def highlight(self, color = YELLOW_C, family = True, condition = None):
|
||||
"""
|
||||
Condition is function which takes in one arguments, (x, y, z).
|
||||
"""
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def gradient_highlight(self, start_color, end_color):
|
||||
raise Exception("Not implemented")
|
||||
raise Exception("Not implemented")
|
||||
|
||||
def submobject_gradient_highlight(self, start_color, end_color):
|
||||
mobs = self.family_members_with_points()
|
||||
colors = Color(start_color).range_to(end_color, len(mobs))
|
||||
for mob, color in zip(mobs, colors):
|
||||
mob.highlight(color, family = False)
|
||||
return self
|
||||
|
||||
def set_color(self, color):
|
||||
self.highlight(color)
|
||||
|
@ -305,10 +314,10 @@ class Mobject(object):
|
|||
return self
|
||||
|
||||
def fade_to(self, color, alpha):
|
||||
start = color_to_rgb(self.get_color())
|
||||
end = color_to_rgb(color)
|
||||
new_rgb = interpolate(start, end, alpha)
|
||||
for mob in self.family_members_with_points():
|
||||
start = color_to_rgb(mob.get_color())
|
||||
end = color_to_rgb(color)
|
||||
new_rgb = interpolate(start, end, alpha)
|
||||
mob.highlight(Color(rgb = new_rgb))
|
||||
return self
|
||||
|
||||
|
@ -554,8 +563,10 @@ class Mobject(object):
|
|||
mobject.family_members_with_points()
|
||||
)
|
||||
for i, (self_sub, mob_sub) in enumerate(pairs):
|
||||
if spcm == "lagged_start":
|
||||
if spcm in ["lagged_start", "smoothed_lagged_start"]:
|
||||
prop = float(i)/len(pairs)
|
||||
if spcm is "smoothed_lagged_start":
|
||||
prop = smooth(prop)
|
||||
sub_a = np.clip(2*a - prop, 0, 1)
|
||||
sub_b = np.clip(2*b - prop, 0, 1)
|
||||
elif spcm == "one_at_a_time":
|
||||
|
|
|
@ -26,9 +26,10 @@ class PMobject(Mobject):
|
|||
self.rgbs = np.append(self.rgbs, rgbs, axis = 0)
|
||||
return self
|
||||
|
||||
def highlight(self, color = YELLOW_C, condition = None):
|
||||
def highlight(self, color = YELLOW_C, family = True, condition = None):
|
||||
rgb = Color(color).get_rgb()
|
||||
for mob in self.family_members_with_points():
|
||||
mobs = self.family_members_with_points() if family else [self]
|
||||
for mob in mobs:
|
||||
if condition:
|
||||
to_change = np.apply_along_axis(condition, 1, mob.points)
|
||||
mob.rgbs[to_change, :] = rgb
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from vectorized_mobject import VMobject
|
||||
from svg_mobject import SVGMobject, VMobjectFromSVGPathstring
|
||||
from topics.geometry import Rectangle
|
||||
from helpers import *
|
||||
import collections
|
||||
|
||||
|
@ -101,7 +102,15 @@ class TexMobject(SVGMobject):
|
|||
lambda m1, m2 : int((m1.get_left()-m2.get_left())[0])
|
||||
)
|
||||
|
||||
|
||||
def add_background_rectangle(self, color = BLACK, opacity = 0.75):
|
||||
rect = Rectangle(
|
||||
stroke_width = 0,
|
||||
fill_color = color,
|
||||
fill_opacity = opacity
|
||||
)
|
||||
rect.replace(self, stretch = True)
|
||||
self.submobjects = [rect] + self.submobjects
|
||||
return self
|
||||
|
||||
class TextMobject(TexMobject):
|
||||
CONFIG = {
|
||||
|
|
|
@ -6,8 +6,9 @@ from helpers import *
|
|||
|
||||
class VMobject(Mobject):
|
||||
CONFIG = {
|
||||
"fill_color" : BLACK,
|
||||
"fill_color" : None,
|
||||
"fill_opacity" : 0.0,
|
||||
"stroke_color" : None,
|
||||
#Indicates that it will not be displayed, but
|
||||
#that it should count in parent mobject's path
|
||||
"is_subpath" : False,
|
||||
|
@ -21,12 +22,10 @@ class VMobject(Mobject):
|
|||
|
||||
## Colors
|
||||
def init_colors(self):
|
||||
if not hasattr(self, "stroke_color"):
|
||||
self.stroke_color = self.color
|
||||
self.set_style_data(
|
||||
stroke_color = self.stroke_color,
|
||||
stroke_color = self.stroke_color or self.color,
|
||||
stroke_width = self.stroke_width,
|
||||
fill_color = self.fill_color,
|
||||
fill_color = self.fill_color or self.color,
|
||||
fill_opacity = self.fill_opacity,
|
||||
family = self.propogate_style_to_family
|
||||
)
|
||||
|
@ -58,6 +57,8 @@ class VMobject(Mobject):
|
|||
return self
|
||||
|
||||
def set_fill(self, color = None, opacity = None, family = True):
|
||||
if self.fill_opacity == 0 and opacity is None:
|
||||
opacity = 1
|
||||
return self.set_style_data(
|
||||
fill_color = color,
|
||||
fill_opacity = opacity,
|
||||
|
@ -71,19 +72,22 @@ class VMobject(Mobject):
|
|||
family = family
|
||||
)
|
||||
|
||||
def highlight(self, color):
|
||||
self.set_fill(color = color)
|
||||
self.set_stroke(color = color)
|
||||
def highlight(self, color, family = True):
|
||||
self.set_fill(
|
||||
color = color,
|
||||
opacity = self.get_fill_opacity(),
|
||||
family = family
|
||||
)
|
||||
self.set_stroke(color = color, family = family)
|
||||
return self
|
||||
|
||||
def fade(self, darkness = 0.5):
|
||||
Mobject.fade(self, darkness)
|
||||
return self
|
||||
# def fade(self, darkness = 0.5):
|
||||
# Mobject.fade(self, darkness)
|
||||
# return self
|
||||
|
||||
def get_fill_color(self):
|
||||
try:
|
||||
self.fill_rgb[self.fill_rgb<0] = 0
|
||||
self.fill_rgb[self.fill_rgb>1] = 1
|
||||
self.fill_rgb = np.clip(self.fill_rgb, 0, 1)
|
||||
return Color(rgb = self.fill_rgb)
|
||||
except:
|
||||
return Color(WHITE)
|
||||
|
@ -98,8 +102,10 @@ class VMobject(Mobject):
|
|||
except:
|
||||
return Color(WHITE)
|
||||
|
||||
#TODO, get color? Specify if stroke or fill
|
||||
#is the predominant color attribute?
|
||||
def get_color(self):
|
||||
if self.fill_opacity == 0:
|
||||
return self.get_stroke_color()
|
||||
return self.get_fill_color()
|
||||
|
||||
## Drawing
|
||||
def start_at(self, point):
|
||||
|
|
|
@ -132,20 +132,16 @@ class Scene(object):
|
|||
return [m.copy() for m in self.mobjects]
|
||||
|
||||
def align_run_times(self, *animations, **kwargs):
|
||||
if "run_time" in kwargs:
|
||||
run_time = kwargs["run_time"]
|
||||
for animation in animations:
|
||||
animation.set_run_time(run_time)
|
||||
else:
|
||||
max_run_time = max([a.run_time for a in animations])
|
||||
for animation in animations:
|
||||
if animation.run_time != max_run_time:
|
||||
new_rate_func = squish_rate_func(
|
||||
animation.get_rate_func(),
|
||||
0, 1./max_run_time
|
||||
)
|
||||
animation.set_rate_func(new_rate_func)
|
||||
animation.set_run_time(max_run_time)
|
||||
max_run_time = max([a.run_time for a in animations])
|
||||
for animation in animations:
|
||||
animation.update_config(**kwargs)
|
||||
if animation.run_time != max_run_time:
|
||||
new_rate_func = squish_rate_func(
|
||||
animation.get_rate_func(),
|
||||
0, 1./max_run_time
|
||||
)
|
||||
animation.set_rate_func(new_rate_func)
|
||||
animation.set_run_time(max_run_time)
|
||||
return animations
|
||||
|
||||
def separate_moving_and_static_mobjects(self, *animations):
|
||||
|
|
|
@ -44,8 +44,8 @@ class Dot(Circle): #Use 1D density, even though 2D
|
|||
CONFIG = {
|
||||
"radius" : 0.05,
|
||||
"stroke_width" : 0,
|
||||
"fill_color" : WHITE,
|
||||
"fill_opacity" : 1.0
|
||||
"fill_opacity" : 1.0,
|
||||
"color" : WHITE
|
||||
}
|
||||
def __init__(self, point = ORIGIN, **kwargs):
|
||||
Circle.__init__(self, **kwargs)
|
||||
|
|
|
@ -116,6 +116,7 @@ class NumberPlane(VMobject):
|
|||
"color" : BLUE_D,
|
||||
"secondary_color" : BLUE_E,
|
||||
"axes_color" : WHITE,
|
||||
"secondary_stroke_width" : 1,
|
||||
"x_radius": SPACE_WIDTH,
|
||||
"y_radius": SPACE_HEIGHT,
|
||||
"space_unit_to_x_unit" : 1,
|
||||
|
@ -127,6 +128,7 @@ class NumberPlane(VMobject):
|
|||
"written_coordinate_nudge" : 0.1*(DOWN+RIGHT),
|
||||
"num_pair_at_center" : (0, 0),
|
||||
"propogate_style_to_family" : False,
|
||||
"submobject_partial_creation_mode" : "smoothed_lagged_start",
|
||||
}
|
||||
|
||||
def generate_points(self):
|
||||
|
@ -170,9 +172,11 @@ class NumberPlane(VMobject):
|
|||
|
||||
def init_colors(self):
|
||||
VMobject.init_colors(self)
|
||||
self.axes.set_stroke(self.axes_color)
|
||||
self.main_lines.set_stroke(self.color)
|
||||
self.secondary_lines.set_stroke(self.secondary_color, 1)
|
||||
self.axes.set_stroke(self.axes_color, self.stroke_width)
|
||||
self.main_lines.set_stroke(self.color, self.stroke_width)
|
||||
self.secondary_lines.set_stroke(
|
||||
self.secondary_color, self.secondary_stroke_width
|
||||
)
|
||||
return self
|
||||
|
||||
def get_center_point(self):
|
||||
|
@ -236,10 +240,10 @@ class NumberPlane(VMobject):
|
|||
arrow = Arrow(ORIGIN, coords, **kwargs)
|
||||
return arrow
|
||||
|
||||
def prepare_for_nonlinear_transform(self):
|
||||
def prepare_for_nonlinear_transform(self, num_inserted_anchor_points = 40):
|
||||
for mob in self.submobject_family():
|
||||
if mob.get_num_points() > 0:
|
||||
mob.insert_n_anchor_points(20)
|
||||
mob.insert_n_anchor_points(num_inserted_anchor_points)
|
||||
mob.change_anchor_mode("smooth")
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue