![如何提高通用曲线。\pgfdeclaredecoration 的问题](https://linux22.com/image/241586/%E5%A6%82%E4%BD%95%E6%8F%90%E9%AB%98%E9%80%9A%E7%94%A8%E6%9B%B2%E7%BA%BF%E3%80%82%5Cpgfdeclaredecoration%20%E7%9A%84%E9%97%AE%E9%A2%98.png)
我想要实现的目标是通过 TikZ 命令定义一条与通用曲线平行的曲线\draw
。为了实现它,我使用了 TikZ 装饰库和命令 \pgfdeclaredecoration 来创建它。我采用的解决方案效率不高,但从概念上讲是可行的。这是我的清单的一个最小示例:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,decorations}
\makeatletter
\newlength\@l
\newcount\@c
\tikzset{
raise line/.initial = 25pt,
raise points/.initial = 100
}
\pgfdeclaredecoration{Parallel Line}{initial}{
\state{initial}[persistent precomputation={%
\pgfmathsetlength{\@l}%
{\pgfdecoratedpathlength/(\pgfkeysvalueof{/tikz/raise points})}%
\@c=1%
},
next state = middle,
width =\@l]{\coordinate (DecoratedPointRaised-\the\@c) at
($(0,0)+(0,\pgfkeysvalueof{/tikz/raise line})$);}
\state{middle}[persistent precomputation = {\@c=\numexpr\the\@c+1\relax},
width = \@l]{\coordinate (DecoratedPointRaised-\the\@c) at
($(0,0)+(0,\pgfkeysvalueof{/tikz/raise line})$);}
\state{final}[persistent precomputation = {\@c=\numexpr\the\@c+1\relax},
persistent postcomputation = {\foreach[count=\t from 1]\n in{2,...,100}{ %
\draw (DecoratedPointRaised-\t)-- % Here it does not work!!
(DecoratedPointRaised-\n);}}]{ %
\pgfcoordinate{DecoratedPointRaised-\the\@c}{\pgfpointdecoratedpathlast}
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\draw[decorate,decoration=Parallel Line] (0,0) .. controls++(1,1) and (6,-3).. (7,0);
%\foreach[count=\t from 1]\n in{2,...,100}{ %
% \draw (DecoratedPointRaised-\t)--(DecoratedPointRaised-\n); % Here it works!!!!
%} %
\end{tikzpicture}
\end{document}
这是我画的:
下面这一行是原有的,上面这一行是装饰的。
创建平行曲线的步骤如下:
- 我创建了一个新的长度
\@l
,它是步长decoration
。我创建了一个新的计数器,\@c
以便拥有我将要创建的坐标的顺序名称。 - 第一个状态是
initial
计算间距\@l
并在开始时\@c
将其设置为 1。然后DecoratedPointRaised-\the\@c
创建系列的第一个坐标。完成初始状态后,装饰将传递到中间状态。 - 在中间状态预计算中,将新的计算
\@c
为\@c=\@c+1
。\@c
创建坐标后。 - 必要时,装饰将进入最终状态,
\@c
计算最后一个坐标。在这里,我使用后计算来绘制连接所有创建的坐标的所有线段。
问题是最终状态下的后计算不起作用,而如果我在命令之后在其中写入代码\draw
,则不会出现问题。为什么?我该如何避免?
在最终状态下,我在命令中使用的坐标系是\state
全局坐标系而不是变换后的坐标系吗?
答案1
这似乎也适用于行首的一个小工件double
,但使用的是 TikZ v2.10 的标准版本。
\usetikzlibrary{decorations.markings}
\tikzset{forcedist/.style={decorate, decoration={markings,
mark=between positions 0 and 1 step 0.0999 with {\draw[<-] (0,-#1) -- (0,#1); }}}}%Here
\begin{tikzpicture}
\draw [double distance = 1cm,thick] (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\draw [forcedist=5mm] (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\draw [double distance = 5mm,thick] (0,3) --++(8,0);
\draw [forcedist=2.5mm] (0,3)--++(8,0);
\end{tikzpicture}
导致
您可以相当轻松地调整箭头的间距和梁的高度。请注意切线计算的奇怪不匹配。直线不会受到此影响。
我没有尝试将这两个命令结合起来,首先我不知道这是否是你想要的,其次你可以使用自己的代码来绘制移动的线并将其添加到其顶部。
编辑:我使用的方法如下:我将装饰物覆盖到double line
。我提供了位于 的坐标中间或者中心这条装饰线的坐标,而不是边的坐标。但可能你正在使用坐标作为其中一条边并复制它,因为其中一条黑线从红色曲线的中心穿过。我会尝试将其融入代码中。
编辑2为了能够使用给定的路径作为边缘,我认为你可以使用\pgfsetinnerlinewidth{}
第 73.2.7 节中给出的命令内线在 TikZ v2.10 手册中。我还没有尝试过,但似乎是最简单的方法。
编辑3(作者:Andrew Stacey)以下是获取指定线上箭头的略显临时的方法。我们绘制双线,但将其自身裁剪,以便只绘制一半(参见有没有办法在路径的“内部”或“外部”绘制 TikZ 线?有关此技术的更多信息)。这是设计中最粗糙的部分:由于路径没有闭合,我们需要闭合它们以制作剪辑。然后我们绘制线本身。最后,我们使用 percusse 的装饰来装饰它,只是我们调整坐标以使箭头的底部位于线上。
\documentclass{standalone}
%\url{https://tex.stackexchange.com/q/31707/86}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}
\tikzset{forcedist/.style={decorate, decoration={markings,
mark=between positions 0 and 1 step 0.0999 with {\draw[->] (0,0) -- (0,-#1); }}}}%Here
\begin{document}
\begin{tikzpicture}
\begin{scope}
\clip[overlay] (0,0) .. controls++(1,1) and (6,-3).. (7,0) -- ++(3,0) -- ++(0,-5) -- ++(-13,0) -- ++(0,5) -- cycle;
\draw [double distance=2cm,thick] (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\end{scope}
\draw [thick] (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\draw [forcedist=1cm] (0,0) .. controls++(1,1) and (6,-3).. (7,0);
\begin{scope}
\clip[overlay] (0,3) -- ++(8,0) -- ++(3,0) -- ++(0,-5) -- ++(-13,0) -- ++(0,5) -- cycle;
\draw [double distance=2cm,thick] (0,3) --++(8,0);
\end{scope}
\draw [thick] (0,3) --++(8,0);
\draw [forcedist=1cm] (0,3)--++(8,0);
\end{tikzpicture}
\end{document}
结果:
(初始箭头看起来那样是因为该点处的线的曲率。)
答案2
我可以提供一个解决方案,它只能使用 LuaLaTeX 和最新版本的 PGF 2.10-CVS 进行编译,因为它将 luamath 功能引入 pgf。以下是清单
% !TEX encoding = UTF-8
% !TEX program = LuaLaTeX
% !TEX spellcheck = en_GB
\documentclass{standalone}
%\usepackage[margin=2.5cm,left=3cm]{geometry}
\usepackage{tikz}
\usepgflibrary{luamath}
\pgfkeys{/pgf/luamath=true}%<-Put it fase to see what happen
\usetikzlibrary{decorations}
\makeatletter
\newlength\pgf@distributed@force@pitch
\newcount\pgf@distributed@force@new@point
\newcount\pgf@distributed@force@old@point
\newcount\pgf@distributed@force@pitch@points
\tikzset{
distributed force intensity/.initial = 20pt,
distributed force angle/.initial = 90,
distributed force intervals/.initial = 8,
distributed force points/.initial = 200,%<-I used this value because it does not give problems at path end.
% change it to see what I mean
}
\pgfdeclaredecoration{Distributed Force}{initial}{
\state{initial}[persistent precomputation={%
\pgfmathsetmacro{\pgf@distributed@force@draw@arrow@index}%
{\pgfkeysvalueof{/tikz/distributed force points}/\pgfkeysvalueof{/tikz/distributed force intervals}}
\pgfmathsetlength{\pgf@distributed@force@pitch}%
{\pgfdecoratedpathlength/(\pgfkeysvalueof{/tikz/distributed force points})}%
},
next state = middle,
width =\pgf@distributed@force@pitch]
{\global\pgf@distributed@force@new@point=0%
\global\pgf@distributed@force@pitch@points=0%
\draw[<-] (0,0)--
(0,\pgfkeysvalueof{/tikz/distributed force intensity})
coordinate (DecoratedPointRaised-\the\pgf@distributed@force@new@point);}
\state{middle}[width=\pgf@distributed@force@pitch]
{\global\pgf@distributed@force@old@point=\pgf@distributed@force@new@point
\global\pgf@distributed@force@new@point=\numexpr\the\pgf@distributed@force@new@point+1\relax
\global\pgf@distributed@force@pitch@points=\numexpr\the\pgf@distributed@force@pitch@points+1\relax
\draw (0,\pgfkeysvalueof{/tikz/distributed force intensity})
coordinate(DecoratedPointRaised-\the\pgf@distributed@force@new@point)--
(DecoratedPointRaised-\the\pgf@distributed@force@old@point);
\ifnum\pgf@distributed@force@pitch@points=\pgf@distributed@force@draw@arrow@index
\draw[<-] (0,0)--(0,\pgfkeysvalueof{/tikz/distributed force intensity});
\global\pgf@distributed@force@pitch@points=0
\fi
}
\state{final}{\global\pgf@distributed@force@old@point=\pgf@distributed@force@new@point
\global\pgf@distributed@force@new@point=\numexpr\the\pgf@distributed@force@new@point+1\relax
\pgftransformshift{\pgfpointdecoratedpathlast}
\draw[<-] (0,0)--++(0,\pgfkeysvalueof{/tikz/distributed force intensity})
coordinate(DecoratedPointRaised-\the\pgf@distributed@force@new@point);
\draw (DecoratedPointRaised-\the\pgf@distributed@force@new@point)--
(DecoratedPointRaised-\the\pgf@distributed@force@old@point);
}
}
\makeatother
\tikzset{distributed force/.style = {postaction=decorate,decoration=Distributed Force}}
\begin{document}
\centering
\begin{tikzpicture}
\draw[distributed force,yshift=-3cm,distributed force intensity=10pt]
(0,1) .. controls (1,2) and (6,-2).. (7,0);
\draw[distributed force] (0,0)--++(8,0);
\end{tikzpicture}
\end{document}
这就是我得到的