7

I had a look at TeX-FAQ on Non-letters in macro names and tried to implement the approach #2. It looks like I'm missing something. When trying to refer later to the new commands the result is not what I expected.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}

\newcommand{\DefineNode}[2]
{
  \expandafter\newcommand\csname node-#1\endcsname{#2}
}
\newcommand{\GetNode}[1]{\csname node-#1\endcsname}

\begin{tikzpicture}
  \def \intra {1}
  \def \inter {3}

  % Calculate values
  \foreach \x [count=\xi from 0] in {a,...,c}
  {
    \pgfmathsetmacro\tmpi{\xi * \inter}
    \DefineNode{n\x.0}{\tmpi}

    \pgfmathsetmacro\tmpii{\xi * \inter + \intra}
    \DefineNode{n\x.1}{\tmpii}

    \message{\GetNode{n\x.0} ^^J}
    \message{\GetNode{n\x.1} ^^J}
  }

  % Doing something with them later
  \foreach \x in {a,...,c}
  {
    \message{\GetNode{n\x.0} ^^J}
    \message{\GetNode{n\x.1} ^^J}
  }
\end{tikzpicture}

\end{document}

The result is:

0.0
1.0
3.0
4.0
6.0
7.0
\node-na.0
\node-na.1
\node-nb.0
\node-nb.1
\node-nc.0
\node-nc.1

Instead of repeating numbers twice.

EDIT: Solved the group issue by forcing names to be globals.

\newcommand{\DefineNode}[2]
{
  \globaldefs=1\relax
  \expandafter\newcommand\csname node-#1\endcsname{#2}
}

Result currently:

0.0
1.0
3.0
4.0
6.0
7.0
6.0
7.0
6.0
7.0
6.0
7.0

Instead of repeating first 6 lines, now 6.0 and 7.0 are repeated. This is due to using only two macros \tmpi and \tmpii. How to solve this?

6
  • 1
    Maybe TikZ \foreach defines a group? In this case the definition would be local to the body of \foreach. Jul 9, 2014 at 14:12
  • Welcome to TeX.SX! You can have a look at our starter guide to familiarize yourself further with our format. Jul 9, 2014 at 14:13
  • According to tex.stackexchange.com/a/75152/56821 TikZ \foreach defines two groups. Edited the question to solve the group issue.
    – karu
    Jul 9, 2014 at 17:48
  • 3
    No, don't do \globaldefs=1. Use \expandafter\gdef\csname node-#1\endcsname{#2} instead.
    – egreg
    Jul 9, 2014 at 17:51
  • You mean like this? \gdef \DefineNode#1#2 { \expandafter\gdef\csname node-#1\endcsname{#2} } It will produce: 0.0 1.0 3.0 4.0 6.0 7.0 ! Undefined control sequence. \node-na.0 ->\tmpi
    – karu
    Jul 9, 2014 at 18:16

1 Answer 1

5

A feature of \foreach is that it performs each cycle in a group; its main purpose was to add paths or nodes to a tikzpicture being built and this operation is indeed global.

Doing \globaldefs=1 is not a good workaround, because \newcommand performs several assignments that you really don't want to be global.

You can look at \global\renewcommand equivalent of \global\def for a \gnewcommand that doesn't require \globaldefs=1. However, in the case at hand, a simpler

\newcommand{\DefineNode}[2]{%
  \expandafter\xdef\csname node-#1\endcsname{#2}%
}

seems sufficient. You need \xdef in order to expand \tmpi and \tmpii.

You won't be warned about redefining the same control sequence. If you really need this feature, then

\makeatletter
\providecommand\@nameedef[1]{\expandafter\edef\csname#1\endcsname}
\newcommand{\DefineNode}[2]{%
  \expandafter\@ifdefinable\expandafter{\csname node-#1\endcsname}{%
    \global\@nameedef\node-#1}{#2}%
  }%
}
\makeatother

is what you're looking for. Again an expanded definition is necessary.

2
  • I'm must be missing something. First one produces: 0.0 1.0 3.0 4.0 6.0 7.0 ! Undefined control sequence. \node-na.0 ->\tmpi Second one produces: ! Extra }, or forgotten \endgroup.
    – karu
    Jul 9, 2014 at 18:39
  • @karu You have to use \xdef, of course, so \tmpi is expanded. With \globaldefs=1 you got no error, but wrong output. I have modified my answer to reflect this.
    – egreg
    Jul 9, 2014 at 19:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .