Created
October 5, 2021 22:14
-
-
Save PennRobotics/f419cf621a92b9e680d0cd9d4205f074 to your computer and use it in GitHub Desktop.
Spice drawer simple packing optimization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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