tikz 路径的分段样式和装饰?

tikz 路径的分段样式和装饰?

我有这条路径,我想从单一规范的角度对其进行“分段”样式设置,如下图所示:

测试06.png

正如图片所示,我想装饰 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 获得的输出:

测试02b

首先要记住的是,如果你认为括号{}在路径中有任何类型的分组\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}

相关内容