基于 三维装箱问题的算法研究-2 的基础,对整个过程进行了优化
因为后面研究的视图依赖于Three.js进行成像,需要写一些简单的vue页面,所以把整个算法包括数据格式的调用做成了django后端系统和vue前台显示
前提:整一个装箱的实现,实际上就是一直在判断:
东西可以放在哪里?不可以放在哪里?应该怎么放?放完之后对整个空间有什么影响?
基本概念:所以这里产生了几个基本概念,放置点,可用放置点,残余空间
通过一个放置点【这里是原点(0,0,0)】,和物体在XYZ轴的长度,我们可以调整物体的位置和朝向。
按照人为装箱的习惯:当我们放下一个物体,会在它的这三个点上继续的放置物体,且这三个放置位置的使用,根据实际情况存在优先级。
1.一般来说优先使用Y轴宽度
2.等摆完一列宽之后,向高方向蔓延,在上面使用新的宽度
3.等摆完一整面之后,向长方向蔓延,在长方向上使用新的高度(回到X轴基线)
这里产生一个问题,如果是混装情况,当我们摆完一面之后会发现物体参差不齐
也就是说,所有在长方向上产生的放置点,都有可能不可用,因为在这个方向上摆放的物体可能会和上一面发生重叠情况,基于这种情况做了两步优化:
这样就能够保证最先进去的物体比后面的物体大,产生的放置点不会和前面的物体发生重叠
cargos=[
{"length": 500,"width": 100,"height": 300,"num": 5000},
{"length": 600,"width": 100,"height": 450,"num": 2000},
{"length": 500,"width": 90,"height": 350,"num": 2000}
]
from operator import itemgetter
# 创造货物列表,理论上先大后小,因为小的方便堆叠在大的上面,大的不方便堆叠在小的上面
def MakeList(cargos):
# 先排序
cargos = sorted(cargos ,key = itemgetter('length','width','height','num'),reverse=True)
# 再生成列表
cargo_list = []
for cargo in cargos:
cargo_list = cargo_list + [(cargo['length'],cargo['width'],cargo['height']) for num in range(0,cargo['num'])]
return cargo_list
# 第一种衍生方法,仅底部向外衍生
# 考虑到每一次摆完一面之后都是从最低成开始放置,所以在长方向上只在最底下生成放置点,避免放置点悬空和后面的摆放造成重叠情况
# 但是这就会照成如果极小物体放在较大物体上面时,只用完宽度就会向新一面衍生
def newsite1(put,O,B_i):
# 在X轴方向上生成
O1 = (O[0]+B_i[0],O[1],O[2])
if O1 not in put and O[1]==0 and O[2]==0:
put.append(O1)
# 在Y轴方向上生成
O2 = (O[0],O[1]+B_i[1],O[2])
if O2 not in put:
put.append(O2)
# 在Z轴方向上生成
O3 = (O[0],O[1],O[2]+B_i[2])
if O3 not in put :
put.append(O3)
# 这里加入一步排序,让我们优先级的放置点排到前面先被使用
return sorted(put, key=lambda x: (x[0],x[2],x[1]))
在测试过程中又发现一个新的问题,如图上的阴影,开始我以为是three.js渲染出来的顶部触顶的阴影效果
最后数来数去发现数量不对,放大一看,是在这里发生了堆叠,前面物体在高方向上产生的放置点被后面的物体使用后发生了堆叠情况
那么我们除了限制在高方向上放置点的生成,也要限制在高方向放置点的生成
# 第三种衍生方法,不仅仅限制长方向上的衍生,也限制高方向的衍生
# 在测试中发现,如果在高上继续衍生放置点,当后面的货物比前面小的时候,会因为前面更大的物体产生的悬空放置点发生重叠情况
# 所以不限制高上衍生仅在前一个物体比后一个物体大的情况,其余情况限制只有在贴边时允许向上蔓延
# 缺点是因为算力和逻辑严谨性,没有对比前后两个货物的高度差,也就是可能出现当前面的物体高度较大,后面当面的物体只摆了两层的情况
def newsite3(put,O,B_i):
# 在X轴方向上生成
O1 = (O[0]+B_i[0],O[1],O[2])
if O1 not in put and O[1]==0 and O[2]==0:
put.append(O1)
# 在Y轴方向上生成
O2 = (O[0],O[1]+B_i[1],O[2])
if O2 not in put:
put.append(O2)
# 在Z轴方向上生成
O3 = (O[0],O[1],O[2]+B_i[2])
if O3 not in put and O[1]==0:
put.append(O3)
return sorted(put, key=lambda x: (x[0],x[2],x[1]))
在这种方法里不再在高的方向产生放置点,那么我们只需要外部判断下条件,在贴面(OXZ)时,或前一个物体更大时,使用不限制,其他情况使用这个限制方法