Skip to content

Instantly share code, notes, and snippets.

@PennRobotics
Created October 5, 2021 22:14
Show Gist options
  • Save PennRobotics/f419cf621a92b9e680d0cd9d4205f074 to your computer and use it in GitHub Desktop.
Save PennRobotics/f419cf621a92b9e680d0cd9d4205f074 to your computer and use it in GitHub Desktop.
Spice drawer simple packing optimization
#!/usr/bin/env python3
# This is used to determine the best cylinder packing for a rectangular spice drawer
import numpy as np
from math import pi, sqrt
"""
VARIABLES
"""
DEBUG = 0
if DEBUG:
d_list = [4.9]
else:
d_min = 3.55 # 4.65
d_max = 5.60 # 4.95
step = 0.05 # 0.01
d_list = [round(_, 2) for _ in np.arange(d_min, d_max + step, step)]
w = 30.5
l = 47.1
h = 9.0 # unused
"""
ROUTINES
"""
def debug(string):
if DEBUG:
print(string)
pass
"""
CALCULATIONS
"""
area = round(w * l, 4)
target_hex = round(0.9069 * area, 3)
target_rect = round(0.7854 * area, 3)
worst_case = round(0.5390 * area, 3)
a_list = []
# Calculate naive solutions for each diameter
for d in d_list:
circle_area = round(pi * (d**2) / 4, 5)
hex_diag_dist = d * 0.5 * sqrt(3)
debug(f'width {w}, '\
f'length {l}, '\
f'diameter {d}, '\
f'hex RA dist {round(hex_diag_dist,3)}, '\
f'CA {round(circle_area,3)}')
# Base case: rectangular packing from one corner, no gap filling
n_rows = int(w / d)
n_cols = int(l / d)
n_rect = n_rows * n_cols
rect_area = n_rect * circle_area
debug(f'RECT: {n_rows} per row, {n_cols} per col')
# Hex packing with straight rows from one edge only, no gap filling
n_even_rows = n_rows
rows = 1 + int((l - d) / hex_diag_dist)
n_odd_rows = int(w / d - 0.5)
odd_rows = int(rows / 2)
even_rows = rows - odd_rows
n_hex_1 = n_even_rows * even_rows + n_odd_rows * odd_rows
hex_1_area = n_hex_1 * circle_area
debug(f'ROWS: {n_even_rows} per even, {n_odd_rows} per odd, {rows} rows ({odd_rows} odd)')
# Hex packing with straight columns from one edge only, no gap filling
n_even_cols = n_cols
cols = 1 + int((w - d) / hex_diag_dist)
n_odd_cols = int(l / d - 0.5)
odd_cols = int(cols / 2)
even_cols = cols - odd_cols
n_hex_2 = n_even_cols * even_cols + n_odd_cols * odd_cols
hex_2_area = n_hex_2 * circle_area
debug(f'COLS: {n_even_cols} per even, {n_odd_cols} per odd, {cols} cols ({odd_cols} odd)')
a_list.append( (rect_area, hex_1_area, hex_2_area, n_rect, n_hex_1, n_hex_2) )
debug(f'AREA: {area}, '\
f'BEST HEX: {target_hex}, '\
f'BEST SQUARE: {target_rect}, '\
f'WORST CASE: {worst_case}')
# "Ideal" compares the best area for a particular packing method with the actual area
# "Total" compares the used area with the available area
print(f'DIAMETER \tRECT/SQUARE-PACKED ideal / total \tHEX, STRAIGHT ROWS ideal / total \tHEX, STRAIGHT COLS ideal / total')
print(f'======== \t================== ====== ====== \t================== ====== / ====== \t================== ====== / ======')
for i in range(len(a_list)):
ra, h1a, h2a, nr, nh1, nh2 = [round(elem, 2) for elem in a_list[i]]
dia = d_list[i]
rec_rec_eta = round(100 * ra / target_rect, 2)
h1a_hex_eta = round(100 * h1a / target_hex, 2)
h2a_hex_eta = round(100 * h2a / target_hex, 2)
rec_total_eta = round(100 * ra / area, 2)
h1a_total_eta = round(100 * h1a / area, 2)
h2a_total_eta = round(100 * h2a / area, 2)
print(f'd = {dia:.2f}, \t'\
f'RECT: { ra:>7.2f} (qty { nr:>3}, {rec_rec_eta:.2f}% / {rec_total_eta:.2f}%), \t'\
f'ROWS: {h1a:>7.2f} (qty {nh1:>3}, {h1a_hex_eta:.2f}% / {h1a_total_eta:.2f}%), \t'\
f'COLS: {h2a:>7.2f} (qty {nh2:>3}, {h2a_hex_eta:.2f}% / {h2a_total_eta:.2f}%)')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment