You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:47:44