TOOL for renaming parts in STEP file created with PyQt5
2021/04/27 categories:TOOL| tags:TOOL|PyQt5|Python|STEP|QTreeView|
STEP file structure
The STEP file looks like text data, and when you open it with a text editor, it has the following structure.
ISO-10303-21;
HEADER;
...
ENDSEC;
DATA;
...
ENDSEC;
END-ISO-10303-21;
The header part is described in HEADER; … ENDSEC ;, and the data part is described in DATA; … ENDSEC ;. It seems that the part names in the STEP data are included in the data section.
Part name in STEP file
Create a model with a characteristic name for the part name in CAD, export it to a STEP file, open the STEP file with a text editor and search for a character string, as shown below, the part that seems to be the part name Can be found.
DATA;
...
#393=PRODUCT('DDDDDDD','DDDDDDD',' ',(#402));
#394=PRODUCT('CCCCCCC','CCCCCCC',' ',(#403));
#395=PRODUCT('BBBBBB','BBBBBB',' ',(#404));
#396=PRODUCT('AAAAAAA','AAAAAAA',' ',(#405));
...
ENDSEC;
Create a program to get the part name such as’AAAAAAA’ from this item called PRODUCT.
Get the data part from the STEP file
with open(filePath, mode='r') as f:
text = f.read()
The above code will open the STEP data as a text file and store the string in text.
splited = text.split('DATA;\n')
data = splited[1]
The stored character string is divided by’DATA; \ n’, and the second element divided becomes the text data of the data part, and that character string is stored in 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
You can see that the data is separated by a semicolon line by line and is written in a structure like #number = name (data) ;, so process each data as follows.
- Split string with semicolon
- For one piece of data in ↑, divide by equal
- Divide the second element of the ↑ data by the first appearing parenthesis
- Get the data of PRODUCT with dataType as the first element of ↑ as dataType
- Divide the data part of PRODUCT with a comma and use the first part of the divided data as the part name.
Operation
![](https://ymt-lab.com//images/post/2021/step-file-part-renamer-01.gif)
Source code
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()