TikZ:中途改变路径的颜色

TikZ:中途改变路径的颜色

问题如下:

\documentclass{minimal}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
[scale = 3,
foo/.style={line width = 5pt}]
\draw[foo,red] (0,0) -- (0,1);
\draw[foo,blue] (0,1) -- (1,2);
\end{tikzpicture}
\end{document}

我想要一条在中途改变颜色的线。我可以用两条路径来实现(如上所示),但正如您所见,图片看起来不太好。

TikZ 问题

我也可以把第一条路径向上移动(1,2),然后在上面画,但根本问题是粗线的角度不对。我希望红色和蓝色之间的过渡角度合适。

有没有办法用路径来实现这一点,还是我必须创建自定义形状才能达到我想要的效果?看起来像这样:

TikZ 问题 2

答案1

使用剪辑。提供剪辑确实会影响线的结尾,因此如果您以正确的角度剪辑路径,它将真正按照您想要的方式剪辑路径。可能有更简单的方法来实现这一点(即,可能有更快的方法来获取所涉及的坐标),但下面的方法似乎有效。

\documentclass{minimal}

\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (2,1);
\coordinate (c) at (0,-1);
\path (a);
\pgfgetlastxy{\ax}{\ay}
\path (b);
\pgfgetlastxy{\bx}{\by}
\path (c);
\pgfgetlastxy{\cx}{\cy}
\pgfmathsetmacro{\bx}{\bx - \ax}
\pgfmathsetmacro{\by}{\by - \ay}
\pgfmathsetmacro{\cx}{\cx - \ax}
\pgfmathsetmacro{\cy}{\cy - \ay}
\pgfmathsetmacro{\blen}{veclen(\bx,\by)}
\pgfmathsetmacro{\clen}{veclen(\cx,\cy)}
\pgfmathsetmacro{\dx}{\bx * \clen/\blen + \cx}
\pgfmathsetmacro{\dy}{\by * \clen/\blen + \cy}

\begin{scope}
\clip (a) -- ++(\dx pt, \dy pt) -- ++(2* \bx pt, 2* \by pt) -- ++(-2* \dx pt, -2 * \dy pt) -- ++(-2 * \bx pt, -2 * \by pt) -- (a);
\draw[line width=1cm,blue,line cap=rect] (a) -- (b);
\end{scope}
\begin{scope}
\clip (a) -- ++(\dx pt, \dy pt) -- ++(2* \cx pt, 2* \cy pt) -- ++(-2* \dx pt, -2 * \dy pt) -- ++(-2 * \cx pt, -2 * \cy pt) -- (a);
\draw[line width=1cm,red,line cap=rect] (a) -- (c);
\end{scope}
\end{tikzpicture}
\end{document}

可怕的计算只是找到一个平分向量 (a)->(b) 和 (a)->(c) 之间夹角的点。我们通过找到从 (a) 到 (b) 的直线上的点来实现这一点,该点的距离与 (c) 到 (a) 的距离相同,然后找到该点和 (c) 之间的中点。这个中点(或者说,从 (a) 到该点的相对向量)就是我们想要的向量。然后,我们绘制两个四边形,它们的基本特性是,在 (a) 附近,它们的角度与它们平分角度 (b)(a)(c) 成一角,并且足够大以容纳其余路径。

分割色彩路径

这种方法很可靠,因为更改三个点的坐标可以正常工作。不可靠的地方在于,如果路径更复杂,那么裁剪框将需要更复杂才能容纳它们。正如我所说,可能还有更简洁的方法,使用更多内部内容来实现这一点。

答案2

请原谅我添加了第二个答案,但由于想法完全不同,我认为这样更利于组织。

以下解决方案完全自动化,不需要任何数学运算。它适用于任何角度(0 度和 180 度除外),但如果大于 180 度,您可能需要交换部分belowabove。此外,对于非常锐角,您可能需要添加一些剪辑(并参见下面的注释pos)。

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{calc,intersections}
\begin{document}

\begin{tikzpicture}[scale = 3]
    \def\linewidth{5pt}
    \def\pointa{(0,0)}
    \def\pointb{(0,1)}
    \def\pointc{(1,2)}
    \path \pointa -- 
        node[pos=0,coordinate,sloped,above=\linewidth/2] (tmp1-1) {} 
        node[pos=2,coordinate,sloped,above=\linewidth/2] (tmp1-2) {}
        node[pos=0,coordinate,sloped,below=\linewidth/2] (tmp1-3) {}
        node[pos=2,coordinate,sloped,below=\linewidth/2] (tmp1-4) {}
        \pointb;
    \path \pointb -- 
        node[pos=-1,coordinate,sloped,above=\linewidth/2] (tmp2-1) {} 
        node[pos=1,coordinate,sloped,above=\linewidth/2] (tmp2-2) {}
        node[pos=-1,coordinate,sloped,below=\linewidth/2] (tmp2-3) {}
        node[pos=1,coordinate,sloped,below=\linewidth/2] (tmp2-4) {}
        \pointc;

    \path[name path=line11] (tmp1-1) -- (tmp1-2);
    \path[name path=line12] (tmp1-3) -- (tmp1-4);
    \path[name path=line21] (tmp2-1) -- (tmp2-2);
    \path[name path=line22] (tmp2-3) -- (tmp2-4);

    \path[name intersections={of=line11 and line21}] node[coordinate] (i1) at (intersection-1) {};
    \path[name intersections={of=line12 and line22}] node[coordinate] (i2) at (intersection-1) {};

    \fill[red] (tmp1-1) -- (i1) -- (i2) -- (tmp1-3) -- cycle;
    \fill[blue] (tmp2-2) -- (i1) -- (i2) -- (tmp2-4) -- cycle;
\end{tikzpicture}
\end{document}

首先,我们在线的两侧创建一些节点,距离中心有一半线宽。末端节点应恰好位于路径末端的高度,但中间节点需要延伸一点。对于非常短的路径和较大的线宽或非常锐角,您可能需要将值设置为pos=2pos=-1更大。另一方面,对于“合适的比例”,您可能需要将它们缩小,以便节点不会扩大您的边界框。(或者只是在之后重置边界框。)

我们使用这些节点来指定我们想要绘制的线条两侧的一些路径,然后与这些路径相交以获得颜色应该相遇的点。

最后,我们不再画线,而是使用 TikZ 为我们计算的所有点来填充两个形状。

结果

答案3

这里还有另一个答案。我在思考如何实现clipTeX-SX 包的解决方案,以及如何处理确保剪辑路径只剪辑正确部分的问题,并想到了一个完全不同的解决方案。这个解决方案定义了一组新的箭头,它们根据某个设定的角度使线变得尖锐。

代码如下:

\documentclass{standalone}

\usepackage{tikz}

\makeatletter

\pgfkeys{
  /tikz/sharp arrow angle/.code={%
    \pgfsetarrowoptions{sharp left}{#1}
    \pgfsetarrowoptions{sharp right}{#1}
  },
  /tikz/sharp left arrow angle/.code={%
    \pgfsetarrowoptions{sharp left}{#1}
  },
  /tikz/sharp right arrow angle/.code={%
    \pgfsetarrowoptions{sharp right}{#1}
  }
}

\tikzset{sharp arrow angle=30}

\pgfarrowsdeclare{sharp left}{sharp left}{%
  \pgfmathsetlength{\pgf@xa}{.5*\pgflinewidth * tan(\pgfgetarrowoptions{sharp left})}
  \pgfarrowsleftextend{\pgf@xa}
  \pgfarrowsrightextend{\pgf@xa}
}{%
  \pgfmathsetlength{\pgf@xa}{\pgflinewidth * tan(\pgfgetarrowoptions{sharp left})}
  \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{-.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{0pt}{-.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{\pgf@xa}{.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{.5\pgflinewidth}}
  \pgfusepathqfill
}
\pgfarrowsdeclare{sharp right}{sharp right}{%
  \pgfmathsetlength{\pgf@xa}{.5*\pgflinewidth * tan(\pgfgetarrowoptions{sharp right})}
  \pgfarrowsleftextend{\pgf@xa}
  \pgfarrowsrightextend{\pgf@xa}
}{%
  \pgfmathsetlength{\pgf@xa}{\pgflinewidth * tan(\pgfgetarrowoptions{sharp right})}
  \pgfpathmoveto{\pgfqpoint{-.1\pgflinewidth}{.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{0pt}{.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{\pgf@xa}{-.5\pgflinewidth}}
  \pgfpathlineto{\pgfqpoint{-.1\pgflinewidth}{-.5\pgflinewidth}}
  \pgfusepathqfill
}

\makeatother

\begin{document}
\begin{tikzpicture}
\path (0,2) rectangle (9,-6);
\draw[line width=3cm,red,sharp arrow angle=60,-sharp left] (0,0) -- (6,0);
\draw[line width=3cm,blue,sharp arrow angle=60,sharp right-] (6,0) -- +(-120:6);
\draw[thick,blue] (0,0) -- (6,0);
\draw[thick,red] (6,0) -- +(-120:6);
\end{tikzpicture}
\end{document}

结果如下:

使用箭头改变路径颜色

矩形只是为了确保边界框足够大(箭头尖似乎被忽略了)。另外两条线是为了显示尖线在正确的位置相交。

答案4

这是一个概念验证。它有很多实现问题需要解决才能实现自动化,但 Ulrike 的回答TikZ 中的线条交叉不良给了我一个想法,教我如何通过一个非常巧妙的技巧做到这一点。基本上,你绘制路径到连接点,然后每个路径都转向平分线路径。那个转弯形成一个很好的尖角。如果转弯路径的部分长度合适,这是一种让路径以一定角度结束的廉价方法。从图片中你可以看到,它不是 100% 完美的,因为有一些额外的填充(试着缩短延伸部分,看​​看我为什么要这么做)。代码中的数字是通过反复试验获得的(尽管我相信它们可以自动化)。

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}

\begin{tikzpicture}[line width=7]
\draw[red] (0,0) -- ($(1,1)+(-.5\pgflinewidth,-.5\pgflinewidth)$) -- +(180:.35\pgflinewidth);
\draw[green] (0,2) -- ($(1,1)+(-.5\pgflinewidth,.5\pgflinewidth)$) -- +(180:.35\pgflinewidth);
\end{tikzpicture}
\end{document}

结果:

改变线条弯曲处的颜色

相关内容