11

Is there an easy way to draw the decorated honeycomb as attached here in tikz? enter image description here

My attempt is as follows but this method didn't let me fill up the hexagons with colors. Also, it is currently a bit inefficient to draw a lattice as one should use a for loop while using scope.

\documentclass[10pt]{article}
\usepackage{tikz}  
\usepackage{calculator}  
\usetikzlibrary{rulercompass}  
\usetikzlibrary{intersections,quotes,angles}  
\usetikzlibrary{calc}
\usepackage{calc}

\newlength{\R}\setlength{\R}{2cm}
\newcommand{\gettikzxy}[3]{%
  \tikz@scan@one@point\pgfutil@firstofone#1\relax
  \edef#2{\the\pgf@x}%
  \edef#3{\the\pgf@y}%
}
\begin{document}
\begin{tikzpicture}
  %% Try to define a style, to prevent typing
  [inner sep=0mm,
  minicirc/.style={circle,draw=black!40,fill=black!40,thick}]

  %% Now do the circle with nodes
  \node (circ1) at (60:\R) [minicirc] {};
  \node (circ2) at (120:\R) [minicirc] {};
  \node (circ3) at (180:\R) [minicirc] {};
  \node (circ4) at (240:\R) [minicirc] {};
  \node (circ5) at (300:\R) [minicirc] {};
  \node (circ6) at (360:\R) [minicirc] {};
  
  \node (circ7) at (45:2*\R) [minicirc] {};
  \node (circ8) at (105:2*\R) [minicirc] {};
  \node (circ9) at (165:2*\R) [minicirc] {};
  \node (circ10) at (225:2*\R) [minicirc] {};
  \node (circ11) at (285:2*\R) [minicirc] {};
  \node (circ12) at (345:2*\R) [minicirc] {};
  
  
\node (circ13) at (75:2*\R) [minicirc] {};
\node (circ14) at (135:2*\R) [minicirc] {};
\node (circ15) at (195:2*\R) [minicirc] {};
\node (circ16) at (255:2*\R) [minicirc] {};
\node (circ17) at (315:2*\R) [minicirc] {};
\node (circ18) at (375:2*\R) [minicirc] {};
    

  %% Connect those circs
  \draw [black] (circ1) to (circ2) to (circ3) 
  to (circ4) to (circ5) to (circ6) to (circ1);
  
  \fill [orange] (circ1) to (circ2) to (circ3) 
  to (circ4) to (circ5) to (circ6) to (circ1);
  
  \draw [] (circ7) to (circ13) to (circ8) 
  to (circ14) to (circ9) to (circ15) to (circ10) to (circ16) to (circ11) to (circ17) to (circ12) to (circ18) to (circ7);
  
 \draw[](circ1)--(circ7);
 \draw (circ2)--(circ8);
  \draw (circ3)--(circ9);
 \draw (circ4)--(circ10);
  \draw (circ5)--(circ11);
 \draw (circ6)--(circ12);
 
 
  \draw (circ1)--(circ13);
 \draw (circ2)--(circ14);
  \draw (circ3)--(circ15);
 \draw (circ4)--(circ16);
  \draw (circ5)--(circ17);
 \draw (circ6)--(circ18);
 
\draw  node[scale=3]{B} (0,0);

\node (circshift) at ($ (circ7) + (\R,0) $) [minicirc] {};

\begin{scope}[shift={(circshift)}]
\node (circ1) at (60:\R) [minicirc] {};
 \node (circ2) at (120:\R) [minicirc] {};
  \node (circ3) at (180:\R) [minicirc] {};
  \node (circ4) at (240:\R) [minicirc] {};
  \node (circ5) at (300:\R) [minicirc] {};
  \node (circ6) at (360:\R) [minicirc] {};
  
     \node (circ7) at (45:2*\R) [minicirc] {};
  \node (circ8) at (105:2*\R) [minicirc] {};
  \node (circ9) at (165:2*\R) [minicirc] {};
  \node (circ10) at (225:2*\R) [minicirc] {};
  \node (circ11) at (285:2*\R) [minicirc] {};
  \node (circ12) at (345:2*\R) [minicirc] {};
  
  
\node (circ13) at (75:2*\R) [minicirc] {};
\node (circ14) at (135:2*\R) [minicirc] {};
\node (circ15) at (195:2*\R) [minicirc] {};
\node (circ16) at (255:2*\R) [minicirc] {};
\node (circ17) at (315:2*\R) [minicirc] {};
\node (circ18) at (375:2*\R) [minicirc] {};
    

  %% Connect those circs
  \draw [black] (circ1) to (circ2) to (circ3) 
  to (circ4) to (circ5) to (circ6) to (circ1);
  
  \fill [orange] (circ1) to (circ2) to (circ3) 
  to (circ4) to (circ5) to (circ6) to (circ1);
  
  \draw [] (circ7) to (circ13) to (circ8) 
  to (circ14) to (circ9) to (circ15) to (circ10) to (circ16) to (circ11) to (circ17) to (circ12) to (circ18) to (circ7);
  
 \draw (circ1)--(circ7);
 \draw (circ2)--(circ8);
  \draw (circ3)--(circ9);
 \draw (circ4)--(circ10);
  \draw (circ5)--(circ11);
 \draw (circ6)--(circ12);
 
 
  \draw (circ1)--(circ13);
 \draw (circ2)--(circ14);
  \draw (circ3)--(circ15);
 \draw (circ4)--(circ16);
  \draw (circ5)--(circ17);
 \draw (circ6)--(circ18);
 
%  \node (origin) at (0,0,0) {0};
\draw  node[scale=3]{R} (0,0);%

\end{scope}

\end{tikzpicture}
\end{document}
4
  • 1
    Draw the hexagons first as a closed polygon, then you can fill them. Then place the circles (fill=white) on the corners. The library shapes.geometric might help with the regular polygon shape. Sep 8 at 7:31
  • This doesn't look like a honeycomb lattice (and not like a Kagome lattice either). What type of lattice is this? Sep 8 at 7:53
  • 1
    Hi! You should use the translation symmetries of your figure and then two loops. Explicitely, the fundamental element should be the hexagon (that can be drawn with a loop too, by the way) and three rectangles (say East South East, ENE, and N). On this fundamental element you do a loop that represents a shift with the vector (30 : {(1+sqrt(3))*\R})' where \R` is the side of the hexagon. Then, on the result, you do another loop (shifts) with vector `(90 : {(1+sqrt(3))*\R})'. We can talk afterwards for the colors, letters,...
    – Daniel N
    Sep 8 at 8:21
  • 2
    @HenriMenke --> en.wikipedia.org/wiki/Rhombitrihexagonal_tiling
    – Thruston
    Sep 8 at 11:28

2 Answers 2

9

Everything's a node.

This uses the regular polygon shape and every step it places the following picture:

enter image description here

or with the line

node[hc41={##1}{##2}]node[hc42={##1}{##2}]node[hc43={##1}{##2}]

uncommented:

enter image description here

(The squares aren't really needed since all sides are covered by the hexagons or the triangles.)

For every hexagon node exists a style that can be changed:

  • every hexagon node gets two parameters (the x and the y value) and
  • hexagon node x-y for every individual hexagon

The first style can be used to find specific hexagons via:

every hexagon node/.style 2 args={label=center:#1/#2}

Even the triangles have hc31 and hc32 including hc31-x-y and hc32-x-y. The same applies for the squares if they're used.

For small n-gon side lengths it's safer to use label instead of node contents because the label won't change the node's size.

The output is at the end of this answer and looks exactly the same as the next one, however, when the hc?? styles uncommented, it looks a bit more colorful.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{shapes.geometric}
\tikzset{decorated honeycomb lattice/.style={
  /utils/exec=\colorlet{honeycomb@0}{blue!50}%
              \colorlet{honeycomb@1}{green!75!black}%
              \colorlet{honeycomb@2}{red!75!black},
  n-gon side length/.initial={#1},
  n-gon/.style={shape=regular polygon, regular polygon sides={##1},
    inner sep=+0pt, outer sep=+0pt, line join=round, node contents=},
  6-gon/.style={n-gon=6, draw,
    minimum size=2*(\pgfkeysvalueof{/tikz/n-gon side length})},
  4-gon/.style={n-gon=4, draw, anchor=corner 3,
    minimum size=1.41421356*(\pgfkeysvalueof{/tikz/n-gon side length})},
  3-gon/.style={n-gon=3, draw, anchor=corner 2,
    minimum size=1.15470053838*(\pgfkeysvalueof{/tikz/n-gon side length})},
  dots/.style={shape=circle, draw, fill=white, inner sep=+0pt,
    minimum size=(\pgfkeysvalueof{/tikz/n-gon side length})/5},
  hc41/.style 2 args={4-gon,at=(@.corner 2),hc41-##1/.try},
  hc42/.style 2 args={4-gon,at=(@.corner 3),rotate=60,hc42-##2/.try},
  hc43/.style 2 args={4-gon,at=(@.corner 4),rotate=120,hc43-##2/.try},
  hc31/.style 2 args={3-gon,at=(@.corner 2),rotate=90, hc31-##2/.try},
  hc32/.style 2 args={3-gon,at=(@.corner 3),rotate=150,hc32-##2/.try},
  @aac/.style 2 args={append after command={
    node[hc41={##1}{##2}]node[hc42={##1}{##2}]node[hc43={##1}{##2}]
    node[hc31={##1}{##2}]node[hc32={##1}{##2}]\pgfextra{\def\tikzlastnode{@}}}},
  place hexagon/.style 2 args={
    6-gon, name=hc-##1-##2, at={(##1,##2)}, alias=@,
    /utils/exec=\pgfmathint{mod(mod(##1,3)-mod(##2,3)+3,3)},
    fill/.expanded=honeycomb@\pgfmathresult,
    @aac/.expanded={\pgfmathresult}{##1-##2},
    every hexagon node/.try={##1}{##2}, hexagon node ##1-##2/.try},
  x={([shift=(60:\pgfkeysvalueof{/tikz/n-gon side length}),
       shift=(30:\pgfkeysvalueof{/tikz/n-gon side length})]
               0:\pgfkeysvalueof{/tikz/n-gon side length})},
  y={([shift=(120:\pgfkeysvalueof{/tikz/n-gon side length}),
       shift=(90:\pgfkeysvalueof{/tikz/n-gon side length})]
              60:\pgfkeysvalueof{/tikz/n-gon side length})}}}
\newcommand*\tikzplacehexagonsanddots[2]{%
\foreach \x in {#1} \foreach \y in {#2} \node[place hexagon={\x}{\y}]{};
\foreach \x in {#1} \foreach \y in {#2} \foreach \corner in {1,...,6}
  \node[at=(hc-\x-\y.corner \corner),dots]{};}
\begin{document}
\begin{tikzpicture}[
  decorated honeycomb lattice=.5cm,
%  every hexagon node/.style 2 args={label=center:#1/#2},
  every hexagon node/.append style={font=\itshape},
  hexagon node 3-0/.style={node contents=b},
  hexagon node 2-0/.style={node contents=r},
  hexagon node 3--1/.style={node contents=g},
%  hc41/.append style={fill=honeycomb@#1!50},
%  hc42/.append style={fill=honeycomb@#1!50},
%  hc43/.append style={fill=honeycomb@#1!50},
%  hc31/.append style={fill=honeycomb@#1!50},
%  hc32/.append style={fill=honeycomb@#1!50},
]
\clip (-.5,0) rectangle (4,1.25);
\tikzplacehexagonsanddots{0,...,5}{-3,...,3}
\end{tikzpicture}
\end{document}

Recursive paths

This solution uses only paths but places them recursively so that we can place the dots when coming back from the recursion.

Some algorithms are taken from the previous approach.

The squares are disabled in this (see \path[dhl/square/.try] …) but even when enabled, they don't put draw anything, for this the style dhl/square needs to be defined (say to draw). This does not distinguish between the different triangles and squares but that can easily be done by splitting up the paths.

Code

\documentclass[tikz]{standalone}
\makeatletter
\pgfqkeys{/utils}{TeX/ifnum/.code n args={3}{%
  \ifnum#1\relax\expandafter\pgfutil@firstoftwo\else
  \expandafter\pgfutil@secondoftwo\fi{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}}}
\makeatother
\colorlet{honeycomb@0}{blue!50}
\colorlet{honeycomb@1}{green!75!black}
\colorlet{honeycomb@2}{red!75!black}
\tikzset{
  dhl/cs/.style={
    /tikz/x={([shift=(60:#1),shift=(30:#1)]0:#1)},
    /tikz/y={([shift=(120:#1),shift=(90:#1)]60:#1)}},
  dhl/dots/.style={
    shape=circle, draw, fill=white, inner sep=+0pt, minimum size=.1cm},
  dhl/draw hexagon/.code n args={5}{%
    \pgfmathtruncatemacro\hccolor{mod(mod(#1,3)-mod(#3,3)+3,3)}%
    \coordinate (hc-#1-#3) at (xyz cs:/tikz/dhl/cs={#5},x=#1,y=#3);
    \draw[shift=(hc-#1-#3), fill/.expanded=honeycomb@\hccolor, x={#5}, y={#5},
    dhl/hexagon/.try={#1}{#3}, dhl/hexagon-#1-#3/.try](0:#5) --(60:#5)--(120:#5)
      coordinate(@1)--(180:#5)coordinate(@2)--(240:#5)--(300:#5)--cycle;
    \draw[dhl/triangle/.try] (@1) --+(90:#5) --+(150:#5) -- cycle
                             (@2) --+(150:#5)--+(210:#5) -- cycle;
%    \path[dhl/square/.try] (@1)--++(0:#5)--([turn]90:#5)--([turn]90:#5)--cycle
%                         (@1)--++(150:#5)--([turn]90:#5)--([turn]90:#5)--cycle
%                         (@2)--++(210:#5)--([turn]90:#5)--([turn]90:#5)--cycle;
    \tikzset{
      /utils/TeX/ifnum={#1<#2}{% to the right?
        dhl/draw hexagon/.expanded={\the\numexpr#1+1\relax}{#2}{#3}{#4}{#5}},
      /utils/TeX/ifnum={#1=0}{% first row …
        /utils/TeX/ifnum={#3<#4}{% … upwards?
          dhl/draw hexagon/.expanded={#1}{#2}{\the\numexpr#3+1\relax}{#4}{#5}}}}
    \path[shift=(hc-#1-#3)] foreach \ang in {0,60,...,359}{
      node[dhl/dots] at (\ang:#5){}};},
  start hexagon/.style args={#1 and #2 length #3}{
    dhl/draw hexagon={0}{#1}{0}{#2}{#3}}}
\begin{document}
\begin{tikzpicture}[
%  dhl/hexagon/.style 2 args={insert path={node{#1/#2}}},
  dhl/text/.style={font=\itshape},
  dhl/hexagon-2-3/.style={insert path={node[dhl/text]{r}}},
  dhl/hexagon-3-2/.style={insert path={node[dhl/text]{g}}},
  dhl/hexagon-3-3/.style={insert path={node[dhl/text]{b}}}
]
\clip[dhl/cs=.5cm] (-.5,3) rectangle (4,4.25);
\tikzset{start hexagon=6 and 7 length .5cm}
\end{tikzpicture}
\end{document}

Output

enter image description here

6
  • You are right! Drawing just the two triangles is indeed even simpler than three squares. Sep 8 at 18:03
  • I've lied, the dots are still nodes in the second solution. Sep 8 at 21:02
  • But you need to make sure that the tiles are placed in a certain order, right? In this case from right to left and from top to bottom ... Sep 9 at 7:39
  • 1
    @JasperHabicht In both solutions the tiles are placed from left to right and from bottom to top, but in the first solutions the columns are completed before the next row and in the second the columns are completed from right to the left after the first row has been constructed. In the second solution the dots are placed when we're coming back from the recursion, i.e. when the neighbouring tiles have been placed. If we'd be smart we draw those triangles that are in the direction of the drawing loop. Sep 9 at 9:12
  • 1
    When we draw the triangles at angle 0° and 60° we need to draw diagonal-wise (diagonal = where the sum of x and y is equal). With a little calculation and loops via .list we can do this pretty comfortable: 656538.tex This now draws a (possibly at the lower-left corner clipped) triangle shape of tiles instead of a parallelogram shape. Sep 9 at 13:46
6

Using a \pic, I came up with the following:

\documentclass[border=10mm]{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[
    pics/rhombitrihexagonal tiling/.default={r}{g}{b},
    pics/rhombitrihexagonal tiling/.style n args={3}{
        code={
            \foreach \s/\c/\n in {(30:1+2*sin(60))/red/#1, (0:0)/green/#2, (-30:1+2*sin(60))/blue/#3} {
                \begin{scope}[shift={\s}]
                    \draw[fill=\c] (0:1) -- (60:1) -- (120:1) -- (180:1) -- (240:1) -- (300:1) -- cycle;
                    \node at (0,0) {\n};
                    \foreach \i in {2,3} {
                        \begin{scope}[rotate=60*\i, shift={(0:1)}]
                            \draw (0:0) -- (30:1) -- (-30:1) -- cycle;
                        \end{scope}
                    }
                \end{scope}
            }
        }
    }]
  
    \foreach \y in {0,...,3} {
        \foreach \x in {0,...,3} {
            \path ({(0.5*mod(\y,2)+\x)*(3+2*sin(60))},{\y*(1.5+3*sin(60))}) pic {rhombitrihexagonal tiling};
        }
    }

\end{tikzpicture}
\end{document}

enter image description here


With the small circles added and the possibility to set custom colors:

\documentclass[border=10mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{backgrounds}

\colorlet{rhombitrihexagonal tiling color one}{red}
\colorlet{rhombitrihexagonal tiling color two}{green}
\colorlet{rhombitrihexagonal tiling color three}{blue}

\begin{document}
\begin{tikzpicture}[
    pics/rhombitrihexagonal tiling/.default={r}{g}{b},
    pics/rhombitrihexagonal tiling/.style n args={3}{
        code={
            \foreach \s/\c/\n in {
                (30:1+2*sin(60))/rhombitrihexagonal tiling color one/#1,
                (0:0)/rhombitrihexagonal tiling color two/#2,
                (-30:1+2*sin(60))/rhombitrihexagonal tiling color three/#3
            } {
                \begin{scope}[shift={\s}]
                    \begin{pgfonlayer}{background}
                        \draw[fill=\c] (0:1) -- (60:1) -- (120:1) -- (180:1) -- (240:1) -- (300:1) -- cycle;
                        \node at (0,0) {\n};
                        \foreach \i in {2,3} {
                            \begin{scope}[rotate=60*\i, shift={(0:1)}]
                                \draw (0:0) -- (30:1) -- (-30:1) -- cycle;
                            \end{scope}
                        }
                    \end{pgfonlayer}
                    \foreach \i in {0,...,5} {
                        \draw[fill=white] ({60*\i}:1) circle[radius=2pt];
                    }
                \end{scope}
            }
        }
    }]
  
    \foreach \y in {0,...,3} {
        \foreach \x in {0,...,3} {
            \path ({(0.5*mod(\y,2)+\x)*(3+2*sin(60))},{\y*(1.5+3*sin(60))}) pic {rhombitrihexagonal tiling};
        }
    }

\end{tikzpicture}
\end{document}

enter image description here

The use of the backgrounds library is needed in this example, because otherwise the small circles won't be always in the foreground. However, this will result in problems with clipping, because things on background layers won't be clipped due to scoping.

Therefore, I changed the code a bit to make the use of the backgrounds library unnecessary. In this solution it is important, however, that the tiles are added from left to right and from bottom to top, in order to make the small circles always overlap the previous tiles:

\documentclass[border=10mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{backgrounds}

\colorlet{rhombitrihexagonal tiling color one}{red}
\colorlet{rhombitrihexagonal tiling color two}{green}
\colorlet{rhombitrihexagonal tiling color three}{blue}

\begin{document}
\begin{tikzpicture}[
    pics/rhombitrihexagonal tiling/.default={r}{g}{b},
    pics/rhombitrihexagonal tiling/.style n args={3}{
        code={
            \foreach \s/\c/\n [count=\k] in {
                (0:0)/rhombitrihexagonal tiling color two/#2,
                (-30:1+2*sin(60))/rhombitrihexagonal tiling color three/#3,
                (30:1+2*sin(60))/rhombitrihexagonal tiling color one/#1
            } {
                \begin{scope}[shift={\s}]
                    \draw[fill=\c] (0:1) -- (60:1) -- (120:1) -- (180:1) -- (240:1) -- (300:1) -- cycle;
                    \node at (0,0) {\n};
                    \foreach \i in {4,5} {
                        \begin{scope}[rotate=60*\i, shift={(0:1)}]
                            \draw (0:0) -- (30:1) -- (-30:1) -- cycle;
                            \draw[fill=white] (0:0) circle[radius=2pt];
                            \draw[fill=white] (-30:1) circle[radius=2pt];
                            \ifnum\i=5
                                \ifnum\k=2
                                    \draw[fill=white] (30:1) circle[radius=2pt];
                                \fi
                            \else
                                \draw[fill=white] (30:1) circle[radius=2pt];
                            \fi
                        \end{scope}
                    }
                    \ifnum\k=3\else
                        \draw[fill=white] (180:1) circle[radius=2pt];
                    \fi
                \end{scope}
            }
        }
    }]
    
    \clip[draw] (4,2) rectangle (15,10);
  
    \foreach \y in {0,...,3} {
        \foreach \x in {0,...,3} {
            \path ({(0.5*mod(\y,2)+\x)*(3+2*sin(60))},{\y*(1.5+3*sin(60))}) pic {rhombitrihexagonal tiling};
        }
    }
    
\end{tikzpicture}
\end{document}

enter image description here

The single tile looks like this:

enter image description here

3
  • Thanks. One simple question. If I use $\clip(4,2) rectangle (15,10)$ before your for loop to cut out a rectangular figure, I lose some of the small white circles that you drew. How should that be corrected?
    – user25957
    Sep 9 at 0:58
  • @user25957 Interesting! I am unsure why that is. I'll look into it. It seems that the stuff on the background layer is not clipped. Sep 9 at 5:53
  • 1
    @user25957 Thanks for pointing out this problem! The reason is that clipping does not work with background layers which I used to make sure that the small circles are always on top of everything else. I added an alternative solution that does not use backgrounds, but which requires to place the tiles in a certain order (namely from left to right and from below to bottom to top. It was a bit tricky to get the order of the small circles right ... I think I got it now. Sep 9 at 7:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.