0

In TikZ: How to draw a pattern at the border of a not closed tikz path, the solution draws a hatched pattern beside a line. I would like to adapt it to also fill in the space behind the pattern to cover up things drawn before the hatching, but adding a "fill" in the place that seems logical to me (by comment % MODIFIED: added fill=white in the MWE) doesn't work. MWE:

\documentclass[tikz]{standalone}
\usepackage{tikz}
\usetikzlibrary{patterns}
\usetikzlibrary{decorations,backgrounds}

% BEGIN from https://tex.stackexchange.com/questions/518580/tikz-how-to-draw-a-pattern-at-the-border-of-a-not-closed-tikz-path \newcounter{tmp} \newif\ifpathisclosed

\makeatletter \def\pgfdecoratedcontourdistance{0pt} \pgfset{ decoration/contour distance/.code=% \pgfmathsetlengthmacro\pgfdecoratedcontourdistance{#1}} \pgfdeclaredecoration{contour lineto closed}{start}{% \state{start}[ next state=draw, width=0pt, persistent precomputation=\let\pgf@decorate@firstsegmentangle\pgfdecoratedangle]{% %\xdef\myList{}\xdef\mySecondList{}% \setcounter{tmp}{0}% \global\pathisclosedfalse% \pgfpathmoveto{\pgfpointlineattime{.5} {\pgfqpoint{0pt}{\pgfdecoratedcontourdistance}} {\pgfqpoint{\pgfdecoratedinputsegmentlength}{\pgfdecoratedcontourdistance}}}% }% \state{draw}[next state=draw, width=\pgfdecoratedinputsegmentlength]{% \ifpgf@decorate@is@closepath@% \pgfmathsetmacro\pgfdecoratedangletonextinputsegment{% -\pgfdecoratedangle+\pgf@decorate@firstsegmentangle}% \fi \pgfmathsetlengthmacro\pgf@decoration@contour@shorten{% -\pgfdecoratedcontourdistance*cot(-\pgfdecoratedangletonextinputsegment/2+90)}% \pgfpathlineto {\pgfpoint{\pgfdecoratedinputsegmentlength+\pgf@decoration@contour@shorten} {\pgfdecoratedcontourdistance}}% \stepcounter{tmp}% \pgfcoordinate{muemmel\number\value{tmp}}{\pgfpoint{\pgfdecoratedinputsegmentlength+\pgf@decoration@contour@shorten} {\pgfdecoratedcontourdistance}}% \pgfcoordinate{feep\number\value{tmp}}{\pgfpoint{\pgfdecoratedinputsegmentlength}{0pt}}%
\ifnum\value{tmp}=1\relax% \pgfcoordinate{muemmel0}{\pgfpoint{0pt}{\pgfdecoratedcontourdistance}}% \pgfcoordinate{feep0}{\pgfpoint{0pt}{0pt}}%
\xdef\myList{(muemmel\number\value{tmp})}% \xdef\mySecondList{(feep\number\value{tmp})}% \else \xdef\myList{\myList -- (muemmel\number\value{tmp})}% \xdef\mySecondList{(feep\number\value{tmp}) -- \mySecondList}% \fi \ifpgf@decorate@is@closepath@% \pgfpathclose \global\pathisclosedtrue% \fi }% \state{final}{%\typeout{\myList,\mySecondList}% \ifpathisclosed% \xdef\myList{\myList -- cycle}% \xdef\mySecondList{\mySecondList -- cycle}% %\typeout{closed \mySecondList \myList } \else %\typeout{\number\value{tmp}}% \xdef\myList{(muemmel0) -- \myList -- cycle}% \xdef\mySecondList{\mySecondList -- (feep0) --}% %\typeout{not closed \mySecondList \myList }%
\fi }% } \makeatother \tikzset{ contour/.style={ decoration={ name=contour lineto closed, contour distance=#1 }, decorate} }

\tikzset{EDR/.style={ preaction={draw=red,line width=1pt}, preaction={decoration={contour lineto closed, contour distance=6pt}, decorate, }, postaction={ insert path={% \pgfextra{% \pgfinterruptpath \path[pattern=north west lines, pattern color=red,even odd rule] \mySecondList \myList ; \endpgfinterruptpath} }}, }}

% END from https://tex.stackexchange.com/questions/518580/tikz-how-to-draw-a-pattern-at-the-border-of-a-not-closed-tikz-path

\tikzset{EDRB/.style={ preaction={draw=red,line width=1pt}, preaction={decoration={contour lineto closed, contour distance=6pt}, decorate, }, postaction={ insert path={% \pgfextra{% \pgfinterruptpath \path[fill=white,pattern=north west lines, pattern color=red,even odd rule] % MODIFIED: added fill=white \mySecondList \myList ; \endpgfinterruptpath} }}, }}

\begin{document}

\begin{tikzpicture}
    \node at (3,3.5) {Current};

        \draw[ultra thick,blue] (0,3) -- (6,2);
        \path [EDR,draw, red, line width=1pt] (0,3) -- ++(0,-1) -- ++(6,0) -- ++(0,1) 
            -- ++(-3.125cm-6pt,0);

    \begin{scope}[shift={(0,-3)}]

        \node at (3,3.5) {Desired};

        \begin{scope}
            \clip (6pt,3) rectangle (6cm-6pt,2cm+6pt);
            \draw[ultra thick,blue] (0,3) -- (6,2);
        \end{scope}

        \path [EDR,draw, red, line width=1pt] (0,3) -- ++(0,-1) -- ++(6,0) -- ++(0,1) 
        -- ++(-3.125cm-6pt,0);

    \end{scope}

    \begin{scope}[shift={(0,-6)}]

        \node at (3,3.5) {Attempt: ``EDRB'' Style};

        \draw[ultra thick,blue] (0,3) -- (6,2);

        \path [EDR,draw, red, line width=1pt] (0,3) -- ++(0,-1) -- ++(6,0) -- ++(0,1) 
        -- ++(-3.125cm-6pt,0);

    \end{scope}
\end{tikzpicture}


\end{document}

MWE Output:

enter image description here

Is there a way to add a fill behind the pattern?

user1476176
  • 1,225
  • So much code … is the blue line overpainted by non-opaque layer before it? – MS-SPO Jun 08 '23 at 14:50
  • I'm not sure I understand what you mean about a non-opaque layer. I'm not actively using layers - in the "Desired" image I got the behaviour that I want using a clip rectangle, but I don't want to have to do that manually.

    I agree that it is a lot of code, but it is almost entirely copied from the linked question. As far as I can tell, it is the minimal working example.

    – user1476176 Jun 08 '23 at 14:54
  • It means that blue is overpainted by the red regions, so blue can‘t shine through. Just like with regular drawing programs, which use layers. // If that‘s your minimal code, something is wrong. And no, I didn‘t spend more than a glance on it. But it‘s longer multiple times compared to code from the pgfmanual. – MS-SPO Jun 08 '23 at 15:18
  • Hmm, two fills: one white and one patterned? Or clip the blue line in a scope., – John Kormylo Jun 08 '23 at 17:25
  • If I'm seeing this correctly, the blue shouldn't merely get covered/clipped against the patterned area but actually shortened since the top part doesn't show up above the patterned area. On the other end, the blue line should look like it's clipped. This won't be easy to recreate. – Qrrbrbirlbel Jun 08 '23 at 18:34
  • @Qrrbrbirbel The clipping at the top left is actually something that I didn't think about when I was illustrating the desired output! I used clipping because it seemed like a quick way to illustrate what I wanted, but in fact it's OK for a little bit of blue to appear above the hatching at the top left. Thanks for pointing this out. – user1476176 Jun 08 '23 at 21:28

1 Answers1

2

I was able to hack together something that works. The changes required were:

  1. Add a separate \path in the \pgfextra{} block for applying the filling
  2. Add a new draw to the postaction list so that the edge line is above the fill (without this the edge line is below the fill so half its width is obscured

The MWE is then:

\documentclass[tikz]{standalone}
\usepackage{tikz}
\usetikzlibrary{patterns}
\usetikzlibrary{decorations,backgrounds}

% BEGIN from https://tex.stackexchange.com/questions/518580/tikz-how-to-draw-a-pattern-at-the-border-of-a-not-closed-tikz-path \newcounter{tmp} \newif\ifpathisclosed

\makeatletter \def\pgfdecoratedcontourdistance{0pt} \pgfset{ decoration/contour distance/.code=% \pgfmathsetlengthmacro\pgfdecoratedcontourdistance{#1}} \pgfdeclaredecoration{contour lineto closed}{start}{% \state{start}[ next state=draw, width=0pt, persistent precomputation=\let\pgf@decorate@firstsegmentangle\pgfdecoratedangle]{% %\xdef\myList{}\xdef\mySecondList{}% \setcounter{tmp}{0}% \global\pathisclosedfalse% \pgfpathmoveto{\pgfpointlineattime{.5} {\pgfqpoint{0pt}{\pgfdecoratedcontourdistance}} {\pgfqpoint{\pgfdecoratedinputsegmentlength}{\pgfdecoratedcontourdistance}}}% }% \state{draw}[next state=draw, width=\pgfdecoratedinputsegmentlength]{% \ifpgf@decorate@is@closepath@% \pgfmathsetmacro\pgfdecoratedangletonextinputsegment{% -\pgfdecoratedangle+\pgf@decorate@firstsegmentangle}% \fi \pgfmathsetlengthmacro\pgf@decoration@contour@shorten{% -\pgfdecoratedcontourdistance*cot(-\pgfdecoratedangletonextinputsegment/2+90)}% \pgfpathlineto {\pgfpoint{\pgfdecoratedinputsegmentlength+\pgf@decoration@contour@shorten} {\pgfdecoratedcontourdistance}}% \stepcounter{tmp}% \pgfcoordinate{muemmel\number\value{tmp}}{\pgfpoint{\pgfdecoratedinputsegmentlength+\pgf@decoration@contour@shorten} {\pgfdecoratedcontourdistance}}% \pgfcoordinate{feep\number\value{tmp}}{\pgfpoint{\pgfdecoratedinputsegmentlength}{0pt}}%
\ifnum\value{tmp}=1\relax% \pgfcoordinate{muemmel0}{\pgfpoint{0pt}{\pgfdecoratedcontourdistance}}% \pgfcoordinate{feep0}{\pgfpoint{0pt}{0pt}}%
\xdef\myList{(muemmel\number\value{tmp})}% \xdef\mySecondList{(feep\number\value{tmp})}% \else \xdef\myList{\myList -- (muemmel\number\value{tmp})}% \xdef\mySecondList{(feep\number\value{tmp}) -- \mySecondList}% \fi \ifpgf@decorate@is@closepath@% \pgfpathclose \global\pathisclosedtrue% \fi }% \state{final}{%\typeout{\myList,\mySecondList}% \ifpathisclosed% \xdef\myList{\myList -- cycle}% \xdef\mySecondList{\mySecondList -- cycle}% %\typeout{closed \mySecondList \myList } \else %\typeout{\number\value{tmp}}% \xdef\myList{(muemmel0) -- \myList -- cycle}% \xdef\mySecondList{\mySecondList -- (feep0) --}% %\typeout{not closed \mySecondList \myList }%
\fi }% } \makeatother \tikzset{ contour/.style={ decoration={ name=contour lineto closed, contour distance=#1 }, decorate} }

\tikzset{D/.style={ preaction={draw=blue,line width=1pt}, preaction={decoration={contour lineto closed, contour distance=6pt}, decorate, }, postaction={ insert path={% \pgfextra{% \pgfinterruptpath \path[fill=white,even odd rule] \mySecondList \myList ; \path[pattern=north west lines, pattern color=red,even odd rule] \mySecondList \myList ; \endpgfinterruptpath} }}, }} \tikzset{EDR/.style={ preaction={draw=red,line width=1pt}, preaction={decoration={contour lineto closed, contour distance=6pt}, decorate, }, postaction={ insert path={% \pgfextra{% \pgfinterruptpath \path[fill=white,even odd rule] \mySecondList \myList ; \path[pattern=north west lines, pattern color=red,even odd rule] \mySecondList \myList ; \endpgfinterruptpath} }}, }}

% END from https://tex.stackexchange.com/questions/518580/tikz-how-to-draw-a-pattern-at-the-border-of-a-not-closed-tikz-path

\tikzset{ EDRB fill color/.initial=white, % NEW EDRB fill color/.get=\EDRBfillcolor, % NEW EDRB fill color/.store in=\EDRBfillcolor, % NEW EDRB/.style={ preaction={decoration={contour lineto closed, contour distance=6pt}, decorate, }, postaction={ insert path={% \pgfextra{% \pgfinterruptpath \path[fill=\EDRBfillcolor,even odd rule] % NEW \mySecondList \myList % NEW ; % NEW \path[pattern=north west lines,pattern color=red,even odd rule] \mySecondList \myList ; \endpgfinterruptpath} }, draw=red,% NEW }, } }

\begin{document}

\begin{tikzpicture}
    \node at (3,3.5) {Current};

        \draw[ultra thick,blue] (0,3) -- (6,2);
        \path [EDR,draw, red, line width=1pt] (0,3) -- ++(0,-1) -- ++(6,0) -- ++(0,1) 
            -- ++(-3.125cm-6pt,0);

    \begin{scope}[shift={(0,-3)}]

        \node at (3,3.5) {Desired};

        \begin{scope}
            \clip (6pt,3) rectangle (6cm-6pt,2cm+6pt);
            \draw[ultra thick,blue] (0,3) -- (6,2);
        \end{scope}

        \path [EDR,draw, red, line width=1pt] (0,3) -- ++(0,-1) -- ++(6,0) -- ++(0,1) 
        -- ++(-3.125cm-6pt,0);

    \end{scope}

    \begin{scope}[shift={(0,-6)}]

        \node at (3,3.5) {Acceptable: ``EDRB'' Style};

        \draw[ultra thick,blue] (0,3) -- (6,2);

        \path [EDRB, line width=1pt] (0,3) -- ++(0,-1) -- ++(6,0) -- ++(0,1) 
        -- ++(-3.125cm-6pt,0);

    \end{scope}
\end{tikzpicture}


\end{document}

Output: enter image description here

The portion of the blue that extends outside of the hatching at the top left is something that I can live with.

user1476176
  • 1,225