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.

As @Heidar says in the comments I see there is now a package for doing the cobordism diagrams (Topological Quantum Field Theory diagrams with pstricks or tikz) and I encourage others to use it as well. But my specific question is about a particular failed syntax in TikZ that I would still like to know the answer to.


I am writing my own package for drawing cobordisms. One of the features I want to implement is to have the option of coloring the cobordisms. One way of achieving that is to draw a continuous path tracing the outline of the cobordism, e.g. a pair of pants.

Let me give you an example of something I want to draw:

Cobordism

One way of drawing this is as follows (save the genus):

    \begin{tikzpicture}[thick]
    \filldraw[fill=green!25, fill opacity=0.8]
      (1,2.6) .. controls (0.75,2.6) and (0.75,3.4) .. (1,3.4) .. 
      controls (3,3.4) and (3,4.3) .. (6,4.3) .. 
      controls (3.25,4.3) and (3.25,3.5) .. (6,3.5) .. 
      controls (4.8,3.5) and (4.8,2.5) .. (6,2.5) .. 
      controls (6.25,2.5) and (6.25,1.7) .. (6,1.7) ..
      controls (3,1.7) and (3,2.6) .. (1,2.6);
     \draw[dashed]
       (1,2.6) .. controls (1.25,2.6) and (1.25,3.4) .. (1,3.4);
     \draw  
       (6,4.3) .. controls (5.75,4.3) and (5.75,3.5) .. (6,3.5);
     \draw
       (6,2.5) .. controls (5.75,2.5) and (5.75,1.7) .. (6,1.7);
     \end{tikzpicture}

But this is not as general as I would like it. For one thing I would like to able to have one command that helps me draw any cobordism from n circles to m circles. My question is then:

How to get tikz to draw a continuous path tracing the outline of the cobordism?

My initial attempt was to use the \foreach command:

   \newcommand{\outline}[2]{
     \pgfmathsetmacro{\in}{#1}
     \pgfmathsetmacro{\out}{#2}
     \pgfmathsetmacro{\intop}{2*\in - 4}
     \pgfmathsetmacro{\intopp}{2*\in - 2}

     % Connected piece
     \draw
       (0,0) .. \foreach \a in {0,2,...,\intop}{
         controls (-0.25,\a) and (-0.25,\a+1) .. (0,\a+1) .. 
         controls (0.5,\a+1) and (0.5,\a+2) .. (0,\a+2) ..
       } controls (-0.25,\intopp) and (-0.25,\intopp+1) .. 
       (0,\intopp+1);
   }

When I try to compile it I get ! Undefined control sequence. \pgfutil@reserved@c ->\tikz@curveto@auto. I would be very grateful for any helpful suggestions.

share|improve this question
2  
This tex.stackexchange.com/questions/17031/… might be of minor relevance. –  Heidar Oct 6 '11 at 13:16
1  
@Heidar: You beat me to it! Nonetheless, the actual question remains: why is that path going wrong? –  Loop Space Oct 6 '11 at 13:22
add comment

1 Answer

up vote 9 down vote accepted

The answer is surprisingly simple. It transpires that the \foreach command can't come at arbitrary places in a path command. My guess, based on experiment, would be that it can only come when TikZ is looking for the next type of path, namely just after a coordinate. Once TikZ knows the type of path, it goes into a different mode where it looks just for those things it knows can be part of that path.

As a simpler example, try:

\draw (0,0) -- \foreach \a in {0,1,...,10} {(\a,0) -- (\a,1) -- } (11,0);

Here, TikZ is looking for a coordinate when it encounters the \foreach, so it complains. The simplest solution is to switch things around a little to ensure that the \foreach comes when TikZ is expecting it. In the baby example, this would be:

\draw (0,0) \foreach \a in {0,1,...,10} { -- (\a,0) -- (\a,1) } -- (11,0);

To a human, these are the same, but the second compiles (and gives a nice sawtooth wave) because TikZ encounters the \foreach when it is able to cope with it.

In your example, you would have:

\pgfmathsetmacro{\in}{#1}
\pgfmathsetmacro{\out}{#2}
\pgfmathsetmacro{\intop}{2*\in - 4}
\pgfmathsetmacro{\intopp}{2*\in - 2}

% Connected piece
\draw
   (0,0) \foreach \a in {0,2,...,\intop}{
     .. controls (-0.25,\a) and (-0.25,\a+1) .. (0,\a+1) .. 
        controls (0.5,\a+1) and (0.5,\a+2) .. (0,\a+2)
   } .. controls (-0.25,\intopp) and (-0.25,\intopp+1) .. 
   (0,\intopp+1);

So I've shifted the first .. inside the \foreach, and the last .. that was inside the loop outside again. This now works.


This answer was sponsored by the Answers to Packages team, suppliers of cobordisms for quality TQFTs.

share|improve this answer
1  
Two examples are given page 659 of the pgfmanual (last CVS version)."Using the foreach-statement inside paths. TikZ allows you to use a \foreach statement inside a path construction. In such a case, the ⟨commands⟩ must be path construction commands." –  Alain Matthes Oct 6 '11 at 15:02
    
@Altermundus: That's useful to know - I didn't have time to look this up in the manual. My first modification worked, so figured I'd post it and hope that someone would come along and add any extra. As you did! Thanks. –  Loop Space Oct 6 '11 at 16:31
1  
Thinking about this a bit more, I suspect it might be an expansion thing. TikZ is happy to expand a macro to see if it will give a coordinate, so ` -- \foreach ... {(coordinate)}` would work if \foreach were expandable. Since (if I remember aright) it isn't, it doesn't. –  Loop Space Oct 6 '11 at 16:48
    
@AndrewStacey \foreach cannot be expandable even in principle, since it requires an assignment of your variable \a to each value in the list. Any expandable method would require you to define a function \def\mycoord#1{(#1,0)--(#1,1)--} then feed integers from 0 to 10 to \mycoord (that could be done rather easily expandably). –  Bruno Le Floch Oct 7 '11 at 22:10
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.