15

Using north east hatch from the answer to this question Filling rectangle in TikZ with more than one color I wanted to make a north west hatch. However, it has funny teeth I do not know how to get rid of. What is wrong and how can I correct that?

enter image description here

MWE:

\documentclass{minimal}

\usepackage{tikz}

\begin{document}

\begin{tikzpicture}


\usetikzlibrary{patterns}

\makeatletter
\tikzset{hatch distance/.store in=\hatchdistance,hatch distance=5pt,hatch thickness/.store in=\hatchthickness,hatch thickness=5pt}

\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north east hatch}% name
    {\pgfqpoint{-1pt}{-1pt}}% below left
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}% above right
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north west hatch}% name
    {\pgfqpoint{-1pt}{-1pt}}% below left
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}% above right
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{\hatchdistance}{0pt}}
        \pgfpathlineto{\pgfqpoint{0pt}{\hatchdistance}}
        \pgfusepath{stroke}
    }
\makeatother

\draw[pattern=north east hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange] (0,0) rectangle +(1,1);
\draw[pattern=north west hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange] (2,0) rectangle +(1,1);


\end{tikzpicture}
\end{document}
AndréC
  • 24,137
Pygmalion
  • 6,387
  • 4
  • 34
  • 68
  • This is just to let you know that I really liked this question of yours, and would like to ask you not to get discouraged by comments of certain users. (BTW, this question has an arguably simpler answer since now the patterns.meta library is available.) –  Mar 07 '20 at 21:49

3 Answers3

15

By enlarging the bounding box sufficiently, the problem is solved.

According to my calculations, it must be enlarged by at least 71%.

screenshot

To simplify, I expanded it by an integer multiple of \hatchdistance.

{\pgfqpoint{-\hatchdistance}{-\hatchdistance}}% below left
{\pgfqpoint{2\hatchdistance}{2\hatchdistance}}% above right

hatch not really straight

screenshot

The hatches are not perfectly straight (like the default ones in the patterns library) but they remain unchanged by scaling as shown in the above result.

Straight hatch

To do this, I enlarged the line that traces the hatching of an integer multiple \hatchdistance (noninteger multiples pose problems that I have not yet understood).

\pgfpathmoveto{\pgfqpoint{2\hatchdistance}{-\hatchdistance}}
\pgfpathlineto{\pgfqpoint{-\hatchdistance}{2\hatchdistance}}

screenshot

Code for really straight hatch:

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

\begin{document}

\begin{tikzpicture}
\usetikzlibrary{patterns}

\makeatletter
\tikzset{hatch distance/.store in=\hatchdistance,hatch distance=5pt,hatch thickness/.store in=\hatchthickness,hatch thickness=5pt}

\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north east hatch}% name
    {\pgfqpoint{-1pt}{-1pt}}% below left
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}% above right
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north west hatch}% name
    {\pgfqpoint{-\hatchdistance}{-\hatchdistance}}% below left
    {\pgfqpoint{2\hatchdistance}{2\hatchdistance}}% above right
    {\pgfpoint{\hatchdistance}{\hatchdistance}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{2\hatchdistance}{-\hatchdistance}}
        \pgfpathlineto{\pgfqpoint{-\hatchdistance}{2\hatchdistance}}
        \pgfusepath{stroke}
    }
\makeatother


\draw[pattern=north east hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange] (0,0) rectangle +(1,1);
\draw[pattern=north west hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange,scale=2] (.6,0) rectangle +(1,1);

\end{tikzpicture}
\end{document}

Code for hatch that are not really straight:

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

\begin{document}

\begin{tikzpicture}
\usetikzlibrary{patterns}

\makeatletter
\tikzset{hatch distance/.store in=\hatchdistance,hatch distance=5pt,hatch thickness/.store in=\hatchthickness,hatch thickness=5pt}

\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north east hatch}% name
    {\pgfqpoint{-1pt}{-1pt}}% below left
    {\pgfqpoint{\hatchdistance}{\hatchdistance}}% above right
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        \pgfpathlineto{\pgfqpoint{\hatchdistance}{\hatchdistance}}
        \pgfusepath{stroke}
    }
\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north west hatch}% name
    {\pgfqpoint{-\hatchdistance}{-\hatchdistance}}% below left
    {\pgfqpoint{2\hatchdistance}{2\hatchdistance}}% above right
    {\pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{\hatchdistance}{0pt}}
        \pgfpathlineto{\pgfqpoint{0pt}{\hatchdistance}}
        \pgfusepath{stroke}
    }
\makeatother

\draw[pattern=north east hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange] (0,0) rectangle +(1,1);
\draw[pattern=north west hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange,scale=2] (1,0) rectangle +(1,1);

\end{tikzpicture}
\end{document}
AndréC
  • 24,137
  • Not at all, your first answer adds dimensions with the macro \pgfqpoint. This is prohibited see the manual. – AndréC Jul 03 '19 at 08:12
  • @AndréC I am trying to see the statement that you have mentioned, since I am unfamiliar with \pgfqpoint, could you tell me where in the manual it is mentioned that the using dimensions with macro \pgfqpoint is not allowed/prohibited? – Raaja_is_at_topanswers.xyz Jul 03 '19 at 08:42
  • @Raaja see page 1205 of 3.1.3 manual. I quote: This command does the same as \pgfpoint, but x and y must be simple dimensions like 1pt or 1cm. Things like 2ex or 2cm+1pt are not allowed. – AndréC Jul 03 '19 at 08:52
  • @AndréC Thanks for pointing me to the location. Correct me if I am wrong, doesn't it tries to say not to mix-up different units? I think using same units should not be a problem per se. Because as I see in the previous answer: \tikzset{hatch distance/.store in=\hatchdistance,hatch distance=5pt,hatch thickness/.store in=\hatchthickness,hatch thickness=5pt} both are in the same unit. So, I think it is correct. – Raaja_is_at_topanswers.xyz Jul 03 '19 at 09:22
  • ???? It is you who uses \pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}. Again, you write "By enlarging the bounding box sufficiently, the problem is solved.", which is incorrect, and also not what you are doing. Please stay with the facts and do not make incorrect statements about my answer, which explains things, and which you essentially copy. –  Jul 03 '19 at 12:24
  • @marmot \pgfpoint{\hatchdistance-1pt}{\hatchdistance-1pt}{\hatchdistance-1pt} does not define the bounding box, it defines the size of the tile. The bounding box is defined by the first two parameters. While this code is the third parameter of the function \pgfdeclarepatternformonly Read page 1147 of manual 3.1.3. – AndréC Jul 03 '19 at 14:03
  • @marmot I didn't change the size of the tile, it's the same as the one given in his question by Pygmalion. I only changed the size of the bounding box. In your first answer, you did not change the size of the bounding box, you changed the code (the last parameter). – AndréC Jul 03 '19 at 14:37
  • The only thing which is important is the relation between the path and the tile size, and it is crucial that there is some overshoot, i.e. the path has to go beyond the boundaries of the tile, as I wrote. –  Jul 03 '19 at 14:40
  • @marmot The path that Pygmalion traces in the code (last parameter) is the northwest diagonal of the square. Its pencil line due to its thickness extends beyond the boundaries of this square. In my first solution, I just modified the dimensions of the bounding box and it worked perfectly. Scaling can be done without distorting the hatching, which is not the case with your first solution. That this doesn't make sense to you is another matter. – AndréC Jul 03 '19 at 15:10
  • @Raaja The dimensions referred to in Tikz manual 3.1.3 are those defined in chapter 10 of the tex Book (page 57). These are pt, pc, in, bp, cm, mm, dd, cc and sp. On page 154, the TeX Book specifies that the ex unit depends on the character font. Thus, I interpret this passage as not allowing calculations. Despite this, we see that \pgfqpoint has made a sum of two values. So? What is allowed or prohibited? Was this calculation done correctly and without error? – AndréC Jul 03 '19 at 16:07
  • @Raaja (continued) ... We can ask ourselves the question since on page 1203 of the TikZ manual 3.1.3 there is a calculation problem with the registers. As for me, I only interpret strictly what is written in the manual because I don't yet master TeX enough to answer it. This is an interesting question, you should ask it so that TeX specialists can answer it. – AndréC Jul 03 '19 at 16:09
  • @AndréC I read the content today, and I don't expect a problem due to the calculation performed in the previous answer. Moreover, the units are the same (during the mathematical operations). Disclaimer: I am not a TikZ expert ;-). Nevertheless, if I ask to myself whether I can do such a compuation, why not? I don't see a problem using that and too with the answer as well. – Raaja_is_at_topanswers.xyz Jul 04 '19 at 06:31
  • @Raaja If you look at the source code of pgf, you will see that no addition is ever made in a \pgfqpoint command. On the other hand, there are some with \pgfpoint. See for example in the /tex/generic/pgf/libraries/shapes/ folder line 290 of the pgflibraryshapes.misc.code.tex file. In my opinion, this is no coincidence. – AndréC Jul 04 '19 at 12:27
  • @marmot and @AndréC: I can accept only one of your answers, but I don't know which, because I don't understand exactly the nature of your disagreement. Could you direct me to the resource where \pgfdeclarepatternformonly and its parameters are explained? AndréC could you explain why only north west has to be adapted and north east not? – Pygmalion Jul 12 '19 at 07:39
  • @Pygmalion This command is explained on page 1147 and following of the TikZ 3.13 manual. The problem comes from the fact that this command defines the bounding box by the vertices of the north-east diagonal which is the same as that of your first pattern (which works) but is not the same as that of the second (north-west). Is that explicit enough? As for marmot, he keeps spreading lies and spends his time looking for problems with everyone who answers the same questions as him. – AndréC Jul 12 '19 at 08:05
  • I still don't understand the essence of your dispute, but there is one thing that is definitely not OK with your explanation and your solution: you don't distinguish between \hatchdistance and \hatchthickness. The tile increase should be related to \hatchthickness and not \hatchdistance. This is why my acceptance goes to the other answer. – Pygmalion Jul 12 '19 at 11:26
  • @Pygmalion Differentiating between these two parameters is not useful since it is the size of the tile defined by the third and fourth parameters that defines this tile. Thus, if the line thickness is too wide, the tile will be fully colored. I like to write the simplest possible code and the easiest to understand (unlike marmot). – AndréC Jul 12 '19 at 15:52
14

You do what one usually does: define the cell size a bit smaller than what the path actually covers. The problem is that if the width of the line exceeds 0.5pt, an overshoot by 1pt is no longer sufficient. So one may want to use a more generous overshoot. The following may be a bit "too generous" (but being generous has no real sideeffects here AFAIK), and this one seems to work for many viewers and zoom levels, i.e. some of the things but not all in your code are also viewer issues.

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

\begin{document}

\begin{tikzpicture}


\usetikzlibrary{patterns}

\makeatletter
\tikzset{hatch distance/.store in=\hatchdistance,hatch distance=5pt,hatch thickness/.store in=\hatchthickness,hatch thickness=5pt}

\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north east hatch}% name
    {\pgfqpoint{-\hatchthickness}{-\hatchthickness}}% below left
    {\pgfqpoint{\hatchdistance+\hatchthickness}{\hatchdistance+\hatchthickness}}% above right
    {\pgfpoint{\hatchdistance}{\hatchdistance}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{-\hatchthickness}{-\hatchthickness}}       
        \pgfpathlineto{\pgfqpoint{\hatchdistance+\hatchthickness}{\hatchdistance+\hatchthickness}}
        \pgfusepath{stroke}
    }
\pgfdeclarepatternformonly[\hatchdistance,\hatchthickness]{north west hatch}% name
    {\pgfqpoint{-\hatchthickness}{-\hatchthickness}}% below left
    {\pgfqpoint{\hatchdistance+\hatchthickness}{\hatchdistance+\hatchthickness}}% above right
    {\pgfpoint{\hatchdistance}{\hatchdistance}}%
    {
        \pgfsetcolor{\tikz@pattern@color}
        \pgfsetlinewidth{\hatchthickness}
        \pgfpathmoveto{\pgfqpoint{\hatchdistance+\hatchthickness}{-\hatchthickness}}
        \pgfpathlineto{\pgfqpoint{-\hatchthickness}{\hatchdistance+\hatchthickness}}
        \pgfusepath{stroke}
    }
\makeatother

\draw[pattern=north east hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange] (0,0) rectangle +(1,1);
\draw[pattern=north west hatch,hatch distance=7pt,hatch thickness=3pt,pattern color=orange] (2,0) rectangle +(1,1);


\end{tikzpicture}
\end{document}

enter image description here

EXCITING NEWS: Soon the customization of patterns will be much easier, because of the pattern.meta library, see here. I thank JouleV for pointing this out.

6

Thanks to the patterns.meta library, this question has now an arguably simpler answer.

\documentclass[tikz,border=3mm]{standalone}
\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}{\hatchsize/2}} 
\pgfpathlineto{\pgfpoint{\hatchsize+.1pt}{\hatchsize/2}} 
\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} 
 \draw [pattern=hatch, pattern color=orange, hatch size=7pt,hatch line width=4pt,
  hatch angle=45] (0,0) rectangle ++(2,2); 
 \draw [pattern=hatch, pattern color=orange, hatch size=7pt,hatch line width=4pt,
  hatch angle=-45] (2.4,0) rectangle ++(2,2); 
\end{tikzpicture}
\end{document}

enter image description here