Skip to content

Instantly share code, notes, and snippets.

@stla
Last active September 30, 2023 12:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stla/e41b6e02d6375b348b559923bd0dbd79 to your computer and use it in GitHub Desktop.
Save stla/e41b6e02d6375b348b559923bd0dbd79 to your computer and use it in GitHub Desktop.
Boerdijk-Coxeter helix (tetrahelix)
library(rgl)
# tetrahedra vertices
r <- 3*sqrt(3)/10
theta <- acos(-2/3)
h <- 1/sqrt(10)
n <- 20
i <- 1:n
p <- cbind(r*cos(i*theta), r*sin(i*theta), i*h)
# the octahedron within a tetrahedron, given the tetrahedron vertices
# this function returns a mesh
octaFromTetra <- function(vs) {
p1 <- (vs[, 1] + vs[, 2]) / 2
p2 <- (vs[, 1] + vs[, 3]) / 2
p3 <- (vs[, 1] + vs[, 4]) / 2
p4 <- (vs[, 2] + vs[, 3]) / 2
p5 <- (vs[, 2] + vs[, 4]) / 2
p6 <- (vs[, 3] + vs[, 4]) / 2
P <- rbind(p1, p2, p3, p4, p5, p6)
faces <- cbind(
c(1L, 2L, 3L),
c(1L, 2L, 4L),
c(1L, 3L, 5L),
c(1L, 4L, 5L),
c(6L, 2L, 3L),
c(6L, 2L, 4L),
c(6L, 3L, 5L),
c(6L, 4L, 5L)
)
tmesh3d(
vertices = t(P),
indices = faces
)
}
# take the tetrahedron faces
th0 <- tetrahedron3d()$it
# tetrahedra vertices - there are n-3 tetrahedra in the helix
VS <- lapply(1:(n-3), function(k) {
cbind(p[k, ], p[1L+k, ], p[2L+k, ], p[3L+k, ])
})
# tetrahedra meshes
tetrahedra <- lapply(1:(n-3), function(k) {
tmesh3d(
vertices = VS[[k]],
indices = th0
)
})
# octahedra meshes
octahedra <- lapply(1:(n-3), function(k) {
octaFromTetra(VS[[k]])
})
# non-duplicated octahedra vertices
ovs <- unique(do.call(
rbind,
lapply(1:(n-3), function(k) {
vs <- VS[[k]]
p1 <- (vs[, 1] + vs[, 2]) / 2
p2 <- (vs[, 1] + vs[, 3]) / 2
p3 <- (vs[, 1] + vs[, 4]) / 2
p4 <- (vs[, 2] + vs[, 3]) / 2
p5 <- (vs[, 2] + vs[, 4]) / 2
p6 <- (vs[, 3] + vs[, 4]) / 2
rbind(p1, p2, p3, p4, p5, p6)
})
))
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(0, 90)
invisible(lapply(1:(n-3), function(k) {
wire3d(tetrahedra[[k]], color = "navy", lwd = 4)
shade3d(octahedra[[k]], color = "darkgreen", polygon_offset = 1)
wire3d(octahedra[[k]], color = "black", lwd = 4)
invisible()
}))
spheres3d(p, radius = 0.1, color = "navy")
spheres3d(ovs, radius = 0.06, color = "darkgreen")
# animation ####
movie3d(
spin3d(axis = c(0, 0, 1), rpm = 60),
duration = 1, fps = 60,
movie = "zzpic", dir = ".",
convert = FALSE, webshot = FALSE,
startTime = 1/60
)
library(gifski)
gifski(
Sys.glob("zzpic*.png"),
"Octahelix.gif",
width = 512, height = 512,
delay = 1/10
)
file.remove(Sys.glob("zzpic*.png"))
library(rgl)
# tetrahedra vertices
r <- 3*sqrt(3)/10
theta <- acos(-2/3)
h <- 1/sqrt(10)
n <- 20
i <- 1:n
p <- cbind(r*cos(i*theta), r*sin(i*theta), i*h)
# we will also plot the circular helix
ii <- seq(1, n, length.out = 600L)
helix <- cbind(r*cos(ii*theta), r*sin(ii*theta), ii*h)
tube <- addNormals(cylinder3d(
helix, radius = 0.05, sides = 30, closed = TRUE
))
# take the tetrahedron faces
th0 <- tetrahedron3d()$it
# there are n-3 tetrahedra in the helix
tetrahedra <- lapply(1:(n-3), function(k) {
vs <- cbind(p[k, ], p[1+k, ], p[2+k, ], p[3+k, ])
tmesh3d(
vertices = vs,
indices = th0
)
})
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512))
colors <- viridisLite::viridis(n-3)
invisible(lapply(1:(n-3), function(k) {
shade3d(tetrahedra[[k]], color = colors[k], polygon_offset = 1)
wire3d(tetrahedra[[k]])
invisible()
}))
shade3d(tube, color = "maroon")
spheres3d(p, radius = 0.1, color = "black")
# animation ####
movie3d(
spin3d(axis = c(0, 0, 1), rpm = 60),
duration = 1, fps = 60,
movie = "zzpic", dir = ".",
convert = FALSE, webshot = FALSE,
startTime = 1/60
)
library(gifski)
gifski(
Sys.glob("zzpic*.png"),
"BoerdijkCoxeterTetrahelix.gif",
width = 512, height = 512,
delay = 1/10
)
file.remove(Sys.glob("zzpic*.png"))
@stla
Copy link
Author

stla commented Sep 30, 2023

BoerdijkCoxeterTetrahelix

@stla
Copy link
Author

stla commented Sep 30, 2023

Octahelix

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