基于py3dbp的装箱可视化交互功能开发技术求助
实现PyQt5与3D装箱视图的交互联动
1. 核心思路
要实现列表与3D视图的联动,关键是将物品实例与其对应的3D绘图对象绑定,并通过列表选中事件触发颜色切换逻辑:
- 给每个装箱后的物品添加自定义属性,存储其3D图中的绘图对象和原始颜色
- 在PyQt5列表项中绑定对应的物品实例
- 监听列表选中事件,遍历所有物品的3D对象,切换选中/未选中状态的颜色
2. 完整代码实现
import sys from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QListWidget, QListWidgetItem import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D, art3d from py3dbp import Packer, Bin, Item # 读取Excel物品数据(替换为你的实际读取逻辑) def load_items_from_excel(): # 示例数据,实际场景中用pandas读取Excel return [ Item("Box_A", 12, 8, 6, 2), Item("Box_B", 15, 10, 7, 3), Item("Box_C", 9, 9, 9, 1), Item("Box_D", 20, 8, 5, 4) ] class InteractivePackingViewer(QWidget): def __init__(self): super().__init__() self.init_layout() self.run_packing() self.bind_interaction() def init_layout(self): self.setWindowTitle("装箱可视化交互") main_layout = QHBoxLayout() # 左侧物品列表 self.item_list = QListWidget() main_layout.addWidget(self.item_list) # 右侧3D画布 self.figure = plt.figure(figsize=(8, 8)) self.ax = self.figure.add_subplot(111, projection='3d') from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas self.canvas = FigureCanvas(self.figure) main_layout.addWidget(self.canvas) self.setLayout(main_layout) def run_packing(self): # 初始化装箱器 packer = Packer() packer.add_bin(Bin("MainBin", 50, 40, 30, 100)) items = load_items_from_excel() for item in items: packer.add_item(item) # 执行装箱计算 packer.pack() self.all_packed_items = packer.bins[0].items # 绘制箱体 self.draw_cube(self.ax, 0, 0, 0, 50, 40, 30, color=(0.9, 0.9, 0.9, 0.2)) # 绘制每个物品并绑定3D对象与原始颜色 color_index = 0 for item in self.all_packed_items: # 生成区分色 base_color = plt.cm.Set2(color_index % 8)[:3] # 绘制立方体并获取3D对象 cube_obj = self.draw_cube( self.ax, item.position[0], item.position[1], item.position[2], item.width, item.height, item.depth, color=base_color ) # 给物品实例绑定属性 item.3d_obj = cube_obj item.original_color = base_color color_index += 1 # 添加到列表 list_item = QListWidgetItem(f"{item.name} | {item.width}×{item.height}×{item.depth}") list_item.setData(0, item) # 绑定物品实例 self.item_list.addItem(list_item) # 设置3D轴标签 self.ax.set_xlabel("Width") self.ax.set_ylabel("Height") self.ax.set_zlabel("Depth") self.canvas.draw() def draw_cube(self, ax, x, y, z, w, h, d, color): # 定义立方体6个面的顶点坐标 faces = [ [(x, y, z), (x+w, y, z), (x+w, y+h, z), (x, y+h, z)], [(x, y, z+d), (x+w, y, z+d), (x+w, y+h, z+d), (x, y+h, z+d)], [(x, y, z), (x+w, y, z), (x+w, y, z+d), (x, y, z+d)], [(x, y+h, z), (x+w, y+h, z), (x+w, y+h, z+d), (x, y+h, z+d)], [(x, y, z), (x, y+h, z), (x, y+h, z+d), (x, y, z+d)], [(x+w, y, z), (x+w, y+h, z), (x+w, y+h, z+d), (x+w, y, z+d)] ] cube = art3d.Poly3DCollection(faces, facecolors=color, edgecolors="black") ax.add_collection3d(cube) return cube def bind_interaction(self): # 绑定列表选中事件 self.item_list.itemSelectionChanged.connect(self.update_3d_view) def update_3d_view(self): selected_items = self.item_list.selectedItems() if not selected_items: # 无选中时恢复所有物品原色 for item in self.all_packed_items: item.3d_obj.set_facecolor(item.original_color) else: # 获取选中的物品实例 target_item = selected_items[0].data(0) # 遍历所有物品切换颜色 for item in self.all_packed_items: if item == target_item: item.3d_obj.set_facecolor(item.original_color) else: item.3d_obj.set_facecolor((0.5, 0.5, 0.5, 1)) # 灰色 # 刷新3D画布 self.canvas.draw() if __name__ == "__main__": app = QApplication(sys.argv) viewer = InteractivePackingViewer() viewer.show() sys.exit(app.exec_())
3. 关键注意事项
- 如果使用Mayavi等其他3D库,只需替换
draw_cube方法和颜色设置API(比如Mayavi中用actor.property.color) - 若Excel物品有重名,建议在列表项中加入唯一ID(如物品序号)避免混淆
- 多选中场景可扩展逻辑:遍历所有选中的列表项,保留多个物品的原色,其余变灰
内容的提问来源于stack exchange,提问作者JakeP
相关产品推荐
相关产品推荐

