Skip to content

Instantly share code, notes, and snippets.

@bryanhanson
Last active May 12, 2024 18:55
Show Gist options
  • Save bryanhanson/fb4206132c41c96bf192f6a686d42daa to your computer and use it in GitHub Desktop.
Save bryanhanson/fb4206132c41c96bf192f6a686d42daa to your computer and use it in GitHub Desktop.
Tetrahedral Decomposition
#
# Following https://micronote.tech/2020/12/Generating-STL-Models-with-Python/
#
# Remember Python indexes starting at 0!
# Coordinates derived from R script tetrahedral_decomp.R
# The .stl file created contains one unit of the 4 from a tetrahedral decomposition (they
# are all identical of course). Dimensions default to mm, so the object is about 1.3 mm
# in its longest dimension. For 3D printing we scaled by 2500% to get an object about
# an inch tall, which is a good size.
import numpy as np
from stl import mesh
vertices = np.array([
[0.0, 0.0, 0.0],
[1.0, 1.0, 1.0],
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
[0.333, 0.333, -0.333],
[0.333, -0.333, 0.333],
[-0.333, 0.333, 0.333],
])
faces = np.array([
[4, 1, 7],
[7, 1, 3],
[4, 6, 1],
[6, 2, 1],
[6, 0, 5],
[6, 5, 2],
[0, 7, 3],
[0, 3, 5],
[4, 7, 0],
[4, 0, 6],
[1, 2, 5],
[1, 5, 3],
])
shape = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))
for i, f in enumerate(faces):
for j in range(3):
shape.vectors[i][j] = vertices[f[j], :]
shape.save("tetra_decomp.stl")
# Decomposition of a Tetrahedron
# Bryan Hanson, May 2024
# Inspired by https://twitter.com/dreugeniacheng/status/1787725859605942480
library("rgl")
# corners of tetrahedron inscribed inside of a cube centered on 0, 0, 0 in Cartesian coordinates
verts <- data.frame(
x = c(1, 1, -1, -1),
y = c(1, -1, 1, -1),
z = c(1, -1, -1, 1))
rownames(verts) <- c("A", "B", "C", "D") # label the vertices
# need center of each face (ABC, ABD, ACD, BCD)
abc <- colMeans(verts[c("A", "B", "C"),])
abd <- colMeans(verts[c("A", "B", "D"),])
acd <- colMeans(verts[c("A", "C", "D"),])
bcd <- colMeans(verts[c("B", "C", "D"),])
# need mid-point of each edge (6 edges total, no unique order exists)
edges <- data.frame(
x = c(1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1),
y = c(1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1),
z = c(1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1))
rownames(edges) <- c("A1", "B1", "B2", "C1", "C2", "D1",
"D2", "A2", "C3", "A3", "B3", "D3")
# need mid-point of AB, BC, CD, DA, CA, BD (pairs of rows in edges data frame)
ab <- colMeans(edges[1:2, ])
bc <- colMeans(edges[3:4, ])
cd <- colMeans(edges[5:6, ])
da <- colMeans(edges[7:8, ])
ca <- colMeans(edges[9:10, ])
bd <- colMeans(edges[11:12, ])
# plot it; no attempt at polishing the color scheme(s)
points3d(verts, size = 15, point_antialias = TRUE) # vertices
points3d(abc, size = 15, point_antialias = TRUE, col = "red") # face centers
points3d(abd, size = 15, point_antialias = TRUE, col = "red")
points3d(acd, size = 15, point_antialias = TRUE, col = "red")
points3d(bcd, size = 15, point_antialias = TRUE, col = "red")
segments3d(edges$x, edges$y, edges$z, line_antialias = TRUE, col = "blue", lwd = 4) # edges
points3d(ab, size = 15, point_antialias = TRUE, col = "green") # edge mid-points
points3d(bc, size = 15, point_antialias = TRUE, col = "green")
points3d(cd, size = 15, point_antialias = TRUE, col = "green")
points3d(da, size = 15, point_antialias = TRUE, col = "green")
points3d(ca, size = 15, point_antialias = TRUE, col = "green")
points3d(bd, size = 15, point_antialias = TRUE, col = "green")
points3d(c(0, 0, 0), size = 15, point_antialias = TRUE) # the center
# add the vertices of one piece
points3d(c(0, 0, 0), size = 20, point_antialias = TRUE, col = "orange") # the center
points3d(verts[1,], size = 20, point_antialias = TRUE, col = "orange") # vertex A
points3d(ab, size = 20, point_antialias = TRUE, col = "orange") # mid-point ab
points3d(ca, size = 20, point_antialias = TRUE, col = "orange") # mid-point ca
points3d(da, size = 20, point_antialias = TRUE, col = "orange") # mid-point da
points3d(abc, size = 20, point_antialias = TRUE, col = "orange") # face center abc
points3d(abd, size = 20, point_antialias = TRUE, col = "orange") # face center abd
points3d(acd, size = 20, point_antialias = TRUE, col = "orange") # face center acd
# coordinates of a single piece
piece <- rbind(c(0, 0, 0), verts[1, ], ab, ca, da, abc, abd, acd)
rownames(piece) <- 1:8
# new plot (close any open rgl windows)
# show the piece vertices marked inside the tetrahedron
points3d(verts, size = 15, point_antialias = TRUE) # vertices
points3d(abc, size = 15, point_antialias = TRUE) # face centers
points3d(abd, size = 15, point_antialias = TRUE)
points3d(acd, size = 15, point_antialias = TRUE)
points3d(bcd, size = 15, point_antialias = TRUE)
segments3d(edges$x, edges$y, edges$z, line_antialias = TRUE, col = "blue", lwd = 4) # edges
points3d(ab, size = 15, point_antialias = TRUE, col = "red") # edge mid-points
points3d(bc, size = 15, point_antialias = TRUE, col = "red")
points3d(cd, size = 15, point_antialias = TRUE, col = "red")
points3d(da, size = 15, point_antialias = TRUE, col = "red")
points3d(ca, size = 15, point_antialias = TRUE, col = "red")
points3d(bd, size = 15, point_antialias = TRUE, col = "red")
points3d(piece, size = 20, point_antialias = TRUE, col = "green")
text3d(piece, texts = as.character(1:8), cex = 5) # label for working out the stl details
@bryanhanson
Copy link
Author

bryanhanson commented May 12, 2024

Use tetrahedral_decomposition.R to generate coordinates, and then use tetra_decomp.py to generate the .stl file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment