【Manim】用manim描述二次曲面——上
二次曲面是可以化为一般形式的任意方程的图形
这里面A,...,J是常数。我们不可能把它们都列出来,但是有一些标准方程所以这里是一些更常见的二次曲面的列表。
1. 椭球体
这是椭球体的一般方程。。
这是一个典型椭球体的草图。
接下来我们用Manim实现该椭球体的绘制。
示例代码:
from manim import * # 导入 Manim 的所有模块和类 class EllipsoidScene(ThreeDScene): # 定义一个名为 EllipsoidScene 的 3D 场景类 def construct(self): # 定义构造方法 self.camera.background_color = WHITE # 设置相机背景颜色为白色 # 设置椭球体的参数 a, b, c = 1.5, 3.5, 1 # a, b, c 分别是椭球体的半径参数 # 使用参数方程创建椭球体 ellipsoid = Surface( lambda u, v: np.array([ a * np.cos(u) * np.sin(v), # x 坐标 b * np.sin(u) * np.sin(v), # y 坐标 c * np.cos(v) # z 坐标 ]), u_range=[0, TAU], # 参数 u 的范围为 0 到 2π v_range=[0, 2*PI], # 参数 v 的范围为 0 到 2π resolution=(24, 48), # 设置网格分辨率 ) # 设置椭球体的样式:填充颜色为红色,填充透明度为1,轮廓颜色为白色 ellipsoid.set_style(fill_color=(RED, RED_E), fill_opacity=1, stroke_color=WHITE) # 在椭球体的表面上添加平行线 for v in np.linspace(-PI/2, PI/2, 5): # 在 v 的范围内均匀分布5个值 line = Line( start=np.array([a * np.cos(0) * np.sin(v), b * np.sin(0) * np.sin(v), c * np.cos(v)]), end=np.array([a * np.cos(TAU) * np.sin(v), b * np.sin(TAU) * np.sin(v), c * np.cos(v)]) ) line.set_color(WHITE) # 将线的颜色设置为白色 line.set_stroke(width=1.5) # 设置线的宽度 self.add(line) # 将线添加到场景中 # 将椭球体添加到场景中 self.add(ellipsoid) # 添加坐标轴 axes = ThreeDAxes().set_color(BLACK) # 创建坐标轴,并设置颜色为黑色 self.add(axes) # 将坐标轴添加到场景中 # 为坐标轴添加标签 x_label = MathTex("X").next_to(axes.x_axis.get_end(), RIGHT).set_color(BLACK) y_label = MathTex("Y").next_to(axes.y_axis.get_end(), UP).set_color(BLACK) z_label = MathTex("Z").next_to(axes.z_axis.get_end(), RIGHT).set_color(BLACK) self.add(x_label, y_label, z_label) # 将标签添加到场景中 # 设置相机的旋转角度,以更好地查看椭球体 self.set_camera_orientation(phi=75 * DEGREES, theta=45 * DEGREES) # self.set_camera_orientation(pitch=75 * DEGREES, yaw=145 * DEGREES, roll=130 * DEGREES) # 这一行是备用的相机设置 # self.play( Rotate(ellipsoid, angle=-135 * DEGREES, axis=UP), run_time=2 ) # 为椭球体添加旋转动画 # self.wait(2) # 等待2秒 # 运行此代码的命令为: manim -pql your_file.py EllipsoidScene # 不要删除下面的命令,以使运行按钮正常工作
%manim -qm -v WARNING EllipsoidScene
运行结果:
代码解释
-
导入库:代码开始时导入了
manim
包,这是一个用于创建数学动画的 Python 库。 -
类定义:
EllipsoidScene
继承自ThreeDScene
,是一个用于创建 3D 动画的场景类。
-
构造方法:
construct
方法是用于构建场景的主要方法,包含了所有的绘制和动画逻辑。
-
设置背景和椭球体参数:
- 背景颜色被设置为白色,椭球体的三个半径参数
a
,b
,c
定义了其形状和大小。
- 背景颜色被设置为白色,椭球体的三个半径参数
-
创建椭球体:
- 使用参数方程创建椭球体
ellipsoid
,在给定的参数范围内生成表面。u
和v
控制椭球体的各个方向。
- 使用参数方程创建椭球体
-
添加平行线:
- 在椭球体的表面上添加几条平行线,以增强视觉效果。
np.linspace
用于确定每条线的v
值。
- 在椭球体的表面上添加几条平行线,以增强视觉效果。
-
添加椭球体和坐标轴:
- 椭球体和黑色坐标轴被添加到场景中,并且为每个坐标轴添加了相应的标签(X、Y、Z)。
-
设置相机角度:
- 使用
set_camera_orientation
设置相机的角度,从特定的视角观察椭球体。
- 使用
-
注释和备用代码:
- 其中有几行代码被注释掉,可以通过解注释来执行动画或更改相机设置。
如果 a= b= c然后我们得到一个球体。
注意,我们只给出了以原点为中心的椭球的方程。显然椭球不必以原点为中心。然而,为了使本节的讨论更容易一些,我们选择以某种方式集中在原点“居中”的表面上。
2.圆锥体
这是圆锥体的方程 。
这是一个典型锥体的草图。
示例代码
from manim import * class ConeScene(ThreeDScene): def construct(self): # 设置背景颜色为白色 self.camera.background_color = WHITE # 设置圆锥体的参数 a, b, c = 1.5, 1.5, 1.5 # 这里我定义了一个适合的 c 值用于圆锥体 # 创建圆锥体,使用参数方程 cone = Surface( lambda u, v: np.array([ a * v * np.cos(u), # x 轴坐标 b * v * np.sin(u), # y 轴坐标 c * v # z 轴坐标 ]), u_range=[0, TAU], # u 的范围从 0 到 2π v_range=[1, -1], # v 的范围从 1 到 -1 (表示从尖端到底部) resolution=(24, 48), ) # 设置圆锥体的样式 cone.set_style(fill_color=(DARK_BROWN, PINK), fill_opacity=0.55, stroke_color=YELLOW) # 在圆锥体的表面添加平行线 for v in np.linspace(0, 1, 5): # 在 v 的范围内均匀分布5个线段 line = Line( start=np.array([a * 0 * np.cos(0), b * 0 * np.sin(0), c * 0]), # 尖端位置 end=np.array([a * v * np.cos(TAU), b * v * np.sin(TAU), c * v]) # 底部边缘位置 ) line.set_color(BLUE_E) # 设置线的颜色为蓝色 line.set_stroke(width=1) # 设置线宽 self.add(line) # 添加线到场景 # 将圆锥体添加到场景 self.add(cone) # 添加三维坐标轴 axes = ThreeDAxes().set_color(BLACK) self.add(axes) # 给坐标轴添加标签 x_label = MathTex("X").next_to(axes.x_axis.get_end(), RIGHT).set_color(BLACK) y_label = MathTex("Y").next_to(axes.y_axis.get_end(), UP).set_color(BLACK) z_label = MathTex("Z").next_to(axes.z_axis.get_end(), RIGHT).set_color(BLACK) self.add(x_label, y_label, z_label) # 添加标签到场景 # 旋转坐标轴 self.set_camera_orientation(phi=75 * DEGREES, theta=45 * DEGREES) # self.set_camera_orientation(pitch=75 * DEGREES, yaw=145 * DEGREES, roll=130 * DEGREES) # self.wait(1) # 等待一段时间(可选) # 动画效果:旋转圆锥体以获得更好的视角(可选) # self.play(Rotate(cone, angle=-135 * DEGREES, axis=UP), run_time=2) # self.wait(2) # 要运行该代码,请使用以下命令:manim -pql your_file.py ConeScene # 请勿删除下面的命令以确保运行按钮有效
%manim -qm -v WARNING ConeScene
运行结果:
现在,请注意,虽然我们称它为锥,但它更像是一个钟杯形状,而不是大多数人所说的锥。当然,钟形玻璃杯的上部和下部确实是我们通常认为的锥体。
这就带来了一个问题:如果我们真的只想要上半部分或下半部分(即传统意义上的圆锥体)怎么办?这个问题很容易回答。我们要做的就是解出给定的 z 的方程,如下所示
我们稍微化简了系数,使方程更容易处理。现在,我们知道平方根总是返回正数,所以我们可以看到将总是正的,所以对于上面的“锥”的上半部分,方程也是正的。同样,总是负的,所以这个方程只是上面“锥”的下半部分。
同时,注意这是一个沿z方向打开的圆锥的方程,设在。为了得到沿另一个轴打开的锥的方程我们需要做的就是对方程做一点修改。这将是我们将在本节中看到的其他表面的情况。在圆锥体的例子中,等号一侧的变量将决定圆锥体打开的轴。例如,一个沿x轴打开的圆锥体的方程,
对于下列大多数曲面,我们将不给出其他可能的公式。然而,我们将承认如何改变每个公式来改变表面的方向。
3.圆柱体
这是圆柱体的一般方程。
这是一个横截面为椭圆的圆柱体。如果a= b我们有一个圆柱体,它的横截面是圆。我们会更多地处理这些圆柱体而不是一般形式的圆柱体所以具有圆形截面的圆柱体的方程是,
这是一个典型的具有椭圆截面的圆柱体的草图。
圆柱体将位于与没有出现在方程中的变量对应的轴的中心。
注意不要把这个和圆搞混了。在二维空间中它是一个圆,但在三维空间中它是一个圆柱体。
示例代码
from manim import * class VerticalCylinderScene01(ThreeDScene): def construct(self): # 设置背景颜色为白色 self.camera.background_color = WHITE # 定义圆柱体的参数 radius = 1 # 圆柱的半径 height = 3 # 圆柱的高度 # 创建圆柱体,方向为向上(沿z轴) cylinder = Cylinder(radius=radius, height=height, direction=UL) cylinder.set_fill(BLUE_D, opacity=0.6) # 设置填充颜色和不透明度 cylinder.set_stroke(BLACK, width=2) # 设置边框颜色和边框宽度 # 将圆柱体添加到场景 self.add(cylinder) # 请勿删除下面的命令以确保运行按钮有效
%manim -qm -v WARNING VerticalCylinderScene01
运行结果:
4.单叶双曲面
这是单张双曲面的方程。
这是一个典型的单张双曲面的草图。前面带负号的变量将给出图形居中的轴。
接下来用manim实现一下该图像的绘制。
示例代码:
from manim import * class HyperboloidofOneSheetScene01(ThreeDScene): def construct(self): self.camera.background_color = WHITE # 设置参数 a, b, c = 0.8, 0.5, 1.1 # 双曲面的 semi-axis 长度 # 创建单叶双曲面 hyperboloid = Surface( lambda u, v: np.array([ a * np.cosh(v) * np.cos(u), # x = a * cosh(v) * cos(u) b * np.cosh(v) * np.sin(u), # y = b * cosh(v) * sin(u) c * v # z = c * v(线性变化) ]), u_range=[0, TAU], # u 从 0 到 2π v_range=[-2, 2], # v 的范围可以根据需要修改 resolution=(24, 48) # 网格分辨率 ) hyperboloid.set_style(fill_color=(BLUE, DARK_BROWN), fill_opacity=1, stroke_color=BLACK) # 在曲面上添加平行线 for v in np.linspace(-2, 2, 5): # 在双曲面表面添加平行线 line = Line( start=np.array([a * np.cosh(-2) * np.cos(0), b * np.cosh(-2) * np.sin(0), c * -2]), end=np.array([a * np.cosh(2) * np.cos(TAU), b * np.cosh(2) * np.sin(TAU), c * 2]) ) line.set_color(BLACK) line.set_stroke(width=0.5) self.add(line) # 将双曲面添加到场景中 self.add(hyperboloid) # 添加三维坐标轴 axes = ThreeDAxes().set_color(BLACK) self.add(axes) # 添加坐标轴标签 x_label = MathTex("X").next_to(axes.x_axis.get_end(), RIGHT).set_color(BLACK) y_label = MathTex("Y").next_to(axes.y_axis.get_end(), UP).set_color(BLACK) z_label = MathTex("Z").next_to(axes.z_axis.get_end(), RIGHT).set_color(BLACK) self.add(x_label, y_label, z_label) # 设置相机视角 self.set_camera_orientation(phi=75 * DEGREES, theta=45 * DEGREES) # 可选:为更好的视图旋转整个场景 # self.play(Rotate(hyperboloid, angle=-135 * DEGREES, axis=UP), run_time=2) # self.wait(2) # 运行此代码,请使用:manim -pql your_file.py HyperboloidofOneSheetScene # 不要移除以下命令以使运行按钮正常工作
%manim -qm -v WARNING HyperboloidofOneSheetScene01