3b1b-manim/old_projects/domino_play.py

322 lines
9.5 KiB
Python
Raw Normal View History

2017-11-26 13:29:57 -08:00
#!/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