基于 三维装箱问题的算法研究-1 的基础上,对整个装箱过程发生的函数进行封装

# -*- coding: utf-8 -*-
from matplotlib import pyplot as plt
#设置图表刻度等格式
from matplotlib.ticker import MultipleLocator, FormatStrFormatter 
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

#make_pic内置函数
def box(ax,x, y, z, dx, dy, dz, color='red'):
    xx = [x, x, x+dx, x+dx, x]
    yy = [y, y+dy, y+dy, y, y]
    kwargs = {'alpha': 1, 'color': color}
    ax.plot3D(xx, yy, [z]*5, **kwargs)#下底
    ax.plot3D(xx, yy, [z+dz]*5, **kwargs)#上底
    ax.plot3D([x, x], [y, y], [z, z+dz], **kwargs)
    ax.plot3D([x, x], [y+dy, y+dy], [z, z+dz], **kwargs)
    ax.plot3D([x+dx, x+dx], [y+dy, y+dy], [z, z+dz], **kwargs)
    ax.plot3D([x+dx, x+dx], [y, y], [z, z+dz], **kwargs)
    return ax
#显示图形的函数:Items = [[num[0],num[1],num[2],num[3],num[4],num[5],num[6]],]
def make_pic(Items):
    fig = plt.figure()
    ax = Axes3D(fig)
    ax.xaxis.set_major_locator(MultipleLocator(50)) 
    ax.yaxis.set_major_locator(MultipleLocator(50)) 
    ax.zaxis.set_major_locator(MultipleLocator(50)) 
    for num in Items:
        box(ax,num[0],num[1],num[2],num[3],num[4],num[5],num[6])
    plt.title('Cube')
    plt.show()
#把尺寸数据生成绘图数据
def make(O,C,color):
    data = [O[0],O[1],O[2],C[0],C[1],C[2],color]
    return data
#可用点的生成方法
def newsite(O,B_i):
    # 在X轴方向上生成
    O1 = (O[0]+B_i[0],O[1],O[2])
    # 在Y轴方向上生成
    O2 = (O[0],O[1]+B_i[1],O[2])
    # 在Z轴方向上生成
    O3 = (O[0],O[1],O[2]+B_i[2])
    return [O1,O2,O3]
#3.拟人化依次堆叠方体
def packing3D(show_num,color,O,Box_list):
    canput = 0
    O_items = [O]
    O_pop = []
    for i in range(0,len(Box_list)):
        #货物次序应小于等于可用点数量,如:第四个货物i=3,使用列表内的第4个放置点O_items[3],i+1即常见意义的第几个,len即总数,可用点总数要大于等于目前个数
        if i+1 <= len(O_items):
            #如果放置点放置货物后,三个方向都不会超过箱体限制,则认为可以堆放
            if O_items[i-1][0]+Box_list[i][0]<=C[0] and O_items[i-1][1]+Box_list[i][1]<=C[1] and O_items[i-1][2]+Box_list[i][2]<=C[2]:
                #使用放置点,添加一个图显信息
                new_show = make(O_items[i-1],Box_list[i],color)
                if new_show not in show_num:
                    show_num.append(make(O_items[i-1],Box_list[i],color))
                #计数加1
                canput = len(show_num) - 1
                #把堆叠后产生的新的点,加入放置点列表
                for new_O in newsite(O_items[i-1],Box_list[i]):
                    #保证放入的可用点是不重复的
                    if new_O not in O_items:
                        O_items.append(new_O)
            #如果轮到的这个放置点不可用
            else:
                #把这个可用点弹出弃用
                O_pop.append(O_items.pop(i-1))
                #弃用可用点后,货物次序应小于等于剩余可用点数量
                if i+1 <= len(O_items):# and len(O_items)-1>=0:
                    #当可用点一直不可用时
                    while O_items[i-1][0]+Box_list[i][0]>C[0] or O_items[i-1][1]+Box_list[i][1]>C[1] or O_items[i-1][2]+Box_list[i][2]>C[2]:
                        #一直把可用点弹出弃用
                        O_pop.append(O_items.pop(i-1))
                        #如果弹出后货物次序超出剩余可用点,则认为无法继续放置
                        if i-1 > len(O_items)-1:
                            break
                    #货物次序应小于等于剩余可用点数量
                    if i+1 <= len(O_items):
                        #如果不再超出限制,在这个可用点上堆叠
                        new_show = make(O_items[i-1],Box_list[i],color)
                        if new_show not in show_num:
                            show_num.append(make(O_items[i-1],Box_list[i],color))
                        #计数加1
                        canput = len(show_num) - 1
                        #把堆叠后产生的新的点,加入放置点列表
                        for new_O in newsite(O_items[i-1],Box_list[i]):
                            #保证放入的可用点是不重复的
                            if new_O not in O_items:
                                O_items.append(new_O)
    return canput,O_items,O_pop
#<<<---写一个函数专门用来调整方向和计算剩余货物
def surplus(num,Box_list,change):#change='ab','bc','ac',0有三组对调可能,共6种朝向
    new_Box_list = Box_list[num-1:-1]
    if num == 0:
        new_Box_list = Box_list
    if change == 'ab':
        for i in range(0,len(new_Box_list)):
            new_Box_list[i]=(new_Box_list[i][1],new_Box_list[i][0],new_Box_list[i][2])
    elif change == 'bc':
        for i in range(0,len(new_Box_list)):
            new_Box_list[i]=(new_Box_list[i][0],new_Box_list[i][2],new_Box_list[i][1])
    elif change == 'ac':
        for i in range(0,len(new_Box_list)):
            new_Box_list[i]=(new_Box_list[i][2],new_Box_list[i][1],new_Box_list[i][0])
    elif change == 0:
        return new_Box_list
    else:
        return new_Box_list
    return new_Box_list
#残余点二次分配函数
def twice(show_num,color,O_pop,Box_list):
    for a2 in O_pop:
        if a2[0]==0 and a2[1]==0:
            Plan = packing3D(show_num,color,a2,Box_list)
            Box_list = surplus(Plan[0],Box_list,0)
        elif a2[1]==0 and a2[2]==0:
            Plan = packing3D(show_num,color,a2,Box_list)
            Box_list = surplus(Plan[0],Box_list,0)
        elif a2[0]==0 and a2[2]==0:
            Plan = packing3D(show_num,color,a2,Box_list)
            Box_list = surplus(Plan[0],Box_list,0)
    return Box_list

调用这些函数进行一次初步装箱和二次转向装箱

#1.给定空间容器C      4.2*1.9*1.8
O = (0,0,0)           #原点坐标
C = (420,190,180)    #箱体长宽高
color = 'red'         #箱体颜色
#显示箱体
show_num = [make(O,C,color)]

#2.给定有限量个方体 500个(60,40,50)的方体,当方体大小存在差异时,我们将按照体积大小降序排列,优先摆放大体积的
B=[(40,50,60) for num in range(0,1200)]

#把货物第一次装箱
Plan1 = packing3D(show_num,'blue',(0,0,0),B)
#print(len(show_num))

#把剩下的货物分出来
B2 = surplus(Plan1[0],B,'ab')

#把剩下的货物再次尝试装箱,针对三个在轴线上的点为新的原点
twice(show_num,'orange',Plan1[2],B2)
print(len(show_num))

make_pic(show_num)

最终显示效果

python三维装箱库 三维装箱算法python_python


可以看到在第二次发生简单转向后,箱体的利用率再一次得到提升,这个时候装载率达到114/箱,那么如果全部货物1200件,1200/114向上舍入,11车能够装完