Skip to content

Instantly share code, notes, and snippets.

@stla
Created September 30, 2023 09:56
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/74e14eeac39d75d1bc1945c7cb1fd54e to your computer and use it in GitHub Desktop.
Save stla/74e14eeac39d75d1bc1945c7cb1fd54e to your computer and use it in GitHub Desktop.
Torus knots 4D
library(rgl)
library(cgalMeshes)
# trefoil (2,3) ####
p <- function(theta, phi) {
c(
cos(theta)*cos(phi), cos(theta)*sin(phi),
sin(theta)*cos(1.5*phi), sin(theta)*sin(1.5*phi)
)
}
s <- Vectorize(function(theta, phi) {
q <- p(theta, phi)
q[c(1L,2L,3L)] / (1 - q[4L])
})
phi_ <- seq(0, 4*pi, length.out = 400L)
pts <- t(s(0, phi_))
tube1 <- addNormals(
cylinder3d(pts, radius = 0.05, sides = 30),
)
pts <- t(s(pi/12, phi_))
tube2 <- addNormals(
cylinder3d(pts, radius = 0.05, sides = 30),
)
pts <- t(s(pi/6, phi_))
tube3 <- addNormals(
cylinder3d(pts, radius = 0.05, sides = 30),
)
pts <- t(s(pi/4, phi_))
tube4 <- addNormals(
cylinder3d(pts, radius = 0.05, sides = 30),
)
mesh1 <- addNormals(parametricMesh(
s, c(0, pi/12), c(0, 4*pi), periodic = c(FALSE, TRUE),
nu = 50L, nv = 600L
))
mesh2 <- addNormals(parametricMesh(
s, c(pi/12, pi/6), c(0, 4*pi), periodic = c(FALSE, TRUE),
nu = 50L, nv = 600L
))
mesh3 <- addNormals(parametricMesh(
s, c(pi/6, pi/4), c(0, 4*pi), periodic = c(FALSE, TRUE),
nu = 50L, nv = 600L
))
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9)
shade3d(mesh1, color = "navy")
shade3d(mesh2, color = "yellow")
shade3d(mesh3, color = "navy")
#shade3d(tube1, color = "firebrick4")
shade3d(tube2, color = "pink")
shade3d(tube3, color = "maroon")
shade3d(tube4, color = "firebrick4")
#
theta_ <- seq(0, pi/2, length.out = 10L)[1L:6L]
phi_ <- seq(0, 4*pi, length.out = 400L)
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.95)
for(i in seq_along(theta_)) {
theta <- theta_[i]
pts <- t(s(theta, phi_))
tube <- addNormals(
cylinder3d(pts, radius = 0.05, sides = 30),
)
shade3d(tube, color = "navy")
}
# (3, 11)-knot
p <- function(theta, phi) {
c(
cos(theta)*cos(phi), cos(theta)*sin(phi),
sin(theta)*cos(11/3*phi), sin(theta)*sin(11/3*phi)
)
}
s <- Vectorize(function(theta, phi) {
q <- p(theta, phi)
q[c(1L,2L,3L)] / (1 - q[4L])
})
theta_ <- seq(0, pi/2, length.out = 10L)[2L:5L]
phi_ <- seq(0, 6*pi, length.out = 600L)
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.85)
for(i in seq_along(theta_)) {
theta <- theta_[i]
pts <- t(s(theta, phi_))
tube <- addNormals(
cylinder3d(pts, radius = 0.03, sides = 30),
)
shade3d(tube, color = "navy")
}
# (4, 3)-knot
p <- function(theta, phi) {
c(
cos(theta)*cos(phi), cos(theta)*sin(phi),
sin(theta)*cos(3/4*phi), sin(theta)*sin(3/4*phi)
)
}
s <- Vectorize(function(theta, phi) {
q <- p(theta, phi)
q[c(1L,2L,3L)] / (1 - q[4L])
})
theta_ <- seq(0, pi/2, length.out = 10L)[2L:5L]
phi_ <- seq(0, 8*pi, length.out = 600L)
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.85)
for(i in seq_along(theta_)) {
theta <- theta_[i]
pts <- t(s(theta, phi_))
tube <- addNormals(
cylinder3d(pts, radius = 0.03, sides = 30),
)
shade3d(tube, color = "navy")
}
# # -- if you want an animation
M <- par3d("userMatrix")
movie3d(
par3dinterp(
time = seq(0, 1, len = 9),
userMatrix = list(
M,
rotate3d(M, pi, 1, 0, 0),
rotate3d(M, pi, 1, 1, 0),
rotate3d(M, pi, 1, 1, 1),
rotate3d(M, pi, 0, 1, 1),
rotate3d(M, pi, 0, 1, 0),
rotate3d(M, pi, 1, 0, 1),
rotate3d(M, pi, 0, 0, 1),
M
)
),
fps = 100,
duration = 1,
dir = ".",
movie = "zzpic",
convert = FALSE, webshot = FALSE
)
library(gifski)
gifski(
png_files = Sys.glob("zzpic*.png"),
gif_file = "TrefoilKnots4D.gif",
width = 512,
height = 512,
delay = 1/8
)
file.remove(Sys.glob("zzpic*.png"))
@stla
Copy link
Author

stla commented Sep 30, 2023

TrefoilKnots4D

@stla
Copy link
Author

stla commented Sep 30, 2023

TrefoilKnot4D

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