mirror of
https://github.com/3b1b/manim.git
synced 2025-07-30 21:44:19 +08:00
Up to formal definition of linearity in EoLA chapter 3
This commit is contained in:
@ -98,12 +98,8 @@ class ApplyMethod(Transform):
|
||||
"the method you want to animate"
|
||||
)
|
||||
assert(isinstance(method.im_self, Mobject))
|
||||
Transform.__init__(
|
||||
self,
|
||||
method.im_self,
|
||||
copy.deepcopy(method)(*args),
|
||||
**kwargs
|
||||
)
|
||||
target = copy.deepcopy(method)(*args)
|
||||
Transform.__init__(self, method.im_self, target, **kwargs)
|
||||
|
||||
class FadeOut(Transform):
|
||||
CONFIG = {
|
||||
|
174
eola/chapter3.py
174
eola/chapter3.py
@ -20,6 +20,10 @@ from mobject.vectorized_mobject import *
|
||||
from eola.matrix import *
|
||||
from eola.two_d_space import *
|
||||
|
||||
def curvy_squish(point):
|
||||
x, y, z = point
|
||||
return (x+np.cos(y))*RIGHT + (y+np.sin(x))*UP
|
||||
|
||||
class OpeningQuote(Scene):
|
||||
def construct(self):
|
||||
words = TextMobject([
|
||||
@ -49,7 +53,6 @@ class OpeningQuote(Scene):
|
||||
self.play(Write(comment))
|
||||
self.dither()
|
||||
|
||||
|
||||
class Introduction(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
title = TextMobject("Matrices as linear transformations")
|
||||
@ -71,7 +74,6 @@ class Introduction(TeacherStudentsScene):
|
||||
return (SPACE_WIDTH+SPACE_HEIGHT)*p/np.linalg.norm(p)
|
||||
self.play(ApplyPointwiseFunction(spread_out, everything))
|
||||
|
||||
|
||||
class ShowGridCreation(Scene):
|
||||
def construct(self):
|
||||
plane = NumberPlane()
|
||||
@ -114,7 +116,6 @@ class IntroduceLinearTransformations(LinearTransformationScene):
|
||||
)
|
||||
self.dither()
|
||||
|
||||
|
||||
class SimpleLinearTransformationScene(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
@ -143,8 +144,7 @@ class SimpleNonlinearTransformationScene(LinearTransformationScene):
|
||||
self.dither()
|
||||
|
||||
def func(self, point):
|
||||
x, y, z = point
|
||||
return (x+np.cos(y))*RIGHT + (y+np.sin(x))*UP
|
||||
return curvy_squish(point)
|
||||
|
||||
class MovingOrigin(SimpleNonlinearTransformationScene):
|
||||
CONFIG = {
|
||||
@ -185,7 +185,6 @@ class SneakyNonlinearTransformationExplained(SneakyNonlinearTransformation):
|
||||
self.play(ShowCreation(diag))
|
||||
self.add_transformable_mobject(diag)
|
||||
|
||||
|
||||
class AnotherLinearTransformation(SimpleLinearTransformationScene):
|
||||
CONFIG = {
|
||||
"transposed_matrix" : [
|
||||
@ -209,7 +208,6 @@ class AnotherLinearTransformation(SimpleLinearTransformationScene):
|
||||
self.play(Write(text))
|
||||
self.dither()
|
||||
|
||||
|
||||
class Rotation(SimpleLinearTransformationScene):
|
||||
CONFIG = {
|
||||
"angle" : np.pi/3,
|
||||
@ -221,8 +219,6 @@ class Rotation(SimpleLinearTransformationScene):
|
||||
]
|
||||
SimpleLinearTransformationScene.construct(self)
|
||||
|
||||
|
||||
|
||||
class YetAnotherLinearTransformation(SimpleLinearTransformationScene):
|
||||
CONFIG = {
|
||||
"transposed_matrix" : [
|
||||
@ -231,7 +227,6 @@ class YetAnotherLinearTransformation(SimpleLinearTransformationScene):
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class MoveAroundAllVectors(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
@ -269,17 +264,15 @@ class MoveAroundAllVectors(LinearTransformationScene):
|
||||
self.add(vector.copy().highlight(DARK_GREY))
|
||||
else:
|
||||
for vector in vectors.split():
|
||||
self.add_vector(vector)
|
||||
self.add_vector(vector, animate = False)
|
||||
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
|
||||
@ -297,8 +290,6 @@ class RotateIHat(LinearTransformationScene):
|
||||
self.play(Write(j_label, run_time = 1))
|
||||
self.dither()
|
||||
|
||||
|
||||
|
||||
class TransformationsAreFunctions(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject([
|
||||
@ -345,7 +336,6 @@ class TransformationsAreFunctions(Scene):
|
||||
self.play(Write(v), ShowCreation(a), run_time = 1)
|
||||
self.dither()
|
||||
|
||||
|
||||
class UsedToThinkinfOfFunctionsAsGraphs(VectorScene):
|
||||
def construct(self):
|
||||
self.show_graph()
|
||||
@ -409,6 +399,158 @@ class UsedToThinkinfOfFunctionsAsGraphs(VectorScene):
|
||||
)
|
||||
self.dither()
|
||||
|
||||
class TryingToVisualizeFourDimensions(Scene):
|
||||
def construct(self):
|
||||
randy = Randolph().to_corner()
|
||||
bubble = randy.get_bubble()
|
||||
formula = TexMobject("""
|
||||
L\\left(\\left[
|
||||
\\begin{array}{c}
|
||||
x \\\\
|
||||
y
|
||||
\\end{array}
|
||||
\\right]\\right) =
|
||||
\\left[
|
||||
\\begin{array}{c}
|
||||
2x + y \\\\
|
||||
x + 2y
|
||||
\\end{array}
|
||||
\\right]
|
||||
""")
|
||||
formula.next_to(randy, RIGHT)
|
||||
formula.split()[3].highlight(X_COLOR)
|
||||
formula.split()[4].highlight(Y_COLOR)
|
||||
VMobject(*formula.split()[9:9+4]).highlight(MAROON_C)
|
||||
VMobject(*formula.split()[13:13+4]).highlight(BLUE)
|
||||
thought = TextMobject("""
|
||||
Do I imagine plotting
|
||||
$(x, y, 2x+y, x+2y)$???
|
||||
""")
|
||||
thought.split()[-17].highlight(X_COLOR)
|
||||
thought.split()[-15].highlight(Y_COLOR)
|
||||
VMobject(*thought.split()[-13:-13+4]).highlight(MAROON_C)
|
||||
VMobject(*thought.split()[-8:-8+4]).highlight(BLUE)
|
||||
|
||||
bubble.position_mobject_inside(thought)
|
||||
thought.shift(0.2*UP)
|
||||
|
||||
self.add(randy)
|
||||
|
||||
self.play(
|
||||
ApplyMethod(randy.look, DOWN+RIGHT),
|
||||
Write(formula)
|
||||
)
|
||||
self.play(
|
||||
ApplyMethod(randy.change_mode, "pondering"),
|
||||
ShowCreation(bubble),
|
||||
Write(thought)
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.dither()
|
||||
self.remove(thought)
|
||||
bubble.make_green_screen()
|
||||
self.dither()
|
||||
self.play(Blink(randy))
|
||||
self.play(ApplyMethod(randy.change_mode, "confused"))
|
||||
self.dither()
|
||||
self.play(Blink(randy))
|
||||
self.dither()
|
||||
|
||||
class ForgetAboutGraphs(Scene):
|
||||
def construct(self):
|
||||
self.play(Write("You must unlearn graphs"))
|
||||
self.dither()
|
||||
|
||||
class ThinkAboutFunctionAsMovingVector(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
"leave_ghost_vectors" : True,
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
vector = self.add_vector([2, 1])
|
||||
label = self.add_transformable_label(vector, "v")
|
||||
self.dither()
|
||||
self.apply_transposed_matrix([[1, 1], [-3, 1]])
|
||||
self.dither()
|
||||
|
||||
class PrepareForFormalDefinition(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
self.setup()
|
||||
self.teacher_says("Get ready for a formal definition!")
|
||||
self.dither(3)
|
||||
bubble = self.student_thinks("")
|
||||
bubble.make_green_screen()
|
||||
self.dither(3)
|
||||
|
||||
class AdditivityProperty(LinearTransformationScene):
|
||||
CONFIG = {
|
||||
"show_basis_vectors" : False,
|
||||
"give_title" : True,
|
||||
"transposed_matrix" : [[2, 0], [1, 1]],
|
||||
"nonlinear_transformation" : None,
|
||||
"vector_v" : [2, 1],
|
||||
"vector_w" : [1, -2],
|
||||
}
|
||||
def construct(self):
|
||||
self.setup()
|
||||
added_anims = []
|
||||
if self.give_title:
|
||||
title = TextMobject("""
|
||||
First fundamental property of
|
||||
linear transformations
|
||||
""")
|
||||
title.to_edge(UP)
|
||||
title.add_background_rectangle()
|
||||
self.play(Write(title))
|
||||
added_anims.append(Animation(title))
|
||||
self.dither()
|
||||
# self.play(ApplyMethod(self.plane.fade))
|
||||
|
||||
v, w = self.draw_all_vectors()
|
||||
self.apply_transformation()
|
||||
self.show_final_sum(v, w)
|
||||
|
||||
def draw_all_vectors(self):
|
||||
v = self.add_vector(self.vector_v, color = MAROON_C)
|
||||
v_label = self.add_transformable_label(v, "v")
|
||||
w = self.add_vector(self.vector_w, color = GREEN)
|
||||
w_label = self.add_transformable_label(w, "w")
|
||||
new_w = w.copy().fade(0.4)
|
||||
self.play(ApplyMethod(new_w.shift, v.get_end()))
|
||||
sum_vect = self.add_vector(new_w.get_end(), color = PINK)
|
||||
sum_label = self.add_transformable_label(
|
||||
sum_vect,
|
||||
"%s + %s"%(v_label.expression, w_label.expression),
|
||||
rotate = True
|
||||
)
|
||||
self.play(FadeOut(new_w))
|
||||
return v, w
|
||||
|
||||
def apply_transformation(selfe):
|
||||
if self.nonlinear_transformation:
|
||||
self.apply_nonlinear_transformation(self.nonlinear_transformation)
|
||||
else:
|
||||
self.apply_transposed_matrix(
|
||||
self.transposed_matrix,
|
||||
added_anims = added_anims
|
||||
)
|
||||
self.dither()
|
||||
|
||||
def show_final_sum(self, v, w):
|
||||
new_w = w.copy()
|
||||
self.play(ApplyMethod(new_w.shift, v.get_end()))
|
||||
self.dither()
|
||||
|
||||
|
||||
class NonlinearLacksAdditivity(AdditivityProperty):
|
||||
CONFIG = {
|
||||
"give_title" : False,
|
||||
"nonlinear_transformation" : curvy_squish,
|
||||
"vector_w" : [2, -3],
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -84,28 +84,22 @@ class VectorScene(Scene):
|
||||
direction = "left",
|
||||
rotate = False,
|
||||
color = WHITE,
|
||||
buff_factor = 2,
|
||||
label_scale_val = VECTOR_LABEL_SCALE_VAL):
|
||||
if len(label) == 1:
|
||||
label = "\\vec{\\textbf{%s}}"%label
|
||||
label = TexMobject(label)
|
||||
label.highlight(color)
|
||||
label.highlight(color)
|
||||
label.scale(label_scale_val)
|
||||
if rotate:
|
||||
label.rotate(vector.get_angle())
|
||||
label.add_background_rectangle()
|
||||
|
||||
vector_vect = vector.get_end() - vector.get_start()
|
||||
if direction is "left":
|
||||
rot_angle = -np.pi/2
|
||||
else:
|
||||
rot_angle = np.pi/2
|
||||
boundary_dir = -np.round(rotate_vector(vector_vect, rot_angle))
|
||||
boundary_point = label.get_critical_point(boundary_dir)
|
||||
label.shift(buff_factor*boundary_point)
|
||||
label.shift(vector_vect/2.)
|
||||
angle = vector.get_angle()
|
||||
label.shift(label.get_height()*UP)
|
||||
label.rotate(angle)
|
||||
label.shift((vector.get_end() - vector.get_start())/2)
|
||||
if not rotate:
|
||||
label.rotate_in_place(-angle)
|
||||
return label
|
||||
|
||||
|
||||
def label_vector(self, vector, label, animate = True, **kwargs):
|
||||
label = self.get_vector_label(vector, label, **kwargs)
|
||||
if animate:
|
||||
@ -252,11 +246,13 @@ class LinearTransformationScene(VectorScene):
|
||||
"show_basis_vectors" : True,
|
||||
"i_hat_color" : X_COLOR,
|
||||
"j_hat_color" : Y_COLOR,
|
||||
"leave_ghost_vectors" : False,
|
||||
}
|
||||
def setup(self):
|
||||
self.background_mobjects = []
|
||||
self.transformable_mobject = []
|
||||
self.transformable_mobjects = []
|
||||
self.moving_vectors = []
|
||||
self.transformable_labels = []
|
||||
|
||||
self.background_plane = NumberPlane(
|
||||
**self.background_plane_kwargs
|
||||
@ -281,8 +277,8 @@ class LinearTransformationScene(VectorScene):
|
||||
|
||||
def add_transformable_mobject(self, *mobjects):
|
||||
for mobject in mobjects:
|
||||
if mobject not in self.transformable_mobject:
|
||||
self.transformable_mobject.append(mobject)
|
||||
if mobject not in self.transformable_mobjects:
|
||||
self.transformable_mobjects.append(mobject)
|
||||
self.add(mobject)
|
||||
|
||||
def add_vector(self, vector, color = YELLOW, **kwargs):
|
||||
@ -292,6 +288,14 @@ class LinearTransformationScene(VectorScene):
|
||||
self.moving_vectors.append(vector)
|
||||
return vector
|
||||
|
||||
def add_transformable_label(self, vector, label, **kwargs):
|
||||
label_mob = self.label_vector(vector, label, **kwargs)
|
||||
label_mob.target_text = "L(%s)"%label_mob.expression
|
||||
label_mob.vector = vector
|
||||
label_mob.kwargs = kwargs
|
||||
self.transformable_labels.append(label_mob)
|
||||
return label_mob
|
||||
|
||||
def get_matrix_transformation(self, transposed_matrix):
|
||||
transposed_matrix = np.array(transposed_matrix)
|
||||
if transposed_matrix.shape == (2, 2):
|
||||
@ -302,14 +306,24 @@ class LinearTransformationScene(VectorScene):
|
||||
raise "Matrix has bad dimensions"
|
||||
return lambda point: np.dot(point, transposed_matrix)
|
||||
|
||||
def get_piece_movement(self, pieces):
|
||||
start = VMobject(*pieces)
|
||||
target = VMobject(*[mob.target for mob in pieces])
|
||||
if self.leave_ghost_vectors:
|
||||
self.add(start.copy().fade(0.7))
|
||||
return Transform(start, target, submobject_mode = "all_at_once")
|
||||
|
||||
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)
|
||||
for v in self.moving_vectors:
|
||||
v.target = Vector(func(v.get_end()), color = v.get_color())
|
||||
return self.get_piece_movement(self.moving_vectors)
|
||||
|
||||
def get_transformable_label_movement(self):
|
||||
for l in self.transformable_labels:
|
||||
l.target = self.get_vector_label(
|
||||
l.vector.target, l.target_text, **l.kwargs
|
||||
)
|
||||
return self.get_piece_movement(self.transformable_labels)
|
||||
|
||||
def apply_transposed_matrix(self, transposed_matrix, **kwargs):
|
||||
func = self.get_matrix_transformation(transposed_matrix)
|
||||
@ -322,18 +336,20 @@ class LinearTransformationScene(VectorScene):
|
||||
self.apply_function(func, **kwargs)
|
||||
|
||||
def apply_nonlinear_transformation(self, function, **kwargs):
|
||||
self.plane.prepare_for_nonlinear_transform(100)
|
||||
self.plane.prepare_for_nonlinear_transform()
|
||||
self.apply_function(function, **kwargs)
|
||||
|
||||
def apply_function(self, function, **kwargs):
|
||||
def apply_function(self, function, added_anims = [], **kwargs):
|
||||
if "run_time" not in kwargs:
|
||||
kwargs["run_time"] = 3
|
||||
self.play(
|
||||
ApplyPointwiseFunction(
|
||||
function,
|
||||
VMobject(*self.transformable_mobject),
|
||||
VMobject(*self.transformable_mobjects),
|
||||
),
|
||||
self.get_vector_movement(function),
|
||||
self.get_transformable_label_movement(),
|
||||
*added_anims,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
@ -12,6 +12,7 @@ from scipy import linalg
|
||||
from constants import *
|
||||
|
||||
CLOSED_THRESHOLD = 0.01
|
||||
STRAIGHT_PATH_THRESHOLD = 0.01
|
||||
|
||||
def get_smooth_handle_points(points):
|
||||
num_handles = len(points) - 1
|
||||
@ -262,7 +263,7 @@ def path_along_arc(arc_angle):
|
||||
If vect is vector from start to end, [vect[:,1], -vect[:,0]] is
|
||||
perpendicualr to vect in the left direction.
|
||||
"""
|
||||
if arc_angle == 0:
|
||||
if abs(arc_angle) < STRAIGHT_PATH_THRESHOLD:
|
||||
return straight_path
|
||||
def path(start_points, end_points, alpha):
|
||||
vects = end_points - start_points
|
||||
|
@ -314,7 +314,7 @@ class Mobject(object):
|
||||
start = color_to_rgb(mob.get_color())
|
||||
end = color_to_rgb(color)
|
||||
new_rgb = interpolate(start, end, alpha)
|
||||
mob.highlight(Color(rgb = new_rgb))
|
||||
mob.highlight(Color(rgb = new_rgb), family = False)
|
||||
return self
|
||||
|
||||
def fade(self, darkness = 0.5):
|
||||
|
@ -45,22 +45,22 @@ class VMobject(Mobject):
|
||||
for mob in mobs:
|
||||
if stroke_color is not None:
|
||||
mob.stroke_rgb = color_to_rgb(stroke_color)
|
||||
if stroke_width is not None:
|
||||
mob.stroke_width = stroke_width
|
||||
if fill_color is not None:
|
||||
mob.fill_rgb = color_to_rgb(fill_color)
|
||||
if stroke_width is not None:
|
||||
mob.stroke_width = stroke_width
|
||||
if fill_opacity is not None:
|
||||
mob.fill_opacity = fill_opacity
|
||||
probably_meant_to_change_opacity = reduce(op.and_, [
|
||||
fill_color is not None,
|
||||
fill_opacity is None,
|
||||
mob.fill_opacity == 0
|
||||
])
|
||||
if probably_meant_to_change_opacity:
|
||||
mob.fill_opacity = 1
|
||||
return self
|
||||
|
||||
def set_fill(self, color = None, opacity = None, family = True):
|
||||
probably_meant_to_change_opacity = reduce(op.and_, [
|
||||
color is not None,
|
||||
opacity is None,
|
||||
self.fill_opacity == 0
|
||||
])
|
||||
if probably_meant_to_change_opacity:
|
||||
opacity = 1
|
||||
return self.set_style_data(
|
||||
fill_color = color,
|
||||
fill_opacity = opacity,
|
||||
@ -75,8 +75,11 @@ class VMobject(Mobject):
|
||||
)
|
||||
|
||||
def highlight(self, color, family = True):
|
||||
self.set_fill(color = color, family = family)
|
||||
self.set_stroke(color = color, family = family)
|
||||
self.set_style_data(
|
||||
stroke_color = color,
|
||||
fill_color = color,
|
||||
family = family
|
||||
)
|
||||
return self
|
||||
|
||||
# def fade(self, darkness = 0.5):
|
||||
@ -203,6 +206,13 @@ class VMobject(Mobject):
|
||||
self.submobjects
|
||||
)
|
||||
|
||||
def apply_function(self, function, maintain_smoothness = True):
|
||||
Mobject.apply_function(self, function)
|
||||
if maintain_smoothness:
|
||||
self.make_smooth()
|
||||
return self
|
||||
|
||||
|
||||
## Information about line
|
||||
|
||||
def component_curves(self):
|
||||
|
@ -226,12 +226,9 @@ class Bubble(SVGMobject):
|
||||
return mobject
|
||||
|
||||
def add_content(self, mobject):
|
||||
if self.content in self.submobjects:
|
||||
self.submobjects.remove(self.content)
|
||||
self.position_mobject_inside(mobject)
|
||||
self.content = mobject
|
||||
self.add(self.content)
|
||||
return self
|
||||
return self.content
|
||||
|
||||
def write(self, text):
|
||||
self.add_content(TextMobject(text))
|
||||
@ -296,11 +293,12 @@ class TeacherStudentsScene(Scene):
|
||||
bubble.add_content(content)
|
||||
if pi_creature.bubble:
|
||||
content_intro_anims = [
|
||||
Transform(pi_creature.bubble, bubble)
|
||||
Transform(pi_creature.bubble, bubble),
|
||||
Transform(pi_creature.bubble.content, bubble.content)
|
||||
]
|
||||
else:
|
||||
content_intro_anims = [
|
||||
FadeIn(bubble.split()[0]),
|
||||
FadeIn(bubble),
|
||||
Write(content),
|
||||
]
|
||||
pi_creature.bubble = bubble
|
||||
@ -324,7 +322,10 @@ class TeacherStudentsScene(Scene):
|
||||
|
||||
for p in self.get_everyone():
|
||||
if p.bubble and p is not pi_creature:
|
||||
added_anims.append(FadeOut(p.bubble))
|
||||
added_anims += [
|
||||
FadeOut(p.bubble),
|
||||
FadeOut(p.bubble.content)
|
||||
]
|
||||
p.bubble = None
|
||||
added_anims.append(ApplyMethod(p.change_mode, "plain"))
|
||||
|
||||
@ -335,24 +336,25 @@ class TeacherStudentsScene(Scene):
|
||||
),
|
||||
]
|
||||
self.play(*anims)
|
||||
return pi_creature.bubble
|
||||
|
||||
def teacher_says(self, content, **kwargs):
|
||||
self.introduce_bubble(
|
||||
return self.introduce_bubble(
|
||||
content, "speech", self.get_teacher(), **kwargs
|
||||
)
|
||||
|
||||
def student_says(self, content, student_index = 1, **kwargs):
|
||||
student = self.get_students()[student_index]
|
||||
self.introduce_bubble(content, "speech", student, **kwargs)
|
||||
return self.introduce_bubble(content, "speech", student, **kwargs)
|
||||
|
||||
def teacher_thinks(self, content, **kwargs):
|
||||
self.introduce_bubble(
|
||||
return self.introduce_bubble(
|
||||
content, "thought", self.get_teacher(), **kwargs
|
||||
)
|
||||
|
||||
def student_thinks(self, content, student_index = 1, **kwargs):
|
||||
student = self.get_students()[student_index]
|
||||
self.introduce_bubble(content, "thought", student, **kwargs)
|
||||
return self.introduce_bubble(content, "thought", student, **kwargs)
|
||||
|
||||
def random_blink(self, num_times = 1):
|
||||
for x in range(num_times):
|
||||
|
@ -240,11 +240,11 @@ class NumberPlane(VMobject):
|
||||
arrow = Arrow(ORIGIN, coords, **kwargs)
|
||||
return arrow
|
||||
|
||||
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(num_inserted_anchor_points)
|
||||
mob.change_anchor_mode("smooth")
|
||||
def prepare_for_nonlinear_transform(self, num_inserted_anchor_points = 50):
|
||||
for mob in self.family_members_with_points():
|
||||
mob.insert_n_anchor_points(num_inserted_anchor_points)
|
||||
mob.make_smooth()
|
||||
return self
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user