mirror of
https://github.com/3b1b/manim.git
synced 2025-07-29 21:12:35 +08:00
209 lines
6.3 KiB
Python
209 lines
6.3 KiB
Python
from big_ol_pile_of_manim_imports import *
|
|
from active_projects.eop.reusables.eop_helpers import *
|
|
from active_projects.eop.reusables.eop_constants import *
|
|
from active_projects.eop.reusables.upright_coins import *
|
|
|
|
class BrickRow(VMobject):
|
|
|
|
CONFIG = {
|
|
"left_color" : COLOR_HEADS,
|
|
"right_color" : COLOR_TAILS,
|
|
"height" : 1.0,
|
|
"width" : 8.0,
|
|
"outcome_shrinkage_factor_x" : 0.95,
|
|
"outcome_shrinkage_factor_y" : 0.94
|
|
}
|
|
|
|
def __init__(self, n, **kwargs):
|
|
self.subdiv_level = n
|
|
self.coloring_level = n
|
|
VMobject.__init__(self, **kwargs)
|
|
|
|
|
|
def generate_points(self):
|
|
|
|
self.submobjects = []
|
|
self.rects = self.get_rects_for_level(self.coloring_level)
|
|
self.add(self.rects)
|
|
self.subdivs = self.get_subdivs_for_level(self.subdiv_level)
|
|
self.add(self.subdivs)
|
|
|
|
self.border = SurroundingRectangle(self,
|
|
buff = 0, color = WHITE)
|
|
self.add(self.border)
|
|
|
|
|
|
|
|
def get_rects_for_level(self,r):
|
|
rects = VGroup()
|
|
for k in range(r + 1):
|
|
proportion = float(choose(r,k)) / 2**r
|
|
new_rect = Rectangle(
|
|
width = proportion * self.width,
|
|
height = self.height,
|
|
fill_color = graded_color(r,k),
|
|
fill_opacity = 1,
|
|
stroke_width = 0
|
|
)
|
|
if len(rects.submobjects) > 0:
|
|
new_rect.next_to(rects,RIGHT,buff = 0)
|
|
else:
|
|
new_rect.next_to(self.get_center() + 0.5 * self.width * LEFT, RIGHT, buff = 0)
|
|
rects.add(new_rect)
|
|
return rects
|
|
|
|
|
|
def get_subdivs_for_level(self,r):
|
|
subdivs = VGroup()
|
|
x = - 0.5 * self.width
|
|
for k in range(0, r):
|
|
proportion = float(choose(r,k)) / 2**r
|
|
x += proportion * self.width
|
|
subdiv = Line(
|
|
x * RIGHT + 0.5 * self.height * UP,
|
|
x * RIGHT + 0.5 * self.height * DOWN,
|
|
)
|
|
subdivs.add(subdiv)
|
|
subdivs.move_to(self.get_center())
|
|
return subdivs
|
|
|
|
|
|
def get_sequence_subdivs_for_level(self,r):
|
|
subdivs = VGroup()
|
|
x = - 0.5 * self.width
|
|
dx = 1.0 / 2**r
|
|
for k in range(1, 2 ** r):
|
|
proportion = dx
|
|
x += proportion * self.width
|
|
subdiv = DashedLine(
|
|
x * RIGHT + 0.5 * self.height * UP,
|
|
x * RIGHT + 0.5 * self.height * DOWN,
|
|
)
|
|
subdivs.add(subdiv)
|
|
subdivs.move_to(self.get_center())
|
|
return subdivs
|
|
|
|
|
|
def get_outcome_centers_for_level(self,r):
|
|
|
|
dpos = float(self.width) / (2 ** r) * RIGHT
|
|
pos = 0.5 * self.width * LEFT + 0.5 * dpos
|
|
centers = []
|
|
for k in range(0, 2 ** r):
|
|
centers.append(self.get_center() + pos + k * dpos)
|
|
|
|
return centers
|
|
|
|
def get_outcome_rects_for_level(self, r, inset = False, with_labels = False):
|
|
|
|
centers = self.get_outcome_centers_for_level(r)
|
|
if inset == True:
|
|
outcome_width = self.outcome_shrinkage_factor_x * float(self.width) / (2 ** r)
|
|
outcome_height = self.outcome_shrinkage_factor_y * self.height
|
|
else:
|
|
outcome_width = float(self.width) / (2 ** r)
|
|
outcome_height = self.height
|
|
|
|
corner_radius = 0.1 # max(0.1, 0.3 * min(outcome_width, outcome_height))
|
|
# this scales down the corner radius for very narrow rects
|
|
rect = RoundedRectangle(
|
|
width = outcome_width,
|
|
height = outcome_height,
|
|
corner_radius = corner_radius,
|
|
fill_color = OUTCOME_COLOR,
|
|
fill_opacity = OUTCOME_OPACITY,
|
|
stroke_width = 0
|
|
)
|
|
rects = VGroup()
|
|
for center in centers:
|
|
rects.add(rect.copy().move_to(center))
|
|
|
|
rects.move_to(self.get_center())
|
|
|
|
|
|
if with_labels == False:
|
|
return rects
|
|
|
|
# else
|
|
sequences = self.get_coin_sequences_for_level(r)
|
|
labels = VGroup()
|
|
for (seq, rect) in zip(sequences, rects):
|
|
coin_seq = CoinSequence(seq, direction = DOWN)
|
|
coin_seq.shift(rect.get_center() - coin_seq.get_center())
|
|
# not simply move_to bc coin_seq is not centered
|
|
rect.add(coin_seq)
|
|
rect.label = coin_seq
|
|
|
|
return rects
|
|
|
|
def get_coin_sequences_for_level(self,r):
|
|
# array of arrays of characters
|
|
if r < 0 or int(r) != r:
|
|
raise Exception("Level must be a positive integer")
|
|
if r == 0:
|
|
return []
|
|
if r == 1:
|
|
return [["H"], ["T"]]
|
|
|
|
previous_seq_array = self.get_coin_sequences_for_level(r - 1)
|
|
subdiv_lengths = [choose(r - 1, k) for k in range(r)]
|
|
|
|
seq_array = []
|
|
index = 0
|
|
for length in subdiv_lengths:
|
|
|
|
for seq in previous_seq_array[index:index + length]:
|
|
seq_copy = copy.copy(seq)
|
|
seq_copy.append("H")
|
|
seq_array.append(seq_copy)
|
|
|
|
for seq in previous_seq_array[index:index + length]:
|
|
seq_copy = copy.copy(seq)
|
|
seq_copy.append("T")
|
|
seq_array.append(seq_copy)
|
|
index += length
|
|
|
|
return seq_array
|
|
|
|
|
|
def get_outcome_width_for_level(self,r):
|
|
return self.width / (2**r)
|
|
|
|
def get_rect_widths_for_level(self, r):
|
|
ret_arr = []
|
|
for k in range(0, r):
|
|
proportion = float(choose(r,k)) / 2**r
|
|
ret_arr.append(proportion * self.width)
|
|
return ret_arr
|
|
|
|
|
|
|
|
|
|
class SplitRectsInBrickWall(AnimationGroup):
|
|
|
|
def __init__(self, mobject, **kwargs):
|
|
|
|
#print mobject.height, mobject.get_height()
|
|
r = self.subdiv_level = mobject.subdiv_level + 1
|
|
|
|
subdivs = VGroup()
|
|
x = -0.5 * mobject.get_width()
|
|
|
|
anims = []
|
|
for k in range(0, r):
|
|
proportion = float(choose(r,k)) / 2**r
|
|
x += proportion * mobject.get_width()
|
|
subdiv = DashedLine(
|
|
mobject.get_top() + x * RIGHT,
|
|
mobject.get_bottom() + x * RIGHT,
|
|
dash_length = 0.05
|
|
)
|
|
subdivs.add(subdiv)
|
|
anims.append(ShowCreation(subdiv))
|
|
|
|
mobject.add(subdivs)
|
|
AnimationGroup.__init__(self, *anims, **kwargs)
|
|
|
|
|
|
|