Discussion:
Tikz \foreach loop doesn't work when the list is reversed
oatmealbrain
2020-06-12 20:27:51 UTC
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