第2关:曲面三角剖分
任务描述
本关任务:编写一个能绘制三维曲面的程序。
相关知识
为了完成本关任务,你需要掌握:1.如何三角剖分图形;2.绘制莫比乌斯带。
- 适用场景:立体图视觉上层次分明色彩鲜艳,具有很强的视觉冲击力,让观看的人驻景时间长,留下深刻的印象。
曲面三角剖分
在某些应用的场景中,之前那些些要求均匀采样的网格数据显得太过严格且不太容易实现。这时就可以使用三角剖分图形了。
def f(x, y):
return np.sin(np.sqrt(x ** 2 + y ** 2))
theta = 2 * np.pi * np.random.random(1000)
r = 6 * np.random.random(1000)
x = np.ravel(r * np.sin(theta))
y = np.ravel(r * np.cos(theta))
z = f(x, y)
ax = plt.axes(projection='3d')
ax.scatter(x, y, z, c=z, cmap='viridis', linewidth=0.5)
plt.show()
可以看到图形中还有许多地方需要修补,这些工作可以由ax.plot_trisurf
函数完成。它首先找到一组所有点都连接起来的三角形,然后用这些三角形创建曲面。
ax = plt.axes(projection='3d')
ax.plot_trisurf(x, y, z,cmap='viridis', edgecolor='none');
虽然结果没有之前用均匀网格画的图完美,但是这种三角剖分方法很灵活,可以创建各种有趣的三维图。
莫比乌斯带
莫比乌斯带是把一根纸条扭转 180
度后,再把两头粘起来做成的纸带圈。从拓扑学的角度看,莫比乌斯带非常神奇,因为它总共只有一个面!
接下来让我们用matplotlib
的三维功能来画一条莫比乌斯带。绘制的关键是想出它的绘图参数:由于它是一条二维带,因此需要两个内在维度。让我们把一维度定义为θ
,取值范围为0~2 π
;另一个维度是w
,取值范围是-1~1
,表示莫比乌斯带的宽度:
theta = np.linspace(0, 2 * np.pi, 30)
w = np.linspace(-0.25, 0.25, 8)
w, theta = np.meshgrid(w, theta)
有了参数之后,我们必须确定带上每个点的直角坐标 ( x
, y
, z
)。 仔细思考一下,我们可能会找到两种旋转关系:一种是圆圈绕着圆心旋转(角度用 θ
定义),另一种是莫比乌斯带在自己的坐标轴上旋转(角度用 Φ
定义)。因此,对于一条莫比乌斯带,我们必然会有环的一半扭转 180
度,即 Δ Φ = Δ θ / 2
。
phi = 0.5 * theta
现在用我们的三角学知识将极坐标转换成三维直角坐标。定义每个点到中心的距离(半径)r
,那么直角坐标 (z
,y
,z
) 就是:
r = 1 + w * np.cos(phi)
x = np.ravel(r * np.cos(theta))
y = np.ravel(r * np.sin(theta))
z = np.ravel(w * np.sin(phi))
最后,要画出莫比乌斯带,还必须确保三角剖分是正确的。最好的实现方法就是首先用基本参数化方法定义三角剖分,然后用Matplotlib
将这个三角剖分映射到莫比乌斯带的三维空间里,这样就可以画出图形:
from matplotlib.tri import Triangulation
tri = Triangulation(np.ravel(w), np.ravel(theta))
ax = plt.axes(projection='3d')
ax.plot_trisurf(x, y, z, triangles=tri.triangles,
cmap='viridis', linewidths=0.2);
ax.set_xlim(-1, 1); ax.set_ylim(-1, 1); ax.set_zlim(-1, 1);
编程要求
本关的编程任务是补全右侧上部代码编辑区内的相应代码,根据输入数据x、y
计算z
坐标值,计算方式为np.sin(-x * y)
。再绘制曲面图并设置颜色条为jet
、线宽为0.2
,具体可视化要求如下:
-
图形的
figsize
为(10, 10)
; -
文件名为
Task2/img/T1.png
; -
具体要求请参见后续测试样例。
请先仔细阅读右侧上部代码编辑区内给出的代码框架,再开始你的编程工作! ####测试说明 平台会对你编写的代码进行测试,对比你输出的数值与实际正确的数值,只有所有数据全部计算正确才能进入下一关。
测试输入:
无测试输入
预期输出:你的答案与正确答案一致
开始你的任务吧,祝你成功!
import matplotlib
matplotlib.use("Agg")
import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def student(x,y):
# ********* Begin *********#
fig=plt.figure(figsize=(10,10))
ax = plt.axes(projection='3d')
z=np.sin(-x * y)
ax.plot_trisurf(x, y, z,cmap='jet', edgecolor='none');
plt.savefig('Task2/img/T1.png')
plt.show()
# ********* End *********#