Discussion:
Tikz \foreach loop doesn't work when the list is reversed
(too old to reply)
oatmealbrain
2020-06-12 20:27:51 UTC
Permalink
After struggling for two weeks, I gave up on getting TikZ working in LaTeX3 so I went back to doing what I need in LaTeX2e. I'm looping through a TikZ \foreach loop but the catch is the original list, passed as #1, must be reversed before \foreach acts on it. For some reason it's not working and I can't find the problem. The reason the list must be reversed is to make the drawing's come out correctly layered; they must be drawn from last to first. I hope that makes sense.

Without reversing the list, the "slots" are drawn in precisely the reverse order I want them drawn in and thus when they are "filled" the result isn't realistic. The list seems correctly reversed and. like I said I can't see the error. Any help would be appreciated.

\documentclass{article}
\usepackage{tikz}
\usepackage{xargs}
\usepackage{xstring} % needed for \StrCount
\usepackage{ifthen}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsfonts}
\usepackage{arev}
\usepackage[T1]{fontenc}
%\usepackage[margin=0.5in]{geometry}

\newcommandx{\tensormachinetwoe}[2][1]{%
% \ifthenelse{\equal{#1}{}}%
% {scalar}% % no arguments given (the default); machine is a scalar
% {% % we have slots, which may be filled or unfilled
% \foreach \x in {#1}{%
% %\IfSubStr{\x}{v}{\IfSubStr{\x}{+}{filled vector}{vector}}{}
% %\IfSubStr{\x}{o}{\IfSubStr{\x}{+}{filled 1-form}{1-form}}{}

% %\IfBeginWith{\x}{v}{\IfEndWith{\x}{+}{filled vector}{vector}}{}
% %\IfBeginWith{\x}{o}{\IfEndWith{\x}{+}{filled 1-form}{1-form}}{}

% \x\ is a
% \IfEndWith{\x}{+}{filled %
% \IfBeginWith{\x}{v}{vector}{1-form}}{\IfBeginWith{\x}{v}{vector}{1-form}}
% slot
% }%

% % machine is a scalar only if all slots are filled
% \StrCount{#1,}{,}[\numslots]
% \StrCount{#1}{+}[\numfilledslots]
% the machine is
% \ifthenelse{\numslots=\numfilledslots}{scalar}{not scalar}
% }%
\begin{tikzpicture}[baseline]
\pgfmathsetmacro{\cubex}{4}
\pgfmathsetmacro{\cubey}{1}
\pgfmathsetmacro{\cubez}{3}
\pgfmathsetmacro{\slotwidth}{1}
% \pgfmathsetmacro{\startvslotx}{-0.25*\cubex-0.5*\slotwidth}
% \pgfmathsetmacro{\startoslotx}{+0.25*\cubex-0.5*\slotwidth}
% \pgfmathsetmacro{\sloty}{0.5*\cubey}
% \pgfmathsetmacro{\totalnumslots}{\numslots}
% \pgfmathsetmacro{\slotspace}{\cubez / (\totalnumslots + 1)}

% front
\draw[fill=white,thick] (0.5*\cubex,0.5*\cubey,0.5*\cubez) --
++(-\cubex,0,0) -- ++(0,-\cubey,0) -- ++(\cubex,0,0) -- cycle
% label the machine
node at (0.30*\cubex,0,0.5*\cubez) {\(\boldsymbol{\mathbf{#2}}\)};
% side
\draw[fill=white,thick] (0.5*\cubex,0.5\cubey,-0.5*\cubez) --
++(0,0,\cubez) -- ++(0,-\cubey,0) -- ++(0,0,-\cubez) -- cycle;
% top
\draw[fill=white,thick] (0.5*\cubex,0.5*\cubey,-0.5*\cubez) --
++(-\cubex,0,0) -- ++(0,0,\cubez) -- ++(\cubex,0,0) -- cycle;
% output slot
\draw[fill=black, ultra thick] (-0.5*\slotwidth,0,0.5*\cubez) --
++(0,0.03,0) -- ++(\slotwidth,0,0) -- ++(0,-0.03,0) -- cycle;
%\fill (0,0,0) circle (2pt); % origin

% For reasons that aren't obvious, we need to reverse the order of
% slots given in #1.
\let\revslots\empty
\foreach \x in {#1}{%
\ifx\revslots\empty
\xdef\revslots{\x}
\else
\xdef\revslots{\x,\revslots}
\fi
}%
\node at (0,-4,0) {\{#1\}\ becomes \{\revslots\}};
\ifthenelse{\equal{#1}{}}%
{% We have a scalar. Fill the output slot and we're done.
\draw[fill=white, thin,-] (-0.5*\slotwidth+0.1,0,0.5*\cubez)
-- ++(-0.25,-\slotwidth,0) -- ++(\slotwidth-0.2,0,0)
-- ++(0.25,\slotwidth,0)
node at (-0.125*\slotwidth,-0.5*\cubey,0.5*\cubez) {\(\mathbb{R}\)};
}%
{% We have slots, which may be filled or unfilled.
% Set some values.
\StrCount{#1,}{,}[\numslots]
\StrCount{#1}{+}[\numfilledslots]
\pgfmathsetmacro{\startvslotx}{-0.25*\cubex-0.5*\slotwidth}
\pgfmathsetmacro{\startoslotx}{+0.25*\cubex-0.5*\slotwidth}
\pgfmathsetmacro{\sloty}{0.5*\cubey}
\pgfmathsetmacro{\totalnumslots}{\numslots}
\pgfmathsetmacro{\slotspace}{\cubez / (\totalnumslots + 1)}
\pgfmathsetmacro{\islotspaceindex}{1}
% Loop through the reversed list of slots.
\foreach \currentslot in {\revslots}{%
\IfBeginWith{\currentslot}{v}%
{% Draw a vector slot.
\draw[fill=black, ultra thick]
(\startvslotx,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,0,0.04) -- ++(\slotwidth,0,0) -- ++(0,0,-0.04) -- cycle;
% Test to see if we need to fill the slot.
\IfEndWith{\currentslot}{+}%
{% Fill the slot.
\draw[fill=white,thin]
(\startvslotx+0.1,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,\slotwidth,0) -- ++(\slotwidth-0.2,0,0) -- ++(0,-\slotwidth,0);
}%
{% Leave it empty.
}%
}%
{% Draw a 1-form slot.
\draw[fill=black, ultra thick]
(\startoslotx,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,0,0.04) -- ++(\slotwidth,0,0)-- ++(0,0,-0.04) -- cycle;
% Test to see if we need to fill the slot.
\IfEndWith{\currentslot}{+}%
{% Fill the slot.
\draw[fill=lightgray,thin]
(\startoslotx+0.1,\sloty,-0.5*\cubez+\islotspaceindex*\slotspace)
-- ++(0,\slotwidth,0) -- ++(\slotwidth-0.2,0,0) -- ++(0,-\slotwidth,0);
}%
{% Leave it empty.
}%
}%
\pgfmathparse{\islotspaceindex+1}
\xdef\islotspaceindex{\pgfmathresult}
}%
% Test to see if we need to fill the output slot.
\ifthenelse{\equal{\numslots}{\numfilledslots}}%
{% Fill the output slot.
\draw[fill=white, thin,-] (-0.5*\slotwidth+0.1,0,0.5*\cubez)
-- ++(-0.25,-\slotwidth,0) -- ++(\slotwidth-0.2,0,0)
-- ++(0.25,\slotwidth,0)
node at (-0.125*\slotwidth,-0.5*\cubey,0.5*\cubez) {\(\mathbb{R}\)};
}%
{% Leave it empty.
}%
}%
\end{tikzpicture}
}%

\begin{document}
\tensormachinetwoe[v+,v+,o+]{T}
\end{document}
oatmealbrain
2020-06-13 02:56:04 UTC
Permalink
Post by oatmealbrain
Without reversing the list, the "slots" are drawn in precisely the reverse order I want them drawn in and thus when they are "filled" the result isn't realistic. The list seems correctly reversed and. like I said I can't see the error. Any help would be appreciated.
The problem turned out to be the braces around \revslots in the \foreach line. Removing them makes the whole thing work, but I've no idea why.
Loading...