首页 > 其他分享 >共轭与共振

共轭与共振

时间:2023-04-05 11:12:21浏览次数:40  
标签:anim show self molecule orbitals resonance 共轭 共振

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

相关文章