1

Add WIP code

This commit is contained in:
2024-11-21 11:44:08 +01:00
parent f7dc5cdb39
commit 49bbd2b3e7
2 changed files with 306 additions and 0 deletions

168
containers.py Normal file
View File

@ -0,0 +1,168 @@
import matplotlib.pyplot as plt
class Container:
def __init__(self, length, width, height, capacity):
self.length = length # Länge in m
self.width = width # Breite in m
self.height = height # Höhe in m
self.capacity = capacity # Gewichtskapazität in t
self.items = []
self.fitting = []
def volume(self):
return self.length * self.width * self.height
def used_volume(self):
if len(self.items) == 0:
raise Exception("Container empty, can't calculate used volume!")
return sum(item[0].volume() * item[1] for item in self.items)
def utilization_volume(self):
return self.used_volume() / self.volume() * 100
def used_weight(self):
if len(self.items) == 0:
raise Exception("Container empty, can't calculate load weight!")
return sum(item[0].weight * item[1] for item in self.items)
def utilization_weight(self):
return self.used_weight() / self.capacity * 100
def try_fit(self, items) -> bool:
self.items = items
if self.used_weight() > self.capacity:
print("Load too heavy!")
return False
if self.used_volume() > self.volume():
print("Load too large!")
return False
fitting = []
# Packstücke, Packordnung: Y, Z, X (Breite -> Höhe -> Länge)
x_offset = 0
y_offset = 0
z_offset = 0
for i, item_ in enumerate(items):
item, count = item_
for _ in range(count):
fitting += [
(
x_offset,
y_offset,
z_offset,
item.length,
item.width,
item.height,
COLORS[i],
)
]
if y_offset + item.width < self.width:
# Selbe "Zeile"
y_offset += item.width
elif z_offset + item.height < self.height:
y_offset = 0
# Neue "Ebene" (Höhe)
z_offset += item.height
elif x_offset + item.length < self.length:
y_offset = 0
z_offset = 0
# Neue "Scheibe" (Länge)
x_offset += item.length
else:
return False
if x_offset + item.length < self.length:
x_offset += item.length
else:
return False
y_offset = 0
z_offset = 0
self.fitting = fitting
return True
def visualize(self):
if len(self.fitting) == 0:
raise Exception("Container not fitted, can't visualize!")
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
# Container
ax.bar3d(0, 0, 0, self.length, self.width, self.height, alpha=0.1, color="gray")
# TODO: Don't add individual packages, combine them into blocks (perf)
# Packages
for x, y, z, l, w, h, color in self.fitting:
ax.bar3d(x, y, z, l, w, h, color=color)
ax.set_xlim([0, self.length])
ax.set_ylim([0, self.width])
ax.set_zlim([0, self.height])
ax.set_xlabel("Länge (cm)")
ax.set_ylabel("Breite (cm)")
ax.set_zlabel("Höhe (cm)")
plt.title(f"Container-Auslastung: {self.utilization_volume():.2f}%")
plt.autoscale()
plt.show()
class Item:
def __init__(self, length, width, height, weight):
self.length = length # Länge in cm
self.width = width # Breite in cm
self.height = height # Höhe in cm
self.weight = weight # Gewicht in kg
def volume(self):
return self.length * self.width * self.height
# Length (cm), Width (cm), Height (cm), Capacity (kg)
CONTAINERS = {
"20'": Container(590, 235, 239, 21670),
"40'": Container(1203, 240, 239, 25680),
"40'HQ": Container(1203, 235, 269, 26480),
}
COLORS = ["red", "blue", "green", "yellow", "purple"]
def main():
print("Container-Auslastungsrechner")
items = []
while True:
print("\nNeues Packstück hinzufügen:")
length = float(input("Länge (cm): "))
width = float(input("Breite (cm): "))
height = float(input("Höhe (cm): "))
weight = float(input("Gewicht (kg): "))
count = int(input("Anzahl der Packstücke: "))
item = Item(length, width, height, weight)
items += [(item, count)]
more_items = input("Weitere Packstücke hinzufügen? (ja/nein): ").strip().lower()
if more_items != "ja":
break
for name, container in CONTAINERS.items():
if container.try_fit(items):
print(
f"\nBenötigter Container: {name}, Gesamtauslastung (Volumen): {container.utilization_volume():.2f}%, Ladungsgewicht: {container.used_weight()}kg, Gesamtauslastung (Gewicht): {container.utilization_weight():.2f}%"
)
container.visualize()
return
print("Couldn't find fitting container!")
if __name__ == "__main__":
main()

138
containersV2.py Normal file
View File

@ -0,0 +1,138 @@
from typing import Dict, List, Tuple
import ezdxf
from ezdxf import colors
from ezdxf.addons import binpacking as bp
from ezdxf.addons.drawing import RenderContext, Frontend, matplotlib
from ezdxf.addons.drawing.matplotlib import MatplotlibBackend
import matplotlib.pyplot as plt
# Length (cm), Width (cm), Height (cm), Capacity (kg)
CONTAINERS: List[Tuple[str, float, float, float, float]] = [
("20'", 590, 235, 239, 21670),
("40'", 1203, 240, 239, 25680),
("40'HQ", 1203, 235, 269, 26480),
]
COLORS: List[str] = ["red", "blue", "green", "yellow", "purple"]
def float_input(msg: str) -> float:
read_str: str = input(f"{msg}: ")
read_float: float
try:
read_float = float(read_str)
except:
return float_input(msg)
return read_float
def int_input(msg: str) -> int:
read_str: str = input(f"{msg}: ")
read_int: int
try:
read_int = int(read_str)
except:
return int_input(msg)
return read_int
def yes_no_input(msg: str) -> bool:
read_str: str = input(f"{msg} (j/n): ").strip().lower()
if read_str == "j":
return True
elif read_str == "n":
return False
else:
return yes_no_input(msg)
def build_packer(
items: List[Tuple[Tuple[float, float, float, float], int]]
) -> bp.Packer:
packer: bp.Packer = bp.Packer()
for i, ((length, width, height, weight), count) in enumerate(items):
for ii in range(count):
packer.add_item(f"Item {i}_{ii}", width, height, length, weight)
return packer
def make_doc():
doc = ezdxf.new()
doc.layers.add("FRAME", color=colors.YELLOW)
doc.layers.add("ITEMS")
doc.layers.add("TEXT")
return doc
def main() -> None:
print("Container-Auslastungsrechner")
items: List[Tuple[Tuple[float, float, float, float], int]] = []
more_items: bool = True
while more_items:
print("\nNeues Packstück hinzufügen:")
length = float_input("- Länge (cm)")
width = float_input("- Breite (cm)")
height = float_input("- Höhe (cm)")
weight = float_input("- Gewicht (kg)")
count = int_input("- Packstückzahl")
items += [((length, width, height, weight), count)]
more_items = yes_no_input("Weitere Packstücke hinzufügen?")
for name, length, width, height, capacity in CONTAINERS:
print(
f"Teste {name:>5} Container ({length / 100:>5.2f}m x {width / 100:>5.2f}m x {height / 100:>5.2f}m mit {capacity / 1000:>5.2f}t)..."
)
packer: bp.Packer = build_packer(items)
packer.add_bin(name, width, height, length, capacity)
packer.pack(bp.PickStrategy.BIGGER_FIRST)
if len(packer.unfitted_items) > 0:
print(f"{name} Container ist zu klein!")
break
bins: List[bp.Bin] = []
bins.extend(packer.bins)
doc = make_doc()
bp.export_dxf(doc.modelspace(), bins, offset=(0, 20, 0))
# doc.saveas("packing.dxf")
print(
f"{name} Container passt: Zu {packer.get_fill_ratio() * 100:.2f}% gefüllt ({packer.get_total_weight():.2f}kg)"
)
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
# Container bounding box
ax.bar3d(0, 0, 0, length, width, height, alpha=0.1, color="gray")
# Package bounding boxes
for it in packer.bins[0].items:
x, y, z = it.position
w, h, l = it.width, it.height, it.depth
ax.bar3d(x, y, z, l, w, h, color="red")
plt.title(
f"{name} Container mit {packer.get_fill_ratio() * 100:.2f}% Auslastung"
)
plt.autoscale()
plt.show()
return
print("Konnte keinen passenden Container ermitteln!")
if __name__ == "__main__":
main()