我有这条路径,我想从单一规范的角度对其进行“分段”样式设置,如下图所示:
正如图片所示,我想装饰 2-3 和 5-6 段,并只为 3-4 着色。我想用snake
(正弦装饰)装饰 2-3 段,这意味着向上的 1-2 段应该被绘制成不可见的(有点像 moveto)。
问题在于,正如图像上所看到的,我在第三张图片上完全没有得到任何装饰,这意味着我没有得到分段样式和装饰的正确语法(如果可能的话)。
我的问题是 - 我怎样才能实现我想要的那种装饰,但只用一条“线”(用一个坐标的路径规范)?到目前为止的 MWE 如下:
% \documentclass{article}
\documentclass[varwidth,tightpage,border=1bp]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usetikzlibrary{decorations.pathmorphing} % (solid) snake :)
\usetikzlibrary{decorations.pathreplacing} % show path construction
\pagecolor{yellow!15} % ignored with preview, but not w/ varwidth
\begin{document}
This is the plain linear path:
\begin{tikzpicture}
\draw[]
(0,0) -- ++(1,0) node[fill,scale=0.5](A){}
-- +(0,1) -- +(0,-1) -- ++(1,0)
-- ++(2,1) -- ++(0,-1) -- ++(1,0);
\end{tikzpicture}
This is the path construction:
\gdef\cnt{0}
\begin{tikzpicture}
\draw[decoration={show path construction,
moveto code={
\fill [red] (\tikzinputsegmentfirst) circle (2pt);
},
lineto code={
\pgfmathtruncatemacro{\tmp}{\cnt+1} \xdef\cnt{\tmp} %
\ifnum\cnt=2{\gdef\tw{3pt}}\else{\gdef\tw{1pt}}\fi %
\ifnum\cnt=3{\gdef\tc{blue!50}}\else{\gdef\tc{blue}}\fi %
\draw [draw=\tc,line width=\tw,->] (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast) node[fill=none,draw=green,minimum size=2pt,font=\bf]{\tmp};
},
closepath code={
%\draw [draw=none] (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast);
},
},
decorate]
(0,0) -- ++(1,0) node[fill,scale=0.5](A){}
-- +(0,1) -- +(0,-1) -- ++(1,0)
-- ++(2,1) -- ++(0,-1) -- ++(1,0);
\end{tikzpicture}
Attempt at decorating only segments\\ 2-3 and 5-6, and coloring only 3-4
\begin{tikzpicture}
\draw[]
(0,0) -- ++(1,0) node[fill,scale=0.5](A){}
{ [draw=none]-- +(0,1) }
{ [decorate,decoration={snake},draw=red]-- +(0,-1) } % 2-3
{ [draw=green]-- ++(1,0) }
-- ++(2,1)
{ [decorate,decoration={snake},draw=red]-- ++(0,-1) } %5-6
-- ++(1,0);
\end{tikzpicture}
\end{document}
答案1
好的,我找到了一种部分解决方案,所以我将在这里发布它...这是我使用下面发布的 MWE 获得的输出:
首先要记住的是,如果你认为括号{}
在路径中有任何类型的分组\draw
,那么它们确实不是;您可以尝试[draw=green]{-- ++(1,0)}
或者{ [draw=green]-- ++(1,0)}
——但颜色将被忽略,或者将被全局应用于路径。
第二件事是,有一种使用装饰来解决这个问题的方法,但不能使用元装饰。元装饰和常规装饰一样,基本上是沿着一条线重复图案(换句话说,它们重复状态);在这里我想将单独的样式应用于特定的(即随机的)线段;因此,像这样的装饰的完整功能不适用于这个问题。
什么是不过,适用的是,有一个decoration=moveto
,它实际上可以按原样使用来“隐藏”任意线段。问题是,语法与我的 Tikz & PF 手册版本(2.10 版手册)中的内容直接矛盾:
事实上,下面两个命令有同样的效果:
1.\path decorate[ options ] { path };
2.\path [decorate, options ] path ;
好吧,至少在我的版本中,幸运的是,这是不正确的;如果你写:
decorate[decoration=moveto]{ -- +(0,1) }
- 然后装饰将被应用仅有的到括号内的线段,我想要[decorate,decoration=moveto]{ -- +(0,1) }
- 那么装饰要么被忽略,要么被全局应用
因此,至少对于隐藏和snake
没有其他要求的装饰来说,这是可行的。但我们可以应用个人样式吗?大多数情况下,在装饰[]
选项中输入颜色或线宽选项将被忽略(或全局应用)。
因此,在下面的代码中,有一个名为的自定义装饰example
。它基本上跳过了它的{initial}
状态,然后直接进入{final}
。在那里,它首先使用输出到该点建立的路径\pgfusepath
- 但是,应该注意的是\pgfusepath
杀死全局路径到该点为止,因此您必须至少手动指定moveto
一个点,以便进一步的路径构建结构能够工作。然后保存“当前”描边颜色,并从之前设置的选项中读取新颜色(参见读取 - 以及效果 - (默认) tikz/pgf 键?了解全局 TikZ 选项键如何工作的陷阱)。
然后设置;然后线段完成,然后\pgfusepath
再次调用,以便路径输出样式 - 但这再次破坏了全局路径,所以我们必须至少再次移动。然后,由于我们还想在那里重置回原始颜色,我们重新设置回之前设置的默认设置 - 但我们必须再次调用\pgfusepath
来设置新颜色(:)
),并且由于这会破坏全局路径,因此我们必须在此之后至少移动一次。呼!:D
最后,这允许对线段进行单独样式设置 - 但这并不完美;如果您指定例如\draw[line width=1pt]
,您会看到它仅适用于最后的线段(显然,因为引入了所有破坏\pgfusepath
)。
以下是生成上述图像的代码:
\documentclass[varwidth,tightpage,border=1bp]{standalone}
\usepackage{tikz}
\usetikzlibrary{scopes} %% nope
\usetikzlibrary{decorations}
\usetikzlibrary{decorations.pathmorphing} % (solid) snake :)
\usetikzlibrary{decorations.pathreplacing} % show path construction
\pagecolor{yellow!15} % ignored with preview, but not w/ varwidth
\makeatletter
\global\let\tmpmc\relax \global\let\tmpcc\relax
\pgfdeclaredecoration{example}{initial}
{
% {initial} is done for as long
% as \pgfdecoratedremainingdistance < width;
% but for 0pt it loops indefinitely!
% > "First, this option causes an immediate switch
% > to the state final if the remaining distance
% > on the input path is less than dimension."
% When \pgfdecoratedremainingdistance+1pt, indeed
% it jumps immediately, nothing inside executes;
\state{initial}[width=\pgfdecoratedremainingdistance+1pt]
{
% this will never print
\typeout{decoration{example} INITIAL} %
}
\state{final}
{
% example for printing coordinates of point:
% (note, here \pgfpointdecoratedinputsegmentlast
% is same as \pgfpointdecoratedpathlast)
\pgfpointdecoratedpathlast % first go here, at this point
\pgfgetlastxy{\dcplx}{\dcply} % grab coords in macros
\typeout{dcpl \dcplx, \dcply} % print coords to stdout
%
% NOTE:
% > "\pgfusepath{ actions } Applies the given
% > actions to the current path. Afterwards,
% > the current path is (globally) empty."
% print all the path, up to now, with default (black) color
\pgfusepath{draw,stroke} %
%
% remember the current (old), set the new color
\makeatletter %
\typeout{\string\color@pgf@tempcolor, % \color@pgf@tempcolor,
\csname\string\color@pgf@tempcolor\endcsname} % 0 g 0 G
\extractcolorspec{pgf@tempcolor}{\tmpc} %
\extractcolorspecs{pgf@tempcolor}{\tmpmc}{\tmpcc} %
\typeout{tmpc \tmpc} % tmpc {gray}{0}
\typeout{tmpmc \tmpmc, tmpcc \tmpcc} % tmpmc gray, tmpcc 0
\makeatother %
% get the new color from previously set key:
\pgfkeysgetvalue{/tikz/draw}{\tmpdraw} %
\typeout{tmpI \tmpdraw} % tmpI green
% finally, set new color as stroke color
% (green!50 works here; note black!0 is transparent!)
\pgfsetstrokecolor{\tmpdraw} %
%
% since now after \pgfusepath, the global path is dead/cleaned;
% have to reinitialize the global path first by a moveto
% (else the lineto after, doesn't know what to lineto from)
% happily, here the coord system is local to the segment,
% so 0.0pt refers to the first point of the segment
\pgfpathmoveto{\pgfpoint{0pt}{0pt}}
\pgfpathlineto{\pgfpointdecoratedpathlast} %
%
% must usepath again, to output stroked
\pgfusepath{draw,stroke} %
%
% now global path is dead again - so move to the
% end point; but we'll have to reset the color...
%\color[gray]{0.5} % this resets the stroke color to default,
% but does not set it! ok syntax, complains
% if range not [0,1]
%\colorlet{tmpold}[gray]{0.5} % no can do
%\definecolor{tmpold}{gray}{0.5} % ok
\definecolor{tmpold}{\tmpmc}{\tmpcc} %
\pgfsetstrokecolor{tmpold} %
\pgfpathmoveto{\pgfpointdecoratedpathlast}
% moveto is enough here, no need for \pgfpathlineto
% must usepath again, to output stroked
% (print all up to now with black)
\pgfusepath{draw,stroke} %
%
% now global path is dead again - move to the end
\pgfpathmoveto{\pgfpointdecoratedpathlast}
% now further subpaths can continue to
% append to the last point here...
}
}
\makeatother
\begin{document}
This is the plain linear path:
\begin{tikzpicture}
\draw[]
(0,0) -- ++(1,0) node[fill,scale=0.5](A){}
-- +(0,1) -- +(0,-1) -- ++(1,0)
-- ++(2,1) -- ++(0,-1) -- ++(1,0);
\pgfkeysgetvalue{/tikz/color}{\tmp}\typeout{tmpX \tmp \meaning\tmp}
\end{tikzpicture}
This is the path construction:
\gdef\cnt{0}
\begin{tikzpicture}
\draw[decoration={show path construction,
moveto code={
\fill [red] (\tikzinputsegmentfirst) circle (2pt);
},
lineto code={
\pgfmathtruncatemacro{\tmp}{\cnt+1} \xdef\cnt{\tmp} %
\ifnum\cnt=2{\gdef\tw{3pt}}\else{\gdef\tw{1pt}}\fi %
\ifnum\cnt=3{\gdef\tc{blue!50}}\else{\gdef\tc{blue}}\fi %
\draw [draw=\tc,line width=\tw,->] (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast) node[fill=none,draw=green,minimum size=2pt,font=\bf]{\tmp};
},
closepath code={
%\draw [draw=none] (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast);
},
},
decorate]
(0,0) -- ++(1,0) node[fill,scale=0.5](A){}
-- +(0,1) -- +(0,-1) -- ++(1,0)
-- ++(2,1) -- ++(0,-1) -- ++(1,0);
\end{tikzpicture}
Attempt at decorating only segments\\ 2-3 and 5-6, and coloring only 3-4
% \edef\dcA{decorate[decoration={lineto,},green]} % color no effect here
\def\dcA{decorate[decoration={example,/tikz/draw/.initial=green,},every path/.append style={line width=1pt}]} % color ok, line width no effect here
\begin{tikzpicture}
\draw[line width=1pt]
% start here:
(0,0)
% (default) line to here:
-- ++(1,0)
% place node:
node[fill,scale=0.5](A){}
% line, but hidden (moveto):
decorate[decoration=moveto]{ -- +(0,1) }
% only this segment, decorate snake:
decorate[decoration={snake,}]{ -- +(0,-1) } % 2-3
% only this segment, decorate example (green):
\dcA{ -- ++(1,0) }
% (default) line to here:
-- ++(2,1)
% only this segment, decorate snake:
% [decorate,decoration={snake},red] out here
% would be applied globally! (but only from
% the end of example decoration)
% with decorate[decoration={snake},red],
% the red is ignored.
decorate[decoration={snake},red]{ -- ++(0,-1) } %5-6
% (default) line to here:
-- ++(1,0)
;
\end{tikzpicture}
\end{document}