通过 pgfmathsetlengthmacros 之间的操作计算 foreach 限制

通过 pgfmathsetlengthmacros 之间的操作计算 foreach 限制

我仍然不太习惯\pgfmath...命令和calctikzlibrary 操作。

今天我想使用两个宏之间的操作来定义\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}

代码

相关内容