TikZ:如何在 tikz 路径的边界上绘制图案

TikZ:如何在 tikz 路径的边界上绘制图案

我想根据德国 VFR 地图样式绘制空域形状,但我对禁区(此图中的 ED-R44)遇到了问题: 德国ICAO地图图例
(来源:航班计划网站

我已经找到了如何处理空域 A 和 B、C、D,但填充机制不能转换成我正在寻找的填充图案:

\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}

目前的工作状态与 MWE 相同 问题是,白色填充不适用于任意多边形,但我无法想出一种预先采取的动作、后采取的动作或装饰方法来使其发挥作用。

答案1

基于您自己的答案的新答案:这样可以避免白色填充。更新:一种风格就能完成任务。(我还画了蓝色轮廓。)

\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}

在此处输入图片描述

原始答案:一些非常相似的问题已经得到回答这里。使用那里写的代码,我可以编写一个命令\DrawBorder,我相信它可以满足您的要求。但请注意,当前版本仅适用于多边形。(编辑:添加了BCD样式,清理了代码并添加了解释。)

\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}

在此处输入图片描述

免责声明:它还不能处理任意角度(远大于 270 度)。处理这些角度要么需要蛮力,即相当多的工作,要么需要一些聪明的想法。一旦我知道这是可行的方法,我打算重新审视这项任务。

答案2

我找到了另一个解决方案,它基于在 TikZ 中绘制额外的平行路径此外使用偏移绘制的多边形

\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}

最后结果

相关内容