界面程序
"""测试一个经典的GUI程序的写法,使用面向对象的方式"""
import time
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog
import threading
from cut_brick import cal_brick
class Application(Frame):
"""一个经典的GUI程序的类的写法"""
def __init__(self, master=None):
super().__init__(master)
self.master=master
self.pack()
self.createWidget()
self.file_name = ""
def createWidget(self):
"""创建组件"""
self.result = Label(self,text="")
self.label_width = Label(self, text="整砖的宽度")
self.label_height = Label(self, text="整砖的高度")
self.width_entry = Entry(self)
self.height_entry = Entry(self)
self.label_width.grid(row=0, column=0,pady=10)
self.width_entry.grid(row=0, column=1,pady=10)
self.label_height.grid(row=1, column=0,pady=10)
self.height_entry.grid(row=1, column=1,pady=10)
self.select_file = Button(self,text="选择文件", command=self.select_file_path)
self.file_path = Label(self, text="文件名称")
self.select_file.grid(row=2, column=0, pady=10)
self.file_path.grid(row=2, column=1, pady=10)
self.btn01 = Button(self)
self.btn01["text"] = "运行结果"
self.btn01["command"] = self.cal_brick_num
self.btn01.grid(row=3, column=0, columnspan=2,pady=10)
self.result.grid(row=4, column=0, columnspan=2,pady=10)
def cal_brick_num(self):
def run():
self.result["text"] = "运行中"
self.btn01.config(state=DISABLED)
save_path = self.file_name.replace(self.file_path["text"], "") + "cut_img\\"
excel_file_path = self.file_name
brick_num = cal_brick(excel_file_path,int(input_width),int(input_height), save_path)
self.result["text"] = "所需砖数为" + str(brick_num)
self.btn01.config(state=NORMAL)
input_width = self.width_entry.get()
input_height = self.height_entry.get()
if input_width == "" or input_height == "" or self.file_name == "":
messagebox.showinfo("提示", "存在输入为空,请检查输入!")
return
t = threading.Thread(target=run)
t.setDaemon(True)
t.start()
def select_file_path(self):
img_path = filedialog.askopenfilename()
self.file_name = img_path
self.file_path["text"] = img_path.split("/")[-1]
if __name__ == "__main__":
root=Tk()
root.geometry("400x300+200+300")
root.title("最少瓷砖切割算法")
app = Application(master=root)
root.mainloop()

其它文件
- cut_brick.py
import sys,os
from tools import *
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import random
Bin=[600,600]
excel_path = "D:\project\C\LayoutAapter\Layout\data\dong\\floor3\\237\\brick.xlsx"
img_save_path = "D:\\Data\\myimg\\brick_img\\"
sheet_name = "整层"
def draw_bin(AllItem,RPNXY,name_index = 0):
global img_save_path
fig, ax = plt.subplots(1, 1)
ax1 = fig.gca()
for i in RPNXY:
width,height = AllItem[i[0]]
rx,ry = i[1],i[2]
lx,ly = rx-width,ry-height
plt.xlim((0, Bin[0]))
plt.ylim((0, Bin[1]))
color = "#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])
rect = patches.Rectangle((lx, ly), width,height,linewidth=1, facecolor = color)
ax1.text(lx + width/2 - 30, ly + height / 2, str(width) + "*" + str(height))
ax1.add_patch(rect)
plt.savefig(img_save_path + str(name_index) + ".jpg")
plt.close()
def arr_sort(AllItem):
item_dict = {}
for i in range(len(AllItem)):
item_dict[i] = AllItem[i].copy()
item_dict = dict(sorted(item_dict.items(), key=lambda x: -x[1][1]))
for i, key in enumerate(item_dict.keys()):
AllItem[i] = item_dict[key]
return AllItem
def get_all_item_by_excel(file_path=None):
import pandas as pd
global excel_path,sheet_name
if file_path is None:
file_path = excel_path
xlsx = pd.ExcelFile(file_path)
df = pd.read_excel(xlsx, sheet_name)
AllItem = []
for i in range(len(df) - 1):
print(df.iloc[i,0],df.iloc[i,1])
brick_size = np.asarray(df.iloc[i,0].split("*")[:2],dtype=int)
for j in range(int(df.iloc[i,1])):
if sum(brick_size) == sum(Bin):
continue
AllItem.append(brick_size)
return np.asarray(AllItem)
def get_data_by_excel(file_path=None):
import pandas as pd
global excel_path
if file_path is None:
file_path = excel_path
xlsx = pd.ExcelFile(file_path)
if file_path.__contains__("floor"):
sheet_name = "整层"
else:
sheet_name = "整栋"
print(pd.read_excel(xlsx, sheet_name))
df = pd.read_excel(xlsx, sheet_name)
AllItem = []
for i in range(len(df) - 1):
print(df.iloc[i,0],df.iloc[i,1])
brick_size = np.asarray(df.iloc[i,0].split("*")[:2],dtype=int)
brick_size[np.where(brick_size>600)] = 600
for j in range(int(df.iloc[i,1])):
if sum(brick_size) == sum(Bin):
continue
AllItem.append(brick_size)
box_size = [Bin]
return box_size, AllItem
def get_1D_data_by_excel(file_path=None):
import pandas as pd
global excel_path
if file_path is None:
file_path = excel_path
xlsx = pd.ExcelFile(file_path)
if file_path.__contains__("floor"):
sheet_name = "整层"
else:
sheet_name = "整栋"
print(pd.read_excel(xlsx, sheet_name))
df = pd.read_excel(xlsx, sheet_name)
AllItem = []
for i in range(len(df) - 1):
print(df.iloc[i,0],df.iloc[i,1])
brick_size = np.asarray(df.iloc[i,0].split("*")[:2],dtype=int)
brick_size[np.where(brick_size>600)] = 600
for j in range(int(df.iloc[i,1])):
AllItem.append(brick_size[1])
box_size = [Bin[0]]
return box_size, AllItem
def put_bin(AllItem):
itemNum=len(AllItem)
ran=list(range(itemNum))
AllItem = arr_sort(AllItem)
ansBXY=np.zeros((itemNum,3))
boxes = []
RPNXY=[]
BinNum=0
flagItem=np.zeros(itemNum)
for i in range(itemNum):
if flagItem[ran[i]]==0:
item=AllItem[ran[i],:]
itemRP=Bin
is_put = False
for j in range(len(boxes)):
RPNXY = boxes[j]
flagOL=overlap(item,AllItem,itemRP,RPNXY)
if flagOL==0:
itemRP=finalPos(item,AllItem,itemRP,RPNXY)
if len(itemRP)>0:
RPNXY.append([ran[i],itemRP[0],itemRP[1]])
flagItem[ran[i]]=1
boxes[j] = RPNXY
is_put = True
break
if not is_put:
BinNum=BinNum+1
RPNXY=[[ran[i], item[0], item[1]]]
flagItem[ran[i]] = 1
boxes.append(RPNXY)
return boxes,AllItem
def cal_brick(file_name, width, height, save_path):
global excel_path,Bin,img_save_path
excel_path = file_name
Bin = [width, height]
img_save_path = save_path
if not os.path.exists(save_path):
os.mkdir(save_path)
for file_name in os.listdir(img_save_path):
os.remove(img_save_path+file_name)
all_items = get_all_item_by_excel()
boxes,AllItem = put_bin(all_items)
for index in range(len(boxes)):
draw_bin(AllItem,boxes[index],index)
return len(boxes)
if __name__ == "__main__":
argv_path = None
argv_save_path = None
argv_width = None
excel_sheet_name = None
for index in range(1, len(sys.argv)):
if index == 1:
argv_path = sys.argv[1]
if index == 2:
argv_save_path = sys.argv[2]
if index == 3:
argv_width = sys.argv[3]
if index == 4:
excel_sheet_name = sys.argv[4]
if argv_width is not None:
Bin = [int(argv_width),int(argv_width)]
if argv_path is not None:
excel_path = argv_path
if argv_save_path is not None:
img_save_path = argv_save_path
if excel_sheet_name is not None:
sheet_name = excel_sheet_name
for file_name in os.listdir(img_save_path):
os.remove(img_save_path + file_name)
all_items = get_all_item_by_excel()
boxes, AllItem = put_bin(all_items)
print(len(boxes))
for index in range(len(boxes)):
draw_bin(AllItem, boxes[index], index)
- tools.py
import numpy as np
def Horizontal_Lines_Intersect(line1,line2):
if line1[2]<=line2[0]:
flag=0
HD=line1[1]-line2[1]
elif (line1[2]>line2[0]) and (line1[2]<=line2[0]):
flag=1
HD=line1[1]-line2[1]
elif (line1[0]>=line2[0]) and (line1[0]<line2[2]):
flag=1
HD=line1[1]-line2[1]
elif line1[0]>=line2[2]:
flag=0
HD=line1[1]-line2[1]
else:
flag=1
HD=line1[1]-line2[1]
return flag,HD
def Point_Horizontal_Line(item,RPXY):
RBPXY=[RPXY[0],RPXY[1]-item[1]]
LBPXY=[RPXY[0]-item[0],RPXY[1]-item[1]]
bottomLine=[]
bottomLine.extend(LBPXY)
bottomLine.extend(RBPXY)
return bottomLine
def downHAtPoint(item,AllItem,itemRP,RPNXY):
bottomLine=Point_Horizontal_Line(item,itemRP)
RP_NUM=len(RPNXY)
if RP_NUM!=0:
sRPNXY=np.array(sorted(list(RPNXY), key=lambda x:x[2],reverse=True))
sRBPNXY=sRPNXY.copy()
sRBPNXY[:,1]=sRPNXY[:,1]-AllItem[sRPNXY[:,0],0]
topLine=np.concatenate((sRBPNXY[:,1:3],sRPNXY[:,1:3]),axis=1)
alldownH=[]
for i in range(RP_NUM):
flag,HD=Horizontal_Lines_Intersect(bottomLine,topLine[i,:])
if (flag==1) and (HD>=0):
alldownH.append(HD)
if len(alldownH)==0:
downH=itemRP[1]-item[1]
else:
downH=min(alldownH)
else:
downH=itemRP[1]-item[1]
return downH
def Vertical_Lines_Intersect(line1,line2):
if line1[3]>=line2[1]:
flag=0
HD=line1[0]-line2[0]
elif (line1[3]<line2[1])and (line1[3]>=line2[3]):
flag=1
HD=line1[0]-line2[0]
elif (line1[1]<=line2[1]) and (line1[1]>line2[3]):
flag=1
HD=line1[0]-line2[0]
elif line1[1]<=line2[3]:
flag=0
HD=line1[0]-line2[0]
else:
flag=1
HD=line1[0]-line2[0]
return flag,HD
def Point_Vertical_Line(item,RPXY):
LUPXY=[RPXY[0]-item[0],RPXY[1]]
LBPXY=[RPXY[0]-item[0],RPXY[1]-item[1]]
leftLine=[]
leftLine.extend(LUPXY)
leftLine.extend(LBPXY)
return leftLine
def leftWAtPoint(item,Item,itemRP,RPNXY):
leftLine=Point_Vertical_Line(item,itemRP)
RP_NUM=len(RPNXY)
if RP_NUM!=0:
sRPNXY=np.array(sorted(list(RPNXY), key=lambda x:x[0]))
sRBPNXY=sRPNXY.copy()
sRBPNXY[:,2]=sRPNXY[:,2]-Item[sRPNXY[:,0],1]
rightLine=np.concatenate((sRPNXY[:,1:3],sRBPNXY[:,1:3]),axis=1)
allLeftW=[]
for i in range(RP_NUM):
flag,HD=Vertical_Lines_Intersect(leftLine,rightLine[i,:])
if (flag==1) and (HD>=0):
allLeftW.append(HD)
if len(allLeftW)==0:
leftW=itemRP[0]-item[0]
else:
leftW=min(allLeftW)
else:
leftW=itemRP[0]-item[0]
return leftW
def Update_itemRP(itemRP,downH,leftW):
h=itemRP[1]-downH
w=itemRP[0]-leftW
return [w,h]
class Rectangle:
def __init__(self, x, y,w,h):
self.x = x
self.y = y
self.width = w
self.height = h
def finalPos(item,Item,itemRP,RPNXY):
while 1:
downH=downHAtPoint(item,Item,itemRP,RPNXY)
leftW=0
itemRP=Update_itemRP(itemRP,downH,leftW)
downH=0
leftW=leftWAtPoint(item,Item,itemRP,RPNXY)
itemRP=Update_itemRP(itemRP,downH,leftW)
if (downH==0)and (leftW==0):
finalRP=itemRP
break
return finalRP
def overlap(item,Item,itemRP,RPNXY):
flagOL=0
itemLBP=[itemRP[0]-item[0],itemRP[1]-item[1]]
A = Rectangle(itemLBP[0],itemLBP[1],item[0],item[1])
num=len(RPNXY)
if num>0:
for i in range(num):
width=Item[RPNXY[i][0],0]
height=Item[RPNXY[i][0],1]
LBPXY=[RPNXY[i][1]-width,RPNXY[i][2]-height]
B = Rectangle(LBPXY[0],LBPXY[1],width,height)
area=rectint(A,B)
if area>0:
flagOL=1
break
return flagOL
def rectint(rect1, rect2):
xl1, yb1, xr1, yt1 = rect1.x,rect1.y,rect1.x+rect1.width,rect1.y+rect1.height
xl2, yb2, xr2, yt2 = rect2.x,rect2.y,rect2.x+rect2.width,rect2.y+rect2.height
xmin = max(xl1, xl2)
ymin = max(yb1, yb2)
xmax = min(xr1, xr2)
ymax = min(yt1, yt2)
width = xmax - xmin
height = ymax - ymin
if width <= 0 or height <= 0:
return 0
cross_square = width * height
return cross_square