3

Based on the solution provided at TikZ: How to draw a pattern at the border of a tikz path I was able to do all the graphics in my thesis, except for one shape. As you can see in the graphic

enter image description here

the solution works e.g. for a square, but for the specific shape shown in the top right, the overlap creates a second white area, which should be filled. nonzero rule does not solve the issue and I have no idea, except for manual calculation of the white area, how to properly draw this shape.

The MWE:

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


% defining the new dimensions and parameters
\newlength{\hatchspread}
\newlength{\hatchthickness}
\newlength{\hatchshift}
\newcommand{\hatchcolor}{}
% declaring the keys in tikz
\tikzset{hatchspread/.code={\setlength{\hatchspread}{#1}},
         hatchthickness/.code={\setlength{\hatchthickness}{#1}},
         hatchshift/.code={\setlength{\hatchshift}{#1}},% must be >= 0
         hatchcolor/.code={\renewcommand{\hatchcolor}{#1}}}
% setting the default values
\tikzset{hatchspread=1.5pt,
         hatchthickness=0.5pt,
         hatchshift=0pt,% must be >= 0
         hatchcolor=black}
% declaring the pattern
\pgfdeclarepatternformonly[\hatchspread,\hatchthickness,\hatchshift,\hatchcolor]% variables
   {custom north west lines}% name
   {\pgfqpoint{\dimexpr-2\hatchthickness}{\dimexpr-2\hatchthickness}}% lower left corner
   {\pgfqpoint{\dimexpr\hatchspread+2\hatchthickness}{\dimexpr\hatchspread+2\hatchthickness}}% upper right corner
   {\pgfqpoint{\dimexpr\hatchspread}{\dimexpr\hatchspread}}% tile size
   {% shape description
    \pgfsetlinewidth{\hatchthickness}
    \pgfpathmoveto{\pgfqpoint{0pt}{\dimexpr\hatchspread+\hatchshift}}
    \pgfpathlineto{\pgfqpoint{\dimexpr\hatchspread+0.15pt+\hatchshift}{-0.15pt}}
    \ifdim \hatchshift > 0pt
      \pgfpathmoveto{\pgfqpoint{0pt}{\hatchshift}}
      \pgfpathlineto{\pgfqpoint{\dimexpr0.15pt+\hatchshift}{-0.15pt}}
    \fi
    \pgfsetstrokecolor{\hatchcolor}
%    \pgfsetdash{{1pt}{1pt}}{0pt}% dashing cannot work Dly in all situation this way
    \pgfusepath{stroke}
   }


\newcounter{tmp}
\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]{%
    \pgfextra{\xdef\myList{}\xdef\mySecondList{}}
    \pgfextra{\setcounter{tmp}{0}}
    \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\thetmp}{\pgfpoint{\pgfdecoratedinputsegmentlength+\pgf@decoration@contour@shorten}
      {\pgfdecoratedcontourdistance}}
    \pgfcoordinate{feep\thetmp}{\pgfpoint{\pgfdecoratedinputsegmentlength}{0pt}}      
    \pgfextra{\xdef\myList{\myList (muemmel\thetmp) -- }%
        \xdef\mySecondList{\mySecondList (feep\thetmp) -- }}
    \ifpgf@decorate@is@closepath@%
      \pgfpathclose
      \pgfextra{\xdef\myList{\myList cycle}% 
      \xdef\mySecondList{\mySecondList cycle}}
    \fi
  }%
  \state{final}{}%
}
\makeatother



\tikzset{EDR/.style={
draw=none,
preaction={draw=red,line width=0.5pt},
preaction={decoration={contour lineto closed, contour distance=-2pt},
decorate,
},
postaction={
insert path={%
\pgfextra{%
\pgfinterruptpath
\path[pattern=custom north west lines,hatchspread=1.5pt,hatchthickness=0.25pt,hatchcolor=red,even odd rule] 
\mySecondList \myList
;
\endpgfinterruptpath}
}},
}}

\begin{document}

\begin{tikzpicture}[scale=0.2]
\draw[EDR](35,57) -- (37,57) -- (37,55) -- (35,55) -- cycle;
\draw[EDR](41.1298,62.3343) -- (42.8362,62.341) -- (41.8438,58.9344) -- (41.5201,58.9331) -- cycle;
%\draw[thin](41.1298,62.3343) -- (42.8362,62.341) -- (41.61147,58.13688) -- cycle;
\end{tikzpicture}

\end{document}
  • 2
    Yup, this was written before I knew how dangerous \pgfextra is. – user121799 Dec 15 '18 at 22:09
1

First of all, sorry to hear that there are problems. And sorry^2 for using \pgfextra. This is not the issue here, but it is really bad. (And still there are accepted and highly voted answers that use it even though the answerer knows that it is bad. My above code, unfortunately, has contributed, to the distribution of this practice. \pgfextra can, however, be used for exporting definitions like in \pgfextra{\xdef\myList{}\xdef\mySecondList{}}, which is AFAIK not dangerous. Drawing paths in \pgfextra is dangerous.)

Now to the real question. Here is an alternative. Two disadvantages:

  1. You need to use a scope if you draw anything after the boundary. (IMHO this is not too bad.)
  2. This version does not work with angles that are larger than 180 degrees. Here the angle is the angle seen by an observer inside. So a rectangle would have four times 90 degrees (and not 270 degrees). (It would be very straightforward to cover also larger angles, if needed.)

Here is the code.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{patterns,decorations.pathreplacing,calc}


% defining the new dimensions and parameters
\newlength{\hatchspread}
\newlength{\hatchthickness}
\newlength{\hatchshift}
\newcommand{\hatchcolor}{}
% declaring the keys in tikz
\tikzset{hatchspread/.code={\setlength{\hatchspread}{#1}},
         hatchthickness/.code={\setlength{\hatchthickness}{#1}},
         hatchshift/.code={\setlength{\hatchshift}{#1}},% must be >= 0
         hatchcolor/.code={\renewcommand{\hatchcolor}{#1}}}
% setting the default values
\tikzset{hatchspread=1.5pt,
         hatchthickness=0.5pt,
         hatchshift=0pt,% must be >= 0
         hatchcolor=black}
% declaring the pattern
\pgfdeclarepatternformonly[\hatchspread,\hatchthickness,\hatchshift,\hatchcolor]% variables
   {custom north west lines}% name
   {\pgfqpoint{\dimexpr-2\hatchthickness}{\dimexpr-2\hatchthickness}}% lower left corner
   {\pgfqpoint{\dimexpr\hatchspread+2\hatchthickness}{\dimexpr\hatchspread+2\hatchthickness}}% upper right corner
   {\pgfqpoint{\dimexpr\hatchspread}{\dimexpr\hatchspread}}% tile size
   {% shape description
    \pgfsetlinewidth{\hatchthickness}
    \pgfpathmoveto{\pgfqpoint{0pt}{\dimexpr\hatchspread+\hatchshift}}
    \pgfpathlineto{\pgfqpoint{\dimexpr\hatchspread+0.15pt+\hatchshift}{-0.15pt}}
    \ifdim \hatchshift > 0pt
      \pgfpathmoveto{\pgfqpoint{0pt}{\hatchshift}}
      \pgfpathlineto{\pgfqpoint{\dimexpr0.15pt+\hatchshift}{-0.15pt}}
    \fi
    \pgfsetstrokecolor{\hatchcolor}
    \pgfusepath{stroke}
   }

\pgfset{
  decoration/contour distance/.code=%
    \pgfmathsetlengthmacro\pgfdecoratedcontourdistance{#1}}

\begin{document}
\tikzset{EDR/.style={clip,
decoration={show path construction,
lineto code={
\path[pattern=custom north west lines,hatchspread=1.5pt,hatchthickness=0.25pt,hatchcolor=red] 
(\tikzinputsegmentfirst) 
--
($(\tikzinputsegmentfirst)!\pgfdecoratedcontourdistance!90:(\tikzinputsegmentlast)$)
--
($(\tikzinputsegmentlast)!\pgfdecoratedcontourdistance!-90:(\tikzinputsegmentfirst)$)
-- (\tikzinputsegmentlast);
},closepath code={
\path[pattern=custom north west lines,hatchspread=1.5pt,hatchthickness=0.25pt,hatchcolor=red] 
(\tikzinputsegmentfirst) 
--
($(\tikzinputsegmentfirst)!\pgfdecoratedcontourdistance!90:(\tikzinputsegmentlast)$)
--
($(\tikzinputsegmentlast)!\pgfdecoratedcontourdistance!-90:(\tikzinputsegmentfirst)$)
-- (\tikzinputsegmentlast);
}},preaction={draw=red,line width=0.5pt},postaction=decorate}}
\begin{tikzpicture}[scale=0.2]
\pgfset{decoration/contour distance=-2pt}
\begin{scope}
\path[EDR]
(35,57) -- (37,57) -- (37,55) -- (35,55) -- cycle;
\end{scope}
\path[EDR]
(41.1298,62.3343) -- (42.8362,62.341) -- (41.8438,58.9344) -- (41.5201,58.9331) -- cycle;
%\draw[thin](41.1298,62.3343) -- (42.8362,62.341) -- (41.61147,58.13688) -- cycle;
\end{tikzpicture}
\end{document}

enter image description here

  • Awesome how quick you are, thanks for this solution! – TobiBS Dec 15 '18 at 23:19
  • @TobiBS You're welcome! (Please let me know if you ever encounter angles larger than 180 degrees. In principle you could tackle those by drawing the thing with the old and with the new EDR style, however, due to \pgfextra things may break.) – user121799 Dec 15 '18 at 23:23
  • At least for now I am done, this was the last graphic to tackle and the PDF will be sent for printing on Monday. – TobiBS Dec 15 '18 at 23:28
  • @TobiBS I see. Xmas saved by a marmot. ;-) (Just kidding.) – user121799 Dec 15 '18 at 23:31

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.