class PackerTestCaseTrue(unittest.TestCase): def setUp(self): shape_data = "A 582 58 22;B 732 58 20;C 770 450.7 17" bin_data = u"A 双面胡桃木哑光25mm 2430 1210 1 0;B 双面白布纹哑光18mm 2430*1210*18;C 单面胡桃木哑光9mm 2430 1210 1" BORDER = 5 # 产品间的间隔, 算在损耗中 self.packer = PackerSolution(shape_data, bin_data, border=BORDER) def tearDown(self): self.packer = None def test_validation(self): self.assertTrue(self.packer.is_valid()) def test_get_bins_key(self): self.assertEqual(len(self.packer.get_bins_key()), 3) self.assertEqual(self.packer.get_bins_key()[0], 'A') def test_get_bin_data(self): self.assertEqual(len(self.packer.get_bin_data('A')), 7) self.assertEqual(self.packer.get_bin_data('A', key='width'), 2430) self.assertEqual(self.packer.get_bin_data('A', key='height'), 1210) self.assertEqual(self.packer.get_bin_data('A', key='is_texture'), 1) self.assertEqual(self.packer.get_bin_data('A', key='shape_num')[0], 22) def test_find_solution(self): res = self.packer.find_solution() self.assertEqual(len(res), 3) self.assertLess(res[2]['rate'], 1) self.assertLess(res[2]['algo_id'], 60) res = self.packer.find_solution(algo_list=[0]) self.assertEqual(res[2]['algo_id'], 0)
def find_best_piece(input_data): # 保存之前的五个结果,求方差 rate_res = list() num_pic = 1 best_pic = 1 best_rate = 0 best_rates = None while True: # 创建分析对象 packer = PackerSolution(input_data['shape_data'], input_data['bin_data'], border=int(input_data['border']), num_pic=num_pic) if packer.is_valid(): # 选择几种经常用的算法 res = packer.find_solution(algo_list=[0, 4, 40, 8, 20, 44, 24]) # 平均使用率 total_rate = 0 for data in res: total_rate += data['rate'] tmp_avg_rate = total_rate / len(res) # 记录最大值 if best_rate < tmp_avg_rate: best_rate = tmp_avg_rate best_pic = num_pic best_rates = [(data['bin_key'], data['rate']) for data in res] if num_pic > my_settings.NUM_SAVE: rate_res.append(tmp_avg_rate) np_arr = np.array(rate_res[-1 * my_settings.NUM_SAVE:]) var_rate = np_arr.var() if var_rate < my_settings.MAX_VAR_RATE: # 少于阈值返回最佳值 return { 'error': False, 'piece': best_pic, 'rates': best_rates } else: rate_res.append(tmp_avg_rate) else: return {'error': True, 'info': packer.error_info()} num_pic += 1
def find_best_piece(shape_data, bin_data, border=5): rate_res = list() num_pic = 1 best_pic = 1 best_rate = 0 best_rates = {} while True: # 创建分析对象 packer = PackerSolution( shape_data, bin_data, border=border, num_pic=num_pic ) if packer.is_valid(): # 选择几种经常用的算法 res = packer.find_solution(algo_list=[0, 4, 40, 8, 20, 44, 24]) # 平均使用率 total_rate = 0 for data in res: total_rate += data['rate'] tmp_avg_rate = total_rate / len(res) # 记录最大值 if best_rate < tmp_avg_rate: best_rate = tmp_avg_rate best_pic = num_pic for data in res: best_rates[data['bin_key']] = data['rate'] if num_pic > my_settings.NUM_SAVE: rate_res.append(tmp_avg_rate) np_arr = np.array(rate_res[-1 * my_settings.NUM_SAVE:]) var_rate = np_arr.var() if var_rate < my_settings.MAX_VAR_RATE: # 少于阈值返回最佳值 return False, {'piece': best_pic, 'rates': best_rates} else: rate_res.append(tmp_avg_rate) else: return True, {'info': packer.error_info()} num_pic += 1
class PackerTestCaseFalse(unittest.TestCase): def tearDown(self): self.packer = None def test_validation(self): shape_data = "A 582 58 22;B 732 58 20;D 770 450 17" bin_data = u"A 双面胡桃木哑光25mm 2430 1210 1 0;B 双面白布纹哑光18mm 2430*1210*18;C 单面胡桃木哑光9mm 2430 1210 1" BORDER = 5 # 产品间的间隔, 算在损耗中 self.packer = PackerSolution(shape_data, bin_data, border=BORDER) self.assertFalse(self.packer.is_valid()) shape_data = "A 582 58 22;B 732 58 20;D 770 450 17" bin_data = u"A 双面胡桃木哑光25mm 2430 1210 1 0;B 双面白布纹哑光18mm 2430*1210*18;C 单面胡桃木哑光9mm 2430 1210 1" self.packer = PackerSolution(shape_data, bin_data) self.assertFalse(self.packer.is_valid()) shape_data = "A 582 58 22;B 732 58 20" bin_data = u"A 双面胡桃木哑光25mm 2430*1210*2 否;B 双面白布纹哑光18mm 2430*1210*18 是;C 单面胡桃木哑光9mm 2430 1210 1" self.packer = PackerSolution(shape_data, bin_data) self.assertTrue(self.packer.is_valid()) shape_data = "A 582 58 22;B 732.4 58.5 20" bin_data = u"A 双面胡桃木哑光25mm 2430*1210*2 否;B 双面白布纹哑光18mm 2430*1210*18 是;C 单面胡桃木哑光9mm 2430 1210 1" self.packer = PackerSolution(shape_data, bin_data, border=10) self.assertTrue(self.packer.is_valid()) self.packer.find_solution(algo_list=[0]) shape_data = '[{"SkuCode":"32050052","Length":548.0,"Width":397.0,"Amount":11}]' bin_data = u'[{"SkuCode":"32050052","ItemName":"三聚氰胺板-双面仿古白哑光单保(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050519","ItemName":"三聚氰胺板-双面仿古白哑光双保(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050093","ItemName":"三聚氰胺板-双面仿古白哑光(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32050038","ItemName":"三聚氰胺板-双面仿古白哑光单保(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32050076","ItemName":"三聚氰胺板-双面仿古白哑光(5mm)","SkuName":"2440*1220*5mm","HasGrain":"否"},{"SkuCode":"32050434","ItemName":"三聚氰胺板-2#8834双面仿橡胶木哑光(12mm)","SkuName":"2440*1220*12mm","HasGrain":"是"},{"SkuCode":"32010003","ItemName":"中纤板(E1)-B(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32010004","ItemName":"中纤板(E1)-B(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050051","ItemName":"三聚氰胺板-双面仿古白哑光(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"}]' bins_num = '[{"SkuCode":"32050052","Amount":2,"SkuName":"1440*720*25mm"},{"SkuCode":"32050052","Amount":1,"SkuName":"740*720*25mm"}]' self.packer = PackerSolution(shape_data, bin_data, bins_num=bins_num) self.assertTrue(self.packer.is_valid()) self.assertEqual( self.packer.get_bin_data('32050052', key='is_texture'), 0) self.packer.find_solution(algo_list=[40]) shape_data = '[{"SkuCode":"32050052","Length":548.5,"Width":397.0,"Amount":11}]' bin_data = u'[{"SkuCode":"32050052","ItemName":"三聚氰胺板-双面仿古白哑光单保(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050519","ItemName":"三聚氰胺板-双面仿古白哑光双保(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050093","ItemName":"三聚氰胺板-双面仿古白哑光(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32050038","ItemName":"三聚氰胺板-双面仿古白哑光单保(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32050076","ItemName":"三聚氰胺板-双面仿古白哑光(5mm)","SkuName":"2440*1220*5mm","HasGrain":"否"},{"SkuCode":"32050434","ItemName":"三聚氰胺板-2#8834双面仿橡胶木哑光(12mm)","SkuName":"2440*1220*12mm","HasGrain":"是"},{"SkuCode":"32010003","ItemName":"中纤板(E1)-B(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32010004","ItemName":"中纤板(E1)-B(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050051","ItemName":"三聚氰胺板-双面仿古白哑光(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"}]' self.packer = PackerSolution(shape_data, bin_data, empty_section_min_height=10, empty_section_min_size=1000) self.assertTrue(self.packer.is_valid()) self.assertEqual( self.packer.get_bin_data('32050052', key='is_texture'), 0) self.packer.find_solution(algo_list=[40])
# encoding=utf8 from package import PackerSolution from package_tools import find_the_same_position, use_rate, draw_one_pic if __name__ == '__main__': shape_data = '[{"SkuCode":"32050093","Length":1019.0,"Width":30.3,"Amount":4},{"SkuCode":"32050093","Length":319.0,"Width":30.0,"Amount":20},{"SkuCode":"32050076","Length":406.0,"Width":291.0,"Amount":20},{"SkuCode":"32050434","Length":396.0,"Width":110.0,"Amount":20},{"SkuCode":"32050434","Length":295.0,"Width":110.0,"Amount":40},{"SkuCode":"32050038","Length":484.0,"Width":190.0,"Amount":20},{"SkuCode":"32050076","Length":396.0,"Width":456.0,"Amount":10},{"SkuCode":"32050093","Length":386.0,"Width":362.0,"Amount":20},{"SkuCode":"32050093","Length":446.0,"Width":75.0,"Amount":10},{"SkuCode":"32050519","Length":516.0,"Width":397.0,"Amount":10},{"SkuCode":"32050052","Length":516.0,"Width":397.0,"Amount":10},{"SkuCode":"32050038","Length":340.0,"Width":55.0,"Amount":10},{"SkuCode":"32050038","Length":1294.0,"Width":398.0,"Amount":9},{"SkuCode":"32050093","Length":1444.0,"Width":296.0,"Amount":9},{"SkuCode":"32010004","Length":1056.0,"Width":279.0,"Amount":9},{"SkuCode":"32010004","Length":1200.0,"Width":330.0,"Amount":9},{"SkuCode":"32050051","Length":2010.0,"Width":128.0,"Amount":18},{"SkuCode":"32050052","Length":1444.0,"Width":456.0,"Amount":9},{"SkuCode":"32050052","Length":1444.0,"Width":163.0,"Amount":9}]' bin_data = u'[{"SkuCode":"32050093","ItemName":"三聚氰胺板-双面仿古白哑光(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32050076","ItemName":"三聚氰胺板-双面仿古白哑光(5mm)","SkuName":"2440*1220*5mm","HasGrain":"否"},{"SkuCode":"32050434","ItemName":"三聚氰胺板-2#8834双面仿橡胶木哑光(12mm)","SkuName":"2440*1220*12mm","HasGrain":"是"},{"SkuCode":"32050038","ItemName":"三聚氰胺板-双面仿古白哑光单保(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32050519","ItemName":"三聚氰胺板-双面仿古白哑光双保(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050052","ItemName":"三聚氰胺板-双面仿古白哑光单保(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32010004","ItemName":"中纤板(E1)-B(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050051","ItemName":"三聚氰胺板-双面仿古白哑光(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"}]' packer = PackerSolution(shape_data, bin_data, border=5, num_pic=2, empty_section_min_size=100000) if packer.is_valid(): res = packer.find_solution(algo_list=[0, 4, 40, 8, 20]) print res for data in res: best_solution = data['solution'] bins_list = data['bins_list'] shape_list = packer.get_bin_data(data['bin_key'], key='shape_list') # 计算使用率 rate_list = list() for s_id in range(0, len(best_solution)): r = use_rate(best_solution[s_id], bins_list[s_id][0], bins_list[s_id][1]) rate_list.append(r) title = u'平均利用率: %s' % str(data['rate']) # 返回唯一的排版列表,以及数量 same_bin_list = find_the_same_position(best_solution) draw_one_pic(best_solution, rate_list, width=2430, height=1210, path='package_min_b' + data['bin_key'], border=1, num_list=same_bin_list, title=title, shapes=shape_list, empty_positions=data['empty_sections'])
def package_main_function(input_data, pathname): bins_num = None min_size = None min_height = None min_width = None cut_linear_p = 30 # 切割线重要系数 empty_section_p = 70 # 余料重要系数 if 'bins_num' in input_data.keys(): if input_data['bins_num'] != '': bins_num = input_data['bins_num'] min_size = int(input_data['min_size']) min_height = int(input_data['min_height']) min_width = int(input_data['min_width']) if 'use_rate_p' in input_data.keys(): cut_linear_p = int(input_data['cut_linear_p']) empty_section_p = int(input_data['empty_section_p']) if 'effective_rate' in input_data.keys(): effective_rate = float(input_data['empty_section_p']) else: effective_rate = EFFECTIVE_RATE # 创建分析对象 packer = PackerSolution(input_data['shape_data'], input_data['bin_data'], border=int(input_data['border']), bins_num=bins_num, empty_section_min_size=min_size, empty_section_min_height=min_height, empty_section_min_width=min_width, cut_linear_p=cut_linear_p, empty_section_p=empty_section_p) algo_list = None if 'algo_list' in input_data.keys(): algo_list = [int(x) for x in input_data.getlist('algo_list')] # 若数据没有错,返回结果 if packer.is_valid(): res = packer.find_solution(algo_list=algo_list) statistics_data = [] # 汇总报告 for data in res: best_solution = data['solution'] empty_sections = data['empty_sections'] bins_list = data['bins_list'] shape_list = packer.get_bin_data(data['bin_key'], key='shape_list') shape_num = packer.get_bin_data(data['bin_key'], key='shape_num') name = packer.get_bin_data(data['bin_key'], key='name') # 计算总利用率 = 余料使用率/2 + 组件利用率 ,余料面积的1/2 有效余料 rate_list = list() # 组件使用率 total_rate_list = list() # 总利用率 empty_ares_list = list() # 余料面积 for s_id in range(0, len(best_solution)): r = use_rate(best_solution[s_id], bins_list[s_id][0], bins_list[s_id][1]) empty_r = use_rate(empty_sections[s_id], bins_list[s_id][0], bins_list[s_id][1]) rate_list.append(r) total_rate_list.append( float("%0.4f" % (empty_r * effective_rate + r))) # 余料总面积 empty_ares_list.append(empty_ares(empty_sections[s_id])) title = 'average rate: %s' % str(data['rate']) # 返回唯一的排版列表,以及数量 same_bin_list = find_the_same_position(best_solution) draw_one_pic(best_solution, rate_list, bins_list=bins_list, path=pathname + data['bin_key'], border=1, num_list=same_bin_list, title=title, shapes=shape_list, empty_positions=data['empty_sections']) # 保存统计信息 statistics_data.append({ 'error': False, 'rate': data['rate'], 'num_sheet': len(best_solution), 'detail': detail_text(shape_list, best_solution, same_bin_list), 'num_shape': str(shape_num)[1:-1], 'same_bin_list': str(same_bin_list)[1:-1], 'sheet_num_shape': str([len(s) for s in best_solution])[1:-1], 'rates': str(rate_list)[1:-1], 'sheet': name, 'name': data['bin_key'] + ' ' + name + u' 切割线(mm):%s' % str(data['cut_linear']), 'bin_type': data['bin_key'], 'pic_url': pathname + data['bin_key'] + '.png', 'empty_sections': detail_empty_sections( empty_sections, shape_list, packer.get_border(), packer.get_bin_data(data['bin_key'], key='is_texture'), packer.get_bin_data(data['bin_key'], key='is_vertical')), 'algo_id': data['algo_id'], 'total_rates': str(total_rate_list)[1:-1], 'empty_section_ares': str(empty_ares_list)[1:-1], }) # 返回结果 return {'statistics_data': statistics_data, 'error': False} else: # 有错误,返回错误信息 return {'error': True, 'info': packer.error_info()}