Truncated octahedron in TikZ

I'm having trouble drawing a truncated octahedron for a Brillouin zone in TikZ. My attempt so far is an adaptation of this answer which produces wonky square bits that are also too small (the sides of the hexagons should be equal in length).

The size of the square parts could be changed by adjusting the nodes but this seems very manual and there must be a better way. Can anyone enlighten me? Perhaps a TikZ-3D plot is more appropriate?

Output:

MWE:

\documentclass{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}[thick,scale=10]
%
\coordinate (C1) at (0.3,-0.15);
\coordinate (C2) at (0.55,-0.15);
\coordinate (C3) at (0.425,-0.025);
\coordinate (C4) at (0.425,-0.275);
%
\coordinate (D1) at (0.85,-0.05);
\coordinate (D2) at (0.9,0.05);
\coordinate (D3) at (0.875,0.125);
\coordinate (D4) at (0.875,-0.125);
%
\coordinate (E1) at (0.375,0.375);
\coordinate (E2) at (0.625,0.375);
\coordinate (E3) at (0.525,0.425);
\coordinate (E4) at (0.525,0.325);
%
\coordinate (F1) at (0.15,0.015);
\coordinate (F2) at (0.1,-0.015);
\coordinate (F3) at (0.125,0.125);
\coordinate (F4) at (0.125,-0.125);
%
\coordinate (G1) at (0.375,-0.375);
\coordinate (G2) at (0.625,-0.375);
\coordinate (G3) at (0.475,-0.425);
\coordinate (G4) at (0.575,-0.325);

\begin{scope}[thick,dashed]
\draw (C1) -- (C4) -- (C2) -- (C3) -- (C1);
\draw (D1) -- (D4) -- (D2) -- (D3) -- (D1);
\draw (E1) -- (E4) -- (E2) -- (E3) -- (E1);
\draw (F1) -- (F4) -- (F2) -- (F3) -- (F1);
\draw (G1) -- (G4) -- (G2) -- (G3) -- (G1);
\end{scope}
\draw (F3) -- (F2) -- (C1) -- (C3) -- (E4) -- (E1);
\draw (C1) -- (C4) -- (G3) -- (G1) -- (F4) -- (F2);
\draw (D1) -- (C2) -- (C3) -- (E4) -- (E2) -- (D3) -- (D1);
\draw (D1) -- (C2) -- (C4) -- (G3) -- (G2) --(D4) -- (D1);
\draw (E2) -- (E3) -- (E1) -- (F3) -- (F2) -- (F4) -- (G1) -- (G3) --  (G2) -- (D4) -- (D1) -- (D3) --cycle;
\end{tikzpicture}

\end{document}


Desired output:

Please note I haven't added the labels to my attempt as undoubtably they would change after getting the shape right.

• This would probably be easier in 3D, but you will still need to do some trig to orient the faces perpendicular to the radius. Apr 9 '15 at 13:26
• I suggest that you read the pst-solides3d package. This uses pstricks. It has the octahedron easy to plot and there is the ability to remove slices from the octahedron to get a truncated octahedron. texdoc.net/texmf-dist/doc/generic/pst-solides3d/… Apr 9 '15 at 14:58
• @R.Schumacher Is that package compatible with pdfLaTeX? The manual says pdfTeX won't work so that should mean pdfLaTeX won't work either as it's non dvips? Apr 9 '15 at 15:12
• @Christopher Not directly, however this discussing some ways to get pdf output with pstricks. tex.stackexchange.com/questions/8413/… I suggested this because ease of getting your figure. Personally, I would use pstricks with standalone, then use the aforementioned conversion utilities to get a pdf which I would put in my original document using includegraphics Apr 9 '15 at 16:59

This ought to get you started constructing the shape in 3d.

I started by drawing all the squares, then joining neighboring corners one at a time.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw[blue] (1.414,.707,0) -- (1.414,0,.707) -- (1.414,-.707,0) -- (1.414,0,-.707) -- cycle;
\draw[blue,dashed] (-1.414,.707,0) -- (-1.414,0,.707) -- (-1.414,-.707,0) -- (-1.414,0,-.707) -- cycle;
\draw[red] (.707,1.414,0) -- (0,1.414,.707) -- (-.707,1.414,0) -- (0,1.414,-.707) -- cycle;
\draw[red,dashed] (.707,-1.414,0) -- (0,-1.414,.707) -- (-.707,-1.414,0) -- (0,-1.414,-.707) -- cycle;
\draw[green] (.707,0,1.414) -- (0,.707,1.414) -- (-.707,0,1.414) -- (0,-.707,1.414) -- cycle;
\draw[green,dashed] (.707,0,-1.414) -- (0,.707,-1.414) -- (-.707,0,-1.414) -- (0,-.707,-1.414) -- cycle;
\draw (1.414,.707,0) -- (.707,1.414,0)
(1.414,0,.707) -- (.707,0,1.414)
(0,1.414,.707) -- (0,.707,1.414)
(1.414,-.707,0) -- (.707,-1.414,0)
(-.707,0,1.414) -- (-1.414,0,.707)
(0,-.707,1.414) -- (0,-1.414,.707)
(-.707,1.414,0) -- (-1.414,.707,0)
(-1.414,-.707,0) -- (-.707,-1.414,0);
\end{tikzpicture}
\end{document}


• I understand the trigonometry but I'm at a loss when it comes telling TikZ-3D this information. There's a TikZ-3D as an alternative answer to the one linked in the question but how do you put in the additional points? Apr 9 '15 at 14:40
• You don't really need tikz-3d unless you intend to rotate the image. Just use (x,y,z) when entering the points. Apr 9 '15 at 14:42
• Some form of paremetrization probably? Apr 9 '15 at 14:53

Here's an alternative approach that uses tikz-3d (The vertices are in 4D - I don't understand exactly how/why tikz-3d still works with 4D coordinates, but it does!).

In my case I wanted to draw a Hamiltonian path on the truncated octahedron, so it was useful to have a way to systematically generate the vertices following a Hamiltonian path traversal.

\documentclass{minimal}
\usepackage{tikz,tikz-3dplot}

\definecolor{aa}{RGB}{100,140,100}
\definecolor{bb}{RGB}{186,146,162}
\definecolor{cc}{RGB}{91,173,69}
\definecolor{dd}{RGB}{52,30,40}
\definecolor{ee}{RGB}{72,52,111}
\definecolor{ff}{RGB}{111,52,92}
\definecolor{gg}{RGB}{111,92,52}

\tdplotsetmaincoords{70}{165}

\begin{document}
\begin{tikzpicture}[scale=3,tdplot_main_coords]
\coordinate (O) at (0,0,0);

% Use Steinhaus-Johnson-Trotter algorithm to generate the vertices.
% These coordinates correspond to a Cayley Graph, where each neighbouring
% vertex is produced by swapping the values of two adjacent entries.
% \coordinate (A) at (1, 2, 3, 4);
% \coordinate (B) at (2, 1, 3, 4);
% \coordinate (C) at (2, 3, 1, 4);
% \coordinate (D) at (2, 3, 4, 1);
% \coordinate (E) at (3, 2, 4, 1);
% \coordinate (F) at (3, 2, 1, 4);
% \coordinate (G) at (3, 1, 2, 4);
% \coordinate (H) at (1, 3, 2, 4);
% \coordinate (I) at (1, 3, 4, 2);
% \coordinate (J) at (3, 1, 4, 2);
% \coordinate (K) at (3, 4, 1, 2);
% \coordinate (L) at (3, 4, 2, 1);
% \coordinate (M) at (4, 3, 2, 1);
% \coordinate (N) at (4, 3, 1, 2);
% \coordinate (O) at (4, 1, 3, 2);
% \coordinate (P) at (1, 4, 3, 2);
% \coordinate (Q) at (1, 4, 2, 3);
% \coordinate (R) at (4, 1, 2, 3);
% \coordinate (S) at (4, 2, 1, 3);
% \coordinate (T) at (4, 2, 3, 1);
% \coordinate (U) at (2, 4, 3, 1);
% \coordinate (V) at (2, 4, 1, 3);
% \coordinate (W) at (2, 1, 4, 3);
% \coordinate (X) at (1, 2, 4, 3);

% The truncated octahedron is equivalent to a permutahedron of order 4.
% The permutahedron has vertices which are inverse permutations of the above
% Example (2, 3, 1, 4) -> (3, 1, 2, 4)
% because if you take the values of (2, 3, 1, 4) at indices (3, 1, 2, 4)
% you get (1, 2, 3, 4).
% More details in the article below
% https://commons.wikimedia.org/wiki/Category:Permutohedron_of_order_4_(raytraced)#Permutohedron_vs._Cayley_graph
\coordinate (A) at (1, 2, 3, 4);  % equal to its inverse
\coordinate (B) at (2, 1, 3, 4);  % equal to its inverse
\coordinate (C) at (3, 1, 2, 4);  % <- the inverse permutation of (2, 3, 1, 4)
\coordinate (D) at (4, 1, 2, 3);
\coordinate (E) at (4, 2, 1, 3);
\coordinate (F) at (3, 2, 1, 4);
\coordinate (G) at (2, 3, 1, 4);
\coordinate (H) at (1, 3, 2, 4);
\coordinate (I) at (1, 4, 2, 3);
\coordinate (J) at (2, 4, 1, 3);
\coordinate (K) at (3, 4, 1, 2);
\coordinate (L) at (4, 3, 1, 2);
\coordinate (M) at (4, 3, 2, 1);
\coordinate (N) at (3, 4, 2, 1);
\coordinate (O) at (2, 4, 3, 1);
\coordinate (P) at (1, 4, 3, 2);
\coordinate (Q) at (1, 3, 4, 2);
\coordinate (R) at (2, 3, 4, 1);
\coordinate (S) at (3, 2, 4, 1);
\coordinate (T) at (4, 2, 3, 1);
\coordinate (U) at (4, 1, 3, 2);
\coordinate (V) at (3, 1, 4, 2);
\coordinate (W) at (2, 1, 4, 3);
\coordinate (X) at (1, 2, 4, 3);

% Label the vertices
\node[above=2pt, right=2pt] at (A) {A};
\node[above=2pt, left=2pt] at (B) {B};
\node[above=2pt, right=2pt] at (C) {C};
\node[above=2pt, right=2pt] at (D) {D};
\node[above=3pt, left=2pt] at (E) {E};
\node[above=5pt, left=2pt] at (F) {F};
\node[above=2pt, right=2pt] at (G) {G};
\node[above=2pt, right=2pt] at (H) {H};
\node[above=2pt, right=2pt] at (I) {I};
\node[above=2pt, left=2pt] at (J) {J};
\node[above=3pt, left=2pt] at (K) {K};
\node[above=2pt, left=2pt] at (L) {L};
\node[above=2pt, left=2pt] at (M) {M};
\node[above=2pt, left=2pt] at (N) {N};
\node[below=2pt, right=2pt] at (O) {O};
\node[above=2pt, right=2pt] at (P) {P};
\node[above=6pt, left=0pt] at (Q) {Q};
\node[below=2pt, left=2pt] at (R) {R};
\node[above=2pt, left=2pt] at (S) {S};
\node[above=2pt, left=2pt] at (T) {T};
\node[above=2pt, left=2pt] at (U) {U};
\node[above=2pt, left=2pt] at (V) {V};
\node[above=6pt, left=0pt] at (W) {W};
\node[above=2pt, left=2pt] at (X) {X};

% Draw the outlines of faces of the truncated octahedron.
\draw (M) -- (N) -- (O) -- (R) -- (S) -- (T) -- cycle;
\draw (S) -- (R) -- (Q) -- (X) -- (W) -- (V) -- cycle;
\draw (O) -- (N) -- (K) -- (J) -- (I) -- (P) -- cycle;
\draw (M) -- (L) -- (E) -- (D) -- (U) -- (T) -- cycle;
\draw[dashed, opacity=0.3] (A) -- (B) -- (C) -- (F) -- (G) -- (H) -- cycle;
\draw[dashed, opacity=0.3] (E) -- (F) -- (G) -- (J) -- (K) -- (L) -- cycle;
\draw[dashed, opacity=0.3] (W) -- (B) -- (C) -- (D) -- (U) -- (V) -- cycle;
\draw[dashed, opacity=0.3] (Q) -- (X) -- (A) -- (H) -- (I) -- (P) -- cycle;
\draw (L) -- (K);
\draw (Q) -- (P);
\draw (V) -- (U);

% draw Hamiltonian
\draw[dotted, line width=0.6mm] (A) -- (B) -- (C) -- (D) --
(E) -- (F) -- (G) -- (H) -- (I) -- (J) -- (K) -- (L) --
(M) -- (N) -- (O) -- (P) -- (Q) -- (R) -- (S) -- (T) --
(U) -- (V) -- (W) -- (X) -- cycle;

% Fill faces that are in foreground with colour
\fill[aa, opacity=0.4] (M) -- (N) -- (O) -- (R) -- (S) -- (T) -- cycle;
\fill[bb, opacity=0.4] (S) -- (R) -- (Q) -- (X) -- (W) -- (V) -- cycle;
\fill[cc, opacity=0.4] (O) -- (N) -- (K) -- (J) -- (I) -- (P) -- cycle;
\fill[dd, opacity=0.4] (M) -- (L) -- (E) -- (D) -- (U) -- (T) -- cycle;
\fill[ee, opacity=0.4] (U) -- (V) -- (S) -- (T) -- cycle;
\fill[ff, opacity=0.4] (R) -- (Q) -- (P) -- (O) -- cycle;
\fill[gg, opacity=0.4] (M) -- (N) -- (K) -- (L) -- cycle;

\end{tikzpicture}
\end{document}


Breakdown of the steps:

1. Generate all possible permutations of 4 elements using the Johnson-Trotter algorithm Steinhaus-Johnson-Trotter algorithm (generates a Hamiltonian path, see also Adjacent Exchanges section in this paper). The vertices produced are vertices of a graph where neighbouring vertices differ by a swap of adjacent values (A Cayley Graph).

2. Invert the "coordinates" of the vertices using the inverse permutation, to get the coordinates of vertices of a permutohedron of order 4 (a truncated octahedron). Permutohedron vs Cayley Graph

3. Join the vertices of the 8 hexagonal faces.