В идеале я хотел бы иметь команду, \vertex
которая вела бы себя как
\vertex (a); ---> \node[empty vertex] (a) {};
\vertex[foo] (a); ---> \node[empty vertex, foo] (a) {};
\vertex[foo] (a) at (0, 0); ---> \node[empty vertex, foo] (a) at (0, 0) {};
\vertex (a) {bar}; ---> \node[filled vertex] (a) {bar};
и аналогично для различных других комбинаций; но я даже не имею представления, как написать такую функцию.
Есть ли у кого-нибудь идеи, как этого можно добиться?
В качестве запасного варианта, возможно ли, чтобы стиль узла зависел от содержимого узла? Таким образом, всегда нужно было бы писать final {...}
, но конечный результат будет зависеть от того, заполнены ли эти скобки или нет.
Первой моей мыслью было попробовать реализовать такой стиль
\tikzset{
vertex/.append code={
\ifx\tikz@node@content\relax
\pgfkeysalso{/tikz/shape=coordinate}
\else
\pgfkeysalso{/tikz/shape=circle}
\pgfkeysalso{/tikz/draw}
\fi
},
}
Однако это, похоже, не работает, поскольку стиль будет проанализирован до того, как \tikz@node@content
будет заполнен [1] , поэтому true
ветвь всегда выполняется.
В конечном счете,
[1]: Это основано на рассмотрении tikz.code.tex
, в частности, строки 3668, где \tikz@node@content
установлено .
решение1
Я думаю, если мы собираемся взломать, то проще всего взломать парсер в точке, где он настаивает на том, чтобы узел имел какой-то контент. Возможно, так...
\documentclass[tikz,border=5]{standalone}
\makeatletter
\newif\iftikznodeallowempty
\def\tikz@@scan@fig{%
\pgfutil@ifnextchar a{\tikz@fig@scan@at}
{\pgfutil@ifnextchar({\tikz@fig@scan@name}
{\pgfutil@ifnextchar[{\tikz@fig@scan@options}%
{\pgfutil@ifnextchar\bgroup{\tikz@fig@main}%
{\iftikznodeallowempty%
\tikzset{every empty node/.try}%
\else%
\tikzerror{A node must have a (possibly empty) label text}%
\fi%
\tikz@fig@main{}}}}}}%}}
\tikzset{every empty node/.style={shape=coordinate}}
\def\vertex{\path \pgfextra{\tikznodeallowemptytrue}
node [every vertex/.try]}
\begin{document}
\begin{tikzpicture}
\vertex [label=315:v1] (v1);
\vertex [label=0:v2] (v2) at (1,1);
\vertex [label=90:v3] (v3) at (-1,1);
\vertex [anchor=north] (v4) at (-1,-1) {text};
\draw [red] (v1) -- (v2) -- (v3) -- (v4.north) -- cycle;
\end{tikzpicture}
\end{document}
Однако следует отметить, что одной из причин возникновения ошибки (если только не node contents
были использованы ключи) является то, что анализатор использует фигурные скобки {}
для определения момента окончания спецификации узла, поэтому описанный выше прием следует использовать с осторожностью.
решение2
Никогда не поздно. Вы можете проверить, является ли узел пустым, измерив ширину \pgfnodeparttextbox
. А затем переопределить \tikz@shape
соответствующим образом.
\documentclass[border=30,tikz]{standalone}
\usepgflibrary{shapes.misc}
\begin{document}
\makeatletter
\def\tikz@fig@boxdone{%
%%% old definition ↓↓↓
\tikz@atend@node%
\ifx\tikz@text@width\pgfutil@empty%
\else%
\pgfutil@endminipage%
\endgroup%
\fi%
\endpgfinterruptpicture%
\egroup%
%%% new code ↓↓↓
\ifdim0pt=\wd\pgfnodeparttextbox%
\def\tikz@shape{cross out}\tikzset{draw=red}%
\else%
\def\tikz@shape{circle}\pgfkeysalso{/tikz/draw}%
\fi%
%%% old definition ↓↓↓
\pgfutil@ifnextchar c{\tikz@fig@mustbenamed\tikz@fig@continue}%
{\pgfutil@ifnextchar[{\tikz@fig@mustbenamed\tikz@fig@continue}%
{\pgfutil@ifnextchar t{\tikz@fig@mustbenamed\tikz@fig@continue}
{\pgfutil@ifnextchar e{\tikz@fig@mustbenamed\tikz@fig@continue}
{\ifx\tikz@after@path\pgfutil@empty\expandafter\tikz@fig@continue\else\expandafter\tikz@fig@mustbenamed\expandafter\tikz@fig@continue\fi}}}}}%}
\tikz\path(0,3)node{}
(0,2)node{bravo}
(0,1)node{\hbox to0pt{charlie}}
(0,0)node{\hbox to-1pt{delta}};
\end{document}