def getLengthDecreaing(self): length_list = [] for i, poly in enumerate(self.polys): bottom_pt, top_pt = LPAssistant.getBottomPoint( poly), LPAssistant.getTopPoint(poly) length_list.append([i, top_pt[1] - bottom_pt[1]]) return length_list
def getWidthDecreaing(self, polys): width_list = [] for i, poly in enumerate(self.polys): left_pt, right_pt = LPAssistant.getLeftPoint( poly), LPAssistant.getRightPoint(poly) width_list.append([i, right_pt[0] - left_pt[0]]) return width_list
def getPolyDepeth(self, index): cur_min_depth, pt = 0, LPAssistant.getTopPoint(self.polys[index]) for j in range(len(self.polys)): if j == index or self.pair_overlap[index][j] == 0: continue cur_min_depth = cur_min_depth + self.getPairDepenetration( pt, index, j) return cur_min_depth
def getNFP(self, j, i): # j是固定位置,i是移动位置 row = j * 192 + i * 16 + self.poly_status[j][2] * 4 + self.poly_status[ i][2] bottom_pt = LPAssistant.getBottomPoint(self.polys[j]) delta_x, delta_y = bottom_pt[0], bottom_pt[1] nfp = GeoFunc.getSlide(json.loads(self.fu_pre["nfp"][row]), delta_x, delta_y) return nfp
def slideToContainer(self): # 平移部分形状 for index, poly in enumerate(self.polys): right_pt = LPAssistant.getRightPoint(poly) if right_pt[0] > self.cur_length: delta_x = self.cur_length - right_pt[0] GeoFunc.slidePoly(poly, delta_x, 0) top_pt = self.poly_status[index][1] self.poly_status[index][1] = [top_pt[0] + delta_x, top_pt[1]]
def getPrerequisite(self, i, orientation, **kw): # 获得全部NFP以及拆分情况 self.all_nfps,self.all_points_target,self.all_edges_target = [],[],[] offline = kw['offline'] for j, item in enumerate(self.polys): # 两个相等的情况,跳过否则会计算错误 if j == i: self.all_nfps.append([]) self.all_points_target.append([]) self.all_edges_target.append([]) continue # 预处理的情况 points_target, edges_target, nfp = [], [], [] if offline == True: row = j * 192 + i * 16 + self.poly_status[j][ 2] * 4 + orientation bottom_pt = LPAssistant.getBottomPoint(self.polys[j]) delta_x, delta_y = bottom_pt[0], bottom_pt[1] nfp = GeoFunc.getSlide(json.loads(self.fu_pre["nfp"][row]), delta_x, delta_y) else: nfp = LPAssistant.deleteOnline( self.NFPAssistant.getDirectNFP( self.polys[j], self.polys[i])) # NFP可能有同一直线上的点 # 计算对应目标函数 for pt_index in range(len(nfp)): edges_target.append( LPAssistant.getTargetFunction( [nfp[pt_index - 1], nfp[pt_index]])) points_target.append([nfp[pt_index][0], nfp[pt_index][1]]) # 添加上去 self.all_nfps.append(nfp) self.all_edges_target.append(edges_target) self.all_points_target.append(points_target) # 获取IFR self.target_poly = self.all_polygons[i][orientation] self.ifr = PackingUtil.getInnerFitRectangle(self.target_poly, self.cur_length, self.width) self.IFR = Polygon(self.ifr) self.final_IFR = Polygon(self.ifr)
def polysOverlapIFR(self, poly1, poly2): '''判断两个形状之间是否重叠、重叠区域面积、重叠区域是否与IFR有重叠''' P1, P2 = Polygon(poly1), Polygon(poly2) inter = P1.intersection(P2) overlap, overlap_poly = False, [] if inter.area > bias: new_inter = inter.intersection(self.IFR) if new_inter.area > bias: overlap, overlap_poly = True, LPAssistant.processRegion( new_inter) # 相交区域肯定是凸多边形 return overlap, overlap_poly
def main(self): ration_dec, ration_inc = 0.04, 0.01 max_time = 2000 print("执行主程序") self.best_length = LPAssistant.getLength(self.polys) # 最佳状态 print("初始高度:", self.best_length) self.cur_length = self.best_length * (1 - ration_dec) # 当前的宽度 self.slideToContainer() # 把突出去的移进来 start_time = time.time() self.use_ratio.append(self.total_area / (self.best_length * self.width)) print("当前利用率:", self.total_area / (self.best_length * self.width)) while time.time() - start_time < max_time: # 最小化重叠 self.minimizeOverlap() if LPAssistant.judgeFeasible(self.polys) == True: # 更新全部状态 self.length = self.cur_length self.use_ratio.append(self.total_area / (self.length * self.width)) print("当前利用率:", self.total_area / (self.length * self.width)) self.best_polys = copy.deepcopy(self.polys) self.best_poly_status = copy.deepcopy(self.poly_status) # 收缩边界,并且把突出去的移进来 self.cur_length = self.length * (1 - ration_dec) self.slideToContainer() else: # 如果不可行就直接拆分 self.cur_length = self.best_length * (1 + ration_inc) end_time = time.time() print("最优结果:", self.best_polys) self.showPolys() self.plotRecord("use ratio:", self.use_ratio)
def getConstants(self): self.W = [] # 最高位置到右侧的距离 self.W_ = [] # 最高位置到左侧的距离 self.H = [] # 最高点 self.Xi = [] # Xi的初始位置 self.Yi = [] # Yi的初始位置 self.PLACEMENTPOINT = [] for i, poly in enumerate(self.polys): left, bottom, right, top = LPAssistant.getBoundPoint(poly) self.PLACEMENTPOINT.append([top[0], top[1]]) self.Xi.append(top[0]) self.Yi.append(top[1]) self.W.append(right[0] - top[0]) self.W_.append(top[0] - left[0]) self.H.append(top[1] - bottom[1])
def checkOneSeq(self, one_list): new_polys = [] for item in one_list: new_polys.append(self.polys[item[0]]) packing_polys = BottomLeftFill( 760, new_polys, NFPAssistant=self.nfp_assistant).polygons _len = LPAssistant.getLength(packing_polys) ratio = 433200 / (_len * 760) res = [[] for i in range(len(new_polys))] for i, item in enumerate(one_list): res[one_list[i][0]] = packing_polys[i] return ratio, res
def getInitialResult(self): index = 6 blf = pd.read_csv( "/Users/sean/Documents/Projects/Packing-Algorithm/record/blf.csv") self.total_area = blf["total_area"][index] self.polys = json.loads(blf["polys"][index]) self.best_polys = copy.deepcopy(self.polys) # 按照index的顺序排列 self.best_poly_status, self.poly_status = json.loads( blf["poly_status"][index]), json.loads(blf["poly_status"][index]) self.use_ratio = [] # 在没有的时候全部加载一遍 if len(self.best_poly_status) == 0: for i, poly in enumerate(self.polys): top_pt = LPAssistant.getTopPoint(poly) self.best_poly_status.append([i, top_pt, 0]) # 分别为序列号、位置及方向 self.poly_status.append([i, top_pt, 0]) # 分别为序列号、位置及方向 print("一共", len(self.polys), "个形状")
def getProblemLP(self): # 获得目标区域 self.ifr_points = [] self.target_areas = [[], [], [], [], [], [], [], [], []] self.last_index = [[], [], [], [], [], [], [], [], []] # 获得两个NFP在IFR中重叠的情况 self.nfp_overlap_pair = [[i] for i in range(len(self.all_nfps))] for i in range(len(self.all_nfps) - 1): for j in range(i + 1, len(self.all_nfps)): overlap, overlap_poly = self.polysOverlapIFR( self.all_nfps[i], self.all_nfps[j]) if overlap == True: self.nfp_overlap_pair[i].append(j) self.nfp_overlap_pair[j].append(i) self.target_areas[1].append([overlap_poly, i, j]) self.last_index[1].append([i, j]) # 分别添加i,j # 切去一维重叠情况 for i, nfp in enumerate(self.all_nfps): # 删除与IFR重叠区域 new_region = Polygon(nfp).intersection(self.IFR) self.final_IFR = self.final_IFR.difference(Polygon(nfp)) # 删除与其他NFP拆分的重叠 for j in self.nfp_overlap_pair[i][1:]: P = Polygon(self.all_nfps[j]) new_region = new_region.difference(P) # 在目标区域增加情况,首先排除点和直线,以及面积过小 if new_region.is_empty != True and new_region.geom_type != "Point" and new_region.geom_type != "LineString" and new_region.area > bias: self.target_areas[0].append( [LPAssistant.processRegion(new_region), i]) # 删除直线/顶点情况 else: self.target_areas[0].append([]) self.last_index[0].append([]) # 增加IFR的计算 if self.final_IFR.is_empty != True and self.final_IFR.geom_type != "Point" and self.final_IFR.geom_type != "LineString" and self.final_IFR.area > bias: self.ifr_points = LPAssistant.processRegion(self.final_IFR) # 获得后续的重叠 for i in range(2, len(self.target_areas)): # 遍历上一阶段计算的结果 for j, target_area in enumerate(self.target_areas[i - 1]): area, P1 = target_area[0], Polygon(target_area[0]) # 获得当前目标可行解 all_possible_target = [] # 如果大于三个,只需要计算最后加入的,否则是第一个 if i >= 3: all_possible_target = self.nfp_overlap_pair[ target_area[-1]] else: all_possible_target = self.nfp_overlap_pair[ target_area[1]] + self.nfp_overlap_pair[target_area[2]] all_possible_target = PolyListProcessor.deleteRedundancy( all_possible_target) # 删除所有更小的,保证正序,获得判断这些形状是否会重叠,若有则添加并求解目标区域 all_possible_target_larger = LPAssistant.deleteTarget( all_possible_target, [ i for i in range( 0, max(item for item in target_area[1:]) + 1) ]) for possible_target in all_possible_target_larger: P2 = Polygon(self.all_nfps[possible_target]) # 只有相交才进一步计算 if P1.intersects(P2): inter = P1.intersection(P2) if inter.area > bias: self.last_index[i].append([j]) self.target_areas[i].append( [LPAssistant.processRegion(inter)] + target_area[1:] + [possible_target]) # 删除已经有的,遍历计算重叠 all_possible_target_difference = LPAssistant.deleteTarget( all_possible_target, [item for item in target_area[1:]]) new_region = self.cutFrontRegion( all_possible_target_difference, P1) if new_region.is_empty != True and new_region.geom_type != "Point" and new_region.geom_type != "LineString" and new_region.area > bias: target_area[0] = LPAssistant.processRegion(new_region) else: self.target_areas[i - 1][j] = [] # 如果该轮没有计算出重叠则停止 if self.target_areas[i] == []: self.max_overlap = i # print("至多",i,"个形状重叠,计算完成") break
def minimizeOverlap(self): start_time = time.time() # 记录引导检索的相关内容 self.miu = [[1] * len(self.polys) for _ in range(len(self.polys))] self.initialOverlap() # 记录重叠变化情况 self.overlap_reocrd = [] # 检索次数限制/超出倍数退出 it, N = 0, 50 minimal_overlap = self.getTotalOverlap() cur_overlap = minimal_overlap print("初始重叠:", cur_overlap) # 限定计算次数 print("开始一次检索") while it < N: print("it:", it) # 获得随机序列并逐一检索 permutation = np.arange(len(self.polys)) np.random.shuffle(permutation) for i in range(len(self.polys)): # 选择特定形状 choose_index = permutation[i] # 通过重叠判断是否需要计算 with_overlap = False for item in self.pair_overlap[choose_index]: if item > 0: with_overlap = True break if with_overlap == False: continue # 获得当前的最小的深度(调整后),如果没有重叠,直接下一个 self.getPrerequisite(choose_index, self.poly_status[choose_index][2], offline=True) cur_min_depth = self.getPolyDepeth(choose_index) # 记录最优情况,默认是当前情况 original_position = self.poly_status[choose_index][1] best_position, best_orientation, best_depth = self.poly_status[ choose_index][1], self.poly_status[choose_index][ 2], cur_min_depth # print("当前最低高度:",best_depth) print("测试第", i, "个形状") # 遍历四个角度的最优值 for orientation in [0, 1, 2, 3]: # print("测试角度:",90*orientation,"度") self.getPrerequisite(choose_index, orientation, offline=True) self.getProblemLP() new_position, new_depth = self.searchBestPosition( choose_index) # 获得最优位置 if new_depth < best_depth: best_position, best_orientation, best_depth = copy.deepcopy( new_position), orientation, new_depth # 如果有变化状态则需要更新overlap以及移动形状 if best_position != original_position: print("本次检索最低深度:", best_depth) # 更新记录的位置 self.poly_status[choose_index][1] = copy.deepcopy( best_position) self.poly_status[choose_index][2] = best_orientation # 获取形状顶部位置并平移过去 new_poly = copy.deepcopy( self.all_polygons[choose_index][best_orientation]) top_point = LPAssistant.getTopPoint(new_poly) GeoFunc.slidePoly(new_poly, best_position[0] - top_point[0], best_position[1] - top_point[1]) # 更新形状与重叠情况 self.polys[choose_index] = new_poly self.updateOverlap(choose_index) # self.showPolys() # 计算新方案的重叠情况 cur_overlap = self.getTotalOverlap() self.overlap_reocrd.append(cur_overlap) if cur_overlap < bias: print("没有重叠,本次检索结束") break elif cur_overlap < minimal_overlap: minimal_overlap = cur_overlap it = 0 print("\n当前重叠:", cur_overlap, "\n") it = it + 1 self.updateMiu() # 超出检索次数 if it == N: print("超出更新次数/超出倍数") # self.showPolys() end_time = time.time() print("本轮耗时:", end_time - start_time) print("最终结果:", self.polys) print("当前状态:", self.poly_status) with open( "/Users/sean/Documents/Projects/Packing-Algorithm/record/fu_result.csv", "a+") as csvfile: writer = csv.writer(csvfile) writer.writerows([[ time.asctime(time.localtime(time.time())), end_time - start_time, self.cur_length, self.total_area / (self.cur_length * self.width), cur_overlap, self.poly_status, self.polys ]]) self.showPolys() self.plotRecord("Overlap Record:", self.overlap_reocrd)