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.

TobiBS
  • 5,240
  • 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 '18 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 '18 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 '18 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 https://tex.stackexchange.com/questions/282012/change-angle-of-decoration-or-pattern-along-a-path-independently but I have to do it on arbitrary polygons, so I cannot manually define the fill area. – TobiBS Mar 10 '18 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 07 '20 at 09:22
  • @n4pK, I needed it to draw figures for my PhD which needed a simplified ICAO map look. Can you send me a personal message or similar? I try to add a graphic here if I find some time. – TobiBS Feb 08 '20 at 20:09
  • @TobiBS where can I send you a message? Seems like StackExchange does not have this feature by design... – n4pK Feb 09 '20 at 20:10
  • Mmh, it seems I am also not able to provide the images here in a comment and I don‘t want to put them into the question. Can you maybe leave a hint how to contact you on your profile page, as suggested in the question you are referring, then I can e.g. send you an e-mail? – TobiBS Feb 11 '20 at 14:31
  • @n4pK, if you are still interested, please send me a means of communication or a hint, how I can find you. – TobiBS May 15 '20 at 11:51
  • @n4pK, are you still interested in the application? – TobiBS Jul 21 '20 at 09:32
  • @n4pK Send me an e-mail with your e-mail address to stackexchange@tempr.email and I will contact you. Please post another comment here, when you did so. – TobiBS Jul 21 '20 at 10:20
  • @n4pK I received it and replied through my private e-mail, let's continue there. I will delete all comments related to our conversation here in a minute. – TobiBS Jul 21 '20 at 11:07

2 Answers2

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.

  • 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 '18 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 '18 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 ... ;-) –  Mar 11 '18 at 17:22
  • Regarding your comment about tikzstyle: Is it really deprecated now, I was still under the impression of https://tex.stackexchange.com/questions/52372/should-tikzset-or-tikzstyle-be-used-to-define-tikz-styles – TobiBS Mar 11 '18 at 17:23
  • Sounds good and I know that TikZ is tricky, but that is the challenge, right? – TobiBS Mar 11 '18 at 17:25
  • @TobiBS Frankly, I don't know if it is really deprecated, but what I do know is that whenever I use it I get angry comments. ;-) And yes, it is a nice challenge.... –  Mar 11 '18 at 17:26
  • good to know, I will avoid it when answering questions of others. – TobiBS Mar 11 '18 at 17:29
  • @TobiBS One more thing: your white filled triangle inside is rather harmless if you draw it on the background layer. The reason why I did not go this way is (a) the challenge and (b) that if you need to put other stuff on backgrounds, it will be slightly more complicated because you'll need to deal with all the layers. –  Mar 11 '18 at 17:34
  • 1
    Here is a version that does not use \pgfextra. –  Dec 15 '18 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

TobiBS
  • 5,240
  • 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 '18 at 14:09
  • I have added a slightly modified version of your code to my answer which avoids the fill. –  Mar 11 '18 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.. – white_gecko Nov 28 '19 at 13:15