我想根据德国 VFR 地图样式绘制空域形状,但我对禁区(此图中的 ED-R44)遇到了问题:
(来源:航班计划网站)
我已经找到了如何处理空域 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}
答案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}