精华内容
下载资源
问答
  • 二维装箱算法
    千次阅读
    2021-11-30 12:50:48

    一、获取代码方式

    获取代码方式1:
    完整代码已上传我的资源: 【二维装箱】基于matlab遗传算法求解矩形地块二维装箱放置优化问题【含Matlab源码 1556期】
    点击上面蓝色字体,直接付费下载,即可。

    获取代码方式2:
    付费专栏优化求解(Matlab)

    备注:
    点击上面蓝色字体付费专栏优化求解(Matlab),扫描上面二维码,付费299.9元订阅海神之光博客付费专栏,凭支付凭证,私信博主,可免费获得5份本博客上传CSDN资源代码(有效期为订阅日起,三天内有效);
    点击CSDN资源下载链接:5份本博客上传CSDN资源代码

    二、二维装箱简介

    1 引言
    二维装箱问题是随着计算机技术的产生而出现的,大量出现 在 机 械 制 造、皮革服装加 工、汽车、造船、货物装载以及大规模集成电路板的设计等领域。排样布局的优劣直接与材料的成本及经济效益相关。目前主要存在的问题是材料的利用率偏低

    更多相关内容
  • 二维箱式包装 所罗门·博斯韦尔 一个基于JukkaJylänki的文章包装箱的的二维箱包装库 该库用于脱机打包。 Jukka文章中的所有算法试探法和优化都包括在内。 可获得用Flask和ReactJS制作的Web演示。打包性能随优化...
  • 该项目是我们工程学院尼斯索菲亚理工学院算法课程的作业。 问题与装箱有关:我们有尺寸相同的容器和各种尺寸的箱子。 目标是使用尽可能少的容器来装满所有的盒子。 他们 == 方法== 我们的方法是对所有高度递减的框...
  • 多个车子,N个箱子,用二维矩形方式进行装车。采用二叉树实现。java
  • 二维矩形装箱算法--二叉树--java实现.rar
  • 【python】欧姆龙智能物料排布之二维装箱算法实现

    千次阅读 热门讨论 2020-02-24 10:13:52
    算法衍生自欧姆龙杯大赛智能物料排布赛项 最终实现给出一个在一个指定的平面区域内,不同形状、大小、数量的平面物料的最节省空间的排布方式,且具有实时显示功能 问题描述: 排布区域 平面区域为40×50(X方向×...

    本算法衍生自欧姆龙杯大赛智能物料排布赛项

    简介

    最终能实现给出一个在一个指定的平面区域内,不同形状、大小、数量的平面物料的最节省空间的排布方式,且具有实时显示功能

    问题描述:

    • 排布区域
      平面区域为40×50(X方向×Y方向)的矩形。
    • 物料描述
      1、包含矩形和三角形两种形状。
      2、矩形和三角形的总数为25个,每种形状至少有一个。
      3、矩形和三角形的面积、数量随机。
    • 排布规则
      1、所有物料都必须使用
      2、所有物料之间不能叠放
      3、物料可以进行任意角度的旋转
      4、物料不可进行镜像翻转
      5、所有物料的排布位置不能超过排布区域

    程序界面:


    (注:此图还没排完,处在暂停当中)


    • 显示框内红色线为此桢的排列的高度最高峰;灰色线为100%利用率高度线
    • 主线程mywin使用pyqt5实现界面的显示和刷新。在程序接收到物块坐标数据,并点击开始之后,线程Calculator开始对坐标数据进行计算,同时,mywin将以100hz的频率刷新显示。

    源码链接:

    https://github.com/Ralphson/2D-binning_omron


    突然有了契机,来回忆一下程序的实现

    运算框架


    • 其中排矩形是一个类贪心算法,保障底层排序时的空隙尽量小
    • 排三角形的逻辑是在矩形表面处的点上做遍历,在一个点上取重心低的姿态存储,一个三角形取所有位置低的姿态为最终姿态
    • 回溯则是在所有图形都排完后,对结果按照从高到低的顺序依次重新寻找位置:如示例界面中所示,红色的为当前最高峰、灰色为100%线,故数据集的回溯为从最高峰开始依次剔除100%线以上的所有图形并重新排列

    重要功能的实现

    1. 点在图形内检测:
      如何判断一个点是否在图形内(三角形、矩形甚至任意多边形),我用的方法是判断点与角的关系,即判断点是否在该角内,再重复所有角达到判断是否在图形内的目的。

      其中两组向量叉乘:
      O P ⃗ × O A ⃗ 和 O P ⃗ × O B ⃗ \vec {OP} \times\vec {OA}和\vec {OP} \times \vec {OB} OP ×OA OP ×OB
      反映了向量OP与向量OAOB的位置关系:如果点P在角AOB内,则结果异号;若在边上,则结果包含0;若在外面,则结果同号。判断一个角如上,判断所有角同理。
    def judgePointInner(x, y, location):
    	'''
    	判断点在多边形内
    	进行区域规整的快速判断
    	:param x: 判断点x
    	:param y: 判断点y
    	:param location:待检测区域。必须是按照边的顺序,连着给的点; 图形坐标:[[], [], [], []]
    	:return:在里面为-1,在外面为1,在边上0
    	'''
    	# 判断是否在包络外
    	x_set = [i[0] for i in location]
    	y_set = [i[1] for i in location]
    	x_min = min(x_set)
    	x_max = max(x_set)
    	y_min = min(y_set)
    	y_max = max(y_set)
    	if x < x_min or x > x_max:
    	    return 1    # 在外面
    	if y < y_min or y > y_max:
    	    return 1    # 在外面
    	
    	flag = -1   # -1在里面;0在边上;1在外面
    	for i in range(len(location)):
    	    point = location[i]
    	    if i == 0:
    	        point_next = location[i + 1]
    	        point_bef = location[-1]
    	    elif i == len(location) - 1:
    	        point_next = location[0]
    	        point_bef = location[i - 1]
    	    else:
    	        point_next = location[i + 1]
    	        point_bef = location[i - 1]
    	    v0 = [x - point[0], y - point[1]]
    	    v1 = [point_next[0] - point[0], point_next[1] - point[1]]
    	    v2 = [point_bef[0] - point[0], point_bef[1] - point[1]]
    	
    	    # 叉乘之积
    	    answer = (v0[0]*v1[1] - v1[0]*v0[1]) * (v0[0]*v2[1] - v2[0]*v0[1])
    	    if answer > 0:  # 在外面
    	        flag = 1
    	        return flag
    	    if answer == 0:	# 在边上
    	        flag = 0
    	
    	return flag # 在里面
    
    1. 图形的重叠检测:
      在有了点是否在图形内的判断的基础上,就容易实现图形的重叠检测:
      (这套判断适用于任意多边形之间的判断,对于三角形和矩形的情景应该有简化的方案)
    现有图形A、B
    判断:
    1、A是否在B的矩形包络内;
    2、A的重心是否在B内,B的重心是否在A内;
    3、A的所有点是否在B内;
    4、A的所有边是否与B相交;
    
    def judgeCoin(self, Xc, Yc, location):
    	'''
    	待排图形与已排图形的重叠检测
    	根据已排图形来
    	
    	location:待检查图形, [[], [], []]
    	Xc:形心x
    	Yc:形心y
    	:return:    重叠T/不重叠F
    	'''
    	#判断是否在包络外
    	x_list = [i[0] for i in location]
    	y_list = [i[1] for i in location]
    	x_min = min(x_list) # 带派图形的x最低值
    	x_max = max(x_list)
    	y_min = min(y_list)
    	y_max = max(y_list)
    	
    	# 遍历已经排放图形的顶点信息
    	for Point in self.settledPoints: # [[Yc, y_max, Xc, gender, location, num, s], ..]
    	    settledGraph = Point[4] # [[], [], [], []] # 以排图形
    	    x_list_set = [i[0] for i in settledGraph]
    	    y_list_set = [i[1] for i in settledGraph]
    	    x_min_set = min(x_list_set)  # 已派图形的x最低值
    	    x_max_set = max(x_list_set)
    	    y_min_set = min(y_list_set)
    	    y_max_set = max(y_list_set)
    	    # 离得太远的直接跳过
    	    if x_max<x_min_set or x_min>x_max_set or y_max<y_min_set or y_min>y_max_set:
    	        continue
    	
    	    # 检查重心
    	    exist0 = self.judgePointInner(Xc, Yc, settledGraph)
    	    if exist0 == -1 or exist0 == 0:   # 形心不能在里面或边上
    	        return True # 形心在里面
    	
    	    # 检查各个点
    	    for i in range(len(location)):
    	        x = location[i][0]
    	        y = location[i][1]
    	        exist1 = self.judgePointInner(x, y, settledGraph)  # 图形的顶点
    	        if exist1  == -1:   # 顶点可以在边上但不能在里面
    	            return True #形心在里面
    	
    	    # 检查边界线香蕉
    	    line_already = []   # 已排图形的线
    	    if len(settledGraph) == 3:    # 三角形
    	        l = [[settledGraph[0], settledGraph[1]],   # 边线1
    	              [settledGraph[1], settledGraph[2]],   # 边线2
    	              [settledGraph[2], settledGraph[0]],   # 边线3
    	              # [settledGraph[0], [(settledGraph[1][0] + settledGraph[2][0])/2, (settledGraph[1][1] + settledGraph[2][1])/2]] ,   # 中线1
    	              # [settledGraph[1], [(settledGraph[0][0] + settledGraph[2][0])/2, (settledGraph[0][1] + settledGraph[2][1])/2]]      # 中线2
    	            ]
    	        line_already.extend(l)
    	    else:   # 矩形
    	        l = [[settledGraph[0], settledGraph[1]],  # 边线1
    	             [settledGraph[1], settledGraph[2]],  # 边线2
    	             [settledGraph[2], settledGraph[3]],  # 边线3
    	             [settledGraph[3], settledGraph[0]],  # 边线4
    	             # [settledGraph[0], settledGraph[2]],  # 中线1
    	             # [settledGraph[1], settledGraph[3]]  # 中线2
    	            ]
    	        line_already.extend(l)
    	    line_noready = []   # 未排图形的线
    	    if len(location) == 3:
    	        l = [[location[0], location[1]],   # 边线1
    	             [location[1], location[2]],   # 边线2
    	             [location[2], location[0]],   # 边线3
    	             [location[0], [(location[1][0] + location[2][0]) / 2, (location[1][1] + location[2][1]) / 2]],    # 中线1
    	             [location[1], [(location[0][0] + location[2][0]) / 2, (location[0][1] + location[2][1]) / 2]]    # 中线2
    	            ]
    	        line_noready.extend(l)
    	    else:   # 矩形
    	        l = [[location[0], location[1]],  # 边线1
    	             [location[1], location[2]],  # 边线2
    	             [location[2], location[3]],  # 边线3
    	             [location[3], location[0]],  # 边线4
    	             [location[0], location[2]],  # 中线1
    	             [location[1], location[3]]  # 中线2
    	            ]
    	        line_noready.extend(l)
    	
    	    for line0 in line_already:
    	        for line1 in line_noready:
    	            exist = self.judgeLineCross(line1, line0) # 检查线段
    	            if exist:
    	                return True # 出现香蕉
    	
    	return False    # 检查中没有发现重叠的情况
    
    1. 待补充

    另:

    python有现成的图形检测的包shapely,嫌自己开发麻烦的话直接pip install即可,但是在效率上貌似不如自己写逻辑来的好

    欢迎交流

    展开全文
  • 此源程序为解决一集装箱装载问题,但是为维和三维算法提供了很好的思路。
  • 二维装箱问 题 是 随 着 计 算 机 技 术 的 产 生 而 出现的,大量出现 在 机 械 制 造、皮 革 服 装 加 工、汽 车、造船、货物装载以及大规模集成电路板的设计等领域。排样布局 的 优 劣 直 接 与 材 料 的 成 本 ...

    1 简介

    通过分析人工排列的思考过程和实际经验,提出一种解决二维规则物体排列问题的算法。通过计算可放置点和可放置空间,高效解决物块的排列问题。应用遗传算法,求得最优的排列方案。实际应用证明了该算法的有效性。二维装箱问 题 是 随 着 计 算 机 技 术 的 产 生 而 出现的,大量出现 在 机 械 制 造、皮 革 服 装 加 工、汽 车、造船、货物装载以及大规模集成电路板的设计等领域。排样布局 的 优 劣 直 接 与 材 料 的 成 本 及 经 济效益相关。目前主要存在的问题是材料的利用率偏低,造成巨大的浪费。对于规模较大的生产厂家来说,即使是材料利 用 率 有 很 小 的 提 升,也 会 带 来巨大的经济效益。

    2 部分代码

    function [F,newX2]=objection(X)

    global  data NUM layout

    %%

    H=200;

    L=200;

    X1=X(1:NUM);

    X2=X(NUM+1:end);

    X2=X2(X1);

    newX2=X2;

    for i=1:NUM

      if X1(i)>1

        newX2(i)=sum(layout(1:X1(i)-1))+X2(i);

      end

    end

    % F=sum(data(newX2,4));

    % return;

    flag=1;

    F=0;

    sizeX=0;%记录左右以用长度

    sizeY0=0;%记录上下以用长度

    sizeY1=0;

    j=1;

    k=1;

    for i=1:NUM

        if i==1

    %        sizeX=data(newX2(i),1);

           sizeX=data(newX2(i),1)+data(newX2(i),5);

           sizeY0=0;

           sizeY1=data(newX2(i),2)+data(newX2(i),4);

           F=F+data(newX2(i),6);

           row(1,1)=newX2(i);

        else

            if sizeX+data(newX2(i),1)+data(newX2(i),5)<H

               if sizeY0+data(newX2(i),2)+data(newX2(i),4)<L

                 sizeY1=max(sizeY1,sizeY0+data(newX2(i),2)+data(newX2(i),4));

                 sizeX=sizeX+data(newX2(i),1)+data(newX2(i),5);

                 F=F+data(newX2(i),6);

                 k=k+1;

                 row(j,k)=newX2(i); %记录摆放顺序

               else

    %                flag=0;

                   break;

               end

            else

                if sizeY1+data(newX2(i),2)+data(newX2(i),4)<L

                    sizeY0=sizeY1;

                    sizeY1=sizeY1+data(newX2(i),2)+data(newX2(i),4);

                    sizeX=data(newX2(i),1);

                    F=F-data(newX2(i-1),6)+data(newX2(i),7)+data(newX2(i),6);%表示去除最右侧单元体东西间距,计算容积率之和

                    j=j+1;

                    k=1;

                    row(j,k)=newX2(i);%记录摆放顺序

                else

    %                 F=F-data(newX2(i-1),6)+data(newX2(i),8)+data(newX2(i),6);

    %                 flag=0;

                    break;

                end

            end

        end

    end

    row %记录摆放顺序

    [a,b]=size(row);

    B=row(a,:);%

    for i=1:b

        if B(i)~=0

         F=F-data(B(i),6)+data(B(i),8); %最后一层,去除南北间距后,计算容积率之和

        end

    end

    if flag==0

       F=F+1000; 

    end


     

    3 仿真结果

    4 参考文献

    [1]田大肥, 申喜, and 周巍. "二维装箱问题的遗传算法求解." 舰船电子工程 34.1(2014):5.

    博主简介:擅长智能优化算法、神经网络预测、信号处理、元胞自动机、图像处理、路径规划、无人机等多种领域的Matlab仿真,相关matlab代码问题可私信交流。

    部分理论引用网络文献,若有侵权联系博主删除。

    展开全文
  • 二维装箱算法实现矩形地块放置优化问题,使用遗传算法优化
  • 1 题目 将若干个矩形物品装进矩形箱子中,并且在...2 装箱算法 2.1 所有装箱算法 参考【A Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin Packing】 以下我将会介绍其中一.

    在这里插入图片描述

    1 题目

    将若干个矩形物品装进矩形箱子中,并且在装箱的过程中不允许将矩形物品斜着放,即平行于横坐标。一般来说求解的目标是最小化箱子的箱子数目或者是箱子空间占用率。

    当该算法适用于矩阵存储时,求解的最优目标是箱子的最大化空间占用率。以下即是求解的过程

    2 装箱算法

    2.1 所有装箱算法

    参考【A Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin Packing

    在这里插入图片描述

    以下我将会介绍其中一种叫Bottom-Left装箱算法。算法过程就是,矩形从箱子的右上角开始进入,先尽可能向下移动,再向左移动,一直循环,直至不再移动。在以下算法过程中,以0-1背包问题的思路去实现,即某个矩形装进箱子,则flag相应为1,未装进的flag为0。输出单个箱子占用率。

    2.2 Bottom-Left具体算法过程

    初始化是,输入箱子大小[W,H]

    再输入每一个矩形的长和宽

    4 5

    4 7

    4 2

    4 4

    7 4

    初始装箱顺序为:12345

    在这里插入图片描述

    第一步:装第一个矩形,从右上角进入,一直向下移动,然后移动一直向左移动,直到左下角。用一个列表记录装进箱子的矩阵。表示为【x,y,width,height】x和y使右上角坐标。该矩形的flag标记为1。

    在这里插入图片描述

    第二步:装第二个矩形,先将矩形放入右上角,再判断第二个矩形是否与箱子中的矩形是否相交(overlap函数)。如果相交,就不放进箱子,换下一个矩形,如果不相交,计算可向下移动的距离(downHAtPoint函数),向下移动,并更新矩形位置(Update_itemRP函数),最后计算可向左移动的距离(leftWAtPoint函数),向左移动,并更新位置,直至可移动距离为0。将第二个矩形最终位置信息【x,y,width,height】添加进列表。该矩形的flag标记未1。

    在这里插入图片描述

    第三步:剩下的矩形,和第二步一样。如果该矩形装不进箱子,就换下一个矩阵,继续装,直至遍历完所有箱子。

    在这里插入图片描述

    3 Python 实现

    本算法实现中,只用了一个箱子。如果想要多个箱子来装,可以修改本人去掉注释的地方,启用下一个箱子。

    3.1 main.py主函数

    from tools import *
    import random
    
    #   BL(bottom-up left-justified)法求解二位装箱问题
    #   @BetterBench
    #   思想:首先将选中的物体放在箱子的右上角,然后尽量向下向左作连续移动,直到不能移动为止
    # 输入参数
    itemNum=30 #物品数目
    AllItem=np.array([[random.randint(1, 5) for j in range(1, 3)] for i in range(1,itemNum+1)])  #随机生成30个物品,[width,height]
    Bin=[10,10] #箱子宽度与高度
    ran=list(range(itemNum))
    random.shuffle(ran) #随机生成装箱序列
    
    ansBXY=np.zeros((itemNum,3))  #[箱子编号,X坐标,Y坐标]
    RPNXY=[];
    BinNum=1;
    flagItem=np.zeros(itemNum) #标记物品是否被装入箱子,0没有装入,1装入
    # 开始装箱
    
    for i in range(itemNum):
        if flagItem[ran[i]]==0:
            item=AllItem[ran[i],:]
            itemRP=Bin  #起点全部在箱子右上角顶点
            flagOL=overlap(item,AllItem,itemRP,RPNXY) #如果重合flagOL=1;反之flagOL=0
            if flagOL==0:
                itemRP=finalPos(item,AllItem,itemRP,RPNXY) #更新物品从当前位置向下向左移动后到最终位置后右上角顶点坐标
                RPNXY.append([ran[i],itemRP[0],itemRP[1]]) # 记录装进箱子的矩形【ID,width,height】
                flagItem[ran[i]]=1
    # 启用第下一个箱子
    # if list(flagItem).count(0)>0:
    #     BinNum=BinNum+1
    #     RPNXY=[]
    

    输出哪些矩形被装进箱子

    print(flagItem)
    

    array([0., 0., 1., 1., 1., 0., 1., 0., 1., 1., 0., 0., 1., 1., 1., 1., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.])

    计算箱子占用率

    rect_area = 0
    bin_area = Bin[0]*Bin[1]
    for id in RPNXY:
      width,height = AllItem[id[0]]
      rect_area += width*height
    print('占用率:{}'.format(rect_area/bin_area))
    

    占用率:0.81

    可视化装箱后的结果

    import matplotlib.pyplot as plt
    import matplotlib.patches as patches
    import random
    fig, ax = plt.subplots(1, 1)
    ax1 = fig.gca()
    for i in RPNXY:
        width,height = AllItem[i[0]]
        rx,ry = i[1],i[2]
        lx,ly = rx-width,ry-height
        plt.xlim((0, Bin[0]))
        plt.ylim((0, Bin[1]))
        color = "#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)])
        rect = patches.Rectangle((lx, ly), width,height,linewidth=1, facecolor = color)
        ax1.add_patch(rect)
    plt.show()
    

    在这里插入图片描述

    3.2 overlap函数

    判断物品item在当前位置itemRP与箱子中其他物品是否有重合,如果有重合FlagOL=1,反之FlagOL=0。

    # 输入item:   物品[宽度,高度]
    # 输入Item:   各个物品[宽度,高度]
    # 输入itemRP: 此时物品右上角顶点坐标[x,y]
    # 输入RPNXY:  当前箱子中所有物品右上角顶点坐标数组
    # 输出flagOL: 如果重合flagOL=1;反之flagOL=0
    def overlap(item,Item,itemRP,RPNXY):
        flagOL=0  # 初始化不存在重合情况
        itemLBP=[itemRP[0]-item[0],itemRP[1]-item[1]] #左下角顶点坐标
        A = Rectangle(itemLBP[0],itemLBP[1],item[0],item[1])
        num=len(RPNXY) # 箱子中物品数目
        if num>0:
            for i in range(num):
                width=Item[RPNXY[i][0],0]  #Item(RPNXY(i,1),:)宽度
                height=Item[RPNXY[i][0],1]  #Item(RPNXY(i,1),:)高度
                LBPXY=[RPNXY[i][1]-width,RPNXY[i][2]-height]  #在箱子中的当前矩形Item(RPNXY(i,1),:)的左下角顶点坐标
                B = Rectangle(LBPXY[0],LBPXY[1],width,height)
                area=rectint(A,B)#计算物品A与B相交的面积
                #如果AB相交,则满足下列关系
                if area>0:
                    flagOL=1
                    break
        return flagOL
    

    3.3 finalPos函数

    计算一个新的矩形从当前位置向下向左移动后到最终位置后右上角顶点坐标

    # 输入item:   物品[宽度,高度]
    # 输入Item:   各个物品[宽度,高度]
    # 输入itemRP: 此时物品右上角顶点坐标[x,y]
    # 输入RPNXY:  当前箱子中所有物品右上角顶点坐标数组
    # 输出finalRP:物品item在箱子内任意位置向下向左移动后到最终位置后右上角顶点坐标
    def finalPos(item,Item,itemRP,RPNXY):
        # 当物品item不能再继续下降或不能继续左移的时候,跳出循环
        while 1:
            downH=downHAtPoint(item,Item,itemRP,RPNXY) #计算物品item在箱子内itemRP位置处可以下降的最大高度
            leftW=0
            itemRP=Update_itemRP(itemRP,downH,leftW) #更新物品item当前位置右上角顶点坐标
            downH=0
            leftW=leftWAtPoint(item,Item,itemRP,RPNXY) #计算物品item在箱子内itemRP位置处可以向左移动的最大距离
            itemRP=Update_itemRP(itemRP,downH,leftW) #更新物品item当前位置右上角顶点坐标
            if (downH==0)and (leftW==0):
                finalRP=itemRP
                break
        return finalRP
    

    3.4 downHAtPoint函数

    使用downHAtPoint()函数可以计算在当前箱子中,矩形在当前位置可以下降的最大高度。

    # 计算在当前箱子中,物品item在箱子内任意位置可以下降的最大高度
    # 输入item:   物品[宽度,高度]
    # 输入AllItem:   各个物品[宽度,高度]
    # 输入itemRP: 此时物品右上角顶点坐标[x,y]
    # 输入RPNXY:  当前箱子中所有物品右上角顶点坐标数组
    # 输出downH:  物品item在箱子内任意位置可以下降的最大高度(如果能装入当前箱子,则downH为正数;如果不能装入当前箱子,则为负数)
    def downHAtPoint(item,AllItem,itemRP,RPNXY):
        bottomLine=Point_Horizontal_Line(item,itemRP)  #物品下端水平线段左右两端坐标[leftx,lefty,rightx,righty]
        RP_NUM=len(RPNXY) #箱子内物品数目
        if RP_NUM!=0:
            sRPNXY=np.array(sorted(list(RPNXY), key=lambda x:x[2],reverse=True))#将RPNXY按照Y坐标降序排列
            sRBPNXY=sRPNXY.copy()
            sRBPNXY[:,1]=sRPNXY[:,1]-AllItem[sRPNXY[:,0],0]  #将RPNXY按照Y坐标降序排列后的左上角顶点坐标
            
            topLine=np.concatenate((sRBPNXY[:,1:3],sRPNXY[:,1:3]),axis=1)  #物品按照Y坐标降序排列后,物品上端水平线段左右两端坐标[leftx,lefty,rightx,righty]
            # 逐个遍历sRPNXY中的物品
            alldownH=[]  # 储存所有满足相交条件的下降距离
            for i in range(RP_NUM):
                #判断两条水平线段经过竖直移动后是否会相交,flag=1相交,flag=0不相交
                #两条水平线段距离是多少,如果竖直移动后相交,HD为正数,反之为负数
                flag,HD=Horizontal_Lines_Intersect(bottomLine,topLine[i,:])
                if (flag==1) and (HD>=0):
                    alldownH.append(HD)
            # 如果不存在满足相交条件的物品,则直接下降到箱子最底端
            if len(alldownH)==0:
                downH=itemRP[1]-item[1]
            else:  # 如果存在满足相交条件的物品,则下降距离为alldownH中的最小值
                downH=min(alldownH)
        else:
            downH=itemRP[1]-item[1]  #此时箱子没有物品,物品直接下降到箱子底端
        return downH
    

    3.5 Update_itemRP函数

    计算物品在箱子中从右上角下降downH又向左移动leftW后,右上角顶点的坐标

    # 输入itemRP: 此时物品右上角顶点坐标[x,y]
    # 输入downH:  物品item从右上角可以下降的最大高度
    # 输入leftW:  物品item从右上角下降最大高度以后,可以向左移动的最大距离
    # 输出itRPXY: 物品item在箱子中下降downH又向左移动leftW后,右上角顶点的坐标
    def Update_itemRP(itemRP,downH,leftW):
        h=itemRP[1]-downH  #y坐标
        w=itemRP[0]-leftW   #x坐标
        return [w,h]
    

    3.6 leftWAtPoint函数

    计算在当前箱子中,物品item在箱子内任意位置可以向左移动的最大距离

    # 输入item:   物品[宽度,高度]
    # 输入Item:   各个物品[宽度,高度]
    # 输入itemRP: 此时物品右上角顶点坐标[x,y]
    # 输入RPNXY:  当前箱子中所有物品右上角顶点坐标数组
    # 输出leftW:  物品item在箱子内任意位置可以向左移动的最大距离
    def leftWAtPoint(item,Item,itemRP,RPNXY):
        leftLine=Point_Vertical_Line(item,itemRP)  #物品左端竖直线段上下两端坐标[topx,topy,bottomx,bottomy]
        RP_NUM=len(RPNXY)#箱子内物品数目
        if RP_NUM!=0:
            sRPNXY=np.array(sorted(list(RPNXY), key=lambda x:x[0]))  #将RPNXY按照X坐标降序排列
            sRBPNXY=sRPNXY.copy()
            sRBPNXY[:,2]=sRPNXY[:,2]-Item[sRPNXY[:,0],1] #将RPNXY按照X坐标降序排列后的右下角顶点坐标
            rightLine=np.concatenate((sRPNXY[:,1:3],sRBPNXY[:,1:3]),axis=1)#物品按照X坐标降序排列后,右端线段上下两端坐标[topx,topy,bottomx,bottomy]
            #逐个遍历sRPNXY中的物品
            allLeftW=[]  #储存所有满足相交条件的左移距离
            for i in range(RP_NUM):
                #判断两条竖直线经过水平移动后是否会相交,flag=1相交,flag=0不相交
                #两条竖直线段距离是多少,如果平移动后相交,HD为正数,反之为负数
                flag,HD=Vertical_Lines_Intersect(leftLine,rightLine[i,:])
                if (flag==1) and (HD>=0):
                    allLeftW.append(HD)
            # 如果不存在满足相交条件的物品,则直接移动箱子最左端
            if len(allLeftW)==0:
                leftW=itemRP[0]-item[0]
            else: #如果存在满足相交条件的物品,则左移距离为allLeftW中的最小值
                leftW=min(allLeftW)
        else:
            leftW=itemRP[0]-item[0]
        return leftW
    

    3.7 其他小功能的函数

    from matplotlib.pyplot import axis
    import numpy as np
    # 矩形类,[x,y,width,height]左下角坐标、长和宽
    class Rectangle:
        def __init__(self, x, y,w,h):
          self.x = x
          self.y = y
          self.width = w
          self.height = h
          
    def Horizontal_Lines_Intersect(line1,line2):
        # 判断两条水平线段经过竖直移动后是否会相交,如果相交,计算两条水平线段竖直距离是多少
        # 思路:分5种情况:1)左方不相交;2)左方相交;3)右方相交;4)右方不相交;5)line1完全包含line2
        # 输入line1:  第一条线段[x1,y1,x2,y2]
        # 输入line2:  第二条线段[x1,y1,x2,y2]
        # 输出flag:  判断两条水平线段经过竖直移动后是否会相交,flag=1相交,flag=0不相交
        # 输出HD:  两条竖直线段距离是多少,如果平移动后相交,HD为正数,反之为负数
        #第一种情况,line1完全在line2左方,即line1右端顶点x坐标小于等于line2左端顶点x坐标,且两条线段经过竖直移动后不会相交
        if line1[2]<=line2[0]:
            flag=0
            HD=line1[1]-line2[1]
        #第二种情况,line1在line2左方,即line1右端顶点x坐标大于line2左端顶点x坐标且小于等于且line2右端顶点x坐标,但两条线段经过竖直移动后会相交
        elif (line1[2]>line2[0]) and (line1[2]<=line2[0]):
            flag=1
            HD=line1[1]-line2[1]
        #第三种情况,line1在line2右方,即line1左端顶点x坐标大于等于line2左端顶点x坐标且小于且line2右端顶点x坐标,但两条线段经过竖直移动后会相交
        elif (line1[0]>=line2[0]) and (line1[0]<line2[2]):
            flag=1
            HD=line1[1]-line2[1]
        #第四种情况,line1完全在line2右方,即line1左端顶点x坐标大于等于line2右端顶点x坐标,且两条线段经过竖直移动后不会相交
        elif line1[0]>=line2[2]:
            flag=0
            HD=line1[1]-line2[1]
        #第五种情况,line1完全包含line2,即line1左端顶点x坐标小于等于line2左端顶点x坐标,
        #line1右端顶点x坐标大于等于line2右端顶点x坐标,且两条线段经过竖直移动后会相交
        else:
            flag=1
            HD=line1[1]-line2[1]
        return flag,HD
      
    # 根据物品右上角顶点坐标和物品宽度和高度,求出物品下端水平线段左右两端坐标[leftx,lefty,rightx,righty]
    # 输入item:  物品[宽度,高度]
    # 输入RPXY:物品右上角顶点坐标[x,y]
    # 输出leftLine:  物品下端水平线段左右两端坐标[leftx,lefty,rightx,righty]
    def Point_Horizontal_Line(item,RPXY):
        。。。
        return bottomLine
     
    # 判断两条竖直线段经过水平移动后是否会相交,如果相交,计算两条竖直线段水平距离是多少
    # 思路:分5种情况:1)上方不相交;2)上方相交;3)下方相交;4)下方不相交;5)line1完全包含line2
    # 输入line1:  第一条线段[topx,topy,bottomx,bottomy]
    # 输入line2:  第二条线段[topx,topy,bottomx,bottomy]
    # 输出flag:  判断两条竖直线经过水平移动后是否会相交,flag=1相交,flag=0不相交
    # 输出HD:  两条竖直线段距离是多少,如果平移动后相交,HD为正数,反之为负数
    def Vertical_Lines_Intersect(line1,line2):
        # 第一种情况,line1完全在line2上方,且两条线段经过平移后不会相交
        if line1[3]>=line2[1]:
            flag=0
            HD=line1[0]-line2[0]
        # 第二种情况,line1在line2上方,但两条线段经过平移后会相交
        elif (line1[3]<line2[1])and (line1[3]>=line2[3]):
            flag=1
            HD=line1[0]-line2[0]
        # 第三种情况,line1在line2下方,但两条线段经过平移后会相交
        elif (line1[1]<=line2[1]) and (line1[1]>line2[3]):
            flag=1
            HD=line1[0]-line2[0]
        # 第四种情况,line1完全在line2下方,且两条线段经过平移后不会相交
        elif line1[1]<=line2[3]:
            flag=0
            HD=line1[0]-line2[0]
        else:
            flag=1
            HD=line1[0]-line2[0]
        return flag,HD
     
    # 根据物品右上角顶点坐标和物品宽度和高度,求出物品左端竖直线段上下两端坐标[topx,topy,bottomx,bottomy]
    # 输入item:  物品[宽度,高度]
    # 输入RPXY:物品右上角顶点坐标[x,y]
    # 输出leftLine:  物品左端竖直线段上下两端坐标[topx,topy,bottomx,bottomy]
    def Point_Vertical_Line(item,RPXY):
      。。。
        
    

    在这里插入图片描述

    # 计算两个矩形相交的面积,和MATLAB中rectint函数作用一样
    def rectint(rect1, rect2):
        xl1, yb1, xr1, yt1 = rect1.x,rect1.y,rect1.x+rect1.width,rect1.y+rect1.height # (xl1, yb1)为矩形左下角坐标, (xr1, yt1)为右上角坐标
        xl2, yb2, xr2, yt2 = rect2.x,rect2.y,rect2.x+rect2.width,rect2.y+rect2.height # (xl2, yb2)为矩形左下角坐标, (xr2, yt2)为右上角坐标
        xmin = max(xl1, xl2)
        ymin = max(yb1, yb2)
        xmax = min(xr1, xr2)
        ymax = min(yt1, yt2)
        width = xmax - xmin
        height = ymax - ymin
        if width <= 0 or height <= 0:
            return 0
        cross_square = width * height
        return cross_square
    

    4 缺点及改进

    装箱顺序会影响占用率。比如会存在如下所示的装箱方案,物品4应该放置到物品2的上面。可以通过调整装箱顺序,让4和2调换一下装箱顺序,就可以达到更好的效果。

    当矩阵数量庞大的时候,可以采用优化算法,来搜索最佳的排列组合,达到最大占用率。比如以人工蜂群算法实现。
    在这里插入图片描述

    import numpy as np
    import random, math, copy
    import matplotlib.pyplot as plt
    from tools import *
    import random
     
    
    def fitness(Bin,AllItem,ran):
        # ran 是装箱顺序
        itemNum=AllItem.shape[0] #物品数目
        RPNXY=[];
        flagItem=np.zeros(itemNum) #标记物品是否被装入箱子,0没有装入,1装入
        # 开始装箱
    
        for i in range(itemNum):
            if flagItem[ran[i]]==0:
                item=AllItem[ran[i],:]
                itemRP=Bin  #起点全部在箱子右上角顶点
                flagOL=overlap(item,AllItem,itemRP,RPNXY) #如果重合flagOL=1;反之flagOL=0
                if flagOL==0:
                    itemRP=finalPos(item,AllItem,itemRP,RPNXY) #更新物品从当前位置向下向左移动后到最终位置后右上角顶点坐标
                    if len(itemRP)>0:
                        RPNXY.append([ran[i],itemRP[0],itemRP[1]])
                        flagItem[ran[i]]=1
        rect_area = 0
        bin_area = Bin[0]*Bin[1]
        for id in RPNXY:
            width,height = AllItem[id[0]]
            rect_area += width*height
        score = rect_area/bin_area
        print('利用率:{}'.format(score))
        return score
     
    class ABSIndividual:
        def __init__(self,bin,item):
            self.score = 0.
            self.invalidCount = 0                      #无效次数(成绩没有更新的累积次数)
            self.bin = bin  #箱子宽度与高度
            self.allitem = item
            self.ran =  list(range(self.allitem.shape[0]))# 装箱顺序
            self.calculateFitness()        
     
        def calculateFitness(self):
            self.score = fitness(self.bin,self.allitem,self.ran)          #计算当前成绩
            
    class ArtificialBeeSwarm:
        def __init__(self, foodCount, onlookerCount,Bin, item, maxIterCount=1000, maxInvalidCount=200):
            self.foodCount = foodCount                  #蜜源个数,等同于雇佣蜂数目
            self.onlookerCount = onlookerCount          #观察蜂个数 
            self.item = item                          #各参数上下界
            self.maxIterCount = maxIterCount            #迭代次数
            self.maxInvalidCount = maxInvalidCount      #最大无效次数
            self.Bin = Bin
            self.foodList = [ABSIndividual(self.Bin,self.item) for k in range(self.foodCount)]   #初始化各蜜源
            self.foodScore = [d.score for d in self.foodList]                             #各蜜源最佳成绩
            self.bestFood = self.foodList[np.argmax(self.foodScore)]                      #全局最佳蜜源
     
        def updateFood(self, i):                                                  #更新第i个蜜源
            vi = copy.deepcopy(self.foodList[i])
            order =list(range(vi.allitem.shape[0]))
            random.shuffle(order) #随机生成装箱序列
            vi.ran = order
            vi.calculateFitness()
            if vi.score > self.foodList[i].score:           #如果成绩比当前蜜源好
                self.foodList[i] = vi
                if vi.score > self.foodScore[i]:            #如果成绩比历史成绩好(如重新初始化,当前成绩可能低于历史成绩)
                    self.foodScore[i] = vi.score
                    if vi.score > self.bestFood.score:      #如果成绩全局最优
                        self.bestFood = vi
                self.foodList[i].invalidCount = 0
            else:
                self.foodList[i].invalidCount += 1
                
        def employedBeePhase(self):
            for i in range(0, self.foodCount):              #各蜜源依次更新
                self.updateFood(i)            
     
        def onlookerBeePhase(self):
            foodScore = [d.score for d in self.foodList]  
            maxScore = np.max(foodScore)        
            accuFitness = [(0.9*d/maxScore+0.1, k) for k,d in enumerate(foodScore)]        #得到各蜜源的 相对分数和索引号
            for k in range(0, self.onlookerCount):
                i = random.choice([d[1] for d in accuFitness if d[0] >= random.random()])  #随机从相对分数大于随机门限的蜜源中选择跟随
                self.updateFood(i)
     
        def scoutBeePhase(self):
            for i in range(0, self.foodCount):
                if self.foodList[i].invalidCount > self.maxInvalidCount:                    #如果该蜜源没有更新的次数超过指定门限,则重新初始化
                    self.foodList[i] = ABSIndividual(self.bound)
                    self.foodScore[i] = max(self.foodScore[i], self.foodList[i].score)
     
        def solve(self):
            trace = []
            trace.append((self.bestFood.score, np.mean(self.foodScore)))
            for k in range(self.maxIterCount):
                self.employedBeePhase()
                self.onlookerBeePhase()
                self.scoutBeePhase()
                trace.append((self.bestFood.score, np.mean(self.foodScore)))
            print(self.bestFood.score)
            self.printResult(np.array(trace))
     
        def printResult(self, trace):
            x = np.arange(0, trace.shape[0])
            plt.plot(x, [(1-d)/d for d in trace[:, 0]], 'r', label='optimal value')
            plt.plot(x, [(1-d)/d for d in trace[:, 1]], 'g', label='average value')
            plt.xlabel("Iteration")
            plt.ylabel("function value")
            plt.title("Artificial Bee Swarm algorithm for function optimization")
            plt.legend()
            plt.show()
     
    if __name__ == "__main__":
        random.seed()
        itemNum = 1000
        AllItem=np.array([[random.randint(1, 5) for j in range(1, 3)] for i in range(1,itemNum+1)])  #随机生成30个物品,[width,height]
        Bin=[100,100] #箱子宽度与高度
        iternum = 100 # 迭代次数
        maxInvalidCount = 50
        abs = ArtificialBeeSwarm(30, 30, Bin,AllItem, iternum, maxInvalidCount)
        abs.solve()
        print()
    

    5 完整代码下载

    https://github.com/BetterBench/BetterBench-Shop

    展开全文
  • 简单的二维装箱代码

    热门讨论 2012-08-01 23:51:31
    简单实现了二维装箱问题。不过仅仅是简单实现,排列7、8个矩形没问题,超过10个就要花N久了。。
  • 一种新的集装箱问题算法,适用二维
  • 文章目录一、何为二维矩形排样代码编写项目结构pom文件data.txtInstance类PlacePoint类PlaceSquare类Solution类Square类 一、何为二维矩形排样 代码编写 项目结构 pom文件 <?xml version="1.0" encoding="UTF-...
  • 二维装箱

    千次阅读 2018-07-24 12:25:14
    //节点 public class Node { public int X { get; set; } public int Y { get; set; } public int W { get; set; } public int H { get; set; } public bool Is...
  • 项目的大体框架(一些实体类,数据读取类等)和禁忌搜索算法求解二维矩形装箱问题(java代码实现)中的差不多,所以本文只提供蚁群算法的核心代码,大家用的时候只需要将两个禁忌搜索算法的类替换为下文中的蚁群算法...
  • 二维矩形装箱算法之二叉树

    万次阅读 2018-03-21 15:28:29
    如何将所有二维矩形块放入一个矩形框内。2.在满足问题1的情况下,矩形框的最小宽度和高度是多少。期望的效果图: 下面我们就来解决以上问题。1. 把矩形块放在固定大小的框内假设有一个固定大小的矩形框,比如1024...
  • 针对二维矩形条带装箱问题提出了一种启发式布局算法,即底部左齐择优匹配算法(lowest—level left align bestfit,简称LLABF).LLABF算法遵循最佳匹配优先原则,该原则综合考虑完全匹配优先、宽度匹配优先、高度...
  • 二维装箱】基于matlab遗传算法求解矩形地块二维装箱放置优化问题【含Matlab源码 1556期】.zip,【二维装箱】基于matlab遗传算法求解矩形地块二维装箱放置优化问题【含Matlab源码 1556期】,objection.m,运行结果2....
  • 二维下料matlab bl算法,bl.mat是主函数,可以直接运行
  • 二维装箱问题是具有广泛应用背景的一类组合优化问题 ,这类问题是 NP难问题 ,很难得到精确解 。将二维装箱问题表示为一个非线性规划模型 ,用变分分析中切锥的概念建立了这一优化问题的一阶最优性条件 。给出了求解这...
  • 这里的装箱问题和我们在算法上归纳的装箱问题不是一个概念!也就是不同于下面这篇博客里的装箱问题。 【C++】2018华为软挑:模拟退火+贪心FF解决装箱问题_玛丽莲茼蒿的博客-CSDN博客本文的主要工作是补充这篇博客的...
  • 在一个特定的尺寸(1000*1200mm)内以最佳利用率的方式放满N个长方形或正方形(相同或不同尺寸均有),每个图形之间的距离为2mm,欢迎一起探讨(可私信),谢谢!
  • 题目描述一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1*1, 2*2, 3*3, 4*4, 5*5, 6*6。这些产品通常使用一个 6*6*h 的长方体包裹包装然后邮寄给客户。...
  • matlab二维装箱问题求解
  • 简称2DRP)以及在此基础上拓展的二维装箱问题(2D strip packing problem,简称2DSP),以及由____数据魔术师团队____提出的解决该问题的一钟启发式算法。 这次介绍的算法运用了启发式算法**禁忌搜索算法(Tabu ...
  • 主要介绍了PHP实现的装箱算法,结合实例形式分析了PHP装箱算法的概念、原理、定义及使用方法,需要的朋友可以参考下
  • Matlab 三维装箱遗传算法实现

    千次阅读 2022-01-29 22:26:24
    % 使用遗传算法得到最大装载方式 % 定义初始种群为100个 % 交叉方式为两两交叉组合,分裂概率为0.7 % 变异方式为随机变异,变异概率为0.3 % 然后进行选择 选择前面最优的100个 rateCom=0.7;%结合概率 rateAbe=0
  • 求解二维装箱问题的强化学习启发式算法.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,813
精华内容 1,525
关键字:

二维装箱算法

友情链接: misc_regs.rar