5

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

1 Answer 1

9

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.

5
  • 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, 2019 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!
    – user194703
    Nov 19, 2019 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, 2019 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.
    – user194703
    Nov 19, 2019 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.
    – user194703
    Nov 19, 2019 at 19:48

You must log in to answer this question.

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