分子轨道
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)