NumPy特性
NumPy 是Python中用于科学计算的核心库,它提供了高效的多维数组对象ndarray,以及大量的数学函数来操作这些数组。
内侧菱形三十面体的顶点坐标计算和点积方法
下面用python来实现数学模型,正好最近考虑到了一个有趣的数学问题:有没有什么多面体,它的每个面都是凹多边形? 笔者在搜索 wikipedia 的过程中,发现了一个有趣的图形:内侧菱形三十面体 (medial rhombic triacontahedron),如下图所示:
对于构造内侧菱形三十面体,我们先选取二十四个顶点坐标如下:
通过坐标计算可以发现:
根据对称性,当我们选取 V17, V4, V11, V13 四个点的时候,可得其构成与之前全等的菱形。如此, 我们可以找到 30 个全等的菱形,为我们所需的三十个面。
python实现伪代码如下:
import numpy as np
# 常量定义
sqrt5 = np.sqrt(5)
C0 = 3 * (sqrt5 - 1) / 8
C1 = 3 * (sqrt5 + 1) / 8
# 顶点坐标生成 (24个顶点)
vertices = [
(0.75, 0, C1), # V0
(0.75, 0, -C1), # V1
(-0.75, 0, C1), # V2
(-0.75, 0, -C1), # V3
(C1, 0.75, 0), # V4
(C1, -0.75, 0), # V5
(-C1, 0.75, 0), # V6
(-C1, -0.75, 0), # V7
(0, C1, 0.75), # V8
(0, C1, -0.75), # V9
(0, -C1, 0.75), # V10
(0, -C1, -0.75), # V11
(C0, 0, 0.75), # V12
(C0, 0, -0.75), # V13
(-C0, 0, 0.75), # V14
(-C0, 0, -0.75), # V15
(0.75, C0, 0), # V16
(0.75, -C0, 0), # V17
(-0.75, C0, 0), # V18
(-0.75, -C0, 0), # V19
(0, 0.75, C0), # V20
(0, 0.75, -C0), # V21
(0, -0.75, C0), # V22
(0, -0.75, -C0), # V23
]
# 验证菱形面 V17, V4, V12, V10
def validate_rhombus():
v17 = np.array(vertices[17])
v4 = np.array(vertices[4])
v12 = np.array(vertices[12])
v10 = np.array(vertices[10])
# 计算四条边向量
edge1 = v4 - v17 # V17→V4
edge2 = v12 - v4 # V4→V12
edge3 = v10 - v12 # V12→V10
edge4 = v17 - v10 # V10→V17
# 验证平行性和模长
print("验证对边平行且等长:")
print(f"V17V4 与 V12V10 平行: {np.allclose(np.cross(edge1, edge3), [0,0,0])}")
print(f"模长: {np.linalg.norm(edge1):.4f} (理论值: {3*np.sqrt(3)/4:.4f})")
print(f"V4V12 与 V10V17 平行: {np.allclose(np.cross(edge2, edge4), [0,0,0])}")
print(f"模长: {np.linalg.norm(edge2):.4f} (理论值: {3*np.sqrt(3)/4:.4f})")
# 计算角度余弦
cos_angle1 = np.dot(edge1, edge4) / (np.linalg.norm(edge1) * np.linalg.norm(edge4))
cos_angle2 = np.dot(edge1, edge2) / (np.linalg.norm(edge1) * np.linalg.norm(edge2))
print(f"\n验证凹角:")
print(f"cos(∠V4V17V10) = {cos_angle1:.4f} (理论值: {-sqrt5/3:.4f})")
print(f"cos(∠V17V4V12) = {cos_angle2:.4f} (理论值: {sqrt5/3:.4f})")
validate_rhombus()
# 定义30个菱形面 (示例定义部分面)
faces = [
[17, 4, 12, 10], # 第一个菱形
[4, 12, 10, 17], # 对称面
[16, 5, 13, 11], # 其他面
[5, 13, 11, 16],
[18, 7, 14, 22],
[7, 14, 22, 18],
# 可根据对称性补充完整30个面...
]
另外最近看到了 Branko Grünbaum 和 G. C. Shephard 在 1998 年的论文《Isohedra with Nonconvex Faces》中给出了一些例子,这其中有些结构十分精巧,可以说如果不特别去构造几乎难以想 象。在本文中我们将引用其中一些例子,分享一下这些结构的顶点坐标和平面方程如何计算。一些 最常见的例子 (Figure 7 in Branko) 如图所示:
如果要计算这些特定多面体的顶点坐标,我们将引用 APPENDIX 当中的一些记号和术语,并 且对于一两个特殊图形作出距离。在每一种情形中,我们都从一个正多面体 P(四面体、八面体或 二十面体)出发,其顶点记为 Di,以及其对偶多面体 P ′(四面体、立方体或十二面体),其顶点记 为 Ej。于是,根据图中所示的参数 a, b, c,面 F 的五个顶点可以按如下顺序表示:
其中 d 与 e 是 a, b, c 的函数,选定以使这五个 (∗) 当中的点共面。不同情形下的具体表达将在 下文给出。显然,对参数做统一缩放对应于相似多面体;因此这些参数可以理解为同类多面体空间 中某种给定拓扑类型的“等面体空间”中的齐次坐标。 第一类问题是如下的这类多面体,它们看起来很夸张,但是顶点坐标是容易表示的:
我们可以取 P,也就是这些多面体的母体作为具有以下十二个顶点坐标的二十面体:
然后其对偶的十二面体 P ′ 的二十个顶点坐标为:
这里关于 d, e 的计算相当复杂,我们仅给出一个 d 的式子:
第二类问题当中,图形可能更简单,它们都来自于一个正四面体:其中,P 是一个四面体,其
所有顶点为: 当中带有偶数个负号的点,表示正四面体 P 的顶点。
而对偶四面体 P ′ 的顶点坐标为:
当中带有奇数个负号的点。
在公式 (∗) 中我们取:
由此即可类似地得到 d 和 e 的计算:
一个特别有趣的图形是如下的 12 面体,其中每个五边形都是一个由正五边形向下 “压缩”后的结果
这个图形是完全被嵌入在立方体(cube)A1A2A3A4 − A5A6A7A8 当中的,实际上如果我们设 这个立方体的外面 8 个顶点为:
则其内部的凹陷顶点坐标可以写作:
我们再提出一个有趣的例子:
这个图形的所有顶点位于一个正八面体上 (octahedron), 其 6 个顶点坐标为:
和它的坐标排列,这样它的对偶多面体 P ′ 就可以取为:
在(*)中我们取
import numpy as np
# ================== 通用工具函数 ==================
def normalize(v):
return v / np.linalg.norm(v)
# ================== 第一类:二十面体衍生结构 ==================
def icosidodecahedron_case(a=1.0, b=0.5, c=0.3):
tau = (1 + np.sqrt(5)) / 2
# 定义原始二十面体顶点
D1 = np.array([0, tau, 1])
D2 = np.array([tau, 1, 0])
# 定义对偶十二面体顶点
E1 = np.array([1, tau**2, 0])
E2 = np.array([tau, tau, tau])
E3 = np.array([0, 1, tau**2])
# 计算d参数(共面条件)
numerator = a**2*c + 3*a*b*c + b**2*c - c**3 - a*c**2 + 2*a*b**2 + tau*(2*a**2*b + 2*a*b**2 + 4*a*b*c + 2*b**2*c - 2*c**3)
denominator = a*c + 2*b*c - 2*c**2 + tau*(2*a*b + b*c - c**2)
d = numerator / denominator
# 生成五个顶点
X1 = a*D1 + b*E1 + c*E2
X2 = a*D2 + b*E2 + c*E1
X3 = a*D1 + b*E2 + c*E3
Z1 = d*D1
# 计算e参数(Y2顶点)
Y2 = (a**2*c - 2*a*b*c + 2*a*c**2 - b**2*c + c**3 - 2*a**2*b - 2*a*b**2) / (c**2 - a*c - b*c - 2*a*b) * E2
return [X1, X2, X3, Y2, Z1]
# ================== 第二类:四面体衍生结构 ==================
def tetrahedral_case(a=0.8, b=0.6, c=0.4):
# 正四面体顶点(偶数负号)
D1 = np.array([1, 1, 1])
D2 = np.array([-1, -1, 1])
# 对偶四面体顶点(奇数负号)
E1 = np.array([-1, 1, 1])
E2 = np.array([1, -1, 1])
E3 = np.array([1, 1, -1])
# 计算d和e参数
numerator = a**2*c - 2*a*b*c + 2*a*c**2 - b**2*c + c**3 - 2*a**2*b - 2*a*b**2
d = numerator / (3*c**2 + a*c - 3*b*c - 2*a*b)
e = numerator / (c**2 - a*c - b*c - 2*a*b)
# 生成五个顶点
X1 = a*D1 + b*E1 + c*E2
X2 = a*D2 + b*E2 + c*E1
X3 = a*D1 + b*E2 + c*E3
Z1 = d*D1
Y2 = e*E2
return [X1, X2, X3, Y2, Z1]
# ================== 第三类:立方体内嵌凹十二面体 ==================
def cubic_pentagonal_dodecahedron():
alpha = (np.sqrt(5)-1)/2
# 立方体顶点
A = [np.array(v) for v in [
(1,1,1), (-1,1,1), (-1,-1,1), (1,-1,1),
(1,1,-1), (-1,1,-1), (-1,-1,-1), (1,-1,-1)
]]
# 内凹顶点
B = [np.array(v) for v in [
(alpha**2, alpha, 0), (alpha**2, -alpha, 0),
(0, alpha**2, alpha), (0, alpha**2, -alpha),
(alpha, 0, alpha**2), (-alpha, 0, alpha**2),
(-alpha**2, alpha, 0), (-alpha**2, -alpha, 0),
(0, -alpha**2, alpha), (0, -alpha**2, -alpha),
(alpha, 0, -alpha**2), (-alpha, 0, -alpha**2)
]]
# 定义五边形面(示例)
faces = [
[0, 8, 1, 9, 4], # A1-B9-B2-A2-B5
[0, 2, 10, 3, 8], # A1-B3-B4-A2-B9
# 可根据对称性补充其他面...
]
return A + B, faces
最后我们在开始提到的图形当中提出一个小问题,如果需要计算如下的图形的各个顶点坐标, 应当如何标注?
绘制图片代码如下:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
# 3D可视化
def plot_polyhedron():
fig = plt.figure(figsize=(12, 10))
ax = fig.add_subplot(111, projection='3d')
# 绘制顶点
xs, ys, zs = zip(*vertices)
ax.scatter(xs, ys, zs, color='red', s=50)
# 绘制面片
for face in faces:
verts = [vertices[i] for i in face]
ax.add_collection3d(Poly3DCollection([verts], alpha=0.7, edgecolor='k', linewidths=1, facecolor='cyan'))
# 设置坐标轴
max_val = max(max(abs(x), abs(y), abs(z)) for x, y, z in vertices) * 1.2
ax.set_xlim([-max_val, max_val])
ax.set_ylim([-max_val, max_val])
ax.set_zlim([-max_val, max_val])
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('Medial Rhombic Triacontahedron (部分面展示)')
# 视角调整
ax.view_init(elev=25, azim=45)
plt.tight_layout()
plt.show()
导出为STL文件用于3D打印:
from stl import mesh
def export_stl():
poly = mesh.Mesh(np.zeros(len(faces), dtype=mesh.Mesh.dtype))
for i, f in enumerate(faces):
poly.vectors[i] = [vertices[idx] for idx in f]
poly.save('medial_rhombic.stl')
通过接入deepseek,对问题进行分析,测试大模型的分析与解决问题的能力。摘抄部分结果:
多面体类型 | 关键数学工具 | DeepSeek实现重点 |
---|---|---|
内侧菱形三十面体 | 黄金比例τ、向量平行性验证 | 顶点坐标精确计算、凹角可视化 |
二十面体衍生结构 | 参数化共面条件(d/e公式) | 复杂分式运算、对称性生成 |
立方体内嵌十二面体 | 五边形凹陷拓扑、平面方程 | 自动内凹顶点生成、非凸面片渲染 |
对后续编程代码的启示:
-
自动化面片生成
-
基于图论自动识别多面体面片拓扑
-
-
物理特性分析
-
集成有限元分析(如应力分布计算)
-
-
教育应用开发
-
构建交互式几何学习工具(如Jupyter插件)
-
修改历史
2019-05-08
1.在帖子中增加第三类立方体内嵌凹十二面体的代码;
2.修改帖子中denominator 参数的计算方式
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2020-11-20
1.帖子中的代码引入matplotlib库,增加3D可视化代码,进行简单展示。
2.解决anaconda 启动非常慢问题
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2022-07-05
1.利用NumPy1.21版本的特性,引入np.linalg.lstsq
的rcond
参数,优化最小二乘解的稳定性。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2024-02-26
1.通过借鉴《平面设计理论》,修改代码使用半透明青色面片显示非凸面。
2.增加引入STL,可以将结果导出为STL文件用于3D打印
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2025-04-19
使用deepseek对内容代码进行优化,并测试deepseek的性能。并保留对未来的启示,待后续有新思路时继续更新帖子