我仍然不太习惯\pgfmath...
命令和calc
tikzlibrary 操作。
今天我想使用两个宏之间的操作来定义\pgfmathsetlengthmacro
上限foreach
。比如
\pgfmathsetlengthmacro\X{10mm}
\pgfmathsetlengthmacro\Y{2mm}
\foreach \i in {0,...,\X/\Y}
或者
\foreach \i in {0,...,{int(\X/\Y)}}
或者
\foreach \i in {0,...,{int(scalar(\X/\Y))}}
因为前面的方案不起作用,所以写了第二和第三个解决方案,但是并没有真正理解问题出在哪里。
这三个例子都没有起作用,最后我用辅助宏解决了
\pgfmathsetmacro{\XdivY}{\X/\Y}
\foreach \i in {0,...,\XdivY}
你能解释一下为什么我的第一次测试没有成功吗?我该如何在\X
和之间写出正确的运算\Y
作为的限制\foreach
?
如果你需要一些代码来进行测试,这里是:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\pgfmathsetlengthmacro\X{10mm}
\pgfmathsetlengthmacro\Y{2mm}
\pgfmathsetmacro{\XdivY}{\X/\Y}
\foreach \i in {0,...,\XdivY}
\node at (\i,0) {\i};
% This doesn't work
%\foreach \i in {0,...,{int(scalar(\X/\Y))}}
% \node at (\i,0) {\i};
\end{tikzpicture}
\end{document}
答案1
使用我的一些新宏;部分代码未被使用。
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{xparse,tikz}
\setlength{\parindent}{0pt} % just for the example
\ExplSyntaxOn
\providecommand\fpeval{\fp_eval:n}
\providecommand\dimtofp{\dim_to_fp:n}
\NewDocumentCommand{\nforeach}{ m +m }
{
\tl_clear:N \l__manual_nforeach_type_tl
\keys_set:nn { manual/nforeach }
{
type=integers,start = 1, step = 1, end = 0,
}
\keys_set:nn { manual/nforeach } { #1 }
\__manual_nforeach_exec:n { #2 }
}
\int_new:N \g__manual_foreach_map_int
\int_new:N \g__manual_fp_map_int
\tl_new:N \l__manual_nforeach_type_tl
\keys_define:nn { manual/nforeach }
{
type .choice:,
type .value_required:n = true,
type/integers .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { integers },
type/fp .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { fp },
type/alph .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { alph },
type/Alph .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { Alph },
start .tl_set:N = \l__manual_nforeach_start_tl,
step .tl_set:N = \l__manual_nforeach_step_tl,
end .tl_set:N = \l__manual_nforeach_end_tl,
}
\cs_new_protected:Nn \__manual_nforeach_exec:n
{
\int_gincr:N \g__manual_foreach_map_int
\str_case:Vn \l__manual_nforeach_type_tl
{
{integers}{\__manual_nforeach_exec_integers:n { #1 }}
{fp} {\__manual_nforeach_exec_fp:n { #1 }}
{alph} {\__manual_nforeach_exec_alph:Nn \int_to_alph:n { #1 }}
{Alph} {\__manual_nforeach_exec_alph:Nn \int_to_Alph:n { #1 }}
}
\int_gdecr:N \g__manual_foreach_map_int
}
\cs_generate_variant:Nn \str_case:nn { V }
\cs_new_protected:Nn \__manual_nforeach_exec_integers:n
{
\int_step_inline:nnnn
{ \l__manual_nforeach_start_tl }
{ \l__manual_nforeach_step_tl }
{ \l__manual_nforeach_end_tl }
{ #1 }
}
\cs_new_protected:Nn \__manual_nforeach_exec_alph:Nn
{
\cs_set:cn { __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :n } { #2 }
\cs_generate_variant:cn
{ __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :n }
{ f }
\int_step_inline:nnnn
{ \int_from_alph:f { \l__manual_nforeach_start_tl } }
{ \l__manual_nforeach_step_tl }
{ \int_from_alph:f { \l__manual_nforeach_end_tl } }
{
\use:c { __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :f }
{ #1 { ##1 } }
}
}
\cs_generate_variant:Nn \cs_generate_variant:Nn { c }
\cs_generate_variant:Nn \int_from_alph:n { f }
\cs_new_protected:Nn \__manual_nforeach_exec_fp:n
{
\manual_fp_step_inline:nnnn
{ \l__manual_nforeach_start_tl }
{ \l__manual_nforeach_step_tl }
{ \l__manual_nforeach_end_tl }
{ #1 }
}
% a replacement for \fp_step_inline:nnnn
\seq_new:N \l__manual_fp_step_seq
\fp_new:N \l__manual_fp_step_start_fp
\cs_new_protected:Nn \manual_fp_step_inline:nnnn
{
\int_gincr:N \g__manual_fp_map_int
\seq_clear_new:c { l__manual_fp_step_ \int_use:N \g__manual_fp_map_int _seq }
\fp_compare:nTF { #2 < \c_zero_fp }
{
\__manual_fp_step_make_neg:nnn { #1 } { #2 } { #3 }
}
{
\__manual_fp_step_make_pos:nnn { #1 } { #2 } { #3 }
}
\seq_map_inline:cn { l__manual_fp_step_ \int_use:N \g__manual_fp_map_int _seq } { #4 }
\int_gdecr:N \g__manual_fp_map_int
}
\cs_new_protected:Nn \__manual_fp_step_make_neg:nnn
{
\fp_set:Nn \l__manual_fp_step_start_fp { #1 }
\fp_do_while:nn { \l__manual_fp_step_start_fp >= #3 }
{
\seq_put_right:cx { l__manual_fp_step_ \int_use:N \g__manual_fp_map_int _seq }
{ \fp_eval:n { \l__manual_fp_step_start_fp } }
\fp_add:Nn \l__manual_fp_step_start_fp { #2 }
}
}
\cs_new_protected:Nn \__manual_fp_step_make_pos:nnn
{
\fp_set:Nn \l__manual_fp_step_start_fp { #1 }
\fp_do_while:nn { \l__manual_fp_step_start_fp <= #3 }
{
\seq_put_right:cx { l__manual_fp_step_ \int_use:N \g__manual_fp_map_int _seq }
{ \fp_eval:n { \l__manual_fp_step_start_fp } }
\fp_add:Nn \l__manual_fp_step_start_fp { #2 }
}
}
\NewDocumentCommand{\lforeach}{ s O{} m +m }
{
\IfBooleanTF{#1}
{
\manual_lforeach:non { #2 } { #3 } { #4 }
}
{
\manual_lforeach:nnn { #2 } { #3 } { #4 }
}
}
\cs_new_protected:Nn \manual_lforeach:nnn
{
\keys_set:nn { manual/lforeach } { single }
\keys_set:nn { manual/lforeach } { #1 }
\clist_set:Nn \l__manual_lforeach_list_clist { #2 }
\int_gincr:N \g__manual_foreach_map_int
\__manual_lforeach_define:n { #3 }
\clist_map_inline:Nn \l__manual_lforeach_list_clist
{
\use:c { __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w } ##1 \q_stop
}
\int_gdecr:N \g__manual_foreach_map_int
}
\cs_generate_variant:Nn \manual_lforeach:nnn { no }
\cs_new_protected:Nn \__manual_lforeach_define:n
{
\exp_last_unbraced:NcV
\cs_set:Npn
{ __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w }
\l__manual_lforeach_format_tl
\q_stop
{#1}
}
\keys_define:nn { manual/lforeach }
{
format .tl_set:N = \l__manual_lforeach_format_tl,
single .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1 },
double .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2 },
triple .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2/##3 },
}
\ExplSyntaxOff
\newcommand{\ignasiX}{30mm}
\newcommand{\ignasiY}{6mm}
\newcommand{\ignasiA}{45pt}
\newcommand{\ignasiB}{17pt}
\begin{document}
\begin{tikzpicture}
\nforeach{
start=0,
end=\fpeval{trunc(\dimtofp{\ignasiX}/\dimtofp{\ignasiY})},
step=1,
}{
\node at (#1,0) {#1};
}
\end{tikzpicture}
\begin{tikzpicture}
\nforeach{
type=fp,
start=0,
end=\fpeval{trunc(\dimtofp{\ignasiA}/\dimtofp{\ignasiB})},
step=0.3,
}{
\node at (#1,#1) {#1};
}
\end{tikzpicture}
\end{document}
当然你也可以这样做\foreach
:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\pgfmathsetlengthmacro\X{10mm}
\pgfmathsetlengthmacro\Y{2mm}
\foreach \i in {0,...,\numexpr\dimexpr\X/\dimexpr\Y\relax}
\node at (\i,0) {\i};
\end{tikzpicture}
\end{document}
答案2
作为敲击据说,\foreach
宏不会评估列表的元素——至少默认情况下不会。
但是,那/pgf/foreach/parse
钥匙激活列表中最后一个元素的解析。由于某种原因,它的默认值是false
,而不是true
其他布尔键,因此您需要parse=true
或快速修复,例如
\pgfkeys{/pgf/foreach/parse/.default=true}
需要注意的是,您不能使用更复杂的元素(但它们很少与 一起使用),并且最后一个元素当然...
需要通过 进行解析。\pgfmathparse
不过,对于简单的计算来说\numexpr
它可能仍然是最好的工具,因为它可能比使用完整的 PGFMath 解析器更快。
对于更复杂的列表,我建议use int
查看use float
我的另一个答案。
代码
\documentclass[tikz]{standalone}
% for some reason, parse doesn't
% default to parse=true, fix it:
\pgfkeys{/pgf/foreach/parse/.default=true}
\begin{document}
\begin{tikzpicture}
\pgfmathsetlengthmacro\X{10mm}
\pgfmathsetlengthmacro\Y{2mm}
\pgfmathsetmacro{\XdivY}{\X/\Y}
\foreach \i in {0,...,\XdivY}
\node at (\i,0) {\i};
\foreach \i[parse] in {0,...,\X/\Y}
\node at (\i,-1) {\i};
\end{tikzpicture}
\end{document}