PyQt5で作るSTEPファイルのパーツの名前を変更するツール
2021/04/27 categories:TOOL| tags:TOOL|PyQt5|Python|STEP|QTreeView|
STEPファイルの構造
STEPファイルはテキストデータのようで、テキストエディタで開いてみると以下のような構造になっています。
ISO-10303-21;
HEADER;
...
ENDSEC;
DATA;
...
ENDSEC;
END-ISO-10303-21;
ヘッダ部はHEADER; … ENDSEC;に記載されていて、データ部はDATA; … ENDSEC;に記載されています。STEPデータ内の部品名などはデータ部に含まれているようです。
STEPファイル内の部品名
CADで部品名に特徴的な名前を付けたモデルを作成して、STEPファイルにエクスポートし、そのSTEPファイルをテキストエディタで開いて文字列の検索をすると以下のように、部品名と思われる部分が見つかります。
DATA;
...
#393=PRODUCT('DDDDDDD','DDDDDDD',' ',(#402));
#394=PRODUCT('CCCCCCC','CCCCCCC',' ',(#403));
#395=PRODUCT('BBBBBB','BBBBBB',' ',(#404));
#396=PRODUCT('AAAAAAA','AAAAAAA',' ',(#405));
...
ENDSEC;
このPRODUCTという項目から’AAAAAAA’などの部品名を取得するプログラムを作成します。
STEPファイルからデータ部を取得
with open(filePath, mode='r') as f:
text = f.read()
上記のコードで、STEPデータをテキストファイルとして開いて、textに文字列を格納します。
splited = text.split('DATA;\n')
data = splited[1]
格納した文字列を’DATA;\n’で分割して、分割した2番目の要素がデータ部のテキストデータとなり、dataにその文字列を格納します。
returnData = {}
for i in data.split(';\n'):
line = i.strip().replace('\n', '')
splitIndex = line.find('=')
lineNumber = line[:splitIndex].strip()
lineText = line[splitIndex + 1:].strip()
dataType = lineText[ : lineText.find('(') ].strip()
if not dataType == '':
dataInner = lineText[ lineText.find('(') + 1 : lineText.rfind(')') ].strip()
datas = [ i.strip().replace("'", '') for i in dataInner.split(',') ]
if dataType == 'PRODUCT':
self.products[lineNumber] = [ dataType, datas ]
returnData[lineNumber] = [ dataType, datas ]
return returnData
データは1行ごとにセミコロンで区切られていて、#番号=名前(データ);のような構造で書かれているということが分かるので、データに対してそれぞれ以下のように処理を行います。
- 文字列をセミコロンで分割
- ↑のデータ1個に対して、イコールで分割
- ↑のデータの2個目の要素を最初に出現する括弧で分割
- ↑の1個目の要素をdataTypeとして、dataTypeがPRODUCTのデータを取得
- PRODUCTのデータ部分をカンマで分割して分割されたデータの1個目を部品名とする
動作の様子
ソースコード
import sys
from pathlib import Path
from PyQt5 import QtWidgets, QtCore, QtGui
class StepFileRenamer(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(StepFileRenamer, self).__init__(parent)
self.resize(800, 400)
self.filePath = None
self.model = QtGui.QStandardItemModel(self)
self.view = QtWidgets.QTableView(self)
self.view.setModel(self.model)
self.setCentralWidget( QtWidgets.QWidget(self) )
self.centralWidget().setLayout( QtWidgets.QVBoxLayout() )
self.centralWidget().layout().addWidget(self.view)
self.toolBar = QtWidgets.QToolBar()
self.toolBar.addAction('Open', self.open)
self.toolBar.addAction('Save', self.save)
self.addToolBar(self.toolBar)
def open(self):
filePath, _ = QtWidgets.QFileDialog.getOpenFileName(None, 'Open file', '', 'STEP file(*.stp *.step)')
if filePath == '':
return
with open(filePath, mode='r') as f:
self.step = STEP( f.read() )
self.filePath = Path(filePath)
self.model.clear()
self.model.setHorizontalHeaderLabels(['Before', 'After'])
self.view.setColumnWidth(0, 400)
self.view.horizontalHeader().setStretchLastSection(True)
for lineNumber in self.step.products:
part_name = self.step.products[lineNumber][1][0]
self.model.appendRow([ QtGui.QStandardItem(part_name), QtGui.QStandardItem(part_name) ])
def save(self):
filePath, _ = QtWidgets.QFileDialog.getSaveFileName(None, 'Save file', self.filePath.name, 'STEP file(*.stp )')
if filePath == '':
return
text = self.step.text
for row in range( self.model.rowCount() ):
source, target = self.model.item(row, 0), self.model.item(row, 1)
if not source == target:
text = text.replace( source.text(), target.text() )
with open( Path(filePath).with_suffix('.stp'), mode='w' ) as f:
f.write(text)
class STEP():
class Item():
def __init__(self, name, parent=None):
self.name = name
self.parent = parent
self.children = []
def __init__(self, text):
self.text = text
splited = text.split('DATA;\n')
self.products = {}
self.header = self.loadHeader( splited[0].split('HEADER;\n')[1] )
self.data = self.loadData( splited[1] )
def loadHeader(self, headerText):
return [ i.strip().replace('\n', '') for i in headerText.split(';\n') ]
def loadData(self, dataText):
returnData = {}
for i in dataText.split(';\n'):
line = i.strip().replace('\n', '')
splitIndex = line.find('=')
lineNumber = line[:splitIndex].strip()
lineText = line[splitIndex + 1:].strip()
dataType = lineText[ : lineText.find('(') ].strip()
if not dataType == '':
dataInner = lineText[ lineText.find('(') + 1 : lineText.rfind(')') ].strip()
datas = [ i.strip().replace("'", '') for i in dataInner.split(',') ]
if dataType == 'PRODUCT':
self.products[lineNumber] = [ dataType, datas ]
returnData[lineNumber] = [ dataType, datas ]
return returnData
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
view = StepFileRenamer()
view.show()
app.exec()