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 POrbital(SVGMobject): def __init__(self): file_path = r"D:\manimSVG\figures\p_orbital.svg" super().__init__(file_path) self.set_opacity(0.4) self.set_color(color=[BLUE_A, BLUE_D]) class SP2Orbital(VGroup): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) file_path = r"D:\manimSVG\figures\single_p_orbital.svg" single_p_orbital = SVGMobject(file_path) single_p_orbital.set_opacity(0.4).set_color(color=[BLUE_A, BLUE_D]).shift(1.2*UP) p_orbitals = VGroup() for i in range(0, 3): p_orbitals.add(single_p_orbital.copy().rotate(2*PI/3*i, about_point=ORIGIN)) dot = Dot().set_opacity(0) self.add(dot, p_orbitals) self.dot = dot self.p_orbitals = p_orbitals self.scale(0.5) def move_accurately_to(self, point_or_mobject): if isinstance(point_or_mobject, Mobject): distance = point_or_mobject.get_center() - self.dot.get_center() else: distance = point_or_mobject - self.dot.get_center() self.shift(distance) return self def rotate_about_center(self, *args, **kwargs): self.rotate(about_point=self.dot.get_center(), *args, **kwargs) return self class ResonanceMolecule(VMobject): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def mob_molecule(self, str, scale_factor=1): molecule = SVGMobject(str).scale(scale_factor) self.scale_factor = scale_factor return molecule def mob_p_orbitals(self, indexes, colors): molecule = self.molecule.copy() molecule.rotate(PI/4, axis=[1,0,0]) if type(indexes[0]) == int: p_orbitals = VGroup(*(POrbital().move_to(molecule[index]) for index in indexes)) else: p_orbitals = VGroup(*(POrbital().move_to(index) for index in indexes)) for i in range(len(colors)): if colors[i] == BLUE: p_orbitals[i].set_color(color=[BLUE_A, BLUE_D]) elif colors[i] == RED: p_orbitals[i].set_color(color=[RED_A, RED_D]) elif colors[i] == PURPLE: p_orbitals[i].set_color(color=[PURPLE_A, PURPLE_D]) return p_orbitals def mob_sp2_orbitals(self, indexes, angles, scale_factor=1): molecule = self.molecule if type(indexes[0]) == int: sp2_orbitals = VGroup(*(SP2Orbital().scale(scale_factor).move_accurately_to(molecule[indexes[i]]).rotate_about_center(angles[i]).scale(scale_factor) for i in range(len(indexes)))) else: sp2_orbitals = VGroup(*(SP2Orbital().scale(scale_factor).move_accurately_to(indexes[i]).rotate_about_center(angles[i]) for i in range(len(indexes)))) return sp2_orbitals def anim_show_p_orbitals(self, return_mob=False): molecule = self.molecule p_orbitals = self.p_orbitals anim = Succession(Rotate(molecule, PI/4, axis=[1,0,0]), LaggedStart(*(FadeIn(orbital, shift=DOWN) for orbital in p_orbitals), run_time=len(p_orbitals)/2)) if return_mob: molecule.rotate(PI/4, axis=[1,0,0]) return VGroup(molecule, p_orbitals) else: return anim def anim_show_sp2_orbitals(self): sp2_orbitals = self.sp2_orbitals anim = LaggedStart(*(GrowFromCenter(sp2_orbital) for sp2_orbital in sp2_orbitals), run_time=len(sp2_orbitals)/1.5) return anim def anim_show_lines_between_p_orbitals(self, indexes_list = None, return_mob=False): p_orbitals = self.p_orbitals lines = VGroup() if indexes_list is None: for i in range(len(p_orbitals) - 1): line1 = DashedLine(p_orbitals[i][2].get_center(), p_orbitals[i+1][2].get_center()) line2 = DashedLine(p_orbitals[i][5].get_center(), p_orbitals[i+1][5].get_center()) lines.add(line1, line2) else: for index in indexes_list: line1 = DashedLine(p_orbitals[index[0]][2].get_center(), p_orbitals[index[1]][2].get_center()) line2 = DashedLine(p_orbitals[index[0]][5].get_center(), p_orbitals[index[1]][5].get_center()) lines.add(line1, line2) anim = LaggedStart(*(Write(line) for line in lines), run_time=len(p_orbitals)/2) if return_mob: return lines else: return anim def anim_change_between_resonance_contributors(self, mol_trans_list): original_mol = self.molecule target_mol = SVGMobject(mol_trans_list[0]).scale(self.scale_factor) anim = Succession(Rotate(original_mol, -PI/4, axis=[1,0,0]), CorrespondingPartsTransform([original_mol, target_mol], mol_trans_list[1], run_time=3)) return anim def anim_show_resonance_hybrid(self, resonance_structures, resonance_hybrid, direction_buffs_scales = [RIGHT, 2, 1, 1, 1]): resonance_structures = VGroup(*(SVGMobject(file_path).scale(direction_buffs_scales[3]) for file_path in resonance_structures)).set_color(color=[BLUE_A, BLUE_D]).arrange(direction_buffs_scales[0], buff=direction_buffs_scales[1]) resonance_hybrid = SVGMobject(resonance_hybrid).set_color(color=[GREEN_A, GREEN_D]).scale(direction_buffs_scales[4]).next_to(resonance_structures, direction=DOWN, buff=direction_buffs_scales[2]) VGroup(resonance_structures, resonance_hybrid).center() anim = Succession(Write(resonance_structures), Write(resonance_hybrid)) return anim class Benzene(ResonanceMolecule): def __init__(self): self.molecule = self.mob_molecule(r"D:\manimSVG\molecules\benzene.svg", scale_factor=2) self.p_orbitals = self.mob_p_orbitals() self.sp2_orbitals = self.mob_sp2_orbitals() self.show_p_orbitals = self.anim_show_p_orbitals() self.show_sp2_orbitals = self.anim_show_sp2_orbitals() self.show_large_pi_orbital = self.anim_show_large_pi_orbital() self.to_different_bond_length = self.anim_to_different_bond_length() self.to_same_bond_length = self.anim_to_same_bond_length() self.show_lines_between_p_orbitals = self.anim_show_lines_between_p_orbitals(indexes_list=[[0,1], [1,2], [2,3], [3,4], [4,5], [5,0]], return_mob=True) self.change_between_resonance_contributors = self.anim_change_between_resonance_contributors([r"D:\manimSVG\molecules\benzene_resonance_1.svg", [0, 1, [6, 0, 8, 1, 0, 3, 2, 4, 3, 6, 5, 7, 1, 2, 7, 8, 4, 5]]]) self.show_resonance_hybrid = self.anim_show_resonance_hybrid([r"D:\manimSVG\molecules\benzene.svg", r"D:\manimSVG\molecules\benzene_resonance_1.svg"], r"D:\manimSVG\molecules\benzene_resonance_hybrid.svg") def mob_p_orbitals(self): molecule = self.molecule.copy() molecule.rotate(PI/4, axis=[1,0,0]) points = [molecule.get_left(), molecule[2].get_left(), molecule[2].get_right(), molecule.get_right(), molecule[6].get_right(), molecule[6].get_left()] p_orbitals = super().mob_p_orbitals(points, [BLUE for i in range(6)]) return p_orbitals def mob_sp2_orbitals(self): molecule = self.molecule points = [molecule.get_left(), molecule[2].get_left(), molecule[2].get_right(), molecule.get_right(), molecule[6].get_right(), molecule[6].get_left()] angles = [90*DEGREES, 150*DEGREES, 210*DEGREES, 270*DEGREES, 330*DEGREES, 390*DEGREES] sp2_orbitals = super().mob_sp2_orbitals(points, angles, scale_factor=0.9) return sp2_orbitals def anim_show_large_pi_orbital(self): large_pi_orbital1 = SVGMobject(r"D:\manimSVG\figures\large_pi_orbital.svg").scale(1.5) large_pi_orbital1.set(fill_opacity=0, stroke_color=BLUE, stroke_opacity=0.6) large_pi_orbital2 = large_pi_orbital1.copy() large_pi_orbital1.shift(0.5*UP) large_pi_orbital2.shift(0.5*DOWN) anim = Succession(FadeIn(large_pi_orbital1, shift=DOWN), FadeIn(large_pi_orbital2, shift=UP)) return anim def anim_to_different_bond_length(self): mol = self.molecule target = SVGMobject(r"D:\manimSVG\molecules\benzene_with_different_bond_length.svg").scale(self.scale_factor) return Transform(mol, target) def anim_to_same_bond_length(self): mol = self.molecule target = SVGMobject(r"D:\manimSVG\molecules\benzene.svg").scale(self.scale_factor) return Transform(mol, target) class Example1(ResonanceMolecule): def __init__(self): self.molecule = self.mob_molecule(r"D:\manimSVG\molecules\example_1.svg", scale_factor=2) self.p_orbitals = self.mob_p_orbitals([10, 6, 8], [BLUE, BLUE, PURPLE]) self.sp2_orbitals = self.mob_sp2_orbitals([6, 10], [PI/2, PI/6], scale_factor=1.05) self.show_p_orbitals = self.anim_show_p_orbitals() self.show_sp2_orbitals = self.anim_show_sp2_orbitals() self.show_lines_between_p_orbitals = self.anim_show_lines_between_p_orbitals() self.change_between_resonance_contributors = self.anim_change_between_resonance_contributors([r"D:\manimSVG\molecules\example_1_resonance_1.svg", [0, 1, ['0.9', '0.9', 9, 10, 14, 9, 13, 12, 12, 14, 10, 11]]]) self.show_resonance_hybrid = self.anim_show_resonance_hybrid([r"D:\manimSVG\molecules\example_1.svg", r"D:\manimSVG\molecules\example_1_resonance_1.svg"], r"D:\manimSVG\molecules\example_1_resonance_hybrid.svg") class Example2(ResonanceMolecule): def __init__(self): self.molecule = self.mob_molecule(r"D:\manimSVG\molecules\example_2.svg") self.p_orbitals = self.mob_p_orbitals([3, 5, 9], [BLUE, BLUE, RED]) self.sp2_orbitals = self.mob_sp2_orbitals([3, 5], [-PI/2, PI/2], scale_factor=1.2) self.show_p_orbitals = self.anim_show_p_orbitals() self.show_sp2_orbitals = self.anim_show_sp2_orbitals() self.show_lines_between_p_orbitals = self.anim_show_lines_between_p_orbitals() self.change_between_resonance_contributors = self.anim_change_between_resonance_contributors([r"D:\manimSVG\molecules\example_2_resonance_1.svg", [0, 1, ['0.7', '0.7', 8, 14, 7, 12, 14, 13, '9.14', '7.12']]]) self.show_resonance_hybrid = self.anim_show_resonance_hybrid([r"D:\manimSVG\molecules\example_2.svg", r"D:\manimSVG\molecules\example_2_resonance_1.svg"], r"D:\manimSVG\molecules\example_2_resonance_hybrid.svg", direction_buffs_scales = [RIGHT, 1.5, 1, 0.5, 0.35]) class Example3(ResonanceMolecule): pass class Example4(ResonanceMolecule): def __init__(self): self.molecule = self.mob_molecule(r"D:\manimSVG\molecules\example_4.svg", scale_factor=2) self.p_orbitals = self.mob_p_orbitals([1, 0, 4], [BLUE, BLUE, PURPLE]) self.sp2_orbitals = self.mob_sp2_orbitals([1, 0], [PI, 0], scale_factor=1.05) self.show_p_orbitals = self.anim_show_p_orbitals() self.show_sp2_orbitals = self.anim_show_sp2_orbitals() self.show_lines_between_p_orbitals = self.anim_show_lines_between_p_orbitals() self.change_between_resonance_contributors = self.anim_change_between_resonance_contributors([r"D:\manimSVG\molecules\example_4_resonance_1.svg", [0, 1, [11, 9, 1, 1, 12, 10, 2, 11, 3, 13, 0, 0, 9, 8, 8, 7, 7, 6, 10, 5, '4.7', '2.5']]]) self.show_resonance_hybrid = self.anim_show_resonance_hybrid([r"D:\manimSVG\molecules\example_4.svg", r"D:\manimSVG\molecules\example_4_resonance_1.svg"], r"D:\manimSVG\molecules\example_4_resonance_hybrid.svg", direction_buffs_scales = [RIGHT, 2, 1, 1.1, 1.1])
class MyScene(Scene): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.current_narrator = None self.fixed_mobjects = [] def play_with_narrator(self, text, *anims, start=False, end=False, start_end=False): def text_duration(text, *anims): time = len(text)/10 if anims != (): time += 1 # 基础时间为 1s anim_run_time_list = [] for anim in anims: anim_run_time_list.append(anim.get_run_time()) anim_run_time = max(anim_run_time_list) if anim_run_time >= time: time = 1 else: time -= anim_run_time return time if start: self.play(FadeIn(text), *anims) self.wait(text_duration(text, *anims), frozen_frame =False) # 使用 frozen_frame 可以让 updater 动画正常运行 self.current_narrator = text self.add_fixed_mobjects(text) elif end: origin_text = self.current_narrator self.play(Transform(origin_text, text), *anims) self.wait(text_duration(text, *anims), frozen_frame =False) self.play(FadeOut(origin_text)) self.current_narrator = None self.remove_fixed_mobject(origin_text) elif start_end: self.play(FadeIn(text), *anims) self.wait(text_duration(text, *anims), frozen_frame =False) self.play(FadeOut(text)) elif not start and not end: origin_text = self.current_narrator self.play(Transform(origin_text, text), *anims) self.wait(text_duration(text, *anims), frozen_frame =False) if self.current_narrator is not None: self.current_narrator.set_z_index(10) def clear_all(self, except_fixed_mobjects = False): if except_fixed_mobjects: anim = [FadeOut(*self.mobjects), *(mob.animate.scale(1) for mob in self.fixed_mobjects)] else: anim = [FadeOut(*self.mobjects)] self.fixed_mobjects = [] self.play(*anim) self.clear() # 这一步不可忽略,否则会出现动画完成后物件突然消失的 bug self.add(*self.fixed_mobjects) def add_fixed_mobjects(self, *mobs): self.fixed_mobjects.extend(mobs) def remove_fixed_mobject(self, *mobs): for mob in mobs: self.fixed_mobjects.remove(mob) class CorrespondingPartsTransform(AnimationGroup): def __init__( self, names, *args, **kwargs ): # names is a list of mobjects # args represent lists, such as [0,1,[0,0,1,1,2,2]], the 1st and 2nd numbers represent the index of mobject in the names list def pretrans0(name, i): # get the transforming part if type(i) == int: back = name[i] elif type(i) == str: m = i.find('.') n1 = int(i[0:m]) n2 = int(i[m+1:]) back = name[n1:n2] return back def pretrans(name, i): if type(i) == int: back = name[i] elif type(i) == str: m = i.find('.') n1 = int(i[0:m]) n2 = int(i[m+1:]) back = name[n1:n2] elif type(i) == list: back = VGroup() for j in i: item = pretrans0(name, j) back.add(item) return back ag = [] itemli = [] for l in names: itemli.append(list(range(len(l)))) # delete the tranformed part def countli0(name, i): if type(i) == int: name.remove(i) elif type(i) == str: m = i.find('.') n1 = int(i[0:m]) n2 = int(i[m+1:])-1 p1 = name.index(n1) p2 = name.index(n2) del name[p1:p2+1] def countli(name, i): if type(i) == int: name.remove(i) elif type(i) == str: m = i.find('.') n1 = int(i[0:m]) n2 = int(i[m+1:])-1 p1 = name.index(n1) p2 = name.index(n2) del name[p1:p2+1] elif type(i) == list: for j in i: item = countli0(name, j) set1 = set() set2 = set() # two groups of transforming for m in range(len(args)): n = 0 for i in args[m][2]: n += 1 if n % 2 != 0: u = pretrans(names[args[m][0]], i) countli(itemli[args[m][0]], i) set1.add(args[m][0]) else: v = pretrans(names[args[m][1]], i) item = Transform(u,v) # item = ReplacementTransform(u,v) ag.append(item) countli(itemli[args[m][1]], i) set2.add(args[m][1]) for i in set1: for ii in itemli[i]: names[i][ii].save_state() ag.append(ShrinkToCenter(names[i][ii])) for j in set2: for jj in itemli[j]: ag.append(GrowFromCenter(names[j][jj])) super().__init__(*ag, **kwargs)
标签:anim,show,self,molecule,orbitals,resonance,共轭,共振 From: https://www.cnblogs.com/daxiangcai/p/17288979.html