from manim import * import sympy as sym import numpy as np if type("xxp's manim") == str: # 不写在下方 construct 函数中,因为这可能使用到其内部的函数,我想与其分离,因为如果 construct 内部的函数改写了,我此处的类也需要改写 if type('remarks') == str: pass # 代码主要由三部分构成:1、自定义类;2、manim 类;3、执行代码部分 # 其中代码执行部分又由三部分构成:1、变量定义区(包括物件和动画);2、变量初始化区;3、动画区 if type('function') == str: def harmonic_func(u, v, l, m): # 请不要使用 if l == x & m == y 这种形式,会报错 if l == 0 & m == 0: r = np.sqrt(1/(4*PI)) elif l == 1: if m == 0: r = np.sqrt(3/(4*PI))*np.cos(u) elif m == 1: r = np.sqrt(3/(4*PI))*np.sin(u)*np.cos(v) elif m == -1: r = np.sqrt(3/(4*PI))*np.sin(u)*np.sin(v) elif l == 2: if m == 0: r = np.sqrt(5/(16*PI))*(3*np.cos(u)**2 - 1) if m == 1: r = np.sqrt(15/(4*PI))*np.sin(u)*np.cos(u)*np.cos(v) if m == -1: r = np.sqrt(15/(4*PI))*np.sin(u)*np.cos(u)*np.sin(v) if m == 2: r = np.sqrt(15/(16*PI))*np.sin(u)**2*np.sin(2*v) if m == -2: r = np.sqrt(15/(16*PI))*np.sin(u)**2*np.cos(2*v) elif l == 3: if m == 0: r = 1/4*np.sqrt(7/PI)*(5*np.cos(u)**3 - 3*np.cos(u)) if m == 1: r = 1/8*np.sqrt(42/PI)*np.sin(u)*(5*np.cos(u)**2 - 1)*np.cos(v) if m == -1: r = 1/8*np.sqrt(42/PI)*np.sin(u)*(5*np.cos(u)**2 - 1)*np.sin(v) if m == 2: r = 1/4*np.sqrt(105/PI)*np.sin(u)**2*np.cos(u)*np.sin(2*v) if m == -2: r = 1/4*np.sqrt(105/PI)*np.sin(u)**2*np.cos(u)*np.cos(2*v) if m == 3: r = 1/8*np.sqrt(70/PI)*np.sin(u)**3*np.cos(3*v) if m == -3: r = 1/8*np.sqrt(70/PI)*np.sin(u)**3*np.sin(3*v) else: raise Exception('l or m is too large') return r if type('mobject') == str: class Atom(VGroup): def __init__( self, quantum_num_li: list, # each item in this list is a list position_correction: bool = False, # 这个是专门为 sp2 杂化设计的,因为我发现 sp2 杂化时原子核不在中心,这是因为正三角形放置在画布中时不会以自身的中心为中心点,而是会产生一些偏移,于是我们使用 p 轨道定位 show_nucleus: bool = True, **kwargs ): super().__init__(**kwargs) # 如果不使用这句话,那么 self.add 会失效 nucleus = Sphere(fill_opacity=0.7, stroke_width=0, radius=0.3).set_color( "#9AFF9A") axes = ThreeDAxes(x_range=(-5, 5, 1), y_range=(-5, 5, 1), z_range=(-5, 5, 1), x_length=5, y_length=5, z_length=5) # 注意默认的 x, y, z 轴长度不相等,图像会拉伸 orbits = VGroup() for num in quantum_num_li: orbit = Surface( # 在不杂化的原子中,num 是含有两个元素的列表,分布代表 l 和 m;在杂化的原子中,num 是含有大于等于六个元素的列表,一部分包括杂化轨道的系数 lambda u, v: axes.c2p(*self.specific_harmonic_func(u, v, num)), resolution=(20, 20), v_range=[0, 2*PI], u_range=[0, 2*PI], checkerboard_colors=[BLUE], fill_opacity=0.3, stroke_width=0, ) orbits.add(orbit) nucleus_radius = nucleus.width # if orbits.depth > orbits.width: # 事实上,三维物体要考虑 width, height, depth # orbits.set(depth=6*nucleus_radius) # else: # orbits.set(width=6*nucleus_radius) if position_correction: distance_deviation = nucleus.get_center() - orbits[-1].get_center() orbits.shift(distance_deviation) orbits.rotate(angle = PI/2, axis = [1,0,0]) # sp2 杂化默认视角在 p 轨道上方,旋转 PI/2 从侧面观察 nucleus.rotate(angle = PI/2, axis = [1,0,0]) # 不能使用 self.rotate(),因为 self.add() 在下方才定义 self.nucleus = nucleus self.orbits = orbits if show_nucleus: self.add(nucleus, orbits) else: self.add(orbits) def specific_harmonic_func(self, u, v, num) -> list: # 这个函数根据是否杂化而变化 pass class AutographIntroduction(Group): def __init__( self, image: str, name: str, date_of_birth_and_death: str, **kwargs ): super().__init__(**kwargs) image = ImageMobject(image) if image.width > image.height: image.set(width = 5.5) else: image.set(height = 5.5) image.shift(3.5*LEFT+0.8*UP) name = Narrator(name).next_to(image,DOWN) date_of_birth_and_death = Narrator(date_of_birth_and_death).scale(0.8).next_to(name,DOWN) self.add(image, name, date_of_birth_and_death) class ColorBar(VGroup): def __init__( self, start_color: color = BLUE, end_color: color = RED, **kwargs ): super().__init__(**kwargs) width = 7 height = 0.5 bar = RoundedRectangle(width=width, height=height, fill_opacity=1, corner_radius=0.2).set_color_by_gradient([end_color, start_color]) bar.set(stroke_color=WHITE) pointer = Triangle(radius=0.2, fill_opacity=1).rotate(PI/3) self.start_color = start_color self.end_color = end_color self.width = width self.height = height self.bar = bar self.pointer = pointer self.add(bar, pointer) self.arrange(direction=np.array([0,1,0]),buff=0.1) # 如果使用 [0,1,0] 会报错 def begin_color_update(self): def update_color(pointer): position_deviation = (pointer.get_x() - self.bar.get_x() + self.width/2)/self.width # 范围为 0 到 1,但是会有一点点的偏差,可能超过 1 if position_deviation > 1: position_deviation = 1 pointer.set_color(interpolate_color(self.start_color, self.end_color, position_deviation)) self.pointer.add_updater(update_color) def end_color_update(self): self.pointer.clear_updater() def pointer_to_rightmost_end(self): # 效果并不理想 distance = self.bar.get_x() + self.width/2 - self.pointer.get_x() return ApplyMethod(self.pointer.shift, distance * RIGHT) def pointer_to_leftmost_end(self): # 效果并不理想 distance = self.bar.get_x() - self.width/2 - self.pointer.get_x() return ApplyMethod(self.pointer.shift, distance * RIGHT) class DotGroup(VGroup): def __init__( self, num: int = 10, internal_radius: float = 0, external_radius: float = 2.5, scale_min: float = 0.6, scale_max: float = 1.4, **kwargs ): super().__init__(**kwargs) for i in range(num): radius = internal_radius + (external_radius - internal_radius)*np.random.rand() scale = scale_min + (scale_max - scale_min)*np.random.rand() theta = np.random.rand()*2*PI self.add(Dot().copy().shift(radius*np.cos(theta)*RIGHT+radius*np.sin(theta)*UP).scale(scale)) class HybridAtom(Atom): def __init__( self, hybrid_type: int, **kwargs ): self.hybrid_type = hybrid_type quantum_num_li = self.hybrid_coefficient(hybrid_type) if hybrid_type == 2: position_correction = True else: position_correction = False super().__init__(quantum_num_li, position_correction=position_correction, **kwargs) def hybrid_coefficient(self, hybrid_type): if hybrid_type == 1: coe = [[[1/np.sqrt(2), 0, 0], [1/np.sqrt(2), 1, 1]], [[1/np.sqrt(2), 0, 0], [-1/np.sqrt(2), 1, 1]], [ [1, 1, -1]], [[1, 1, 0]]] # this represents f1 = s + px, f2 = x - px, f3 = p, f4 = p elif hybrid_type == 2: coe = [[[np.sqrt(1/3), 0, 0], [np.sqrt(2/3), 1, 1]], [[np.sqrt(1/3), 0, 0], [-np.sqrt(1/6), 1, 1], [ np.sqrt(1/2), 1, -1]], [[np.sqrt(1/3), 0, 0], [-np.sqrt(1/6), 1, 1], [-np.sqrt(1/2), 1, -1]], [[1, 1, 0]]] elif hybrid_type == 3: coe = [[[1, 0, 0], [1, 1, 1], [1, 1, -1], [1, 1, 0]], [[1, 0, 0], [1, 1, 1], [-1, 1, -1], [-1, 1, 0]], [[1, 0, 0], [-1, 1, 1], [1, 1, -1], [-1, 1, 0]], [[1, 0, 0], [-1, 1, 1], [-1, 1, -1], [1, 1, 0]]] return coe def specific_harmonic_func(self, u, v, num) -> list: r = 0 for i in num: r += i[0]*harmonic_func(u, v, i[1], i[2]) r = r ** 2 return [r*np.sin(u)*np.cos(v), r*np.sin(u)*np.sin(v), r*np.cos(u)] def correct_position(self, direction): # 将杂化的轨道调整到 direction 的方向 # 这个函数的作用效果取决于是否使用了 set_camera_orientation(),例如,我们现在想要让杂化轨道朝右,如果没有使用此方法,direction 为 [1,0,0],如果使用了此方法,direction 为 [0,1,0],这是因为 set_camera_orientation() 会使x, y 轴互换 if self.hybrid_type == 1: orbits_direction = [1,0,0] elif self.hybrid_type == 2: orbits_direction = [1,0,0] elif self.hybrid_type == 3: orbits_direction = [1,1,1] angle = angle_between_vectors(orbits_direction, direction) axis = get_unit_normal(orbits_direction, direction) # 旋转之后仍然需要调整角度来和坐标轴平行 # sp3: 15*DEGREES self.rotate(angle = angle, axis = axis) return self class LinesBetweenCenterAndVertexesOfPolyhedron(VGroup): def __init__( self, mobject, **kwargs ): # 只适用于多面体 super().__init__(**kwargs) vertexes = mobject.vertex_coords for vertex in vertexes: line = DashedLine(mobject.get_center(), vertex, shade_in_3d = True) self.add(line) class MusicRecommender(Group): def __init__( self, recommender: str, music: str, **kwargs ): super().__init__(**kwargs) image = ImageMobject(f"D:\\manimIMG\\{recommender}.png").set(width=1) music = Text(music, font='STFangSong').scale(0.7).next_to(img,10*LEFT) name = ImageMobject(f"D:\\manimIMG\\{recommender}name.png").match_height(music).next_to(img,2*RIGHT) self.add(image, music, name) class Narrator(Text): def __init__( self, text: str, font_type: int = 1, **kwargs ): if font_type == 1: font = "STZhongsong" elif font_type == 2: font = "STFangsong" super().__init__(text, font=font, **kwargs) self.to_edge(DOWN).scale(0.6) class TextFlower(VGroup): def __init__( self, text: str, color_type: int = 1, use_latex: bool = False, font: str = 'STZhongsong', **kwargs ): super().__init__(**kwargs) if color_type == 1: color = ['#f3e9e0', '#fea8a9'] elif color_type == 2: color = ['#f3e9e0', '#b1d85c'] elif color_type == 3: color = ['#f3e9e0', '#6A5ACD'] if use_latex: text = MathTex(text, stroke_width=2).set_color(color = color) else: text = Text(text, font = font, stroke_width=2).set_color(color = color) flower = SVGMobject(r"D:\manimSVG\figures\icon.svg")[8].rotate(PI/2).set_color(color = color[::-1]).scale(1.5) text.next_to(flower, RIGHT) self.add(flower, text) self.set(height = 0.6) self.move_to(ORIGIN) class UnhybridAtom(Atom): def __init__( self, *args, # this list contains l, m **kwargs ): super().__init__([[*args]], **kwargs) def specific_harmonic_func(self, u, v, num) -> list: r = harmonic_func(u, v, *num) r = r ** 2 return [r*np.sin(u)*np.cos(v), r*np.sin(u)*np.sin(v), r*np.cos(u)] class xa(Atom): # Atom def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xai(AutographIntroduction): # AutographIntroduction def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xcb(ColorBar): # ColorBar def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xdg(DotGroup): # DotGroup def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xha(HybridAtom): # HybridAtom def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xlb(LinesBetweenCenterAndVertexesOfPolyhedron): # LinesBetweenCenterAndVertexesOfPolyhedron def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xmr(MusicRecommender): # MusicRecommender def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xn(Narrator): # Narrator def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xtf(TextFlower): # TextFlower def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class xua(UnhybridAtom): # UnhybridAtom def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if type('animation') == str: 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) # 如果使用改进的 at(),会显示未定义 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) class CorrespondingPartsTransformOrigin(AnimationGroup): def __init__( self, original_mobject: mobject, target_mobject: mobject, corresponding_parts_list: list, **kwargs ): # a and b represent mobjects, c represents the corresponding transform parts def pretrans0(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] 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 n = 0 ag = [] for i in corresponding_parts_list: n += 1 if n % 2 != 0: u = pretrans(original_mobject, i) else: v = pretrans(target_mobject, i) item = Transform(u,v) ag.append(item) super().__init__(*ag, **kwargs) class DotFadeIn(AnimationGroup): def __init__( self, *mobjects, **kwargs ): ag = [] for i in mobjects: dots = DotGroup(len(i)).set_color(WHITE).set_opacity(0) ag.append(Transform(dots,i)) super().__init__(*ag, **kwargs) class DotFadeOut(AnimationGroup): def __init__( self, *mobjects, **kwargs ): ag = [] for i in mobjects: dots = DotGroup(len(i)).set_color(WHITE).set_opacity(0) ag.append(Transform(i,dots)) super().__init__(*ag, **kwargs) class FadeInDownward(AnimationGroup): def __init__( self, *mobjects, **kwargs ): ag = [] for mobject in mobjects: ag.append(FadeIn(mobject, shift=DOWN)) super().__init__(*ag, **kwargs) class FadeOutDownward(AnimationGroup): def __init__( self, *mobjects, **kwargs ): ag = [] for mobject in mobjects: ag.append(FadeOut(mobject, shift=DOWN)) super().__init__(*ag, **kwargs) class FisheyeGrow(AnimationGroup): def __init__( self, *mobjects, **kwargs ): # 注意如果对 Text 使用此动画,要使用索引才能生效:Text()[0] ag = [] for a in mobjects: a0 = a.copy() myl = 5 # myl represents the fish eye's border, default: 5 li = a.points def getlen(k): return np.sqrt(k[0]**2 + k[1]**2 + k[2]**2) for i in li: times = 0.04*(myl - getlen(i))**3 i *= times # the further, times is smaller ag.append(Transform(a0,a)) super().__init__(*ag, **kwargs) class FisheyeShrink(AnimationGroup): def __init__( self, *mobjects, **kwargs ): # 注意如果对 Text 使用此动画,要使用索引才能生效:Text()[0] ag = [] for a in mobjects: a0 = a.copy() li = a.points def getlen(k): return np.sqrt(k[0]**2 + k[1]**2 + k[2]**2) for i in li: times = 0.02*getlen(i)**3 + 0.5 # 0.5 represent the minimum, because when the point is near center, genlen() return a number near 0 i *= times # the further, times is larger ag.append(Transform(a0,a)) super().__init__(*ag, **kwargs) class RotateAboutOwnAxis(Rotate): def __init__( self, mobject, *args, **kwargs ): super().__init__(mobject, axis = [0,np.sqrt(3),1], *args, **kwargs) class SubTextFlowersCatalogue(AnimationGroup): def __init__( self, **kwargs ): super().__init__(**kwargs) def begin_animation(self, text): text_flower = TextFlower(text, color_type=2, font="Cambria Math").to_corner(UL).shift(0.8*DOWN) animation = DrawBorderThenFill(text_flower) self.text_flower = text_flower super().__init__(animation) return self def alter(self, text): text_flower_after = TextFlower(text, color_type=2, font="Cambria Math").to_corner(UL).shift(0.8*DOWN) text_flower = self.text_flower animation1 = yfod(text_flower) animation2 = yfid(text_flower_after) self.text_flower = text_flower_after super().__init__(animation1, animation2) return self def end_animation(self): text_flower = self.text_flower animation = FadeOut(text_flower) super().__init__(animation) return self class TextFlowersCatalogue(Succession): def __init__( self, texts: list, # a list of texts grid: list, buff: float = 2, # the spacing of each item **kwargs ): text_flowers = VGroup(*map(TextFlower, texts)).arrange_in_grid(*grid,buff=buff) self.text_flowers = text_flowers super().__init__(**kwargs) def begin_animation(self): # 注意不能使用 begin 命名 text_flowers = self.text_flowers flower_num = len(text_flowers) flower = TextFlower("").shift(0.7*LEFT) flowers = VGroup(*[flower.copy() for i in range(flower_num)]) # 注意不能直接写成 VGroup(... for i in ...),必须使用 * animation1 = DrawBorderThenFill(flowers) animation2 = AnimationGroup(*[Rotate(flowers[i+1], angle=2*PI/flower_num*(i+1), about_point=ORIGIN) for i in range(flower_num-1)], lag_ratio=0.3) animation3 = Transform(flowers, text_flowers) # 我用 ReplacementTransform 不能实现预期的效果 self.text_flowers = flowers # 注意,这里改变成了 transform 的对象 flowers super().__init__(animation1, animation2, animation3) return self def forward(self, index): text_flowers = self.text_flowers text_flowers_after = text_flowers[index-1].copy().to_corner(UL) shift_distance = text_flowers_after.get_center() - text_flowers[index-1].get_center() animation1 = ApplyMethod(text_flowers[index-1].shift, shift_distance) animation2 = FadeOut(text_flowers[0:index-1]) animation3 = FadeOut(text_flowers[index:]) self.shift_distance = shift_distance self.index = index return AnimationGroup(animation1, animation2, animation3) def remaining_text_flower(self, index): text_flowers = self.text_flowers text_flowers_after = text_flowers[index-1].copy().to_corner(UL) shift_distance = text_flowers_after.get_center() - text_flowers[index-1].get_center() self.shift_distance = shift_distance self.index = index return text_flowers[index-1].to_corner(UL) def backward(self): text_flowers = self.text_flowers index = self.index shift_distance = self.shift_distance animation1 = ApplyMethod(text_flowers[index-1].shift, -shift_distance) # 不再使用 Restore() animation2 = FadeIn(text_flowers[0:index-1]) animation3 = FadeIn(text_flowers[index:]) return AnimationGroup(animation1, animation2, animation3) def end_animation(self): text_flowers = self.text_flowers flower_num = len(text_flowers) flower = TextFlower("").shift(0.7*LEFT) flowers = VGroup(*[flower.copy().rotate(angle=2*PI/flower_num*i, about_point=ORIGIN) for i in range(flower_num)]) animation1 = Transform(text_flowers, flowers) animation2 = AnimationGroup(*[DrawBorderThenFill(text_flowers[i], reverse_rate_function = True) for i in range(flower_num)], lag_ratio=0.3) super().__init__(animation1, animation2) return self class Vibration(AnimationGroup): def __init__( self, *mobjects, t: int = 2, **kwargs ): ag = [] for mobject in mobjects: li = [] center = mobject.get_center() vibration_times = int(t*5) # 否则为 float 类型 for i in range(vibration_times): x = np.random.rand()*0.3 y = np.random.rand()*2*PI li.append(ApplyMethod(mobject.move_to, center+x*np.cos(y)*RIGHT+x*np.sin(y)*UP, run_time=0.2)) ag.append(Succession(*li)) super().__init__(*ag, **kwargs) class ycpt(CorrespondingPartsTransform): # CorrespondingPartsTransform def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class ycpto(CorrespondingPartsTransformOrigin): # CorrespondingPartsTransformOrigin def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class ydfi(DotFadeIn): # DotFadeIn def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class ydfo(DotFadeOut): # DotFadeOut def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class yfid(FadeInDownward): # FadeInDownward def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class yfod(FadeOutDownward): # FadeOutDownward def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class yfg(FisheyeGrow): # FisheyeGrow def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class yfs(FisheyeShrink): # FisheyeShrink def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class yrab(RotateAboutOwnAxis): # RotateAboutOwnAxis def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class ystf(SubTextFlowersCatalogue): # SubTextFlowersCatalogue def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class ytfc(TextFlowersCatalogue): # TextFlowersCatalogue def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class yv(Vibration): # Vibration def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if type('protagonist') == str: class Orbital(VGroup): def __init__( self, l: int, m: int, **kwargs ): super().__init__(**kwargs) self.l = l self.m = m phi = self.wave_func_phi(m) theta = self.wave_func_theta(l, m) p = sym.symbols('p') t = sym.symbols('t') def harmonic_func(u, v): r = phi.subs(p, v)*theta.subs(t, u) # u v 的顺序不要搞错 r = r ** 2 return [r*np.sin(u)*np.cos(v), r*np.sin(u)*np.sin(v), r*np.cos(u)] axes = ThreeDAxes(x_range=(-5, 5, 1), y_range=(-5, 5, 1), z_range=(-5, 5, 1), x_length=5, y_length=5, z_length=5) nucleus = Sphere(fill_opacity=0.7, stroke_width=0, radius=0.5).set_color("#9AFF9A") orbit = Surface( lambda u, v: axes.c2p(*harmonic_func(u, v)), resolution=(20, 20), v_range=[0, 2*PI], u_range=[0, PI], checkerboard_colors=[BLUE], fill_opacity=0.8, stroke_width=0, ) nucleus_radius = nucleus.width if orbit.width >= orbit.height: if orbit.width >= orbit.depth: orbit.set(width=6*nucleus_radius) else: orbit.set(depth=6*nucleus_radius) else: if orbit.height >= orbit.depth: orbit.set(height=6*nucleus_radius) else: orbit.set(depth=6*nucleus_radius) self.orbit = orbit self.l_and_m = f'l = {str(l)}, m = {str(m)}' self.add(orbit) def wave_func_phi(self, m): p = sym.symbols('p') if m >= 0: result = sym.cos(m*p) # 省略了系数 elif m < 0: result = sym.sin(np.abs(m)*p) # 省略了系数 return result def wave_func_theta(self, l, m): m = np.abs(m) x = sym.symbols('x') t = sym.symbols('t') def associated_legendre_polynomial(l, m): def legendre_polynomial(n): if n == 0: return 1 elif n == 1: return x elif n >= 2: result = (2*n-1)/n*x*legendre_polynomial(n-1) - (n-1)/n*legendre_polynomial(n-2) return sym.simplify(result) result = (1-x**2)**(m/2)*sym.diff(legendre_polynomial(l), x, m) return sym.simplify(result.subs(x, sym.cos(t))) result = associated_legendre_polynomial(l, m) # 省略了系数 return result def wave_func_radius(self, n, l): x = sym.symbols('x') def associated_Laguerre_polynomial(n, l): result = x**(-l)*sym.exp(x)*sym.diff(sym.exp(-x)*x**(n+l), x, n) # 这里的 x 实际上也要乘以一个系数 return sym.simplify(result) result = sym.exp(-x/2)*x**l*associated_Laguerre_polynomial(n, l) # 省略了系数 return result def harmonic_func(self, u, v, l, m): phi = self.wave_func_phi(m) theta = self.wave_func_theta(l, m) p = sym.symbols('p') t = sym.symbols('t') func = phi.subs(p, v)*theta.subs(t, u) # u v 的顺序不要搞错 return func def axes(self): axes = SVGMobject(r"D:\manimSVG\axes.svg").set_height(5.5) axes_distance_deviation = ORIGIN - axes[-1].get_center() axes.shift(axes_distance_deviation) return axes class HybridOrbital(VGroup): def __init__( self, hybrid_num: int, **kwargs ): super().__init__(**kwargs) self.num = hybrid_num property = self.hybrid_orbit_property(hybrid_num) axes = ThreeDAxes(x_range=(-5, 5, 1), y_range=(-5, 5, 1), z_range=(-5, 5, 1), x_length=5, y_length=5, z_length=5) orbits = VGroup() labels = VGroup() for coe in property[4:]: def hybrid_orbit(u, v): r = 0 n = 0 for origin_orbit in property[3]: r += coe[n]*self.harmonic_func(u, v, *origin_orbit) n += 1 r = r ** 2 return [r*np.sin(u)*np.cos(v), r*np.sin(u)*np.sin(v), r*np.cos(u)] orbit = Surface( lambda u, v: axes.c2p(*hybrid_orbit(u, v)), resolution=(40, 40), v_range=[0, 2*PI], u_range=[0, PI], checkerboard_colors=[BLUE], fill_opacity=0.8, stroke_width=0, ) orbits.add(orbit) self.scale_to_fit(orbits) geometry = self.geometry() self.add(orbits, geometry) self.arrange(buff=2) label1 = TextFlower(property[0], color_type=1, use_latex=True).to_corner(UL) label2 = TextFlower(property[1], color_type=2, use_latex=True).next_to(label1, RIGHT) label3 = TextFlower(property[2], color_type=3).next_to(label2, RIGHT) labels.add(label1, label2, label3) self.add(labels) def scale_to_fit(self, mob): if mob.width >= mob.height: if mob.width >= mob.depth: mob.set(width=4.5) else: mob.set(depth=4.5) else: if mob.height >= mob.depth: mob.set(height=4.5) else: mob.set(depth=4.5) def hybrid_orbit_property(self, num): if num == 2: property = ['AB_{2}','sp','直线形',[[0,0],[1,1]],[np.sqrt(1/2), np.sqrt(1/2)],[np.sqrt(1/2), -np.sqrt(1/2)]] elif num == 3: property = ['AB_{3}','sp^{2}','平面正三角形',[[0,0],[1,1],[1,-1]],[np.sqrt(1/3),np.sqrt(2/3),0],[np.sqrt(1/3),-np.sqrt(1/6),np.sqrt(1/2)],[np.sqrt(1/3),-np.sqrt(1/6),-np.sqrt(1/2)]] elif num == 4: property = ['AB_{4}','sp^{3}','正四面体',[[0,0],[1,0],[1,1],[1,-1]],[1/2,1/2,1/2,1/2],[1/2,-1/2,-1/2,1/2],[1/2,1/2,-1/2,-1/2],[1/2,-1/2,1/2,-1/2]] elif num == 5: property = ['AB_{4}','dsp^{2}','平面正方形',[[0,0],[2,2],[1,1],[1,-1]],[1/2,1/2,np.sqrt(1/2),0],[1/2,-1/2,0,np.sqrt(1/2)],[1/2,1/2,-np.sqrt(1/2),0],[1/2,-1/2,0,-np.sqrt(1/2)]] elif num == 6: property = ['AB_{5}','dsp^{3}/d^{3}sp','三角双锥',[[0,0],[2,0],[1,1],[1,-1],[1,0]],[np.sqrt(1/2),0,0,0,np.sqrt(1/2)],[np.sqrt(1/2),0,0,0,-np.sqrt(1/2)],[0,np.sqrt(1/3),np.sqrt(2/3),0,0],[0,np.sqrt(1/3),-np.sqrt(1/6),np.sqrt(1/2),0],[0,np.sqrt(1/3),-np.sqrt(1/6),-np.sqrt(1/2),0]] elif num == 7: property = ['AB_{6}','d^{4}sp','正三棱柱',[[0,0],[1,1],[1,-1],[1,0],[2,1],[2,-1]],[np.sqrt(1/6),np.sqrt(1/3),0,-np.sqrt(1/6),-np.sqrt(1/3),0],[np.sqrt(1/6),np.sqrt(1/3),0,np.sqrt(1/6),np.sqrt(1/3),0],[np.sqrt(1/6),-np.sqrt(1/12),1/2,-np.sqrt(1/6),np.sqrt(1/12),-1/2],[np.sqrt(1/6),-np.sqrt(1/12),1/2,np.sqrt(1/6),-np.sqrt(1/12),1/2],[np.sqrt(1/6),-np.sqrt(1/12),-1/2,np.sqrt(1/6),-np.sqrt(1/12),-1/2],[np.sqrt(1/6),-np.sqrt(1/12),-1/2,-np.sqrt(1/6),np.sqrt(1/12),1/2]] elif num == 8: property = ['AB_{6}','sp^{3}d^{2}/d^{2}sp^{3}','正八面体',[[0,0],[2,0],[2,2],[1,1],[1,-1],[1,0]],[np.sqrt(1/6),-np.sqrt(1/12),1/2,np.sqrt(1/2),0,0],[np.sqrt(1/6),-np.sqrt(1/12),1/2,-np.sqrt(1/2),0,0],[np.sqrt(1/6),-np.sqrt(1/12),-1/2,0,np.sqrt(1/2),0],[np.sqrt(1/6),-np.sqrt(1/12),-1/2,0,-np.sqrt(1/2),0],[np.sqrt(1/6),np.sqrt(1/3),0,0,0,np.sqrt(1/2)],[np.sqrt(1/6),np.sqrt(1/3),0,0,0,-np.sqrt(1/2)]] elif num == 9: sin1=np.sin(0.4*PI) sin2=np.sin(0.8*PI) cos1=np.cos(0.4*PI) cos2=np.cos(0.8*PI) s1 = sin1/np.sqrt(2*(sin1**2+sin2**2)) s2 = sin2/np.sqrt(2*(sin1**2+sin2**2)) c1 = cos1/np.sqrt(1+2*(cos1**2+cos2**2)) c2 = cos2/np.sqrt(1+2*(cos1**2+cos2**2)) constant = 1/np.sqrt(1+2*(cos1**2+cos2**2)) property = ['AB_{7}','d^{3}sp^{3}','五角双锥',[[2,0],[0,0],[1,1],[1,-1],[2,2],[2,-2],[1,0]],[np.sqrt(1/7),np.sqrt(1/2),0,0,0,0,np.sqrt(1/2)],[np.sqrt(1/7),np.sqrt(1/2),0,0,0,0,-np.sqrt(1/2)],[np.sqrt(1/7),0,0,constant,constant,0,0],[np.sqrt(1/7),0,s2,c2,c1,s1,0],[np.sqrt(1/7),0,-s1,c1,c2,s2,0],[np.sqrt(1/7),0,s1,c1,c2,-s2,0],[np.sqrt(1/7),0,-s2,c2,c1,-s1,0]] elif num == 10: c = np.sqrt(1/8) property = ['AB_{8}','d^{3}fsp^{3}','立方体',[[0,0],[2,1],[2,-1],[2,-2],[3,2],[1,1],[1,-1],[1,0]],[c,c,c,c,c,c,c,c],[c,-c,c,-c,-c,-c,c,c],[c,-c,-c,c,c,-c,-c,c],[c,c,-c,-c,-c,c,-c,c],[c,-c,-c,c,-c,c,c,-c],[c,c,-c,-c,c,-c,c,-c],[c,c,c,c,-c,-c,-c,-c],[c,-c,c,-c,c,c,-c,-c]] elif num == 11: c = np.sqrt(1/8) property = ['AB_{8}','d^{4}sp^{3}','正四角反棱柱',[[0,0],[1,0],[1,1],[1,-1],[2,2],[2,-2],[2,1],[2,-1]],[c,-c,c,-c,0,-1/2,-c,c],[c,-c,c,c,0,1/2,-c,-c],[c,-c,-c,c,0,-1/2,c,-c],[c,-c,-c,-c,0,1/2,c,c],[c,c,1/2,0,1/2,0,1/2,0],[c,c,0,1/2,-1/2,0,0,1/2],[c,c,-1/2,0,1/2,0,-1/2,0],[c,c,0,-1/2,-1/2,0,0,-1/2]] elif num == 12: property = ['AB_{8}','d^{4}sp^{3}','十二面体',[[0,0],[2,0],[2,2],[1,0],[1,1],[1,-1],[2,1],[2,-1]],[1/2,0,1/2,0,np.sqrt(1/2),0,0,0],[1/2,0,-1/2,0,0,np.sqrt(1/2),0,0],[1/2,0,1/2,0,-np.sqrt(1/2),0,0,0],[1/2,0,-1/2,0,0,-np.sqrt(1/2),0,0],[0,1/2,0,1/2,0,0,np.sqrt(1/2),0],[0,1/2,0,1/2,0,0,-np.sqrt(1/2),0],[0,1/2,0,-1/2,0,0,0,np.sqrt(1/2)],[0,1/2,0,-1/2,0,0,0,-np.sqrt(1/2)]] return property def harmonic_func(self, u, v, l, m): if l == 0 & m == 0: r = np.sqrt(1/(4*PI)) elif l == 1: if m == 0: r = np.sqrt(3/(4*PI))*np.cos(u) elif m == 1: r = np.sqrt(3/(4*PI))*np.sin(u)*np.cos(v) elif m == -1: r = np.sqrt(3/(4*PI))*np.sin(u)*np.sin(v) elif l == 2: if m == 0: r = np.sqrt(5/(16*PI))*(3*np.cos(u)**2 - 1) if m == 1: r = np.sqrt(15/(16*PI))*np.sin(2*u)*np.cos(v) if m == -1: r = np.sqrt(15/(16*PI))*np.sin(2*u)*np.sin(v) if m == 2: r = np.sqrt(15/(16*PI))*np.sin(u)**2*np.cos(2*v) if m == -2: r = np.sqrt(15/(16*PI))*np.sin(u)**2*np.sin(2*v) elif l == 3: if m == 0: r = 1/4*np.sqrt(7/PI)*(5*np.cos(u)**3 - 3*np.cos(u)) if m == 1: r = 1/8*np.sqrt(42/PI)*np.sin(u)*(5*np.cos(u)**2 - 1)*np.cos(v) if m == -1: r = 1/8*np.sqrt(42/PI)*np.sin(u)*(5*np.cos(u)**2 - 1)*np.sin(v) if m == 2: r = 1/4*np.sqrt(105/PI)*np.sin(u)**2*np.cos(u)*np.sin(2*v) if m == -2: r = 1/4*np.sqrt(105/PI)*np.sin(u)**2*np.cos(u)*np.cos(2*v) if m == 3: r = 1/8*np.sqrt(70/PI)*np.sin(u)**3*np.cos(3*v) if m == -3: r = 1/8*np.sqrt(70/PI)*np.sin(u)**3*np.sin(3*v) else: raise Exception('l or m is too large') return r def geometry(self): num = self.num if num == 2: vertex_coords = [[1,0,0],[-1,0,0]] faces_list = [[0,1]] elif num == 3: vertex_coords = [[2,0,0],[-1,np.sqrt(3),0],[-1,-np.sqrt(3),0]] faces_list = [[0,1,2]] elif num == 4: vertex_coords = [[1,1,1],[-1,-1,1],[1,-1,-1],[-1,1,-1]] faces_list = [[0,1,2],[0,1,3],[0,2,3],[1,2,3]] elif num == 5: vertex_coords = [[1,0,0],[0,1,0],[-1,0,0],[0,-1,0]] faces_list = [[0,1,2,3]] elif num == 6: vertex_coords = [[-2,0,0],[1,np.sqrt(3),0],[1,-np.sqrt(3),0],[0,0,2],[0,0,-2]] faces_list = [[0,1,3],[1,2,3],[0,2,3],[0,1,4],[1,2,4],[0,2,4]] elif num == 7: vertex_coords = [[-1,np.sqrt(3),np.sqrt(3)],[2,0,np.sqrt(3)],[-1,-np.sqrt(3),np.sqrt(3)],[-1,np.sqrt(3),-np.sqrt(3)],[2,0,-np.sqrt(3)],[-1,-np.sqrt(3),-np.sqrt(3)]] faces_list = [[0,1,2],[0,2,5,3],[2,1,4,5],[0,1,4,3],[3,4,5]] elif num == 8: vertex_coords = [[0,-1,0],[-1,0,0],[0,1,0],[1,0,0],[0,0,1],[0,0,-1]] faces_list = [[0,1,4],[1,2,4],[2,3,4],[0,3,4],[0,1,5],[1,2,5],[2,3,5],[0,3,5]] elif num == 9: vertex_coords = [[0,-1,0],[np.cos(0.1*PI),-np.sin(0.1*PI),0],[np.cos(0.3*PI),np.sin(0.3*PI),0],[-np.cos(0.3*PI),np.sin(0.3*PI),0],[-np.cos(0.1*PI),-np.sin(0.1*PI),0],[0,0,1],[0,0,-1]] faces_list = [[5,4,0],[5,0,1],[5,1,2],[5,2,3],[5,3,4],[5,4,0],[6,4,0],[6,0,1],[6,1,2],[6,2,3],[6,3,4],[6,4,0]] elif num == 10: vertex_coords = [[1,1,1],[1,-1,1],[-1,-1,1],[-1,1,1],[1,1,-1],[1,-1,-1],[-1,-1,-1],[-1,1,-1]] faces_list = [[0,1,2,3],[3,0,4,7],[0,1,5,4],[2,1,5,6],[2,3,7,6],[4,5,6,7]] elif num == 11: vertex_coords = [[0,np.sqrt(2),1],[np.sqrt(2),0,1],[0,-np.sqrt(2),1],[-np.sqrt(2),0,1],[1,1,-1],[1,-1,-1],[-1,-1,-1],[-1,1,-1]] faces_list = [[0,1,2,3],[3,0,7],[0,1,4],[1,4,5],[1,2,5],[2,5,6],[2,3,6],[3,6,7],[4,5,6,7]] elif num == 12: vertex_coords = [[0,2,0],[2,0,0],[0,-2,0],[-2,0,0],[-1,0,np.sqrt(3)],[1,0,np.sqrt(3)],[0,1,-np.sqrt(3)],[0,-1,-np.sqrt(3)]] faces_list = [[0,3,4],[0,1,5],[0,4,5],[2,3,4],[1,2,5],[2,4,5],[0,3,6],[0,1,6],[2,3,7],[1,2,7],[3,6,7],[1,6,7]] geo = Polyhedron(vertex_coords, faces_list) self.scale_to_fit(geo) for dot in geo.graph: dot.set(width=0.3) return geo class k1(Scene): def construct(self): if type('abbreviation') == str: # 必须写在 construct 函数里面 if type('constant') == str: r = RIGHT;l = LEFT;d = DOWN;u = UP;o = ORIGIN # color cr = RED;cb = BLUE;cg = GREEN;cgo = GOLD;cp = PINK;ct = TEAL;cw = WHITE if type('manim CE') == str: def sa(*args, **kwargs): # self.add() return self.add(*args, **kwargs) def saw(*args, **kwargs): # self.add() and self.wait() self.add(*args, **kwargs);self.wait() def sc(*args, **kwargs): # self.clear() return self.clear(*args, **kwargs) def sp(*args, **kwargs): # self.play() return self.play(*args, **kwargs) def sr(*args, **kwargs): # self.remove() return self.remove(*args, **kwargs) def sw(*args, **kwargs): # self.wait() return self.wait(*args, **kwargs) def ac(a, b): # Animation coloring return ApplyMethod(a.set_color, b) def acg(*args, **kwargs): # Animation coloring group li = [] for i in range(len(args)): if i % 2 == 0: li.append(ApplyMethod(args[i].set_color, args[i+1], **kwargs)) return AnimationGroup(*li) def aci(a, *args, **kwargs): # Animation Circumscribe() return Circumscribe(a, *args, **kwargs) def acct(a, b, *args, **kwargs): # Animation CounterclockwiseTransform() return CounterclockwiseTransform(a, b, *args, **kwargs) def act(a, b, *args, **kwargs): # Animation ClockwiseTransform() return ClockwiseTransform(a, b, *args, **kwargs) def adb(*args, **kwargs): # Animation DrawBorderThenFill() li = [] for i in args: li.append(DrawBorderThenFill(i, **kwargs)) return AnimationGroup(*li) def adbo(a, *args, **kwargs): # Animation DrawBorderThenFill() origin return DrawBorderThenFill(a, *args, **kwargs) def adbr(a, *args, **kwargs): # Animation DrawBorderThenFill() reverse return DrawBorderThenFill(a, *args, **kwargs, reverse_rate_function = True) def afi(a, *args, **kwargs): # Animation FadeIn() return FadeIn(a, *args, **kwargs) def afii(a, *args, **kwargs): # Animation FadeIn() return FadeIn(a, *args, shift=DOWN, **kwargs) def afo(a, *args, **kwargs): # Animation FadeOut() return FadeOut(a, *args, **kwargs) def afoo(a, *args, **kwargs): # Animation FadeOut() return FadeOut(a, *args, shift=DOWN, **kwargs) def agf(*args, **kwargs): # Animation GrowFromCenter() li = [] for i in args: li.append(GrowFromCenter(i, **kwargs)) return AnimationGroup(*li) def agfe(a, b, *args, **kwargs): # Animation GrowFromEdge() return GrowFromEdge(a, b, *args, **kwargs) def agfo(a, *args, **kwargs): # Animation GrowFromCenter() origin return GrowFromCenter(a, *args, **kwargs) def agfp(a, b, *args, **kwargs): # Animation GrowFromPoint() return GrowFromPoint(a, b, *args, **kwargs) def ai(a, *args, **kwargs): # Animation Indicate return Indicate(a, *args, **kwargs) def als(a, *args, **kwargs): # Animation LaggedStart() return LaggedStart(a, *args, **kwargs) def ama(a, b, *args, **kwargs): # Animation MoveAlongPath() return MoveAlongPath(a, b, *args, **kwargs) def amt(*args, **kwargs): # Animation move to li = [] i = 1 for a in args: if i % 2 != 0: li.append(ApplyMethod(a.move_to, args[i], **kwargs)) i += 1 return AnimationGroup(*li) def are(a, *args, **kwargs): # Animation Restore() return Restore(a, *args, **kwargs) def aro(a, *args, **kwargs): # Animation Rotate() return Rotate(a, *args, **kwargs) def art(a, b, *args, **kwargs): # Animation ReplacementTransform() return ReplacementTransform(a, b, *args, **kwargs) def asc(a, b): # Animation scale return ApplyMethod(a.scale, b) def ascg(*args, **kwargs): # Animation scale group li = [] i = 1 for a in args: if i % 2 != 0: li.append(ApplyMethod(a.scale, args[i], **kwargs)) i += 1 return AnimationGroup(*li) def ash(a, b): # Animation Shift return ApplyMethod(a.shift, b) def ashg(*args, **kwargs): # Animation Shift group li = [] i = 1 for a in args: if i % 2 != 0: li.append(ApplyMethod(a.shift, args[i], **kwargs)) i += 1 return AnimationGroup(*li) def asho(a, b, *args, **kwargs): # Animation Shift origin return a.animate.shift(b, *args, **kwargs) def asi(a, *args, **kwargs): # Animation SpinInFromNothing return SpinInFromNothing(a, angle=2 * PI, *args, **kwargs) def asir(a, *args, **kwargs): # Animation SpinInFromNothing reverse return SpinInFromNothing(a, angle=2 * PI, *args, **kwargs, reverse_rate_function = True) def aso(*args, **kwargs): # Animation set opacity li = [] for i in range(len(args)): if i % 2 == 0: li.append(ApplyMethod(args[i].set_opacity, args[i+1], **kwargs)) return AnimationGroup(*li) def ast(*args, **kwargs): # Animation ShrinkToCenter def ast_single(a, *args, **kwargs): dot = Dot(radius=0.01).set_opacity(0).move_to(a) return at(a,dot) li = [] for i in args: li.append(ast_single(i)) return AnimationGroup(*li) def asto(a, *args, **kwargs): # Animation ShrinkToCenter origin # a will restore after shrink a.save_state() li = [] li.append(ShrinkToCenter(a, *args, **kwargs)) li.append(Restore(a, run_time=0)) return Succession(*li) def asu(*args): # Animation Succession return Succession(*args) def at(a, b, *args, **kwargs): # Animation Transform() (improved) # improve: a will not change after transform a.save_state() return Succession(ReplacementTransform(a, b, *args, **kwargs),Restore(a,run_time=0)) def atm(a, b, *args, **kwargs): # Animation TransformMatchingShapes() return TransformMatchingShapes(a, b, *args, **kwargs) def ato(a, b, *args, **kwargs): # Animation Transform() origin return Transform(a, b, *args, **kwargs) def auw(a, *args, **kwargs): # Animation Unwrite() return Unwrite(a, *args, **kwargs) def aw(*args, **kwargs): # Animation Wait() return Wait(*args, **kwargs) def awi(a, *args, **kwargs): # Animation Wiggle() return Wiggle(a, *args, **kwargs) def awr(a, *args, **kwargs): # Animation Write() return Write(a, *args, **kwargs) def mab(a, b, *args, **kwargs): # mobject ArcBetweenPoints return ArcBetweenPoints(a.get_center(), b.get_center(), angle = 120*DEGREES, *args, **kwargs) def mbbm(a,b,buff,rise=0,single=0,dire=DOWN): # mobject BraceBetweenMobject x = a.get_center() - b.get_center() y = x/np.sqrt(x[0]**2+x[1]**2+x[2]**2) if single == 0: return BraceBetweenPoints(a.get_center() + buff + rise/2*y, b.get_center() + buff - rise/2*y) else: return BraceBetweenPoints(a.get_center() + buff - rise/2*dire, b.get_center() + buff + rise/2*(dire)) def mdl(a, b, *args, **kwargs): # mobject DashedLine return DashedLine(a, b, *args, **kwargs) def mmt(text, *args, **kwargs): # mobject MathTex return MathTex(text, *args, **kwargs) def msm(name, *args, **kwargs): # mobject SVGMobject sm = SVGMobject(f'D:\\manimSVG\\{name}.svg') return sm def msmc(name, *args, **kwargs): # mobject SVGMobject constant sm = SVGMobject(f'D:\\manimSVG\\constants\\{name}.svg').scale(0.4).shift(5*r) return sm def mt(text, *args, **kwargs): # mobject Text return Text(text, *args, **kwargs) def mte(*args, **kwargs): # mobject Tetrahedron return Tetrahedron(*args, **kwargs) def mteu(edge_length = 1.2): # mobject Tetrahedron upright vertex_coords = [ [-np.sqrt(3)*edge_length, 0, -1*edge_length], [np.sqrt(3)*edge_length, 0, -1*edge_length], [0, 0, 2*edge_length], [0, 2*np.sqrt(2)*edge_length, 0] ] faces_list = [ [0, 1, 2], [3, 1, 2], [0, 3, 2], [0, 1, 3] ] return Polyhedron(vertex_coords, faces_list) def mvg(*args, **kwargs): # mobject VGroup return VGroup(*args, **kwargs) if type('organization') == str: def obc(*args): # organization beforehand coloring i = 1 for a in args: if i % 2 != 0: a.set_color(args[i]) i += 1 def obmt(*args): # organization beforehand move to i = 1 for a in args: if i % 2 != 0: a.move_to(args[i]) i += 1 def obnt(*args): # organization beforehand next to i = 0 for a in args: if i % 3 == 0: a.next_to(args[i+1], args[i+2]) i += 1 def obntr(*args): # organization beforehand next to regardless of thickness i = 0 for a in args: if i % 3 == 0: a.move_to(args[i+1]).shift(args[i+2]) i += 1 def obo(*args): # organization beforehand (set) opacity i = 1 for a in args: if i % 2 != 0: a.set_opacity(args[i]) i += 1 def obsc(*args): # organization beforehand scale i = 1 for a in args: if i % 2 != 0: if type(a) == list: for j in a: j.scale(args[i]) else: a.scale(args[i]) i += 1 def obsh(*args): # organization beforehand shift i = 1 for a in args: if i % 2 != 0: a.shift(args[i]) i += 1 def oc(*args): # organization check self.camera.background_color = WHITE full = FullScreenRectangle() for svg in args: if type(svg) == list: self.clear() def checkedge(a): for i in a: if i.width/i.height > 1920/1080: i.set(width = full.width/2.5) else: i.set(height = full.height/2.5) checkedge(svg) if len(svg) == 2: svg[0].to_corner(UL) svg[1].to_corner(DR) elif len(svg) == 3: svg[0].to_corner(UL) svg[1].to_corner(UR) svg[2].to_corner(DL) elif len(svg) == 4: svg[0].to_corner(UL) svg[1].to_corner(UR) svg[2].to_corner(DL) svg[3].to_corner(DR) for sss in svg: self.add(sss.set(color = RED)) for sss in svg: n = 0 for i in sss: num = Integer(number=n, stroke_width=2).set_color(BLACK).move_to(i) n += 1 self.add(num) self.wait() else: self.clear() self.add(svg.set(color = RED)) n = 0 for i in svg: num = Integer(number=n, stroke_width=2).set_color(BLACK).move_to(i) n += 1 self.add(num) self.wait() self.clear() def ocoi(*args): # organization color and opacity init def xc2h(c): return rgb_to_hex(color_to_rgb(c)) for a in args: # 先缩放再设置透明度(否则会消失不见) a.set_opacity(1) for i in a: if xc2h(i.color) == '#ff0000': i.set_color([RED_C, RED_E]).set_sheen(0.3).set_opacity(0.8) elif xc2h(i.color) == '#ffff00': i.set_color([GOLD_C, GOLD_E]).set_sheen(0.3).set_opacity(0.8) elif xc2h(i.color) == '#00ff00': i.set_color([GREEN_C, GREEN_E]).set_sheen(0.3).set_opacity(0.8) elif xc2h(i.color) == '#00ffff': i.set_color([TEAL_C, TEAL_E]).set_sheen(0.3).set_opacity(0.8) elif xc2h(i.color) == '#0000ff': i.set_color([BLUE_C, BLUE_E]).set_sheen(0.3).set_opacity(0.8) elif xc2h(i.color) == '#ff00ff': i.set_color([PINK_C, PINK_E]).set_sheen(0.3).set_opacity(0.8) def oen(a): # organization execute narrator for i in a: globals()[f't{str(i)}']=xn(a[i]) def oeo(name,a): # organization execute object # attention: when you try to use object defined before in oeo(), you should run this function before you defined for i in a: if type(a[i]) == str: globals()[name + str(i)]=xn(a[i], font_type=2) else: globals()[name + str(i)]=a[i] def oes(name, num): # organization execute SVGMobject for i in range(num): globals()[name + str(i+1)]=msm(name + str(i+1)) def olal(t,*argss): # organization lagged animations list args = [] for i in argss: args.append(i) args.reverse() # 不是args = args.reverse() n = 0 for a in args: if n == 1: ag = AnimationGroup(args[1],args[0],lag_ratio=t) elif n > 1: ag = AnimationGroup(a,ag,lag_ratio=t) n += 1 return ag def oms(a, n1, b, n2): # organization move and scale (according to components) scale = b[n2].width/a[n1].width a.scale(scale) vect = b[n2].get_center() - a[n1].get_center() a.shift(vect) def onp(*args): # organization normalize perspective for i in args: i.rotate(angle = -PI/2, axis=[1,0,0]) # 让 z 轴向上 i.rotate(angle = PI/6, axis=[1,0,0]) def ont(a,n,b,m,buff): # organization next to (according to components) a1 = a[n].copy() a[n].next_to(b[m],buff) vect = a[n].get_center() - a1.get_center() aleft = mvg(a[0:n],a[n+1:]) aleft.shift(vect) def oos(num, *args): # organization opacity scale (according to components) # num represents the magnification of the 1st mobject, args represent the mobjects def premovescale(a, b): for i in a: # 设置 get_fill_opacity() == 0.5 会失效 if i.get_fill_opacity() < 1: x = i for j in b: if j.get_fill_opacity() < 1: y = j scale = y.height/x.height a.scale(scale) # 先缩放再移动 vector = y.get_center() - x.get_center() a.shift(vector) args[0].scale(num) for n in range(len(args) - 1): premovescale(args[n+1], args[n]) ocoi(*args) def opic(r, *args): # organization place in circle n = 0 vg = VGroup() for i in args: i.move_to(ORIGIN) i.shift(r*np.cos(n*2*PI/len(args) + PI/2)*RIGHT + r*np.sin(n*2*PI/len(args) + PI/2)*UP) vg.add(i) n += 1 return vg def opifb(*args): # organization place in flex box # about the screen: # 横向为 x 方向,纵向为 y 方向,垂直屏幕方向为 z 方向(不使用 set_camera_orientation()) # x 方向为 width,y 方向为 height,z 方向为 depth # 总宽为 13.2,即 6.6 * 2 # 总高为 5.6,即 2.8 * 2(除去底部旁白和顶部目录) full_width = 13.2 full_height = 5.6 buff = 1.2 # 物体之间的间距 def scale_according_to_aspect_radio(mobject, width, height): aspect_radio = width/height mob_aspect_radio = mobject.width/mobject.height if mob_aspect_radio > aspect_radio: mobject.scale_to_fit_width(width) else: mobject.scale_to_fit_height(height) row_num = len(args) each_mob_height = (full_height - (row_num - 1)*buff)/row_num row_index = 0 for arg in args: column_num = len(arg) each_mob_width = (full_width - (column_num - 1)*buff)/column_num column_index = 0 for mob in arg: scale_according_to_aspect_radio(mob, each_mob_width, each_mob_height) mob.move_to(ORIGIN) mob.shift(full_width/2*LEFT + full_height/2*UP + (row_index + 1/2)*each_mob_height*DOWN + row_index*buff*DOWN + (column_index + 1/2)*each_mob_width*RIGHT + column_index*buff*RIGHT) column_index += 1 row_index += 1 def osp(*args): # organization successive play (deprecated) for a in args: if type(a) == list: self.wait(0.5) self.play(*a) self.wait(0.5) elif type(a) == tuple: self.clear() self.add(*a) elif a.__class__.__name__ == 'Wait': self.play(a) else: self.wait(0.5) self.play(a) self.wait(0.5)
标签:4.2,self,args,sqrt,kwargs,np,def,manim From: https://www.cnblogs.com/daxiangcai/p/17110188.html