STLファイルは3DプリンタやCAEシミュレーションで扱う3Dモデルとして工学系のエンジニアに多用されています。ここではSTLファイルをPythonとPyVistaで開いて情報を取得したり編集する方法を紹介します。
こんにちは。wat(@watlablog)です。何かと便利なSTLをPython×PyVistaで扱う方法を紹介します!
STLファイルの概要
STLファイルとは?
STL(Standard Tessellation Language)とは、3Dの形状データを保存するためのファイルフォーマットです。Stereolithography(光造形法)が真の語源のようです。
今ではほとんどのCADソフトがSTLファイルをサポートしており、ソフト間の移動にSTLファイルに変換するという事もよくやります。
世間一般(?)では3Dプリンタ用のデータとして頻繁に利用されています。
他にも、製品の3D形状を使って強度や振動といった構造解析をしたり、製品表面の風流れや熱の伝わりを調べたりといったCAEシミュレーションにもSTLファイルは利用されています。
STLファイルはASCII形式とバイナリ形式があり、基本は右ねじの法則にしたがって配置された三角形サーフェスで構成されています。
くわしくはWikipediaがわかりやすいのでリンクを貼っておきます。
Wikipedia:Standard Triangulated Language
STLをプログラムで操作したい理由
3D形状の座標変換をしたい
現在ではフリーでもSTLファイルを操作できるソフトが沢山出ていますが、プログラムで操作できるようになると自動化が可能です。
STLファイルは上記の通り大変便利なファイルフォーマットであり、色々なモデルを組み合わせて使う事が多くあります。
そのため各モデルファイルを数式に従って簡単に座標変換可能なプログラムができれば、業務の生産性が上がりそうです。
3D形状を修正したい
上記座標変換のニーズと近いですが、ちょっとした形状修正もプログラムを使ってできると、これも数式ベースで点列を操作できる事になり生産性というか業務の品質が向上しそうです。
3Dモデルの形状修正ってソフトの熟練度もありますが、結構骨が折れるんですよね…。
3D形状をゼロから作りたい
修正以外にも、プログラムでSTLファイルを操作する事ができれば、1から…いやゼロから形状を作成する事も可能となるでしょう。
すると製品の粗モデルを数式ベースで作成し、上記シミュレーションと組み合わせて完全自動化、最適化ループを回すといった事もできそうです。これは新たな価値創造として面白そう。
…今回はそこまでやりませんが、まずはPyVistaをインストールする所と、簡単なSTLファイルの操作を学びたいと思います。
PyVistaの概要とインストール
PyVistaとは?
PyVistaについて詳しくは公式ドキュメントに記載されています。まずは皆様にとって得体の知れない筆者が書く当ブログではなく、1次情報を参照するのは重要だと思います。
公式ドキュメント:https://pyvista-doc.readthedocs.io/ja/latest/index.html
PyVistaは...
PyVista
"人間のためのVTK": Visualization Toolkit (VTK) の高レベルAPI
空間データセットのメッシュデータ構造とフィルタリング方法
大規模/複雑なデータジオメトリ用にシンプルかつ構築された3 Dプロット
…STLだけでなく様々なデータを可視化する強力なツールのようです。サンプルをみているだけで楽しい。
PyVistaは公式ドキュメントも充実しているので助かります。ただ、内容が膨大であるため、当ブログでは僕が使う所に絞って備忘録を残していきたいと思います。
PyVistaをインストールする
PyVistaはPyPIにあるので、pip installが可能です。今回僕は以下のコマンドでPython3にインストールしました。
1 2 3 4 5 |
#Windows python -m pip install pyvista #Mac pip3 install pyvista |
PyVistaでSTLを扱うPythonコード
3Dモデルの用意
今回僕はBlenderを使って以下のような3Dモデルを作成し、STLとしてエクスポートしました。
BlenderもPyVistaもフォロワーさんから教えてもらったので感謝!
モデルを表示させるコード
3Dモデルをただ表示させるだけなら、以下のコードで可能です。非常に簡単でわかりやすい。.readはSTL以外のファイルフォーマットにも対応しているとのこと。すごい。
1 2 3 4 5 |
import pyvista as pv filename = 'sample.stl' mesh = pv.read(filename) cpos = mesh.plot() |
以下のように表示されます。
エッジを表示させる
STLは三角形面の組み合わせで構成されています。エッジ(辺)を表示させるにはplotに以下のパラメータを設定します。
1 |
cpos = mesh.plot(show_edges=True) |
エッジを可視化する事でSTLの精度(どのくらい細かく分割されているのか)を確認する事ができます。単純形状の場合は面の数が少なくても良いのがSTLの強み。エッジを確認して無駄が無いか確認しましょう。
モデルをぐりぐり動かす
plotはマウスを使ってぐりぐりと動かす事が出来ます。以下の動画は今回のモデルを動かしてみた結果です。ぬるぬる動くので気持ち良いですよ。
拡大縮小、回転、平行移動(パン)の他に、wキーでワイヤーフレーム表示、sキーでサーフェス表示といった切替も可能です。詳しくは以下の公式ドキュメントをご覧下さい。
公式ドキュメント:https://pyvista-doc.readthedocs.io/ja/latest/plotting/plotting.html
点の情報を取得するコード
.pointsを使う事でSTLの頂点(Node:ノード)のXYZ座標値を取得する事が出来ます。
1 2 |
points = mesh.points print(points) |
ndarray形式なのでそのまま行列演算も出来そうです。座標変換はどうやら簡単にできそうですね。
1 2 3 4 5 6 7 8 9 10 11 12 |
[[ 0. 1. 2.1903157 ] [-1. 1. 1. ] [-1. -1. 1. ] [ 0. -1. 2.1903157 ] [ 0. -1. 0.19031572] [-1. -1. -1. ] [-1. 1. -1. ] [ 0. 1. 0.19031572] [ 1. 1. -1. ] [ 1. -1. -1. ] [ 1. 1. 1. ] [ 1. -1. 1. ]] |
面の情報を取得するコード
面の情報は.facesで取得する。面の情報とは、三角形の3つのノードセットを意味している。単純に.facesのみだと区切りの無い数値の羅列になってしまうので、下コードのようにreshapeして取得する。
1 2 |
faces = mesh.faces.reshape(-1, 4)[:, 1:] # 1つの面(=3つの頂点セット)でreshapeしている。 print(faces) |
こんな感じで面を構成するノードセットを取得する事ができる。STL以外のファイルの場合はreshapeのサイズを変えれば良いと思う。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[[ 0 1 2] [ 0 2 3] [ 4 3 2] [ 4 2 5] [ 5 2 1] [ 5 1 6] [ 7 8 9] [ 7 9 4] [ 8 10 11] [ 8 11 9] [ 7 0 10] [ 7 10 8] [ 6 1 0] [ 6 0 7] [ 6 7 4] [ 6 4 5] [ 9 11 3] [ 9 3 4] [10 0 3] |
その他モデルの情報を取得するコード
他にも点、面、重心といった情報はよく使いそうなのでメモ。
1 2 3 |
n_points = mesh.n_points #点の数 n_faces = mesh.n_faces #面の数 center = mesh.center #重心 |
まとめ
本記事ではSTLファイルの概要と、STLをプログラムで操作すると出来そうな事を紹介しました。
また、PythonでSTLを扱うには、PyVistaを使うと良さそうという事がわかりました。
ここでは実際にPyVistaをインストールする所から、簡単なモデル表示、動かし方、点と面の情報を取得する方法を試してみました。
公式ドキュメントにはさらに色々な機能が沢山載っていましたが、当ブログではそれらを組み合わせてやりたい事を実現していくような記事を書いていきたいです。
3D形状までもPythonで扱うライブラリがあるとは!かなり興味が出てきました!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!
この方法で試してみたところ
[[-413.17615 -133.78394 3652.5256 ]
[-419.8834 -118.59123 3643.7488 ]
[-405.6976 -124.95581 3657.6584 ]
…
[ 286.8586 -152.18904 3223.3042 ]
[ 280.05627 -151.37302 3227.6575 ]
[ 279.7713 -150.9331 3254.9792 ]]
のように省略されて表示されます。
対処法を教えていただけないでしょうか。
ご訪問ありがとうございます。
データ量が多い場合は出力が省略されてしまいます。
for i in range(len(points)):
print(points[i])
のように1行ずつ出力する方法であれば全行確認することができます。