mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 08:54:38 +08:00
Beginning related rates example in eoc5
This commit is contained in:
384
eoc/chapter5.py
384
eoc/chapter5.py
@ -80,20 +80,15 @@ class SlopeOfCircleExample(ZoomedScene):
|
|||||||
"zoomed_canvas_corner_buff" : MED_SMALL_BUFF,
|
"zoomed_canvas_corner_buff" : MED_SMALL_BUFF,
|
||||||
}
|
}
|
||||||
def construct(self):
|
def construct(self):
|
||||||
should_skip_animations = self.skip_animations
|
|
||||||
self.skip_animations = True
|
|
||||||
|
|
||||||
self.setup_plane()
|
self.setup_plane()
|
||||||
self.introduce_circle()
|
self.introduce_circle()
|
||||||
self.talk_through_pythagorean_theorem()
|
self.talk_through_pythagorean_theorem()
|
||||||
self.draw_example_slope()
|
self.draw_example_slope()
|
||||||
# self.show_perpendicular_radius()
|
self.show_perpendicular_radius()
|
||||||
self.show_dx_and_dy()
|
self.show_dx_and_dy()
|
||||||
self.write_slope_as_dy_dx()
|
self.write_slope_as_dy_dx()
|
||||||
# self.point_out_this_is_not_a_graph()
|
self.point_out_this_is_not_a_graph()
|
||||||
self.skip_animations = should_skip_animations
|
|
||||||
self.perform_implicit_derivative()
|
self.perform_implicit_derivative()
|
||||||
self.show_rearrangement()
|
|
||||||
self.show_final_slope()
|
self.show_final_slope()
|
||||||
|
|
||||||
def setup_plane(self):
|
def setup_plane(self):
|
||||||
@ -115,6 +110,7 @@ class SlopeOfCircleExample(ZoomedScene):
|
|||||||
circle.point_from_proportion(1./8),
|
circle.point_from_proportion(1./8),
|
||||||
UP+RIGHT
|
UP+RIGHT
|
||||||
)
|
)
|
||||||
|
equation.to_edge(RIGHT)
|
||||||
|
|
||||||
self.play(ShowCreation(circle, run_time = 2))
|
self.play(ShowCreation(circle, run_time = 2))
|
||||||
self.play(Write(equation))
|
self.play(Write(equation))
|
||||||
@ -239,12 +235,11 @@ class SlopeOfCircleExample(ZoomedScene):
|
|||||||
self.play(PiCreatureBubbleIntroduction(
|
self.play(PiCreatureBubbleIntroduction(
|
||||||
morty, "Suppose you \\\\ don't know this.",
|
morty, "Suppose you \\\\ don't know this.",
|
||||||
))
|
))
|
||||||
|
to_fade =self.get_mobjects_from_last_animation()
|
||||||
self.play(Blink(morty))
|
self.play(Blink(morty))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
self.play(*map(
|
self.play(*map(FadeOut, to_fade))
|
||||||
FadeOut, [morty, morty.bubble, morty.bubble.content]
|
|
||||||
))
|
|
||||||
self.play(*map(FadeOut, [radial_line, perp_mark]))
|
self.play(*map(FadeOut, [radial_line, perp_mark]))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
@ -317,13 +312,15 @@ class SlopeOfCircleExample(ZoomedScene):
|
|||||||
dy_dx = TexMobject("\\frac{dy}{dx}")
|
dy_dx = TexMobject("\\frac{dy}{dx}")
|
||||||
VGroup(*dy_dx[:2]).highlight(RED)
|
VGroup(*dy_dx[:2]).highlight(RED)
|
||||||
VGroup(*dy_dx[-2:]).highlight(GREEN)
|
VGroup(*dy_dx[-2:]).highlight(GREEN)
|
||||||
dy_dx.next_to(new_slope_word, RIGHT, buff = SMALL_BUFF)
|
dy_dx.next_to(new_slope_word, RIGHT)
|
||||||
dy_dx.add_background_rectangle()
|
dy_dx.add_background_rectangle()
|
||||||
|
|
||||||
self.play(Transform(slope_word, new_slope_word))
|
self.play(Transform(slope_word, new_slope_word))
|
||||||
self.play(Write(dy_dx))
|
self.play(Write(dy_dx))
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
self.dy_dx = dy_dx
|
||||||
|
|
||||||
def point_out_this_is_not_a_graph(self):
|
def point_out_this_is_not_a_graph(self):
|
||||||
equation = self.circle_equation
|
equation = self.circle_equation
|
||||||
x = equation[1][0]
|
x = equation[1][0]
|
||||||
@ -364,13 +361,370 @@ class SlopeOfCircleExample(ZoomedScene):
|
|||||||
|
|
||||||
def perform_implicit_derivative(self):
|
def perform_implicit_derivative(self):
|
||||||
equation = self.circle_equation
|
equation = self.circle_equation
|
||||||
|
morty = Mortimer()
|
||||||
|
morty.flip()
|
||||||
|
morty.next_to(ORIGIN, LEFT)
|
||||||
|
morty.to_edge(DOWN, buff = SMALL_BUFF)
|
||||||
|
q_marks = TexMobject("???")
|
||||||
|
q_marks.next_to(morty, UP)
|
||||||
|
|
||||||
def show_rearrangement(self):
|
rect = Rectangle(
|
||||||
pass
|
width = SPACE_WIDTH - SMALL_BUFF,
|
||||||
|
height = SPACE_HEIGHT - SMALL_BUFF,
|
||||||
|
stroke_width = 0,
|
||||||
|
fill_color = BLACK,
|
||||||
|
fill_opacity = 0.8,
|
||||||
|
)
|
||||||
|
rect.to_corner(DOWN+RIGHT, buff = 0)
|
||||||
|
|
||||||
|
derivative = TexMobject("2x\\,dx + 2y\\,dy = 0")
|
||||||
|
dx = VGroup(*derivative[2:4])
|
||||||
|
dy = VGroup(*derivative[7:9])
|
||||||
|
dx.highlight(GREEN)
|
||||||
|
dy.highlight(RED)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeIn(rect),
|
||||||
|
FadeIn(morty),
|
||||||
|
equation.next_to, ORIGIN, DOWN, MED_LARGE_BUFF,
|
||||||
|
equation.shift, SPACE_WIDTH*RIGHT/2,
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
morty.change_mode, "confused",
|
||||||
|
morty.look_at, equation
|
||||||
|
)
|
||||||
|
self.play(Blink(morty))
|
||||||
|
derivative.next_to(equation, DOWN)
|
||||||
|
derivative.shift(
|
||||||
|
equation[1][-3].get_center()[0]*RIGHT - \
|
||||||
|
derivative[-2].get_center()[0]*RIGHT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#Differentiate
|
||||||
|
self.play(
|
||||||
|
morty.look_at, derivative[0],
|
||||||
|
*[
|
||||||
|
ReplacementTransform(
|
||||||
|
equation[1][i].copy(),
|
||||||
|
derivative[j],
|
||||||
|
)
|
||||||
|
for i, j in (1, 0), (0, 1)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.play(Write(dx, run_time = 1))
|
||||||
|
self.dither()
|
||||||
|
self.play(*[
|
||||||
|
ReplacementTransform(
|
||||||
|
equation[1][i].copy(),
|
||||||
|
derivative[j],
|
||||||
|
)
|
||||||
|
for i, j in (2, 4), (3, 6), (4, 5)
|
||||||
|
])
|
||||||
|
self.play(Write(dy, run_time = 1))
|
||||||
|
self.play(Blink(morty))
|
||||||
|
self.play(*[
|
||||||
|
ReplacementTransform(
|
||||||
|
equation[1][i].copy(),
|
||||||
|
derivative[j],
|
||||||
|
)
|
||||||
|
for i, j in (-3, -2), (-2, -1), (-1, -1)
|
||||||
|
])
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
#React
|
||||||
|
self.play(morty.change_mode, "erm")
|
||||||
|
self.play(Blink(morty))
|
||||||
|
self.play(Write(q_marks))
|
||||||
|
self.dither()
|
||||||
|
self.play(Indicate(dx), morty.look_at, dx)
|
||||||
|
self.play(Indicate(dy), morty.look_at, dy)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
morty.change_mode, "shruggie",
|
||||||
|
FadeOut(q_marks)
|
||||||
|
)
|
||||||
|
self.play(Blink(morty))
|
||||||
|
self.play(
|
||||||
|
morty.change_mode, "pondering",
|
||||||
|
morty.look_at, derivative,
|
||||||
|
)
|
||||||
|
|
||||||
|
#Rearrange
|
||||||
|
x, y, eq = np.array(derivative)[[1, 6, 9]]
|
||||||
|
final_form = TexMobject(
|
||||||
|
"\\frac{dy}{dx} = \\frac{-x}{y}"
|
||||||
|
)
|
||||||
|
new_dy = VGroup(*final_form[:2])
|
||||||
|
new_dx = VGroup(*final_form[3:5])
|
||||||
|
new_dy.highlight(dy.get_color())
|
||||||
|
new_dx.highlight(dx.get_color())
|
||||||
|
new_dy.add(final_form[2])
|
||||||
|
new_x = VGroup(*final_form[6:8])
|
||||||
|
new_y = VGroup(*final_form[8:10])
|
||||||
|
new_eq = final_form[5]
|
||||||
|
|
||||||
|
final_form.next_to(derivative, DOWN)
|
||||||
|
final_form.shift((eq.get_center()[0]-new_eq.get_center()[0])*RIGHT)
|
||||||
|
|
||||||
|
|
||||||
|
self.play(*[
|
||||||
|
ReplacementTransform(
|
||||||
|
mover.copy(), target,
|
||||||
|
run_time = 2,
|
||||||
|
path_arc = np.pi/2,
|
||||||
|
)
|
||||||
|
for mover, target in [
|
||||||
|
(dy, new_dy),
|
||||||
|
(dx, new_dx),
|
||||||
|
(eq, new_eq),
|
||||||
|
(x, new_x),
|
||||||
|
(y, new_y)
|
||||||
|
]
|
||||||
|
] + [
|
||||||
|
morty.look_at, final_form
|
||||||
|
])
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
self.morty = morty
|
||||||
|
self.neg_x_over_y = VGroup(*final_form[6:])
|
||||||
|
|
||||||
def show_final_slope(self):
|
def show_final_slope(self):
|
||||||
pass
|
morty = self.morty
|
||||||
|
dy_dx = self.dy_dx
|
||||||
|
coords = self.example_point_coords_mob
|
||||||
|
x, y = coords[1][1].copy(), coords[1][3].copy()
|
||||||
|
|
||||||
|
frac = self.neg_x_over_y.copy()
|
||||||
|
frac.generate_target()
|
||||||
|
eq = TexMobject("=")
|
||||||
|
eq.add_background_rectangle()
|
||||||
|
eq.next_to(dy_dx, RIGHT)
|
||||||
|
frac.target.next_to(eq, RIGHT)
|
||||||
|
frac.target.shift(SMALL_BUFF*DOWN)
|
||||||
|
rect = BackgroundRectangle(frac.target)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
FadeIn(rect),
|
||||||
|
MoveToTarget(frac),
|
||||||
|
Write(eq),
|
||||||
|
morty.look_at, rect,
|
||||||
|
run_time = 2,
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(FocusOn(coords), morty.look_at, coords)
|
||||||
|
self.play(Indicate(coords))
|
||||||
|
scale_factor = 1.4
|
||||||
|
self.play(
|
||||||
|
x.scale, scale_factor,
|
||||||
|
x.highlight, GREEN,
|
||||||
|
x.move_to, frac[1],
|
||||||
|
FadeOut(frac[1]),
|
||||||
|
y.scale, scale_factor,
|
||||||
|
y.highlight, RED,
|
||||||
|
y.move_to, frac[3], DOWN,
|
||||||
|
y.shift, SMALL_BUFF*UP,
|
||||||
|
FadeOut(frac[3]),
|
||||||
|
morty.look_at, frac,
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(Blink(morty))
|
||||||
|
|
||||||
|
class NameImplicitDifferentation(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
title = TextMobject("``Implicit differentiation''")
|
||||||
|
|
||||||
|
equation = TexMobject("x^2", "+", "y^2", "=", "5^2")
|
||||||
|
derivative = TexMobject(
|
||||||
|
"2x\\,dx", "+", "2y\\,dy", "=", "0"
|
||||||
|
)
|
||||||
|
VGroup(*derivative[0][2:]).highlight(GREEN)
|
||||||
|
VGroup(*derivative[2][2:]).highlight(RED)
|
||||||
|
arrow = Arrow(ORIGIN, DOWN, buff = SMALL_BUFF)
|
||||||
|
group = VGroup(title, equation, arrow, derivative)
|
||||||
|
group.arrange_submobjects(DOWN)
|
||||||
|
group.to_edge(UP)
|
||||||
|
|
||||||
|
self.add(title, equation)
|
||||||
|
self.play(
|
||||||
|
self.get_teacher().change_mode, "raise_right_hand",
|
||||||
|
ShowCreation(arrow)
|
||||||
|
)
|
||||||
|
self.change_student_modes(
|
||||||
|
*["confused"]*3,
|
||||||
|
look_at_arg = derivative,
|
||||||
|
added_anims = [ReplacementTransform(equation.copy(), derivative)]
|
||||||
|
)
|
||||||
|
self.dither(2)
|
||||||
|
self.teacher_says(
|
||||||
|
"Don't worry...",
|
||||||
|
added_anims = [
|
||||||
|
group.scale, 0.7,
|
||||||
|
group.to_corner, UP+LEFT,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.change_student_modes(*["happy"]*3)
|
||||||
|
self.dither(3)
|
||||||
|
|
||||||
|
class Ladder(VMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"height" : 4,
|
||||||
|
"width" : 1,
|
||||||
|
"n_rungs" : 6,
|
||||||
|
}
|
||||||
|
def generate_points(self):
|
||||||
|
left_line, right_line = [
|
||||||
|
Line(ORIGIN, self.height*UP).shift(self.width*vect/2.0)
|
||||||
|
for vect in LEFT, RIGHT
|
||||||
|
]
|
||||||
|
rungs = [
|
||||||
|
Line(
|
||||||
|
left_line.point_from_proportion(a),
|
||||||
|
right_line.point_from_proportion(a),
|
||||||
|
)
|
||||||
|
for a in np.linspace(0, 1, self.n_rungs+2)[1:-1]
|
||||||
|
]
|
||||||
|
self.add(left_line, right_line, *rungs)
|
||||||
|
self.center()
|
||||||
|
|
||||||
|
|
||||||
|
class RelatedRatesExample(ThreeDScene):
|
||||||
|
CONFIG = {
|
||||||
|
"start_x" : 3.0,
|
||||||
|
"start_y" : 4.0,
|
||||||
|
"wall_color" : color_gradient([GREY_BROWN, BLACK], 4)[1],
|
||||||
|
"wall_center" : LEFT,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
should_skip_animations = self.skip_animations
|
||||||
|
self.skip_animations = True
|
||||||
|
|
||||||
|
self.introduce_ladder()
|
||||||
|
self.write_related_rates()
|
||||||
|
self.measure_ladder()
|
||||||
|
self.skip_animations = should_skip_animations
|
||||||
|
self.slide_ladder()
|
||||||
|
|
||||||
|
def introduce_ladder(self):
|
||||||
|
ladder = Ladder(height = self.get_ladder_length())
|
||||||
|
|
||||||
|
wall = Prism(
|
||||||
|
dimensions = [0.5, 6, 5],
|
||||||
|
fill_color = self.wall_color,
|
||||||
|
fill_opacity = 1,
|
||||||
|
)
|
||||||
|
wall.rotate(np.pi/12, UP)
|
||||||
|
wall.shift(self.wall_center)
|
||||||
|
|
||||||
|
ladder.generate_target()
|
||||||
|
ladder.fallen = ladder.copy()
|
||||||
|
ladder.target.rotate(self.get_ladder_angle(), LEFT)
|
||||||
|
ladder.fallen.rotate(np.pi/2, LEFT)
|
||||||
|
for ladder_copy in ladder.target, ladder.fallen:
|
||||||
|
ladder_copy.rotate(-5*np.pi/12, UP)
|
||||||
|
ladder_copy.next_to(wall, LEFT, 0, DOWN)
|
||||||
|
ladder_copy.shift(LARGE_BUFF*RIGHT)
|
||||||
|
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
ShowCreation(ladder, run_time = 2)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
DrawBorderThenFill(wall),
|
||||||
|
MoveToTarget(ladder),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
self.ladder = ladder
|
||||||
|
|
||||||
|
def write_related_rates(self):
|
||||||
|
words = TextMobject("Related rates")
|
||||||
|
words.to_corner(UP+RIGHT)
|
||||||
|
self.play(Write(words))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def measure_ladder(self):
|
||||||
|
ladder = self.ladder
|
||||||
|
ladder_brace = self.get_ladder_brace(ladder)
|
||||||
|
|
||||||
|
x_and_y_lines = self.get_x_and_y_lines(ladder)
|
||||||
|
x_line, y_line = x_and_y_lines
|
||||||
|
|
||||||
|
y_label = TexMobject("%dm"%int(self.start_y))
|
||||||
|
y_label.next_to(y_line, LEFT, buff = SMALL_BUFF)
|
||||||
|
y_label.highlight(y_line.get_color())
|
||||||
|
|
||||||
|
x_label = TexMobject("%dm"%int(self.start_x))
|
||||||
|
x_label.next_to(x_line, UP)
|
||||||
|
x_label.highlight(x_line.get_color())
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
GrowFromCenter(ladder_brace),
|
||||||
|
Write(ladder_brace.length_label),
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(ShowCreation(y_line), Write(y_label))
|
||||||
|
self.dither()
|
||||||
|
self.play(ShowCreation(x_line), Write(x_label))
|
||||||
|
self.dither(2)
|
||||||
|
self.play(*map(FadeOut, [x_label, y_label]))
|
||||||
|
|
||||||
|
self.ladder_brace = ladder_brace
|
||||||
|
self.x_and_y_lines = x_and_y_lines
|
||||||
|
|
||||||
|
def slide_ladder(self):
|
||||||
|
ladder = self.ladder
|
||||||
|
brace = self.ladder_brace
|
||||||
|
x_and_y_lines = self.x_and_y_lines
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Transform(
|
||||||
|
ladder, ladder.fallen,
|
||||||
|
rate_func = None,
|
||||||
|
run_time = self.start_y,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
|
||||||
|
#########
|
||||||
|
|
||||||
|
def get_ladder_brace(self, ladder):
|
||||||
|
vect = rotate_vector(LEFT, -self.get_ladder_angle())
|
||||||
|
brace = Brace(ladder, vect)
|
||||||
|
length_string = "%dm"%int(self.get_ladder_length())
|
||||||
|
length_label = brace.get_text(length_string)
|
||||||
|
brace.length_label = length_label
|
||||||
|
return brace
|
||||||
|
|
||||||
|
def get_x_and_y_lines(self, ladder):
|
||||||
|
top_point = ladder.get_corner(UP+RIGHT)
|
||||||
|
bottom_point = ladder.get_corner(DOWN+LEFT)
|
||||||
|
interim_point = top_point[0]*RIGHT + bottom_point[1]*UP
|
||||||
|
y_line = Line(top_point, interim_point)
|
||||||
|
y_line.highlight(RED)
|
||||||
|
x_line = Line(bottom_point, interim_point)
|
||||||
|
x_line.highlight(GREEN)
|
||||||
|
|
||||||
|
return VGroup(x_line, y_line)
|
||||||
|
|
||||||
|
def get_ladder_angle(self):
|
||||||
|
if hasattr(self, "ladder"):
|
||||||
|
c1 = self.ladder.get_corner(UP+RIGHT)
|
||||||
|
c2 = self.ladder.get_corner(DOWN+LEFT)
|
||||||
|
vect = c1-c2
|
||||||
|
return np.pi/2 - angle_of_vector(vect)
|
||||||
|
else:
|
||||||
|
return np.arctan(self.start_x/self.start_y)
|
||||||
|
|
||||||
|
def get_ladder_length(self):
|
||||||
|
return np.linalg.norm([self.start_x, self.start_y])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ class Mobject(object):
|
|||||||
self.do_in_place(self.stretch, factor, dim)
|
self.do_in_place(self.stretch, factor, dim)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def stretch_to_fit(self, length, dim, stretch = True):
|
def rescale_to_fit(self, length, dim, stretch = False):
|
||||||
old_length = self.length_over_dim(dim)
|
old_length = self.length_over_dim(dim)
|
||||||
if old_length == 0:
|
if old_length == 0:
|
||||||
return self
|
return self
|
||||||
@ -303,16 +303,16 @@ class Mobject(object):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def stretch_to_fit_width(self, width):
|
def stretch_to_fit_width(self, width):
|
||||||
return self.stretch_to_fit(width, 0)
|
return self.rescale_to_fit(width, 0, stretch = True)
|
||||||
|
|
||||||
def stretch_to_fit_height(self, height):
|
def stretch_to_fit_height(self, height):
|
||||||
return self.stretch_to_fit(height, 1)
|
return self.rescale_to_fit(height, 1, stretch = True)
|
||||||
|
|
||||||
def scale_to_fit_width(self, width):
|
def scale_to_fit_width(self, width):
|
||||||
return self.stretch_to_fit(width, 0, stretch = False)
|
return self.rescale_to_fit(width, 0, stretch = False)
|
||||||
|
|
||||||
def scale_to_fit_height(self, height):
|
def scale_to_fit_height(self, height):
|
||||||
return self.stretch_to_fit(height, 1, stretch = False)
|
return self.rescale_to_fit(height, 1, stretch = False)
|
||||||
|
|
||||||
def space_out_submobjects(self, factor = 1.5, **kwargs):
|
def space_out_submobjects(self, factor = 1.5, **kwargs):
|
||||||
self.scale_in_place(factor)
|
self.scale_in_place(factor)
|
||||||
@ -337,7 +337,7 @@ class Mobject(object):
|
|||||||
self.stretch_to_fit_width(mobject.get_width())
|
self.stretch_to_fit_width(mobject.get_width())
|
||||||
self.stretch_to_fit_height(mobject.get_height())
|
self.stretch_to_fit_height(mobject.get_height())
|
||||||
else:
|
else:
|
||||||
self.stretch_to_fit(
|
self.rescale_to_fit(
|
||||||
mobject.length_over_dim(dim_to_match),
|
mobject.length_over_dim(dim_to_match),
|
||||||
dim_to_match,
|
dim_to_match,
|
||||||
stretch = False
|
stretch = False
|
||||||
|
@ -171,7 +171,7 @@ class Brace(TexMobject):
|
|||||||
mob.rotate(angle)
|
mob.rotate(angle)
|
||||||
|
|
||||||
def put_at_tip(self, mob, **kwargs):
|
def put_at_tip(self, mob, **kwargs):
|
||||||
mob.next_to(self, self.direction, **kwargs)
|
mob.next_to(self.get_tip(), self.get_direction(), **kwargs)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_text(self, *text, **kwargs):
|
def get_text(self, *text, **kwargs):
|
||||||
@ -179,6 +179,17 @@ class Brace(TexMobject):
|
|||||||
self.put_at_tip(text_mob, **kwargs)
|
self.put_at_tip(text_mob, **kwargs)
|
||||||
return text_mob
|
return text_mob
|
||||||
|
|
||||||
|
def get_tip(self):
|
||||||
|
# Very specific to the LaTeX representation
|
||||||
|
# of a brace, but it's the only way I can think
|
||||||
|
# of to get the tip regardless of orientation.
|
||||||
|
return self.submobjects[2].get_anchors()[7]
|
||||||
|
|
||||||
|
def get_direction(self):
|
||||||
|
vect = self.get_tip() - self.get_center()
|
||||||
|
return vect/np.linalg.norm(vect)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def tex_hash(expression, template_tex_file):
|
def tex_hash(expression, template_tex_file):
|
||||||
|
@ -24,7 +24,7 @@ class CameraWithPerspective(Camera):
|
|||||||
|
|
||||||
class ThreeDCamera(CameraWithPerspective):
|
class ThreeDCamera(CameraWithPerspective):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"sun_vect" : 3*UP+LEFT,
|
"sun_vect" : 5*UP+LEFT,
|
||||||
"shading_factor" : 0.5,
|
"shading_factor" : 0.5,
|
||||||
}
|
}
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -66,18 +66,16 @@ class ThreeDCamera(CameraWithPerspective):
|
|||||||
|
|
||||||
def display_multiple_vectorized_mobjects(self, vmobjects):
|
def display_multiple_vectorized_mobjects(self, vmobjects):
|
||||||
def z_cmp(*vmobs):
|
def z_cmp(*vmobs):
|
||||||
is_three_d = np.array([
|
#Compare to three dimensional mobjects based on their
|
||||||
hasattr(vm, "part_of_three_d_mobject")
|
#z value, otherwise don't compare.
|
||||||
for vm in vmobs
|
is_three_d = [hasattr(vm, "part_of_3d_mobject") for vm in vmobs]
|
||||||
])
|
has_points = [vm.get_num_points() > 0 for vm in vmobs]
|
||||||
if sum(is_three_d) == 2:
|
if all(is_three_d) and all(has_points):
|
||||||
cmp_vect = self.get_unit_normal_vect(vmobs[0])
|
cmp_vect = self.get_unit_normal_vect(vm)
|
||||||
return cmp(*[
|
return cmp(*[
|
||||||
np.dot(vm.get_center(), cmp_vect)
|
np.dot(vm.get_center(), cmp_vect)
|
||||||
for vm in vmobs
|
for vm in vmobs
|
||||||
])
|
])
|
||||||
elif sum(is_three_d) == 1:
|
|
||||||
return 1 if is_three_d[0] else -1
|
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
Camera.display_multiple_vectorized_mobjects(
|
Camera.display_multiple_vectorized_mobjects(
|
||||||
@ -95,7 +93,7 @@ class ThreeDMobject(VMobject):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
VMobject.__init__(self, **kwargs)
|
VMobject.__init__(self, **kwargs)
|
||||||
for submobject in self.submobject_family():
|
for submobject in self.submobject_family():
|
||||||
submobject.part_of_three_d_mobject = True
|
submobject.part_of_3d_mobject = True
|
||||||
|
|
||||||
class Cube(ThreeDMobject):
|
class Cube(ThreeDMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
@ -113,7 +111,14 @@ class Cube(ThreeDMobject):
|
|||||||
|
|
||||||
self.add(face)
|
self.add(face)
|
||||||
|
|
||||||
|
class Prism(Cube):
|
||||||
|
CONFIG = {
|
||||||
|
"dimensions" : [3, 2, 1]
|
||||||
|
}
|
||||||
|
def generate_points(self):
|
||||||
|
Cube.generate_points(self)
|
||||||
|
for dim, value in enumerate(self.dimensions):
|
||||||
|
self.rescale_to_fit(value, dim, stretch = True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user