14

I want to draw the shapes of airspaces according to the german VFR map style and I have problems with the restricted areas, ED-R44 in this picture: Legend of German ICAO Map
(source: flightplanner.de)

I already found out how to do the airspace A and B,C,D but the fill mechanism doesn't transpose to the hatch pattern I am looking for:

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{patterns}

\tikzstyle{EDR}=[draw=red,line width=1pt,preaction={clip, postaction={pattern=north west lines, pattern color=red}}]
\tikzstyle{D}=[draw=blue,line width=1pt,preaction={clip, postaction={draw=blue,opacity=0.5,line width=12pt}}]

\begin{document}
\begin{tikzpicture}
\draw[EDR] (1,0) -- (4.5,1.5) -- (4,4) -- (1,3.5) -- (2.5,2) -- cycle;

\node at (6,2) {$\rightarrow$};

\draw[EDR] (8,0) rectangle (12,4);
\draw[fill=white,draw=none] (8.5,0.5) rectangle (11.5,3.5);

\draw[D] (13,0) rectangle (17,4);
\end{tikzpicture}
\end{document}

CUrrent state of work as in the MWE The problem is, that the white fill doesn't work for arbitraray polygons, but I am unable to think of a way for preaction, postaction or decoration, to make it work.

12
  • 2
    please, extend your code snippet to complete small document beginning with \documentclass{...}` and ending with \end{document}. this is needed for test your code (it is not fun to write from scratch what you already done. help us to help you.
    – Zarko
    Mar 10, 2018 at 20:40
  • Sorry @Zarko, I am using TikZEdit, hence the old code was my complete example. I now expanded it to a complete document which should compile. And please don't get me wrong, I don't want to replicate the whole legend, it is only about the restricted areas with the hatch pattern.
    – TobiBS
    Mar 10, 2018 at 21:55
  • reproducing complete shoved image is to broad for asking, so in such case your question be closed :-). from the very beginning, I understood that you are only interested in the part, that you interested only for part produced by your mwe. there is not clear, what you like to obtain? the most left image with patterns only band at shape border?
    – Zarko
    Mar 10, 2018 at 22:00
  • Sorry, just wanted to make clear, because the image might be confusing without the text above. And exactly, I need to have the hatch pattern only at the border, like in the two rectangles (one with the red hatch, one with the blue solid), but without the trick of drawing white over the hatch, like in the MWE. Basically the result in tex.stackexchange.com/questions/282012/… but I have to do it on arbitrary polygons, so I cannot manually define the fill area.
    – TobiBS
    Mar 10, 2018 at 22:05
  • I am really curious about what your project was. An ICAO500-like map done in tikz? Do you have some website/image, what the overall outcome was?
    – n4pK
    Feb 7, 2020 at 9:22

2 Answers 2

8

NEW ANSWER BASED ON YOUR OWN ANSWER: This avoids the white filling. UPDATE: One single style does the job. (I also did the blue contour.)

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

\newcounter{tmp}

%\tikzstyle{D}=[draw=blue,line width=1pt,preaction={clip, postaction={draw=blue,opacity=0.5,line width=12pt}}]
%<- note that tikzstyle is deprecated

\tikzset{D/.style={
preaction={draw=blue,line width=1pt},
preaction={decoration={contour lineto closed, contour distance=6pt},
decorate,
},
postaction={
insert path={%
\pgfextra{%
\pgfinterruptpath
\begin{scope}[opacity=0.5, transparency group]
\path[fill=blue,even odd rule] 
\mySecondList \myList 
;
\end{scope}
\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[pattern=north west lines, pattern color=red,even odd rule] 
\mySecondList \myList 
;
\endpgfinterruptpath}
}},
}}

\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}{\pgfextra{%\typeout{\myList,\mySecondList}
  }}%
}
\makeatother
\tikzset{
  contour/.style={
    decoration={
      name=contour lineto closed,
      contour distance=#1
    },
    decorate}}
\begin{document}

\begin{tikzpicture}
\draw(0,0) -- ({sqrt(8)},4) node[midway,sloped,above]{That's just a test!};

\path[EDR]
(1,0) -- (4.5,1.5) -- (4,4) -- (1,3.5) -- (3.5,2) -- cycle;

\path[D] (7,0) -- (9.5,2.5) -- (11,4) -- (9,3.5) -- (8,2) -- cycle;


\end{tikzpicture}

\end{document}

enter image description here

ORIGINAL ANSWER: Some very similar question has been answered here. Using the code written there allowed me to write a command \DrawBorder, which I believe does what you want. Note, however, that the present version works for polygons only. (EDIT: Added the BCD style, cleaned up the code and added explanations.)

\documentclass[tikz,border=3pt]{standalone}
\usetikzlibrary{patterns,decorations,calc}
%
\def\contourwidth{12pt} 
% Notice that this width enters at two places
% first it defines the widths of the nodes created by \tikzsegment
% but it also defines the overshoot, required when an angle is larger than 
% 180 degrees
\newcommand{\tikzsegment}[3][]{ % from https://tex.stackexchange.com/a/192824/121799
\path let
      \p1=($#3-#2$),
      \n1={veclen(\p1)+1.75*\contourwidth}
 in #2 -- #3 
 node[minimum width=\n1, 
         inner sep=0pt, 
         pos=0.5,sloped,rectangle,
         fill=white]{} 
    node[minimum width=\n1, 
         inner sep=0pt, 
         pos=0.5,sloped,rectangle,
         #1] 
     (line){};
}
\newcommand{\DrawBorderA}[2][]{
\begin{scope}
\foreach \point [count=\n] in {#2} {
\ifnum\n=1
\xdef\ClipList{\point --}
\else
\xdef\ClipList{\ClipList \point --}
\fi
\node (prev) at \point {};
}
\xdef\ClipList{\ClipList cycle;}%\typeout{\ClipList}
\clip \ClipList
\foreach \point in {#2} {
\node (new) at \point {};%\typeout{\point}
\tikzsegment[pattern=north west lines, pattern color=red,
               minimum height={2*\contourwidth}]
              {(prev.center)}{(new.center)}    
\node (prev) at \point {};            
}
\draw[red,line width=2pt] \ClipList                    
\end{scope}
}

\newcommand{\DrawBorderBCD}[2][]{
\begin{scope}[opacity=0.5, transparency group]
\foreach \point [count=\n] in {#2} {
\ifnum\n=1
\xdef\ClipList{\point --}
\else
\xdef\ClipList{\ClipList \point --}
\fi
\node (prev) at \point {};
}
\xdef\ClipList{\ClipList cycle;}%\typeout{\ClipList}
\clip \ClipList
\foreach \point in {#2} {
\node (new) at \point {};%\typeout{\point}
\tikzsegment[fill=blue,
               minimum height={2*\contourwidth}]
              {(prev.center)}{(new.center)}
\node (prev) at \point {};            
}             
\end{scope}
\draw[blue,opacity=1,line width=1pt] \ClipList            
s}

% \tikzstyle{EDR}=[draw=red,line width=1pt,preaction={clip, postaction={pattern=north west lines, pattern color=red}}]
% \tikzstyle{D}=[draw=blue,line width=1pt,preaction={clip, postaction={draw=blue,opacity=0.5,line width=12pt}}]
\begin{document}

\begin{tikzpicture}

\DrawBorderA{(1,0),(4.5,1.5),(4,4),(1,3.5),(2.5,2)}

\begin{scope}[xshift=5cm]
\DrawBorderBCD{(1,0),(4.5,1.5),(4,4),(1,3.5),(2.6,2)}
\end{scope}

\end{tikzpicture}
\end{document}

enter image description here

DISCLAIMER: It does not yet work with arbitrarily crazy angles (much larger than 270 degrees). Dealing with those will either require brute force, i.e. some fair amount of work, or some clever idea. I plan to revisit this task once I know that this is the way to go.

10
  • In general the results looks like my expectation, but this solution creates problems in my actual file, which is scaled and hence creates nasty effects on some edges.
    – TobiBS
    Mar 11, 2018 at 14:08
  • That is a nice solution, but shouldn't it be possible to avoid to have the path twice? I know one could save it or one could again build a macro around it, but I think we are very close to a solution which can be completely embedded in a style.
    – TobiBS
    Mar 11, 2018 at 17:20
  • @TobiBS I am working on that, my attempts use append after command and insert path. As you probably know, TikZ can be tricky ... ;-)
    – user121799
    Mar 11, 2018 at 17:22
  • Regarding your comment about tikzstyle: Is it really deprecated now, I was still under the impression of tex.stackexchange.com/questions/52372/…
    – TobiBS
    Mar 11, 2018 at 17:23
  • 1
    Here is a version that does not use \pgfextra.
    – user121799
    Dec 15, 2018 at 23:08
5

I found another solution for my problem which is based on Draw additional parallel paths in TikZ and furthermore Polygon drawn with an offset

\tikzstyle{EDR}=[draw=red,line width=1pt,pattern=north west lines, pattern color=red,postaction={decoration={contour lineto closed, contour distance=6pt}, fill=white, decorate}]

\makeatletter
\usetikzlibrary{decorations,backgrounds}
\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]{%
    \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}}%
    \ifpgf@decorate@is@closepath@%
      \pgfpathclose
    \fi
  }%
  \state{final}{}%
}
\makeatother
\tikzset{
  contour/.style={
    decoration={
      name=contour lineto closed,
      contour distance=#1
    },
    decorate}}

\begin{tikzpicture}
\draw[EDR] (1,0) -- (4.5,1.5) -- (4,4) -- (1,3.5) -- (2.5,2) -- cycle;
\end{tikzpicture}

Final result

3
  • Is anybody able to propose a good way to create the white area via clipping, instead of my poor mans filling? It works in my current project, but might create issues for others.
    – TobiBS
    Mar 11, 2018 at 14:09
  • I have added a slightly modified version of your code to my answer which avoids the fill.
    – user121799
    Mar 11, 2018 at 15:29
  • Is it possible to use this pattern also with a not closed path? When I remove the cycle I get the error: Package tikz Error: Cannot parse this coordinate.. Nov 28, 2019 at 13:15

You must log in to answer this question.

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