2

I have used Tikz to make a cube and now I'd like to make multiple instance of it at different position. Therefore I imaging something like a parameterized pic or a "normal programming function" to reuse my cube. The problem with the pic is, that I already used a pic to draw parts of the cube. So I would need a pic in a pic.

As parameters I'd like to have the position and ideally orientation of the cube, with both frames fixed in the cube, but rotating with the cube. So ideally there's some kind of grouping and everything rotates with the settings. How can I accomplish this?

Thanks!

enter image description here

\documentclass[border=1cm]{standalone}
\usepackage{tikz}

\usetikzlibrary{shapes.geometric, arrows.meta, 3d, calc, decorations.markings,shapes,positioning, backgrounds, scopes}
\usepackage{tikz-3dplot}

\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground} 

\begin{document}
\begin{tikzpicture}[>=latex,scale=1.5,line cap=round, line join =round]

\tikzset{pics/coordsys/.style n args={4}{ code = { 
        \draw [->, #1] (0,0,0) -- +(1,0,0)[red] node [pos=1.3]{#2}; 
        \draw [->, #1] (0,0,0) -- +(0,1,0)[green!80!black] node [pos=1.2]{#3}; 
        \draw [->, #1] (0,0,0) -- +(0,0,1)[blue] node [pos=1.2]{#4}; } }} 

\pgfmathsetmacro{\cubex}{5}
\pgfmathsetmacro{\cubey}{1}
\pgfmathsetmacro{\cubez}{5}
\newcommand{\boxfillcolor}{yellow!20!}
\newcommand{\boxframecolor}{gray!20!}
\begin{scope}
    \draw[\boxframecolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,-\cubey,0) -- ++(\cubex,0,0) -- cycle;
    \draw[\boxframecolor] (0,0,0) -- ++(0,0,-\cubez) -- ++(0,-\cubey,0) -- ++(0,0,\cubez) -- cycle;
    \draw[\boxframecolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,0,-\cubez) -- ++(\cubex,0,0) -- cycle;
\end{scope}
\begin{scope}[on background layer]
    \fill[\boxfillcolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,-\cubey,0) -- ++(\cubex,0,0) -- cycle;
    \fill[\boxfillcolor] (0,0,0) -- ++(0,0,-\cubez) -- ++(0,-\cubey,0) -- ++(0,0,\cubez) -- cycle;
    \fill[\boxfillcolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,0,-\cubez) -- ++(\cubex,0,0) -- cycle;
\end{scope}

\pgfmathsetmacro{\dx}{0.6};
\pgfmathsetmacro{\dy}{2};
\pgfmathsetmacro{\dz}{0.3};
\coordinate (origin) at (-5,-3,0);
\coordinate (M) at (-\dx,-\cubey/\dy,-\dz);
\coordinate (B) at (-\cubex+\dx,-\cubey/\dy,-\cubez+\dz);

\draw (M) pic {coordsys={thick}{$x_M$}{$y_M$}{$z_M$}};
\node [below right] at (M.south) {\textit{M}};
\draw (B) pic {coordsys={dashed}{$x_M'$}{$y_M'$}{$z_M'$}};
\node [above left] at (B.west) {\textit{B}};

\tdplotsetmaincoords{0}{0};
\tdplotsetrotatedcoords{20}{-60}{10};
\tdplotsetrotatedcoordsorigin{(B)};
\draw [tdplot_rotated_coords] (B) pic {coordsys={thick}{$x_{B}$}{$y_{B}$}{$z_{B}$}}; 

\draw [->, thick] (M) -- (B) node [midway,fill=\boxfillcolor] {$q_{MB}, r_{MB}$};

\end{tikzpicture}
\end{document}
4
  • Did you try to nest pics? Also instead of the multiple arguments I would strongly recommend pgf keys. You can also store the thing in a macro and use shift to shift it to a new position. Most importantly for now, your code is not running through because you are using a coordinate Marker which you did not define. Can you make your code compilable?
    – user194703
    Sep 16 '19 at 21:26
  • Can you provide an example? I have no idea how to use this. Thats also why I didn't switch to the pgfkeys in coordsysbefore. Marker is M, I'll edit, sorry.
    – avermaet
    Sep 16 '19 at 21:29
  • Also I wouldn't need full rotations. So the problem with the sidewalls could be avoided. Ability to rotate around x_Mand y_M would be enough + setting the cube/pic position (lets say position of frame M).
    – avermaet
    Sep 16 '19 at 21:31
  • Fixed variable error ....
    – avermaet
    Sep 16 '19 at 21:38
3

This is not a full answer that takes all the parameters into account but to tell you how to make it work in principle.

  1. As far as I know, you can nest pics. At least in the example below it works. So you can make the bigger thing a pic, too.
  2. Store all things that you want to adjust in pgf keys. I did that for the dimensions of the cube, the colors and the axes labels. If you want to add rotation angles and so on, all you need to do is to add more pgf keys. They can be changed for every pic. This is one of the biggest advantages compared to a style with a fixed number of parameters: you can always add some parameter without destroying downwards compatibility, i.e. your older codes will still work.

I also cleaned up your preamble.

\documentclass[tikz,border=1cm]{standalone}
\usepackage{tikz-3dplot} % loads 3d and calc libraries
\usetikzlibrary{backgrounds} % cleaned up

\begin{document}
\begin{tikzpicture}[>=latex,line cap=round, line join =round]

\tikzset{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}$};
        \begin{scope}[on background layer]
        \draw [->,pic actions] (0,0,0) -- +(0,1,0)[green!60!black] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/y}$};
        \end{scope}
        \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} 

\tikzset{pics/complicated/.style={code={\tikzset{complicated/.cd,#1}
\begin{scope}
    \draw[\boxframecolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,-\cubey,0) -- ++(\cubex,0,0) -- cycle;
    \draw[\boxframecolor] (0,0,0) -- ++(0,0,-\cubez) -- ++(0,-\cubey,0) -- ++(0,0,\cubez) -- cycle;
    \draw[\boxframecolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,0,-\cubez) -- ++(\cubex,0,0) -- cycle;
\end{scope}
\begin{scope}[on background layer]
    \fill[\boxfillcolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,-\cubey,0) -- ++(\cubex,0,0) -- cycle;
    \fill[\boxfillcolor] (0,0,0) -- ++(0,0,-\cubez) -- ++(0,-\cubey,0) -- ++(0,0,\cubez) -- cycle;
    \fill[\boxfillcolor] (0,0,0) -- ++(-\cubex,0,0) -- ++(0,0,-\cubez) -- ++(\cubex,0,0) -- cycle;
\end{scope}

%\draw (-\cubex+0.2,-\cubey/2,-0.6) coordinate (origin) pic {coordsys={very thick}{x}{y}{z}}; 
\pgfmathsetmacro{\dx}{0.6};
\pgfmathsetmacro{\dy}{2};
\pgfmathsetmacro{\dz}{0.3};
\coordinate (origin) at (-5,-3,0);
\coordinate (M) at (-\dx,-\cubey/\dy,-\dz);
\coordinate (B) at (-\cubex+\dx,-\cubey/\dy,-\cubez+\dz);

\draw (M) pic[thick] {coordsys={x=x_M,y=y_M,z=z_M}};
\node [below right] at (M.south) {\textit{M}};
\draw (B) pic[dashed] {coordsys={x=x_M',y=y_M',z=z_M'}};
\node [above left] at (B.west) {\textit{B}};

\tdplotsetmaincoords{0}{0};
\tdplotsetrotatedcoords{20}{-60}{10};
\tdplotsetrotatedcoordsorigin{(B)};
%\begin{scope}[on background layer]
\draw [tdplot_rotated_coords] (B) pic[thick]{coordsys={x=x_{B},y=y_{B},z=z_{B}}}; 

\draw [->, thick] (M) -- (B) node [midway,fill=\boxfillcolor] {$q_{MB}, r_{MB}$};
}},complicated/.cd,cube x/.store in=\cubex,cube x=5,
cube y/.store in=\cubey,cube y=1,
cube z/.store in=\cubez,cube z=5,
box fill color/.store in=\boxfillcolor,box fill color=yellow!20!,
box frame color/.store in=\boxframecolor,box frame color=gray!20!,}
\path pic{complicated} (5,0,0) pic{complicated={box fill color=red!20}}
(10,0,0) pic{complicated={box fill color=blue!20,box frame color=blue}};
\end{tikzpicture}
\end{document}

enter image description here

8
  • Great. Is it possible to use tikz-3dplot now to rotate a whole cube including its contents?
    – avermaet
    Sep 16 '19 at 21:57
  • 1
    @avermaet Yes, at least in principle. The trouble is that you start in the TikZ standard 3D coordinate system, which is not an orthogonal projection, and in which the y axis points up. tikz-3dplot provides you with orthogonal projections but has the z axis up (which is also the convention of most of the reasonable 3D tools like pgfplots, where however the theta and phi angle have a different convention). So you basically need to exchange the y and z component and install a view such as the one used in the previous answers.
    – user194703
    Sep 16 '19 at 22:03
  • 1
    @avermaet y <-> z.
    – user194703
    Sep 16 '19 at 22:08
  • 1
    @avermaet If I were you I would do that by hand. You really need to clarify for yourself where the journey will go. Do you want to draw things in orthographic projections and are OK with manually ordering things? The tikz-3dplot may be the right tool (the built-in TikZ 3D coordinates are not really suitable). Do you want a real perspective? Then look at section 63 Three Point Perspective Drawing Library of the pgfmanual. Do you want automatic 3d ordering? Then switch to asymptote.
    – user194703
    Sep 16 '19 at 22:24
  • 1
    @avermaet By hand means that you have to figure out in which order you add the elements. Cf. tex.stackexchange.com/a/508538/194703. You switched the roles of P and Q, and as a consequence 3D ordering was incorrect, and had to be repaired "by hand". As for the 3d perspective library, this was written by a user who created an amazing set of tools in this answer, and made them a library. He is just very humble and mentions explicitly what does not work, you can always rotate yourself by applying the transformation to the coordinates.
    – user194703
    Sep 16 '19 at 22:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.