Skip to content

Commit

Permalink
square checkerboard for Enneper with four corners and ARAP
Browse files Browse the repository at this point in the history
  • Loading branch information
stla committed Oct 7, 2023
1 parent f45a4c6 commit 9d4fdbd
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 7 deletions.
10 changes: 6 additions & 4 deletions inst/essais/Enneper.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
library(cgalMeshes)
library(rgl)

n <- 3
n <- 2
Enneper <- function(phi, r) {
rbind(
r*cos(phi) - r^(2*n-1)*cos((2*n-1)*phi)/(2*n-1),
Expand All @@ -11,7 +11,9 @@ Enneper <- function(phi, r) {
}

rmesh <- parametricMesh(
Enneper, urange = c(0, 2*pi), vrange = c(0, 1.3),
periodic = c(TRUE, FALSE), nu = 200, nv = 100
Enneper, urange = c(0, 2*pi), vrange = c(0, 1.2),
periodic = c(TRUE, FALSE), nu = 200, nv = 100, clean = TRUE
)
rmesh <- Rvcg::vcgClean(rmesh, sel = 0)
#rmesh <- Rvcg::vcgClean(rmesh, sel = 0)

shade3d(rmesh)
156 changes: 156 additions & 0 deletions inst/essais/essai-param-ARAP-Enneper.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
setwd("C:/SL/MyPackages/cgalMeshes/inst/trash")

library(cgalMeshes)
library(rgl)

n <- 2
Enneper <- function(phi, r) {
rbind(
r*cos(phi) - r^(2*n-1)*cos((2*n-1)*phi)/(2*n-1),
r*sin(phi) + r^(2*n-1)*sin((2*n-1)*phi)/(2*n-1),
2*r^n*cos(n*phi)/n
)
}

rmesh <- parametricMesh(
Enneper, urange = c(0, 2*pi), vrange = c(0, 1.2),
periodic = c(TRUE, FALSE), nu = 512L, nv = 128L, clean = TRUE
)

shade3d(rmesh, col = "deeppink4")
bbox3d()

# convert to CGAL mesh ####
mesh <- cgalMesh$new(rmesh)

# take a look at the edge lengths
edges <- mesh$getEdges()
summary(edges[["length"]])

# add vertices in order that the checkeboard has regular lines ####
mesh$isotropicRemeshing(0.008, iterations = 3, relaxSteps = 2)

# compute mesh parameterization ####
UV <- mesh$parameterization(method = "ARAP", lambda = 1000)

png("EnneperARAP_UVspace.png", width = 384, height = 384)
opar <- par(mar = c(4, 4, 0, 0))
plot(UV, asp = 1, pch = 19, xlab = "u", ylab = "v", axes = FALSE)
axis(1, at = seq(-3.5, 1.5, by = 0.5))
axis(2, at = seq(-1.5, 2.5, by = 0.5))
par(opar)
dev.off()


vs <- mesh$getVertices()
vsz <- vs[, 3L]
odec <- order(vsz, decreasing = TRUE)
vz1 <- odec[1L]
vz2 <- odec[2L]

uv1 <- UV[vz1, ]
uv2 <- UV[vz2, ]
alpha <- atan2(uv2[1L]-uv1[1L], uv2[2L]-uv1[2L])

rotation <- function(alpha, uv) {
t(rbind(
c(cos(alpha), -sin(alpha)),
c(sin(alpha), cos(alpha))
) %*% t(uv))
}

UVrot <- rotation(alpha, UV)
Urot <- UVrot[, 1L]
Vrot <- UVrot[, 2L]

png("EnneperARAP_UVspaceWithTheTwoExtremeZPoints.png", width = 384, height = 384)
opar <- par(mar = c(4, 4, 0, 0))
plot(UV, asp = 1, pch = ".", xlab = "u", ylab = "v", axes = FALSE)
axis(1, at = seq(-3.5, 1.5, by = 0.5))
axis(2, at = seq(-1.5, 2.5, by = 0.5))
points(UV[c(v1,v2),], col = c("red", "green"), pch = 19, cex = 2)
par(opar)
dev.off()


# ARAP checkerboard ####
# U <- UV[, 1L]
# V <- UV[, 2L]
# Un <- (U - min(U)) / (max(U) - min(U))
# Vn <- (V - min(V)) / (max(V) - min(V))
# checkerboard <- ifelse(
# (floor(5 * U) %% 2) == (floor(5 * V) %% 2),
# "yellow", "navy"
# )

Un <- (Urot - min(Urot)) / (max(Urot) - min(Urot))
Vn <- (Vrot - min(Vrot)) / (max(Vrot) - min(Vrot))
checkerboard <- ifelse( # c'est ça le bon
(floor(5 * Un) %% 2) == (floor(5 * Vn) %% 2),
"yellow", "navy"
)

png("Enneper_UVcheckerboard_ARAP.png", width = 384, height = 384)
opar <- par(mar = c(4, 4, 0, 0))
plot(
U, V, asp = 1, pch = ".", xlab = "u", ylab = "v",
axes = FALSE, col = checkerboard
)
axis(1, at = seq(-3.5, 1.5, by = 0.5))
axis(2, at = seq(-1.5, 2.5, by = 0.5))
par(opar)
dev.off()

# add normals, convert to 'rgl' mesh, and add colors ####
mesh$computeNormals()
rmesh <- mesh$getMesh()
rmesh[["material"]] <- list("color" = checkerboard)
b <- getBoundary3d(rmesh, sorted = TRUE, color = "black")

# plot ####
library(rgl)
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8)
bg3d("#363940")
par3d(userMatrix = um)
shade3d(rmesh, meshColor = "vertices", polygon_offset = 1)
shade3d(b, lwd = 4)

snapshot3d(sprintf("EnneperWithCheckerboard_ARAP.png"), webshot = FALSE)
saveRDS(um, "userMatrix.rds")

# 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
)

# mount animation
library(gifski)
gifski(
png_files = Sys.glob("zzpic*.png"),
gif_file = "TennisBallWithCheckerboard_FourCorners.gif",
width = 512,
height = 512,
delay = 1/8
)
file.remove(Sys.glob("zzpic*.png"))


112 changes: 112 additions & 0 deletions inst/essais/essai-param-fourCorners-Enneper.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
setwd("C:/SL/MyPackages/cgalMeshes/inst/trash")

library(cgalMeshes)
library(rgl)

n <- 2
Enneper <- function(phi, r) {
rbind(
r*cos(phi) - r^(2*n-1)*cos((2*n-1)*phi)/(2*n-1),
r*sin(phi) + r^(2*n-1)*sin((2*n-1)*phi)/(2*n-1),
2*r^n*cos(n*phi)/n
)
}

rmesh <- parametricMesh(
Enneper, urange = c(0, 2*pi), vrange = c(0, 1.2),
periodic = c(TRUE, FALSE), nu = 512L, nv = 128L, clean = TRUE
)

shade3d(rmesh, col = "deeppink4")
bbox3d()

# convert to CGAL mesh ####
mesh <- cgalMesh$new(rmesh)

# take a look at the edge lengths
edges <- mesh$getEdges()
summary(edges[["length"]])

# add vertices in order that the checkeboard has regular lines ####
mesh$isotropicRemeshing(0.008, iterations = 3, relaxSteps = 2)

# compute mesh parameterization ####
# first, find the four corners
vs <- mesh$getVertices()
vsx <- vs[, 1L]
oinc <- order(vsx)
odec <- order(vsx, decreasing = TRUE)
v1 <- oinc[1L]
v2 <- oinc[2L]
v3 <- odec[2L]
v4 <- odec[1L]

open3d()
view3d(0, 0)
shade3d(rmesh)
points3d(rbind(vs[v1, ]), col = "red", size = 12)
points3d(rbind(vs[v2, ]), col = "green", size = 12)
points3d(rbind(vs[v3, ]), col = "blue", size = 12)
points3d(rbind(vs[v4, ]), col = "black", size = 12)

UV <- mesh$parameterization(method = "DCP", corners = c(v1, v2, v3, v4))

# square checkerboard ####
checkerboard <- ifelse(
(floor(5 * UV[, 1L]) %% 2) == (floor(5 * UV[, 2L]) %% 2),
"yellow", "navy"
)

# add normals, convert to 'rgl' mesh, and add colors ####
mesh$computeNormals()
rmesh <- mesh$getMesh()
rmesh[["material"]] <- list("color" = checkerboard)
b <- getBoundary3d(rmesh, sorted = TRUE, color = "black")

# plot ####
library(rgl)
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8)
bg3d("#363940")
par3d(userMatrix = um)
shade3d(rmesh, meshColor = "vertices", polygon_offset = 1)
shade3d(b, lwd = 4)

snapshot3d(sprintf("EnneperWithCheckerboard_FourCorners.png"), webshot = FALSE)
saveRDS(um, "userMatrix.rds")

# 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
)

# mount animation
library(gifski)
gifski(
png_files = Sys.glob("zzpic*.png"),
gif_file = "TennisBallWithCheckerboard_FourCorners.gif",
width = 512,
height = 512,
delay = 1/8
)
file.remove(Sys.glob("zzpic*.png"))


58 changes: 58 additions & 0 deletions inst/essais/essai_conformalTorus.R
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,61 @@ tube <- addNormals(
shade3d(tube, color = "black")

snapshot3d("Villarceau.png", webshot = FALSE)



################################################################################

f <- function(beta, theta0, phi = pi/4) {
d <- (1 - sin(beta) * sin(phi))
rbind(
cos(theta0 + beta) * cos(phi) / d,
sin(theta0 + beta) * cos(phi) / d,
cos(beta) * sin(phi) / d
)
}

mesh <- parametricMesh(
f, c(0, 2*pi), c(0, 2*pi), c(TRUE, TRUE),
nu = 256, nv = 256
)

f <- function(u, v) { # clifford
rbind(
cospi(u) / (sqrt(2) - sinpi(v)),
sinpi(u) / (sqrt(2) - sinpi(v)),
cospi(v) / (sqrt(2) - sinpi(v))
)
}

N <- 256

mesh <- parametricMesh(
f, c(0, 2), c(0, 2), c(TRUE, TRUE),
nu = 256, nv = 256
)

x_ <- seq(0, 1, length.out = N)
UV <- as.matrix(
expand.grid(U = x_, V = x_)
)

rotation <- function(alpha, uv) {
t(rbind(
c(cos(alpha), -sin(alpha)),
c(sin(alpha), cos(alpha))
) %*% t(uv))
}

UVrot <- rotation(pi/4, UV)

K <- 4*sqrt(2)
rotatedCheckerboardColors <- ifelse(
(floor(K*UVrot[, 1L]) %% 2) == (floor(K*UVrot[, 2L]) %% 2),
"yellow", "navy"
)

mesh$material <- list(color = rotatedCheckerboardColors)
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(-15, -25, zoom = 0.7)
shade3d(mesh, polygon_offset = 1)
9 changes: 6 additions & 3 deletions vignettes/parameterizations.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ checkerboard: the lengths are not preserved, the angles are not preserved.

A parameterization which preserves the angles is called a *conformal*
parameterization. Let's see an example. I know a conformal parameterization
of a torus:
of the torus:

```{r conformalTorus}
# the conformal torus mesh
Expand Down Expand Up @@ -171,6 +171,7 @@ rotatedCheckerboardColors <- ifelse(
```

```{r plotRotatedCheckerboard, eval=FALSE}
# plot the rotated checkerboard
opar <- par(mar = c(0, 0, 0, 0))
plot(
UV, col = rotatedCheckerboardColors, asp = 1, pch = ".",
Expand All @@ -181,6 +182,8 @@ par(opar)

![](rotatedCheckerboard.png)

Now we assign the colors to the vertices of the torus mesh, and we plot.

```{r}
# assign the rotated checkerboard colors to the torus mesh
TorusMesh[["material"]] <- list("color" = rotatedCheckerboardColors)
Expand All @@ -193,7 +196,7 @@ view3d(0, -40, zoom = 0.7)
shade3d(TorusMesh, meshColor = "vertices")
```

![](conformalTorus.png)
![](conformalTorus.gif)

The parameterization is conformal.
It is not very obvious to see, but the right angles are not distorted
Expand All @@ -202,7 +205,7 @@ In fact, the boundaries of the yellow and blue squares form the *Villarceau
circles* of the torus, shown in black on the following picture, and which are
known to meet at right angles.


![](Villarceau.png)



Expand Down

0 comments on commit 9d4fdbd

Please sign in to comment.