Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to use simple macros within tikz commands, but it seems tikz doesn't expand them in the ways I would expect.

For instance, the code

\pgfpointcurveattime{.25}{\pgfpoint{0cm}{0cm}}{\pgfpoint{0cm}{1cm}}{\pgfpoint{1cm}{1cm}}{\pgfpoint{1cm}{0cm}}

nicely returns the point one quarter of the way along the bezier curve specified by those four points. However the code

\newcommand{\bcurve}{{\pgfpoint{0cm}{0cm}}{\pgfpoint{0cm}{1cm}}{\pgfpoint{1cm}{1cm}}{\pgfpoint{1cm}{0cm}}}  
\pgfpointcurveattime{.25}\bcurve

gives an error, even though it expands to the same string. Putting braces around \bcurve doesn't help.

What is the cause of this trouble, and more generally how can you use a macro in such a situation in tikz?

share|improve this question
add comment

2 Answers

up vote 6 down vote accepted

My knowledge of TeX expansion is rather limited, but I think the problem is not with PGF but with TeX itself. It tries to expand \pgfpoincurveattime first and looks for its arguments before expanding \bcurve. Hence \bcurve is taken as one of the arguments of \pgfpointcurveattime and TeX looks for the other arguments in the text that follows.

So what you want to do, is to expand \bcurve first (once). To change the order of expansion, one uses \expandafter: \expandafter\a\b expands \b and adds the result after \a and then continues on to process \a. The problem here is that you want to skip over five tokens ({.25}), which would require a lot of \expandafters:

\expandafter\pgfpointcurveattime\expandafter{\expandafter.\expandafter2\expandafter5\expandafter}\bcurve

After the execution of the \expandafters, this will leave TeX with

\pgfpointcurveattime{.25}{\pgfpoint{0cm}{0cm}}{\pgfpoint{0cm}{1cm}}{\pgfpoint{1cm}{1cm}}{\pgfpoint{1cm}{0cm}}

One possible solution to save on typing all those \expandafters and getting more readable code is to save .25 into a macro that can be skipped over in one step:

\newcommand*\pos{.25}
\expandafter\pgfpointcurveattime\expandafter\pos\bcurve

After the execution of the \expandafters, this will leave TeX with

\pgfpointcurveattime\pos{\pgfpoint{0cm}{0cm}}{\pgfpoint{0cm}{1cm}}{\pgfpoint{1cm}{1cm}}{\pgfpoint{1cm}{0cm}}
share|improve this answer
    
Thanks very much, this solved the problem perfectly. And now I know to be wary of expansion order issues, which should save headaches in the future. –  Chris May 16 '11 at 12:52
    
I encountered the following further problem: \expandafter\a\expandafter\b\c worked fine, except then I wanted \b to be a command that took an input, so I wrote \expandafter\a\expandafter\b{textinput}\c and this produced errors. How can I force evaluation of \b{textinput} in this case? Note \b is defined as \newcommand\b[1]{\ifthenelse{\equal{#1}{test}}{\anothercommand}{}}. Thanks! –  Chris May 16 '11 at 14:30
    
@Chris: \expandafter skips over single tokens, and \b{textinput} are 12 tokens (\b, {, t, ...) so you need an to adapt one of the solutions I gave to skip over these tokens (either with lots of \expandafters inbetween or with some auxiliary macro). –  Caramdir May 16 '11 at 16:45
add comment

You can define an auxiliary macro like that:

\def \mycurve #1{
    \pgfpointcurveattime{.25}#1
}

\newcommand{\bcurve}{{\pgfpoint{0cm}{0cm}}{\pgfpoint{0cm}{1cm}}{\pgfpoint{1cm}{1cm}}{\pgfpoint{1cm}{0cm}}}

then

\expandafter \mycurve \expandafter {\bcurve}

or

\edef \marshal{\noexpand \mycurve{\bcurve}}
\marshal
share|improve this answer
    
Thanks, this is also helpful. –  Chris May 16 '11 at 12:54
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.