如何在 tikz 中绘制路径的轮廓?

如何在 tikz 中绘制路径的轮廓?

使用箭头尖库,我可以绘制带有三角形尖头的粗箭头,如下所示:

\begin{tikzpicture}
  \draw[line width=2ex,
        rounded corners=2ex,
        triangle 90 cap reversed-triangle 90 cap
       ] (0,0) -| (1,1);
\end{tikzpicture}

这些箭头是填充的。我只想要这个箭头的轮廓,但只使用“double”样式无法实现这一点。起始和结束尖端都已填充:

\begin{tikzpicture}
  \draw[line width=2ex,
        rounded corners=2ex,
        double distance between line centers=2ex,
        double,
        line width=1pt,
        triangle 90 cap reversed-triangle 90 cap
       ] (0,0) -| (1,1);
\end{tikzpicture}

我认为我需要创建第一个箭头的轮廓(已完全填充),然后沿着该轮廓画一条线。我只是不知道该怎么做。


我最终按照 EEva 的建议绘制了两次箭头,但按照 Andrew 建议的方式进行了改进。我使用 LaTeX 长度来存储箭头“周围”线条的宽度。此宽度称为 ,\DblTriCapDelta使用此长度的 tikz 样式称为DblTriCap,因为它会生成带有双笔划的三角形封头箭头:

\newlength{\DblTriCapDelta}
\setlength{\DblTriCapDelta}{1pt}
\tikzset{
  DblTriCap/.style={
    postaction={
      draw,
      color=white,
      shorten >=1.4142\DblTriCapDelta,
      shorten <=2.4142\DblTriCapDelta,
      line width={\pgflinewidth-\DblTriCapDelta}
    }
  }
}

我还没有定义密钥处理程序(以前从未这样做过)。当前用法是:

\begin{tikzpicture}
  \draw[line width=4mm,
        rounded corners=4mm,
        triangle 90 cap reversed-triangle 90 cap,
    DblTriCap
       ] (0,0) -| (1,1);
\end{tikzpicture}

我希望能够选择填充颜色,但无法让它发挥作用。

答案1

如果我正确理解了您想要做什么,那么您将需要定义新的箭头形状来获得轮廓。这些箭头被填充的事实已硬编码到它们的定义中。幸运的是,这并不难做到。这些箭头的代码在文件中,pgflibraryarrows.code.tex如下所示:

\pgfarrowsdeclare{triangle 90 cap}{triangle 90 cap}
{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+\pgflinewidth}}
{
  \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{0.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{\pgflinewidth}{0pt}}
  \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{-.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-0.5\pgflinewidth}}
  \pgfusepathqfill
}

在那里我们可以看到最后一个命令是\pgfusepathqfill填充刚刚构建的路径。为了绘制它而不是填充它,我们将其更改为\pgfusepathqstroke。当然,为了避免名称冲突,我们也更改了箭头的名称(并将其放在序言中而不是编辑pgflibraryarrows.code.tex

\pgfarrowsdeclare{triangle 90 cap outline}{triangle 90 cap outline}
{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+\pgflinewidth}}
{
  \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{0.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{\pgflinewidth}{0pt}}
  \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{-.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-0.5\pgflinewidth}}
  \pgfusepathqstroke
}

但即使这样也不能如你所愿,因为你可能只想绘制一些边缘,虽然一条边缘被遗漏了(因为填充隐式关闭了路径),但它不是正确的边缘。此外,线宽是从主路径继承的,这肯定是不对的,因为你想让它成为双笔划“剩余”部分的宽度。所以我们必须对箭头部分的绘制顺序进行一些调整。此外,为了完全灵活,我们应该确保线宽设置正确(顺便说一句,你的两次线宽声明是不必要的;第二个胜过第一个)。

综上所述,以下调整箭头以提供轮廓。它位于一个\makeatletter ... \makeatother块中,因为我使用了一些@名称中带有 s 的临时存储槽。

这是我得到的(左边是你的原版,右边是我的变体):

箭头轮廓

这是代码(该arrows库仅适用于您的示例):

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows}

\makeatletter

\pgfarrowsdeclare{triangle 90 cap outline}{triangle 90 cap outline}
{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+\pgflinewidth}}
{
  \pgfmathsetlength{\pgfutil@tempdima}{.5 * \pgflinewidth + .5 * \pgfinnerlinewidth}
  \pgfsetlinewidth{\pgfutil@tempdima}
  \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{0.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{0\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{.5\pgflinewidth}{-.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-.5\pgflinewidth}}
  \pgfmathsetlength{\pgfutil@tempdimb}{\pgflinewidth -  \pgfinnerlinewidth}
  \pgfsetlinewidth{\pgfutil@tempdimb}
  \pgfusepathqstroke
}

\pgfarrowsdeclare{triangle 90 cap reversed outline}{triangle 90 cap reversed outline}
{\pgfarrowsleftextend{+-.1\pgflinewidth}\pgfarrowsrightextend{+\pgflinewidth}}
{
  \pgfmathsetlength{\pgfutil@tempdima}{.5 * \pgflinewidth + .5 * \pgfinnerlinewidth}
  \pgfsetlinewidth{\pgfutil@tempdima}
  \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{0.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{0.5\pgflinewidth}{0\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{1\pgflinewidth}{-.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-.5\pgflinewidth}}
  \pgfmathsetlength{\pgfutil@tempdimb}{\pgflinewidth -  \pgfinnerlinewidth}
  \pgfsetlinewidth{\pgfutil@tempdimb}
  \pgfusepathqstroke
}
\makeatother

\begin{document}
\begin{tikzpicture}
  \draw[
        rounded corners=2ex,
        double distance between line centers=2ex,
        double,
        line width=1pt,
        triangle 90 cap reversed-triangle 90 cap
       ] (0,0) -| (1,1);
  \draw[
        rounded corners=2ex,
        double distance between line centers=2ex,
        double,
        line width=1pt,
        triangle 90 cap reversed outline-triangle 90 cap outline
       ] (2,0) -| ++(1,1);
\end{tikzpicture}
\end{document}

答案2

我还寻找过空的线帽,但在手册中找不到任何东西。

但是,这里有一个便宜(但有效)的解决方案:

\begin{tikzpicture}
  \draw[line width=2ex,
        rounded corners=2ex,
        triangle 90 cap reversed-triangle 90 cap
       ] (0,0) -| (1,1);
  \draw[line width=1.5ex, color=white,
        rounded corners=2ex,
        triangle 90 cap reversed-triangle 90 cap
       ] (0.1,0) -| (1,.95);
\end{tikzpicture}

空行帽

我只是将第一个例子画了两次,一次黑色,一次白色,并稍微移动了边框。

感谢 Andrew Stacey(在评论中),使用以下命令可以使代码更短更美观postaction

\begin{tikzpicture}
  \draw[line width=2ex,
        rounded corners=2ex,
        triangle 90 cap reversed-triangle 90 cap,
        postaction={draw,color=white,line width=1.5ex,shorten >=.25ex,shorten <=.5ex}
       ] (0,0) -| (1,1);
\end{tikzpicture}

答案3

我也需要一条双击(或者更确切地说是“填充和描边”)的粗箭头线;所以这里对代码片段做了一些修改@EEva 的回答使用后动作 - 具有可控的颜色、宽度和轮廓宽度;它产生类似这样的效果:

测试02b.png

我保留了透明度,因此可以看到箭头如何连接到末端。代码尝试调整缩短,但如果您更改箭头类型(即使没有),您可能必须手动进行微调。代码是:

\documentclass[varwidth]{standalone}

\usepackage{tikz}

\pagecolor{yellow!15}
\begin{document}
\begin{tikzpicture}

\tikzset{%
  % use: dblarw={color}{totalouterwidth}{outlineinsidewidth}
  dblarw/.style n args={3}{%,
    -latex,
    line width=#2,
    draw=black,  % this draw and color could
    color=black, % be an additional style arg
    opacity=0.9,
    % note: just color=#1 makes all black! 
    % fill=#1 makes insides (in an open! curve) filled too!
    % draw=#1,color=#1, seems to work, though
    postaction={
      draw=#1,
      color=#1,
      line width=#2-#3,
      shorten >=2*#3,
      shorten <=#3,
    },
    dblarw/.default={gray}{5pt}{1pt},
    dblarw/.initial={gray}{5pt}{1pt},
  }
}

% unfortunately, must set both style args explicitly;
% cannot do dblarw={green} or dblarw={green}{}{}
\draw[dblarw={green}{5pt}{1pt}]
  (0,0) -- (4,4);
\draw[dblarw={red}{5pt}{1pt}]
  (0,4) ..controls +(east:4) and +(west:4).. (4,0);
\draw[dblarw={blue}{8pt}{3pt}]
  (4,3) -- (0,1);

\end{tikzpicture}
\end{document}

相关内容