[Tex/LaTex] Using TiKz to draw cobordisms

tikz-pgf

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.

Best Answer

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.