├── tempCodeRunnerFile.py
├── py3dbp
├── __init__.py
├── __pycache__
│ ├── main.cpython-36.pyc
│ ├── main.cpython-37.pyc
│ ├── main.cpython-38.pyc
│ ├── __init__.cpython-36.pyc
│ ├── __init__.cpython-37.pyc
│ ├── __init__.cpython-38.pyc
│ ├── constants.cpython-36.pyc
│ ├── constants.cpython-37.pyc
│ ├── constants.cpython-38.pyc
│ ├── auxiliary_methods.cpython-36.pyc
│ ├── auxiliary_methods.cpython-37.pyc
│ └── auxiliary_methods.cpython-38.pyc
├── constants.py
├── auxiliary_methods.py
└── main.py
├── makale.pdf
├── Screens
├── 1_1.png
├── 1_2.png
├── 1_3.png
├── 1_4.png
├── 1_5.png
├── 1_6.png
├── 2_1.png
├── 2_2.png
├── 2_3.png
├── 2_4.png
├── 2_5.png
├── 2_6.png
├── 3_1.png
├── 3_2.png
├── 3_3.png
├── 3_4.png
├── 3_5.png
└── 3_6.png
├── .idea
├── misc.xml
├── vcs.xml
├── .gitignore
├── inspectionProfiles
│ └── profiles_settings.xml
├── other.xml
├── modules.xml
└── BB-container-problem.iml
├── setup.py
├── LICENSE
├── README.md
└── visualize.py
/tempCodeRunnerFile.py:
--------------------------------------------------------------------------------
1 | 240
--------------------------------------------------------------------------------
/py3dbp/__init__.py:
--------------------------------------------------------------------------------
1 | from .main import Packer, Bin, Item
2 |
--------------------------------------------------------------------------------
/makale.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/makale.pdf
--------------------------------------------------------------------------------
/Screens/1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/1_1.png
--------------------------------------------------------------------------------
/Screens/1_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/1_2.png
--------------------------------------------------------------------------------
/Screens/1_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/1_3.png
--------------------------------------------------------------------------------
/Screens/1_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/1_4.png
--------------------------------------------------------------------------------
/Screens/1_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/1_5.png
--------------------------------------------------------------------------------
/Screens/1_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/1_6.png
--------------------------------------------------------------------------------
/Screens/2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/2_1.png
--------------------------------------------------------------------------------
/Screens/2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/2_2.png
--------------------------------------------------------------------------------
/Screens/2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/2_3.png
--------------------------------------------------------------------------------
/Screens/2_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/2_4.png
--------------------------------------------------------------------------------
/Screens/2_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/2_5.png
--------------------------------------------------------------------------------
/Screens/2_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/2_6.png
--------------------------------------------------------------------------------
/Screens/3_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/3_1.png
--------------------------------------------------------------------------------
/Screens/3_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/3_2.png
--------------------------------------------------------------------------------
/Screens/3_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/3_3.png
--------------------------------------------------------------------------------
/Screens/3_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/3_4.png
--------------------------------------------------------------------------------
/Screens/3_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/3_5.png
--------------------------------------------------------------------------------
/Screens/3_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/Screens/3_6.png
--------------------------------------------------------------------------------
/py3dbp/__pycache__/main.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/main.cpython-36.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/main.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/main.cpython-37.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/main.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/main.cpython-38.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/__init__.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/__init__.cpython-38.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/constants.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/constants.cpython-36.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/constants.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/constants.cpython-37.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/constants.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/constants.cpython-38.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/auxiliary_methods.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/auxiliary_methods.cpython-36.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/auxiliary_methods.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/auxiliary_methods.cpython-37.pyc
--------------------------------------------------------------------------------
/py3dbp/__pycache__/auxiliary_methods.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ylmz-dev/3d-bin-packing-problem/HEAD/py3dbp/__pycache__/auxiliary_methods.cpython-38.pyc
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/other.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/py3dbp/constants.py:
--------------------------------------------------------------------------------
1 | class RotationType:
2 | RT_WHD = 0
3 | RT_HWD = 1
4 | RT_HDW = 2
5 | RT_DHW = 3
6 | RT_DWH = 4
7 | RT_WDH = 5
8 |
9 | ALL = [RT_WHD, RT_HWD, RT_HDW, RT_DHW, RT_DWH, RT_WDH]
10 |
11 |
12 | class Axis:
13 | WIDTH = 0
14 | HEIGHT = 1
15 | DEPTH = 2
16 |
17 | ALL = [WIDTH, HEIGHT, DEPTH]
18 |
--------------------------------------------------------------------------------
/.idea/BB-container-problem.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | with open("README.md", "r") as fh:
4 | long_description = fh.read()
5 |
6 | setuptools.setup(
7 | name='py3dbp',
8 | version='1.1',
9 | author="Enzo Ruiz Pelaez",
10 | author_email="enzo.rp.90@gmail.com",
11 | description="3D Bin Packing",
12 | long_description=long_description,
13 | long_description_content_type="text/markdown",
14 | url="https://github.com/enzoruiz/3dbinpacking",
15 | packages=setuptools.find_packages(),
16 | classifiers=[
17 | "Programming Language :: Python :: 3",
18 | "License :: OSI Approved :: MIT License",
19 | "Operating System :: OS Independent",
20 | ],
21 | )
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/py3dbp/auxiliary_methods.py:
--------------------------------------------------------------------------------
1 | from decimal import Decimal
2 | from .constants import Axis
3 |
4 |
5 | def rect_intersect(item1, item2, x, y):
6 | d1 = item1.get_dimension()
7 | d2 = item2.get_dimension()
8 |
9 | cx1 = item1.position[x] + d1[x]/2
10 | cy1 = item1.position[y] + d1[y]/2
11 | cx2 = item2.position[x] + d2[x]/2
12 | cy2 = item2.position[y] + d2[y]/2
13 |
14 | ix = max(cx1, cx2) - min(cx1, cx2)
15 | iy = max(cy1, cy2) - min(cy1, cy2)
16 |
17 | return ix < (d1[x]+d2[x])/2 and iy < (d1[y]+d2[y])/2
18 |
19 |
20 | def intersect(item1, item2):
21 | return (
22 | rect_intersect(item1, item2, Axis.WIDTH, Axis.HEIGHT) and
23 | rect_intersect(item1, item2, Axis.HEIGHT, Axis.DEPTH) and
24 | rect_intersect(item1, item2, Axis.WIDTH, Axis.DEPTH)
25 | )
26 |
27 |
28 | def get_limit_number_of_decimals(number_of_decimals):
29 | return Decimal('1.{}'.format('0' * number_of_decimals))
30 |
31 |
32 | def set_to_decimal(value, number_of_decimals):
33 | number_of_decimals = get_limit_number_of_decimals(number_of_decimals)
34 |
35 | return Decimal(value).quantize(number_of_decimals)
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 3D Bin Packing Problem
2 | ====
3 |
4 | 3D Bin Packing implementasyonu bu makale baz alınarak geliştirilmiştir. [Makale](makale.pdf). Referans kod: [gedex](https://github.com/gedex/bp3d).
5 |
6 | ## Açıklama
7 |
8 | Bin ve item parametrelerinin tanımlanması:
9 | ```py
10 | my_bin = Bin(name, width, height, depth, max_weight)
11 | my_item = Item(name, width, height, depth, weight)
12 | ```
13 | Packer 3 temel fonksiyona sahip:
14 | ```py
15 | packer = Packer() # PACKER DEFINITION
16 |
17 | packer.add_bin(my_bin) # ADDING BINS TO PACKER
18 | packer.add_item(my_item) # ADDING ITEMS TO PACKER
19 |
20 | packer.pack() # PACKING - by default (bigger_first=False, distribute_items=False, number_of_decimals=3)
21 | ```
22 |
23 | Packing işlemi sonrasında:
24 | ```py
25 | packer.bins # GET ALL BINS OF PACKER
26 | my_bin.items # GET ALL FITTED ITEMS IN EACH BIN
27 | my_bin.unfitted_items # GET ALL UNFITTED ITEMS IN EACH BIN
28 | ```
29 |
30 |
31 | ## Kullanım
32 |
33 | Packer oluşturulup istenilen sayıda bin ve istenilen binlere gerekli itemlar eklenebilir. .pack() fonksiyonu verilen bilgiler doğrusunda packing işlemini geçekleştirecektir.
34 |
35 | ```py
36 | from py3dbp import Packer, Bin, Item
37 |
38 | packer = Packer()
39 |
40 | packer.add_bin(Bin('small-envelope', 11.5, 6.125, 0.25, 10))
41 | packer.add_bin(Bin('large-envelope', 15.0, 12.0, 0.75, 15))
42 | packer.add_bin(Bin('small-box', 8.625, 5.375, 1.625, 70.0))
43 | packer.add_bin(Bin('medium-box', 11.0, 8.5, 5.5, 70.0))
44 | packer.add_bin(Bin('medium-2-box', 13.625, 11.875, 3.375, 70.0))
45 | packer.add_bin(Bin('large-box', 12.0, 12.0, 5.5, 70.0))
46 | packer.add_bin(Bin('large-2-box', 23.6875, 11.75, 3.0, 70.0))
47 |
48 | packer.add_item(Item('50g [powder 1]', 3.9370, 1.9685, 1.9685, 1))
49 | packer.add_item(Item('50g [powder 2]', 3.9370, 1.9685, 1.9685, 2))
50 | packer.add_item(Item('50g [powder 3]', 3.9370, 1.9685, 1.9685, 3))
51 | packer.add_item(Item('250g [powder 4]', 7.8740, 3.9370, 1.9685, 4))
52 | packer.add_item(Item('250g [powder 5]', 7.8740, 3.9370, 1.9685, 5))
53 | packer.add_item(Item('250g [powder 6]', 7.8740, 3.9370, 1.9685, 6))
54 | packer.add_item(Item('250g [powder 7]', 7.8740, 3.9370, 1.9685, 7))
55 | packer.add_item(Item('250g [powder 8]', 7.8740, 3.9370, 1.9685, 8))
56 | packer.add_item(Item('250g [powder 9]', 7.8740, 3.9370, 1.9685, 9))
57 |
58 | packer.pack()
59 |
60 | for b in packer.bins:
61 | print(":::::::::::", b.string())
62 |
63 | print("FITTED ITEMS:")
64 | for item in b.items:
65 | print("====> ", item.string())
66 |
67 | print("UNFITTED ITEMS:")
68 | for item in b.unfitted_items:
69 | print("====> ", item.string())
70 |
71 | print("***************************************************")
72 | print("***************************************************")
73 |
74 | ```
75 | ## GÖRSELLEŞTİRME
76 | visualize.py dosyası kullanılarak 3 boyutlu görselleştirilmiş sonuçlara doğrudan ulaşılabilir.
77 |
78 | ### Örnek görselleştirmeler
79 | 
80 | 
81 |
82 |
83 | ## TEST DENEMELERİ
84 | Denenen test case senaryolarının sonuçlarına ve görselleştirmelerine aşağıda linkteki Python Repository sekmesinden ulaşabilirsiniz.
85 | > https://docs.google.com/spreadsheets/d/1GicB3rwzPJe_Hlm_xAzUpQnWtp2qObtKjfGarEcGwDI/edit?usp=sharing
86 |
87 | ## REFERANSLAR
88 |
89 | * https://github.com/bom-d-van/binpacking
90 | * https://github.com/gedex/bp3d
91 | * [MAKALE: Optimizing three-dimensional bin packing through simulation](makale.pdf)
92 |
--------------------------------------------------------------------------------
/visualize.py:
--------------------------------------------------------------------------------
1 | from py3dbp import Packer, Bin, Item
2 | from mpl_toolkits.mplot3d import Axes3D
3 | from mpl_toolkits.mplot3d.art3d import Poly3DCollection
4 | import numpy as np
5 | import matplotlib.pyplot as plt
6 | import random
7 |
8 | trucks = [
9 | [250, 250, 500],
10 | [500, 500, 400],
11 | [300, 300, 300],
12 | [300, 300, 200],
13 | [300, 300, 100],
14 | [500, 500, 500]
15 | ]
16 |
17 |
18 |
19 |
20 | for t in range(len(trucks)):
21 | packer = Packer()
22 |
23 | #packer.add_bin(Bin('small-envelope', 11.5, 6.125, 0.25, 10))
24 | #packer.add_bin(Bin('large-envelope', 15.0, 12.0, 0.75, 15))
25 | #packer.add_bin(Bin('small-box', 8.625, 5.375, 1.625, 70.0))
26 | #packer.add_bin(Bin('medium-box', 11.0, 8.5, 5.5, 70.0))
27 | #packer.add_bin(Bin('medium-2-box', 13.625, 11.875, 3.375, 70.0))
28 | #packer.add_bin(Bin('large-box', 240, 244, 1360, 70.0))
29 | #packer.add_bin(Bin('large-2-box', 23.6875, 11.75, 3.0, 70.0))
30 |
31 | truckX = trucks[t][0]
32 | truckY = trucks[t][1]
33 | truckZ = trucks[t][2]
34 |
35 | packer.add_bin(Bin('LB', truckX, truckY, truckZ, 3000.0))
36 |
37 |
38 | for i in range(300):
39 | packer.add_item(Item('boxL'+str(i), 20, 40, 20, 1))
40 |
41 | for i in range(10):
42 | packer.add_item(Item('boxU'+str(i), 100, 100, 100, 1))
43 |
44 | for i in range(5):
45 | packer.add_item(Item('boxU'+str(i), 200, 100, 50, 1))
46 |
47 | for i in range(10):
48 | packer.add_item(Item('boxU'+str(i), 40, 40, 20, 1))
49 |
50 |
51 | #packer.pack()
52 | packer.pack(bigger_first=False)
53 |
54 | positions = []
55 | sizes = []
56 | colors = []
57 |
58 |
59 | for b in packer.bins:
60 | print(":::::::::::", b.string())
61 |
62 | print("FITTED ITEMS:")
63 | for item in b.items:
64 | print("====> ", item.string())
65 | x = float(item.position[0])
66 | y = float(item.position[1])
67 | z = float(item.position[2])
68 | positions.append((x,y,z))
69 | sizes.append((float(item.get_dimension()[0]), float(item.get_dimension()[1]), float(item.get_dimension()[2])))
70 |
71 | print("UNFITTED ITEMS:")
72 | for item in b.unfitted_items:
73 | print("====> ", item.string())
74 |
75 |
76 | print("***************************************************")
77 | print("***************************************************")
78 |
79 |
80 |
81 | def cuboid_data2(o, size=(1,1,1)):
82 | X = [[[0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 1, 0]],
83 | [[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]],
84 | [[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]],
85 | [[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]],
86 | [[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]],
87 | [[0, 1, 1], [0, 0, 1], [1, 0, 1], [1, 1, 1]]]
88 | X = np.array(X).astype(float)
89 | for i in range(3):
90 | X[:,:,i] *= size[i]
91 | X += np.array(o)
92 | return X
93 |
94 | def plotCubeAt2(positions,sizes=None,colors=None, **kwargs):
95 | if not isinstance(colors,(list,np.ndarray)): colors=["C0"]*len(positions)
96 | if not isinstance(sizes,(list,np.ndarray)): sizes=[(1,1,1)]*len(positions)
97 | g = []
98 | for p,s,c in zip(positions,sizes,colors):
99 | g.append( cuboid_data2(p, size=s) )
100 | return Poly3DCollection(np.concatenate(g),
101 | facecolors=np.repeat(colors,6), **kwargs)
102 |
103 |
104 | colorList = ["crimson","limegreen","g","r","c","m","y","k"]
105 |
106 | for i in range(len(b.items)):
107 | f = random.randint(0,7)
108 | colors.append(colorList[f])
109 |
110 | print(colors)
111 |
112 | fig = plt.figure()
113 | ax = fig.gca(projection='3d')
114 | ax.set_aspect('auto')
115 |
116 | pc = plotCubeAt2(positions,sizes,colors=colors, edgecolor="k")
117 | ax.add_collection3d(pc)
118 |
119 | ax.set_xlim([0,truckX])
120 | ax.set_ylim([0,truckY])
121 | ax.set_zlim([0,truckZ])
122 |
123 | plt.show()
124 |
125 |
126 |
--------------------------------------------------------------------------------
/py3dbp/main.py:
--------------------------------------------------------------------------------
1 | from .constants import RotationType, Axis
2 | from .auxiliary_methods import intersect, set_to_decimal
3 |
4 | DEFAULT_NUMBER_OF_DECIMALS = 3
5 | START_POSITION = [0, 0, 0]
6 |
7 |
8 | class Item:
9 | def __init__(self, name, width, height, depth, weight):
10 | self.name = name
11 | self.width = width
12 | self.height = height
13 | self.depth = depth
14 | self.weight = weight
15 | self.rotation_type = 0
16 | self.position = START_POSITION
17 | self.number_of_decimals = DEFAULT_NUMBER_OF_DECIMALS
18 |
19 | def format_numbers(self, number_of_decimals):
20 | self.width = set_to_decimal(self.width, number_of_decimals)
21 | self.height = set_to_decimal(self.height, number_of_decimals)
22 | self.depth = set_to_decimal(self.depth, number_of_decimals)
23 | self.weight = set_to_decimal(self.weight, number_of_decimals)
24 | self.number_of_decimals = number_of_decimals
25 |
26 | def string(self):
27 | return "%s(%sx%sx%s, weight: %s) pos(%s) rt(%s) vol(%s)" % (
28 | self.name, self.width, self.height, self.depth, self.weight,
29 | self.position, self.rotation_type, self.get_volume()
30 | )
31 |
32 | def get_volume(self):
33 | return set_to_decimal(
34 | self.width * self.height * self.depth, self.number_of_decimals
35 | )
36 |
37 | def get_dimension(self):
38 | if self.rotation_type == RotationType.RT_WHD:
39 | dimension = [self.width, self.height, self.depth]
40 | elif self.rotation_type == RotationType.RT_HWD:
41 | dimension = [self.height, self.width, self.depth]
42 | elif self.rotation_type == RotationType.RT_HDW:
43 | dimension = [self.height, self.depth, self.width]
44 | elif self.rotation_type == RotationType.RT_DHW:
45 | dimension = [self.depth, self.height, self.width]
46 | elif self.rotation_type == RotationType.RT_DWH:
47 | dimension = [self.depth, self.width, self.height]
48 | elif self.rotation_type == RotationType.RT_WDH:
49 | dimension = [self.width, self.depth, self.height]
50 | else:
51 | dimension = []
52 |
53 | return dimension
54 |
55 |
56 | class Bin:
57 | def __init__(self, name, width, height, depth, max_weight):
58 | self.name = name
59 | self.width = width
60 | self.height = height
61 | self.depth = depth
62 | self.max_weight = max_weight
63 | self.items = []
64 | self.unfitted_items = []
65 | self.number_of_decimals = DEFAULT_NUMBER_OF_DECIMALS
66 |
67 | def format_numbers(self, number_of_decimals):
68 | self.width = set_to_decimal(self.width, number_of_decimals)
69 | self.height = set_to_decimal(self.height, number_of_decimals)
70 | self.depth = set_to_decimal(self.depth, number_of_decimals)
71 | self.max_weight = set_to_decimal(self.max_weight, number_of_decimals)
72 | self.number_of_decimals = number_of_decimals
73 |
74 | def string(self):
75 | return "%s(%sx%sx%s, max_weight:%s) vol(%s)" % (
76 | self.name, self.width, self.height, self.depth, self.max_weight,
77 | self.get_volume()
78 | )
79 |
80 | def get_volume(self):
81 | return set_to_decimal(
82 | self.width * self.height * self.depth, self.number_of_decimals
83 | )
84 |
85 | def get_total_weight(self):
86 | total_weight = 0
87 |
88 | for item in self.items:
89 | total_weight += item.weight
90 |
91 | return set_to_decimal(total_weight, self.number_of_decimals)
92 |
93 | def put_item(self, item, pivot):
94 | fit = False
95 | valid_item_position = item.position
96 | item.position = pivot
97 |
98 | for i in range(0, len(RotationType.ALL)):
99 | item.rotation_type = i
100 | dimension = item.get_dimension()
101 | if (
102 | self.width < pivot[0] + dimension[0] or
103 | self.height < pivot[1] + dimension[1] or
104 | self.depth < pivot[2] + dimension[2]
105 | ):
106 | continue
107 |
108 | fit = True
109 |
110 | for current_item_in_bin in self.items:
111 | if intersect(current_item_in_bin, item):
112 | fit = False
113 | break
114 |
115 | if fit:
116 | if self.get_total_weight() + item.weight > self.max_weight:
117 | fit = False
118 | return fit
119 |
120 | self.items.append(item)
121 |
122 | if not fit:
123 | item.position = valid_item_position
124 |
125 | return fit
126 |
127 | if not fit:
128 | item.position = valid_item_position
129 |
130 | return fit
131 |
132 |
133 | class Packer:
134 | def __init__(self):
135 | self.bins = []
136 | self.items = []
137 | self.unfit_items = []
138 | self.total_items = 0
139 |
140 | def add_bin(self, bin):
141 | return self.bins.append(bin)
142 |
143 | def add_item(self, item):
144 | self.total_items = len(self.items) + 1
145 |
146 | return self.items.append(item)
147 |
148 | def pack_to_bin(self, bin, item):
149 | fitted = False
150 |
151 | if not bin.items:
152 | response = bin.put_item(item, START_POSITION)
153 |
154 | if not response:
155 | bin.unfitted_items.append(item)
156 |
157 | return
158 |
159 | for axis in range(0, 3):
160 | items_in_bin = bin.items
161 |
162 | for ib in items_in_bin:
163 | pivot = [0, 0, 0]
164 | w, h, d = ib.get_dimension()
165 | if axis == Axis.WIDTH:
166 | pivot = [
167 | ib.position[0] + w,
168 | ib.position[1],
169 | ib.position[2]
170 | ]
171 | elif axis == Axis.HEIGHT:
172 | pivot = [
173 | ib.position[0],
174 | ib.position[1] + h,
175 | ib.position[2]
176 | ]
177 | elif axis == Axis.DEPTH:
178 | pivot = [
179 | ib.position[0],
180 | ib.position[1],
181 | ib.position[2] + d
182 | ]
183 |
184 | if bin.put_item(item, pivot):
185 | fitted = True
186 | break
187 | if fitted:
188 | break
189 |
190 | if not fitted:
191 | bin.unfitted_items.append(item)
192 |
193 | def pack(
194 | self, bigger_first=False, distribute_items=False,
195 | number_of_decimals=DEFAULT_NUMBER_OF_DECIMALS
196 | ):
197 | for bin in self.bins:
198 | bin.format_numbers(number_of_decimals)
199 |
200 | for item in self.items:
201 | item.format_numbers(number_of_decimals)
202 |
203 | self.bins.sort(
204 | key=lambda bin: bin.get_volume(), reverse=bigger_first
205 | )
206 | self.items.sort(
207 | key=lambda item: item.get_volume(), reverse=bigger_first
208 | )
209 |
210 | for bin in self.bins:
211 | for item in self.items:
212 | self.pack_to_bin(bin, item)
213 |
214 | if distribute_items:
215 | for item in bin.items:
216 | self.items.remove(item)
217 |
--------------------------------------------------------------------------------