mirror of
https://github.com/3b1b/manim.git
synced 2025-04-13 09:47:07 +00:00
322 lines
9.5 KiB
Python
322 lines
9.5 KiB
Python
![]() |
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
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 animation.continual_animation 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 topics.probability import *
|
||
|
from topics.complex_numbers import *
|
||
|
from scene import Scene
|
||
|
from scene.reconfigurable_scene import ReconfigurableScene
|
||
|
from scene.zoomed_scene import *
|
||
|
from camera import Camera
|
||
|
from mobject.svg_mobject import *
|
||
|
from mobject.tex_mobject import *
|
||
|
from topics.graph_scene import *
|
||
|
|
||
|
|
||
|
class SimpleVelocityGraph(GraphScene):
|
||
|
CONFIG = {
|
||
|
# "frame_rate" : 4000,
|
||
|
# "domino_thickness" : 7.5438,
|
||
|
# "domino_spacing" : 8.701314282,
|
||
|
"data_files" : [
|
||
|
"data07.txt",
|
||
|
"data13.txt",
|
||
|
# "data11.txt",
|
||
|
],
|
||
|
"colors" : [WHITE, BLUE, YELLOW, GREEN, MAROON_B],
|
||
|
"x_axis_label" : "$t$",
|
||
|
"y_axis_label" : "$v$",
|
||
|
"x_min" : 0,
|
||
|
"x_max" : 1.8,
|
||
|
"x_tick_frequency" : 0.1,
|
||
|
"x_labeled_nums" : np.arange(0, 1.8, 0.2),
|
||
|
"y_tick_frequency" : 100,
|
||
|
"y_min" : 0,
|
||
|
"y_max" : 1000,
|
||
|
"y_labeled_nums" : range(0, 1000, 200),
|
||
|
"x_axis_width" : 12,
|
||
|
"graph_origin" : 2.5*DOWN + 5*LEFT,
|
||
|
"trailing_average_length" : 20,
|
||
|
"include_domino_thickness" : False,
|
||
|
}
|
||
|
def construct(self):
|
||
|
self.setup_axes()
|
||
|
# self.save_all_images()
|
||
|
for data_file, color in zip(self.data_files, self.colors):
|
||
|
self.init_data(data_file)
|
||
|
self.draw_dots(color)
|
||
|
self.add_label_to_last_dot(
|
||
|
"%s %s %.2f"%(
|
||
|
data_file[4:6],
|
||
|
"hard" if self.friction == "low" else "felt",
|
||
|
self.domino_spacing,
|
||
|
),
|
||
|
color
|
||
|
)
|
||
|
self.draw_lines(color)
|
||
|
|
||
|
def save_all_images(self):
|
||
|
indices = range(1, 20)
|
||
|
for i1, i2 in it.combinations(indices, 2):
|
||
|
to_remove = VGroup()
|
||
|
for index in i1, i2:
|
||
|
index_str = ("%.2f"%float(0.01*index))[-2:]
|
||
|
data_file = "data%s.txt"%index_str
|
||
|
self.init_data(data_file)
|
||
|
color = WHITE if self.friction == "low" else BLUE
|
||
|
self.draw_dots(color)
|
||
|
self.add_label_to_last_dot(
|
||
|
"%s %s %.2f"%(
|
||
|
data_file[4:6],
|
||
|
"hard" if self.friction == "low" else "felt",
|
||
|
self.domino_spacing,
|
||
|
),
|
||
|
color
|
||
|
)
|
||
|
self.draw_lines(color)
|
||
|
to_remove.add(self.dots, self.lines, self.label)
|
||
|
self.save_image("dominos_%d_vs_%d"%(i1, i2))
|
||
|
self.remove(to_remove)
|
||
|
|
||
|
def init_data(self, data_file):
|
||
|
file_name = os.path.join(
|
||
|
os.path.dirname(os.path.realpath(__file__)),
|
||
|
"dominos",
|
||
|
data_file
|
||
|
)
|
||
|
|
||
|
file = open(file_name, "r")
|
||
|
frames, notes = [], []
|
||
|
for line in file:
|
||
|
line = line.replace(" ", ",")
|
||
|
line = line.replace("\n", "")
|
||
|
entries = filter(
|
||
|
lambda s : s is not "",
|
||
|
line.split(",")
|
||
|
)
|
||
|
if len(entries) == 0:
|
||
|
continue
|
||
|
|
||
|
if entries[0] == "framerate":
|
||
|
frame_rate = float(entries[1])
|
||
|
elif entries[0] == "domino spacing":
|
||
|
domino_spacing = float(entries[1])
|
||
|
elif entries[0] == "domino thickness":
|
||
|
domino_thickness = float(entries[1])
|
||
|
elif entries[0] == "friction":
|
||
|
self.friction = entries[1]
|
||
|
else:
|
||
|
try:
|
||
|
frames.append(int(entries[0]))
|
||
|
except:
|
||
|
continue #How to treat?
|
||
|
# frames.append(frames[-1] + (frames[-1] - frames[-2]))
|
||
|
if len(entries) > 1:
|
||
|
notes.append(entries[1])
|
||
|
else:
|
||
|
notes.append("")
|
||
|
frames = np.array(frames)
|
||
|
|
||
|
self.times = (frames - frames[0])/float(frame_rate)
|
||
|
delta_times = self.times[1:] - self.times[:-1]
|
||
|
if self.include_domino_thickness:
|
||
|
distance = domino_spacing+domino_thickness
|
||
|
else:
|
||
|
distance = domino_spacing
|
||
|
self.velocities = distance/delta_times
|
||
|
self.notes = notes
|
||
|
|
||
|
n = self.trailing_average_length
|
||
|
self.velocities = np.array([
|
||
|
np.mean(self.velocities[max(0, i-n):i])
|
||
|
for i in range(len(self.velocities))
|
||
|
])
|
||
|
self.domino_spacing = domino_spacing
|
||
|
self.domino_thickness = domino_thickness
|
||
|
|
||
|
def draw_dots(self, color = WHITE):
|
||
|
dots = VGroup()
|
||
|
for time, v, note in zip(self.times, self.velocities, self.notes):
|
||
|
dot = Dot(color = color)
|
||
|
dot.scale(0.5)
|
||
|
dot.move_to(self.coords_to_point(time, v))
|
||
|
self.add(dot)
|
||
|
dots.add(dot)
|
||
|
if note == "twist":
|
||
|
dot.highlight(RED)
|
||
|
self.dots = dots
|
||
|
|
||
|
def add_label_to_last_dot(self, label, color = WHITE):
|
||
|
dot = self.dots[-1]
|
||
|
label = TextMobject(label)
|
||
|
label.scale(0.75)
|
||
|
label.next_to(dot, UP, buff = MED_SMALL_BUFF)
|
||
|
label.highlight(color)
|
||
|
label.shift_onto_screen()
|
||
|
self.label = label
|
||
|
self.add(label)
|
||
|
|
||
|
def draw_lines(self, color = WHITE, stroke_width = 2):
|
||
|
lines = VGroup()
|
||
|
for d1, d2 in zip(self.dots, self.dots[1:]):
|
||
|
line = Line(d1.get_center(), d2.get_center())
|
||
|
lines.add(line)
|
||
|
lines.set_stroke(color, stroke_width)
|
||
|
self.add(lines, self.dots)
|
||
|
self.lines = lines
|
||
|
|
||
|
class ShowAllSteadyStateVelocities(SimpleVelocityGraph):
|
||
|
CONFIG = {
|
||
|
"x_axis_label" : "\\text{Domino spacing}",
|
||
|
"x_min" : 0,
|
||
|
"x_max" : 40,
|
||
|
"x_axis_width" : 9,
|
||
|
"x_tick_frequency" : 5,
|
||
|
"x_labeled_nums" : range(0, 50, 10),
|
||
|
"y_min" : 0,
|
||
|
"y_max" : 400,
|
||
|
"y_labeled_nums" : [],
|
||
|
# "y_labeled_nums" : range(200, 1400, 200),
|
||
|
}
|
||
|
def construct(self):
|
||
|
self.setup_axes()
|
||
|
for index in range(1, 20):
|
||
|
index_str = ("%.2f"%float(0.01*index))[-2:]
|
||
|
data_file = "data%s.txt"%index_str
|
||
|
self.init_data(data_file)
|
||
|
color = WHITE if self.friction == "low" else BLUE
|
||
|
label = TextMobject(
|
||
|
index_str,
|
||
|
color = color
|
||
|
)
|
||
|
label.scale(0.5)
|
||
|
label.highlight(color)
|
||
|
|
||
|
dot = Dot(color = color)
|
||
|
dot.scale(0.5)
|
||
|
dot.move_to(self.coords_to_point(
|
||
|
self.domino_spacing, self.velocities[-1] - 400
|
||
|
))
|
||
|
label.next_to(
|
||
|
dot,
|
||
|
random.choice([LEFT, RIGHT]),
|
||
|
SMALL_BUFF
|
||
|
)
|
||
|
self.add(dot)
|
||
|
self.add(label)
|
||
|
print index_str, self.velocities[-1], self.friction
|
||
|
|
||
|
class Test(Scene):
|
||
|
def construct(self):
|
||
|
shift_val = 1.5
|
||
|
|
||
|
domino1 = Rectangle(
|
||
|
width = 0.5, height = 3,
|
||
|
stroke_width = 0,
|
||
|
fill_color = GREEN,
|
||
|
fill_opacity = 1
|
||
|
)
|
||
|
domino1.shift(LEFT)
|
||
|
domino2 = domino1.copy()
|
||
|
domino2.set_fill(BLUE_E)
|
||
|
domino2.shift(shift_val*RIGHT)
|
||
|
spacing = shift_val - domino2.get_width()
|
||
|
dominos = VGroup(domino1, domino2)
|
||
|
for domino in dominos:
|
||
|
line = DashedLine(domino.get_left(), domino.get_right())
|
||
|
dot = Dot(domino.get_center())
|
||
|
domino.add(line, dot)
|
||
|
|
||
|
arc1 = Arc(
|
||
|
radius = domino1.get_height(),
|
||
|
start_angle = np.pi/2,
|
||
|
angle = -np.arcsin(spacing / domino1.get_height())
|
||
|
)
|
||
|
arc1.shift(domino1.get_corner(DOWN+RIGHT))
|
||
|
arc2 = Arc(
|
||
|
radius = domino1.get_height()/2,
|
||
|
start_angle = np.pi/2,
|
||
|
angle = -np.arcsin(2*spacing/domino1.get_height())
|
||
|
)
|
||
|
arc2.shift(domino1.get_right())
|
||
|
arc2.highlight(BLUE)
|
||
|
arcs = VGroup(arc1, arc2)
|
||
|
for arc, vect in zip(arcs, [DOWN+RIGHT, RIGHT]):
|
||
|
arc_copy = arc.copy()
|
||
|
point = domino1.get_critical_point(vect)
|
||
|
arc_copy.add_control_points(3*[point])
|
||
|
arc_copy.set_stroke(width = 0)
|
||
|
arc_copy.set_fill(
|
||
|
arc.get_stroke_color(),
|
||
|
0.2,
|
||
|
)
|
||
|
self.add(arc_copy)
|
||
|
|
||
|
domino1_ghost = domino1.copy()
|
||
|
domino1_ghost.fade(0.8)
|
||
|
self.add(domino1_ghost, dominos, arcs)
|
||
|
|
||
|
self.play(Rotate(
|
||
|
domino1,
|
||
|
angle = arc1.angle,
|
||
|
about_point = domino1.get_corner(DOWN+RIGHT),
|
||
|
rate_func = there_and_back,
|
||
|
run_time = 3,
|
||
|
))
|
||
|
self.play(Rotate(
|
||
|
domino1,
|
||
|
angle = arc2.angle,
|
||
|
about_point = domino1.get_right(),
|
||
|
rate_func = there_and_back,
|
||
|
run_time = 3,
|
||
|
))
|
||
|
|
||
|
print arc1.angle, arc2.angle
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|