Unverständliches Verhalten der Calc-Bibliothek mit einer „foreach-Variable“

Unverständliches Verhalten der Calc-Bibliothek mit einer „foreach-Variable“

Wenn ich den folgenden Code kompiliere:

\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}

Ich habe kein Problem und das gibt mir, was ich will. Aber der Ausdruck zwischen "$" ist falsch eingeklammert.

Wenn ich $(\i+(0.7,0.7)$durch ersetze $\i+(0.7,0.7)$erhalte ich folgende Fehlermeldung:

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 

Und wenn ich $(\i+(0.7,0.7)$durch $(\i+(0.7,0.7))$oder ersetze $(\i)+(0.7,0.7)$, erhalte ich die folgende Fehlermeldung:

! 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)$); }

Ist das ein Fehler oder mache ich etwas falsch? (Oder ist es einfach nur eine korrekte, seltsame Syntax?)

Antwort1

In dem vom OP angeführten Beispiel

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

könnte (und sollte wahrscheinlich) sein

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

Wenn jedoch davon ausgegangen wird, dass es sich um ein MWE handelt und die tatsächliche Anwendung die Verwendung der calcBibliothek unumgänglich erfordert, handelt es sich (wie bereits erwähnt) um ein Erweiterungsproblem. Da die calcBibliothek verwendet wird, könnte Folgendes geeignet sein:

\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}

Obwohl

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

wäre (glaube ich) geringfügig effizienter.

Bildbeschreibung hier eingeben

Aber wenn Sie am Limit leben wollen, setzen Sie

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

in Ihrer Präambel. Dann ($(\i)+(0.7,0.7)$)kann es innerhalb der foreach-Schleife verwendet werden.

Antwort2

Ich denke, das ist eine Duplizierung von diesemMathematik in TikZ verwendenKurz gesagt handelt es sich um eine seltsame Interaktion, die eine explizite (und daher vollständig erweiterte) öffnende Klammer benötigt, um den Kontext richtig darzustellen, und die schließende Klammer verwendet, um \idie Syntax korrekt abzuschließen. Wenn sie eine andere sieht, stolpert sie. Der richtige Weg besteht darin, alles in seinem eigenen Kontext einzuklammern und ziemlich {}ausführlich zu sein.

Hier können Sie besser sehen, was passiert, und zwar anhand einer netten Demonstration, wie TeX und TikZ über das Parsen von Token kommunizieren (obwohl dies höchst unintuitiv ist). Beachten Sie die fehlenden Klammern an bestimmten Stellen, einschließlich der Liste.

Der Hauptgrund für solche Dinge ist, dass TikZ verzweigt, indem es untersucht, welches Zeichen als nächstes im Stream gefunden wird. Wenn Sie also an eine falsche Stelle verzweigen und anschließend die richtigen Begriffe eingeben, kann es nicht zurückgehen und richtig verzweigen. Ich glaube nicht, dass Sie bei dieser Art der Programmierung all diese Dinge vermeiden können.

\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}

Bildbeschreibung hier eingeben

Antwort3

Der folgende Code, der keine zusätzlichen Klammern enthält und mit korrekt angeordneten Klammern aufgebaut ist, lässt sich kompilieren und liefert das erwartete Ergebnis:

\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}

Antwort4

Alle vorherigen Lösungen sind perfekt. Einige davon erklären, warum calc in Ihrem Code Fehler macht. Einige davon erklären, was Sie ändern sollten, um foreachdas verwenden zu können, was durch „Punkte“ läuft (x_i,y_i).

Meiner Meinung nach foreachist Ihr „falsch“ im Sinne von TikZ:

  • wenn Sie sagen, \coordinate (A) at (x,y);dann Astellen Sie x,yund nicht dar (x,y)und Sie verwenden es als (A).
  • wenn Sie sagen, let \p1=(x,y)dann \p1stellen Sie x,yund nicht dar (x,y)und Sie verwenden es als (\p1).

Ich denke also, wenn wir foreachdiesen Durchlauf durch Punkte machen wollen, sollten wir

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

und verwenden Sie es dann als (\i).

In Ihrem Fall wird daraus:

\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} 

Bildbeschreibung hier eingeben

verwandte Informationen