0

I am trying to visulize the result from a 3D bin packing model (showing how different size of items are packed in a larger bin).

Below is the full code and a visulization method using matplotlib3D. However, it cannot be saved in a 3D file like format which allow user to rotate it 360 degree after saving it to the desktop as png format. According to the model calculated position data for each item, how to generate .obj file with the same looking as matplotlib3D plot, or in html which allows it open in browser to rotate the picture.

from py3dbp import Packer, Bin, Item
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
import matplotlib.pyplot as plt
import random

trucks = [
    [250, 250, 500],
    [500, 500, 400],
    [300, 300, 300],
    [300, 300, 200],
    [300, 300, 100],
    [500, 500, 500]
]

for t in range(len(trucks)):
    packer = Packer()

    # packer.add_bin(Bin('small-envelope', 11.5, 6.125, 0.25, 10))
    # packer.add_bin(Bin('large-envelope', 15.0, 12.0, 0.75, 15))
    # packer.add_bin(Bin('small-box', 8.625, 5.375, 1.625, 70.0))
    # packer.add_bin(Bin('medium-box', 11.0, 8.5, 5.5, 70.0))
    # packer.add_bin(Bin('medium-2-box', 13.625, 11.875, 3.375, 70.0))
    # packer.add_bin(Bin('large-box', 240, 244, 1360, 70.0))
    # packer.add_bin(Bin('large-2-box', 23.6875, 11.75, 3.0, 70.0))

    truckX = trucks[t][0]
    truckY = trucks[t][1]
    truckZ = trucks[t][2]

    packer.add_bin(Bin('LB', truckX, truckY, truckZ, 3000.0))

    for i in range(300):
        packer.add_item(Item('boxL' + str(i), 20, 40, 20, 1))

    for i in range(10):
        packer.add_item(Item('boxU' + str(i), 100, 100, 100, 1))

    for i in range(5):
        packer.add_item(Item('boxU' + str(i), 200, 100, 50, 1))

    for i in range(10):
        packer.add_item(Item('boxU' + str(i), 40, 40, 20, 1))

    # packer.pack()
    packer.pack(bigger_first=False)

    positions = []
    sizes = []
    colors = []

    for b in packer.bins:
        print(":::::::::::", b.string())

        print("FITTED ITEMS:")
        for item in b.items:
            print("====> ", item.string())
            x = float(item.position[0])
            y = float(item.position[1])
            z = float(item.position[2])
            positions.append((x, y, z))
            sizes.append(
                (float(item.get_dimension()[0]), float(item.get_dimension()[1]), float(item.get_dimension()[2])))

        print("UNFITTED ITEMS:")
        for item in b.unfitted_items:
            print("====> ", item.string())

        print("***************************************************")
        print("***************************************************")


    def cuboid_data2(o, size=(1, 1, 1)):
        X = [[[0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 1, 0]],
             [[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]],
             [[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]],
             [[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]],
             [[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]],
             [[0, 1, 1], [0, 0, 1], [1, 0, 1], [1, 1, 1]]]
        X = np.array(X).astype(float)
        for i in range(3):
            X[:, :, i] *= size[i]
        X += np.array(o)
        return X


    def plotCubeAt2(positions, sizes=None, colors=None, **kwargs):
        if not isinstance(colors, (list, np.ndarray)): colors = ["C0"] * len(positions)
        if not isinstance(sizes, (list, np.ndarray)): sizes = [(1, 1, 1)] * len(positions)
        g = []
        for p, s, c in zip(positions, sizes, colors):
            g.append(cuboid_data2(p, size=s))
        return Poly3DCollection(np.concatenate(g),
                                facecolors=np.repeat(colors, 6), **kwargs)


    colorList = ["crimson", "limegreen", "g", "r", "c", "m", "y", "k"]

    for i in range(len(b.items)):
        f = random.randint(0, 7)
        colors.append(colorList[f])

    print(colors)

    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.set_aspect('auto')

    pc = plotCubeAt2(positions, sizes, colors=colors, edgecolor="k")
    ax.add_collection3d(pc)

    ax.set_xlim([0, truckX])
    ax.set_ylim([0, truckY])
    ax.set_zlim([0, truckZ])

    plt.show()

enter image description here

Zephyr
  • 11,891
  • 53
  • 45
  • 80
Jack
  • 1,339
  • 1
  • 12
  • 31

1 Answers1

0

You could use plotly package. It generates an interactive html file which can be opened in a browser. Here examples of 3D plots.
You can easly integrate some graphs and create an interactive dashboard (here some examples) with dash.
Both packages require a specific syntax (I won't report here the syntax to generate a plot because it is not your specific question), which you have to learn, but I think they are exactly what you need.
In alternative to plotly you can also use bokeh.

Zephyr
  • 11,891
  • 53
  • 45
  • 80
  • Hi Zephyr, I know this package but I am sure how it works. Could you kindly provide an example taking above data? If it works well, I believe it is useful for a great many people in the future visiting this post. – Jack Sep 04 '21 at 05:49
  • Sorry, but this is not a free code service. You have to show your effort to solve your problem. So I suggest you to open a question where you report your data (only your data, i.e. coordinates of boxes verteces, not the `py3dbp` code) and ask for a way to properly plot a plotly 3d graph, what do you want to achieve, reporting you effort to do that and the problem you can't solve – Zephyr Sep 04 '21 at 11:33