Python/PyVistaでSTLモデルを座標変換してみた

  • このエントリーをはてなブックマークに追加

PyVistaを使えばSTLファイルを簡単に表示したり情報を取得したりする事ができるとわかりました。ここでは取得したデータを加工してみます。まずは座標変換として拡大・縮小、平行移動、回転移動をPythonで実装してみます。

こんにちは。wat(@watlablog)です。ここではPythonとPyVistaを駆使してSTLファイルの座標変換をやってみます!

3D座標変換の概要と種類

座標変換の種類

拡大・縮小

ここでは今回実装する座標変換のイメージ図を示します。まずは拡大縮小から。

3D形状の拡大・縮小とは、下図のような変形の事です。3軸方向に倍率をかけてあげれば達成できるため、非常に簡単な変形です。

拡大・縮小の図

3軸の倍率、すなわちスケールファクターを\(S\)とすると、\(xyz\)座標値に対して各スケールファクターとのアダマール積をとれば良いです(行列積の方法の方が一般的かもですが)。

\[ \begin{bmatrix} {x}'\\ {y}'\\ {z}' \end{bmatrix} = \begin{bmatrix} S_{x}\\ S_{y}\\ S_{z} \end{bmatrix} \circ \begin{bmatrix} x\\ y\\ z \end{bmatrix} \]

※アダマール積とは、行列の順番に則って積を演算するのではなく、行列の対応している位置同士で積をとる方法。Numpyでそのまま「*」を使ってやるのがアダマール積、np.dot()で演算するのが行列積です。

平行移動

平行移動はもっと簡単かも知れません。以下の図のように一様にずらすだけです。

平行移動の図

平行移動も移動量\(T\)を\(xyz\)座標値毎にそれぞれ定義し、単純に足すだけで十分です(こちらも行列積の方法もありますが、今回はこの方法で)。

\[ \begin{bmatrix} {x}'\\ {y}'\\ {z}' \end{bmatrix} = \begin{bmatrix} T_{x}\\ T_{y}\\ T_{z} \end{bmatrix} + \begin{bmatrix} x\\ y\\ z \end{bmatrix} \]

回転移動

回転移動だけはちょっとやっかいですが、イメージ図は下図になります。基本は原点周りで回転させる事を前提とします。

回転の図

回転移動の場合は以下のように\(R_{x},R_{y},R_{z}\)と回転行列をそれぞれ定義した方がやりやすいです。

\[ R_{x}=\begin{bmatrix} 1&0&0\\ 0&\cos\theta_{x}&-\sin\theta_{x}\\ 0&\sin\theta_{x}&\cos\theta_{x} \end{bmatrix}, R_{y}=\begin{bmatrix} \cos\theta_{y}&0&\sin\theta_{y}\\ 0&1&0\\ -\sin\theta_{y}&0&\cos\theta_{y} \end{bmatrix}, R_{z}=\begin{bmatrix} \cos\theta_{z}&-\sin\theta_{z}&0\\ \sin\theta_{z}&\cos\theta_{z}&0\\ 0&0&1 \end{bmatrix} \]

定義した回転行列を各点の\(xyz\)座標に対し、行列式で以下のように計算すると、回転させる事が出来ます。但し、この方法は原点周りのみです。任意点周りの場合は予め原点に平行移動させ、回転させてからまた逆の平行移動をさせる方法をとるか、予め回転行列に平行移動分を加味しておくかです。

\[ \begin{bmatrix} {x}'\\ {y}'\\ {z}' \end{bmatrix} = \rm{R_{x}}\rm{R_{y}}\rm{R_{z}} \begin{bmatrix} x\\ y\\ z \end{bmatrix} \]

座標変換には他にもアフィン変換や射影変換といった様々な手法がありますが、今回はこの3つをPythonで実装していきます。

PythonでSTLの座標変換をするコード

PyVistaを使う

STLファイルの取り扱いにはPyVistaを使います。PyVistaについては、以下の記事にまとめましたので参照下さい。

PyVistaをインストールしてPythonでSTLを扱う備忘録

拡大・縮小を行うコード

まずは拡大・縮小を行うコードです。

以下のコードはdef magnification()で拡大・縮小の操作を関数化しています。引数はSTLの点情報(mesh.pointsで取得するもの)と、各方向の倍率です。

今回はモデルを表示させずにpv.save_meshio()を使ってSTLを保存する所まで記載しています。今回はy方向のみを2倍にしてみます。

上記説明で行列積を用いなかったのはNumpyのスライスを使って各成分毎に操作したかったからです(もっと効率良い書き方ありそうですが)。

以下が変換前(before)と変換後(after)です。見事STLモデルのy方向のみが大きくなりました。

STLをy方向のみ拡大した結果

平行移動を行うコード

以下が平行移動を行うコードです。

こちらも上記で行列積を用いなかった理由はNumpyスライスを使いたかったからという理由だけです。やり方は拡大・縮小の時と同じですね。

今回はx方向にのみ100だけずらしてみましょう。

以下が結果です。見事xだけ100ずれました(軸に着目して下さい)。しかし、平行移動なのに対比物がないのでよくわかりませんね。

STLの平行移動を行った結果

以下が点座標print文の結果です。移動前と移動後を比べると、こちらであれば確かに意図した平行移動がされているという事がわかると思います。

回転移動を行うコード

任意点周りの回転を行うコードを以下に示します。原点周りでは無いので、先ほどの平行移動を行う関数と組み合わせています。

各点毎に回転させるためにfor文を使って行列積を行っている所が苦肉の策なのですが、for文を使わないで書くにはどうしたら良いのだろう??
(「Pythonでfor書いたら負け」という言葉があるようです…。)

今回はx軸のみを90度回転させています。

入力は度ですが、計算時はラジアンに直しています。

関数の引数にcenterがありますが、こちらが任意の回転中心の座標です。
今はmesh.centerでモデルの重心を入れています。そのため、回転移動後でも重心は変わりません。

以下が結果です。こちらも意図通りにx軸で90度回転させる事が出来ました。

STLの回転を行った結果

おまけ:結果表示のコード

先ほどまででbefore, afterの図を載せていましたが、PyVistaはmatplotlibのような感覚でsubplotを作って複数モデルを一度に表示させる事が可能です。

以下にコードを載せておきますので、参考までに。

といっても、公式(https://docs.pyvista.org/examples/02-plot/multi-window.html)のページに記載のものをいじっただけです。是非公式もご覧下さい。

まとめ

本記事ではSTLファイルのような3D形状を有するモデルの座標変換の概要を学び、その方法を記録しました。

また、PyVistaを使う事で簡単にSTLファイルの座標変換をするPythonコードが書けました。

STLファイルの座標変換がプログラムで自動で行えるようになるという事は、単品モデルを自動でアセンブリ化する際に利用できそうです。

本ページのコードはMITライセンスに準拠させていただきます(自己責任の範囲でご自由にお使い下さい)。

座標変換も非常に簡単に出来ました!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

SNSでもご購読できます。

コメントを残す

*