mirror of
https://github.com/3b1b/manim.git
synced 2025-09-01 00:48:45 +00:00
Material needed for matrix as transform article
This commit is contained in:
parent
9e22e51591
commit
5b986b9a9e
7 changed files with 310 additions and 48 deletions
|
@ -57,7 +57,7 @@ class Rotating(Animation):
|
||||||
|
|
||||||
class RotationAsTransform(Rotating):
|
class RotationAsTransform(Rotating):
|
||||||
DEFAULT_CONFIG = {
|
DEFAULT_CONFIG = {
|
||||||
"axes" : [IN],
|
"axes" : [OUT],
|
||||||
"radians" : np.pi / 2,
|
"radians" : np.pi / 2,
|
||||||
"run_time" : DEFAULT_ANIMATION_RUN_TIME,
|
"run_time" : DEFAULT_ANIMATION_RUN_TIME,
|
||||||
"alpha_func" : smooth,
|
"alpha_func" : smooth,
|
||||||
|
|
|
@ -18,7 +18,7 @@ LOW_QUALITY_DISPLAY_CONFIG = {
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_POINT_DENSITY_2D = 25
|
DEFAULT_POINT_DENSITY_2D = 25
|
||||||
DEFAULT_POINT_DENSITY_1D = 150
|
DEFAULT_POINT_DENSITY_1D = 200
|
||||||
|
|
||||||
#TODO, Make sure these are not needd
|
#TODO, Make sure these are not needd
|
||||||
DEFAULT_HEIGHT = PRODUCTION_QUALITY_DISPLAY_CONFIG["height"]
|
DEFAULT_HEIGHT = PRODUCTION_QUALITY_DISPLAY_CONFIG["height"]
|
||||||
|
|
|
@ -65,13 +65,15 @@ class NumberLine(Mobject1D):
|
||||||
"unit_length_to_spatial_width" : 1,
|
"unit_length_to_spatial_width" : 1,
|
||||||
"tick_size" : 0.1,
|
"tick_size" : 0.1,
|
||||||
"tick_frequency" : 0.5,
|
"tick_frequency" : 0.5,
|
||||||
"leftmost_tick" : -int(SPACE_WIDTH),
|
"leftmost_tick" : None,
|
||||||
"number_at_center" : 0,
|
"number_at_center" : 0,
|
||||||
"numbers_with_elongated_ticks" : [0],
|
"numbers_with_elongated_ticks" : [0],
|
||||||
"longer_tick_multiple" : 2,
|
"longer_tick_multiple" : 2,
|
||||||
}
|
}
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
digest_config(self, NumberLine, kwargs)
|
digest_config(self, NumberLine, kwargs)
|
||||||
|
if self.leftmost_tick is None:
|
||||||
|
self.leftmost_tick = -int(self.numerical_radius)
|
||||||
self.left_num = self.number_at_center - self.numerical_radius
|
self.left_num = self.number_at_center - self.numerical_radius
|
||||||
self.right_num = self.number_at_center + self.numerical_radius
|
self.right_num = self.number_at_center + self.numerical_radius
|
||||||
Mobject1D.__init__(self, **kwargs)
|
Mobject1D.__init__(self, **kwargs)
|
||||||
|
@ -128,20 +130,12 @@ class NumberLine(Mobject1D):
|
||||||
return 4*DOWN*self.tick_size
|
return 4*DOWN*self.tick_size
|
||||||
|
|
||||||
def get_number_mobjects(self, *numbers):
|
def get_number_mobjects(self, *numbers):
|
||||||
|
#TODO, handle decimals
|
||||||
if len(numbers) == 0:
|
if len(numbers) == 0:
|
||||||
numbers = self.default_numbers_to_display()
|
numbers = self.default_numbers_to_display()
|
||||||
log_spacing = int(np.log10(self.tick_frequency))
|
|
||||||
if log_spacing < 0:
|
|
||||||
num_decimal_places = 2-log_spacing
|
|
||||||
else:
|
|
||||||
num_decimal_places = 1+log_spacing
|
|
||||||
result = []
|
result = []
|
||||||
for number in numbers:
|
for number in numbers:
|
||||||
if number < 0:
|
mob = tex_mobject(str(int(number)))
|
||||||
num_string = str(number)[:num_decimal_places+1]
|
|
||||||
else:
|
|
||||||
num_string = str(number)[:num_decimal_places]
|
|
||||||
mob = tex_mobject(num_string)
|
|
||||||
vert_scale = 2*self.tick_size/mob.get_height()
|
vert_scale = 2*self.tick_size/mob.get_height()
|
||||||
hori_scale = self.tick_frequency*self.unit_length_to_spatial_width/mob.get_width()
|
hori_scale = self.tick_frequency*self.unit_length_to_spatial_width/mob.get_width()
|
||||||
mob.scale(min(vert_scale, hori_scale))
|
mob.scale(min(vert_scale, hori_scale))
|
||||||
|
@ -152,10 +146,12 @@ class NumberLine(Mobject1D):
|
||||||
|
|
||||||
def add_numbers(self, *numbers):
|
def add_numbers(self, *numbers):
|
||||||
self.add(*self.get_number_mobjects(*numbers))
|
self.add(*self.get_number_mobjects(*numbers))
|
||||||
|
return self
|
||||||
|
|
||||||
def remove_numbers(self):
|
def remove_numbers(self):
|
||||||
self.points = self.points[:self.number_of_points_without_numbers]
|
self.points = self.points[:self.number_of_points_without_numbers]
|
||||||
self.rgbs = self.rgbs[:self.number_of_points_without_numbers]
|
self.rgbs = self.rgbs[:self.number_of_points_without_numbers]
|
||||||
|
return self
|
||||||
|
|
||||||
class UnitInterval(NumberLine):
|
class UnitInterval(NumberLine):
|
||||||
DEFAULT_CONFIG = {
|
DEFAULT_CONFIG = {
|
||||||
|
|
|
@ -10,18 +10,16 @@ from animation import *
|
||||||
from mobject import *
|
from mobject import *
|
||||||
from constants import *
|
from constants import *
|
||||||
from region import *
|
from region import *
|
||||||
from scene import Scene, NumberLineScene
|
from scene import Scene
|
||||||
from script_wrapper import command_line_create_scene
|
from script_wrapper import command_line_create_scene
|
||||||
|
|
||||||
|
|
||||||
class SampleScene(NumberLineScene):
|
class SampleScene(Scene):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
NumberLineScene.construct(self)
|
plane = NumberPlane(density = 400)
|
||||||
arrow = Arrow(2*RIGHT+UP, 2*RIGHT)
|
arrow1 = Arrow(ORIGIN, UP, color = "green")
|
||||||
self.add(arrow)
|
arrow2 = Arrow(ORIGIN, LEFT, color = "Red")
|
||||||
self.dither(2)
|
self.add(plane, arrow1, arrow2)
|
||||||
self.zoom_in_on(2.4, zoom_factor = 10)
|
|
||||||
self.dither(2)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
command_line_create_scene()
|
command_line_create_scene()
|
|
@ -73,6 +73,20 @@ class NumberLineScene(Scene):
|
||||||
self.add(self.number_line, *self.number_mobs)
|
self.add(self.number_line, *self.number_mobs)
|
||||||
self.add(*additional_mobjects)
|
self.add(*additional_mobjects)
|
||||||
|
|
||||||
|
def show_multiplication(self, num, **kwargs):
|
||||||
|
if "interpolation_function" not in kwargs:
|
||||||
|
if num > 0:
|
||||||
|
kwargs["interpolation_function"] = straight_path
|
||||||
|
else:
|
||||||
|
kwargs["interpolation_function"] = counterclockwise_path
|
||||||
|
self.play(*[
|
||||||
|
ApplyMethod(self.number_line.stretch, num, 0, **kwargs)
|
||||||
|
]+[
|
||||||
|
ApplyMethod(mob.shift, (num-1)*mob.get_center()[0]*RIGHT, **kwargs)
|
||||||
|
for mob in self.number_mobs
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ class Scene(object):
|
||||||
pass #To be implemented in subclasses
|
pass #To be implemented in subclasses
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
if hasattr(self, "name"):
|
||||||
|
return self.name
|
||||||
return self.__class__.__name__
|
return self.__class__.__name__
|
||||||
|
|
||||||
def set_name(self, name):
|
def set_name(self, name):
|
||||||
|
|
|
@ -38,6 +38,7 @@ class ShowMultiplication(NumberLineScene):
|
||||||
(-3, False),
|
(-3, False),
|
||||||
(-3, True),
|
(-3, True),
|
||||||
(2, True),
|
(2, True),
|
||||||
|
(6, True),
|
||||||
]
|
]
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def args_to_string(num, show_original_line):
|
def args_to_string(num, show_original_line):
|
||||||
|
@ -45,30 +46,17 @@ class ShowMultiplication(NumberLineScene):
|
||||||
return str(num) + end_string
|
return str(num) + end_string
|
||||||
|
|
||||||
def construct(self, num, show_original_line):
|
def construct(self, num, show_original_line):
|
||||||
NumberLineScene.construct(self, density = abs(num)*DEFAULT_POINT_DENSITY_1D)
|
config = {"density" : abs(num)*DEFAULT_POINT_DENSITY_1D}
|
||||||
|
if abs(num) < 1:
|
||||||
|
config["numerical_radius"] = SPACE_WIDTH/num
|
||||||
|
|
||||||
|
NumberLineScene.construct(self, **config)
|
||||||
if show_original_line:
|
if show_original_line:
|
||||||
self.copy_original_line()
|
self.copy_original_line()
|
||||||
kwargs = {
|
|
||||||
"run_time" : 2.0,
|
|
||||||
"interpolation_function" : straight_path if num > 0 else counterclockwise_path
|
|
||||||
}
|
|
||||||
self.dither()
|
self.dither()
|
||||||
new_number_line = deepcopy(self.number_line)
|
self.show_multiplication(num, run_time = 2.0)
|
||||||
new_number_line.stretch(num, 0)
|
|
||||||
self.play(
|
|
||||||
Transform(self.number_line, new_number_line, **kwargs),
|
|
||||||
*[
|
|
||||||
ApplyFunction(
|
|
||||||
lambda m : m.do_in_place(m.stretch, 1.0/num, 0).stretch(num, 0),
|
|
||||||
mobject,
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
for mobject in self.number_mobs
|
|
||||||
]
|
|
||||||
)
|
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
def copy_original_line(self):
|
def copy_original_line(self):
|
||||||
copied_line = deepcopy(self.number_line)
|
copied_line = deepcopy(self.number_line)
|
||||||
copied_num_mobs = deepcopy(self.number_mobs)
|
copied_num_mobs = deepcopy(self.number_mobs)
|
||||||
|
@ -83,15 +71,76 @@ class ShowMultiplication(NumberLineScene):
|
||||||
)
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
class ExamplesOfOneDimensionalLinearTransforms(ShowMultiplication):
|
||||||
|
args_list = []
|
||||||
|
@staticmethod
|
||||||
|
def args_to_string():
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
for num in [2, 0.5, -3]:
|
||||||
|
ShowMultiplication.construct(self, num, False)
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
|
||||||
|
class ExamplesOfNonlinearOneDimensionalTransforms(NumberLineScene):
|
||||||
|
def construct(self):
|
||||||
|
def sinx_plux_x((x, y, z)):
|
||||||
|
return (np.sin(x) + 1.2*x, y, z)
|
||||||
|
def shift_zero((x, y, z)):
|
||||||
|
return (2*x+4, y, z)
|
||||||
|
self.nonlinear = text_mobject("Not a Linear Transform")
|
||||||
|
self.nonlinear.highlight("red").to_edge(UP)
|
||||||
|
pairs = [
|
||||||
|
(sinx_plux_x, "numbers don't remain evenly spaced"),
|
||||||
|
(shift_zero, "zero does not remain fixed")
|
||||||
|
]
|
||||||
|
for func, explanation in pairs:
|
||||||
|
self.dither()
|
||||||
|
self.run_function(func, explanation)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def run_function(self, function, explanation):
|
||||||
|
self.clear()
|
||||||
|
self.add(self.nonlinear)
|
||||||
|
NumberLineScene.construct(self)
|
||||||
|
words = text_mobject(explanation).highlight("red")
|
||||||
|
words.next_to(self.nonlinear, DOWN, buff = 0.5)
|
||||||
|
self.add(words)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ApplyPointwiseFunction(function, self.number_line),
|
||||||
|
*[
|
||||||
|
ApplyMethod(
|
||||||
|
mob.shift,
|
||||||
|
function(mob.get_center()) - mob.get_center()
|
||||||
|
)
|
||||||
|
for mob in self.number_mobs
|
||||||
|
],
|
||||||
|
run_time = 2.0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ShowTwoThenThree(ShowMultiplication):
|
||||||
|
args_list = []
|
||||||
|
@staticmethod
|
||||||
|
def args_to_string():
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
NumberLineScene.construct(self, density = 10*DEFAULT_POINT_DENSITY_1D)
|
||||||
|
self.copy_original_line()
|
||||||
|
self.show_multiplication(2)
|
||||||
|
self.dither()
|
||||||
|
self.show_multiplication(3)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########################################################
|
########################################################
|
||||||
|
|
||||||
class TransformScene2D(Scene):
|
class TransformScene2D(Scene):
|
||||||
def add_number_plane(self, density_factor, use_faded_lines = True):
|
def add_number_plane(self, density_factor = 1, use_faded_lines = True):
|
||||||
config = {
|
config = {
|
||||||
"x_radius" : 2*SPACE_WIDTH,
|
"x_radius" : 2*SPACE_WIDTH,
|
||||||
"y_radius" : 2*SPACE_HEIGHT,
|
"y_radius" : 2*SPACE_HEIGHT,
|
||||||
|
@ -131,13 +180,12 @@ class TransformScene2D(Scene):
|
||||||
|
|
||||||
class ShowMatrixTransform(TransformScene2D):
|
class ShowMatrixTransform(TransformScene2D):
|
||||||
args_list = [
|
args_list = [
|
||||||
([[1, 2], [3, 4]], True, False),
|
([[1, 0.5], [0.5, 1]], True, False),
|
||||||
([[1, 3], [-2, 0]], False, False),
|
([[2, 0], [0, 2]], True, False),
|
||||||
([[1, 3], [-2, 0]], True, True),
|
([[0.5, 0], [0, 0.5]], True, False),
|
||||||
([[0, -1], [1, 0]], True, False),
|
|
||||||
([[0, -1], [1, 0]], False, False),
|
|
||||||
([[-1, 0], [0, -1]], True, False),
|
([[-1, 0], [0, -1]], True, False),
|
||||||
([[-1, 0], [0, -1]], False, False),
|
([[0, 1], [1, 0]], True, False),
|
||||||
|
([[-2, 0], [-1, -1]], True, False),
|
||||||
]
|
]
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def args_to_string(matrix, with_background, show_matrix):
|
def args_to_string(matrix, with_background, show_matrix):
|
||||||
|
@ -157,6 +205,7 @@ class ShowMatrixTransform(TransformScene2D):
|
||||||
self.add_x_y_arrows()
|
self.add_x_y_arrows()
|
||||||
else:
|
else:
|
||||||
self.add_number_plane(**number_plane_config)
|
self.add_number_plane(**number_plane_config)
|
||||||
|
self.save_image()
|
||||||
if show_matrix:
|
if show_matrix:
|
||||||
self.add(matrix_mobject(matrix).to_corner(UP+LEFT))
|
self.add(matrix_mobject(matrix).to_corner(UP+LEFT))
|
||||||
def func(mobject):
|
def func(mobject):
|
||||||
|
@ -184,6 +233,199 @@ class ShowMatrixTransform(TransformScene2D):
|
||||||
anims.append(Transform(arrow, new_arrow, **kwargs))
|
anims.append(Transform(arrow, new_arrow, **kwargs))
|
||||||
self.play(*anims)
|
self.play(*anims)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
self.set_name(str(self) + self.args_to_string(matrix, with_background, show_matrix))
|
||||||
|
self.save_image(os.path.join(MOVIE_DIR, MOVIE_PREFIX, "images"))
|
||||||
|
|
||||||
|
def get_density_factor(self, matrix):
|
||||||
|
max_norm = max([
|
||||||
|
abs(np.linalg.norm(column))
|
||||||
|
for column in np.transpose(matrix)
|
||||||
|
])
|
||||||
|
return max(max_norm, 1)
|
||||||
|
|
||||||
|
def get_interpolation_function(self, matrix):
|
||||||
|
def toggled_sign(n, i):
|
||||||
|
return int(i%2 == 0)^int(n >= 0)
|
||||||
|
rotational_components = [
|
||||||
|
sign*np.arccos(matrix[i,i]/np.linalg.norm(matrix[:,i]))
|
||||||
|
for i in [0, 1]
|
||||||
|
for sign in [toggled_sign(matrix[1-i, i], i)]
|
||||||
|
]
|
||||||
|
average_rotation = sum(rotational_components)/2
|
||||||
|
if abs(average_rotation) < np.pi / 2:
|
||||||
|
return straight_path
|
||||||
|
elif average_rotation > 0:
|
||||||
|
return counterclockwise_path
|
||||||
|
else:
|
||||||
|
return clockwise_path
|
||||||
|
|
||||||
|
|
||||||
|
class ExamplesOfTwoDimensionalLinearTransformations(ShowMatrixTransform):
|
||||||
|
args_list = []
|
||||||
|
@staticmethod
|
||||||
|
def args_to_string():
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
matrices = [
|
||||||
|
[[1, 0.5],
|
||||||
|
[0.5, 1]],
|
||||||
|
[[0, -1],
|
||||||
|
[2, 0]],
|
||||||
|
[[1, 3],
|
||||||
|
[-2, 0]],
|
||||||
|
]
|
||||||
|
for matrix in matrices:
|
||||||
|
self.clear()
|
||||||
|
ShowMatrixTransform.construct(self, matrix, False, False)
|
||||||
|
|
||||||
|
|
||||||
|
class ExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
||||||
|
def construct(self):
|
||||||
|
Scene.construct(self)
|
||||||
|
def squiggle((x, y, z)):
|
||||||
|
return (x+np.sin(y), y+np.cos(x), z)
|
||||||
|
def shift_zero((x, y, z)):
|
||||||
|
return (2*x + 3*y + 4, -1*x+y+2, z)
|
||||||
|
self.nonlinear = text_mobject("Nonlinear Transform")
|
||||||
|
self.nonlinear.highlight("red").to_edge(UP)
|
||||||
|
pairs = [
|
||||||
|
(squiggle, "lines to not remain straight"),
|
||||||
|
(shift_zero, "the origin does not remain fixed")
|
||||||
|
]
|
||||||
|
for function, explanation in pairs:
|
||||||
|
self.apply_function(function, explanation)
|
||||||
|
|
||||||
|
|
||||||
|
def apply_function(self, function, explanation):
|
||||||
|
self.clear()
|
||||||
|
number_plane = NumberPlane(
|
||||||
|
x_radius = 1.5*SPACE_WIDTH,
|
||||||
|
y_radius = 1.5*SPACE_HEIGHT,
|
||||||
|
density = 3*DEFAULT_POINT_DENSITY_1D,
|
||||||
|
)
|
||||||
|
numbers = number_plane.get_coordinate_labels()
|
||||||
|
words = text_mobject(explanation).highlight("red")
|
||||||
|
words.next_to(self.nonlinear, DOWN, buff = 0.5)
|
||||||
|
|
||||||
|
self.add(number_plane, self.nonlinear, words, *numbers)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
ApplyPointwiseFunction(function, number_plane),
|
||||||
|
*[
|
||||||
|
ApplyMethod(
|
||||||
|
mob.shift,
|
||||||
|
function(mob.get_center())-mob.get_center()
|
||||||
|
)
|
||||||
|
for mob in numbers
|
||||||
|
],
|
||||||
|
run_time = 2.0
|
||||||
|
)
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
|
||||||
|
class TrickyExamplesOfNonlinearTwoDimensionalTransformations(Scene):
|
||||||
|
def construct(self):
|
||||||
|
number_plane = NumberPlane()
|
||||||
|
phrase1, phrase2 = text_mobject([
|
||||||
|
"These might look like they keep lines straight...",
|
||||||
|
"but diagonal lines get curved"
|
||||||
|
]).to_edge(UP).split()
|
||||||
|
phrase2.highlight("red")
|
||||||
|
diagonal = Line(
|
||||||
|
DOWN*SPACE_HEIGHT+LEFT*SPACE_WIDTH,
|
||||||
|
UP*SPACE_HEIGHT+RIGHT*SPACE_WIDTH
|
||||||
|
)
|
||||||
|
def sunrise((x, y, z)):
|
||||||
|
return ((SPACE_HEIGHT+y)*x, y, z)
|
||||||
|
|
||||||
|
def squished((x, y, z)):
|
||||||
|
return (x + np.sin(x), y+np.sin(y), z)
|
||||||
|
|
||||||
|
self.add(phrase1)
|
||||||
|
self.run_function(sunrise, number_plane)
|
||||||
|
self.run_function(squished, number_plane)
|
||||||
|
self.add(phrase2)
|
||||||
|
self.play(ShowCreation(diagonal))
|
||||||
|
self.remove(diagonal)
|
||||||
|
number_plane.add(diagonal)
|
||||||
|
self.run_function(sunrise, number_plane)
|
||||||
|
self.run_function(squished, number_plane)
|
||||||
|
|
||||||
|
|
||||||
|
def run_function(self, function, plane):
|
||||||
|
number_plane = deepcopy(plane)
|
||||||
|
self.add(number_plane)
|
||||||
|
self.dither()
|
||||||
|
self.play(ApplyPointwiseFunction(function, number_plane, run_time = 2.0))
|
||||||
|
self.dither(3)
|
||||||
|
self.remove(number_plane)
|
||||||
|
|
||||||
|
|
||||||
|
############# HORRIBLE! ##########################
|
||||||
|
class ShowMatrixTransformHack(TransformScene2D):
|
||||||
|
args_list = [
|
||||||
|
([[1, 3], [-2, 0]], True, False),
|
||||||
|
]
|
||||||
|
@staticmethod
|
||||||
|
def args_to_string(matrix, with_background, show_matrix):
|
||||||
|
background_string = "WithBackground" if with_background else "WithoutBackground"
|
||||||
|
show_string = "ShowingMatrix" if show_matrix else ""
|
||||||
|
return matrix_to_string(matrix) + background_string + show_string
|
||||||
|
|
||||||
|
def construct(self, matrix, with_background, show_matrix):
|
||||||
|
matrix = np.array(matrix)
|
||||||
|
number_plane_config = {
|
||||||
|
"density_factor" : self.get_density_factor(matrix)
|
||||||
|
}
|
||||||
|
if with_background:
|
||||||
|
self.add_background()
|
||||||
|
number_plane_config["use_faded_lines"] = False
|
||||||
|
self.add_number_plane(**number_plane_config)
|
||||||
|
self.add_x_y_arrows()
|
||||||
|
else:
|
||||||
|
self.add_number_plane(**number_plane_config)
|
||||||
|
if show_matrix:
|
||||||
|
self.add(matrix_mobject(matrix).to_corner(UP+LEFT))
|
||||||
|
def func(mobject):
|
||||||
|
mobject.points[:, :2] = np.dot(mobject.points[:, :2], np.transpose(matrix))
|
||||||
|
return mobject
|
||||||
|
dot = Dot((-1, 2, 0), color = "yellow")
|
||||||
|
x_arrow_copy = deepcopy(self.x_arrow)
|
||||||
|
y_arrow_copy = Arrow(LEFT, LEFT+2*UP, color = "red")
|
||||||
|
|
||||||
|
self.number_plane.add(dot)
|
||||||
|
self.play(ApplyMethod(x_arrow_copy.rotate, np.pi))
|
||||||
|
self.play(ShowCreation(y_arrow_copy))
|
||||||
|
self.dither()
|
||||||
|
self.remove(x_arrow_copy, y_arrow_copy)
|
||||||
|
kwargs = {
|
||||||
|
"run_time" : 2.0,
|
||||||
|
"interpolation_function" : self.get_interpolation_function(matrix)
|
||||||
|
}
|
||||||
|
anims = [ApplyFunction(func, self.number_plane, **kwargs)]
|
||||||
|
if hasattr(self, "x_arrow") and hasattr(self, "y_arrow"):
|
||||||
|
for arrow, index in (self.x_arrow, 0), (self.y_arrow, 1):
|
||||||
|
new_arrow = Arrow(
|
||||||
|
ORIGIN,
|
||||||
|
self.number_plane.num_pair_to_point(matrix[:,index]),
|
||||||
|
color = arrow.get_color()
|
||||||
|
)
|
||||||
|
arrow.remove_tip()
|
||||||
|
new_arrow.remove_tip()
|
||||||
|
Mobject.align_data(arrow, new_arrow)
|
||||||
|
arrow.add_tip()
|
||||||
|
new_arrow.add_tip()
|
||||||
|
anims.append(Transform(arrow, new_arrow, **kwargs))
|
||||||
|
self.play(*anims)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
x_arrow_copy = deepcopy(self.x_arrow)
|
||||||
|
y_arrow_copy = Arrow(LEFT+2*UP, 5*RIGHT+2*UP, color = "red")
|
||||||
|
self.play(ApplyMethod(x_arrow_copy.rotate, np.pi))
|
||||||
|
self.play(ShowCreation(y_arrow_copy))
|
||||||
|
self.remove(x_arrow_copy, y_arrow_copy)
|
||||||
|
self.dither(3)
|
||||||
|
|
||||||
def get_density_factor(self, matrix):
|
def get_density_factor(self, matrix):
|
||||||
max_norm = max([
|
max_norm = max([
|
||||||
|
@ -207,8 +449,18 @@ class ShowMatrixTransform(TransformScene2D):
|
||||||
return clockwise_path
|
return clockwise_path
|
||||||
|
|
||||||
|
|
||||||
|
class Show90DegreeRotation(TransformScene2D):
|
||||||
|
def construct(self):
|
||||||
|
self.add_number_plane()
|
||||||
|
self.add_background()
|
||||||
|
self.add_x_y_arrows()
|
||||||
|
|
||||||
|
self.dither()
|
||||||
|
self.play(*[
|
||||||
|
RotationAsTransform(mob, run_time = 2.0)
|
||||||
|
for mob in self.number_plane, self.x_arrow, self.y_arrow
|
||||||
|
])
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue