예제 #1
0
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)
예제 #2
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
# 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'])
예제 #5
0
if __name__ == '__main__':
    shape_data = '[{"SkuCode":"32050093","Length":596.0,"Width":475.0,"Amount":2},{"SkuCode":"32050038","Length":596.0,"Width":475.0,"Amount":2},{"SkuCode":"32050093","Length":463.0,"Width":320.0,"Amount":2},{"SkuCode":"32050076","Length":581.0,"Width":471.0,"Amount":4},{"SkuCode":"32050051","Length":1188.0,"Width":296.0,"Amount":2},{"SkuCode":"32050093","Length":320.0,"Width":168.0,"Amount":3},{"SkuCode":"32050093","Length":1910.0,"Width":236.0,"Amount":1},{"SkuCode":"32050093","Length":1910.0,"Width":168.0,"Amount":1},{"SkuCode":"32050051","Length":1910.0,"Width":342.0,"Amount":1},{"SkuCode":"32050093","Length":573.0,"Width":342.0,"Amount":3},{"SkuCode":"32050093","Length":1910.0,"Width":360.0,"Amount":1},{"SkuCode":"32050093","Length":1910.0,"Width":296.0,"Amount":1},{"SkuCode":"32050434","Length":1900.0,"Width":600.0,"Amount":2},{"SkuCode":"32050051","Length":1910.0,"Width":396.0,"Amount":1},{"SkuCode":"32050051","Length":1910.0,"Width":128.0,"Amount":1},{"SkuCode":"32050093","Length":1142.0,"Width":60.0,"Amount":2},{"SkuCode":"32050038","Length":1160.0,"Width":539.0,"Amount":2}]'

    bin_data = '[{"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":"32050051","ItemName":"三聚氰胺板-双面仿古白哑光(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"},{"SkuCode":"32050434","ItemName":"三聚氰胺板-2#8834双面仿橡胶木哑光(12mm)","SkuName":"2440*1220*12mm","HasGrain":"是"}]'

    filename = u'功能床TESTDI5A00001.txt'

    num_pic = 1
    # 保存之前的五个结果,求方差
    rate_res = list()
    num_save = 5
    max_var_rate = 0.00001
    while True:
        packer = PackerSolution(shape_data,
                                bin_data,
                                border=5,
                                num_pic=num_pic)
        if packer.is_valid():
            tmp_avg_rate = main_process(num_pic, packer, filename)
            if num_pic > num_save:
                rate_res.append(tmp_avg_rate)
                np_arr = np.array(rate_res[-1 * num_save:])
                var_rate = np_arr.var()
                print('%d: var=%f' % (num_pic, var_rate))
                if var_rate < max_var_rate:
                    break
            else:
                rate_res.append(tmp_avg_rate)

        else:
            print packer.error_info()
if __name__ == '__main__':
    # 床
    shape_data_1 = '[{"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_1 = '[{"SkuCode":"32050038","ItemName":"三聚氰胺板-双面仿古白哑光单保(18mm)","SkuName":"2440*1220*18mm","HasGrain":"否"},{"SkuCode":"32050093","ItemName":"三聚氰胺板-双面仿古白哑光(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":"否"},{"SkuCode":"32050052","ItemName":"三聚氰胺板-双面仿古白哑光单保(25mm)","SkuName":"2440*1220*25mm","HasGrain":"否"}]'
    # 床头柜
    bin_data_2 = '[{"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":"否"}]'
    shape_data_2 = '[{"SkuCode":"32050093","Length":319.0,"Width":136.0,"Amount":10},{"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}]'

    for num_1 in range(1, 4):
        for num_2 in range(num_1+1, 5):
            # 合并数据
            shape_data = merge_shape_data(shape_data_1, shape_data_2, num_1, num_2)
            bin_data = merge_bin_data(bin_data_1, bin_data_2)

            for num_pic in range(1, 30):
                packer = PackerSolution(shape_data, bin_data, border=5, num_pic=num_pic)
                if packer.is_valid():
                    res = packer.find_solution(algo_list=[0, 4, 40, 8, 20, 44])
                    for data in res:
                        best_solution = data['solution']
                        bins_list = data['bins_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)

                        with open('bed_DI1B_DIA_mix_2.txt', 'a+') as f:
                            f.write('%d,%d,%d,%s,%d,%s\n' % (num_1, num_2, num_pic, data['bin_key'],
                                                             len(best_solution), str(data['rate'])))
예제 #7
0
 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)
예제 #8
0
    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])
예제 #9
0
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()}