# 檢視 3D 模型檔案

OBJ 檔案為例，它可以使用純文字編輯器開啟，當中會包含頂點座標與三角面的頂點索引，例如 caterpillar.obj，就包含了以下的資料：

``````# Exported from 3D Builder
o Object.1
v 32.023987 34.396461 42.497063
v 32.023983 32.002457 43.037056
v 32.023987 34.166458 43.651062
v 20.774000 34.396450 42.497063
v 20.774000 34.166451 43.651062
v 20.774002 32.002453 43.037060
v 20.774002 32.202454 41.829056
v 21.527994 32.202454 41.829056
v -17.877909 -18.721634 40.853043
...略

f 2 1 3
f 1 4 3
f 5 3 4
f 5 4 6
f 7 6 4
f 4 14 7
f 15 7 14
f 23 15 14
f 14 24 23
f 23 24 26
f 20114 26 24
f 24 20113 20114
...略
``````

``````import numpy as np
import matplotlib.pyplot as plt

obj = np.fromregex('caterpillar.obj',
r'([vf]) ([-\d.]+) ([-\d.]+) ([-\d.]+)',
dtype=np.str)
``````

``````t = obj[:,0]
# v 的個數
vleng = obj[:,0][t == 'v'].size

v = obj[0:vleng,1:].astype(np.float)
f = obj[vleng:,1:].astype(np.int) - 1
``````

``````# 接受 Axes3D 實例
def set_axis_cube(ax):
# 目前的軸最大最小值
xlim = ax.get_xlim()
ylim = ax.get_ylim()
zlim = ax.get_zlim()

# 計算繪製需要的範圍
r = 0.5 * max([
abs(xlim[1] - xlim[0]),
abs(ylim[1] - ylim[0]),
abs(zlim[1] - zlim[0])]
)

xmid = np.mean(xlim)
ymid = np.mean(ylim)
zmid = np.mean(zlim)

# 以資料中點，r 為範圍重新設定軸最大最小值
ax.set_xlim([xmid - r, xmid + r])
ax.set_ylim([ymid - r, ymid + r])
ax.set_zlim([zmid - r, zmid + r])
``````

``````import numpy as np
import matplotlib.pyplot as plt

def set_axis_cube(ax):
xlim = ax.get_xlim3d()
ylim = ax.get_ylim3d()
zlim = ax.get_zlim3d()

r = 0.5 * max([
abs(xlim[1] - xlim[0]),
abs(ylim[1] - ylim[0]),
abs(zlim[1] - zlim[0])]
)

xmid = np.mean(xlim)
ymid = np.mean(ylim)
zmid = np.mean(zlim)

ax.set_xlim3d([xmid - r, xmid + r])
ax.set_ylim3d([ymid - r, ymid + r])
ax.set_zlim3d([zmid - r, zmid + r])

obj = np.fromregex('caterpillar.obj',
r'([vf]) ([-\d.]+) ([-\d.]+) ([-\d.]+)',
dtype=np.str)
t = obj[:,0]
vleng = obj[:,0][t == 'v'].size

v = obj[0:vleng,1:].astype(np.float)
f = obj[vleng:,1:].astype(np.int) - 1

vx = v[:,0]
vy = v[:,1]
vz = v[:,2]

ax = plt.axes(projection='3d')
ax.plot_trisurf(vx, vy, vz, triangles = f)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
set_axis_cube(ax)

plt.show()
``````

``````import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from stl.mesh import Mesh

# 修改一下 xlim、ylim 與 zlim 的取得方式
def set_axis_cube(ax, stl):
x = stl.vectors[:,0,0]
y = stl.vectors[:,0,1]
z = stl.vectors[:,0,2]

xlim = [x.min(), x.max()]
ylim = [y.min(), y.max()]
zlim = [z.min(), z.max()]

r = 0.5 * max([
abs(xlim[1] - xlim[0]),
abs(ylim[1] - ylim[0]),
abs(zlim[1] - zlim[0])]
)

xmid = np.mean(xlim)
ymid = np.mean(ylim)
zmid = np.mean(zlim)

ax.set_xlim([xmid - r, xmid + r])
ax.set_ylim([ymid - r, ymid + r])
ax.set_zlim([zmid - r, zmid + r])

# 讀取 STL
stl = Mesh.from_file('caterpillar.stl')

ax = plt.axes(projection='3d')
# stl.vectors 就是各個三角面的頂點組成之陣列
# 可直接搭配 Poly3DCollection
Poly3DCollection(stl.vectors,
linewidth=0.1,
facecolor='white',
edgecolor='black'
)
)

ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
set_axis_cube(ax, stl)

plt.show()
``````