75 lines
3.1 KiB
Python
75 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
step-to-stl.py —— 真实 STEP 批量转 STL 网格 (桌面软件窗口内 3D 预览用)
|
|
|
|
内核: OpenCASCADE 的 Python 绑定 (cadquery/OCP, 开源 LGPL)。
|
|
用途: 把 catalog\\step\\ 里的真实数模 (体积 > 20KB 的 .step/.stp, 占位几何 ~7KB 自动跳过)
|
|
转成 catalog\\mesh\\ 下同名 .stl 网格。桌面 3D 标签页发现有网格就在窗口内直渲。
|
|
|
|
断点续跑: 同名 STL 已存在且不比 STEP 旧 → 跳过。
|
|
以后新增真实 STEP 后重跑本脚本即可 (或用 NX journal 的 exportStl 自动导出)。
|
|
|
|
用法: python step-to-stl.py
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
STEP_DIR = os.path.join(BASE, 'catalog', 'step')
|
|
MESH_DIR = os.path.join(BASE, 'catalog', 'mesh')
|
|
REAL_MIN_BYTES = 20 * 1024 # 20KB 以上算真实数模 (占位几何 ~7KB)
|
|
LIN_DEFLECTION = 1.5 # 网格线性偏差 (mm): 越小越精细、文件越大 (1.5mm 屏幕预览足够, 保证流畅旋转)
|
|
|
|
|
|
def convert(step_path, stl_path):
|
|
from cadquery.occ_impl.shapes import Shape
|
|
from OCP.STEPControl import STEPControl_Reader
|
|
from OCP.StlAPI import StlAPI_Writer
|
|
from OCP.BRepMesh import BRepMesh_IncrementalMesh
|
|
from OCP.IFSelect import IFSelect_RetDone
|
|
|
|
reader = STEPControl_Reader()
|
|
if reader.ReadFile(str(step_path)) != IFSelect_RetDone:
|
|
raise RuntimeError('STEP 读取失败: %s' % step_path)
|
|
reader.TransferRoots()
|
|
shape = Shape(reader.OneShape())
|
|
BRepMesh_IncrementalMesh(shape.wrapped, LIN_DEFLECTION, False, 0.5, True).Perform()
|
|
writer = StlAPI_Writer()
|
|
writer.SetASCIIMode(False) # 二进制 STL (比 ASCII 小 ~3 倍)
|
|
if not writer.Write(shape.wrapped, str(stl_path)):
|
|
raise RuntimeError('STL 写出失败: %s' % stl_path)
|
|
|
|
|
|
def main():
|
|
if not os.path.isdir(MESH_DIR):
|
|
os.makedirs(MESH_DIR)
|
|
step_files = [f for f in os.listdir(STEP_DIR)
|
|
if f.lower().endswith(('.step', '.stp'))]
|
|
done = skip = 0
|
|
errors = []
|
|
for name in sorted(step_files):
|
|
step_path = os.path.join(STEP_DIR, name)
|
|
if os.path.getsize(step_path) < REAL_MIN_BYTES:
|
|
continue # 占位几何, 不转
|
|
stl_path = os.path.join(MESH_DIR, os.path.splitext(name)[0] + '.stl')
|
|
# 跳过条件: STL 存在、比 STEP 新、且不是占位网格 (<50KB 视为占位, 强制重转)
|
|
if (os.path.exists(stl_path) and os.path.getsize(stl_path) > 50 * 1024
|
|
and os.path.getmtime(stl_path) >= os.path.getmtime(step_path)):
|
|
skip += 1
|
|
continue
|
|
try:
|
|
convert(step_path, stl_path)
|
|
done += 1
|
|
print(' OK %-24s -> %s (%.1f KB)' % (name, os.path.basename(stl_path),
|
|
os.path.getsize(stl_path) / 1024.0))
|
|
except Exception as e:
|
|
errors.append('%s: %s' % (name, e))
|
|
print('FAIL %s: %s' % (name, e))
|
|
print('完成: 转换 %d, 跳过 %d, 失败 %d → %s' % (done, skip, len(errors), MESH_DIR))
|
|
if errors:
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|