[Tex/LaTex] Correcting TikZ pattern offsets

patternpositioningtikz-pgf

I have some automatic placed nodes which should be filled with a pattern. However, I noticed that the pattern offset depends on the node position, which makes the nodes looks different.

Minimal example:

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{patterns}

\begin{document}
\begin{tikzpicture}
\foreach \n in {0,1,...,5}
{
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,pattern=north west lines] at (1.1*\n cm, 0) {};
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,pattern=dots] at (1.1*\n cm, 1.1) {};
}
\end{tikzpicture}
\end{document}

How can I achieve that the patterns are drawn identical for every node? I think I have to adjust some pattern origin for that.

Best Answer

The patterns.meta library has keys that allow one to shift patterns. This works for the Dots pattern. For the Lines pattern the order of transformations in the library is IMHO inconvenient. So I added a version MovableLines, which can be moved in an arguably more intuitive way.1

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{patterns.meta}

\pgfdeclarepattern{
  name=MovableLines,
  parameters={
      \pgfkeysvalueof{/pgf/pattern keys/distance},
      \pgfkeysvalueof{/pgf/pattern keys/angle},
      \pgfkeysvalueof{/pgf/pattern keys/xshift},
      \pgfkeysvalueof{/pgf/pattern keys/yshift},
      \pgfkeysvalueof{/pgf/pattern keys/line width},
  },
  bottom left={%
    \pgfpoint
      {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}%
      {-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}},
  top right={%
    \pgfpoint
      {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}%
      {.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}},
  tile size={%
    \pgfpoint
      {\pgfkeysvalueof{/pgf/pattern keys/distance}}%
      {\pgfkeysvalueof{/pgf/pattern keys/distance}}},
  tile transformation={%
    \pgftransformshift{%
      \pgfpoint
        {\pgfkeysvalueof{/pgf/pattern keys/xshift}}%
        {\pgfkeysvalueof{/pgf/pattern keys/yshift}}}%
    \pgftransformrotate{\pgfkeysvalueof{/pgf/pattern keys/angle}}},
  defaults={
    distance/.initial=3pt,
    angle/.initial=0,
    xshift/.initial=0pt,
    yshift/.initial=0pt,
    line width/.initial=\the\pgflinewidth,
  },
  code={%
    \pgfsetlinewidth{\pgfkeysvalueof{/pgf/pattern keys/line width}}%
    \pgfpathmoveto{\pgfpoint{-.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}%
    \pgfpathlineto{\pgfpoint{.5*(\pgfkeysvalueof{/pgf/pattern keys/distance})}{0pt}}%
    \pgfusepath{stroke}%
  },
}


\begin{document}
\begin{tikzpicture}
\foreach \n in {0,1,...,5}
{
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
    pattern={MovableLines[angle=-45,distance={sqrt(0.5)*3pt},
       line width=0.4pt]}] at (1.1*\n cm, 0) {};
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
     pattern=Dots] at (1.1*\n cm, 1.1) {};   
}
\end{tikzpicture}

\begin{tikzpicture}
\foreach \n in {0,1,...,5}
{
    \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
    pattern={MovableLines[xshift={1.1*\n cm},angle=-45,distance={sqrt(0.5)*3pt},
       line width=0.4pt]}] at (1.1*\n cm, 0) {};
     \node [rectangle,draw,minimum width=1cm,minimum height=1cm,
     pattern={Dots[xshift={1.1*\n cm}]}] at (1.1*\n cm, 1.1) {};   
}
\end{tikzpicture}

\end{document}

enter image description here

In the upper panel, no shift is applied, and the rectangles look different. In the lower panel we shift according to the horizontal position of the nodes, and the rectangles look the same.

One can also make the pattern transformation part of the definition of the nodes, but this requires some extra work.

Finally, let me mention that patterns are tricky (OK, we know that;-): if you convert the resulting pdf to another format, the patterns may get shifted around.

1One can definitely transform the original lines, too, one just has to backwards engineer the shift. See here for the transformation and the feature request to change the order or add a version that can be shifted in a more intuitive way.