2

I've got a tile that I need to rotate or to symmetrize a certain amount of times to make a pattern. I defined the pic itself and made the pattern manually.

tile pattern

I failed to automatize the process.

Is there a clever and shorter way to make this? A very nice answer would be one that lets me just use maybe a matrix where four letters could be used to say A: the initial tile, B: the symmetric, C: the rotated one, D: the symmetric rotated one.

I hope I'm clear enough.

\documentclass[tikz,border=3.14mm]{standalone}

\tikzset{
    tile/.pic={
        \draw (0,0) --++ (0.8*\lmot,0) --++ (0,0.2*\lmot) --++ (-0.3*\lmot,0) --++ (0,0.6*\lmot) --++ (-0.3*\lmot,0) --++ (0,0.2*\lmot) --++ (-0.2*\lmot,0) -- cycle;%  
        },
    num/.style={line width=.5pt,circle,draw,inner sep=0pt,minimum size=11pt,font=\footnotesize}
        }
        
\newcommand{\num}[1]{\raisebox{-2.5pt}{\tikz \node[num]{#1};}}

\newcommand{\lmot}{2} % Tile size

\begin{document}
    \begin{sffamily}
    \begin{tikzpicture}
        \path pic {tile} pic [xscale=-1] {tile} --++ (\lmot,\lmot) pic[rotate=180] {tile} pic[rotate=180,xscale=-1] {tile} --++ (\lmot,-\lmot) pic {tile} pic [xscale=-1] {tile};
        \begin{scope}[yshift=-\lmot cm, xshift=-\lmot cm]
            \path  pic {tile} --++ (\lmot,\lmot) pic[rotate=180] {tile} pic[rotate=180,xscale=-1] {tile} --++ (\lmot,-\lmot) pic {tile} pic [xscale=-1]  {tile} --++ (\lmot,\lmot) pic[rotate=180] {tile} pic[rotate=180,xscale=-1] {tile};
        \end{scope}

        \begin{scope}[yshift=-\lmot cm, xshift=-\lmot cm]
            \path  pic[rotate=180,xscale=-1] {tile} --++ (\lmot,-\lmot) pic {tile} pic [xscale=-1]  {tile} --++ (\lmot,\lmot) pic[rotate=180] {tile} pic[rotate=180,xscale=-1] {tile} --++ (\lmot,-\lmot) pic {tile} pic [xscale=-1]  {tile} --++ (\lmot,\lmot);
        \end{scope}
        
        \foreach \i in {1,2,...,6}
            {
            \pgfmathsetmacro{\j}{\i*0.5*\lmot-0.75*\lmot}
            \node at (\j,0.5*\lmot) {\num{\i}};
            }
        
        \foreach \i in {7,...,13}
            {
            \pgfmathsetmacro{\j}{(\i-8)*0.5*\lmot-0.25*\lmot}
            \node at (\j,-0.5*\lmot) {\num{\i}};
            }

        \foreach \i in {14,...,20}
            {
            \pgfmathsetmacro{\j}{(\i-15)*0.5*\lmot-0.25*\lmot}
            \node at (\j,-1.5*\lmot) {\num{\i}};
            }
            
        \begin{scope}[font=\small]

        \node[above left] at (-\lmot,0) {A};
        \node[above left] at (0,0) {B};
        \node[below left] at (\lmot,\lmot) {C};
        \node[above left] at (\lmot,0) {D};
        \node[above left] at (2*\lmot,0) {E};
        \node[above left] at (-\lmot,-\lmot) {F};
        \node[above left] at (\lmot,-\lmot) {G};
        
        \end{scope}

    \end{tikzpicture}
    \end{sffamily}
\end{document}
4
  • 3
    What kind of automation are you missing? You're already using loops and transformations to use one pic in four variants at different positions. What would be your preferred input syntax? We could define it as a shape with a the main compass anchors which might make it easier to stack these boxes a bit more automatically. We could anchors to a pic, in a way but they can't be used to place a pic. You could also put a node inside that pic and use that for placement. Your pic is well defined enough for that. Oct 4 at 14:34
  • Maybe the [tilings library](ctan.org/pkg/tilings) is of help. Oct 4 at 16:37
  • It's a shame there aren't coffins in TikZ (or drawing for coffins) as they'd be perfect for this. (If you're not familiar with coffins, texdoc xcoffins.)
    – cfr
    Oct 4 at 16:37
  • My answer uses only scales, no rotation because rotate = 180, xscale = -1 is the same as yscale=-1. And just rotate=180 is the same as scale = -1. Oct 4 at 22:47

2 Answers 2

3

This is for me the best approach to getting a proper tile: Use a node.

Here I'm hijacking a rectangle node with by altering its background path. (It's called that way because it is behind the here missing node text.)

Granted, this is not a top-level interface but with using \tikzinsertpath we can almost use a TikZ path without much adjustment.

We'd need to adjust how TikZ parses a coordinate to use the anchors of the node with the usual (.south west) syntax but by setting both minimum width and minimum height as well as setting x and y to the appropriate settings we can basically use a coordinate system that follows the node's dimensions.


In the example below, I'm actually using a matrix with four macros defining the various options with a weird column sep every odd row that helps push the tiles together. (We could use some form of overlay inside the cells so that the matrix will ignore that “foot” of the tile but that has other side effects.)

Since it's a node now its anchors can be accessed while placing it and later, it can be used with the positioning and the chains library.

Sure, it's not a good idea to try to connect lines to it but that's not worse than with a pic.

Instead of letter we can use the digits 0, 1, 2 and 3 to define the variations of tile … and then we can use the mod(\i, 4) function to select the right variation based on a incremental counter \i (say in a \foreach loop which places nodes on a chain …).

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{chains}
\makeatletter
\tikzset{
  replace bg path/.code=\tikz@addoption
    {\pgfutil@namedef{pgf@sh@bg@\tikz@shape}{#1}},
  @create tile/.code=\pgfutil@namedef{tile#1}{\node[every tile, tile #1]{};},
  @create tile/.list={A, B, C, D}} % for the matrix solution
\makeatother
\newcommand*\tikzinsertpath[1]{\pgfkeysvalueof{/tikz/insert path/.@cmd}#1\pgfeov}
\tikzset{
  replace bg path tikz/.style={replace bg path=\tikzinsertpath{#1}},
  tile/.style 2 args={
    shape=rectangle, draw, inner sep=+0pt, outer sep=+0pt,
    minimum  width=.5*(\pgfkeysvalueof{/tikz/tile size}),
    minimum height=    \pgfkeysvalueof{/tikz/tile size},
    replace bg path tikz={[x={#1*(\pgfkeysvalueof{/tikz/tile size})},
                           y={#2*(\pgfkeysvalueof{/tikz/tile size})}]
      (-.25,-.5) -| ++( .8, .2) -| ++ (-.30, .6) -| ++(-.3, .2) -| cycle}},
  tile A/.style={tile={ 1}{ 1}}, tile B/.style={tile={-1}{ 1}},
  tile C/.style={tile={ 1}{-1}}, tile D/.style={tile={-1}{-1}},
  tile size/.initial=2cm}
\newcounter{steppy} % for the matrix solution
\tikzset{
  every label/.append style={
    shape=circle, draw, thin, inner sep=+.1em, label position=center,
    text width=width("00"), align=center, font=\sffamily\footnotesize}}
\begin{document}
\tikz[
  thick, inner sep=+0pt, outer sep=+0pt,
  every odd column/.style={
    column sep=-.6*(\pgfkeysvalueof{/tikz/tile size})-\pgflinewidth},
  row sep=-\pgflinewidth, column sep=-\pgflinewidth,
  every tile/.append style={label=\stepcounter{steppy}\thesteppy}]
\matrix{
         & \tileB & \tileA & \tileD & \tileC & \tileB & \tileA \\
  \tileA & \tileD & \tileC & \tileB & \tileA & \tileD & \tileC \\
  \tileC & \tileB & \tileA & \tileD & \tileC & \tileB & \tileA \\
};
\tikz[
  node distance=+0pt, thick,
  tile styles/.style n args={4}{
    tile #1/.style=tile A, tile #2/.style=tile B,
    tile #3/.style=tile C, tile #4/.style=tile D}]
\foreach[count=\row from 0] \mir/\List/\extraStyle in {
  2103/{ 1, ..., 6}/,
  3210/{ 7, ..., 13}/below left=of Tile 1,
  0321/{14, ..., 20}/below=of Tile 7%
} \path[tile styles/.expanded=\mir, start chain={row\row} going right]
  node foreach{[evaluate={\style=int(mod(\i,4));}]\i}in \List
    [style/.expand once=\extraStyle, tile \style,
     on chain=row\row, label=\i] (Tile \i) {};
\end{document}

Output

enter image description here

2
  • The order of the tiles is always DCBA or 3210 just with different phases. Oct 4 at 22:57
  • Thanks a lot, Qrrbrbirlbel. I imagined something lighter but couldn't achieve it. Your solution is pretty and clever as always. I'll dig into it. The matrix solution is pretty much what I was looking for.
    – SebGlav
    Oct 5 at 7:25
3

Here is an effort in Metapost.

enter image description here

This is wrapped up in luamplib so you need to compile it with lualatex:

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
path shape;
shape = (1,0) -- (6,0) -- (6,6) -- (5,6) -- (5,5) -- (3,5) -- (3,1) -- (1,1) -- cycle;
numeric u; u = 13;
shape := shape scaled u;
beginfig(1);

  for i=1 upto 20:

    fill shape withcolor 7/8[if odd i: blue else: red fi, white];
    draw shape; 
    pair c; c = 1/2[point 3/2 of shape, point 11/2 of shape];
    unfill fullcircle scaled 15 shifted c;
    draw fullcircle scaled 15 shifted c; 
    label(decimal i, c);

    if i mod 7 = 6:
      shape := shape shifted ((3,1) * -6u);
    elseif xpart (point 1 of shape - point 0 of shape) > 0:
      shape := shape reflectedabout(point 1 of shape, point 2 of shape);
    else:
      shape := shape rotatedabout(point 5.5 of shape, 180);
    fi

  endfor
endfig;
\end{mplibcode}
\end{document}

The only clever bit is the if/elseif/else/fi block that applies the appropriate transform to the shape.

1
  • 1
    Thanks a lot for the effort. I don't use metapost as a regular language but it's worth a try.
    – SebGlav
    Oct 5 at 7:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .