From 0aabfdaeaf4922ffe644a47ff633bd0a3342d8f8 Mon Sep 17 00:00:00 2001 From: stla Date: Sat, 7 Oct 2023 05:18:10 +0200 Subject: [PATCH] continued blog post Enneper-checkerboard2 --- .../Enneper-checkerboard2.Rmd | 95 +++++++++++++++++- .../figures/EnneperARAP_UVspace.png | Bin 2071 -> 3006 bytes inst/essais/essai-param-ARAP-Enneper.R | 2 +- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/inst/essais/Enneper-checkerboard2/Enneper-checkerboard2.Rmd b/inst/essais/Enneper-checkerboard2/Enneper-checkerboard2.Rmd index bdf470d..1203f87 100644 --- a/inst/essais/Enneper-checkerboard2/Enneper-checkerboard2.Rmd +++ b/inst/essais/Enneper-checkerboard2/Enneper-checkerboard2.Rmd @@ -143,7 +143,100 @@ shade3d(bndry, lwd = 4) ![](./figures/EnneperCheckerboard_FourCorners.gif) -Now you see what I mean by "align". It is quite better, no? +Now you see what I mean by "aligned". It is quite better, no? ### Second method: ARAP parameterization + +The UV-space of the ARAP (As Rigid As Possible) parameterization is not +a square nor a circle in general. It looks like a "flattening" of the mesh. +For example, I tried to apply it to the +[half of the tennis ball](https://laustep.github.io/stlahblog/posts/TennisBall.html) +and the shape of the UV-space looked like a eight. + +Let's try it. + +```{r ARAP, eval=FALSE} +# compute ARAP mesh parameterization #### +# a large value of lambda for a high rigidity +UV <- mesh$parameterization(method = "ARAP", lambda = 1000) +``` + +No luck, the UV-space is a circle: + +```{r UVspaceARAP, eval=FALSE} +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)) +``` + +![](./figures/EnneperARAP_UVspace.png) + +If we draw a checkerboard on this circle with horizontal and vertical lines, +then, the checkerboard mapped on the Enneper surface will not be "aligned". +So we need to draw a rotated checkerboard. + +We take the two vertices at the "top" of the Ennerper surface: the ones +having the highest value of the $z$ coordinate. + +```{r vz1_vz2} +vs <- mesh$getVertices() +vsz <- vs[, 3L] +odec <- order(vsz, decreasing = TRUE) +vz1 <- odec[1L]; vz2 <- odec[2L] +``` + +These two vertices are on the border of the mesh, therefore their +corresponding uv-points are on the border of the UV-space, and they are +diametrically opposite on the circle: + +![](./figures/EnneperARAP_UVspaceWithTheTwoExtremeZPoints.png) + +We rotate the circle in order to bring these two points to the north and +south poles: + +```{r rotation} +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] +``` + +Now we can do the rotated checkerboard: + +```{r rotatedCheckeboard} +Un <- (Urot - min(Urot)) / (max(Urot) - min(Urot)) +Vn <- (Vrot - min(Vrot)) / (max(Vrot) - min(Vrot)) +checkerboard <- ifelse( + (floor(5 * Un) %% 2) == (floor(5 * Vn) %% 2), + "yellow", "navy" +) +``` + +Here is the rotated checkerboard: + +![](./figures/Enneper_UVcheckerboard_ARAP.png) + +So now it remains to do the plot of the mesh with the mapped checkerboard: + +```{r EnneperCheckerboardARAP, eval=FALSE} +rmesh[["material"]] <- list("color" = checkerboard) +open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8) +bg3d("#363940") +shade3d(rmesh, meshColor = "vertices", polygon_offset = 1) +shade3d(b, lwd = 4) +``` + +![](./figures/EnneperCheckerboard_ARAP.gif) + +Perfectly "aligned" and symmetric. \ No newline at end of file diff --git a/inst/essais/Enneper-checkerboard2/figures/EnneperARAP_UVspace.png b/inst/essais/Enneper-checkerboard2/figures/EnneperARAP_UVspace.png index 52efb3213a9a370c58c63b809dcc7301afb3107a..dad1db2924e01de75151bd332de8edbb4191decb 100644 GIT binary patch literal 3006 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 literal 2071 zcmcIlX;f3!8a+uQ38M@Z34>uOI53X_rU?{*C_@AmSU?FP6blldz+;NJD6~=$0w|(P zK|y%DLJ33Er$Q(W#ehWSQKKz`2%^k`A@7DqeebRJyFc#w&i&55`|Nwx-s{VtxI4>A zsY(F=WXUd$o&X>q@qRwgA|IP+KN5bgLB#LYX5X zjz~1Zv>g$NM4V7~1s8ZZV`kA00H%oSXz!g+G<$U*Ccs(#vCnhP>7yGW;ycA%E|Eoi zx+$XS&AXxz(%Fx(%2$+xi2K1n1;teXPk;#;G6k6kstjoGguD=o)+bG0?(Xx_J~t?b zq92i#eUIUpJaV>pF?p^4yNa<;&}F1ymC#tuPUivxQdUZRt1H5D)=T!bWE4a%Z&gRg zH84^x;E?J+iw4nc7|j{{b?OIDu-T?4qXGIDl=G=5{&GvsxsYYjfyPze+_?^V^De*j zWKZMHln1-~RxLB`Oc2JT3^()=2W~$c#hzU^`esG%;fPetnt~0c^1-lF%_CF6Q;sz_(u*%5(x8bpRlr}9WVE+ zcrWO8xQs3Z8Cx=1%N>jHi|!j3*Q0!)X_rM;muqG!)Az=}q@JVwBc0CQdz1t$QO5GD z#MCu;&HA_`$$uI;Rz;|uOh36(%StVNpv=oLvuk>&V#-XRqA@bgG|4-ST!TB2CAT}; zk7vER{Dc#0u)F=sGaQA#b0VUT`NgF@GsFetJK@<$rE`X^g-mK|*F^s9c9+ICPs1W^D_&0r9PbQXS|O?o0<8#qCoxC zfSuYgeLeE(c!!Vo^>)wAb0Oy6^_G(vcJ*qOk=;MH3=L*W*(AOUw6-b_aKE{VSMv9a z(DxGFNhj><&wINWLiIf&EFUJ))LHz9crc7?$0EWod(o`dC_XxD3M>i_qFF&G{y;Xs zLCtim45>|mWsH~D59liP<(197`E+fKZKpq}yj*8m)Y6dLQ z+u+Snuo$OA1*$0SX*7#gh=g4W!LCh2O!4$ufdv|Bmm%a{20AUa6m*~4TCP+l@b^WjvFCYiGnaAWUND=xz>NtZlzAo3X-Va zPTl7q8qmgYfD24sAPgw*ZHeV=$r>-VMX7tF0BP@So#PK}Q0neZaD%#ya0s9P=`a4o zcl&$8Z(`+j0cXs)>^~&xND5*Jyr!nRKzT2G2AXsNDmXha|V5GY8my!o#?)~&WVkWDz6n5j^by=T`xtJ?%5djN zJ`O-SAPD3;*P0=Z3y`R~L*7>vxyU(~IoQhvW=88m66fY03Y`{?ny%2j*i7Ucl68M$ zNmTJKR@Q%=kFTw9%gYUW>M`MSyVIrab!GCq?!CJGv{pfN<2ts*u_ex#Ah z{Y(;j{1)%UYi;-N&goN&RoFZ~>-%4v(7So1|Gkl8=|#=5r8XY_t(Mcbym{5w@QYDH z2OlDZ%1BpEwuc9FVN*Y;UtizBo~uS!@KQRZ`6j1Cm?)_zzu@{5({ZF%Xg{}@^6Qnf z6Zjytg zBX;$Y20y+uH~RZu3pMyZ;PYalpWGtwbLaA6Y0n!p_$719_{jb?4Sp?+nGo@^M}yyN z>_V_y_$U`PNoyxqEG_K`nJ1Kdo0vMLnmHigrZAvvWUPOJpu*xj+#fqMR5gUn{X diff --git a/inst/essais/essai-param-ARAP-Enneper.R b/inst/essais/essai-param-ARAP-Enneper.R index 909c72a..e40f28f 100644 --- a/inst/essais/essai-param-ARAP-Enneper.R +++ b/inst/essais/essai-param-ARAP-Enneper.R @@ -35,7 +35,7 @@ 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) +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)) par(opar)