Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use atan2(,) inside TikZ numeric keys #1071

Closed
ilyaza opened this issue Nov 9, 2021 · 8 comments
Closed

Cannot use atan2(,) inside TikZ numeric keys #1071

ilyaza opened this issue Nov 9, 2021 · 8 comments

Comments

@ilyaza
Copy link

ilyaza commented Nov 9, 2021

Brief outline of the bug

When atan2() is used inside TikZ numeric keys, the parser fails (with ! Package pgfkeys Error: I do not know the key '/tikz/65.4414pt)' and I am going to ignore it, and the internal state gets contaminated. (Using it inside let … in is OK.)

Contamination does not end at the end of tkizpicture — it propagates into following tikzpicture environments.

Aside: the difference of rotate fit and rotate is not documented. Moreover, how to use atan2() with rotate fit should better be documented too — it is in no way obvious even if it worked.

Minimal working example (MWE)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit,calc,shapes}

\begin{document}

Separate (draws OK):
\tikz{	\draw node[draw] at (1.7, 4) (a) {A}  node[draw] at (4, 2.3) (b) {B};
	\draw node[draw,blue,inner sep=-.0ex] at (1.7, 4) (aa) {\phantom A}  
              node[draw,blue,inner sep=-.0ex] at (4, 2.3) (bb) {\phantom B};
	\draw node[orange,opacity=0.7,rotate fit=45,inner sep=-.0ex,ultra thick,ellipse,fit=(a) (b),draw] {};
	\draw let \p1=(a.center), \p2=(b.center), \n1={atan2(\y2-\y1,\x2-\x1)} in 
           node[green,densely dotted,opacity=0.7,rotate fit=\n1,inner sep=-.0ex,ultra thick,ellipse,
                    fit=(a) (b),draw] {};
    }

\hrule

All together (draws following \verb`\draw` at wrong positions):
\tikz{	\draw node[draw] at (1.7, 4) (a) {A}  node[draw] at (4, 2.3) (b) {B};
	\draw node[draw,blue,inner sep=-.0ex] at (1.7, 4) (aa) {\phantom A}  
              node[draw,blue,inner sep=-.0ex] at (4, 2.3) (bb) {\phantom B};
	\draw node[orange,opacity=0.7,rotate fit=45,inner sep=-.0ex,ultra thick,ellipse,fit=(a) (b),draw] {};
	\draw let \p1=(a.center), \p2=(b.center), \n1={\y2-\y1}, \n2={\x2-\x1} in 
             node[yellow,opacity=0.7,{rotate fit={{atan2(\n1,\n2)}}},inner sep=-.0ex,ultra thick,ellipse,
                      fit=(a) (b),draw] {};
	\draw let \p1=(a.center), \p2=(b.center) in 
             node[opacity=0.7,{rotate fit={atan2(\y1-\y2,\x1-\x2)}},inner sep=-.0ex,ellipse,fit=(a) (b),draw] {};
	\draw let \p1=(a.center), \p2=(b.center), \n1={atan2(\y2-\y1,\x2-\x1)} in 
             node[green,densely dotted,opacity=0.7,rotate fit=\n1,inner sep=-.0ex,ultra thick,ellipse,
                      fit=(a) (b),draw] {};
    }

\hrule

Contaminated (leaks numbers):
\tikz{	\draw node[draw] at (1.7, 4) (a) {A}  node[draw] at (4, 2.3) (b) {B};
    }

\end{document}
@ilayn
Copy link
Member

ilayn commented Nov 9, 2021

It's not contamination. It just doesn't stop parsing so goes on to the next picture (another reason to use tikzpicture environments).

You have way too many curly braces and I can't see why you should be using them. Second, you want a key to do some math. That has to be mentioned to the key otherwise, TikZ won't do any math ops in the keys.

Note that if you use braces they become a single entity for the key parser so that we can do things like shift={(1, 1)}

@ilyaza
Copy link
Author

ilyaza commented Nov 9, 2021

Sorry, I should have mentioned what bothers you indeed! “Too many braces” are used to show that these braces do not stop this contamination. Removing the braces does not change anything (as far as I can see).

Unfortunately, I have no clue how to interpret the rest of your reply. I do not know what “goes on to the next picture” may mean. The output clearly shows that the picture is ended “normally” (assuming one forgets about wrong positions of the lines drawn after contamination happens, and junk nodes in the next tikzpicture).

@muzimuzhi
Copy link
Member

muzimuzhi commented Nov 9, 2021

Try

diff --git a/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex b/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex
index 7de158df..2985adfa 100644
--- a/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex
+++ b/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex
@@ -10,7 +10,7 @@
 \ProvidesFileRCS{tikzlibraryfit.code.tex}
 
 \pgfkeys{/tikz/fit/.code=\tikz@lib@fit{#1},
-  /tikz/rotate fit/.code=\def\tikz@lib@fit@rotate{#1}\pgfkeysalso{/tikz/rotate=#1}
+  /tikz/rotate fit/.code=\def\tikz@lib@fit@rotate{#1}\pgfkeysalso{/tikz/rotate={#1}}
 }%
 
 \def\tikz@lib@fit@rotate{0}%

I remembered there's an issue addressed all kinds of such missing-braces problems, but just cannot find it for a while.

@muzimuzhi
Copy link
Member

muzimuzhi commented Nov 9, 2021

I remembered there's an issue addressed all kinds of such missing-braces problems, but just cannot find it for a while.

Found it:

@muzimuzhi
Copy link
Member

Adding braces is a general solution and keeps the evaluation of math expression lazy. For efficiency concerns, we could make the evaluation eager.

diff --git a/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex b/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex
index 7de158df..6a5b1cf2 100644
--- a/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex
+++ b/tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibraryfit.code.tex
@@ -10,7 +10,9 @@
 \ProvidesFileRCS{tikzlibraryfit.code.tex}
 
 \pgfkeys{/tikz/fit/.code=\tikz@lib@fit{#1},
-  /tikz/rotate fit/.code=\def\tikz@lib@fit@rotate{#1}\pgfkeysalso{/tikz/rotate=#1}
+  /tikz/rotate fit/.code=%
+    \pgfmathsetmacro\tikz@lib@fit@rotate{#1}%
+    \pgfkeysalso{/tikz/rotate=+\tikz@lib@fit@rotate}%
 }%
 
 \def\tikz@lib@fit@rotate{0}%
@@ -21,8 +23,6 @@
   \pgf@yb=-16000pt\relax%
   \pgf@ya=16000pt\relax%
   %
-  \pgfmathsetmacro\tikz@lib@fit@rotate{\tikz@lib@fit@rotate}%
-  %
   % Now iterate over the coordinates
   \tikz@lib@fit@scan#1\pgf@stop%
   % Now, let's see what has happened

If any part (function, operator, fpu, ...) of the math parser is changed between option setting and the internal actual use, the subtle differences between lazy- and eager-eval will show.

@ilyaza
Copy link
Author

ilyaza commented Nov 9, 2021

If any part (function, operator, fpu, ...) of the math parser is changed between option setting and the internal actual use, the subtle differences between lazy- and eager-eval will show.

This returns us to my “Aside” in the initial message: what is the semantic of having rotate different from rotate fit? Until I found rotate fit, I have been using rotate — and while it had some effect, I would not be able to spell it out. So my current conjecture is that the documentation (or implementation) should be changed:

  • Either document that rotate should not be used with fit — only use rotate fit;
  • Or make \tikz@lib@fit@rotate mirror /pgf/rotate if rotate fit has not been used.

Aside²: The semantic of inner sep in presence of fit is not documented either. Judging by the results of the code above, it seems to recalculate the boundaries of the nodes one fits around!

@ilyaza
Copy link
Author

ilyaza commented Nov 9, 2021

Another concern: it seems that the issue of “contamination” is not addressed. Can such situations be detected (and maybe warned about), or fixed? I have seen many situations when TikZ “just stops working correctly” — and they were a royal PITA to debug (I usually could massage my code so that this would disappear)… I suspect that these cases may be related to similar “action on a distance” issues…

hmenke added a commit that referenced this issue Nov 9, 2021
Co-authored-by: muzimuzhi <muzimuzhi@gmail.com>
Signed-off-by: Henri Menke <henri@henrimenke.de>
@muzimuzhi
Copy link
Member

muzimuzhi commented Nov 9, 2021

@ilyaza To your asides, I'm not familiar with the relative code (yet), so cannot give my words right now. Perhaps this could be discussed in a new issue. Sometimes I feel hard to follow an issue having dozens of comments.

Another concern: it seems that the issue of “contamination” is not addressed. Can such situations be detected (and maybe warned about), or fixed?

Unfortunately there's very little tikz could do, partly because TeX lacks a primitive-level try-catch scheme. Generally when you get an error, then any following output could be broken. The (derived) TeX program does tries recovering from errors if called with -interaction=nonstopmode, but there's never a guarantee that the final output is the expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

4 participants