from manim import *
frame_width = config["frame_width"]
frame_height = config["frame_height"]
def narrator(a):
for i in a:
globals()[f't{str(i)}']=Text(a[i], font = "STZhongsong").to_edge(DOWN).scale(0.6)
class AtomicOrbitalTemplate(TexTemplate):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.add_to_preamble("\\usepackage{tikzorbital}")
class AtomicOrbital(VGroup):
def __init__(
self,
orbital_name: str,
**kwargs
):
super().__init__(**kwargs)
self.template = AtomicOrbitalTemplate()
orbital = MathTex("\\begin{tikzpicture} \\orbital{%s} \\end{tikzpicture}" % orbital_name, tex_template = self.template, stroke_width=2, fill_color=BLUE, fill_opacity=0.8, **kwargs)
self.orbital = orbital
self.add(orbital)
class AtomicElectronsArrangement(VGroup):
def __init__(
self,
orbital_type,
orbital_label,
electrons_num,
custom_orbital_num = 1, # 用于自定义轨道,一般的 s, p, d 轨道的 orbital_num 会在下面给出
custom_scale_orbital = False,
**kwargs
):
self.orbital_type = orbital_type
self.orbital_label = orbital_label
self.electrons_num = electrons_num
self.custom_orbital_num = custom_orbital_num
self.custom_scale_orbital = custom_scale_orbital
super().__init__(**kwargs)
self.orbitals = self.mob_orbitals()
self.lines = self.mob_lines()
self.label = self.mob_label()
self.dots = self.mob_dots()
self.show_dots = self.anim_show_dots()
self.add(self.orbitals, self.lines, self.label, self.dots)
def mob_orbitals(self):
orbital_type = self.orbital_type
if orbital_type == 's':
self.orbital_num = 1
self.line_length = 1/2
orbital = AtomicOrbital('s')
orbitals = VGroup(orbital)
elif orbital_type == 'p':
self.orbital_num = 3
self.line_length = 1/3
orbital1 = AtomicOrbital('px')
orbital2 = AtomicOrbital('py')
orbital3 = AtomicOrbital('pz')
orbitals = VGroup(orbital1, orbital2, orbital3)
elif orbital_type == 's_sigma':
self.line_length = 1/2
self.orbital_num = self.custom_orbital_num
orbitals = VGroup(*[SMolecularOrbitals().orbitals_sigma_2 for i in range(self.orbital_num)])
elif orbital_type == 's_sigma*':
self.line_length = 1/2
self.orbital_num = self.custom_orbital_num
orbitals = VGroup(*[SMolecularOrbitals().orbitals_sigma_1 for i in range(self.orbital_num)])
elif orbital_type == 'p_sigma':
self.line_length = 1/2
self.orbital_num = self.custom_orbital_num
orbitals = VGroup(*[PMolecularOrbitals().orbitals_sigma_2 for i in range(self.orbital_num)])
elif orbital_type == 'p_sigma*':
self.line_length = 1/2
self.orbital_num = self.custom_orbital_num
orbitals = VGroup(*[PMolecularOrbitals().orbitals_sigma_1 for i in range(self.orbital_num)])
elif orbital_type == 'p_pi':
self.line_length = 1/2
self.orbital_num = self.custom_orbital_num
orbitals = VGroup(*[PMolecularOrbitals().orbitals_pi_2 for i in range(self.orbital_num)])
elif orbital_type == 'p_pi*':
self.line_length = 1/2
self.orbital_num = self.custom_orbital_num
orbitals = VGroup(*[PMolecularOrbitals().orbitals_pi_1 for i in range(self.orbital_num)])
elif orbital_type is None:
self.line_length = 1/2
self.orbital_num = self.custom_orbital_num
orbitals = VGroup(*[VMobject() for i in range(self.orbital_num)])
else:
print('no such orbital type yet')
return orbitals
def mob_lines(self):
line_length = self.line_length
lines = VGroup(*[Line(LEFT*line_length, RIGHT*line_length) for i in range(self.orbital_num)])
lines.arrange(buff=0.5)
orbitals_width = 0
if self.custom_scale_orbital:
orbital_width = self.orbitals[0].width
orbital_height = self.orbitals[0].height
scale_coe = lines[0].width*0.9/orbital_width
if orbital_height*scale_coe > 0.5:
scale_coe_2 = 0.5/(orbital_height*scale_coe)
scale_coe *= scale_coe_2
else:
for orbital in self.orbitals:
orbitals_width += orbital.width
if orbitals_width > lines.width*0.9:
scale_coe = lines.width*0.9/orbitals_width
else:
scale_coe = 1
for i in range(self.orbital_num):
self.orbitals[i].scale(scale_coe)
self.orbitals[i].move_to(lines[i])
return lines
def mob_label(self):
orbital_label = self.orbital_label
lines = self.lines
if self.custom_orbital_num > 1:
label = VGroup()
for line in lines:
single_label = MathTex(orbital_label).scale(0.6).next_to(line, DOWN)
label.add(single_label)
else:
label = MathTex(orbital_label).scale(0.6).next_to(lines, DOWN)
return label
def mob_dots(self):
line_length = self.line_length
dots = VGroup()
electrons_num = self.electrons_num
lines = self.lines
if electrons_num > self.orbital_num:
for i in range(self.orbital_num):
dot = Dot(color=BLUE).move_to(lines[i]).shift(0.2*UP + line_length*0.6*LEFT)
arrow = MathTex(r'\uparrow').set_color(BLUE).scale(0.8).next_to(dot, 0.5*UP)
dots.add(VGroup(dot ,arrow))
for i in range(electrons_num - self.orbital_num):
dot = Dot(color=RED).move_to(lines[i]).shift(0.2*UP + line_length*0.6*RIGHT)
arrow = MathTex(r'\downarrow').set_color(RED).scale(0.8).next_to(dot, 0.5*UP)
dots.add(VGroup(dot ,arrow))
else:
for i in range(electrons_num):
dot = Dot(color=BLUE).move_to(lines[i]).shift(0.2*UP + line_length*0.6*LEFT)
arrow = MathTex(r'\uparrow').set_color(BLUE).scale(0.8).next_to(dot, 0.5*UP)
dots.add(VGroup(dot ,arrow))
return dots
def anim_show_dots(self):
anim = Succession(*[FadeIn(dot) for dot in self.dots]) # bug:使用 animate 会使物件 opacity 变为 1 的同时回到屏幕中心
return anim
class MolecularOrbitals(VGroup):
def __init__(
self,
left_orbital_name: list = None,
right_orbital_name: list = None,
central_orbitals_names: list = None,
central_orbitals_buff = 2,
custom_orbitals_position: list = None,
**kwargs
):
self.left_orbital_name = left_orbital_name
self.right_orbital_name = right_orbital_name
self.central_orbitals_names = central_orbitals_names
self.central_orbitals_buff = central_orbitals_buff
self.custom_orbitals_position = custom_orbitals_position
super().__init__(**kwargs)
self.left_orbital = self.mob_left_orbital()
self.right_orbital = self.mob_right_orbital()
self.central_orbitals = self.mob_central_orbitals()
self.left_lines = self.mob_left_lines()
self.right_lines = self.mob_right_lines()
self.lines_dots = self.mob_lines_dots()
self.show_orbitals_show_lines_1 = self.anim_show_orbitals_show_lines_1()
self.show_orbitals_show_lines_2 = self.anim_show_orbitals_show_lines_2()
self.show_dots = self.anim_show_dots()
self.add(self.left_orbital, self.right_orbital, self.central_orbitals, self.left_lines, self.right_lines)
def mob_left_orbital(self):
left_orbital_name = self.left_orbital_name
custom_orbitals_position = self.custom_orbitals_position
if left_orbital_name is None:
left_orbital = VGroup()
else:
left_orbital = AtomicElectronsArrangement(*left_orbital_name)
left_orbital.shift(frame_width/2*0.6*LEFT)
if custom_orbitals_position is not None:
left_orbital.shift(custom_orbitals_position[0]*UP)
return left_orbital
def mob_right_orbital(self):
right_orbital_name = self.right_orbital_name
custom_orbitals_position = self.custom_orbitals_position
if right_orbital_name is None:
right_orbital = VGroup()
else:
right_orbital = AtomicElectronsArrangement(*right_orbital_name)
right_orbital.shift(frame_width/2*0.6*RIGHT)
if custom_orbitals_position is not None:
right_orbital.shift(custom_orbitals_position[1]*UP)
return right_orbital
def mob_central_orbitals(self):
central_orbitals_names = self.central_orbitals_names
central_orbitals = VGroup()
for name in central_orbitals_names:
central_orbital = AtomicElectronsArrangement(*name, custom_scale_orbital=True)
central_orbitals.add(central_orbital)
if self.custom_orbitals_position is not None:
custom_orbitals_position = self.custom_orbitals_position[2:]
n = 0
for orbital in central_orbitals:
orbital.shift(custom_orbitals_position[n]*UP)
n += 1
else:
central_orbitals.arrange(DOWN, buff=self.central_orbitals_buff)
return central_orbitals
def mob_left_lines(self):
left_orbital = self.left_orbital
central_orbitals = self.central_orbitals
lines = VGroup()
if self.left_orbital_name is not None:
start_point = left_orbital.lines[-1].get_right()
for orbital in central_orbitals:
end_point = orbital.lines[0].get_left()
line = DashedLine(start_point, end_point)
lines.add(line)
return lines
def mob_right_lines(self):
right_orbital = self.right_orbital
central_orbitals = self.central_orbitals
lines = VGroup()
if self.right_orbital_name is not None:
start_point = right_orbital.lines[0].get_left()
for orbital in central_orbitals:
end_point = orbital.lines[-1].get_right()
line = DashedLine(start_point, end_point)
lines.add(line)
return lines
def mob_lines_dots(self):
def get_lines_dots(mob):
# return VGroup(mob.lines, mob.label, mob.dots)
return VGroup(mob.orbitals)
left_orbital = get_lines_dots(self.left_orbital)
right_orbital = get_lines_dots(self.right_orbital)
central_orbitals = VGroup(*[get_lines_dots(orbital) for orbital in self.central_orbitals])
return VGroup(self.left_lines, self.right_lines, left_orbital, right_orbital, central_orbitals)
def anim_show_orbitals_show_lines_1(self):
left_lines = self.left_lines
right_lines = self.right_lines
left_orbital = self.left_orbital
right_orbital = self.right_orbital
central_orbitals = self.central_orbitals
anim1 = DrawBorderThenFill(left_orbital.orbitals)
anim2 = DrawBorderThenFill(right_orbital.orbitals)
anim3_list = []
n = 0
for central_orbital in central_orbitals:
anim3_list.append(DrawBorderThenFill(central_orbital.orbitals))
anim3_list.append(FadeIn(VGroup(left_lines[n], right_lines[n])))
n += 1
anim3 = Succession(*anim3_list)
anim = Succession(anim1, anim2, anim3)
return anim
def anim_show_orbitals_show_lines_2(self):
left_orbital = self.left_orbital
right_orbital = self.right_orbital
central_orbitals = self.central_orbitals
anim1 = FadeOut(left_orbital.orbitals, right_orbital.orbitals, *[central_orbital.orbitals for central_orbital in central_orbitals])
anim2 = FadeIn(left_orbital.lines, left_orbital.label, right_orbital.lines, right_orbital.label, *[orbital.lines for orbital in central_orbitals], *[orbital.label for orbital in central_orbitals])
anim = Succession(anim1, anim2)
return anim
def anim_show_dots(self):
left_orbital = self.left_orbital
right_orbital = self.right_orbital
central_orbitals = self.central_orbitals
effective_central_orbitals = VGroup()
for central_orbital in central_orbitals:
if len(central_orbital.dots) > 0:
effective_central_orbitals.add(central_orbital)
effective_central_orbitals = effective_central_orbitals[::-1]
anim1 = left_orbital.show_dots
anim2 = right_orbital.show_dots
anim3 = Succession(*[central_orbital.show_dots for central_orbital in effective_central_orbitals])
anim = Succession(anim1, anim2, anim3)
return anim
class O2MolecularOrbitals(VGroup):
def __init__(self):
self.molecular_orbitals_1s = self.mob_molecular_orbitals_1s()
self.molecular_orbitals_2s = self.mob_molecular_orbitals_2s()
self.molecular_orbitals_2p = self.mob_molecular_orbitals_2p()
def mob_molecular_orbitals_1s(self):
left_orbital_name = ['s', '1s', 2]
right_orbital_name = ['s', '1s', 2]
central_orbitals_names = [['s_sigma*', '\sigma_{u}^{*}', 2], ['s_sigma', '\sigma_{g}', 2]]
molecular_orbitals = MolecularOrbitals(left_orbital_name, right_orbital_name, central_orbitals_names, central_orbitals_buff=0.5)
return molecular_orbitals
def mob_molecular_orbitals_2s(self):
left_orbital_name = ['s', '2s', 2]
right_orbital_name = ['s', '2s', 2]
central_orbitals_names = [['s_sigma*', '\sigma_{u}^{*}', 2], ['s_sigma', '\sigma_{g}', 2]]
molecular_orbitals = MolecularOrbitals(left_orbital_name, right_orbital_name, central_orbitals_names)
return molecular_orbitals
def mob_molecular_orbitals_2p(self):
left_orbital_name = ['p', '2p', 4]
right_orbital_name = ['p', '2p', 4]
central_orbitals_names = [['p_sigma*', '\sigma_{u}^{*}', 0], ['p_pi*', '\pi_{g}^{*}', 2, 2], ['p_pi', '\pi_{g}', 4, 2], ['p_sigma', '\sigma_{g}', 2]]
molecular_orbitals = MolecularOrbitals(left_orbital_name, right_orbital_name, central_orbitals_names, central_orbitals_buff=0.7)
molecular_orbitals.scale(0.9)
return molecular_orbitals
class HFMolecularOrbitals(VGroup):
def __init__(self):
self.molecular_orbitals = self.mob_molecular_orbitals()
def mob_molecular_orbitals(self):
left_orbital_name = ['s', '1s', 1]
right_orbital_name = ['p', '2p', 5]
central_orbitals_names = [[None, '\sigma^{*}', 0], [None, '\pi', 4, 2], [None, '\sigma', 2]]
molecular_orbitals = MolecularOrbitals(left_orbital_name, right_orbital_name, central_orbitals_names, custom_orbitals_position=[1, -1, 3, -1, -2.5])
molecular_orbitals.left_lines.remove(molecular_orbitals.left_lines[1])
return molecular_orbitals
class COMolecularOrbitals(VGroup):
def __init__(self):
self.molecular_orbitals_2s = self.mob_molecular_orbitals_2s()
self.molecular_orbitals_2p = self.mob_molecular_orbitals_2p()
def mob_molecular_orbitals_2s(self):
left_orbital_name = ['s', '2s', 2]
right_orbital_name = ['s', '2s', 2]
central_orbitals_names = [['s_sigma*', '2\sigma^{*}', 2], ['s_sigma', '2\sigma', 2]]
molecular_orbitals = MolecularOrbitals(left_orbital_name, right_orbital_name, central_orbitals_names, custom_orbitals_position=[1, -1, 2, -2])
return molecular_orbitals
def mob_molecular_orbitals_2p(self):
left_orbital_name = ['p', '2p', 2]
right_orbital_name = ['p', '2p', 4]
central_orbitals_names = [['p_sigma*', '3\sigma^{*}', 0], ['p_pi*', '1\pi^{*}', 0, 2], ['p_sigma', '3\sigma', 2], ['p_pi', '1\pi', 4, 2]]
molecular_orbitals = MolecularOrbitals(left_orbital_name, right_orbital_name, central_orbitals_names, custom_orbitals_position=[2, -2, 3, 2, -1.5, -3])
molecular_orbitals.scale(0.8)
return molecular_orbitals
class SMolecularOrbitals(VGroup):
def __init__(self, **kwargs):
self.orbitals = self.mob_orbitals()
self.orbitals_sigma_1 = self.anim_orbitals_to_sigma_1(return_mobs=True)
self.orbitals_sigma_2 = self.anim_orbitals_to_sigma_2(return_mobs=True)
self.orbitals_to_sigma_1 = self.anim_orbitals_to_sigma_1()
self.orbitals_to_sigma_2 = self.anim_orbitals_to_sigma_2()
self.restore_orbitals = self.anim_restore_orbitals()
super().__init__(**kwargs)
self.add(self.orbitals)
def mob_orbitals(self):
orbital1 = Circle(stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8).shift(0.6*LEFT)
orbital2 = Circle(stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8).shift(0.6*RIGHT)
orbitals = VGroup(orbital1, orbital2)
orbitals.save_state()
return orbitals
def anim_orbitals_to_sigma_1(self, return_mobs=False):
orbitals = self.orbitals
orbital1 = Ellipse(width=1.5, height=3, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8).shift(LEFT)
orbital2 = Ellipse(width=1.5, height=3, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8).shift(RIGHT)
anim1 = AnimationGroup(orbitals[0].animate.set(fill_color=BLUE), orbitals[1].animate.set(fill_color=RED))
anim2 = Wait()
anim3 = AnimationGroup(Transform(orbitals[0], orbital1), Transform(orbitals[1], orbital2))
anim4 = Wait(2)
if return_mobs:
return VGroup(orbital1.set(fill_color=BLUE), orbital2.set(fill_color=BLUE))
else:
return Succession(anim1, anim2, anim3, anim4)
def anim_orbitals_to_sigma_2(self, return_mobs=False):
orbitals = self.orbitals
orbital = Ellipse(width=3, height=2, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8)
anim1 = AnimationGroup(orbitals[0].animate.set(fill_color=BLUE), orbitals[1].animate.set(fill_color=BLUE))
anim2 = Wait()
anim3 = Transform(orbitals, orbital)
anim4 = Wait(2)
if return_mobs:
return orbital.set(fill_color=BLUE)
else:
return Succession(anim1, anim2, anim3, anim4)
def anim_restore_orbitals(self):
orbitals = self.orbitals
anim = Restore(orbitals)
return anim
class PMolecularOrbitals(VGroup):
def __init__(self, **kwargs):
self.orbitals = self.mob_orbitals()
self.orbitals_sigma_1 = self.anim_orbitals_to_sigma_1(return_mobs=True)
self.orbitals_sigma_2 = self.anim_orbitals_to_sigma_2(return_mobs=True)
self.orbitals_pi_1 = self.anim_orbitals_to_pi_1(return_mobs=True)
self.orbitals_pi_2 = self.anim_orbitals_to_pi_2(return_mobs=True)
self.orbitals_to_sigma_1 = self.anim_orbitals_to_sigma_1()
self.orbitals_to_sigma_2 = self.anim_orbitals_to_sigma_2()
self.orbitals_to_pi_1 = self.anim_orbitals_to_pi_1()
self.orbitals_to_pi_2 = self.anim_orbitals_to_pi_2()
self.orbitals_to_no_interaction = self.anim_orbitals_to_no_interaction()
self.restore_orbitals = self.anim_restore_orbitals()
super().__init__(**kwargs)
self.add(self.orbitals)
def mob_orbitals(self):
orbital1 = VGroup(*[Ellipse(width=1, height=1.5, stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8) for i in range(2)]).arrange(buff=0).shift(0.8*LEFT)
orbital2 = VGroup(*[Ellipse(width=1, height=1.5, stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8) for i in range(2)]).arrange(buff=0).shift(0.8*RIGHT)
orbitals = VGroup(orbital1, orbital2)
orbitals.save_state()
return orbitals
def anim_orbitals_to_sigma_1(self, return_mobs=False):
orbitals = self.orbitals
orbital1 = VGroup(Circle(radius=0.5, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8), Ellipse(width=0.8, height=1.8, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8)).arrange(buff=0).shift(LEFT)
orbital2 = VGroup(Ellipse(width=0.8, height=1.8, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8), Circle(radius=0.5, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8)).arrange(buff=0).shift(RIGHT)
anim1 = AnimationGroup(orbitals[0][0].animate.set(fill_color=RED), orbitals[0][1].animate.set(fill_color=BLUE), orbitals[1][0].animate.set(fill_color=RED), orbitals[1][1].animate.set(fill_color=BLUE))
anim2 = Wait()
anim3 = AnimationGroup(Transform(orbitals[0][0], orbital1[0]), Transform(orbitals[0][1], orbital1[1]), Transform(orbitals[1][0], orbital2[0]), Transform(orbitals[1][1], orbital2[1]))
anim4 = Wait(2)
if return_mobs:
return VGroup(orbital1.set(fill_color=BLUE), orbital2.set(fill_color=BLUE))
else:
return Succession(anim1, anim2, anim3, anim4)
def anim_orbitals_to_sigma_2(self, return_mobs=False):
orbitals = self.orbitals
orbital1 = Ellipse(width=1, height=0.8, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8)
orbital2 = Ellipse(width=1.5, height=1, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8)
orbital3 = Ellipse(width=1, height=0.8, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8)
VGroup(orbital1, orbital2, orbital3).arrange(buff=0)
anim1 = AnimationGroup(orbitals[0][0].animate.set(fill_color=RED), orbitals[0][1].animate.set(fill_color=BLUE), orbitals[1][0].animate.set(fill_color=BLUE), orbitals[1][1].animate.set(fill_color=RED))
anim2 = Wait()
anim3 = AnimationGroup(Transform(orbitals[0][0], orbital1), Transform(VGroup(orbitals[0][1], orbitals[1][0]), orbital2), Transform(orbitals[1][1], orbital3))
anim4 = Wait(2)
if return_mobs:
return VGroup(orbital1.set(fill_color=BLUE), orbital2.set(fill_color=BLUE), orbital3.set(fill_color=BLUE))
else:
return Succession(anim1, anim2, anim3, anim4)
def anim_orbitals_to_pi_1(self, return_mobs=False):
orbitals = self.orbitals
orbital1 = VGroup(Ellipse(width=1.2, height=1, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8), Ellipse(width=1.2, height=1, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8)).arrange(direction=DOWN, buff=0).shift(0.7*LEFT)
orbital2 = VGroup(Ellipse(width=1.2, height=1, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8), Ellipse(width=1.2, height=1, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8)).arrange(direction=DOWN, buff=0).shift(0.7*RIGHT)
anim1 = AnimationGroup(orbitals[0][0].animate.set(fill_color=BLUE), orbitals[0][1].animate.set(fill_color=RED), orbitals[1][0].animate.set(fill_color=RED), orbitals[1][1].animate.set(fill_color=BLUE))
anim2 = AnimationGroup(Rotate(orbitals[0], -0.5*PI), Rotate(orbitals[1], -0.5*PI))
anim3 = AnimationGroup(ApplyMethod(orbitals[0].shift, 0.3*RIGHT), ApplyMethod(orbitals[1].shift, 0.3*LEFT))
anim4 = Wait()
anim5 = AnimationGroup(Transform(orbitals[0][0], orbital1[0]), Transform(orbitals[0][1], orbital1[1]), Transform(orbitals[1][0], orbital2[0]), Transform(orbitals[1][1], orbital2[1]))
anim6 = Wait(2)
if return_mobs:
return VGroup(orbital1.set(fill_color=BLUE), orbital2.set(fill_color=BLUE))
else:
return Succession(anim1, anim2, anim3, anim4, anim5, anim6)
def anim_orbitals_to_pi_2(self, return_mobs=False):
orbitals = self.orbitals
orbital1 = Ellipse(width=2.2, height=1, stroke_color=WHITE, stroke_width=2, fill_color=BLUE, fill_opacity=0.8)
orbital2 = Ellipse(width=2.2, height=1, stroke_color=WHITE, stroke_width=2, fill_color=RED, fill_opacity=0.8)
VGroup(orbital1, orbital2).arrange(direction=DOWN, buff=0)
anim1 = AnimationGroup(orbitals[0][0].animate.set(fill_color=BLUE), orbitals[0][1].animate.set(fill_color=RED), orbitals[1][0].animate.set(fill_color=BLUE), orbitals[1][1].animate.set(fill_color=RED))
anim2 = AnimationGroup(Rotate(orbitals[0], -0.5*PI), Rotate(orbitals[1], -0.5*PI))
anim3 = AnimationGroup(ApplyMethod(orbitals[0].shift, 0.3*RIGHT), ApplyMethod(orbitals[1].shift, 0.3*LEFT))
anim4 = Wait()
anim5 = AnimationGroup(Transform(VGroup(orbitals[0][0], orbitals[1][0]), orbital1), Transform(VGroup(orbitals[0][1], orbitals[1][1]), orbital2))
anim6 = Wait(2)
if return_mobs:
return VGroup(orbital1.set(fill_color=BLUE), orbital2.set(fill_color=BLUE))
else:
return Succession(anim1, anim2, anim3, anim4, anim5, anim6)
def anim_orbitals_to_no_interaction(self):
orbitals = self.orbitals
anim = Rotate(orbitals[0], -0.5*PI)
return anim
def anim_restore_orbitals(self):
orbitals = self.orbitals
anim = Restore(orbitals)
return anim
class SPMolecularOrbitals(VGroup):
def __init__(self, **kwargs):
self.orbitals = self.mob_orbitals()
def mob_orbitals(self):
orbital1 = Circle(radius=0.8, stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8).shift(0.7*LEFT)
orbital2 = VGroup(*[Ellipse(width=1, height=1.5, stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8) for i in range(2)]).arrange(buff=0).shift(0.7*RIGHT)
note = Text('只有当 p 轨道朝向和键轴方向一致时,才能发生作用', font = "STFangsong").to_edge(UP).scale(0.6)
return VGroup(orbital1, orbital2, note)
class ChemicalTexTemplate(TexTemplate):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.add_to_preamble("\\usepackage{chemfig}")
class CObejct(MathTex):
def __init__(
self,
chem_str: str,
**kwargs
):
self.template = ChemicalTexTemplate()
super().__init__("\\chemfig{%s}" % chem_str, tex_template = self.template, stroke_width=2, **kwargs) # 如果不适用 stroke_width,那么化学键会不显示
class H2O(CObejct):
def __init__(self, **kwargs):
super().__init__('H-[:30]O-[:-30]H')
self.scale(2)
self.H_orbitals = self.mob_H_orbitals()
self.O_orbital = self.mob_O_orbital()
self.compose_H_orbitals = self.anim_compose_H_orbitals()
self.tex_table = self.mob_tex_table()
def mob_H_orbitals(self):
orbital1 = Circle(radius=0.7, stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8).move_to(self[0][0])
orbital2 = Circle(radius=0.7, stroke_color=WHITE, stroke_width=2, fill_color=GREEN, fill_opacity=0.8).move_to(self[0][3])
return VGroup(orbital1, orbital2)
def mob_O_orbital(self):
orbital = Circle(radius=0.7, stroke_color=WHITE, stroke_width=2, fill_color=PURPLE, fill_opacity=0.8).move_to(self[0][1])
return orbital
def mob_tex_table(self):
tex = MathTex(r'''
\begin{array}{c|cccc|c|c}
C_{2v} & E & C_{2} & \sigma_{v}(xz) & \sigma_{v}(yz) & & \\
\hline & & & & & & \\
A_{1} & 1 & 1 & 1 & 1 & z & x^{2}, y^{2}, z^{2} \\
A_{2} & 1 & 1 & -1 & -1 & R_{z} & xy \\
B_{1} & 1 & -1 & 1 & -1 & x, R_{y} & xz \\
B_{2} & 1 & -1 & -1 & 1 & y, R_{x} & yz \\
\end{array}
''')
tex.scale(0.8)
return tex
def anim_compose_H_orbitals(self):
orbitals = self.H_orbitals
anim1 = AnimationGroup(orbitals[0].animate.set(fill_color=BLUE), orbitals[1].animate.set(fill_color=RED))
anim2 = AnimationGroup(orbitals[0].animate.set(fill_color=GREEN), orbitals[1].animate.set(fill_color=GREEN))
anim3 = AnimationGroup(orbitals[0].animate.set(fill_color=BLUE), orbitals[1].animate.set(fill_color=BLUE))
anim4 = AnimationGroup(orbitals[0].animate.set(fill_color=GREEN), orbitals[1].animate.set(fill_color=GREEN))
return Succession(anim1, anim2, anim3, anim4)