如何让 newcommand 命令使用其自己的名称作为其范围内定义的 tikz 节点的名称?

如何让 newcommand 命令使用其自己的名称作为其范围内定义的 tikz 节点的名称?

如果有一个简单的方法可以避免在以下代码片段中键入(或复制)字符串“nameofthenewcommand”,那就太好了

\newcommand{\nameofthenewcommand}{%
\node (nameofthenewcommand) [] {etc};
}

其目的是在代码其他地方的大型 tikzpicture 中使用。

有类似的东西就好了

\newcommand{\nameofthenewcommand}{%
\node (rocn) [] {etc};
}

其中 rocn 是我刚刚编写的字符串,tikz 应该将其识别为具有“命令名称的反射”含义,从而促使它用字符串“nameofthenewcommand”替换它。

为了实现这一目标您有何建议?

答案1

命令\nodestuff宏为节点定义定义一个包装命令,并像宏一样命名节点。

\node然而,在我看来,这可能无法捕获任何可能的调用,并且用途有限,因为之后仍然需要记住节点名称。

\documentclass{article}

\usepackage{tikz}

\newcommand{\nodestuff}[3][]{%
  \expandafter\newcommand\csname #2\endcsname{%
    \node[#1] (#2) #3;
  }%
}
\begin{document}

\begin{tikzpicture}
  \nodestuff[blue]{foo}{{$E=mc^{2}$}}
  \nodestuff[blue]{foobar}{ at (3,4) {$E=(mc^{2})^{2} + (pc)^{2}$}}
  \foo
  \foobar
  \draw  (foo) -- (foobar) node[midway,right] {A};
\end{tikzpicture}

\end{document}

在此处输入图片描述

答案2

\definenode命令将节点名称作为参数,从而发出命令。参见示例;新命令将节点的坐标作为参数。

\documentclass{article}

\usepackage{tikz}
\usepackage{xparse}

\ExplSyntaxOn
% syntactic sugar
\NewDocumentCommand{\newnamecommand}{m}
 {
  \exp_args:Nc \newcommand{#1}
 }
\ExplSyntaxOff

\NewDocumentCommand{\definenode}{mom}{%
  % #1 = command (no backslash)
  % #2 (optional) = optional argument to \node
  % #3 = replacement text
  \IfNoValueTF{#2}
   {\newnamecommand{#1}[1]{\node (#1) at ##1 {#3};}}
   {\newnamecommand{#1}[1]{\node[#2] (#1) at ##1 {#3};}}%
}

% \foo will expand to "\node (foo) at #1 {$E=mc^2$};"
\definenode{foo}{$E=mc^2$}
% \baz will expand to "\node[blue] at #1 {Energy};"
\definenode{baz}[blue]{Energy}


\begin{document}

\begin{tikzpicture}
  \foo{(0,0)}
  \baz{(3,4)}
  \draw  (foo) -- (baz) node[midway,right] {A};
\end{tikzpicture}

\end{document}

在此处输入图片描述

答案3

如果您经常面临通过 创建控制序列标记的任务\csname..\endcsname,则可以使用 TeX' #{-表示法来定义一个宏\name,其中第一个左括号之前的标记将作为参数,而嵌套在第一个左括号和相应的右括号中的标记将作为另一个/第二个参数,并且在 TeX 处理来自第一个参数的标记之前,从第二个参数形成控制序列标记。

我详细说明了\name在线程中详细阐述了-macro定义控制序列,之后留有空格它于 2016 年 11 月 10 日在 TeX - LaTeX StackExchange 上启动。

\documentclass{article}

\usepackage{tikz}

\makeatletter
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
\newcommand\UD@exchange[2]{#2#1}%
\makeatother

\newcommand{\nodestuff}[3][]{%
  \name\newcommand{#2}{%
    \node[#1] (#2) #3;
  }%
}

\begin{document}

\begin{tikzpicture}
  \nodestuff[blue]{foonode}{{text at foonode}}
  \nodestuff[blue]{barnode}{ at (2,3) {text at barnode}}
  \foonode
  \barnode
  \draw  (foonode) -- (barnode);
\end{tikzpicture}

\end{document}

在此处输入图片描述

如果您更喜欢采用另一种方式,即从控制序列标记中获取名称,您可以让 TeX 应用\string并删除前面的转义字符(如果存在)。请注意一些极端情况,例如整数参数的值为\escapechar32/表示空格。
此外,整数参数产生字符标记的可能值范围\escapechar取决于引擎,即取决于使用的是 LuaTeX/XeTeX 还是“普通”TeX。

\documentclass{article}
\usepackage{tikz}
\usepackage{ifxetex, ifluatex}

\makeatletter

\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%

\newcommand\stringifysecond[2]{%
  \expandafter\UD@PassFirstToSecond\expandafter{\romannumeral0\innerstringifysecond#2}{#1}%
}%

\newcommand\innerstringifysecond{%
  \ifnum\escapechar=32 \expandafter\@gobble\else\expandafter\@firstofone\fi
  % In case escapechar is 32, you get a space as escapechar, thus do nothing
  % and have the space removed as terminator of the \romannumeral-expansion
  % that currently is in progress.
  {%
    \ifnum\escapechar<0 \expandafter\@secondoftwo\else\expandafter\@firstofone\fi
    {%
      \ifnum\escapechar>\ifxetex 1114111 \else\ifluatex 1114111 \else 255 \fi\fi
        \expandafter\@secondoftwo        
      \else
        \expandafter\@firstoftwo
      \fi
      {%
        % There is a non-space escapechar, thus gobble that escapechar 
        % as undelimited argument and insert space for terminating \romannumeral:      
        \@firstofone{\expandafter\expandafter\expandafter} \expandafter\@gobble
      }%
    }{%
      % There is no escapechar, thus just insert space for terminating \romannumeral:
      \@firstofone{\expandafter} %
    }%
  }%
  \string
}%
%
\newcommand{\nodestuff}[2][]{%
  \stringifysecond\innernodestuff{#2}{#1}{#2}%
}%
\newcommand\innernodestuff[4]{%
  \newcommand#3{%
    \node[#2] (#1) #4;
  }%
}%

\makeatother

\begin{document}

\begin{tikzpicture}
  \nodestuff[blue]{\foonode}{{text at foonode}}
  \nodestuff[blue]{\barnode}{ at (2,3) {text at barnode}}
  \foonode
  \barnode
  \draw  (foonode) -- (barnode);
\end{tikzpicture}

\end{document}

在此处输入图片描述

我们看一下无名节点/无名宏的特殊情况:

对无名控制序列标记进行字符串化,该标记反过来可以作为表达式扩展的结果而产生\csname\endcsname,或者可以由于在行尾标记反斜杠字符/类别代码为 0 的字符而产生,而整数参数的值为\endlinechar负数或大于 255(普通 TeX 和 XeTeX;使用 LuaTeX 时尝试分配大于 127 的值以\endlinechar产生错误消息并且不会执行)产生类别代码为 12(other) 的字符标记序列\csname\endcsname

相关内容