29、三维装箱

from pyscipopt import Model, quicksum
from vtk import *
import vtk
import random as rd
import time
import numpy as np
import functools

#数据生成,输入为箱子种类数,箱子最大长、最小长、最大宽、最小宽、商品个数、商品最大长、最小长、最大宽、最小宽
#输出为生成的箱子列表和商品列表
def data_generate_3d(nums_box, max_edge_box, min_edge_box, nums_good, max_edge_good, min_edge_good):

    #随机生成箱子
    boxs = []
    for i in range(nums_box):
        boxs.append([int((max_edge_box-min_edge_box) * rd.random() + min_edge_box),
                     int((max_edge_box-min_edge_box) * rd.random() + min_edge_box),
                     int((max_edge_box-min_edge_box) * rd.random() + min_edge_box)])

    #随机生成商品
    goods = []
    for i in range(nums_good):
        goods.append([int((max_edge_good-min_edge_good) * rd.random() + min_edge_good),
                      int((max_edge_good-min_edge_good) * rd.random() + min_edge_good),
                      int((max_edge_good-min_edge_good) * rd.random() + min_edge_good)])

    return boxs,goods

#二维商品排序用
def cmp_2d(x,y):
    if x[0] < y[0]:
        return -1
    elif x[0] > y[0]:
        return 1
    elif x[1] < y[1]:
        return -1
    elif x[1] > y[1]:
        return 1
    else:
        return 0

#三维商品排序用
def cmp_3d(x,y):
    if x[0] < y[0]:
        return -1
    elif x[0] > y[0]:
        return 1
    elif x[1] < y[1]:
        return -1
    elif x[1] > y[1]:
        return 1
    elif x[2] < y[2]:
        return -1
    elif x[2] > y[2]:
        return 1
    else:
        return 0

def data_pre(boxs, goods):

    #箱子长边作长,放前面
    for i in range(len(boxs)):
        boxs[i] = sorted(boxs[i], reverse=True)

    #箱子排序,大的放前面
    boxs = sorted(boxs, key=functools.cmp_to_key(cmp_3d), reverse=True)

    #箱子种类去重
    i = 0
    while i < len(boxs) - 1:
        j = i + 1
        while j < len(boxs):
            if boxs[i][0] == boxs[j][0] and boxs[i][1] == boxs[j][1] and boxs[i][2] == boxs[j][2]:
                del boxs[j]
            else:
                j += 1
        i += 1

    #商品长边作长,放前面
    for i in range(len(goods)):
        goods[i] = sorted(goods[i], reverse=True)

    #商品排序,大的放前面
    goods = sorted(goods, key=functools.cmp_to_key(cmp_3d), reverse=True)

    return boxs,goods

#检验是否每个商品都能有一个箱子放下它
def check_3d(boxs, goods):
    for good in goods:
        can_put = False
        for box in boxs:
            if good[0] <= box[0] and good[1] <= box[1] and good[2] <= box[2]:
                can_put = True
                break
        if not can_put:
            print(good,"太大,无合适箱子")
            return False
    return True

#三维装箱整数规划
def IP_3d(boxs, goods, time_limit):

    m = len(boxs)
    n = len(goods)

    M = max([max(boxs[i]) for i in range(m)])*10

    model = Model("IP_3d")

    #对X、Y,i为包裹下标,j为商品下标,x[i][j]=1代表第j件商品放进第i个包裹里,y[i]=1表示开启第i个包裹
    X = [[model.addVar(vtype="B", name="X[%s,%s]" % (i, j)) for j in range(n)] for i in range(m*n)]
    Y = [model.addVar(vtype="B", name="Y[%s]" % i) for i in range(m*n)]
    #包裹面积向量,[n个boxs[0],n个boxs[1],...,n个boxs[m-1]]
    c = [boxs[i][0]*boxs[i][1]*boxs[i][2] for i in range(len(boxs)) for j in range(len(goods))]
    cb = [boxs[i] for i in range(len(boxs)) for j in range(len(goods))]

    #码放形式,1代表(l,w), 0代表(w,l)
    tp1 = [model.addVar(vtype="B", name="tp1[%s]" % i) for i in range(n)]
    tp2 = [model.addVar(vtype="B", name="tp2[%s]" % i) for i in range(n)]
    tp3 = [model.addVar(vtype="B", name="tp3[%s]" % i) for i in range(n)]
    tp4 = [model.addVar(vtype="B", name="tp4[%s]" % i) for i in range(n)]
    tp5 = [model.addVar(vtype="B", name="tp5[%s]" % i) for i in range(n)]
    tp6 = [model.addVar(vtype="B", name="tp6[%s]" % i) for i in range(n)]

    #码放长、宽、坐标x、y、z
    L = [model.addVar(vtype="I", name="L[%s]" % i) for i in range(n)]
    W = [model.addVar(vtype="I", name="W[%s]" % i) for i in range(n)]
    H = [model.addVar(vtype="I", name="H[%s]" % i) for i in range(n)]
    x = [model.addVar(vtype="I", name="x[%s]" % i) for i in range(n)]
    y = [model.addVar(vtype="I", name="y[%s]" % i) for i in range(n)]
    z = [model.addVar(vtype="I", name="y[%s]" % i) for i in range(n)]

    #选择变量,fx[i][j]=1代表i在j的左边(小),fy[i][j]=1同理,f[i][j][k]=1代表j、k同时在第i个箱子中
    fx = [[model.addVar(vtype="B", name="fx[%s,%s]" % (i, j)) for j in range(n)] for i in range(n)]
    fy = [[model.addVar(vtype="B", name="fy[%s,%s]" % (i, j)) for j in range(n)] for i in range(n)]
    fz = [[model.addVar(vtype="B", name="fz[%s,%s]" % (i, j)) for j in range(n)] for i in range(n)]
    f = [[[model.addVar(vtype="B", name="f[%s,%s,%s]" % (i, j, k)) for k in range(n)] for j in range(n)] for i in range(m*n)]

    #以总包裹体积最小(即填充率最大)为目标
    model.setObjective(quicksum(Y[i]*c[i] for i in range(m*n)), "minimize")

    # 使用前必须开启
    for i in range(m * n):
        for j in range(n):
            model.addCons(X[i][j] - Y[i] <= 0)

    #每个商品都能被装下
    for j in range(n):
        model.addCons(quicksum(X[i][j] for i in range(m * n)) == 1)

    #码放长宽约束
    for j in range(n):
        model.addCons(tp1[j] + tp2[j] + tp3[j] + tp4[j] + tp5[j] + tp6[j] == 1)
        model.addCons(L[j] - goods[j][0] * (tp1[j] + tp2[j]) - goods[j][1] * (tp3[j] + tp4[j]) - goods[j][2] * (tp5[j] + tp6[j]) == 0)
        model.addCons(W[j] - goods[j][0] * (tp3[j] + tp5[j]) - goods[j][1] * (tp1[j] + tp6[j]) - goods[j][2] * (tp2[j] + tp4[j]) == 0)
        model.addCons(H[j] - goods[j][0] * (tp4[j] + tp6[j]) - goods[j][1] * (tp2[j] + tp5[j]) - goods[j][2] * (tp1[j] + tp3[j]) == 0)

    #位置约束,大于0,不超过边界,不相交
    for j in range(n):
        model.addCons(x[j] >= 0)
        model.addCons(y[j] >= 0)
        model.addCons(z[j] >= 0)

    for i in range(m*n):
        for j in range(n):
            model.addCons(x[j] + L[j] - cb[i][0] - M * (1 - X[i][j]) <= 0)
            model.addCons(y[j] + W[j] - cb[i][1] - M * (1 - X[i][j]) <= 0)
            model.addCons(z[j] + H[j] - cb[i][2] - M * (1 - X[i][j]) <= 0)

    for j in range(n):
        for k in range(j+1,n):
            model.addCons(x[j] + L[j] - x[k] - M * (1 - fx[j][k]) <= 0)
            model.addCons(x[k] + L[k] - x[j] - M * (1 - fx[k][j]) <= 0)
            model.addCons(y[j] + W[j] - y[k] - M * (1 - fy[j][k]) <= 0)
            model.addCons(y[k] + W[k] - y[j] - M * (1 - fy[k][j]) <= 0)
            model.addCons(z[j] + H[j] - z[k] - M * (1 - fz[j][k]) <= 0)
            model.addCons(z[k] + H[k] - z[j] - M * (1 - fz[k][j]) <= 0)

    for i in range(m*n):
        for j in range(n):
            for k in range(j+1,n):
                model.addCons(X[i][j] + X[i][k] - 1 - M*(1 - f[i][j][k]) <= 0)

    for j in range(n):
        for k in range(j+1,n):
            model.addCons(fx[j][k] + fx[k][j] + fy[j][k] + fy[k][j] + fz[j][k] + fz[k][j] + quicksum(f[i][j][k] for i in range(m*n)) >= m*n)

    #设置求解时间
    model.setRealParam("limits/time", time_limit)

    model.optimize()
    print("\ngap:",model.getGap())

    #拿结果
    X1 = [[round(model.getVal(X[i][j])) for j in range(n)] for i in range(m * n)]
    L1 = [round(model.getVal(L[i])) for i in range(n)]
    W1 = [round(model.getVal(W[i])) for i in range(n)]
    H1 = [round(model.getVal(H[i])) for i in range(n)]
    x1 = [round(model.getVal(x[i])) for i in range(n)]
    y1 = [round(model.getVal(y[i])) for i in range(n)]
    z1 = [round(model.getVal(z[i])) for i in range(n)]

    L_box = []
    L_goods = []
    L_coordinates = []

    for i in range(m*n):
        goods_i = []
        coordinates_i = []
        for j in range(n):
            if X1[i][j] == 1:
                goods_i.append(goods[j])
                coordinates_i.append([L1[j],W1[j],H1[j],x1[j],y1[j],z1[j]])
        if len(goods_i) > 0:
            L_box.append(cb[i])
            L_goods.append(goods_i)
            L_coordinates.append(coordinates_i)

    return L_box, L_goods, L_coordinates, model.getGap()


def can_put_3d(l, w, h, goods):
    L = max(l,w,h)
    H = min(l,w,h)
    W = l+w+h-L-H

    for good in goods:
        lg = max(good[0], good[1], good[2])
        hg = min(good[0], good[1], good[2])
        wg = good[0] + good[1] + good[2] - lg - hg
        if lg > L or wg > W or hg > H:
            return False
    return True

#先以w为限制码垛,再以l为限制码垛
#输入为长、宽、商品集,输出为箱子个数
def packing_simple(l, w, h, goods):

    #先检查是否每一个商品在此规则下都能放下
    if not can_put_3d(l, w, h, goods):
        return -1

    #以h为限制码垛成条,商品排序,大的放前面
    goods1 = []
    for good in goods:
        if good[0] <= l and good[1] <= w and good[2] <= h:
            goods1.append([good[0], good[1], good[2]])
        elif good[0] <= l and good[2] <= w and good[1] <= h:
            goods1.append([good[0], good[2], good[1]])
        elif good[1] <= l and good[0] <= w and good[2] <= h:
            goods1.append([good[1], good[0], good[2]])
        elif good[1] <= l and good[2] <= w and good[0] <= h:
            goods1.append([good[1], good[2], good[0]])
        elif good[2] <= l and good[0] <= w and good[1] <= h:
            goods1.append([good[2], good[0], good[1]])
        else:
            goods1.append([good[2], good[1], good[0]])

    goods1 = sorted(goods1, key=functools.cmp_to_key(cmp_3d), reverse=True)

    strips = []
    goods1_used = [0 for i in range(len(goods1))]

    while sum(goods1_used) < len(goods1_used):
        l_used = 0
        w_used = 0
        h_used = 0
        for i in range(len(goods1_used)):
            if goods1_used[i] == 0 and h_used + goods1[i][2] <= h:
                l_used = max(l_used, goods1[i][0])
                w_used = max(w_used, goods1[i][1])
                h_used += goods1[i][2]
                goods1_used[i] = 1
        strips.append([l_used, w_used])

    strips = sorted(strips, key=functools.cmp_to_key(cmp_2d), reverse=True)

    #以w为限制码垛成层
    levels = []
    strip_used = [0 for i in range(len(strips))]

    while sum(strip_used) < len(strip_used):
        l_used = 0
        w_used = 0
        for i in range(len(strips)):
            if strip_used[i] == 0 and w_used + strips[i][1] <= w:
                l_used = max(l_used, strips[i][0])
                w_used += strips[i][1]
                strip_used[i] = 1
        levels.append(l_used)

    #再以l为限制码垛
    levels = sorted(levels, reverse=True)
    L_box_unused = [l]

    for level in levels:
        flag = -1
        for i in range(len(L_box_unused)):
            if L_box_unused[i] >= level:
                if flag == -1:
                    flag = i
                elif L_box_unused[i] < L_box_unused[flag]:
                    flag = i
        if flag == -1:
            L_box_unused.append(l - level)
        else:
            L_box_unused[flag] -= level

    return len(L_box_unused)

#选择合适的主箱子
def box_choose_3d(boxs, nums_simplePacking_1, nums_simplePacking_2,nums_simplePacking_3, nums_simplePacking_4,nums_simplePacking_5, nums_simplePacking_6):
    l = -1
    w = -1
    h = -1
    nums = -1
    for i in range(len(boxs)):
        if nums_simplePacking_1[i] != -1:
            if nums == -1 or (nums != -1 and nums > nums_simplePacking_1[i]) or (nums != -1 and nums == nums_simplePacking_1[i] and l * w * h > boxs[i][0] * boxs[i][1] * boxs[i][2]):
                l = boxs[i][0]
                w = boxs[i][1]
                h = boxs[i][2]
                nums = nums_simplePacking_1[i]
        if nums_simplePacking_2[i] != -1:
            if nums == -1 or (nums != -1 and nums > nums_simplePacking_2[i]) or (nums != -1 and nums == nums_simplePacking_2[i] and l * w * h > boxs[i][0] * boxs[i][1] * boxs[i][2]):
                l = boxs[i][0]
                w = boxs[i][2]
                h = boxs[i][1]
                nums = nums_simplePacking_2[i]
        if nums_simplePacking_3[i] != -1:
            if nums == -1 or (nums != -1 and nums > nums_simplePacking_3[i]) or (nums != -1 and nums == nums_simplePacking_3[i] and l * w * h > boxs[i][0] * boxs[i][1] * boxs[i][2]):
                l = boxs[i][1]
                w = boxs[i][0]
                h = boxs[i][2]
                nums = nums_simplePacking_3[i]
        if nums_simplePacking_4[i] != -1:
            if nums == -1 or (nums != -1 and nums > nums_simplePacking_4[i]) or (nums != -1 and nums == nums_simplePacking_4[i] and l * w * h > boxs[i][0] * boxs[i][1] * boxs[i][2]):
                l = boxs[i][1]
                w = boxs[i][2]
                h = boxs[i][0]
                nums = nums_simplePacking_4[i]
        if nums_simplePacking_5[i] != -1:
            if nums == -1 or (nums != -1 and nums > nums_simplePacking_5[i]) or (nums != -1 and nums == nums_simplePacking_5[i] and l * w * h > boxs[i][0] * boxs[i][1] * boxs[i][2]):
                l = boxs[i][2]
                w = boxs[i][0]
                h = boxs[i][1]
                nums = nums_simplePacking_5[i]
        if nums_simplePacking_6[i] != -1:
            if nums == -1 or (nums != -1 and nums > nums_simplePacking_6[i]) or (nums != -1 and nums == nums_simplePacking_6[i] and l * w * h > boxs[i][0] * boxs[i][1] * boxs[i][2]):
                l = boxs[i][2]
                w = boxs[i][1]
                h = boxs[i][0]
                nums = nums_simplePacking_6[i]
    return l,w,h

def packing_3d(l, w, h, goods):
    # 先检查是否每一个商品在此规则下都能放下
    if not can_put_3d(l, w, h, goods):
        return -1

    # 以h为限制码垛成条,商品排序,大的放前面
    goods1 = []
    for good in goods:
        if good[0] <= l and good[1] <= w and good[2] <= h:
            goods1.append([good[0], good[1], good[2]])
        elif good[0] <= l and good[2] <= w and good[1] <= h:
            goods1.append([good[0], good[2], good[1]])
        elif good[1] <= l and good[0] <= w and good[2] <= h:
            goods1.append([good[1], good[0], good[2]])
        elif good[1] <= l and good[2] <= w and good[0] <= h:
            goods1.append([good[1], good[2], good[0]])
        elif good[2] <= l and good[0] <= w and good[1] <= h:
            goods1.append([good[2], good[0], good[1]])
        else:
            goods1.append([good[2], good[1], good[0]])

    goods1 = sorted(goods1, key=functools.cmp_to_key(cmp_3d), reverse=True)

    strips = []
    strips_goods = []
    goods1_used = [0 for i in range(len(goods1))]

    while sum(goods1_used) < len(goods1_used):
        l_used = 0
        w_used = 0
        h_used = 0
        strip_goods = []
        for i in range(len(goods1_used)):
            if goods1_used[i] == 0 and h_used + goods1[i][2] <= h:
                l_used = max(l_used, goods1[i][0])
                w_used = max(w_used, goods1[i][1])
                strip_goods.append([goods1[i][0], goods1[i][1], goods1[i][2], 0, 0, h_used])
                h_used += goods1[i][2]
                goods1_used[i] = 1
        strips.append([l_used, w_used])
        strips_goods.append(strip_goods)

    # 以w为限制码垛成层
    for i in range(len(strips)-1):
        for j in range(i+1,len(strips)):
            if strips[i][0] < strips[j][0] or (strips[i][0] == strips[j][0] and strips[i][1] < strips[j][1]):
                temp = strips[i]
                strips[i] = strips[j]
                strips[j] = temp
                temp1 = strips_goods[i]
                strips_goods[i] = strips_goods[j]
                strips_goods[j] = temp1

    levels = []
    levels_goods = []
    strip_used = [0 for i in range(len(strips))]

    while sum(strip_used) < len(strip_used):
        l_used = 0
        w_used = 0
        level_goods = []
        for i in range(len(strips)):
            if strip_used[i] == 0 and w_used + strips[i][1] <= w:
                l_used = max(l_used, strips[i][0])
                for g in strips_goods[i]:
                    level_goods.append([g[0],g[1],g[2],0,w_used,g[5]])
                w_used += strips[i][1]
                strip_used[i] = 1
        levels.append(l_used)
        levels_goods.append(level_goods)

    # 再以l为限制码垛
    for i in range(len(levels)-1):
        for j in range(i+1,len(levels)):
            if levels[i] < levels[j]:
                temp = levels[i]
                levels[i] = levels[j]
                levels[j] = temp
                temp1 = levels_goods[i]
                levels_goods[i] = levels_goods[j]
                levels_goods[j] = temp1

    L_box_unused = [l]
    L_goods = []
    L_coordinates = []

    L_goods.append([])
    L_coordinates.append([])

    for i in range(len(levels)):
        flag = -1
        for j in range(len(L_box_unused)):
            if L_box_unused[j] >= levels[j]:
                if flag == -1 or (flag != -1 and L_box_unused[j] < L_box_unused[flag]):
                    flag = j
        if flag == -1:
            L_box_unused.append(l - levels[i])
            L_goods.append([levels_goods[i][j][:3] for j in range(len(levels_goods[i]))])
            L_coordinates.append([levels_goods[i]])
        else:
            L_box_unused[flag] -= levels[i]
            L_goods[flag] += [levels_goods[i][j][:3] for j in range(len(levels_goods[i]))]
            if len(L_coordinates[flag]) == 0:
                L_coordinates[flag] += [levels_goods[i]]
            else:
                L_coordinates[flag] += [[[levels_goods[i][j][0], levels_goods[i][j][1], levels_goods[i][j][2], L_coordinates[flag][-1][0][0] + L_coordinates[flag][-1][0][3], levels_goods[i][j][4], levels_goods[i][j][5]] for j in range(len(levels_goods[i]))]]

    L_coordinates_merge = []

    for i in range(len(L_coordinates)):
        L_coordinates_i = []
        for j in range(len(L_coordinates[i])):
            L_coordinates_i += L_coordinates[i][j]
        L_coordinates_merge.append(L_coordinates_i)

    L_box = [[l, w, h] for i in range(len(L_box_unused))]

    return L_box, L_goods, L_coordinates_merge

#正交二叉树启发式,试每一种箱子装下所有的商品需要的个数,取最少的,再去缩减最后一个箱子
def OBT_3d(boxs, goods):

    #分别以长宽作为限制,依次码垛成层
    nums_simplePacking_1 = []
    nums_simplePacking_2 = []
    nums_simplePacking_3 = []
    nums_simplePacking_4 = []
    nums_simplePacking_5 = []
    nums_simplePacking_6 = []

    for box in boxs:
        nums_simplePacking_1.append(packing_simple(box[0], box[1], box[2], goods))
        nums_simplePacking_2.append(packing_simple(box[0], box[2], box[1], goods))
        nums_simplePacking_3.append(packing_simple(box[1], box[0], box[2], goods))
        nums_simplePacking_4.append(packing_simple(box[1], box[2], box[0], goods))
        nums_simplePacking_5.append(packing_simple(box[2], box[0], box[1], goods))
        nums_simplePacking_6.append(packing_simple(box[2], box[1], box[0], goods))

    #找箱子数最少的箱子
    l,w,h = box_choose_3d(boxs, nums_simplePacking_1, nums_simplePacking_2,nums_simplePacking_3, nums_simplePacking_4,nums_simplePacking_5, nums_simplePacking_6)

    #装载
    L_box, L_goods, L_coordinates = packing_3d(l, w, h, goods)

    return L_box, L_goods, L_coordinates

#检验结果中的商品集是否和原始的商品集一致
def goods_check(goods, L_goods):

    nums = 0
    for gs in L_goods:
        nums += len(gs)

    if len(goods) == nums:
        return True

    return False

#任务分流汇总
#给一系列箱子和商品(箱子可用个数不限),推荐结果
def stacking_3d(boxs, goods, time_limit, nums_limit):

    #长宽预处理,降序排序,箱子去重
    boxs, goods = data_pre(boxs, goods)

    #这里是否所有的商品均至少有一个箱子可以装下,若有商品超出规格则直接返回
    if not check_3d(boxs, goods):
        return [[], []]

    #当商品数超过一定数量时,直接采用启发式算法
    if len(goods) > nums_limit:
        return OBT_3d(boxs, goods)

    # 多类箱子,应用整数规划求解
    L_box, L_goods, L_coordinates, gap = IP_3d(boxs, goods, time_limit)

    # 结果检验,当求解器的结果有问题(商品数不符时)采用混合OBT求解方案
    if not goods_check(goods, L_goods):
        return OBT_3d(boxs, goods)

    # gap较大时,用启发式方法比较,取优
    if gap >= 0.01:
        print("尝试采用启发式方法")
        L_box1, L_goods1, L_coordinates1 = OBT_3d(boxs, goods)
        if sum([L_box[i][0]*L_box[i][1]*L_box[i][2] for i in range(len(L_box))]) > sum([L_box1[i][0]*L_box1[i][1]*L_box1[i][2] for i in range(len(L_box1))]) and goods_check(goods, L_goods1):
            print("采用启发式方法")
            L_box, L_goods, L_coordinates = L_box1, L_goods1, L_coordinates1

    return L_box, L_goods, L_coordinates

#添加商品图形
def Addcube_3d(ren, coordinate, edge_max, x_re, y_re, z_re):
    cube = vtk.vtkCubeSource()
    cube.SetXLength(coordinate[0]/edge_max)
    cube.SetYLength(coordinate[1]/edge_max)
    cube.SetZLength(coordinate[2]/edge_max)
    cube.Update()

    translation = vtkTransform()
    translation.Translate((coordinate[3] + coordinate[0]/2.0)/edge_max + x_re, (coordinate[4] + coordinate[1]/2.0)/edge_max + y_re, (coordinate[5] + coordinate[2]/2.0)/edge_max + z_re)
    transformFilter = vtkTransformPolyDataFilter()
    transformFilter.SetInputConnection(cube.GetOutputPort())
    transformFilter.SetTransform(translation)
    transformFilter.Update()

    transformedMapper = vtkPolyDataMapper()
    transformedMapper.SetInputConnection(transformFilter.GetOutputPort())
    transformedActor = vtkActor()
    transformedActor.SetMapper(transformedMapper)
    transformedActor.GetProperty().SetColor((rd.uniform(0, 1), rd.uniform(0, 1), rd.uniform(0, 1)))

    ren.AddActor(transformedActor)

def png_save(renWin, name):
    windowToImageFilter = vtkWindowToImageFilter()
    windowToImageFilter.SetInput(renWin)
    windowToImageFilter.Update()
    writer = vtkPNGWriter()
    writer.SetFileName(name)
    writer.SetInputConnection(windowToImageFilter.GetOutputPort())
    writer.Write()

#三维展示,输入为箱子集和商品集,包裹的箱子和商品集一一对应
def show_3d(L_box, L_coordinates):

    nums = len(L_box)
    edge_max = max([max(L_box[i]) for i in range(len(L_box))]) if max([max(L_box[i]) for i in range(len(L_box))]) > 0 else 1

    #预设参数
    gap = 0.25
    CL_p = 1.1
    CW_p = nums + gap * (nums - 1)
    CH_p = 0.01
    gap = 0.25

    x_re = -0.5
    y_re = -0.5
    z_re = -0.5

    #渲染及渲染窗口,并根据捕捉的鼠标事件执行相应的操作
    ren = vtk.vtkRenderer()
    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(ren)
    renWin.SetSize(1200, 600)
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)


    """画容器"""
    for i in range(nums):

        cube = vtk.vtkCubeSource()
        cube.SetXLength(L_box[i][0]/edge_max)
        cube.SetYLength(L_box[i][1]/edge_max)
        cube.SetZLength(L_box[i][2]/edge_max)
        cube.Update()

        translation = vtkTransform()
        translation.Translate(L_box[i][0]/edge_max/2.0 + x_re, L_box[i][1]/edge_max/2.0 + i + gap*i + y_re, L_box[i][2]/edge_max/2.0 + z_re)
        transformFilter = vtkTransformPolyDataFilter()
        transformFilter.SetInputConnection(cube.GetOutputPort())
        transformFilter.SetTransform(translation)
        transformFilter.Update()

        transformedMapper = vtkPolyDataMapper()
        transformedMapper.SetInputConnection(transformFilter.GetOutputPort())
        transformedActor = vtkActor()
        transformedActor.SetMapper(transformedMapper)
        transformedActor.GetProperty().SetColor((1, 1, 1))
        transformedActor.GetProperty().SetRepresentationToWireframe()

        ren.AddActor(transformedActor)

    """画托盘"""
    cube = vtk.vtkCubeSource()
    cube.SetXLength(CL_p)
    cube.SetYLength(CW_p)
    cube.SetZLength(CH_p)
    cube.Update()

    translation = vtkTransform()
    translation.Translate(CL_p/2.0 + x_re, CW_p/2.0 + y_re, -CH_p/2.0 + z_re)
    transformFilter = vtkTransformPolyDataFilter()
    transformFilter.SetInputConnection(cube.GetOutputPort())
    transformFilter.SetTransform(translation)
    transformFilter.Update()

    transformedMapper = vtkPolyDataMapper()
    transformedMapper.SetInputConnection(transformFilter.GetOutputPort())
    transformedActor = vtkActor()
    transformedActor.SetMapper(transformedMapper)
    transformedActor.GetProperty().SetColor((0.2, 0.4, 0.8))

    ren.AddActor(transformedActor)

    for i in range(len(L_coordinates)):
        for j in range(len(L_coordinates[i])):
            Addcube_3d(ren, L_coordinates[i][j], edge_max, x_re, i + gap*i + y_re, z_re)

    camera = vtk.vtkCamera()
    camera.SetPosition(5, -0.5, 2)
    camera.SetViewUp(0, 0, 1)
    ren.SetActiveCamera(camera)

    iren.Initialize()
    renWin.Render()
    # 保存过程
    png_save(renWin, "result_D3.png")
    # 展示
    iren.Start()

# 数值实验, 输入为箱子种类数,箱子最大容积、最小容积、商品个数、商品最大体积、商品最小体积、时间限制、实验次数,
# 输出为OBT平均装载率、OBT平均时间、整数规划平均装载率、整数规划平均时间
def experiment_3d(nums_box, max_edge_box, min_edge_box, nums_good, max_edge_good, min_edge_good, time_limit, times_experiment):

    rate_OBT = []
    time_OBT = []
    rate_IP = []
    time_IP = []

    for i in range(times_experiment):
        for j in range(20):
            print("--------------------------", nums_good, "----------------------", i)
        boxs, goods = data_generate_3d(nums_box, max_edge_box, min_edge_box, nums_good, max_edge_good, min_edge_good)
        # 长宽预处理,降序排序,箱子去重
        boxs, goods = data_pre(boxs, goods)
        t1 = time.clock()
        L_box1, L_goods1, L_coordinates1 = OBT_3d(boxs, goods)
        t2 = time.clock()
        L_box2, L_goods2, L_coordinates2, gap = IP_3d(boxs, goods, time_limit)
        t3 = time.clock()
        if sum([L_box1[i][0]*L_box1[i][1]*L_box1[i][2] for i in range(len(L_box1))]) > 0 and goods_check(goods, L_goods2):
            rate_OBT.append(sum([goods[i][0]*goods[i][1]*goods[i][2] for i in range(len(goods))])/sum([L_box1[i][0]*L_box1[i][1]*L_box1[i][2] for i in range(len(L_box1))]))
        else:
            rate_OBT.append(0)
        time_OBT.append(t2-t1)
        if sum([L_box2[i][0]*L_box2[i][1]*L_box2[i][2] for i in range(len(L_box2))]) > 0 and goods_check(goods, L_goods2):
            rate_IP.append(sum([goods[i][0]*goods[i][1]*goods[i][2] for i in range(len(goods))])/sum([L_box2[i][0]*L_box2[i][1]*L_box2[i][2] for i in range(len(L_box2))]))
        else:
            rate_IP.append(0)

        time_IP.append(t3-t2)

    print("rate_OBT:", np.mean(rate_OBT))
    print("rate_IP:", np.mean(rate_IP))
    print("time_OBT:", np.mean(time_OBT))
    print("time_IP:", np.mean(time_IP))

    return np.mean(rate_OBT), np.mean(rate_IP), np.mean(time_OBT), np.mean(time_IP)

if __name__ == "__main__":

    # #生成箱子集和商品集,计算并展示
    # boxs,goods = data_generate_3d(nums_box = 2, max_edge_box = 20, min_edge_box = 10, nums_good = 10, max_edge_good = 10, min_edge_good = 1)
    # # L_box, L_goods, L_coordinates= stacking_3d(boxs, goods, time_limit = 100, nums_limit = 50)
    # L_box, L_goods, L_coordinates = OBT_3d(boxs, goods)
    # print(L_box, L_coordinates)
    # show_3d(L_box, L_coordinates)

    #数值实验
    rate_OBT = []
    rate_IP = []
    time_OBT = []
    time_IP = []
    for i in range(30):
        r1,r2,r3,r4 = experiment_3d(nums_box = 2, max_edge_box = 20, min_edge_box = 10, nums_good = i+1, max_edge_good = 10, min_edge_good = 1, time_limit = 100, times_experiment=50)
        rate_OBT.append(r1)
        rate_IP.append(r2)
        time_OBT.append(r3)
        time_IP.append(r4)
        print("-------------------------", i+1, "个商品测试完成")
        print(rate_OBT)
        print(rate_IP)
        print(time_OBT)
        print(time_IP)




 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值