本人最近遇到一個問題,要對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文件夾都是直接生成的
最後放一張成品截圖:
上面的圖片知識裝飾,沒其他作用。
好了,就是這麼多了,有需要源代碼或者程序的朋友可以私信我