Created
August 3, 2023 08:55
-
-
Save ljyloi/194f07de29dd4bc19763d5e0622ade6a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cv2 | |
import numpy as np | |
class Rect: | |
def __init__(self, width:int, height:int, number=0) -> None: | |
self.width, self.height = width, height | |
self.number = number | |
pass | |
def area(self) : | |
return self.width * self.height | |
def rotate(self) : | |
return Rect(self.height, self.width) | |
def __str__(self): | |
return f"({self.width},{self.height})" | |
def cover(self, b): | |
if self.width > b.width and self.height > b.height: | |
return True | |
if self.height > b.width and self.width > b.height: | |
return True | |
return False | |
class WorkPieceInfo: | |
# t 代表物料类型 | |
# num 代表物料编号 | |
# 平面直角坐标系 x1,y1 左下角, x2,y2 右上角 | |
def __init__(self, t, num, x1, y1, x2, y2) -> None: | |
self.t, self.num, self.x1, self.y1, self.x2, self.y2 = t, num, x1, y1, x2, y2 | |
def __str__(self): | |
return f"物料类型:{self.t} 物料序号:{self.num} 左上角:({self.x1},{self.y2}) 右下角:({self.x2},{self.y1})" | |
class LeftRectMeterial(Rect): | |
# t 代表物料类型 | |
# num 代表物料编号 | |
# x, y 代表左下角坐标 | |
# width, height 代表宽度和高度 | |
def __init__(self, t, width:int, height:int, x:int=0, y:int=0, num = 0) -> None: | |
self.t = t | |
self.num = num | |
Rect.__init__(self, width, height) | |
self.x = x | |
self.y = y | |
def draw(self, image:np.ndarray): | |
cv2.rectangle(image, (self.x, self.y), (self.x + self.width, self.y + self.height), (0, 255, 0), 2) | |
# cut, 不旋转,保证能切分情况下计算方案,返回尽量均匀的方案 | |
# 返回一个 list 包含所有方案,每个方案是一个元组 (起始物料, WorkPieceInfo, 剩余矩形物料数量, 矩形物料...) | |
def cut(self, b:Rect): | |
plans = [] | |
workPieceInfo = WorkPieceInfo(self.t, self.num, self.x, self.y, self.x + b.width, self.y + b.height) | |
# 完全消耗 | |
if self.width == b.width and self.height == b.height: | |
plans.append((self, workPieceInfo, 0)) | |
return plans | |
# 消耗一侧 | |
if self.width == b.width: | |
plans.append((self, workPieceInfo, 1, LeftRectMeterial(self.t, self.x, self.y + b.height, self.width, self.height - b.height, self.num))) | |
return plans | |
if self.height == b.height: | |
plans.append((self, workPieceInfo, 1, LeftRectMeterial(self.t, self.x + b.width, self.y, self.width - b.width, self.height, self.num))) | |
return plans | |
# 总是试图切分为两个比较均匀的矩形 | |
if b.width > b.height: | |
plans.append((self, workPieceInfo, 2, LeftRectMeterial(self.t, self.x + b.width, self.y, self.width - b.width, self.height, self.num), LeftRectMeterial(self.t, self.x, self.y + b.height, b.width, self.height - b.height, self.num))) | |
return plans | |
plans.append((self, workPieceInfo, 2, LeftRectMeterial(self.t, self.x + b.width, self.y, self.width - b.width, b.height, self.num), LeftRectMeterial(self.t, self.x, self.y + b.height, self.width, self.height - b.height, self.num))) | |
return plans | |
# 不保证切分,考虑旋转的情况下,获取所有可能方案 | |
def get_cut_plans(self, b:Rect): | |
plans = [] | |
if self.width > b.width and self.height > b.height: | |
plans.extend(self.cut(b)) | |
if self.height > b.width and self.width > b.height: | |
plans.extend(self.cut(b.rotate())) | |
return plans | |
material_list = [Rect(4000, 3000, 1), Rect(5000, 3000, 2), Rect(6000, 2000, 3)] | |
work_piece_list = [Rect(1500, 1000, 1), Rect(1500, 1000, 2), Rect(1500, 1000, 3), Rect(1500, 1000, 4), Rect(1500, 1000, 5), Rect(2000, 1000, 6), Rect(2000, 1000, 7)] | |
def cal_left_meterials(left_material_list): | |
result = 0 | |
for i in left_material_list: | |
result += i.area() | |
return result | |
def output_plan(plans): | |
for i in plans: | |
print(str(i)) | |
def output_p(p): | |
print("输出计划:") | |
print(str(p[0])) | |
print(str(p[1])) | |
print(" 输出切割后物料:") | |
for i in range(3, 3 + p[2]): | |
print(" {}".format(str(p[i]))) | |
def dfs(left_work_piece_list, left_material_set:set ,material_list, piece_plans, m_cnt): | |
if len(left_work_piece_list) == 0: | |
print(cal_left_meterials(left_material_set)) | |
output_plan(piece_plans) | |
print(m_cnt) | |
return | |
cur_work_piece = left_work_piece_list[0] | |
plans = [] | |
for material in left_material_set: | |
plans += material.get_cut_plans(cur_work_piece) | |
if len(plans) == 0: | |
m_cnt += 1 | |
for i in range(len(material_list)) : | |
material = material_list[i] | |
if material_list[i].cover(cur_work_piece): | |
new_left_material = LeftRectMeterial(i, material.width, material.height, num=m_cnt) | |
left_material_set.add(new_left_material) | |
plans += new_left_material.get_cut_plans(cur_work_piece) | |
if len(plans) == 0: | |
return | |
print("当前 workpiece", str(cur_work_piece)) | |
plan = plans[0] | |
output_p(plan) | |
left_material_set.remove(plan[0]) | |
piece_plans.append(plan[1]) | |
for i in range(3, 3 + plan[2]): | |
left_material_set.add(plan[i]) | |
dfs(left_work_piece_list[1:], left_material_set, material_list, piece_plans, m_cnt) | |
piece_plans.pop() | |
for i in range(3, 3 + plan[2]): | |
left_material_set.remove(plan[i]) | |
left_material_set.add(plan[0]) | |
sorted_work_piece_list = sorted(work_piece_list, key=lambda obj: max(obj.height, obj.width), reverse = True) | |
for i in sorted_work_piece_list: | |
print(str(i)) | |
dfs(sorted_work_piece_list, set(), material_list, [], 0) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment