如何在Matplotlib中移除3D平面与悬链面相交的圆形区域?
解决Matplotlib 3D绘图中平面与悬链面相交区域的遮挡问题
要实现平面不遮挡悬链面开口的效果,我们可以直接硬编码悬链面与平面的交线(圆形),然后在平面网格中排除圆内区域,生成带镂空的平面。
修改后的完整代码
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 悬链面参数方程 def catenoid(u, v, a=1): x = a * np.cosh(u/a) * np.cos(v) y = a * np.cosh(u/a) * np.sin(v) z = u return x, y, z # 生成参数网格 u = np.linspace(-2, 2, 100) v = np.linspace(0, 2 * np.pi, 100) u, v = np.meshgrid(u, v) # 创建绘图对象 fig = plt.figure(figsize=(12, 12)) ax = fig.add_subplot(111, projection="3d", computed_zorder=False) ax.set_box_aspect(aspect=(6, 4, 3)) ax.set_axis_off() # 绘制第一个悬链面 x1, y1, z1 = catenoid(u, v) surf1 = ax.plot_surface(x1, y1, z1, cmap='viridis', edgecolor='grey', alpha=0.5, vmin=-2, vmax=2) # 绘制偏移后的第二个悬链面 x2, y2, z2 = catenoid(u, v) x2_offset = x2 + 8 surf2 = ax.plot_surface(x2_offset, y2, z2, cmap='viridis', edgecolor='grey', alpha=0.5, vmin=-2, vmax=2) # 计算悬链面在z=±2处的圆形截面半径 a = 1 r = a * np.cosh(2/a) # 生成带镂空的底部平面(z=-2) xx, yy = np.meshgrid(np.linspace(-5, 13, 100), np.linspace(-5, 5, 100)) zz = np.full_like(xx, -2) # 掩码:排除两个悬链面对应的圆内区域 mask1 = (xx**2 + yy**2) > r**2 mask2 = ((xx - 8)**2 + yy**2) > r**2 mask_bottom = mask1 & mask2 ax.plot_surface(xx[mask_bottom], yy[mask_bottom], zz[mask_bottom], zorder=-1, alpha=0.5, cmap='viridis', edgecolor='none', vmin=-2, vmax=2) # 生成带镂空的顶部平面(z=2) zz = np.full_like(xx, 2) mask_top = mask1 & mask2 ax.plot_surface(xx[mask_top], yy[mask_top], zz[mask_top], zorder=1, alpha=0.5, cmap='viridis', edgecolor='none', vmin=-2, vmax=2) plt.show()
关键说明
- 悬链面在
z=±2处的截面是标准圆形,半径由参数方程推导为r = a*cosh(2/a),此处a=1,半径约为3.762 - 通过创建布尔掩码,过滤掉平面网格中两个悬链面圆形区域内的点,只保留圆外部分进行绘制
- 最终平面会在悬链面开口位置形成圆形镂空,完全露出悬链面的结构,符合预期视觉效果
内容的提问来源于stack exchange,提问作者guckmalmensch
相关产品推荐
相关产品推荐

