10

How is it possible to use multiple parameters in a single pic? It works nicely with just 1 parameter, but always results in errors in case of more than 1 parameter. I found this post, which didn't solve the issue.

\tikzset{pics/coordsys/.style n args={4}{
    code = {
        \draw [->, #1] (0,0,0) -- +(1,0,0)[red] node [pos=1.1]{#2};
        \draw [->, #1] (0,0,0) -- +(0,1,0)[green] node [pos=1.1]{#3};
        \draw [->, #1] (0,0,0) -- +(0,0,1)[blue] node [pos=1.1]{#4};
    }
}}
\draw [rotate=360] (origin) pic {coordsys={very thick}{x}{y}{z}};

This always results in errors like:

Package pgfkeys Error: I do not know the key '/tikz/every text node part'

2
  • 3
    It works for me: \documentclass[tikz,border=3mm]{standalone} \begin{document} \begin{tikzpicture} \tikzset{pics/coordsys/.style n args={4}{ code = { \draw [->, #1] (0,0,0) -- +(1,0,0)[red] node [pos=1.1]{#2}; \draw [->, #1] (0,0,0) -- +(0,1,0)[green] node [pos=1.1]{#3}; \draw [->, #1] (0,0,0) -- +(0,0,1)[blue] node [pos=1.1]{#4}; } }} \draw (0,0) coordinate (origin) [rotate=360] pic {coordsys={very thick}{x}{y}{z}}; \end{tikzpicture} \end{document}
    – user194703
    Sep 15, 2019 at 21:27
  • 1

1 Answer 1

12

Giving multiple arguments to a pic works for me, i.e.

\documentclass[tikz,border=3mm]{standalone}
\begin{document}
\begin{tikzpicture}
\tikzset{pics/coordsys/.style n args={4}{
    code = {
        \draw [->, #1] (0,0,0) -- +(1,0,0)[red] node [pos=1.1]{#2};
        \draw [->, #1] (0,0,0) -- +(0,1,0)[green] node [pos=1.1]{#3};
        \draw [->, #1] (0,0,0) -- +(0,0,1)[blue] node [pos=1.1]{#4};
    }
}}
\draw  (0,0) coordinate  (origin) [rotate=360] pic {coordsys={very thick}{x}{y}{z}};
\end{tikzpicture}
\end{document}

compiles without errors on my updated TeXLive installation. So I suspect the error comes from something that you did not disclose.

However, I would like to talk you out of this multiple argument thingy for this application. Rather, you could set some standard or initial (in a way default) values using pgf keys, and change them only if you have to. Also the argument thick in the way you use it may be better replaced by the pic actions, which are made for this. (This is the answer I had for your previous question, which got deleted just when I was about to press the submit button. Of course I have no problem deleting it.)

\documentclass[border=2mm,tikz]{standalone} 
\usepackage{tikz-3dplot} 
\begin{document} 
\tdplotsetmaincoords{60}{-15} 
\begin{tikzpicture}[tdplot_main_coords,scale=1.5,line join=round,>=latex, 
line cap=round,declare function={fA(\t)=-sin(\t*144/(1+\t/5));
fAprime(\t)=pow(60/(5+\t),2)*cos(\t*144/(1+\t/5))*pi/180;
fB(\t)=-sin(\t*216/(1+\t*4/15));
fBprime(\t)=6*pow(90/(15+\t*4),2)*cos(\t*216/(1+\t*4/15))*pi/180;},
pics/coordsys/.style = {
    code = {\tikzset{coordsys/.cd,#1}
        \draw [->,pic actions] (0,0,0) -- +(1,0,0)[red] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/x}$};
        \draw [->,pic actions] (0,0,0) -- +(0,1,0)[green!60!black] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/y}$};
        \draw [->,pic actions] (0,0,0) -- +(0,0,1)[blue] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/z}$};
    }
},coordsys/.cd,x/.initial=x,y/.initial=y,z/.initial=z] 
 \draw[dashed] plot[variable=\t,domain=0:5] ({\t},3,{fA(\t)});
 \draw[dashed] plot[variable=\t,domain=0:3.25] ({\t},0,{fB(\t)});
 \foreach \X [count=\Y] in {0,...,4}
 {\draw ({\X*1.25},3,{fA(\X*1.25)}) coordinate (P\Y)
  -- ({\X*3.25/4},0,{fB(\X*3.25/4)}) coordinate (Q\Y);
 \tdplotsetrotatedcoords{0}{atan2(fAprime(\X*1.25),1)}{0} 
 \begin{scope}[tdplot_rotated_coords]
 \path (P\Y) pic{coordsys};
 \end{scope}
 \tdplotsetrotatedcoords{0}{atan2(fBprime(\X*3.25/4),1)}{0} 
 \begin{scope}[tdplot_rotated_coords]
 \path (Q\Y) pic{coordsys={x=x',y=y',z=z'}};
 \end{scope}
 } 
\end{tikzpicture} 
\end{document}

enter image description here

As you can see, the standard values for x, y, and z are just x, y and z, but by saying

 \path (Q\Y) pic{coordsys={x=x',y=y',z=z'}};

for the curve in front, they will become x', y' and z'.

As for the rotations of the coordinate systems: they are rotated such that the x axis is tangent to the curve, and the y axis remains fixed. To this end, one has to guess some functions, and the derivatives have to be done by hand or with a computer algebra system (i.e. plain LaTeX won't do it). From this one computes the slope which gets fed into

 \tdplotsetrotatedcoords{0}{atan2(fBprime(\X*3.25/4),1)}{0} 

where the second argument is the rotation angle about the y axis. For more details consult the manual of tikz-3dplot.

A very quickly written alternative that does not require you to compute the derivative. (Note, however, that when trying to add smooth to the plot options one encounters unexpected difficulties: transformations that cannot be undone. This is the first time I see something like this.)

\documentclass[border=2mm,tikz]{standalone} 
\usepackage{tikz-3dplot} 
\usetikzlibrary{decorations.markings}
\begin{document} 
\tdplotsetmaincoords{60}{-15} 
\begin{tikzpicture}[tdplot_main_coords,scale=2,line join=round,>=latex, 
line cap=round,declare function={fA(\t)=-sin(\t*144/(1+\t/5));
fB(\t)=-sin(\t*216/(1+\t*4/15));},
pics/coordsys/.style = {
    code = {\tikzset{nodes={transform shape},coordsys/.cd,#1}
        \draw [->,pic actions] (0,0,0) -- +(1,0,0)[red] node[pos=1.1,rotate=0]
        {$\pgfkeysvalueof{/tikz/coordsys/x}$};
        \draw [->,pic actions] (0,0,0) -- +(0,1,0)[green!60!black] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/y}$};
        \draw [->,pic actions] (0,0,0) -- +(0,0,1)[blue] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/z}$};
    }
},coordsys/.cd,x/.initial=x,y/.initial=y,z/.initial=z,/tikz/.cd,
rotated coordsys at/.style={postaction={decorate,decoration={markings,
mark=at position #1 with {\pgfmathtruncatemacro{\myint}{5*#1+0.1}
\path (0,0) coordinate (O'-\myint) (1,0) coordinate (X');
\path let \p1=($(X)-(O)$),\p2=($(X')-(O'-\myint)$) in \pgfextra{%
\pgfmathsetmacro{\myangle}{atan2(\y1,\x1)-atan2(\y2,\x2)}
\xdef\myangle{\myangle}};
\tdplotsetrotatedcoords{0}{\myangle}{0} 
\begin{scope}[tdplot_rotated_coords]
 \path (O'-\myint) pic[solid]{coordsys};
\end{scope}
}}}}] 
 \path (0,0,0) coordinate (O) (1,0,0) coordinate (X); 
 \draw[dashed,rotated coordsys at/.list={0,0.2,...,1}] 
    plot[variable=\t,domain=0:5,samples=71] ({\t},3,{fA(\t)});
 \path foreach \X in {0,...,5} {(O'-\X) coordinate (P-\X)};
 \draw[dashed,coordsys/x=x',coordsys/y=y',coordsys/z=z',
 rotated coordsys at/.list={0,0.2,...,1}] 
    plot[variable=\t,domain=0:3.25,samples=71] ({\t},0,{fB(\t)});
 \draw foreach \X in {0,...,5} {(P-\X) -- (O'-\X) coordinate (Q-\X)};   
\end{tikzpicture} 
\end{document}

enter image description here

As you can see, one can set the options coordsys/x=x' in the path.

7
  • 2
    Awesome! Sorry about deleting the question before, I was not expecting a full answer anymore.
    – avermaet
    Sep 15, 2019 at 21:37
  • 1
    @avermaet No worries and you're welcome!
    – user194703
    Sep 15, 2019 at 21:52
  • 2
    (Since the angle between x and z does not change, and since y is fixed, one could construct a pure LaTeX solution with decorations.markings. It wouldn't be as direct but would not require computing derivatives by hand.)
    – user194703
    Sep 15, 2019 at 22:04
  • 1
    @avermaet There is now a second version in which you do not have to compute the derivative of the function. In addition you can play with the view angles, which are set in \tdplotsetmaincoords{60}{-15} .
    – user194703
    Sep 16, 2019 at 2:21
  • 1
    @HenriMenke Yes, that solves the puzzle. Whether or not this will break something, I do not know, but according to my understanding the decorations.text library is independent of decorations.markings, so I would be surprised if the texts got affected by changes in decorations.markings.
    – user194703
    Jun 17, 2020 at 8:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .