mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 08:54:38 +08:00
Beginning of eoc8
This commit is contained in:
130
eoc/chapter2.py
130
eoc/chapter2.py
@ -53,6 +53,7 @@ class Car(SVGMobject):
|
||||
randy.look(RIGHT)
|
||||
randy.move_to(self)
|
||||
randy.shift(0.07*self.height*(RIGHT+UP))
|
||||
self.randy = randy
|
||||
self.add_to_back(randy)
|
||||
|
||||
orientation_line = Line(self.get_left(), self.get_right())
|
||||
@ -318,10 +319,11 @@ class IntroduceCar(Scene):
|
||||
CONFIG = {
|
||||
"should_transition_to_graph" : True,
|
||||
"show_distance" : True,
|
||||
"point_A" : DOWN+4*LEFT,
|
||||
"point_B" : DOWN+5*RIGHT,
|
||||
}
|
||||
def construct(self):
|
||||
point_A = DOWN+4*LEFT
|
||||
point_B = DOWN+5*RIGHT
|
||||
point_A, point_B = self.point_A, self.point_B
|
||||
A = Dot(point_A)
|
||||
B = Dot(point_B)
|
||||
line = Line(point_A, point_B)
|
||||
@ -411,6 +413,8 @@ class GraphCarTrajectory(GraphScene):
|
||||
"graph_origin" : 2.5*DOWN + 5*LEFT,
|
||||
"default_graph_colors" : [DISTANCE_COLOR, VELOCITY_COLOR],
|
||||
"default_derivative_color" : VELOCITY_COLOR,
|
||||
"time_of_journey" : 10,
|
||||
"care_movement_rate_func" : smooth,
|
||||
}
|
||||
def construct(self):
|
||||
self.setup_axes(animate = False)
|
||||
@ -423,10 +427,11 @@ class GraphCarTrajectory(GraphScene):
|
||||
self.ask_critically_about_velocity()
|
||||
|
||||
def graph_sigmoid_trajectory_function(self, **kwargs):
|
||||
graph = self.graph_function(
|
||||
graph = self.get_graph(
|
||||
lambda t : 100*smooth(t/10.),
|
||||
**kwargs
|
||||
)
|
||||
self.s_graph = graph
|
||||
return graph
|
||||
|
||||
def introduce_graph(self, graph, origin):
|
||||
@ -446,6 +451,9 @@ class GraphCarTrajectory(GraphScene):
|
||||
car = Car()
|
||||
car.rotate(np.pi/2)
|
||||
car.move_to(origin)
|
||||
car_target = origin*RIGHT + graph.point_from_proportion(1)*UP
|
||||
|
||||
|
||||
self.add(car)
|
||||
self.play(
|
||||
ShowCreation(
|
||||
@ -453,11 +461,12 @@ class GraphCarTrajectory(GraphScene):
|
||||
rate_func = None,
|
||||
),
|
||||
MoveCar(
|
||||
car, self.coords_to_point(0, 100),
|
||||
car, car_target,
|
||||
rate_func = self.care_movement_rate_func
|
||||
),
|
||||
UpdateFromFunc(h_line, h_update),
|
||||
UpdateFromFunc(v_line, v_update),
|
||||
run_time = 10,
|
||||
run_time = self.time_of_journey,
|
||||
)
|
||||
self.dither()
|
||||
self.play(*map(FadeOut, [h_line, v_line, car]))
|
||||
@ -537,8 +546,12 @@ class GraphCarTrajectory(GraphScene):
|
||||
self.rect = rect
|
||||
|
||||
def get_change_lines(self, curr_time, delta_t = 1):
|
||||
p1 = self.input_to_graph_point(curr_time)
|
||||
p2 = self.input_to_graph_point(curr_time+delta_t)
|
||||
p1 = self.input_to_graph_point(
|
||||
curr_time, self.s_graph
|
||||
)
|
||||
p2 = self.input_to_graph_point(
|
||||
curr_time+delta_t, self.s_graph
|
||||
)
|
||||
interim_point = p2[0]*RIGHT + p1[1]*UP
|
||||
delta_t_line = Line(p1, interim_point, color = TIME_COLOR)
|
||||
delta_s_line = Line(interim_point, p2, color = DISTANCE_COLOR)
|
||||
@ -546,17 +559,16 @@ class GraphCarTrajectory(GraphScene):
|
||||
return VGroup(delta_t_line, delta_s_line, brace)
|
||||
|
||||
def show_velocity_graph(self):
|
||||
velocity_graph = self.get_derivative_graph()
|
||||
velocity_graph = self.get_derivative_graph(self.s_graph)
|
||||
|
||||
self.play(ShowCreation(velocity_graph))
|
||||
def get_velocity_label(v_graph):
|
||||
result = self.label_graph(
|
||||
result = self.get_graph_label(
|
||||
v_graph,
|
||||
label = "v(t)",
|
||||
direction = UP+RIGHT,
|
||||
proportion = 0.5,
|
||||
x_val = 5,
|
||||
buff = SMALL_BUFF,
|
||||
animate = False,
|
||||
)
|
||||
self.remove(result)
|
||||
return result
|
||||
@ -580,7 +592,7 @@ class GraphCarTrajectory(GraphScene):
|
||||
self.play(FadeOut(self.rect))
|
||||
|
||||
#Change distance and velocity graphs
|
||||
self.graph.save_state()
|
||||
self.s_graph.save_state()
|
||||
velocity_graph.save_state()
|
||||
label.save_state()
|
||||
def shallow_slope(t):
|
||||
@ -598,10 +610,9 @@ class GraphCarTrajectory(GraphScene):
|
||||
double_smooth_graph_function,
|
||||
]
|
||||
for graph_func in graph_funcs:
|
||||
new_graph = self.graph_function(
|
||||
new_graph = self.get_graph(
|
||||
graph_func,
|
||||
color = DISTANCE_COLOR,
|
||||
is_main_graph = False
|
||||
)
|
||||
self.remove(new_graph)
|
||||
new_velocity_graph = self.get_derivative_graph(
|
||||
@ -609,13 +620,13 @@ class GraphCarTrajectory(GraphScene):
|
||||
)
|
||||
new_velocity_label = get_velocity_label(new_velocity_graph)
|
||||
|
||||
self.play(Transform(self.graph, new_graph))
|
||||
self.play(Transform(self.s_graph, new_graph))
|
||||
self.play(
|
||||
Transform(velocity_graph, new_velocity_graph),
|
||||
Transform(label, new_velocity_label),
|
||||
)
|
||||
self.dither(2)
|
||||
self.play(self.graph.restore)
|
||||
self.play(self.s_graph.restore)
|
||||
self.play(
|
||||
velocity_graph.restore,
|
||||
label.restore,
|
||||
@ -640,11 +651,12 @@ class ShowSpeedometer(IntroduceCar):
|
||||
"needle_height" : 0.8,
|
||||
"should_transition_to_graph" : False,
|
||||
"show_distance" : False,
|
||||
"speedometer_title_text" : "Speedometer",
|
||||
}
|
||||
def setup(self):
|
||||
start_angle = -np.pi/6
|
||||
end_angle = 7*np.pi/6
|
||||
speedomoeter = Arc(
|
||||
speedometer = Arc(
|
||||
start_angle = start_angle,
|
||||
angle = end_angle-start_angle
|
||||
)
|
||||
@ -655,7 +667,7 @@ class ShowSpeedometer(IntroduceCar):
|
||||
label = TexMobject(str(10*index))
|
||||
label.scale_to_fit_height(self.tick_length)
|
||||
label.shift((1+self.tick_length)*vect)
|
||||
speedomoeter.add(tick, label)
|
||||
speedometer.add(tick, label)
|
||||
|
||||
needle = Polygon(
|
||||
LEFT, UP, RIGHT,
|
||||
@ -666,46 +678,45 @@ class ShowSpeedometer(IntroduceCar):
|
||||
needle.stretch_to_fit_width(self.needle_width)
|
||||
needle.stretch_to_fit_height(self.needle_height)
|
||||
needle.rotate(end_angle-np.pi/2)
|
||||
speedomoeter.add(needle)
|
||||
speedomoeter.needle = needle
|
||||
speedometer.add(needle)
|
||||
speedometer.needle = needle
|
||||
|
||||
speedomoeter.center_offset = speedomoeter.get_center()
|
||||
speedometer.center_offset = speedometer.get_center()
|
||||
|
||||
speedomoeter_title = TextMobject("Speedometer")
|
||||
speedomoeter_title.to_corner(UP+LEFT)
|
||||
speedomoeter.next_to(speedomoeter_title, DOWN)
|
||||
speedometer_title = TextMobject(self.speedometer_title_text)
|
||||
speedometer_title.to_corner(UP+LEFT)
|
||||
speedometer.next_to(speedometer_title, DOWN)
|
||||
|
||||
self.speedomoeter = speedomoeter
|
||||
self.speedomoeter_title = speedomoeter_title
|
||||
self.speedometer = speedometer
|
||||
self.speedometer_title = speedometer_title
|
||||
|
||||
def introduce_added_mobjects(self):
|
||||
speedomoeter = self.speedomoeter
|
||||
speedomoeter_title = self.speedomoeter_title
|
||||
speedometer = self.speedometer
|
||||
speedometer_title = self.speedometer_title
|
||||
|
||||
speedomoeter.save_state()
|
||||
speedomoeter.rotate(-np.pi/2, UP)
|
||||
speedomoeter.scale_to_fit_height(self.car.get_height()/4)
|
||||
speedomoeter.move_to(self.car)
|
||||
speedomoeter.shift((self.car.get_width()/4)*RIGHT)
|
||||
speedometer.save_state()
|
||||
speedometer.rotate(-np.pi/2, UP)
|
||||
speedometer.scale_to_fit_height(self.car.get_height()/4)
|
||||
speedometer.move_to(self.car)
|
||||
speedometer.shift((self.car.get_width()/4)*RIGHT)
|
||||
|
||||
self.play(speedomoeter.restore, run_time = 2)
|
||||
self.play(Write(speedomoeter_title, run_time = 1))
|
||||
self.play(speedometer.restore, run_time = 2)
|
||||
self.play(Write(speedometer_title, run_time = 1))
|
||||
|
||||
def get_added_movement_anims(self):
|
||||
needle = self.speedomoeter.needle
|
||||
center = self.speedomoeter.get_center() - self.speedomoeter.center_offset
|
||||
return [
|
||||
Rotating(
|
||||
needle,
|
||||
about_point = center,
|
||||
radians = -np.pi/2,
|
||||
run_time = 10,
|
||||
rate_func = there_and_back
|
||||
)
|
||||
]
|
||||
def get_added_movement_anims(self, **kwargs):
|
||||
needle = self.speedometer.needle
|
||||
center = self.speedometer.get_center() - self.speedometer.center_offset
|
||||
default_kwargs = {
|
||||
"about_point" : center,
|
||||
"radians" : -np.pi/2,
|
||||
"run_time" : 10,
|
||||
"rate_func" : there_and_back,
|
||||
}
|
||||
default_kwargs.update(kwargs)
|
||||
return [Rotating(needle, **default_kwargs)]
|
||||
|
||||
# def construct(self):
|
||||
# self.add(self.speedomoeter)
|
||||
# self.add(self.speedometer)
|
||||
# self.play(*self.get_added_movement_anims())
|
||||
|
||||
class VelocityInAMomentMakesNoSense(Scene):
|
||||
@ -985,8 +996,8 @@ class SidestepParadox(Scene):
|
||||
car = Car()
|
||||
car.shift(DOWN)
|
||||
show_speedometer = ShowSpeedometer(skip_animations = True)
|
||||
speedomoeter = show_speedometer.speedomoeter
|
||||
speedomoeter.next_to(car, UP)
|
||||
speedometer = show_speedometer.speedometer
|
||||
speedometer.next_to(car, UP)
|
||||
|
||||
title = TextMobject(
|
||||
"Instantaneous", "rate of change"
|
||||
@ -1001,7 +1012,7 @@ class SidestepParadox(Scene):
|
||||
new_words.highlight(TIME_COLOR)
|
||||
|
||||
self.add(title, car)
|
||||
self.play(Write(speedomoeter))
|
||||
self.play(Write(speedometer))
|
||||
self.dither()
|
||||
self.play(Write(cross))
|
||||
self.dither()
|
||||
@ -1379,7 +1390,7 @@ class SecantLineToTangentLine(GraphCarTrajectory, DefineTrueDerivative):
|
||||
|
||||
def get_ds_dt_group(self, dt, animate = False):
|
||||
points = [
|
||||
self.input_to_graph_point(time)
|
||||
self.input_to_graph_point(time, self.graph)
|
||||
for time in self.curr_time, self.curr_time+dt
|
||||
]
|
||||
dots = map(Dot, points)
|
||||
@ -1440,16 +1451,12 @@ class SecantLineToTangentLine(GraphCarTrajectory, DefineTrueDerivative):
|
||||
return 50*smooth(t/5.)
|
||||
else:
|
||||
return 50*(1+smooth((t-5)/5.))
|
||||
graph = self.graph_function(
|
||||
double_smooth_graph_function,
|
||||
animate = False
|
||||
)
|
||||
self.graph_label = self.label_graph(
|
||||
graph, "s(t)",
|
||||
proportion = 1,
|
||||
self.graph = self.get_graph(double_smooth_graph_function)
|
||||
self.graph_label = self.get_graph_label(
|
||||
self.graph, "s(t)",
|
||||
x_val = self.x_max,
|
||||
direction = DOWN+RIGHT,
|
||||
buff = SMALL_BUFF,
|
||||
animate = False
|
||||
)
|
||||
|
||||
def add_derivative_definition(self, target_upper_left):
|
||||
@ -1520,6 +1527,7 @@ class SecantLineToTangentLine(GraphCarTrajectory, DefineTrueDerivative):
|
||||
|
||||
v_line = self.get_vertical_line_to_graph(
|
||||
self.curr_time,
|
||||
self.graph,
|
||||
line_class = Line,
|
||||
line_kwargs = {
|
||||
"color" : MAROON_B,
|
||||
@ -1529,7 +1537,7 @@ class SecantLineToTangentLine(GraphCarTrajectory, DefineTrueDerivative):
|
||||
def v_line_update(v_line):
|
||||
v_line.put_start_and_end_on(
|
||||
self.coords_to_point(self.curr_time, 0),
|
||||
self.input_to_graph_point(self.curr_time),
|
||||
self.input_to_graph_point(self.curr_time, self.graph),
|
||||
)
|
||||
return v_line
|
||||
self.play(ShowCreation(v_line))
|
||||
|
740
eoc/chapter8.py
Normal file
740
eoc/chapter8.py
Normal file
@ -0,0 +1,740 @@
|
||||
from helpers import *
|
||||
|
||||
from mobject.tex_mobject import TexMobject
|
||||
from mobject import Mobject
|
||||
from mobject.image_mobject import ImageMobject
|
||||
from mobject.vectorized_mobject import *
|
||||
|
||||
from animation.animation import Animation
|
||||
from animation.transform import *
|
||||
from animation.simple_animations import *
|
||||
from animation.playground import *
|
||||
from topics.geometry import *
|
||||
from topics.characters import *
|
||||
from topics.functions import *
|
||||
from topics.fractals import *
|
||||
from topics.number_line import *
|
||||
from topics.combinatorics import *
|
||||
from topics.numerals import *
|
||||
from topics.three_dimensions import *
|
||||
from topics.objects import *
|
||||
from scene import Scene
|
||||
from scene.zoomed_scene import ZoomedScene
|
||||
from scene.reconfigurable_scene import ReconfigurableScene
|
||||
from camera import Camera
|
||||
from mobject.svg_mobject import *
|
||||
from mobject.tex_mobject import *
|
||||
|
||||
from eoc.graph_scene import GraphScene
|
||||
from eoc.chapter2 import Car, MoveCar, ShowSpeedometer, \
|
||||
IncrementNumber, GraphCarTrajectory, SecantLineToTangentLine, \
|
||||
VELOCITY_COLOR, TIME_COLOR, DISTANCE_COLOR
|
||||
from topics.common_scenes import OpeningQuote, PatreonThanks
|
||||
|
||||
def v_rate_func(t):
|
||||
return 4*t - 4*(t**2)
|
||||
|
||||
def s_rate_func(t):
|
||||
return 3*(t**2) - 2*(t**3)
|
||||
|
||||
def v_func(t):
|
||||
return t*(8-t)
|
||||
|
||||
def s_func(t):
|
||||
return 4*t**2 - (t**3)/3.
|
||||
|
||||
|
||||
class Chapter8OpeningQuote(OpeningQuote, PiCreatureScene):
|
||||
CONFIG = {
|
||||
"quote" : [
|
||||
" One should never try to prove anything that \\\\ is not ",
|
||||
"almost obvious", ". "
|
||||
],
|
||||
"quote_arg_separator" : "",
|
||||
"highlighted_quote_terms" : {
|
||||
"almost obvious" : BLUE,
|
||||
},
|
||||
"author" : "Alexander Grothendieck"
|
||||
}
|
||||
def construct(self):
|
||||
self.remove(self.pi_creature)
|
||||
OpeningQuote.construct(self)
|
||||
|
||||
words_copy = self.quote.get_part_by_tex("obvious").copy()
|
||||
author = self.author
|
||||
author.save_state()
|
||||
formula = self.get_formula()
|
||||
formula.next_to(author, DOWN, MED_LARGE_BUFF)
|
||||
formula.to_edge(LEFT)
|
||||
|
||||
self.revert_to_original_skipping_status()
|
||||
self.play(FadeIn(self.pi_creature))
|
||||
self.play(
|
||||
author.next_to, self.pi_creature.get_corner(UP+LEFT), UP,
|
||||
self.pi_creature.change_mode, "raise_right_hand"
|
||||
)
|
||||
self.dither(3)
|
||||
self.play(
|
||||
author.restore,
|
||||
self.pi_creature.change_mode, "plain"
|
||||
)
|
||||
self.play(
|
||||
words_copy.next_to, self.pi_creature,
|
||||
LEFT, MED_SMALL_BUFF, UP,
|
||||
self.pi_creature.change_mode, "thinking"
|
||||
)
|
||||
self.dither(2)
|
||||
self.play(
|
||||
Write(formula),
|
||||
self.pi_creature.change_mode, "confused"
|
||||
)
|
||||
self.dither()
|
||||
|
||||
def get_formula(self):
|
||||
result = TexMobject(
|
||||
"{d(\\sin(\\theta)) \\over \\,", "d\\theta}", "=",
|
||||
"\\lim_{", "h", " \\to 0}",
|
||||
"{\\sin(\\theta+", "h", ") - \\sin(\\theta) \\over", " h}", "=",
|
||||
"\\lim_{", "h", " \\to 0}",
|
||||
"{\\big[ \\sin(\\theta)\\cos(", "h", ") + ",
|
||||
"\\sin(", "h", ")\\cos(\\theta)\\big] - \\sin(\\theta) \\over", "h}",
|
||||
"= \\dots"
|
||||
)
|
||||
result.highlight_by_tex("h", GREEN, substring = False)
|
||||
result.highlight_by_tex("d\\theta", GREEN)
|
||||
|
||||
result.scale_to_fit_width(2*SPACE_WIDTH - 2*MED_SMALL_BUFF)
|
||||
return result
|
||||
|
||||
class ThisVideo(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
series = VideoSeries()
|
||||
series.to_edge(UP)
|
||||
this_video = series[7]
|
||||
this_video.save_state()
|
||||
next_video = series[8]
|
||||
|
||||
deriv, integral, v_t, dt, equals, v_T = formula = TexMobject(
|
||||
"\\frac{d}{dT}",
|
||||
"\\int_0^T", "v(t)", "\\,dt",
|
||||
"=", "v(T)"
|
||||
)
|
||||
formula.highlight_by_tex("v", VELOCITY_COLOR)
|
||||
formula.next_to(self.teacher.get_corner(UP+LEFT), UP, MED_LARGE_BUFF)
|
||||
|
||||
self.play(FadeIn(series, submobject_mode = "lagged_start"))
|
||||
self.play(
|
||||
this_video.shift, this_video.get_height()*DOWN/2,
|
||||
this_video.highlight, YELLOW,
|
||||
self.teacher.change_mode, "raise_right_hand",
|
||||
)
|
||||
self.play(Write(VGroup(integral, v_t, dt)))
|
||||
self.change_student_modes(*["erm"]*3)
|
||||
self.dither()
|
||||
self.play(Write(VGroup(deriv, equals, v_T)), )
|
||||
self.change_student_modes(*["confused"]*3)
|
||||
self.dither(3)
|
||||
self.play(
|
||||
this_video.restore,
|
||||
next_video.shift, next_video.get_height()*DOWN/2,
|
||||
next_video.highlight, YELLOW,
|
||||
integral[0].copy().next_to, next_video, DOWN, MED_LARGE_BUFF,
|
||||
FadeOut(formula),
|
||||
*it.chain(*[
|
||||
[pi.change_mode, "plain", pi.look_at, next_video]
|
||||
for pi in self.pi_creatures
|
||||
])
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
class InCarRestrictedView(ShowSpeedometer):
|
||||
CONFIG = {
|
||||
"speedometer_title_text" : "Your view",
|
||||
}
|
||||
def construct(self):
|
||||
car = Car()
|
||||
car.move_to(self.point_A)
|
||||
self.car = car
|
||||
car.randy.save_state()
|
||||
Transform(car.randy, Randolph()).update(1)
|
||||
car.randy.next_to(car, RIGHT, MED_LARGE_BUFF)
|
||||
car.randy.look_at(car)
|
||||
|
||||
window = car[1][6].copy()
|
||||
window.is_subpath = False
|
||||
window.set_fill(BLACK, opacity = 0.75)
|
||||
window.set_stroke(width = 0)
|
||||
|
||||
square = Square(stroke_color = WHITE)
|
||||
square.replace(VGroup(self.speedometer, self.speedometer_title))
|
||||
square.scale_in_place(1.5)
|
||||
square.pointwise_become_partial(square, 0.25, 0.75)
|
||||
|
||||
time_label = TextMobject("Time (in seconds):", "0")
|
||||
time_label.shift(2*UP)
|
||||
|
||||
dots = VGroup(*map(Dot, [self.point_A, self.point_B]))
|
||||
line = Line(*dots, buff = 0)
|
||||
line.highlight(DISTANCE_COLOR)
|
||||
brace = Brace(line, DOWN)
|
||||
brace_text = brace.get_text("Distance traveled?")
|
||||
|
||||
|
||||
#Sit in car
|
||||
self.add(car)
|
||||
self.play(Blink(car.randy))
|
||||
self.play(car.randy.restore, Animation(car))
|
||||
self.play(ShowCreation(window, run_time = 2))
|
||||
self.dither()
|
||||
|
||||
#Show speedometer
|
||||
self.introduce_added_mobjects()
|
||||
self.play(ShowCreation(square))
|
||||
self.dither()
|
||||
|
||||
#Travel
|
||||
self.play(FadeIn(time_label))
|
||||
self.play(
|
||||
MoveCar(car, self.point_B, rate_func = s_rate_func),
|
||||
IncrementNumber(time_label[1], run_time = 8),
|
||||
MaintainPositionRelativeTo(window, car),
|
||||
*self.get_added_movement_anims(
|
||||
rate_func = v_rate_func,
|
||||
radians = -(16.0/70)*4*np.pi/3
|
||||
),
|
||||
run_time = 8
|
||||
)
|
||||
eight = TexMobject("8").move_to(time_label[1])
|
||||
self.play(Transform(
|
||||
time_label[1], eight,
|
||||
rate_func = squish_rate_func(smooth, 0, 0.5)
|
||||
))
|
||||
self.dither()
|
||||
|
||||
#Ask about distance
|
||||
self.play(*map(ShowCreation, dots))
|
||||
self.play(ShowCreation(line))
|
||||
self.play(
|
||||
GrowFromCenter(brace),
|
||||
Write(brace_text)
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
class GraphDistanceVsTime(GraphCarTrajectory):
|
||||
CONFIG = {
|
||||
"y_min" : 0,
|
||||
"y_max" : 100,
|
||||
"y_axis_height" : 6,
|
||||
"y_tick_frequency" : 10,
|
||||
"y_labeled_nums" : range(10, 100, 10),
|
||||
"y_axis_label" : "Distance (in meters)",
|
||||
"x_min" : -1,
|
||||
"x_max" : 9,
|
||||
"x_axis_width" : 9,
|
||||
"x_tick_frequency" : 1,
|
||||
"x_leftmost_tick" : None, #Change if different from x_min
|
||||
"x_labeled_nums" : range(1, 9),
|
||||
"x_axis_label" : "$t$",
|
||||
"time_of_journey" : 8,
|
||||
"care_movement_rate_func" : s_rate_func,
|
||||
"num_graph_anchor_points" : 100
|
||||
}
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
graph = self.get_graph(
|
||||
s_func,
|
||||
color = DISTANCE_COLOR,
|
||||
x_min = 0,
|
||||
x_max = 8,
|
||||
)
|
||||
origin = self.coords_to_point(0, 0)
|
||||
graph_label = self.get_graph_label(
|
||||
graph, "s(t)", color = DISTANCE_COLOR
|
||||
)
|
||||
self.introduce_graph(graph, origin)
|
||||
|
||||
class PlotVelocity(GraphScene):
|
||||
CONFIG = {
|
||||
"x_min" : -1,
|
||||
"x_max" : 9,
|
||||
"x_axis_width" : 9,
|
||||
"x_tick_frequency" : 1,
|
||||
"x_labeled_nums" : range(1, 9),
|
||||
"x_axis_label" : "$t$",
|
||||
"y_min" : 0,
|
||||
"y_max" : 25,
|
||||
"y_axis_height" : 6,
|
||||
"y_tick_frequency" : 5,
|
||||
"y_labeled_nums" : range(5, 30, 5),
|
||||
"y_axis_label" : "Velocity in $\\frac{\\text{meters}}{\\text{second}}$",
|
||||
}
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.add_speedometer()
|
||||
self.plot_points()
|
||||
self.draw_curve()
|
||||
|
||||
def add_speedometer(self):
|
||||
speedometer = Speedometer()
|
||||
speedometer.next_to(self.y_axis_label_mob, RIGHT, LARGE_BUFF)
|
||||
speedometer.to_edge(UP)
|
||||
|
||||
self.play(DrawBorderThenFill(
|
||||
speedometer,
|
||||
submobject_mode = "lagged_start",
|
||||
rate_func = None,
|
||||
))
|
||||
|
||||
self.speedometer = speedometer
|
||||
|
||||
def plot_points(self):
|
||||
times = range(0, 9)
|
||||
points = [
|
||||
self.coords_to_point(t, v_func(t))
|
||||
for t in times
|
||||
]
|
||||
dots = VGroup(*[Dot(p, radius = 0.07) for p in points])
|
||||
dots.highlight(VELOCITY_COLOR)
|
||||
|
||||
pre_dots = VGroup()
|
||||
dot_intro_anims = []
|
||||
|
||||
for time, dot in zip(times, dots):
|
||||
pre_dot = dot.copy()
|
||||
self.speedometer.move_needle_to_velocity(v_func(time))
|
||||
pre_dot.move_to(self.speedometer.get_needle_tip())
|
||||
pre_dot.set_fill(opacity = 0)
|
||||
pre_dots.add(pre_dot)
|
||||
dot_intro_anims += [
|
||||
ApplyMethod(
|
||||
pre_dot.set_fill, YELLOW, 1,
|
||||
run_time = 0.1,
|
||||
),
|
||||
ReplacementTransform(
|
||||
pre_dot, dot,
|
||||
run_time = 0.9,
|
||||
)
|
||||
]
|
||||
self.speedometer.move_needle_to_velocity(0)
|
||||
|
||||
self.play(
|
||||
Succession(
|
||||
*dot_intro_anims, rate_func = None
|
||||
),
|
||||
ApplyMethod(
|
||||
self.speedometer.move_needle_to_velocity,
|
||||
v_func(4),
|
||||
rate_func = squish_rate_func(
|
||||
lambda t : 1-v_rate_func(t),
|
||||
0, 0.95,
|
||||
)
|
||||
),
|
||||
run_time = 5
|
||||
)
|
||||
self.dither()
|
||||
|
||||
def draw_curve(self):
|
||||
graph, label = self.get_v_graph_and_label()
|
||||
|
||||
self.revert_to_original_skipping_status()
|
||||
self.play(ShowCreation(graph, run_time = 3))
|
||||
self.play(Write(graph_label))
|
||||
self.dither()
|
||||
|
||||
##
|
||||
|
||||
def get_v_graph_and_label(self):
|
||||
graph = self.get_graph(
|
||||
v_func,
|
||||
x_min = 0,
|
||||
x_max = 8,
|
||||
color = VELOCITY_COLOR
|
||||
)
|
||||
graph_label = TexMobject("v(t)", "=t(8-t)")
|
||||
graph_label.highlight_by_tex("v(t)", VELOCITY_COLOR)
|
||||
graph_label.next_to(
|
||||
graph.point_from_proportion(7./8.),
|
||||
UP+RIGHT
|
||||
)
|
||||
self.v_graph = graph
|
||||
self.v_graph_label = graph_label
|
||||
return graph, graph_label
|
||||
|
||||
class Chapter2Wrapper(Scene):
|
||||
def construct(self):
|
||||
title = TextMobject("Chapter 2: The paradox of the derivative")
|
||||
title.to_edge(UP)
|
||||
rect = Rectangle(width = 16, height = 9, color = WHITE)
|
||||
rect.scale_to_fit_height(1.5*SPACE_HEIGHT)
|
||||
rect.next_to(title, DOWN)
|
||||
|
||||
self.add(title)
|
||||
self.play(ShowCreation(rect))
|
||||
self.dither(3)
|
||||
|
||||
class GivenDistanceWhatIsVelocity(GraphCarTrajectory):
|
||||
def construct(self):
|
||||
self.force_skipping()
|
||||
self.setup_axes()
|
||||
graph = self.graph_sigmoid_trajectory_function()
|
||||
origin = self.coords_to_point(0, 0)
|
||||
|
||||
self.introduce_graph(graph, origin)
|
||||
self.comment_on_slope(graph, origin)
|
||||
self.revert_to_original_skipping_status()
|
||||
self.show_velocity_graph()
|
||||
|
||||
class DerivativeOfDistance(SecantLineToTangentLine):
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.remove(self.y_axis_label_mob, self.x_axis_label_mob)
|
||||
self.add_derivative_definition(self.y_axis_label_mob)
|
||||
self.add_graph()
|
||||
self.draw_axes()
|
||||
self.show_tangent_line()
|
||||
|
||||
class AskAboutAntiderivative(PlotVelocity):
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.add_v_graph()
|
||||
self.write_s_formula()
|
||||
self.write_antiderivative()
|
||||
|
||||
|
||||
def add_v_graph(self):
|
||||
graph, label = self.get_v_graph_and_label()
|
||||
self.play(ShowCreation(graph))
|
||||
self.play(Write(label))
|
||||
|
||||
self.graph = graph
|
||||
self.graph_label = label
|
||||
|
||||
def write_s_formula(self):
|
||||
ds_dt = TexMobject("ds", "\\over\\,", "dt")
|
||||
ds_dt.highlight_by_tex("ds", DISTANCE_COLOR)
|
||||
ds_dt.highlight_by_tex("dt", TIME_COLOR)
|
||||
ds_dt.next_to(self.graph_label, UP, LARGE_BUFF)
|
||||
|
||||
v_t = self.graph_label.get_part_by_tex("v(t)")
|
||||
arrow = Arrow(
|
||||
ds_dt.get_bottom(), v_t.get_top(),
|
||||
color = WHITE,
|
||||
)
|
||||
|
||||
self.play(
|
||||
Write(ds_dt, run_time = 2),
|
||||
ShowCreation(arrow)
|
||||
)
|
||||
self.dither()
|
||||
|
||||
def write_antiderivative(self):
|
||||
randy = Randolph()
|
||||
randy.to_corner(DOWN+LEFT)
|
||||
randy.shift(2*RIGHT)
|
||||
words = TexMobject(
|
||||
"{d(", "???", ") \\over \\,", "dt}", "=", "t(8-t)"
|
||||
)
|
||||
words.highlight_by_tex("t(8-t)", VELOCITY_COLOR)
|
||||
words.highlight_by_tex("???", DISTANCE_COLOR)
|
||||
words.highlight_by_tex("dt", TIME_COLOR)
|
||||
words.scale(0.7)
|
||||
|
||||
self.play(FadeIn(randy))
|
||||
self.play(PiCreatureSays(
|
||||
randy, words,
|
||||
target_mode = "confused",
|
||||
bubble_kwargs = {"height" : 3, "width" : 4},
|
||||
))
|
||||
self.play(Blink(randy))
|
||||
self.dither()
|
||||
|
||||
class Antiderivative(PiCreatureScene):
|
||||
def construct(self):
|
||||
functions = self.get_functions("t^2", "2t")
|
||||
alt_functions = self.get_functions("???", "t(8-t)")
|
||||
top_arc, bottom_arc = arcs = self.get_arcs(functions)
|
||||
derivative = TextMobject("Derivative")
|
||||
derivative.next_to(top_arc, UP)
|
||||
antiderivative = TextMobject("``Antiderivative''")
|
||||
antiderivative.next_to(bottom_arc, DOWN)
|
||||
antiderivative.highlight(bottom_arc.get_color())
|
||||
group = VGroup(functions, arcs, derivative, antiderivative)
|
||||
|
||||
self.add(functions, top_arc, derivative)
|
||||
self.dither()
|
||||
self.play(
|
||||
ShowCreation(bottom_arc),
|
||||
Write(antiderivative),
|
||||
self.pi_creature.change_mode, "raise_right_hand"
|
||||
)
|
||||
self.dither(2)
|
||||
for pair in reversed(zip(functions, alt_functions)):
|
||||
self.play(
|
||||
Transform(*pair),
|
||||
self.pi_creature.change_mode, "pondering"
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
self.pi_creature_says(
|
||||
"But first!",
|
||||
target_mode = "surprised",
|
||||
look_at_arg = 50*OUT,
|
||||
added_anims = [group.to_edge, LEFT],
|
||||
run_time = 1,
|
||||
)
|
||||
self.dither()
|
||||
|
||||
|
||||
def get_functions(self, left_tex, right_tex):
|
||||
left = TexMobject(left_tex)
|
||||
left.shift(2*LEFT)
|
||||
left.highlight(DISTANCE_COLOR)
|
||||
right = TexMobject(right_tex)
|
||||
right.shift(2*RIGHT)
|
||||
right.highlight(VELOCITY_COLOR)
|
||||
result = VGroup(left, right)
|
||||
result.shift(UP)
|
||||
return result
|
||||
|
||||
def get_arcs(self, functions):
|
||||
f1, f2 = functions
|
||||
top_line = Line(f1.get_corner(UP+RIGHT), f2.get_corner(UP+LEFT))
|
||||
bottom_line = Line(f1.get_corner(DOWN+RIGHT), f2.get_corner(DOWN+LEFT))
|
||||
top_arc = Arc(start_angle = 5*np.pi/6, angle = -2*np.pi/3)
|
||||
bottom_arc = top_arc.copy()
|
||||
bottom_arc.rotate(np.pi)
|
||||
arcs = VGroup(top_arc, bottom_arc)
|
||||
arcs.scale_to_fit_width(top_line.get_width())
|
||||
for arc in arcs:
|
||||
arc.add_tip()
|
||||
top_arc.next_to(top_line, UP)
|
||||
bottom_arc.next_to(bottom_line, DOWN)
|
||||
bottom_arc.highlight(MAROON_B)
|
||||
|
||||
return arcs
|
||||
|
||||
class AreaUnderVGraph(PlotVelocity):
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.add(*self.get_v_graph_and_label())
|
||||
self.show_rects()
|
||||
|
||||
def show_rects(self):
|
||||
rect_list = self.get_riemann_rectangles_list(
|
||||
self.v_graph, 7,
|
||||
max_dx = 1.0,
|
||||
x_min = 0,
|
||||
x_max = 8,
|
||||
)
|
||||
flat_graph = self.get_graph(lambda t : 0)
|
||||
rects = self.get_riemann_rectangles(
|
||||
flat_graph, x_min = 0, x_max = 8, dx = 1.0
|
||||
)
|
||||
|
||||
for new_rects in rect_list:
|
||||
new_rects.set_fill(opacity = 0.8)
|
||||
rects.align_submobjects(new_rects)
|
||||
for alt_rect in rects[::2]:
|
||||
alt_rect.set_fill(opacity = 0)
|
||||
self.play(Transform(
|
||||
rects, new_rects,
|
||||
run_time = 2,
|
||||
submobject_mode = "lagged_start"
|
||||
))
|
||||
self.dither()
|
||||
|
||||
class ConstantVelocityCar(Scene):
|
||||
def construct(self):
|
||||
car = Car()
|
||||
car.scale(2)
|
||||
car.move_to(3*LEFT + 3*DOWN)
|
||||
|
||||
self.add(car)
|
||||
self.dither()
|
||||
self.play(MoveCar(
|
||||
car, 6*RIGHT+3*DOWN,
|
||||
run_time = 5,
|
||||
rate_func = None,
|
||||
))
|
||||
self.dither()
|
||||
|
||||
class ConstantVelocityPlot(PlotVelocity):
|
||||
CONFIG = {
|
||||
"x_axis_label" : "Time"
|
||||
}
|
||||
def construct(self):
|
||||
self.setup_axes()
|
||||
self.x_axis_label_mob.shift(DOWN)
|
||||
self.draw_graph()
|
||||
self.show_product()
|
||||
self.comment_on_area_wierdness()
|
||||
self.note_units()
|
||||
|
||||
|
||||
def draw_graph(self):
|
||||
graph = self.get_graph(
|
||||
lambda t : 10,
|
||||
x_min = 0,
|
||||
x_max = 8,
|
||||
color = VELOCITY_COLOR
|
||||
)
|
||||
|
||||
self.play(ShowCreation(graph, rate_func = None, run_time = 3))
|
||||
self.dither()
|
||||
|
||||
self.graph = graph
|
||||
|
||||
def show_product(self):
|
||||
rect = Rectangle(
|
||||
stroke_width = 0,
|
||||
fill_color = DISTANCE_COLOR,
|
||||
fill_opacity = 0.5
|
||||
)
|
||||
rect.replace(
|
||||
VGroup(self.graph, VectorizedPoint(self.graph_origin)),
|
||||
stretch = True
|
||||
)
|
||||
|
||||
right_brace = Brace(rect, RIGHT)
|
||||
top_brace = Brace(rect, UP)
|
||||
v_label = right_brace.get_text(
|
||||
"$10 \\frac{\\text{meters}}{\\text{second}}$",
|
||||
)
|
||||
v_label.highlight(VELOCITY_COLOR)
|
||||
t_label = top_brace.get_text(
|
||||
"8 seconds"
|
||||
)
|
||||
t_label.highlight(TIME_COLOR)
|
||||
|
||||
s_label = TexMobject("10", "\\times", "8", "\\text{ meters}")
|
||||
s_label.highlight_by_tex("10", VELOCITY_COLOR)
|
||||
s_label.highlight_by_tex("8", TIME_COLOR)
|
||||
s_label.move_to(rect)
|
||||
|
||||
self.play(
|
||||
GrowFromCenter(right_brace),
|
||||
Write(v_label),
|
||||
)
|
||||
self.play(
|
||||
GrowFromCenter(top_brace),
|
||||
Write(t_label),
|
||||
)
|
||||
self.play(
|
||||
FadeIn(rect),
|
||||
Write(s_label),
|
||||
Animation(self.graph)
|
||||
)
|
||||
self.dither(2)
|
||||
|
||||
self.area_rect = rect
|
||||
self.s_label = s_label
|
||||
|
||||
def comment_on_area_wierdness(self):
|
||||
randy = Randolph()
|
||||
randy.to_corner(DOWN+LEFT)
|
||||
bubble = randy.get_bubble(
|
||||
"Distance \\\\ is area?",
|
||||
bubble_class = ThoughtBubble,
|
||||
height = 3,
|
||||
width = 4,
|
||||
fill_opacity = 1,
|
||||
)
|
||||
bubble.content.scale_in_place(0.8)
|
||||
bubble.content.shift(SMALL_BUFF*UP)
|
||||
VGroup(bubble[-1], bubble.content).shift(1.5*LEFT)
|
||||
|
||||
self.play(FadeIn(randy))
|
||||
self.play(randy.change_mode, "pondering")
|
||||
self.play(
|
||||
self.area_rect.highlight, YELLOW,
|
||||
*map(Animation, self.get_mobjects()),
|
||||
rate_func = there_and_back
|
||||
)
|
||||
self.play(Blink(randy))
|
||||
self.play(
|
||||
randy.change_mode, "confused",
|
||||
randy.look_at, randy.bubble,
|
||||
ShowCreation(bubble),
|
||||
Write(bubble.content),
|
||||
)
|
||||
self.dither()
|
||||
self.play(Blink(randy))
|
||||
self.dither()
|
||||
self.play(
|
||||
randy.change_mode, "pondering",
|
||||
FadeOut(bubble),
|
||||
FadeOut(bubble.content),
|
||||
)
|
||||
|
||||
self.randy = randy
|
||||
|
||||
def note_units(self):
|
||||
x_line, y_line = lines = VGroup(*[
|
||||
axis.main_line.copy()
|
||||
for axis in self.x_axis, self.y_axis
|
||||
])
|
||||
lines.highlight(TIME_COLOR)
|
||||
|
||||
self.play(ShowCreation(x_line))
|
||||
self.play(Indicate(self.x_axis_label_mob))
|
||||
self.play(FadeOut(x_line))
|
||||
self.play(
|
||||
ShowCreation(y_line),
|
||||
self.randy.look_at, self.y_axis_label_mob
|
||||
)
|
||||
self.play(Indicate(self.y_axis_label_mob))
|
||||
self.play(FadeOut(y_line))
|
||||
self.dither()
|
||||
for direction in UP, DOWN:
|
||||
self.play(
|
||||
ApplyWave(
|
||||
self.area_rect,
|
||||
run_time = 1,
|
||||
direction = direction,
|
||||
amplitude = MED_SMALL_BUFF,
|
||||
),
|
||||
*map(Animation, self.get_mobjects()) + [
|
||||
self.randy.look_at, self.area_rect
|
||||
]
|
||||
)
|
||||
self.dither()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -221,6 +221,24 @@ class GraphScene(Scene):
|
||||
rectangles.set_stroke(BLACK, width = stroke_width)
|
||||
return rectangles
|
||||
|
||||
def get_riemann_rectangles_list(
|
||||
self,
|
||||
graph,
|
||||
n_iterations,
|
||||
max_dx = 0.5,
|
||||
power_base = 2,
|
||||
**kwargs
|
||||
):
|
||||
return [
|
||||
self.get_riemann_rectangles(
|
||||
graph = graph,
|
||||
dx = float(max_dx)/(power_base**n),
|
||||
stroke_width = 1./(power_base**n),
|
||||
**kwargs
|
||||
)
|
||||
for n in range(n_iterations)
|
||||
]
|
||||
|
||||
def get_vertical_line_to_graph(
|
||||
self,
|
||||
x, graph,
|
||||
|
@ -395,7 +395,14 @@ class PiCreatureScene(Scene):
|
||||
self.get_pi_creatures()
|
||||
))
|
||||
|
||||
def introduce_bubble(self, pi_creature, *content, **kwargs):
|
||||
def introduce_bubble(self, *args, **kwargs):
|
||||
if isinstance(args[0], PiCreature):
|
||||
pi_creature = args[0]
|
||||
content = args[1:]
|
||||
else:
|
||||
pi_creature = self.get_primary_pi_creature()
|
||||
content = args
|
||||
|
||||
bubble_class = kwargs.pop("bubble_class", SpeechBubble)
|
||||
target_mode = kwargs.pop(
|
||||
"target_mode",
|
||||
@ -443,18 +450,16 @@ class PiCreatureScene(Scene):
|
||||
|
||||
self.play(*anims)
|
||||
|
||||
def pi_creature_says(self, pi_creature, *content, **kwargs):
|
||||
def pi_creature_says(self, *args, **kwargs):
|
||||
self.introduce_bubble(
|
||||
pi_creature,
|
||||
*content,
|
||||
*args,
|
||||
bubble_class = SpeechBubble,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def pi_creature_thinks(self, pi_creature, *content, **kwargs):
|
||||
def pi_creature_thinks(self, *args, **kwargs):
|
||||
self.introduce_bubble(
|
||||
pi_creature,
|
||||
*content,
|
||||
*args,
|
||||
bubble_class = ThoughtBubble,
|
||||
**kwargs
|
||||
)
|
||||
|
@ -24,12 +24,12 @@ class OpeningQuote(Scene):
|
||||
},
|
||||
}
|
||||
def construct(self):
|
||||
quote = self.get_quote()
|
||||
author = self.get_author(quote)
|
||||
self.quote = self.get_quote()
|
||||
self.author = self.get_author(self.quote)
|
||||
|
||||
self.play(FadeIn(quote, **self.fade_in_kwargs))
|
||||
self.play(FadeIn(self.quote, **self.fade_in_kwargs))
|
||||
self.dither(2)
|
||||
self.play(Write(author, run_time = 3))
|
||||
self.play(Write(self.author, run_time = 3))
|
||||
self.dither()
|
||||
|
||||
def get_quote(self, max_width = 2*SPACE_WIDTH-1):
|
||||
|
@ -512,7 +512,6 @@ class UtahFillingCurve(SelfSimilarSpaceFillingCurve):
|
||||
"radius_scale_factor" : 2/(3*np.sqrt(3)),
|
||||
}
|
||||
|
||||
|
||||
class FlowSnake(LindenmayerCurve):
|
||||
CONFIG = {
|
||||
"colors" : [YELLOW, GREEN],
|
||||
|
@ -1,17 +1,82 @@
|
||||
from helpers import *
|
||||
|
||||
from mobject import Mobject
|
||||
from mobject.vectorized_mobject import VGroup
|
||||
from mobject.vectorized_mobject import VGroup, VMobject
|
||||
from mobject.svg_mobject import SVGMobject
|
||||
from mobject.tex_mobject import TextMobject
|
||||
from mobject.tex_mobject import TextMobject, TexMobject
|
||||
|
||||
from animation import Animation
|
||||
from animation.simple_animations import Rotating
|
||||
|
||||
from topics.geometry import Circle, Line, Rectangle, Square
|
||||
from topics.geometry import Circle, Line, Rectangle, Square, Arc, Polygon
|
||||
from topics.three_dimensions import Cube
|
||||
|
||||
|
||||
class Speedometer(VMobject):
|
||||
CONFIG = {
|
||||
"arc_angle" : 4*np.pi/3,
|
||||
"num_ticks" : 8,
|
||||
"tick_length" : 0.2,
|
||||
"needle_width" : 0.1,
|
||||
"needle_height" : 0.8,
|
||||
"needle_color" : YELLOW,
|
||||
}
|
||||
def generate_points(self):
|
||||
start_angle = np.pi/2 + self.arc_angle/2
|
||||
end_angle = np.pi/2 - self.arc_angle/2
|
||||
self.add(Arc(
|
||||
start_angle = start_angle,
|
||||
angle = -self.arc_angle
|
||||
))
|
||||
tick_angle_range = np.linspace(start_angle, end_angle, self.num_ticks)
|
||||
for index, angle in enumerate(tick_angle_range):
|
||||
vect = rotate_vector(RIGHT, angle)
|
||||
tick = Line((1-self.tick_length)*vect, vect)
|
||||
label = TexMobject(str(10*index))
|
||||
label.scale_to_fit_height(self.tick_length)
|
||||
label.shift((1+self.tick_length)*vect)
|
||||
self.add(tick, label)
|
||||
|
||||
needle = Polygon(
|
||||
LEFT, UP, RIGHT,
|
||||
stroke_width = 0,
|
||||
fill_opacity = 1,
|
||||
fill_color = self.needle_color
|
||||
)
|
||||
needle.stretch_to_fit_width(self.needle_width)
|
||||
needle.stretch_to_fit_height(self.needle_height)
|
||||
needle.rotate(start_angle - np.pi/2)
|
||||
self.add(needle)
|
||||
self.needle = needle
|
||||
|
||||
self.center_offset = self.get_center()
|
||||
|
||||
def get_center(self):
|
||||
result = VMobject.get_center(self)
|
||||
if hasattr(self, "center_offset"):
|
||||
result -= self.center_offset
|
||||
return result
|
||||
|
||||
def get_needle_tip(self):
|
||||
return self.needle.get_anchors()[1]
|
||||
|
||||
def get_needle_angle(self):
|
||||
return angle_of_vector(
|
||||
self.get_needle_tip() - self.get_center()
|
||||
)
|
||||
|
||||
def rotate_needle(self, angle):
|
||||
self.needle.rotate(angle, about_point = self.get_center())
|
||||
return self
|
||||
|
||||
def move_needle_to_velocity(self, velocity):
|
||||
max_velocity = 10*(self.num_ticks-1)
|
||||
proportion = float(velocity) / max_velocity
|
||||
start_angle = np.pi/2 + self.arc_angle/2
|
||||
target_angle = start_angle - self.arc_angle * proportion
|
||||
self.rotate_needle(target_angle - self.get_needle_angle())
|
||||
return self
|
||||
|
||||
class PartyHat(SVGMobject):
|
||||
CONFIG = {
|
||||
"file_name" : "party_hat",
|
||||
|
Reference in New Issue
Block a user