A zonohedron, roughly speaking, is the projection of a high-dimensional cube to \(\mathbb{R}^3\). For a precise definition see the Zonotopes vignette, section 1.3. A zonohedron is a special type of convex polyhedron.
The goal of this package is to construct any zonohedron, but especially the ones in these 2 families:In the first case, 13 classical zonohedra have been taken from [9] and are built in to the package. In the second case, an object color solid is viewed as a zonohedron; this connection was discovered by Paul Centore and is explained very clearly in [1].
library(zonohedra)
library(rgl)
The package dependencies are:
Some of the figures below are displayed with WebGL - a JavaScript API for rendering interactive 2D and 3D graphics. Try using the left mouse button to rotate and the scroll wheel to zoom.
The generators for a polar zonohedra are particularly simple - they are equally distributed on a circle that is in a plane parallel to the xy-plane and whose center is on the z-axis. Construct polar zonohedra with 5 and 25 generators and plot them.
::mfrow3d( 1, 2 )
rgl= polarzonohedron( 5 ) ; plot( pz5, ewd=5 )
pz5 ::next3d()
rglplot( polarzonohedron( 25 ), ewd=3 )
::rglwidget( webgl=TRUE ) rgl
polar zonohedra with 5 generators (left) and 25 generators (right)    [both of these are interactive WebGL widgets]
In these 2 plots, the black dot is the origin, the 5 vertices nearest to the origin are the 5 generators, and the white dot is the point (0,0,\(\pi\)). Each of the generators is assigned a unique color, and every other edge with that color is parallel to the generator. All parallelograms with an edge of that color form the zone or belt for that generator. Each belt is a topological annulus. For more details on these polar zonohedra, see [2].
Print the generators of the first zonohedron pz5
; they are the columns of this 3x5 matrix.
getmatrix( pz5 )
## 1 2 3 4 5
## [1,] 0.6283185 0.1941611 -0.5083204 -0.5083204 0.1941611
## [2,] 0.0000000 0.5975664 0.3693164 -0.3693164 -0.5975664
## [3,] 0.6283185 0.6283185 0.6283185 0.6283185 0.6283185
A function similar to polarzonohedron()
is regularprism()
.
There are 13 classic zonohedron available in the package, as a list of 3xN matrices, where N is the number of generators. The global data variable is classics.genlist
, with S3 class 'genlist'
. The 13 matrices in the list are taken from [5].
classics.genlist
## fullname generators vertices edges facets area volume pointed
## C cube 3 8 12 6 6.00000 1.00000 TRUE
## RD rhombic dodecahedron 4 14 24 12 33.94113 16.00000 TRUE
## BD Bilinski dodecahedron 4 14 24 12 38.83282 16.94427 TRUE
## RI rhombic icosahedron 5 22 40 20 64.72136 42.36068 TRUE
## RHD rhombo-hexagonal dodecahedron 5 18 28 12 72.55309 48.00000 TRUE
## RT rhombic triacontahedron 6 32 60 30 97.08204 84.72136 TRUE
## TO truncated octahedron 6 24 36 14 53.56922 32.00000 TRUE
## TRD truncated rhombic dodecahedron 7 32 48 18 110.72888 98.76537 TRUE
## TC truncated cuboctahedron 9 48 72 26 123.51034 118.22540 TRUE
## RE rhombic enneacontahedron 10 92 180 90 229.70563 318.88544 FALSE
## RH rhombic hectotriadiohedron 12 134 264 132 869.36961 2367.25310 FALSE
## TI truncated icosidodecahedron 15 120 180 62 697.16812 1654.42719 TRUE
## TSR truncated small rhombicosidodecahedron 21 240 360 122 1336.66780 4497.87138 FALSE
Extract the matrix of generators for the truncated cuboctahedron
, which is abbreviated by TC
.
= classics.genlist[['TC']] ; mat mat
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 1 1.414214 1 0 1 0.000000 0 0.000000 1
## [2,] -1 0.000000 0 1 1 1.414214 1 0.000000 0
## [3,] 0 0.000000 -1 -1 0 0.000000 1 1.414214 1
## attr(,"shortname")
## [1] "TC"
## attr(,"fullname")
## [1] "truncated cuboctahedron"
Create the truncated cuboctahedron and plot it, with filled faces.
::par3d( userMatrix = rotationMatrix( -20*pi/180, 0, 1, 1) )
rgl= zonohedron( mat )
zono plot( zono, type='f' )
::rglwidget( webgl=TRUE ) rgl
truncated cuboctahedron      [This is an interactive WebGL widget]
Before continuing, define function spinit()
used for creating animated GIFs.
library(gifski)
# zono the zonohedron
# id unique ID for this animation, a positive integer
# fps frames per second
# duration of the animation, in seconds
# revolutions number of revolutions
# vpsize viewport size = (width,height)
<- function( zono, index, fps=5, duration=8, revolutions=1, vpsize=c(480,480) ) {
spinit # enlarge viewport
= par3d( "windowRect" )
wr par3d( windowRect = c( wr[1:2], wr[1:2] + vpsize ) )
= "./figs" ; if( ! file.exists(pathtemp) ) dir.create(pathtemp) # make temp folder
pathtemp # make a lot of .PNG files in pathtemp
movie3d( spin3d( getcenter(zono), rpm=revolutions*60/duration ), duration=duration, fps=fps, startTime=1/fps,
convert=F, movie='junk', dir=pathtemp, verbose=F, webshot=F )
# combine all the .PNGs into a single .GIF
= dir( pathtemp, pattern="png$", full=T )
pathvec = sprintf( "./figs/animation%g.gif", index )
gif_file # if( file.exists(gif_file) ) file.remove( gif_file )
= gifski::gifski( pathvec, gif_file=gif_file, delay=1/fps, progress=F, width=vpsize[1], height=vpsize[2] )
out = file.remove( pathvec ) # cleanup the .PNG files, leaving just the .GIF
res
return( out )
}
In colorimetry, an object color solid is a zonohedron.
# colorimetry.genlist[[1]] is a 3x81 matrix with the CIE 1931 CMFs at 5nm interval
= zonohedron( colorimetry.genlist[[1]] )
zono5 plot( zono5, type='f' )
= spinit( zono5, 2, vpsize=c(256,256) ) gif_file
In this figure, the black dot is the black point [0,0,0]. The white dot is the white point, i.e. the column sums of the generating matrix.
Here are a few possible improvements and additions.
export
There should be a way to export a zonohedron as a quadrilateral mesh in some standard format(s).
vignettes
There should be more vignettes. One idea is to show ways to examine individual hyperplanes and facets of a zonohedron. Another idea is to display some interesting Minkowski sums of a few classic zonohedra.
The constructor zonohedron()
uses the optimizations in Paul Heckbert’s memo [6]. The key step is sorting points that lie on a great circle on the sphere. This efficient method is \(O(N^2\log(N))\); whereas the naive method is \(O(N 2^N)\).
The central symmetry is used whenever possible, and when used this can speed things up by a factor of 2. To further speed things up, many of the methods use C/C++.
The function grpDuplicated()
was written by Long Qu, with a small modification of the return value by myself. It is written in C/C++ and is implemented with std::unordered_map
. The code was taken from the discontinued package uniqueAtomMat, see [8].
Logging is performed using the package logger, see [3]. This is a powerful package that allows a separate configuration for logging from within zonohedra, and that is what I have done. During package loading, the logging threshold is changed from INFO
to WARN
. To change it back again, one can execute:
log_threshold( INFO, namespace="zonohedra" )
The layout callback functions is customized; it adds the name of the calling function to the message. To install your own layout function, you can execute:
log_layout( <your function>, namespace="zonohedra" )
The appender callback functions is also customized; it comes to an immediate stop if the message level is ERROR
or FATAL
. To return to the default behavior, you can execute:
log_appender( appender_console, namespace="zonohedra" )
The formatter callback function is forced to be formatter_sprintf()
; this should not be changed.
R version 4.4.1 (2024-06-14 ucrt) Platform: x86_64-w64-mingw32/x64 Running under: Windows 10 x64 (build 19045) Matrix products: default locale: [1] LC_COLLATE=C [2] LC_CTYPE=English_United States.utf8 [3] LC_MONETARY=English_United States.utf8 [4] LC_NUMERIC=C [5] LC_TIME=English_United States.utf8 time zone: America/New_York tzcode source: internal attached base packages: [1] stats graphics grDevices utils datasets methods base other attached packages: [1] gifski_1.12.0-2 orientlib_0.10.5 rgl_1.3.1 zonohedra_0.3-0 loaded via a namespace (and not attached): [1] digest_0.6.35 R6_2.5.1 base64enc_0.1-3 [4] microbenchmark_1.4.10 fastmap_1.2.0 xfun_0.44 [7] magrittr_2.0.3 glue_1.7.0 cachem_1.1.0 [10] knitr_1.47 htmltools_0.5.8.1 logger_0.3.0 [13] rmarkdown_2.27 lifecycle_1.0.4 cli_3.6.2 [16] sass_0.4.9 jquerylib_0.1.4 compiler_4.4.1 [19] highr_0.11 tools_4.4.1 evaluate_0.23 [22] bslib_0.7.0 yaml_2.3.8 htmlwidgets_1.6.4 [25] rlang_1.1.3 jsonlite_1.8.8