TikZ:后续执行类型/.code 键

TikZ:后续执行类型/.code 键

我正在尝试创建一些 TikZ 键,以便轻松在机械结构(或桁架)上绘制分布式负载。我目前编写的代码是:

\documentclass[a4paper]{article}

\usepackage{tikz}
\usetikzlibrary{calc,positioning}
\makeatletter
\tikzset{load start/.style={insert path={coordinate (mec@start@load)}},%
         load end/.style={insert path={coordinate (mec@end@load)}},
         load distance/.initial=1em,
         force distance/.initial=10pt,
         force length/.initial=.7cm}
\tikzset{forze/.code={%
    \coordinate (mec@X1) at ($(mec@start@load)!\pgfkeysvalueof{/tikz/load distance}!90:(mec@end@load)$);
    \coordinate (mec@X2) at ($(mec@end@load)!\pgfkeysvalueof{/tikz/load distance}!-90:(mec@start@load)$);
    \draw (mec@X1) -- (mec@X2);
    \pgfpointdiff{\pgfpointanchor{mec@X1}{center}}{\pgfpointanchor{mec@X2}{center}}
    \pgfmathsetmacro{\mec@force@distrib@lenght}{veclen(\pgf@x,\pgf@y)}
    \pgfmathsetmacro{\mec@force@number}{round(\mec@force@distrib@lenght/\pgfkeysvalueof{/tikz/force distance})}
    \pgfmathsetmacro{\mec@force@distance}{1/\mec@force@number}
    \pgfmathparse{1-\mec@force@distance}
    \foreach \i in {0,\mec@force@distance,...,\pgfmathresult}{
      \coordinate (endarrow) at   ($(mec@X1)!\i!(mec@X2)$);
      \coordinate (startarrow) at ($(endarrow)!\pgfkeysvalueof{/tikz/force length}!90:(mec@X2)$);
      \draw[-latex] (startarrow) -- (endarrow);
    }
    \coordinate (endarrow) at   ($(mec@X1)!1!(mec@X2)$);
    \coordinate (startarrow) at ($(mec@X2)!\pgfkeysvalueof{/tikz/force length}!-90:(mec@X1)$);
    \draw[-latex] (startarrow) -- (endarrow);
  }}%}
\makeatother
\begin{document}
\begin{tikzpicture}[node distance=1mm]
\coordinate (a) at (0,0) node[left=of a]{A};
\coordinate (b) at (0,3) node[left=of b]{B};
\coordinate (c) at (3,3) node[right=of c]{C};
\coordinate (d) at (3,0) node[right=of d]{D};
\draw[thick] (a) -- (b) [load start] -- (c) [load end] -- (d);
\path[forze] (a);
\draw (d) [load start] -- (b) [load end];
\path[forze] (a);
\end{tikzpicture}
\begin{tikzpicture}[node distance=1mm]
\coordinate (a1) at (0,0) node[left=of a1]{A1};
\coordinate (b1) at (0,3) node[left=of b1]{B1};
\coordinate (c1) at (3,3) node[right=of c1]{C1};
\coordinate (d1) at (3,0) node[right=of d1]{D1};
\draw[thick] (a1) -- (b1) [load start] -- (c1) [load end,forze] -- (d1);
\draw[forze] (a1) -- (d1);
\end{tikzpicture}
\end{document}

load start和键load end仅用于保存分布载荷的起始和终止坐标,而 键forze使用这些坐标并以正确的方式绘制基线和所有箭头。在第一个示例中,一切正常,但如您所见,要获得正确的输出,必须定义另一个使用 键的路径(在使用load start和的路径之后) 。load endforze

在第二个例子中,我展示了我想要使用的语法(基本上我想避免定义第二个“假”路径的必要性)但你可以看到有些错误:

  • 第一种情况,箭头出现了,但是指定的路径消失了(结构消失了);
  • 在第二种情况下,路径在那里(从d1到 的线a1),但箭头与之前的箭头重叠。

我认为这种情况发生是因为键中定义的代码forze处理得太早,此时加载的起始和结束坐标尚未正确保存。我尝试使用append after commandexecute at end toexecute at end note键,但结果始终相同。有没有更好的方法?

另一个问题:在键内定义宏(如\mec@force@number)是否正确(如)还是最好在键外定义它们?从“寄存器消耗”的角度来看,哪个更好?\pgfmathsetmacroforze

更新

正如 @percusse 所建议的,我尝试使用preactionpostaction键。我尝试了以下可能性:

\draw[postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);

完美的结果

\draw[thick,postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);
% or
\draw[thick][postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);
% or
\draw[thick][postaction={forze,thin}] (a) -- (b) [load start] -- (c) [load end] -- (d);

不好的结果:负载似乎太厚

\draw[preaction={draw,thick},postaction={forze}] (a) -- (b) [load start] -- (c) [load end] -- (d);

完美的结果,但对用户来说并不透明(应该使用密钥preaction)。因此,似乎第二次使用该路径时,它会自动从第一次路径中获取选项(手册说选项不同,但似乎只有在重新定义相同的选项时才如此)。是否可以避免这种情况,允许在路径上正常指定选项并仅用于postaction={forze}绘制负载(可以通过特定密钥轻松完成)?

答案1

这里的困难在于并非所有选项都以相同的方式处理。您可以将它们粗略地分为“低”和“高”,以及“立即”和“延迟”。

低级选项指的是设置一些 TeX 宏或类似内容的选项。这些选项包括设置线宽、颜色等。基本样式选项。高级选项是设置更多内容的选项,例如设置后续操作。

立即选项是在调用时立即处理的选项。延迟选项是稍后进行实际设置部分(显然在调用时必须执行某些操作,但实际选项是在稍后设置的)。线宽是立即设置的,颜色是延迟设置的。

另一个考虑因素是,许多由 TeX 宏(或类似宏)控制的低级样式遵循 TeX 分组。

考虑到这一点,您最新代码的问题在于,您在主路径上设置选项,并且这些选项在后操作路径中持续存在,因为它位于同一组中,因此这些样式选项会持续存在。因此,如果您希望这些选项不适用于后操作路径,则需要事先保存样式,然后在后操作路径中恢复它。但您需要考虑延迟因素。

因此,以下代码对此略有介绍。当forze调用该键时,此时有效的样式(当前为线宽和颜色,但您可以轻松添加更多内容)将被保存 - 但由于某些选项的延迟,这可能不是您认为的样式。最安全的做法是forze在路径上使用 first。

\documentclass[a4paper]{article}
%\url{http://tex.stackexchange.com/q/75904/86}

\usepackage{tikz}
\usetikzlibrary{calc,positioning}
\makeatletter
\tikzset{load start/.style={insert path={coordinate
(mec@start@load)}},%
         load end/.style={insert path={coordinate (mec@end@load)}},
         load distance/.initial=1em,
         force distance/.initial=10pt,
         force length/.initial=.7cm,
         forze/.code={%
           \tikzset{
             save style=\forze@style,
             postaction={forze code},
           }
         },
         save style/.code={%
           \pgfutil@colorlet{forze@color}{.}%
           \edef#1{%
             line width=\the\pgflinewidth,
             color=forze@color,
           }
         },
         restore style/.code={%
           \expandafter\tikzset\expandafter{#1}%
         }
}
\tikzset{forze code/.code={%
    \message{got called}%
    \begin{scope}[restore style=\forze@style]%
    \coordinate (mec@X1) at
($(mec@start@load)!\pgfkeysvalueof{/tikz/load
distance}!90:(mec@end@load)$);
    \coordinate (mec@X2) at
($(mec@end@load)!\pgfkeysvalueof{/tikz/load
distance}!-90:(mec@start@load)$);
    \draw (mec@X1) -- (mec@X2);
    \pgfpointdiff{\pgfpointanchor{mec@X1}{center}}{\pgfpointanchor{mec@X2}{center}}
    \pgfmathsetmacro{\mec@force@distrib@lenght}{veclen(\pgf@x,\pgf@y)}
    \pgfmathsetmacro{\mec@force@number}{round(\mec@force@distrib@lenght/\pgfkeysvalueof{/tikz/force
distance})}
    \pgfmathsetmacro{\mec@force@distance}{1/\mec@force@number}
    \pgfmathparse{1-\mec@force@distance}
    \foreach \i in {0,\mec@force@distance,...,\pgfmathresult}{
      \coordinate (endarrow) at   ($(mec@X1)!\i!(mec@X2)$);
      \coordinate (startarrow) at
($(endarrow)!\pgfkeysvalueof{/tikz/force length}!90:(mec@X2)$);
      \draw[-latex] (startarrow) -- (endarrow);
    }
    \coordinate (endarrow) at   ($(mec@X1)!1!(mec@X2)$);
    \coordinate (startarrow) at ($(mec@X2)!\pgfkeysvalueof{/tikz/force
length}!-90:(mec@X1)$);
    \draw[-latex] (startarrow) -- (endarrow);
    \end{scope}
  }}%}
\makeatother
\begin{document}
\begin{tikzpicture}[node distance=1mm]
\coordinate (a) at (0,0) node[left=of a]{A};
\coordinate (b) at (0,3) node[left=of b]{B};
\coordinate (c) at (3,3) node[right=of c]{C};
\coordinate (d) at (3,0) node[right=of d]{D};
\draw[forze,ultra thick,red] (a) -- (b) [load start] -- (c) [load end]
-- (d);
\end{tikzpicture}

\begin{tikzpicture}[node distance=1mm]
\coordinate (a) at (0,0) node[left=of a]{A};
\coordinate (b) at (0,3) node[left=of b]{B};
\coordinate (c) at (3,3) node[right=of c]{C};
\coordinate (d) at (3,0) node[right=of d]{D};
\draw[red,ultra thick,forze] (a) -- (b) [load start] -- (c) [load end]
-- (d);
\end{tikzpicture}
\end{document}

相关内容