具有「foreach 變數」的 calc 函式庫的行為難以理解

具有「foreach 變數」的 calc 函式庫的行為難以理解

如果我編譯以下程式碼:

\documentclass[12pt]{article}

\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}


\begin{document}

\begin{tikzpicture}
\foreach \i in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} {
\fill[lightgray] \i rectangle ($(\i+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}

\end{document}

我沒有問題,這給了我我想要的。但「$」之間的表達式沒有括號。

如果我替換$(\i+(0.7,0.7)$$\i+(0.7,0.7)$我有以下錯誤訊息:

Runaway argument?
\i +(0.7,0.7)$); \pgffor@endhook \ifx \pgffor@assign@after@code \pgfutil@empty 
\ETC.
! Paragraph ended before \tikz@cc@parse@factor was complete.
<to be read again> 
               \par 
l.15 

如果我替換$(\i+(0.7,0.7)$$(\i+(0.7,0.7))$or$(\i)+(0.7,0.7)$我有以下錯誤訊息:

! Package tikz Error: + or - expected.

See the tikz package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.12 ...htgray] \i rectangle ($(\i)+(0.7,0.7)$); }

這是一個錯誤還是我做錯了什麼? (或者這只是一個正確的奇怪語法?)

答案1

在OP所給的例子中,

\fill[lightgray] \i rectangle ($(\i+(0.7,0.7)$); 

可以(並且可能應該)是

\fill[lightgray] \i rectangle ++(0.7,0.7); 

然而,假設這是一個 MWE 並且實際應用程式不可避免地需要使用該calc庫,這是(正如已經指出的)擴展問題。由於calc正在使用該庫,以下內容可能適合:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\foreach \i in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} {
\fill let \p1=\i in [lightgray] (\p1) rectangle ($(\p1)+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}
\end{document}

雖然

\fill let \p1=\i in [lightgray] (\p1) rectangle (\x1+.7, \y1+.7);

(我認為)會稍微更有效率。

在此輸入影像描述

但如果你想生活在邊緣,那就把

\makeatletter
\def\pgffor@scanround(#1)#2,{\def\pgffor@value{#1#2}\pgffor@scanned}

在你的序言中。然後($(\i)+(0.7,0.7)$)可以在 foreach 迴圈中使用。

答案2

我認為這是一個騙局在 TikZ 中使用數學長話短說,這是一種奇怪的交互,它需要一個顯式的(因此完全擴展的)左括號來獲得正確的上下文,並使用右括號來\i正確地完成語法。如果它看到另一個人絆倒。正確的方法是將所有內容放在各自的上下文中,並且非常{}冗長。

這是一種更好的方式來了解正在發生的情況,很好地演示了 TeX 和 TikZ 如何在解析令牌方面進行通訊(儘管非常不直觀)。請注意某些地方缺少括號,包括清單。

造成這種情況的主要原因是 TikZ 透過調查在流中找到下一個字元來進行分支。因此,如果您分支到錯誤的位置並隨後輸入正確的術語,則它無法返回並正確分支。我不認為在這種類型的程式設計中你可以消除所有這些東西。

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\foreach \i in {{(0,0},{(0,2.1},{(2.1,2.1},{(2.1,0}} {
\fill[lightgray] \i) rectangle ($(\i)+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}
\end{document}

在此輸入影像描述

答案3

無論如何,以下程式碼沒有額外的大括號,並且使用正確匹配的括號進行設置,可以編譯並給出預期結果:

\documentclass[12pt]{article}

\usepackage[french]{babel}
\usepackage{tikz}
\usetikzlibrary{calc}

\usepackage{xinttools}

\begin{document}

% \begin{tikzpicture}
% \foreach \i in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} {
% \fill[lightgray] \i rectangle ($(\i+(0.7,0.7)$); }
% \draw (0,0) grid[step=0.7] (2.8,2.8);
% \end{tikzpicture}

\begin{tikzpicture}
\xintForpair  #1#2 in {(0,0),(0,2.1),(2.1,2.1),(2.1,0)} \do {
\fill[lightgray] (#1,#2) rectangle ($(#1,#2)+(0.7,0.7)$); }
\draw (0,0) grid[step=0.7] (2.8,2.8);
\end{tikzpicture}

\end{document}

答案4

之前的所有解決方案都是完美的。其中一些解釋了為什麼 calc 在程式碼中會出現混亂。其中一些解釋了您應該更改哪些內容才能使用foreach貫穿“點”的內容(x_i,y_i)

在我看來,你的foreachTikZ 精神是「錯誤的」:

  • 當你說\coordinate (A) at (x,y);thenA代表x,y而不是 時(x,y),你將它用作(A)
  • 當你說let \p1=(x,y)then\p1代表x,y而不是 時(x,y),你將它用作(\p1)

所以我認為當我們想要達到foreach最低點時我們應該這樣做

\foreach \i in {{x_1,y_1},...,{x_n,y_n}}

然後將其用作(\i).

在你的情況下,這變成:

\documentclass[tikz,varwidth,border=5]{standalone}
\usetikzlibrary{calc}
\begin{document}
  \begin{tikzpicture}
    \foreach \i in {{0,0},{0,2.1},{2.1,2.1},{2.1,0}}
      \fill[lightgray] (\i) rectangle ($(\i)+(0.7,0.7)$); 
    \draw (0,0) grid[step=0.7] (2.8,2.8);
  \end{tikzpicture}
\end{document} 

在此輸入影像描述

相關內容