Issue with Expansions of Nested Macros
The macro proposed by our resident marmot is nice, but cannot be used in \fpeval
as it relies to non expandable actions (\memberfalse
and \membertrue
).
The tags \ExplSyntaxOn
and \ExplSyntaxOff
are similar to \makeatletter
and \makeatother
: they have to surround the code where the expl3
syntax is used, not be inside the code.
A better coding:
\documentclass[border=0mm]{standalone}
\usepackage{tikz,xfp,xparse}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Solution by Phelype Oleinik https://tex.stackexchange.com/users/134574/phelype-oleinik
% https://tex.stackexchange.com/a/501777/23594
\ExplSyntaxOn
\prg_new_conditional:Npnn \afp_int_ismember:nn #1#2 { p, T, F, TF }
{
\__afp_ismember_loop:nw {#1} #2 , \q_recursion_tail , \q_recursion_stop
}
\cs_new:Npn \__afp_ismember_loop:nw #1#2,
{
\quark_if_recursion_tail_stop_do:nn {#2}
{ \prg_return_false: }
\int_compare:nNnTF {#1} = {#2}
{ \use_i_delimit_by_q_recursion_stop:nw { \prg_return_true: } }
{ \__afp_ismember_loop:nw {#1} }
}
\NewExpandableDocumentCommand{\convertNum}{mmmmm}
{
\fp_eval:n
{
\afp_int_ismember_p:nn {1} {1,2,3,4,5} ? #3 + 9 + (#4 + #5)*(#1-1) + (#2-1) : 0
}
}
\ExplSyntaxOff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\singleBox}[4]{%
\fill(\fpeval{#1}mm,\fpeval{#2}mm) rectangle
(\fpeval{#1} mm + \fpeval{#3} mm,\fpeval{#2} mm - \fpeval{#4} mm)
}
\begin{document}
\begin{tikzpicture}
\draw[draw=black] (0mm,0mm) rectangle (300 mm, 400 mm);
\singleBox{100}{200}{24}{13};
\singleBox{\convertNum{1}{1}{0}{2}{1.46}}{200}{24}{13};
\end{tikzpicture}
\end{document}
It is true that my macro is "not expandable" BUT I would never ever use \fpeval
in coordinates of a tikzpicture
. This is because TikZ has a very powerful parser, so you can just pass expressions to TikZ and it parses them automatically, so you can just ignore all this "hey, my stuff is expandable" discussion altogether. In particular, it is rather straightforward to declare a function memberQ
that can be parsed like any other function. The resulting code is IMHO much more elegant than a wild mix of \fpeval
and ordinary TikZ parsings.
\documentclass[tikz, border=0mm]{standalone}
\makeatletter
\pgfmathdeclarefunction{memberQ}{2}{%
\begingroup%
\edef\pgfutil@tmpb{0}%
\edef\pgfutil@tmpa{#2}%
\expandafter\pgfmath@member@i\pgfutil@firstofone#1\pgfmath@token@stop
\edef\pgfmathresult{\pgfutil@tmpb}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\def\pgfmath@member@i#1{%
\ifx\pgfmath@token@stop#1%
\else
\ifnum#1=\pgfutil@tmpa\relax%
\gdef\pgfutil@tmpb{1}%
%\typeout{#1=\pgfutil@tmpa}
\fi%
\expandafter\pgfmath@member@i
\fi}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\singleBox}[4]{%
\fill({(#1)*1mm},{(#2)*1mm}) rectangle
({(#1+#3)*1mm},{(#2-#4)*1mm});
}
\begin{document}
\begin{tikzpicture}
\draw[draw=black] (0mm,0mm) rectangle (300 mm, 400 mm);
\singleBox{100}{200}{24}{13} % This works just fine
\pgfmathparse{memberQ({1,2,3,4,5,6,7,8,9,10,11},3)}
\typeout{\pgfmathresult}
\singleBox{ifthenelse(memberQ({1,2,3,5},3),200,300)}{200}{24}{13} % This works just fine
\end{tikzpicture}
\end{document}
ADDENDUM: a memberQ
function that seems to work for arbitrary lists.
\documentclass[tikz, border=0mm]{standalone}
\makeatletter
\pgfmathdeclarefunction{memberQ}{2}{%
\begingroup%
\edef\pgfutil@tmpb{0}%
\edef\pgfutil@tmpa{#2}%
\expandafter\pgfmath@member@i\pgfutil@firstofone#1\pgfmath@token@stop
\edef\pgfmathresult{\pgfutil@tmpb}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup}
\def\pgfmath@member@i#1{%
\ifx\pgfmath@token@stop#1%
\else
\edef\pgfutil@tmpc{#1}%
\ifx\pgfutil@tmpc\pgfutil@tmpa\relax%
\gdef\pgfutil@tmpb{1}%
%\typeout{#1=\pgfutil@tmpa}%
\fi%
\expandafter\pgfmath@member@i
\fi}
\makeatother
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
\pgfmathparse{memberQ({3,4,5},3)}\pgfmathresult
\pgfmathparse{memberQ({3,4,5},1)}\pgfmathresult
\pgfmathparse{memberQ({"a","b","c"},1)}\pgfmathresult
\pgfmathparse{memberQ({"a","b","c"},"a")}\pgfmathresult
\end{document}