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.

Operation

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()

Share post

Related Posts

コメント