STEPから部品リストを自動で抜くスクリプトを書いてみた
設計変更のたびに部品リストを手入力していないですか。
CADを開いて、アセンブリの部品一覧をスクショして、Excelに手入力する。
100部品を超えたらコピペでも振り分けに時間がかかる。
同じ部品名でも何度も入力し直すし、誰かが修正したら、それをまた反映させるのに時間がかかる。
その間に転記ミスも出る。
検図すると、「部品数が合わない」って事もちらほら。
「何かこれを自動化できないか」と思って、PythonでSTEPファイルから部品情報を抽出して、そのままExcelに落とすスクリプトを書いてみました。
前の記事で説明したこと
STEPファイルをPythonで読み込む基本的な方法は、前の記事で説明しています。
この記事では、BOM生成に特有の処理 — 部品情報の抽出とExcel出力 — に絞ります。
アセンブリから部品情報を抽出する
アセンブリのSTEPを読むと、複数のソリッド(部品)が入ってます。
import cadquery as cq
import re
def load_part_names(step_path):
"""STEPファイルのテキストから部品名を抽出"""
with open(step_path, "r", encoding="utf-8", errors="ignore") as f:
text = f.read()
products = re.findall(r"PRODUCT\s*\(\s*'([^']+)'", text)
# ルートアセンブリ(UUID形式)は除外
names = [p for p in products if not (len(p) == 36 and p.count("-") == 4)]
return names
def extract_bom(step_path):
"""STEPからBOM(部品リスト)を抽出"""
result = cq.importers.importStep(step_path)
shape = result.val() # Compoundを取得
solids = shape.Solids() # OCCのShapeリスト
names = load_part_names(step_path)
# 部品名が足りない場合は自動採番
while len(names) < len(solids):
names.append(f"Part_{len(names)+1:03d}")
bom = []
for i, solid in enumerate(solids):
bb = solid.BoundingBox()
bom.append({
"部品番号": i + 1,
"部品名": names[i],
"数量": 1,
"外形_X": round(bb.xlen, 2),
"外形_Y": round(bb.ylen, 2),
"外形_Z": round(bb.zlen, 2),
"体積_mm3": round(solid.Volume(), 1),
"面数": len(solid.Faces()),
})
return bom
実行するとこんなリストが出ます。
bom = extract_bom("assembly.step")
for item in bom:
print(item)
{'部品番号': 1, '部品名': 'Bracket_001', '数量': 1, '外形_X': 45.23, ...}
{'部品番号': 2, '部品名': 'Shaft_002', '数量': 1, '外形_X': 150.00, ...}
ExcelにBOMを出力する
ここが今回の本題。openpyxlを使ってExcelファイルを自動生成します。
pip install cadquery openpyxl
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
def write_bom_to_excel(bom, output_path="BOM.xlsx"):
"""BOMをExcelファイルに書き込む"""
wb = Workbook()
ws = wb.active
ws.title = "BOM"
# ヘッダー
headers = ["部品番号", "部品名", "数量", "外形_X(mm)", "外形_Y(mm)", "外形_Z(mm)", "体積(mm³)", "面数"]
ws.append(headers)
# ヘッダーのスタイル
header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid")
header_font = Font(bold=True, color="FFFFFF")
for cell in ws[1]:
cell.fill = header_fill
cell.font = header_font
cell.alignment = Alignment(horizontal="center")
# データ行
for item in bom:
ws.append([
item["部品番号"],
item["部品名"],
item["数量"],
item["外形_X"],
item["外形_Y"],
item["外形_Z"],
item["体積_mm3"],
item["面数"],
])
# 列幅
ws.column_dimensions["A"].width = 10
ws.column_dimensions["B"].width = 20
ws.column_dimensions["C"].width = 8
for col in ["D", "E", "F", "G", "H"]:
ws.column_dimensions[col].width = 14
# 枠線
thin_border = Border(
left=Side(style="thin"), right=Side(style="thin"),
top=Side(style="thin"), bottom=Side(style="thin"),
)
for row in ws.iter_rows(min_row=1, max_row=len(bom) + 1, min_col=1, max_col=8):
for cell in row:
cell.border = thin_border
wb.save(output_path)
print(f"BOM exported to {output_path}")
これで実行。
bom = extract_bom("assembly.step")
write_bom_to_excel(bom, "BOM_output.xlsx")
ヘッダーは青背景、枠線付きのExcelが出てくる。数十部品のアセンブリなら5秒で終わる。
実務での使い方
自分はこんな感じで回してます。
- CADで修正したアセンブリをSTEPで出す
- 旧版と新版のSTEPを比較して、何が変わったかを確認
- 新版のSTEPを上のスクリプトに投げる
- Excelが自動生成される
- 部品数や名前に漏れがないかをさっと確認して提出
手作業で転記してた頃は30分〜1時間かかってたので、これが自動化できたらだいぶ楽?
修正がたびたび入るときに、そのたびにBOMを生成し直せるのが地味にありがたい。
注意点
部品名の対応が厄介。
CadQueryには部品名を取るAPIがないので、STEPのテキストを正規表現で抜いてます。
設変前後で部品名が変わると別物扱いになる。
同じCADから出したSTEPなら順序は大体変わらないので、実用上はこれで足りてるかなと。
大きいアセンブリは時間がかかる。
実測で約5秒/MB。
30MBのSTEPだと2分くらい。
サーフェスボディは未対応。
製造業のSTEPはほぼソリッドなので、今のところ問題にはなってない。
こういうスクリプトの応用で、STEPの差分比較や3Dビューアも組み合わせたツールを作ってみてます。興味があれば覗いてみてください。