Created
December 7, 2024 05:23
-
-
Save omry/5dda74e1232d397f368c5874dc620956 to your computer and use it in GitHub Desktop.
STL cooling rack generator
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
width: 600 # Width of the cooling rack in mm | |
depth: 800 # Depth of the cooling rack in mm | |
height: 2200 # Total height of the rack in mm | |
grid_spacing: 50 # Spacing between grid bars in mm | |
rack_bar_thickness: 2 # Thickness of the rack bars in mm | |
frame_thickness: 25 # Thickness of the frame and legs in mm | |
leg_height: 100 # Height of the legs in mm | |
num_levels: 8 # Number of stacked levels | |
file_path: "Cooling_Rack_With_Vertical_Frame.stl" # Output STL file path |
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
import numpy as np | |
from stl import mesh | |
from mpl_toolkits.mplot3d import Axes3D, art3d | |
import matplotlib.pyplot as plt | |
import hydra | |
from omegaconf import DictConfig | |
def create_bar(start, end, thickness): | |
print(f"Creating bar from {start} to {end} with thickness {thickness}") | |
delta = np.array(end) - np.array(start) | |
if delta[0] != 0: # Bar extends along the x-axis | |
vertices = np.array([ | |
[start[0], start[1] - thickness / 2, start[2] - thickness / 2], | |
[end[0], start[1] - thickness / 2, start[2] - thickness / 2], | |
[end[0], start[1] + thickness / 2, start[2] - thickness / 2], | |
[start[0], start[1] + thickness / 2, start[2] - thickness / 2], | |
[start[0], start[1] - thickness / 2, start[2] + thickness / 2], | |
[end[0], start[1] - thickness / 2, start[2] + thickness / 2], | |
[end[0], start[1] + thickness / 2, start[2] + thickness / 2], | |
[start[0], start[1] + thickness / 2, start[2] + thickness / 2], | |
]) | |
elif delta[1] != 0: # Bar extends along the y-axis | |
vertices = np.array([ | |
[start[0] - thickness / 2, start[1], start[2] - thickness / 2], | |
[end[0] - thickness / 2, end[1], start[2] - thickness / 2], | |
[end[0] + thickness / 2, end[1], start[2] - thickness / 2], | |
[start[0] + thickness / 2, start[1], start[2] - thickness / 2], | |
[start[0] - thickness / 2, start[1], start[2] + thickness / 2], | |
[end[0] - thickness / 2, end[1], start[2] + thickness / 2], | |
[end[0] + thickness / 2, end[1], start[2] + thickness / 2], | |
[start[0] + thickness / 2, start[1], start[2] + thickness / 2], | |
]) | |
elif delta[2] != 0: # Bar extends along the z-axis | |
vertices = np.array([ | |
[start[0] - thickness / 2, start[1] - thickness / 2, start[2]], | |
[start[0] + thickness / 2, start[1] - thickness / 2, start[2]], | |
[start[0] + thickness / 2, start[1] + thickness / 2, start[2]], | |
[start[0] - thickness / 2, start[1] + thickness / 2, start[2]], | |
[start[0] - thickness / 2, start[1] - thickness / 2, end[2]], | |
[start[0] + thickness / 2, start[1] - thickness / 2, end[2]], | |
[start[0] + thickness / 2, start[1] + thickness / 2, end[2]], | |
[start[0] - thickness / 2, start[1] + thickness / 2, end[2]], | |
]) | |
else: | |
raise ValueError("Start and end coordinates must define a bar along x, y, or z axis.") | |
# Define faces using two triangles per rectangular face | |
faces = np.array([ | |
[0, 1, 2], [0, 2, 3], # Bottom face | |
[4, 5, 6], [4, 6, 7], # Top face | |
[0, 1, 5], [0, 5, 4], # Front face | |
[1, 2, 6], [1, 6, 5], # Right face | |
[2, 3, 7], [2, 7, 6], # Back face | |
[3, 0, 4], [3, 4, 7], # Left face | |
]) | |
bar_mesh = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype)) | |
for i, f in enumerate(faces): | |
for j in range(3): | |
bar_mesh.vectors[i][j] = vertices[f[j]] | |
return bar_mesh | |
# Define faces using the vertices | |
faces = np.array([ | |
[0, 1, 2], [0, 2, 3], # Bottom face | |
[4, 5, 6], [4, 6, 7], # Top face | |
[0, 1, 5], [0, 5, 4], # Front face | |
[1, 2, 6], [1, 6, 5], # Right face | |
[2, 3, 7], [2, 7, 6], # Back face | |
[3, 0, 4], [3, 4, 7], # Left face | |
]) | |
# Fix diagonal face alignment for better rendering | |
faces = np.concatenate([ | |
[[0, 1, 4], [1, 5, 4]], # Adjust diagonals for Front | |
[[1, 2, 5], [2, 6, 5]], # Adjust diagonals for Right | |
[[2, 3, 6], [3, 7, 6]], # Adjust diagonals for Back | |
[[3, 0, 7], [0, 4, 7]], # Adjust diagonals for Left | |
]) | |
# Create mesh | |
bar_mesh = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype)) | |
for i, f in enumerate(faces): | |
for j in range(3): | |
bar_mesh.vectors[i][j] = vertices[f[j]] | |
return bar_mesh | |
@hydra.main(config_path=".", config_name="config", version_base=None) | |
def main(cfg: DictConfig): | |
print("Configuration Loaded:", cfg) | |
width = cfg.width | |
depth = cfg.depth | |
height = cfg.height | |
grid_spacing = cfg.grid_spacing | |
rack_bar_thickness = cfg.rack_bar_thickness | |
frame_thickness = cfg.frame_thickness | |
leg_height = cfg.leg_height | |
num_levels = cfg.num_levels | |
print(f"Dimensions: width={width}, depth={depth}, height={height}") | |
print(f"Grid spacing: {grid_spacing}, Rack bar thickness: {rack_bar_thickness}, Frame thickness: {frame_thickness}") | |
print(f"Leg height: {leg_height}, Number of levels: {num_levels}") | |
bars = [] | |
# Add horizontal grid levels | |
level_height = (height - leg_height) / (num_levels - 1) | |
print(f"Calculated level height: {level_height}") | |
for level in range(num_levels): | |
z = leg_height + level * level_height | |
print(f"Adding horizontal grid at z={z}") | |
for y in range(0, depth + grid_spacing, grid_spacing): | |
start = [0, y, z] | |
end = [width, y, z] | |
bars.append(create_bar(start, end, rack_bar_thickness)) | |
for x in range(0, width + grid_spacing, grid_spacing): | |
start = [x, 0, z] | |
end = [x, depth, z] | |
bars.append(create_bar(start, end, rack_bar_thickness)) | |
# Add vertical corner frames (four corners) | |
corner_positions = [(0, 0), (0, depth), (width, 0), (width, depth)] | |
for i, pos in enumerate(corner_positions): | |
start = [pos[0], pos[1], 0] | |
end = [pos[0], pos[1], height] | |
print(f"Adding vertical corner frame {i} from {start} to {end}") | |
bars.append(create_bar(start, end, frame_thickness)) | |
# Combine all bars into one mesh | |
print(f"Total number of bars: {len(bars)}") | |
combined_mesh = mesh.Mesh(np.concatenate([bar.data for bar in bars])) | |
print(f"Combined mesh has {len(combined_mesh.vectors)} triangles.") | |
file_path = cfg.file_path | |
combined_mesh.save(file_path) | |
print(f"Cooling rack STL file saved at: {file_path}") | |
# Visualize the model | |
fig = plt.figure(figsize=(10, 8)) | |
ax = fig.add_subplot(111, projection="3d") | |
ax.add_collection3d( | |
art3d.Poly3DCollection(combined_mesh.vectors, alpha=1.0, edgecolor="k") | |
) | |
ax.auto_scale_xyz([0, width], [0, depth], [0, height]) | |
plt.savefig("visualization_debug_highres.png", dpi=300) | |
print("Visualization saved as visualization_debug_highres.png") | |
plt.show() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment