以下代码用箭头绘制两个正方形的边。我觉得效果应该相同,但事实并非如此。“node[alive]”子节点处的箭头刚好接触到子节点,而“\living”子节点处的箭头则侵入了子节点。一定是我不理解宏的含义或工作原理的一些基本知识。有人能解释一下吗?
\documentclass{minimal}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[
->,thick,
alive/.style={inner sep=0pt,minimum size=5mm,rectangle,draw} ]
\newcommand{\living}{node[alive]{}}
\node {}
child{[thick]
child{\living}
child{node[alive]{}}
};
\end{tikzpicture}
\end{document}
答案1
正如 egreg 在其评论中所述,\living
宏扩展得太晚了。或者用 TikZ 的话来说:解析器检测内部node
太晚\living
,并且不将子节点视为节点,这会导致边缘被正确绘制(即节点作为目标而不是子节点)。
CVS 版 TikZ 已经修复了这个问题,方法是实现常用的扩展器,它会沿着路径扩展内容,直到找到(在本例中) a node
、 acoordinate
或“无”。这样就不会陷入无限循环,计数会递减,直到达到零。
在许多其他情况下,这通常意味着用户给出了错误的路径,但由于这实际上是一个有效的情况(即child {}
),所以它不会引发错误。
下面的代码直接取自的 CVS 版本tikz.code.tex
。
代码
\documentclass[tikz]{standalone}
\makeatletter
\def\tikz@parse@child@node{%
\pgfutil@ifnextchar n{\tikz@parse@child@node@n}%
{\pgfutil@ifnextchar c{\tikz@parse@child@node@c}%
{\pgfutil@ifnextchar\pgf@stop
\tikz@parse@child@node@rest\tikz@parse@child@node@expand}}}
\def\tikz@parse@child@node@expand{%
\advance\tikz@expandcount by-1\relax%
\ifnum\tikz@expandcount<0\relax%
\expandafter\tikz@parse@child@node@rest%
\else%
\expandafter\expandafter\expandafter\tikz@parse@child@node%
\fi}
\def\tikz@parse@child@node@rest#1\pgf@stop{\tikz@expandcount=100\relax
\def\tikz@child@node@rest{#1}}
\def\tikz@parse@child@node@c c{\tikz@expandcount=100%
\pgfutil@ifnextchar o{\tikz@parse@child@node@co}{\tikz@parse@child@node@rest c}}
\def\tikz@parse@child@node@n node{\tikz@expandcount=100%
\let\tikz@child@node@text=\pgfutil@empty%
\tikz@p@c@s}
\def\tikz@p@c@s{%
\pgfutil@ifnextchar a{\tikz@p@c@s@at}
{\pgfutil@ifnextchar ({\tikz@p@c@s@paran}
{\pgfutil@ifnextchar [{\tikz@p@c@s@bra}
{\pgfutil@ifnextchar \bgroup{\tikz@p@c@s@group}
{\tikzerror{Cannot parse this node}}}}}}
\makeatother
\begin{document}
\begin{tikzpicture}[
->, thick,
alive/.style={inner sep=0pt,minimum size=5mm,rectangle,draw}
]
\newcommand*\living{node[alive]{}}
\node {}
child {
child {\living}
child {node [alive] {}}
};
\end{tikzpicture}
\end{document}