用Python對Hypermesh四面體抽殼

本人最近遇到一個問題,要對Hypermesh中的四面體抽殼,所以用Python做了一個四面體抽殼的工具,寫博客記錄一下。

首先在Hypermesh中導出K文件,接下來的所有操作都是基於K文件進行的,Hypermesh導出K文件如下圖:

 Hypermesh導入K文件如下圖:

第一步,逐行讀取K文件,識別K文件中的單元類型。

        一般情況下K文件含有2種二維單元(shell):三角形和四邊形;含有3種三維單元(solid):四面體,六面體,八面體。

from itertools import combinations
import re
from ToolBox import My_write,My_deletfile,My_recgnize,My_f_write,Find_max_ID
def read_k_file(filename):
    i = 1
    shell_num = 0
    solid_num = 0
    pp = ""
    with open(filename,"r") as F:
        while True:
            Line=F.readline()
            if Line:
                pp = pp + Line
                if "*ELEMENT_SHELL" in Line:
                    shell_num=shell_num+1
                elif "*ELEMENT_SOLID" in Line:
                    solid_num=solid_num+1
            else:
                break
    return pp,shell_num,solid_num
#pp是K文件全部內容,shell_num是shell數量,solid_num是solid數量

 函數返回值爲包含整個K文件的字符串,shell數量和solid數量,用於判斷文件中書否含有待處理的四面體

第二步,分割K文件

        將K文件分割爲幾部分:

               文件頭(head),文件尾(button),根據具體情況將具體單元信息分割爲幾部分(shell_3,shell_4;solid_4,solid_6,

solid_8),分別存入幾個文件中,以待後用

def split_file(pp,shell_num,solid_num):
    My_deletfile("shell_3.k")
    My_deletfile("shell_4.k")
    My_deletfile("shell_temp.k")
    My_deletfile("solid_4.k")
    My_deletfile("solid_6.k")
    My_deletfile("solid_8.k")
    My_deletfile("solid_temp1.k")
    My_deletfile("solid_temp2.k")
    My_deletfile("solid_temp3.k")
    #首先清除所有中間文件
    if shell_num:
        head = re.compile(r'(.*?)\n\*ELEMENT_SHELL.*?END', re.S)
        My_write(head,pp,"head.k")
        #提取文件頭
        if shell_num==2:
            #如果shell_num=2,說明K文件中有全部兩種shell單元,三角形在前,四邊形在後,依次輸出即可
            shell_3 = re.compile(r'\*ELEMENT_SHELL\n(.*?)\n\*ELEMENT_SHELL.*?END', re.S)
            My_write(shell_3,pp,"shell_3.k")
            print("三角形輸出完畢")
            shell_4 = re.compile(r'\*ELEMENT_SHELL.*?\*ELEMENT_SHELL\n(.*?)\n\*.*?END', re.S)
            My_write(shell_4,pp,"shell_4.k")
            print("四邊形輸出完畢")
        elif shell_num==1:
            #如果shell_num=1,說明只有一種shell單元,可能是三角形,也可能是四面體,這時需要先寫入到臨時文件中進一步判斷
            shell_temp = re.compile(r'\*ELEMENT_SHELL\n(.*?)\n\*.*?END', re.S)
            My_write(shell_temp, pp, "shell_temp.k")
            My_recgnize("shell_temp.k")#進一步判斷單元類型
    else:
        #shell_num=0,即沒有面單元,如果有體單元,則頭文件爲*ELEMENT_SOILD之前的部分;如果也沒有體單元,則輸出警告
        if solid_num:
            head = re.compile(r'(.*?)\n\*ELEMENT_SOLID.*?END', re.S)
            My_write(head, pp, "head.k")
        else:
            print("沒有體單元,也沒有面單元")
    if solid_num:
        if solid_num==3:
            #如果文件中含全部三種體單元,按四面體,六面體,八面體的順序輸出即可,否則需要先寫入臨時文件,進一步判斷
            solid_4=re.compile(r'\*ELEMENT_SOLID\n(.*?)\n\*ELEMENT_SOLID.*?\*ELEMENT_SOLID.*?\*.*?END',re.S)
            My_write(solid_4,pp,"solid_4.k")
            print("四面體輸出完畢")
            solid_6 = re.compile(r'\*ELEMENT_SOLID\n.*?\n\*ELEMENT_SOLID\n(.*?)\n\*ELEMENT_SOLID.*?\*.*?END', re.S)
            My_write(solid_6, pp, "solid_6.k")
            print("六面體輸出完畢")
            solid_8 = re.compile(r'\*ELEMENT_SOLID\n.*?\n\*ELEMENT_SOLID.*?\*ELEMENT_SOLID\n(.*?)\n\*.*?END', re.S)
            My_write(solid_8, pp, "solid_8.k")
            print("八面體輸出完畢")
            button = re.compile(r'\*ELEMENT_SOLID.*?\*ELEMENT_SOLID.*?\*ELEMENT_SOLID.*?(\*.*?END)', re.S)
            My_write(button,pp,"button.k")
        elif solid_num==2:
            solid_temp1 = re.compile(r'\*ELEMENT_SOLID\n(.*?)\n\*ELEMENT_SOLID.*?\*.*?END', re.S)
            My_write(solid_temp1, pp, "solid_temp1.k")
            My_recgnize("solid_temp1.k")
            solid_temp2 = re.compile(r'\*ELEMENT_SOLID.*?\*ELEMENT_SOLID\n(.*?)\n\*.*?END', re.S)
            My_write(solid_temp2, pp, "solid_temp2.k")
            My_recgnize("solid_temp2.k")
            button = re.compile(r'\*ELEMENT_SOLID.*?\*ELEMENT_SOLID.*?(\*.*?END)', re.S)
            My_write(button, pp, "button.k")
        elif solid_num==1:
            solid_temp3 = re.compile(r'\*ELEMENT_SOLID\n(.*?)\n\*.*?END', re.S)
            My_write(solid_temp3, pp, "solid_temp3.k")
            My_recgnize("solid_temp3.k")
            button = re.compile(r'\*ELEMENT_SOLID.*?(\*.*?END)', re.S)
            My_write(button, pp, "button.k")
    else:
        print("沒有體單元")

用到的函數:

#刪除文件函數
def My_deletfile(filename):
    if os.path.exists(filename):
        # 刪除文件,可使用以下兩種方法。
        os.remove(filename)
        # os.unlink(my_file)
        print("成功刪除文件:%s" %filename)
    else:
        print('不存在文件:%s' % filename)
#進一步判斷單元類型
def My_recgnize(filename):
    with open(filename,"r",encoding="utf-8") as f:
        Line=f.readline()
        lline=Line.split()
        print(lline)
        content = f.read()
        if len(lline)==6:
            if lline[5]==lline[4]:
                with open("shell_3.k","w",encoding="utf-8")as F :
                    F.write(content)
                print("三角形輸出完畢")
            elif lline[4]!=lline[5]:
                with open("shell_4.k","w",encoding="utf-8")as F :
                    F.write(content)
                print("四邊形輸出完畢")
            else:
                print("都不是")
        if len(lline)==10:
            if lline[8]==lline[6]==lline[7]:
                with open("solid_4.k", "w", encoding="utf-8")as F:
                    F.write(content)
                print("四面體輸出完畢")
            elif lline[7]==lline[6] and lline[8]!=lline[7]:
                with open("solid_6.k", "w", encoding="utf-8")as F:
                    F.write(content)
                print("六面體輸出完畢")
            else:
                with open("solid_8.k", "w", encoding="utf-8")as F:
                    F.write(content)
                print("八面體輸出完畢")

第三步,四面體抽殼和重新封裝K文件

        首先選擇文件保存目錄,並將頭文件先存入目標文件。

        如果原文件含三角形,則先寫入,然後對四面體抽殼並將結果寫入目標文件;如果沒三角形,則直接將四面體抽殼的結果寫入。

        四面體抽殼:

                逐行讀取第二步中得到的solid_4文件,數據格式如下:

                3177856    2009 3093371 3080613 3093375 3080578 3080578 3080578 3080578 3080578

                共10列數據,每列8位,其中第一列爲單元ID,第二行爲componentID,3~10列爲組成單元的8個NodeID。我們可以看到四面體的第5~8個NodeID相同,因此取1~4個NodeID進行排列組合。

          之後將其他單元和文件尾按順序寫入即可

重組主函數:

def Reorder(filename):
    My_deletfile(filename)
    with open(filename,"a",encoding="utf-8") as f:
        Write_orign("head.k",f)
        Write_orign("shell_3.k",f)
        Write_orign("shell_4.k", f)
        Write_orign("solid_4.k", f)
        Write_orign("solid_6.k", f)
        Write_orign("solid_8.k", f)
        Write_orign("button.k", f)

寫入文件函數:

def Write_orign(filename,f):
    try:
        with open(filename,"r",encoding="utf-8") as Orign:
            if filename == "shell_3.k":
                f.write("*ELEMENT_SHELL"+"\n")
                solid2shell(f)
            elif  filename == "shell_4.k":
                f.write("*ELEMENT_SHELL" + "\n")
            elif filename == "solid_4.k" or filename == "solid_6.k" or filename == "solid_8.k":
                f.write("*ELEMENT_SOLID"+"\n")
            f.write(Orign.read()+"\n")
    except:
        if filename=="shell_3.k":
            f.write("*ELEMENT_SHELL"+"\n")
            solid2shell(f)
        print("文件%s" %filename+"不存在")

 四面體抽殼函數:

def solid2shell(f):
    MAX_ID=max(Find_max_ID("shell_3.k",0),Find_max_ID("shell_4.k",0),Find_max_ID("solid_4.k",0),
               Find_max_ID("solid_6.k",0),Find_max_ID("solid_8.k",0))
    MAX_comp_ID = max(Find_max_ID("shell_3.k", 1), Find_max_ID("shell_4.k", 1), Find_max_ID("solid_4.k", 1),
                 Find_max_ID("solid_6.k", 1), Find_max_ID("solid_8.k", 1))
    with open("solid_4.k",'r') as solid:
        k = 1
        while True:
            line = solid.readline()
            if line:
                line1=line.split()
                sort=list(combinations(line1[2:6],3))
                for i in range(len(sort)):
                    My_f_write(MAX_ID+k,f)
                    k = k + 1
                    My_f_write(MAX_comp_ID+1,f)
                    for j in range(len(sort[0])):
                        My_f_write(int(sort[i][j]),f)
                    My_f_write(sort[i][2]+"\n",f)
            else:
                break

尋找最大partID和conponentID函數:

def Find_max_ID(filename,num):
    try:
        with open(filename,"r",encoding="utf-8") as f:
            ID=[0,0]
            while True:
                line=f.readline()
                if line:
                    Line=line.split()
                    try:
                        ID[0]=int(Line[num])
                        if ID[0]>ID[1]:
                            ID[1]=ID[0]
                    except:
                        continue
                else:
                    break
        return ID[1]
    except:
        return 0

 按8位格式將數據寫入文件函數:


def My_f_write(A,f):
    if  int(A)>= 0 and int(A)< 10:
        f.write(" " * 7 + str(A))
    if int(A) >= 10 and int(A) < 100:
        f.write(" " * 6 + str(A))
    if int(A) >= 100 and int(A) < 1000:
        f.write(" " * 5 + str(A))
    if int(A) >= 1000 and int(A) < 10000:
        f.write(" " * 4 + str(A))
    if int(A) >= 10000 and int(A) < 100000:
        f.write(" " * 3 + str(A))
    if int(A) >= 100000 and int(A) < 1000000:
        f.write(" " * 2 + str(A))
    if int(A) >= 1000000 and int(A) < 10000000:
        f.write(" " * 1 + str(A))
    if int(A) >= 10000000 and int(A) < 100000000:
        f.write(str(A))

第五步,製作UI

爲了給程序加上UI,我使用了PyQt5庫。同時還對前文中的一些函數做了更改,但基本的原理沒有改變,更改的目的只是讓UI更人性化。UI程序如下:

import sys
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication,QFileDialog,QMessageBox,QLineEdit,QLabel
from Read_K_File import read_k_file,split_file,Reorder
from PyQt5.QtGui import QIcon,QPixmap,QGuiApplication
from random import randint
from time import clock,sleep
from ToolBox import My_deletfile

class Example(QMainWindow):

    def __init__(self):
        super().__init__()
        self.pp = ""
        self.shell_num = 0
        self.solid_num = 0
        self.initUI()

    def initUI(self):
        self.inputfile_name = QLineEdit(self)
        self.inputfile_name.move(220, 438)
        self.inputfile_name.resize(760, 40)

        self.outputfile_name = QLineEdit(self)
        self.outputfile_name.move(220, 498)
        self.outputfile_name.resize(760, 40)

        #lable_2=QLabel()
        #lable_2.setGeometry(100,500,100,100)
        #lable_2.setPixmap(QPixmap("D:\document\Python\GUIdesign\Boom.jpg"))

        self.lb1 = QLabel(self)
        self.lb1.setGeometry(20, 20, 225, 400)
        self.lb2 = QLabel(self)
        self.lb2.setGeometry(20+225+20, 20, 225, 400)
        self.lb3 = QLabel(self)
        self.lb3.setGeometry(20+225+20+225+20, 20, 225, 400)
        self.lb4 = QLabel(self)
        self.lb4.setGeometry(20+225+20+225+20+225+20, 20, 225, 400)
        self.create_fignum()

        btn1 = QPushButton("選擇待處理K文件", self)
        btn1.move(20, 438)
        btn1.resize(180,40)

        btn2 = QPushButton("選擇K文件保存目錄", self)
        btn2.move(20, 498)
        btn2.resize(180,40)

        btn3 = QPushButton("第一步:讀取K文件", self)
        btn3.move(20, 558)
        btn3.resize(300,40)

        btn4 = QPushButton("第二步:分割K文件", self)
        btn4.move(350, 558)
        btn4.resize(300, 40)

        btn5=QPushButton("第三步:四面體抽殼&&&重組K文件",self)
        btn5.move(680,558)
        btn5.resize(300, 40)

        btn1.clicked.connect(self.buttonClicked)
        btn2.clicked.connect(self.buttonClicked)
        btn3.clicked.connect(self.Read_K_file)
        btn4.clicked.connect(self.Split_K_file)
        btn5.clicked.connect(self.Reorder)

        self.setGeometry(300, 300, 1000,618 )
        self.setWindowTitle('四面體抽殼小程序')
        self.setWindowIcon(QIcon("img\Boom.jpg"))
        self.show()
        self.setFixedSize(self.width(), self.height())
        self.gui = QGuiApplication.processEvents

    def create_fignum(self):
        fig_num = [randint(1, 28)]
        while True:
            if len(fig_num) <4:
                K = randint(1, 28)
                if K in fig_num:
                    continue
                else:
                    fig_num.append(K)
            else:
                break
        self.lb1.setPixmap(QPixmap("img/" + str(fig_num[0]) + "_1.jpg"))
        self.lb2.setPixmap(QPixmap("img/" + str(fig_num[1]) + "_1.jpg"))
        self.lb3.setPixmap(QPixmap("img/" + str(fig_num[2]) + "_1.jpg"))
        self.lb4.setPixmap(QPixmap("img/" + str(fig_num[3]) + "_1.jpg"))

    def buttonClicked(self):
        sender = self.sender()
        if sender.text()=="選擇待處理K文件":
            fileName1, filetype = QFileDialog.getOpenFileName(self,
                                                              "選取文件",
                                                              sys.path[0],
                                                              "K文件(*.k);;txt文件 (*.txt);;所有文件 (*)")
            self.statusBar().showMessage(fileName1)
            self.inputfile_name.setText(fileName1)
        elif sender.text()=="選擇K文件保存目錄":
            self.statusBar().showMessage(sender.text() + ' was pressed')
            fileName2, filetype = QFileDialog.getSaveFileName(self,
                                                              "選取文件",
                                                              sys.path[0],
                                                              "K文件(*.k);;txt文件 (*.txt);;所有文件 (*)")
            self.statusBar().showMessage(fileName2)
            self.outputfile_name.setText(fileName2)
    def Read_K_file(self):
        if self.inputfile_name.text():
            with open(self.inputfile_name.text(),"r") as F:
                start=clock()
                i=1
                line_num=1
                pp=''
                while True:
                    self.statusBar().showMessage("開始讀取K文件,如有卡頓屬於正常現象,稍等即可,不用退出。已讀取 "+str(line_num)+" 行")
                    line_num = line_num + 1
                    Line = F.readline()
                    if Line:
                        pp = pp + Line
                        if "*ELEMENT_SHELL" in Line:
                            self.shell_num=self.shell_num+1
                        elif "*ELEMENT_SOLID" in Line:
                            self.solid_num=self.solid_num+1
                        elif "*END" in Line:
                            self.pp = self.pp + pp
                    else:
                        break
                    if i == 20000:
                        self.pp=self.pp+pp
                        pp=''
                        self.gui()
                        sleep(0.5)
                        self.create_fignum()
                        i=0
                    i=i+1
                endd=clock()
                self.statusBar().showMessage("共讀取 "+str(line_num)+" 行數據,用時:"+str(endd-start)+"秒")
            Message="讀取K文件完畢!"+"\n"+"共有"+str(self.shell_num)+"種面單元;有"+str(self.solid_num)+"種體單元"
            QMessageBox.information(self,"Information",Message,QMessageBox.Yes)
        else:
            self.Message("請選擇待處理K文件!")
    def Split_K_file(self):
        self.statusBar().showMessage("開始分割K文件")
        if self.pp:
            split_file(self.pp, self.shell_num, self.solid_num,self.statusBar().showMessage,self.Message)
            Message="分割K文件完成!"
            QMessageBox.information(self, "Information", Message, QMessageBox.Yes)
        else:
            self.Message("沒有讀取文件")
    def Reorder(self):
        try:
            with open("head.k","r") as f:
                self.statusBar().showMessage("開始抽殼和重組文件,依然會有失去響應的現象,請少安勿燥")
                if self.outputfile_name.text():
                    Reorder(self.outputfile_name.text(),self.statusBar().showMessage,self.Message,self.create_fignum,self.gui)
                    Message = "抽殼和重組文件完成!"
                    QMessageBox.information(self, "Information", Message, QMessageBox.Yes)
                else:
                    self.Message("沒選擇K文件保存目錄")
        except:
            self.Message("還沒有分割K文件!!!")
        My_deletfile("shell_3.k")
        My_deletfile("shell_4.k")
        My_deletfile("shell_temp.k")
        My_deletfile("solid_4.k")
        My_deletfile("solid_6.k")
        My_deletfile("solid_8.k")
        My_deletfile("solid_temp1.k")
        My_deletfile("solid_temp2.k")
        My_deletfile("solid_temp3.k")
        My_deletfile("head.k")
        My_deletfile("button.k")
    def Message(self,message):
        reply=QMessageBox.warning(self,"警告",message,QMessageBox.Yes)



if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

UI中包含了按鈕,文本框,圖片等元素,都比較簡單,有不明白的朋友自行百度即可

第六部,製作exe文件

終於到了最後一步,打包Exe文件,讓這個程序運行在沒有python的環境下,爲此我們需要安裝pyinstaller庫,這個庫直接pip安裝就好,這裏不再介紹。封裝的命令爲:pyinstaller  -w solid2shell.py,封裝後得到一個文件夾,裏面有各種dll文件,我們只需要運行solid2shell.exe文件即可。

放一張打包後的文件截圖:

 其中除了img文件夾都是直接生成的

最後放一張成品截圖:

 上面的圖片知識裝飾,沒其他作用。

 

好了,就是這麼多了,有需要源代碼或者程序的朋友可以私信我

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章