37

My questions are:

  • Is there a possibility to get a view of a Rubik's Cube in TikZ such as in pgfplots; like view={NUMBER1}{NUMBER2}?
  • How can be the Rubik's Cube be scrambled with a number a, such that this number makes a random pattern to the cube (→ scrambeling).

Here is my MWE (it's just the Cube without any functions):

\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{3d}
\begin{document}
    \begin{tikzpicture}[every node/.style={inner sep=1cm,draw,very thick},very thick]
        \draw[step=2cm,canvas is yz plane at x=0] (0,0) grid (8,8);
            \node[fill=red] at (-4.08,-2.09) {};
            \node[fill=white] at (-4.08,-.09) {};
            \node[fill=blue] at (-4.08,1.91) {};
            \node[fill=red] at (-4.08,3.91) {};
        \begin{scope}[shift={(-2,0)}]
            \node[fill=blue] at (-4.08,-2.09) {};
            \node[fill=white] at (-4.08,-.09) {};
            \node[fill=orange] at (-4.08,1.91) {};
            \node[fill=white] at (-4.08,3.91) {};
        \end{scope}
        \begin{scope}[shift={(-4,0)}]
            \node[fill=yellow] at (-4.08,-2.09) {};
            \node[fill=blue] at (-4.08,-.09) {};
            \node[fill=white] at (-4.08,1.91) {};
            \node[fill=green] at (-4.08,3.91) {};
            \begin{scope}[shift={(-2,0)}]
                \node[fill=white] at (-4.08,-2.09) {};
                \node[fill=red] at (-4.08,-.09) {};
                \node[fill=blue] at (-4.08,1.91) {};
                \node[fill=yellow] at (-4.08,3.91) {};
            \end{scope}
        \end{scope}
        \draw[xshift=-8cm,yshift=8cm,step=2cm,canvas is xz plane at y=0] (0,0) grid (8,8);
            \draw[fill=yellow,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=2cm,fill=blue,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=6cm,fill=orange,canvas is yz plane at x=0] (0,0) rectangle (2,2);
        \begin{scope}[shift={(-.77,-.77)}]
            \draw[fill=green,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=2cm,fill=orange,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=4cm,fill=orange,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=6cm,fill=blue,canvas is yz plane at x=0] (0,0) rectangle (2,2);
        \end{scope}
        \begin{scope}[shift={(2*-.77,2*-.77)}]
            \draw[fill=red,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=2cm,fill=yellow,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=4cm,fill=red,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=6cm,fill=red,canvas is yz plane at x=0] (0,0) rectangle (2,2);
        \end{scope}
        \begin{scope}[shift={(3*-.77,3*-.77)}]
            \draw[fill=blue,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=2cm,fill=orange,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=4cm,fill=yellow,canvas is yz plane at x=0] (0,0) rectangle (2,2);
            \draw[yshift=6cm,fill=blue,canvas is yz plane at x=0] (0,0) rectangle (2,2);
        \end{scope}
            \draw[yshift=8cm,xshift=-2cm,fill=blue,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=7.23cm,xshift=-2.76cm,fill=orange,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=6.46cm,xshift=-3.55cm,fill=green,canvas is xz plane at y=0] (0,0) rectangle (2,2);
        \begin{scope}[shift={(-2,0)}]
            \draw[yshift=8cm,xshift=-2cm,fill=green,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=7.23cm,xshift=-2.76cm,fill=white,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=6.46cm,xshift=-3.55cm,fill=red,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=5.68cm,xshift=-4.33cm,fill=red,canvas is xz plane at y=0] (0,0) rectangle (2,2);
        \end{scope}
        \begin{scope}[shift={(-4,0)}]
            \draw[yshift=8cm,xshift=-2cm,fill=yellow,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=7.23cm,xshift=-2.76cm,fill=yellow,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=6.46cm,xshift=-3.55cm,fill=green,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=5.68cm,xshift=-4.33cm,fill=red,canvas is xz plane at y=0] (0,0) rectangle (2,2);
        \end{scope}
        \begin{scope}[shift={(-6,0)}]
            \draw[yshift=8cm,xshift=-2cm,fill=green,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=7.23cm,xshift=-2.76cm,fill=red,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=6.46cm,xshift=-3.55cm,fill=yellow,canvas is xz plane at y=0] (0,0) rectangle (2,2);
            \draw[yshift=5.68cm,xshift=-4.33cm,fill=red,canvas is xz plane at y=0] (0,0) rectangle (2,2);
        \end{scope}
        \begin{scope}[yshift=-4cm]
            \fill[black,canvas is zy plane at x=0] (0,0) rectangle (1.5,1.5);
            \fill[xshift=-2.05cm,yshift=-.58cm] (0,0) rectangle (1.5,1.5);
            \fill[xshift=-1.5cm,yshift=1.49cm,canvas is zx plane at y=0] (0,0) rectangle (1.5,1.5);
                \fill[rounded corners=5,blue,canvas is zy plane at x=0] (0,0) rectangle (1.5,1.5);
                \fill[rounded corners=5,xshift=-2.05cm,yshift=-.58cm,red] (0,0) rectangle (1.5,1.5);
                \fill[rounded corners=5pt,xshift=-1.5cm,yshift=1.49cm,canvas is zx plane at y=0,white] (0,0) rectangle (1.5,1.5);
            \node[fill=white,inner sep=0pt,draw=white] (n) at (-1.3,-1.7) {Another style};
            \draw[line width=1pt,->] (n) --+ (0,1);
        \end{scope}
    \end{tikzpicture}
\end{document}

Here is the original picture:

Screenshot

And the output:

Screenshot

current_user
  • 5,235
  • 4
    For your first question, I think you should look at the tikz-3dplot package. The \tdplotsetmaincoords{}{} command is what you need I think. Also have a look at this question. – Max Aug 06 '18 at 10:51
  • @Max_Snippe: No, this isn't what I was looking for – I want to (1) to get a view which can be change by two parameters and (2) get TikZ to scramble the cube, but thank you anyway. – current_user Aug 06 '18 at 10:53
  • 2
    Damn I really don't have the time to write elaborate answers but you keep testing my procrastination 'skills' with these cool questions. – Max Aug 06 '18 at 11:10
  • 3
    Do you know the Rubik cube packages https://ctan.org/search/?phrase=rubik ? Maybe they could be used to simply the display etc. – samcarter_is_at_topanswers.xyz Aug 06 '18 at 11:11
  • 1
    Note that randomizing the colors is not easy if you want to guarantee a solvable cube. Only showing 3 sides makes it easier, but still not trivial. – Matt Aug 06 '18 at 15:21
  • @Matt: Yeah, I know, but I just mean to randomize is it in such a way, that the cube is still solveable (→ scrambeling the cube) … – current_user Aug 06 '18 at 15:23
  • You do not need to randomize the face's colours on the cube; instead randomize the positions and rotations of the corner and edge cubes. To get all the permutations as a single number is a 66-bit number but this isn't easy to handle unless you enumerate all 4.3e19 states. I have a brief explanation here of encoding a 3x3x3 cube in a more manageable format in 68-bits guaranteeing it is solvable (by only storing 7-of-8 corners and 11-of-12 edges and work out the others from the parity of other values and by enforcing the parity it is solvable). – MT0 Aug 07 '18 at 13:17
  • @MTO: Yeah, I mean exactly that but I was a little bit too lazy to reword my comment … – current_user Aug 07 '18 at 13:28

2 Answers2

63

For your first question, a very simple example of how the tikz-3dplot handles its coordinate changes. Note the \tplotsetmaincoords{<angle>}{<angle>} command that sets the view.

enter image description here

I trust you'll be able to add the colors.

\documentclass[border=5pt,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}
\begin{document}
    \foreach \myPsi in {90,100,...,170}{
    \tdplotsetmaincoords{70}{\myPsi}
    \begin{tikzpicture}
        \clip (-8,-6) rectangle (8,6);
        \begin{scope}[tdplot_main_coords]
            \draw[step=2cm,canvas is yz plane at x=4] (-4.01,-4.01) grid (4,4);
            \draw[step=2cm,canvas is xz plane at y=4] (-4.01,-4.01) grid (4,4);
            \draw[step=2cm,canvas is yx plane at z=4] (-4.01,-4.01) grid (4,4);
        \end{scope}
    \end{tikzpicture}
    }
\end{document}

Edit
This is bit more realistic with rounded corners:

enter image description here

\documentclass[border=5pt,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}
\begin{document}
    \pgfmathsetmacro\radius{0.1}
    \foreach \frontcolor [remember=\frontcolor as \sidecolor (initially blue)] in {red,white,orange,blue}{
        \foreach \myPsi in {90,100,...,170}{
            \tdplotsetmaincoords{70}{\myPsi}
            \begin{tikzpicture}[line join=round]
                \clip (-3,-2.5) rectangle (3,2.5);
                \begin{scope}[tdplot_main_coords]
                    \filldraw [canvas is yz plane at x=1.5] (-1.5,-1.5) rectangle (1.5,1.5);
                    \filldraw [canvas is xz plane at y=1.5] (-1.5,-1.5) rectangle (1.5,1.5);
                    \filldraw [canvas is yx plane at z=1.5] (-1.5,-1.5) rectangle (1.5,1.5);
                    \foreach \X in {-1.5,-0.5,0.5}{
                        \foreach \Y in {-1.5,-0.5,0.5}{
                            \draw [canvas is yz plane at x=1.5,shift={(\X,\Y)},fill=\sidecolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \draw [canvas is xz plane at y=1.5,shift={(\X,\Y)},fill=\frontcolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \draw [canvas is yx plane at z=1.5,shift={(\X,\Y)},fill=green!60!black] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                        }
                    }
                \end{scope}
            \end{tikzpicture}
        }
    }
\end{document}

Edit 2
As per request, rotating one row:

enter image description here

The code becomes increasingly complex, and drawing order is very important.

\documentclass[border=5pt,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}
\begin{document}
    \pgfmathsetmacro\radius{0.1}
    \foreach \frontcolor [remember=\frontcolor as \sidecolor (initially blue)] in {red,white,orange,blue}{
        \foreach \myPsi in {90,100,...,170}{
            \tdplotsetmaincoords{70}{100}
            \begin{tikzpicture}[line join=round]
                \clip (-3,-2.5) rectangle (3,2.5);
                \begin{scope}[tdplot_main_coords]
                    \filldraw [canvas is yz plane at x=1.5] (-1.5,-1.5) rectangle (1.5,0.5);
                    \filldraw [canvas is xz plane at y=1.5] (-1.5,-1.5) rectangle (1.5,0.5);
                    \filldraw [canvas is yx plane at z=0.5] (-1.5,-1.5) rectangle (1.5,1.5);
                    \foreach \X in {-1.5,-0.5,0.5}{
                        \foreach \Y in {-1.5,-0.5}{
                            \draw [canvas is yz plane at x=1.5,shift={(\X,\Y)},fill=blue] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \draw [canvas is xz plane at y=1.5,shift={(\X,\Y)},fill=red] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                        }
                    }
                    \tdplotsetrotatedcoords{0}{0}{-\myPsi+90}
                    \begin{scope}[tdplot_rotated_coords]
                        \foreach \X in {-1.5,-0.5,0.5}{
                            \filldraw [canvas is yz plane at x=1.5,shift={(\X,0.5)}] (0,0) rectangle (1,1);
                            \filldraw [canvas is xz plane at y=1.5,shift={(\X,0.5)}] (0,0) rectangle (1,1);
                            \draw [canvas is yz plane at x=1.5,shift={(\X,0.5)},fill=\sidecolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \draw [canvas is xz plane at y=1.5,shift={(\X,0.5)},fill=\frontcolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \foreach \Y in {-1.5,-0.5,0.5}{
                                \filldraw [canvas is yx plane at z=1.5,shift={(\X,\Y)}] (0,0) rectangle (1,1);
                                \draw [canvas is yx plane at z=1.5,shift={(\X,\Y)},fill=green!60!black] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            }
                        }
                    \end{scope}
                \end{scope}
            \end{tikzpicture}
        }
    }
\end{document}

To get it to rotate back and forth I cheated a bit when converting it to a .gif:

enter image description here

Edit 3
This pretty much makes you able to control the rotation with buttons:

\documentclass[]{article}
\usepackage{animate}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}

\newwrite\OutFile%
\immediate\openout\OutFile=tl.txt%
\immediate\write\OutFile{::0x0,1}
\foreach \i in {2,...,36}{
    \immediate\write\OutFile{::\i}%
}
\immediate\closeout\OutFile


\pgfmathsetmacro\radius{0.1}
\tdplotsetmaincoords{70}{100}

\newcommand{\drawRotatedRow}[2][2]{
    \pgfmathsetmacro\myHeight{-1.5+int(#1)}
    \pgfmathsetmacro\myPsi{#2}
    \pgfmathsetmacro\mySecondPsi{-80+Mod(\myPsi+80,90)}
    \pgfmathtruncatemacro\mySegment{Mod((\myPsi+80)/90,4)}
    \ifcase\mySegment% segment 0
        \def\frontcolor{red}
        \def\sidecolor{blue}
    \or% segment 1
        \def\frontcolor{blue}
        \def\sidecolor{orange}
    \or% segment 2
        \def\frontcolor{orange}
        \def\sidecolor{white}
    \or% segment 3
        \def\frontcolor{white}
        \def\sidecolor{red}
    \fi
    \begin{scope}[tdplot_main_coords]
        \tdplotsetrotatedcoords{0}{0}{\mySecondPsi}
        \begin{scope}[tdplot_rotated_coords]
            \filldraw [canvas is yx plane at z={\myHeight+1}] (-1.5,-1.5) rectangle (1.5,1.5);
            \filldraw [canvas is yz plane at x=1.5] (-1.5,\myHeight) rectangle (1.5,{\myHeight+1});
            \filldraw [canvas is xz plane at y=1.5] (-1.5,\myHeight) rectangle (1.5,{\myHeight+1});
            \foreach \X in {-1.5,-0.5,0.5}{
                \draw [canvas is yz plane at x=1.5,shift={(\X,\myHeight)},fill=\sidecolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                \draw [canvas is xz plane at y=1.5,shift={(\X,\myHeight)},fill=\frontcolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                \ifnum#1=2\relax
                    \foreach \Y in {-1.5,-0.5,0.5}{
                        \draw [canvas is yx plane at z={\myHeight+1},shift={(\X,\Y)},fill=green!60!black] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                    }
                \fi
            }
        \end{scope}
    \end{scope}
}
\begin{document}
    \begin{animateinline}[controls,loop,timeline=tl.txt]{10}
        \begin{tikzpicture}[line join=round]
            \clip (-3,-2.5) rectangle (3,2.5);
            \drawRotatedRow[0]{0}
            \drawRotatedRow[1]{0}
        \end{tikzpicture}
        \newframe
        \multiframe{36}{iPsi=0+10}{%
            \begin{tikzpicture}[line join=round]
                \clip (-3,-2.5) rectangle (3,2.5);
                \drawRotatedRow{\iPsi}
            \end{tikzpicture}
        }
    \end{animateinline}
\end{document}

I added a command that draws a row of cubes, with optional z level (defaults to 2, zero based) and with a rotation about z: \drawRotatedRow[<level>]{<rotation>}. With this command now we can do something like this:

enter image description here

\documentclass[tikz]{standalone}
\usepackage{animate}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}

\pgfmathsetmacro\radius{0.1}
\tdplotsetmaincoords{70}{100}

\newcommand{\drawRotatedRow}[2]{
    \pgfmathsetmacro\myHeight{-1.5+int(#1)}
    \pgfmathsetmacro\myPsi{#2}
    \pgfmathsetmacro\mySecondPsi{-80+Mod(\myPsi+80,90)}
    \pgfmathtruncatemacro\mySegment{Mod((\myPsi+80)/90,4)}
    \ifcase\mySegment% segment 0
        \def\frontcolor{red}
        \def\sidecolor{blue}
    \or% segment 1
        \def\frontcolor{blue}
        \def\sidecolor{orange}
    \or% segment 2
        \def\frontcolor{orange}
        \def\sidecolor{white}
    \or% segment 3
        \def\frontcolor{white}
        \def\sidecolor{red}
    \fi
    \begin{scope}[tdplot_main_coords]
        \tdplotsetrotatedcoords{0}{0}{\mySecondPsi}
        \begin{scope}[tdplot_rotated_coords]
            \filldraw [canvas is yx plane at z={\myHeight+1}] (-1.5,-1.5) rectangle (1.5,1.5);
            \filldraw [canvas is yz plane at x=1.5] (-1.5,\myHeight) rectangle (1.5,{\myHeight+1});
            \filldraw [canvas is xz plane at y=1.5] (-1.5,\myHeight) rectangle (1.5,{\myHeight+1});
            \foreach \X in {-1.5,-0.5,0.5}{
                \draw [canvas is yz plane at x=1.5,shift={(\X,\myHeight)},fill=\sidecolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                \draw [canvas is xz plane at y=1.5,shift={(\X,\myHeight)},fill=\frontcolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                \ifnum#1=2\relax
                    \foreach \Y in {-1.5,-0.5,0.5}{
                        \draw [canvas is yx plane at z={\myHeight+1},shift={(\X,\Y)},fill=green!60!black] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                    }
                \fi
            }
        \end{scope}
    \end{scope}
}
\begin{document}
    \foreach \iPsi in {0,10,...,359}{
        \begin{tikzpicture}[line join=round]
            \clip (-3,-2.5) rectangle (3,2.5);
            \drawRotatedRow{0}{-\iPsi}
            \drawRotatedRow{1}{0}
            \drawRotatedRow{2}{\iPsi}
        \end{tikzpicture}
    }
\end{document}

Or even this (very long GIF):

enter image description here

\documentclass[tikz]{standalone}
\usepackage{animate}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{3d}

\pgfmathsetmacro\radius{0.1}
\tdplotsetmaincoords{70}{100}

\newcommand{\drawRotatedRow}[2]{
    \pgfmathsetmacro\myHeight{-1.5+int(#1)}
    \pgfmathsetmacro\myPsi{#2}
    \pgfmathsetmacro\mySecondPsi{-80+Mod(\myPsi+80,90)}
    \pgfmathtruncatemacro\mySegment{Mod((\myPsi+80)/90,4)}
    \ifcase\mySegment% segment 0
        \def\frontcolor{red}
        \def\sidecolor{blue}
    \or% segment 1
        \def\frontcolor{blue}
        \def\sidecolor{orange}
    \or% segment 2
        \def\frontcolor{orange}
        \def\sidecolor{white}
    \or% segment 3
        \def\frontcolor{white}
        \def\sidecolor{red}
    \fi
    \begin{scope}[tdplot_main_coords]
        \tdplotsetrotatedcoords{0}{0}{\mySecondPsi}
        \begin{scope}[tdplot_rotated_coords]
            \filldraw [canvas is yx plane at z={\myHeight+1}] (-1.5,-1.5) rectangle (1.5,1.5);
            \filldraw [canvas is yz plane at x=1.5] (-1.5,\myHeight) rectangle (1.5,{\myHeight+1});
            \filldraw [canvas is xz plane at y=1.5] (-1.5,\myHeight) rectangle (1.5,{\myHeight+1});
            \foreach \X in {-1.5,-0.5,0.5}{
                \draw [canvas is yz plane at x=1.5,shift={(\X,\myHeight)},fill=\sidecolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                \draw [canvas is xz plane at y=1.5,shift={(\X,\myHeight)},fill=\frontcolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                \ifnum#1=2\relax
                    \foreach \Y in {-1.5,-0.5,0.5}{
                        \draw [canvas is yx plane at z={\myHeight+1},shift={(\X,\Y)},fill=green!60!black] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                    }
                \fi
            }
        \end{scope}
    \end{scope}
}
\begin{document}
    \foreach \level in {0,1,2}{
        \foreach \iPsi in {0,10,...,359}{
            \begin{tikzpicture}[line join=round]
                \clip (-3,-2.5) rectangle (3,2.5);
                \ifcase\level % Level 0 rotating
                    \drawRotatedRow{0}{\iPsi}
                    \drawRotatedRow{1}{0}
                    \drawRotatedRow{2}{0}
                \or % Level 1 rotating
                    \drawRotatedRow{0}{0}
                    \drawRotatedRow{1}{\iPsi}
                    \drawRotatedRow{2}{0}
                \or % Level 2 rotating
                    \drawRotatedRow{0}{0}
                    \drawRotatedRow{1}{0}
                    \drawRotatedRow{2}{\iPsi}
                \fi
            \end{tikzpicture}
        }
    }
\end{document}
Max
  • 9,733
  • 3
  • 28
  • 35
  • @Max_Snippe: Nice, that's it almost; how can I adjust the view for any angle ф, ψ and Ѳ of rotation? – current_user Aug 06 '18 at 11:12
  • 1
    @current_user you can either use the tikz-3dplot native \tdplotsetrotatedcoords{}{}{} command, or have a look at this question and its answers. – Max Aug 06 '18 at 11:13
  • @Max_Snippe: WOW … this looks amazing! Is there a way that, for example, one row can be rotated 90 degrees and back (threaded in the animation)? – current_user Aug 06 '18 at 15:24
  • 1
    @current_user it's possible, but it gets quite hard quite fast. I don't think it is possible to automate the rotation of arbitrary rows and columns. – Max Aug 06 '18 at 16:10
  • @Max_Snippe: OK, this is just incredible – definitely the best answer yet! Is there maybe, just maybe, a way, how buttons can controll the way of rotating? But again – yet the best answer! – current_user Aug 06 '18 at 16:17
  • 1
    @current_user See my latest edit, I believe that it might be possible to expand this to rotating columns, but I will not try to do that. I leave some work for you :) – Max Aug 06 '18 at 19:47
23

Just for completeness. As there was the question about pgfplots, I just spell out Max Snippe's comment.

\documentclass[border=3.14mm,tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\begin{document}
\def\amax{4} %number of squares in each direction
\foreach \X in {30}
{\begin{tikzpicture}
%\path[use as bounding box] (-5,5) rectangle (5,5);
\begin{axis}[height=5cm,unit vector ratio=1 1 1,view={\X}{20},colormap/hot,
    set layers=standard,
    domain=0:{\amax+1},
    domain y=0:{\amax+1},
    samples y=1,
    xmin=-1,ymax=\amax+1,
    hide axis,
    xtick=\empty, ytick=\empty, ztick=\empty,
    clip=false,samples=\amax+1,samples y=\amax+1
]
\addplot3[point meta=rand,mesh,surf] (x,y,\amax+1);
\addplot3[point meta=rand,mesh,surf] (x,0,y);
\addplot3[point meta=rand,mesh,surf] (\amax+1,x,y);
\end{axis}
\end{tikzpicture}}
\end{document}

enter image description here

Note:

  • I was not able to do a proper animation. For some reason the plots got doubled on each slide. I have no idea what's going on, and I was able to do proper pgfplots animations in the past. Most likely I am doing something really dumb. I was really dumb. For another question I changed the viewers preference to two page view. So one could do animations but compared to Max Snippe's result the outcome will be poor.

  • If you give me rough idea what the colors should be I will be happy to add them as well. Ideally this would be some cool formula such that one could use point meta for that, otherwise I guess one has to resort to tables. I added random colors from a colormap that describes the temperatures these days. If I was not hibernating in winter, I could change it to cool then.

ADDENDUM: All credits go to current_user, who had the idea, Max Snippe, who made the superb code (which I just stole), and samcarter, the author of tikzmarmots. ;-)

\documentclass[border=5pt,tikz]{standalone}
\usepackage{tikz-3dplot}
\usepackage{tikzmarmots}
\newsavebox\Marmot
\savebox\Marmot{\tikz[scale=0.4]{\marmot[whiskers,teeth]}}
\usetikzlibrary{3d}
\begin{document}
    \pgfmathsetmacro\radius{0.1}
    \foreach \frontcolor [remember=\frontcolor as \sidecolor (initially blue)] in {red,white,orange,blue}{
        \foreach \myPsi in {90,100,...,170}{ %  
            \tdplotsetmaincoords{70}{\myPsi}
            \begin{tikzpicture}[line join=round]
                \clip (-3,-2.5) rectangle (3,2.5);
                \begin{scope}[tdplot_main_coords]
                    \filldraw [canvas is yz plane at x=1.5] (-1.5,-1.5) rectangle (1.5,1.5);
                    \filldraw [canvas is xz plane at y=1.5] (-1.5,-1.5) rectangle (1.5,1.5);
                    \filldraw [canvas is yx plane at z=1.5] (-1.5,-1.5) rectangle (1.5,1.5);
                    \foreach \X in {-1.5,-0.5,0.5}{
                        \foreach \Y in {-1.5,-0.5,0.5}{
                            \draw [canvas is yz plane at x=1.5,shift={(\X,\Y)},fill=\sidecolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \draw [canvas is xz plane at y=1.5,shift={(\X,\Y)},fill=\frontcolor] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \draw [canvas is yx plane at z=1.5,shift={(\X,\Y)},fill=green!60!black] (0.5,0) -- ({1-\radius},0) arc (-90:0:\radius) -- (1,{1-\radius}) arc (0:90:\radius) -- (\radius,1) arc (90:180:\radius) -- (0,\radius) arc (180:270:\radius) -- cycle;
                            \begin{scope}[canvas is yz plane at x=1.5,transform shape]
                            \node at (\X+0.5,\Y+0.5) {\usebox{\Marmot}};
                            \end{scope}
                            \begin{scope}[canvas is xz plane at y=1.5,transform shape]
                            \node at (\X+0.5,\Y+0.5) {\usebox{\Marmot}};
                            \end{scope}
                            \begin{scope}[canvas is yx plane at z=1.5,transform shape]
                            \node[yscale=-1] at (\X+0.5,\Y+0.5) {\usebox{\Marmot}};
                            \end{scope}
                        }
                    }
                \end{scope}
            \end{tikzpicture}
        }
    }
\end{document}

enter image description here

Barbara Beeton discovered that the marmots are wagging their tails. This is because Max Snippe's routines are automatically such that the tails of the marmots are always behind the marmot. There is a reflection at the right moment. Therefore one may want to promote the marmots to 3D. (I am very optimistic that the tikzmarmots package will provide 3D marmots in the near future. The impatient users may get the following animation by replacing all \fill[ commands by \shade[ball color= in that package and modify the last marmot node to \node[yscale=-1,rotate=\myPsi-90] at (\X+0.5,\Y+0.5) {\usebox{\Marmot}};.)

enter image description here

  • I just got an idea: Could you display your profile photo (the marmot of course) on a canvas, so that one side is your photo? – current_user Aug 06 '18 at 17:16
  • This is brutal! xD Hey, how would it be to collect such things, like everybody can put his own unique style? – current_user Aug 06 '18 at 17:56
  • I mean like modifying like you did – everybody can make an answer, so that we can more and more examples, so that we got something like an “artwork“. – current_user Aug 06 '18 at 18:01
  • 1
    This is great! Shame that you already had my +1 – Max Aug 06 '18 at 18:07
  • 2
    +1, for the turn of the tails from six to nine o'clock and the reset on the green side – J Leon V. Aug 06 '18 at 23:32
  • 1
    @JLeonV. Thanks. That has already lead to some amusement in the chat ;-) But actually I didn't know about it before barbara beeton pointed it out, meaning that the projection by the 3d library does it on its own ... ;-) The reset is due to Max Snippe! –  Aug 06 '18 at 23:35
  • @marmot: The design is just fantastic! Do you want to make some other, too? [of course, +1]. ;) – current_user Aug 06 '18 at 23:49
  • 2
    @current_user Now I understand why that happens. Max Snippe's routine is more tricky than I thought. To understand this, you need to replace the marmots on the sides by different letters in the first two scopes. –  Aug 07 '18 at 00:08
  • 1
    @marmot: As Max Snippet already mentioned: The drawing order is very important … ;) – current_user Aug 07 '18 at 00:10
  • 1
    @marmot As you already understood, I only draw three sides of the cube, and rotate them only in a range of 90 degrees. To simulate that the cube rotates further I just change the colors accordingly. For this application that is enough, but it will become very difficult to implement this for more rotation axes (besides z) and also for column rotations. – Max Aug 07 '18 at 10:03
  • 1
    @MaxSnippe Sometimes I feel one might be able to get closer to 3D by using these tricks, but then I get frightened by the complexity and the loopholes that exist for more general situations, and thus let it be. But your code is truly amazing! ;-) –  Aug 07 '18 at 14:14
  • 1
    @marmot Wow the question you referred to is almost magical. It is good to see that I am not nearly done learning :) I will have to check sometime how 3D CAD software determines what to draw and what to hide. But for now I have more urgent matters to attend to. Anyways, thanks for the appraisal! – Max Aug 07 '18 at 14:22