Skip to content

Instantly share code, notes, and snippets.

@ljyloi
Created August 3, 2023 08:55
Show Gist options
  • Save ljyloi/194f07de29dd4bc19763d5e0622ade6a to your computer and use it in GitHub Desktop.
Save ljyloi/194f07de29dd4bc19763d5e0622ade6a to your computer and use it in GitHub Desktop.
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