こんにちは(@t_kun_kamakiri)
本記事では無償の3D CADソフトであるFreeCADのモデルの作成から面に名前を付けてstlで出力するまでの解説を行います。
OpenFOAMで流体解析を行う場合、境界面に名前を付けて境界条件を設定する必要があるため面に名前を付けれるように自動化しておくと便利です。
- FreeCADで面に名前を付けてアスキーファイル出力
- 出力したファイルを一つにまとめる
以上の事をFreeCAD内のPythonを使って行います。
以前にもまとめたことがあるのですが今回は詳細な資料を使って詳細に解説を行います。
FreeCAD による OpenFOAM 用モデルの作成でstl出力のコードがありましたので参考にさせていただきました。
※今回の記事はこちらのブログのコードを使わせていただいています。
手元のFreeCADでは動作しなかったので編集させていただきました。
FreeCAD 0.20.2
FreeCADのドキュメント
より詳細のFreeCADの使い方に関しては以下のドキュメントを参考にしてください。
FreeCADでモデル作成
今回はダクト内の流れ・・・・のようなモデルを作成します。
stlファイル出力の部分がメインなので寸法も適当にして作成します。
上記の資料はまだ手動でstlファイルを出力していますが、手動で毎回するのは手間がかかります。
マクロで自動化します。
FreeCADマクロ自動化(stlファイル出力)
FreeCAD:0.20
以下の資料の通りにマクロ作成から実行を行います。
FreeCADのバージョンによってはマクロ(Pythonファイル)がなかったりするので自身で作成して実行できる場所に保存する必要があります。
Pythonコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import os import Mesh import MeshPart import re # 現在のディレクトリ doc = App.ActiveDocument PWD = re.findall("(.*)/",doc.FileName)[0] print('現在のディレクトリ:',PWD) labels = [] for obj in doc.Objects: if obj.Visibility == True: if obj.Label[0:3] == 'bc:': mesh = doc.addObject("Mesh::Feature", "Mesh") print(mesh) # mefisto #mesh.Mesh = MeshPart.meshFromShape(Shape=obj.Shape, MaxLength=10) # standard mesh.Mesh = Mesh.Mesh(obj.Shape.tessellate(0.01)) print(mesh.Mesh) label = obj.Label[3:] labels.append(label) Mesh.export([mesh], fr'{PWD}/{label}.ast') print(label) doc.removeObject(mesh.Name) print(doc.Label) print(labels, type(labels)) with open(rf'{PWD}/{doc.Label}.stl', 'w') as f: print('test') for label in labels: with open(rf'{PWD}/{label}.ast', 'r') as fi: for line in fi: if line[:5] == 'solid': line = 'solid ' + label + '\n' elif line[:8] == 'endsolid': line = 'endsolid ' + label + '\n' f.write(line) for label in labels: os.remove(rf'{PWD}/{label}.ast') |
こちらを実行すると面に名前を付けた状態でstlファイルにまとめられます。
以下解説です。
まずは必要なライブラリをインポートします。
1 2 3 4 | import os import Mesh import MeshPart import re |
以下はApp.ActiveDocumentのインスタンス化を行っている部分です。
1 | doc = App.ActiveDocument |
次にstlファイルを保存したい場所をフルパスで指定します。
1 2 3 | # 現在のディレクトリ PWD = r'C:\work\openfoam\20220929_FreeCAD_stl\stl' print('現在のディレクトリ:',PWD) |
os.getcwd()は定番の現在のディレクトリまでのフルパスですが、これだと「C:\Program Files\FreeCAD 0.20\bin」とFreeCAD.exeがあるパスになるので、少以下のような工夫が必要です。
「doc.FileName」が今開いているFreeCADモデルまでの絶対パスになっています。
※例えば「’D:/OpenFOAM/model/model.FCStd’」のようになっているとしましょう。
re.findall(“(.*)/”,doc.FileName)とすることで”/”より前の文字列を抽出することができきます。re.findall(“(.*)/”,doc.FileName)で[‘D:/OpenFOAM/model/model.FCStd’]のようなリスト型として返ってきますので、リストからインデックス0の要素を抽出すると、現在のディレクトリの文字列を取得できるということです。
これはstlファイルの出力先として指定するときに使います。
次はfor文の処理内容です。
1 2 | for obj in doc.Objects: 処理内容... |
doc.Objectsは面に分割した数だけfor文が回ります。
ただし以下のように表示がされているパーツのみ処理内容を行うようにします。
それを行っているのが以下の部分です。
1 | obj.Visibility == True: |
さらに境界面に「bc:」と名前が付いた面だけをファイル出力するようにif文で条件分岐をします。
1 | if obj.Label[0:3] == 'bc:': |
1 2 3 | mesh = doc.addObject("Mesh::Feature", "Mesh") mesh.Mesh = Mesh.Mesh(obj.Shape.tessellate(0.01)) |
作成したメッシュを.ast(アスキー形式)でファイル出力しています。
この時点では1つの面に対して1つのファイルを出力しています。
1 2 3 | label = obj.Label[3:] labels.append(label) Mesh.export([mesh], fr'{PWD}/{label}.ast') |
ここまででモデルツリ―上にメッシュができていますが、必要がないので削除します。
1 | doc.removeObject(mesh.Name) |
次にできた.ast(アスキー形式)を拡張子.stlとしてひとつのファイルに結合します。
1 2 3 4 5 6 7 8 9 10 | with open(rf'{PWD}/{doc.Label}.stl', 'w') as f: print('test') for label in labels: with open(rf'{PWD}/{label}.ast', 'r') as fi: for line in fi: if line[:5] == 'solid': line = 'solid ' + label + '\n' elif line[:8] == 'endsolid': line = 'endsolid ' + label + '\n' f.write(line) |
.astファイルの中のsolidの名前も面の名前になるように変更しています。
※以下は「inlet.ast」の例です。
1 2 | for label in labels: os.remove(rf'{PWD}/{label}.ast') |
指定したフォルダに「.stl」ファイルができているのでParaViewなどで状態を確認します。
以上でFreeCADで面に名前を付けてstlファイル出力ができました。
面の名前の頭に「bc:」を付けるのが面倒だったので、表示されているモデルだけを抽出するプログラムに変えました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import os import Mesh import MeshPart import re # 現在のディレクトリ doc = App.ActiveDocument PWD = re.findall("(.*)/",doc.FileName)[0] print('現在のディレクトリ:',PWD) labels = [] for obj in doc.Objects: if obj.Visibility == True: mesh = doc.addObject("Mesh::Feature", "Mesh") print(mesh) # mefisto #mesh.Mesh = MeshPart.meshFromShape(Shape=obj.Shape, MaxLength=10) # standard mesh.Mesh = Mesh.Mesh(obj.Shape.tessellate(0.01)) print(mesh.Mesh) label = obj.Label[:] labels.append(label) Mesh.export([mesh], fr'{PWD}/{label}.ast') print(label) doc.removeObject(mesh.Name) print(doc.Label) print(labels, type(labels)) with open(rf'{PWD}/{doc.Label}.stl', 'w') as f: print('test') for label in labels: with open(rf'{PWD}/{label}.ast', 'r') as fi: for line in fi: if line[:5] == 'solid': line = 'solid ' + label + '\n' elif line[:8] == 'endsolid': line = 'endsolid ' + label + '\n' f.write(line) for label in labels: os.remove(rf'{PWD}/{label}.ast') |
最終的これを使うのが楽なのでした。
PythonマクロはFreeCADのマクロ保存場所に適当な名前で保存しておけば良いです。
今回は「export_stlAll.py」という名前で保存しました。
次回マクロを実行する際にはこちらの実行ボタンを押せば実行されます。
FreeCADファイルを保存した場所に「フィル名.stl」というファイルができています。
本記事のモデルとは異なりますが、マクロを使って面に名前を付けたstlファイルを作成する一連の流れを動画にしています。
ご参考ください。
参考書
本件の内容はFreeCADですが、FreeCADでモデル作成した先にはOpenFOAMで流体解析を行うのでOpenFOAMの参考書を紹介しておきます。
改訂新版 OpenFOAMの歩き方 (技術の泉シリーズ(NextPublishing))