6

Following this great question, I have been drawing a picture that simulates hand drawing. I want to fill some solids with a simple hatch pattern, however I don't know how to apply the path decorator to the lines that compose the pattern. Here is my MWE:

enter image description here

\documentclass[border=2mm]{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing, patterns}

\begin{document}
\begin{tikzpicture}[
        solid/.style={draw=black,thick,pattern=north west lines, pattern color=black, decorate}
    ]

    \begin{scope}[decoration={random steps,segment length=3pt,amplitude=0.45pt}, decorate]
        \draw[solid] (0,0) rectangle +(2,2);
    \end{scope}
\end{tikzpicture}
\end{document}

I tried to use the following example from the manual as a starting point but I am not sure how to apply the decorations at the "pgf level":

\documentclass[border=2mm]{standalone}

\usepackage{tikz}
\usetikzlibrary{patterns.meta}
\pgfdeclarepattern{%
name=hatch,
parameters={\hatchsize,\hatchangle,\hatchlinewidth},
bottom left={\pgfpoint{-.1pt}{-.1pt}},
top right={\pgfpoint{\hatchsize+.1pt}{\hatchsize+.1pt}},
tile size={\pgfpoint{\hatchsize}{\hatchsize}},
tile transformation={\pgftransformrotate{\hatchangle}},
code={
\pgfsetlinewidth{\hatchlinewidth}
\pgfpathmoveto{\pgfpoint{-.1pt}{-.1pt}}
\pgfpathlineto{\pgfpoint{\hatchsize+.1pt}{\hatchsize+.1pt}}
\pgfpathmoveto{\pgfpoint{-.1pt}{\hatchsize+.1pt}}
\pgfpathlineto{\pgfpoint{\hatchsize+.1pt}{-.1pt}}
\pgfusepath{stroke}
}
}

\tikzset{
hatch size/.store in=\hatchsize,
hatch angle/.store in=\hatchangle,
hatch line width/.store in=\hatchlinewidth,
hatch size=5pt,
hatch angle=0pt,
hatch line width=.5pt,
}

\begin{document}
\begin{tikzpicture}
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=red]
(\r*3,0) rectangle ++(2,2);
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=green, hatch size=2pt]
(\r*3,3) rectangle ++(2,2);
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=blue, hatch size=10pt, hatch angle=21]
(\r*3,6) rectangle ++(2,2);
\foreach \r in {1,...,4}
\draw [pattern=hatch, pattern color=orange, hatch line width=2pt]
(\r*3,9) rectangle ++(2,2);
\end{tikzpicture}

\end{document}
  • It will compile if you (a) use \pgfdeclarepattern{name=hatch, i.e. no empty line, and (b) add \begin{document}. – Schrödinger's cat Nov 19 '19 at 4:16
  • Thanks, I fixed that. – jsb Nov 19 '19 at 4:20
  • You're welcome! Just to make sure I understand the question. You want the diagonal lines to have random steps, right? – Schrödinger's cat Nov 19 '19 at 4:32
  • Correct, so that they would look "hand drawn" and hence in harmony with other lines in the picture. – jsb Nov 19 '19 at 4:35
10

This answer has a really important input by the OP, jsb, who pointed out that what I did with the clipping was insanely complicated. Thanks a lot!

This is a first, faster version:

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{decorations.pathmorphing,patterns.meta}
\pgfdeclarepattern{name=lines,
parameters={\hatchsize,\hatchangle,\hatchlinewidth,\hatchsegmentlength,\hatchamplitude},
bottom left={\pgfpoint{-.1pt}{-.1pt}},
top right={\pgfpoint{\hatchsize+.1pt}{\hatchsize+.1pt}},
tile size={\pgfpoint{\hatchsize}{\hatchsize}},
tile transformation={\pgftransformrotate{\hatchangle}},
code={\pgfsetlinewidth{\hatchlinewidth}
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,0.5*\hatchsize) -- (\hatchsize+.1pt,0.5*\hatchsize);
}
}

\tikzset{
hatch size/.store in=\hatchsize,
hatch angle/.store in=\hatchangle,
hatch line width/.store in=\hatchlinewidth,
hatch size=5pt,
hatch angle=0pt,
hatch line width=.5pt,
hatch segment length/.store in=\hatchsegmentlength,
hatch segment length=3pt,
hatch amplitude/.store in=\hatchamplitude,
hatch amplitude=1pt
}
\begin{document}
\begin{tikzpicture}
 \begin{scope}[thick,
    decoration={random steps,segment length=3pt,amplitude=0.45pt}]
    \draw[decorate,pattern=lines, pattern color=black, hatch size=7pt, hatch angle=21,
     hatch line width=0.9pt] (0,0) rectangle +(2,2);
    \draw[decorate,pattern=lines, pattern color=black, hatch size=12pt, hatch angle=70,
     hatch line width=0.9pt,hatch amplitude=1.4pt,hatch segment length=4pt] (3,0) rectangle +(2,2);
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Note also that these are patterns, so they are fast by repeating things precisely. This means that the pattern does not look as random as it could, one can clearly see the repetition. One way to address this issue is to create a slower pattern that has several (10, say) of these lines.

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{decorations.pathmorphing,patterns.meta}
\pgfdeclarepattern{name=lines,
parameters={\hatchsize,\hatchangle,\hatchlinewidth,\hatchsegmentlength,\hatchamplitude},
bottom left={\pgfpoint{-.1pt}{-.1pt}},
top right={\pgfpoint{10*\hatchsize+.1pt}{10*\hatchsize+.1pt}},
tile size={\pgfpoint{10*\hatchsize}{10*\hatchsize}},
tile transformation={\pgftransformrotate{\hatchangle}},
code={\pgfsetlinewidth{\hatchlinewidth}
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,0.5*\hatchsize) -- (10*\hatchsize+.1pt,0.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,1.5*\hatchsize) -- (10*\hatchsize+.1pt,1.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,2.5*\hatchsize) -- (10*\hatchsize+.1pt,2.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,3.5*\hatchsize) -- (10*\hatchsize+.1pt,3.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,4.5*\hatchsize) -- (10*\hatchsize+.1pt,4.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,5.5*\hatchsize) -- (10*\hatchsize+.1pt,5.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,6.5*\hatchsize) -- (10*\hatchsize+.1pt,6.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,7.5*\hatchsize) -- (10*\hatchsize+.1pt,7.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,8.5*\hatchsize) -- (10*\hatchsize+.1pt,8.5*\hatchsize);
\draw[decoration={random steps,segment length=\hatchsegmentlength,
    amplitude=\hatchamplitude}, decorate,rounded corners=1pt]
 (-.1pt,9.5*\hatchsize) -- (10*\hatchsize+.1pt,9.5*\hatchsize);
}
}

\tikzset{
hatch size/.store in=\hatchsize,
hatch angle/.store in=\hatchangle,
hatch line width/.store in=\hatchlinewidth,
hatch size=5pt,
hatch angle=0pt,
hatch line width=.5pt,
hatch segment length/.store in=\hatchsegmentlength,
hatch segment length=3pt,
hatch amplitude/.store in=\hatchamplitude,
hatch amplitude=1pt
}
\begin{document}
\begin{tikzpicture}
 \begin{scope}[thick,
    decoration={random steps,segment length=3pt,amplitude=0.45pt}]
    \draw[decorate,pattern=lines, pattern color=black, hatch size=7pt, hatch angle=21,
     hatch line width=0.9pt] (0,0) rectangle +(2,2);
    %
    \draw[decorate,pattern=lines, pattern color=black, hatch size=12pt, hatch angle=70,
     hatch line width=0.9pt,hatch amplitude=1.4pt,hatch segment length=4pt] 
     (3,0) rectangle +(2,2);
 \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

The result looks definitely more random but takes longer to compile. I repeated the path by hand since I had once a bad experience when using \foreach in a meta pattern declaration. However, it seems to work fine in most cases. If I ever remember the case that went bad I will add it here. I believe to remember it was in connection with either this post or this post.

  • 1
    Wonderful! I do not understand why you are using \clip, I drew a wedge with: \draw[decorate, pattern=lines, pattern color=black, hatch size=7pt, hatch angle=21, hatch line width=0.9pt] (0,0) -- (3,0) arc (0:30:3) -- cycle; and it looks perfect. I did not have to set the random seed either. – jsb Nov 19 '19 at 19:30
  • @jsb That is a very good point! I just did not think about it. But you are right, this should work. I was being stupid. Thanks a lot! – Schrödinger's cat Nov 19 '19 at 19:33
  • Thank you. Also, I have been playing around with \foreach, do you think you might have run into some bug using it in the past? Did you try it in this case? – jsb Nov 19 '19 at 19:39
  • @jsb Now I regret that I did not keep the example. It is true that it usually works. I just think to have had one use case in which it didn't. And it was not something as stupid as calling the loop variable the same as something that is used elsewhere. but it could definitely be an unfortunate naming of the loop variable, or some expansion issue. But as of now I do not remember the details. – Schrödinger's cat Nov 19 '19 at 19:43
  • @jsb At this point I only believe to remember it was in connection with tex.stackexchange.com/a/510132/194703 or tex.stackexchange.com/a/513715/194703, but I do not remember the details. – Schrödinger's cat Nov 19 '19 at 19:48

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.