如何为 TikZ 中的每个节点执行一个宏?

如何为 TikZ 中的每个节点执行一个宏?

编辑: 我已经开始了威兹提克目标是让 WhizzyEdit 能够处理任意的 TikZ 代码。现在我已经在一个项目中使用了它,效果已经很好了。

背景:

WhizzyTeX是一个显示 dvi(或 pdf)实时更新的系统。当与 主动式DVI观众也具有能力(称为Whizzy编辑) 使用鼠标移动或调整元素大小。元素必须具有特殊标记,通过源特殊标记指示其位置和大小。在 advi 中,使用鼠标进行更改,然后将其带回 emacs,在代码中更改位置(基于行号和命令名称)。重新编译时,元素位于新位置。

要使此操作有效,请使用\adviedit宏。您可以将其包装在另一个宏中 - 只需告诉它新宏的名称,以便 WhizzyTeX 知道在源代码中要更改什么。此外,宏必须有一个类似于的第一个参数,{x=1.2,y=3.4}以便它知道如何编辑源代码。

我的问题:

有没有办法将源特技添加到 PGF/TikZ 基元中,以便 advi 知道所有 TikZ 节点的位置,从而能够移动它们?之后可能需要一些启发式方法来编辑源,但我认为我可以处理这部分。由于我对 PGF/TikZ 内部结构一无所知,我不知道是否有可能为“每个节点”编写源特技。

我知道有一种every node样式,但它似乎不执行代码。还有execute at begin scope,它可能可用于确保\adviedit和 TikZ 使用相同的单位,但它对添加特殊项没有帮助。在路径中,execute at begin toexecute at end to可能有用,但对于孤立节点似乎没用。

最终我想要一个可以覆盖(好吧,希望只是附加)一些内部 TikZ 宏的包,允许我移动任何TikZ 节点,甚至可以使用贝塞尔曲线等。

现在我有第一步,即绘制节点并插入的宏\adviedit。它使用tkz-graph,这样我就不必x=#,y=#自己解析了。

\documentclass[12pt]{article}
\usepackage{advi}

\usepackage{tikz}
\usepackage{tkz-graph}

\begin{document}

 \begin{tikzpicture}[x=1cm,y=1cm]
   \SetVertexNoLabel
   % For reference
   \draw (0,0) rectangle (15,15);
   % My attempt to
   \def\mynode#1{%
     \setedit{unit=1cm}
     \adviedit{comm=\mynode,w=1,h=1,#1}{}
     \Vertex[#1]{}
   }
   % "Turn off" WhizzyEdit
   % \def\mynode#1{\Vertex[#1]{}}%
   \mynode{x=8.9921,y=8.6836}
   \mynode{x=7.2178,y=9.1965}
   \mynode{x=6.464,y=6.6085}
   \mynode{x=7.2497,y=7.8264}
   \mynode{x=3.7562,y=6.9931}
   \mynode{x=3.5366,y=10.3264}
   \mynode{x=9.3650,y=7.0893}
   \mynode{x=10.1343,y=5.4871}
   \mynode{x=7.3460,y=12.1536}
   \mynode{x=2.2179,y=1.5769}
\end{tikzpicture}

\end{document}

请注意,标签放置不正确,这就是我关闭它们的原因。这不是我的错(我不这么认为)。

答案1

我做了一些实验,并编写了一些代码,希望它们能对你有所帮助。无论如何,这都不是一个完整的解决方案。

看来,一个adviedit可行的宏必须是 的形式,\macro{x=<value>,y=<value>}以便whizzytex能够将数字反馈回来。我的第一个想法是简单地为 增加一种风格,\node使其看起来像\node[advi={x=<value,y=<value>}],但这似乎行不通(也许更多的实验会揭示出一种使它工作的方法)。所以我围绕命令定义了一个包装器\node,它在开始时获取坐标,然后将控制权交给原始。由于执行给定选项\node的方式(如),这没有问题。\node\node[draw]

这是代码。我会在代码中对其进行注释。

\documentclass[12pt]{article}
%\url{http://tex.stackexchange.com/q/50468/86}
\usepackage{advi}
\usepackage{tikz}

% We need to use some internal commands with `@`s in them for getting
% the widths of the nodes
\makeatletter
\tikzset{
% This is the workhorse style
  advi/.style={
% We do the advi stuff after the node has been placed so that we can
% get access to its width and height.  What this means is that our
% node ends up being equivalent to
%  \node[at=(x-value,y-value)] {node text} [advi/set advi={x=,y=}];
    append after command={[advi/set advi={#1}]},
% As the advi boxes are specified by lower-left corner, we anchor our
% node at the lower-left so that the given coordinate is the node
% coordinate
    anchor=south west,
% The parameter #1 is of the form "x=<value>,y=<value>".  We trick
% TikZ into taking that as defining some keys in the "/tikz/advi"
% directory
    advi/.cd,
    #1,
% We use the values that have just been set, namely `/tikz/advi/x`
% and `/tikz/advi/y` to specify the location of the node via the
% `at` key.  We need to give the full path as we're currently in at
% `/tikz/advi`
    /tikz/at={(\pgfkeysvalueof{/tikz/advi/x},\pgfkeysvalueof{/tikz/advi/y})}
  },
% This next bit ensures that the `/tikz/advi/x` and `y` keys can be
% used to store values.
  advi/.cd,
  x/.initial=0,
  y/.initial=0,
% This is the part that specifies the boxes in the dvi.  This is
% actually executed after the node has been processed
  set advi/.code={
% As the node has been processed, we can get its width and height by
% looking at a couple of anchors.
    \tikz@scan@one@point\pgfutil@firstofone(\tikzlastnode.north east)
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    \tikz@scan@one@point\pgfutil@firstofone(\tikzlastnode.south west)
% We adjust the values to be multiples of `em`s as that's the default
% for advi/whizzytex
    \pgfmathsetmacro{\advi@node@w}{(\pgf@xa - \pgf@x)/1em}%
    \pgfmathsetmacro{\advi@node@h}{(\pgf@ya - \pgf@y)/1em}%
% Finally, we call the `\adviedit` command
    \adviedit{comm=\advinode,w=\advi@node@w,h=\advi@node@h,#1}{}%}
  }
}
\makeatother

% This is the command that whizzytex will look for.
\newcommand{\advinode}[1]{%
  \node[advi={#1}]
}

\begin{document}

hello world, how are you?

% We use `em` units as those are the defaults for advi/whizzytex.
% Presumably this could be made configurable or some wizardry used
% to ensure that the tikz coordinates and the advi coordinates
% matched.
\begin{tikzpicture}[x=1em,y=1em]
% We can even pass ordinary styles to the node:
   \advinode{x=13.6805,y=7.3048}[red,draw] {A};
   \advinode{x=5.7699,y=10.5065}[circle,fill=blue!50] {B};
   \advinode{x=6.464,y=6.6085} {C};
   \advinode{x=7.2497,y=7.8264} {D};
   \advinode{x=3.7562,y=6.9931} {E};
   \advinode{x=1.8567,y=12.5472} {F};
   \advinode{x=9.3650,y=7.0893} {G};
   \advinode{x=13.9264,y=4.4529} {H};
   \advinode{x=11.4138,y=11.5331} {I};
   \advinode{x=3.3900,y=2.6800} {J};
\end{tikzpicture}

\end{document}

我不太相信可以在standalone课堂上尝试这个,所以这里提供一个屏幕截图。

带有可拖动节点的 advi

蓝色框和绿线是由 绘制的advi。请注意,它们是在下面绘图,因此被节点的边框A和节点的填充区域覆盖B。它们是可拖动的。

绿线表示坐标是相对于某个东西的。实验表明,它们是相对于(0,0)图片内部的 - 这正是它应该的样子。(快速查看代码advi.sty表明,与 PGF 内置函数有一些交互,这可能处理了这一点)。

(最后,这看起来非常有趣,确实值得学习。)

相关内容