# Cube around 2 points with correct perspective

I'd like to display a moving rigid body with 2 coordinate frames attached to it. The body should be displayed around every link in the image below, so that the body is parallel to the line connecting the upper and lower frames in the image below. And it appears as if both frames are in/on the body. I know this needs great 3D skills, which I seem to lack. Even though I know how to rotate the coordinate systems, I can't figure out how to rotate the cubes accordingly.

I imagine that one needs to draw the body/cube with the frames, group it somehow and maybe then rotate it into a couple of different positions as a group.

The code of the plot below can be found in my previous question, or alternatively I can provide this:

\documentclass{article}
\usepackage{tikz}
\usepackage[graphics, active, tightpage]{preview}
\PreviewEnvironment{tikzpicture}

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

\begin{document}
\begin{tikzpicture}[scale=2,axis/.style={->,dashed},thick, >=latex]

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

\coordinate (origin) at (0,0,0);
\coordinate (t1M) at (-2,4,0);
\coordinate (t1B) at (-1.2,5.5,-2);
\coordinate (t2M) at (2,5,0);
\coordinate (t2B) at (2,6,-2);
\coordinate (t3M) at (5,6,0);
\coordinate (t3B) at (5,6,-2);
\coordinate (t4M) at (12,6,0);
\coordinate (t4B) at (12,6,-2);

% origin
\draw (origin) pic {coordsys={very thick}{x}{y}{z}};
\node [below right] at (origin.south) {\textit{G}};
\draw [->, dotted] (origin) -- (t1M) node [midway,fill=white] {$q_1, t_1$};
\draw [->, dotted] (origin) -- (t2M) node [midway,fill=white] {$q_2, t_2$};
\draw [->, dotted] (origin) -- (t3M) node [midway,fill=white] {$q_3, t_3$};
\draw [->, dotted] (origin) -- (t4M) node [midway,fill=white] {$q_4, t_4$};

% set fixed rotation of the two frames
\tdplotsetmaincoords{0}{0};
\tdplotsetrotatedcoords{0}{-45}{30};

% Time t1
\draw (t1M) pic {coordsys={}{}{}{}};
\draw [->, thick] (t1M) -- (t1B) node [midway,fill=white] {$q,t$};
\node [above left] at (t1M.north) {$M_1$};
\draw [->, dashed] (t1M) .. controls +(1,-1,0) and +(-1,-1,0) .. (t2M);

\tdplotsetrotatedcoordsorigin{(t1B)};
\draw [tdplot_rotated_coords] (t1B) pic {coordsys={}{}{}{}};
\node [above left] at (t1B.north) {$B_1$};
\draw [->, dashed] (t1B) .. controls +(1,-1,-2) and +(-1,-1,-2) .. (t2B) node [midway,fill=white] {$q_{12}$};

% Time t2
\draw (t2M) pic {coordsys={}{}{}{}};
\draw [->, thick] (t2M) -- (t2B) node [midway,fill=white] {$q,t$};
\node [above left] at (t2M.north) {$M_2$};
\draw [->, dashed] (t2M) .. controls +(1,1,0) and +(-1,0,0) .. (t3M);

\tdplotsetrotatedcoordsorigin{(t2B)};
\draw [tdplot_rotated_coords] (t2B) pic {coordsys={}{}{}{}};
\node [above left] at (t2B.north) {$B_2$};
\draw [->, dashed] (t2B) .. controls +(1,1,-2) and +(-0.5,0.5,0) .. (t3B) node [midway,fill=white] {$q_{23}$};

% Time t3
\draw (t3M) pic {coordsys={}{}{}{}};
\draw [->, thick] (t3M) -- (t3B) node [midway,fill=white] {$q,t$};
\node [above left] at (t3M.north) {$M_3$};
\draw [->, dashed] (t3M) .. controls +(3,-1,0) and +(-2,-1,0) .. (t4M);

\tdplotsetrotatedcoordsorigin{(t3B)};
\draw [tdplot_rotated_coords] (t3B) pic {coordsys={}{}{}{}};
\node [above right] at (t3B.north) {$B_3$};
\draw [->, dashed] (t3B) .. controls +(1,-1,0) and +(-2,-1,-2) .. (t4B) node [midway,fill=white] {$q_{34}$};

% Time t4
\draw (t4M) pic {coordsys={}{}{}{}};
\draw [->, thick] (t4M) -- (t4B) node [midway,fill=white] {$q,t$};
\node [above left] at (t4M.north) {$M_4$};

\tdplotsetrotatedcoordsorigin{(t4B)};
\draw [tdplot_rotated_coords] (t4B) pic {coordsys={}{}{}{}};
\node [above left] at (t4B.north) {$B_4$};

\end{tikzpicture}
\end{document}


It is fairly easy to add cuboids but they are rotated in one frame. Presumably that's the purpose here, right? (TikZ does not have a 3D engine, so you need to decide yourself which faces are to be drawn, which is why there is an \ifnum. The y' axis is hard coded to be in the background layer...)

\documentclass[border=2mm,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{backgrounds}
\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}$};
\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]
\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,...,3}
{\draw ({\X*5/3},3,{fA(\X*5/3)}) coordinate (P\Y)
-- ({\X*3.25/3},0,{fB(\X*3.25/3)}) coordinate (Q\Y);
\tdplotsetrotatedcoords{0}{atan2(fAprime(\X*5/3),1)}{0}
\begin{scope}[tdplot_rotated_coords]
\path (P\Y) pic{coordsys};
\pgfmathsetmacro{\myang}{atan2(fAprime(\X*1.25),1)}
\pgfmathtruncatemacro{\itest}{sign(\myang)}
\pgfmathsetmacro{\cuboiddim}{2/3}% 2/3 = 1/scale where scale=1.5
\draw[fill opacity=0.5,fill=gray!70]  ($(P\Y)+(0,0,0)$)
--  ($(P\Y)+(\cuboiddim,0,0)$) --  ($(P\Y)+(\cuboiddim,0,\cuboiddim)$)
-- ($(P\Y)+(0,0,\cuboiddim)$) -- cycle;
\ifnum\itest=-1
\draw[fill opacity=0.5,fill=gray]  ($(P\Y)+(\cuboiddim,0,0)$)
--  ($(P\Y)+(\cuboiddim,0,\cuboiddim)$) --  ($(Q\Y)+(\cuboiddim,0,\cuboiddim)$)
-- ($(Q\Y)+(\cuboiddim,0,0)$) -- cycle;
\else
\draw[fill opacity=0.5,fill=gray]  ($(P\Y)+(0,0,0)$)
--  ($(P\Y)+(0,0,\cuboiddim)$) --  ($(Q\Y)+(0,0,\cuboiddim)$)
-- ($(Q\Y)+(0,0,0)$) -- cycle;
\fi
\draw[fill opacity=0.5,fill=gray!70]  ($(P\Y)+(0,0,\cuboiddim)$)
--  ($(P\Y)+(\cuboiddim,0,\cuboiddim)$) --  ($(Q\Y)+(\cuboiddim,0,\cuboiddim)$)
-- ($(Q\Y)+(0,0,\cuboiddim)$) -- cycle;
\draw[fill opacity=0.5,fill=gray!50]  ($(Q\Y)+(0,0,0)$)
--  ($(Q\Y)+(\cuboiddim,0,0)$) --  ($(Q\Y)+(\cuboiddim,0,\cuboiddim)$)
-- ($(Q\Y)+(0,0,\cuboiddim)$) -- cycle;
\end{scope}
\tdplotsetrotatedcoords{0}{atan2(fBprime(\X*3.25/3),1)}{0}
\begin{scope}[tdplot_rotated_coords]
\path (Q\Y) pic{coordsys={x=x',y=y',z=z'}};
\end{scope}
}
\end{tikzpicture}
\end{document}


• Wow, that was fast and I really apprechiate your help. But your solution is a bit too advanced for my current understanding. I get it until you start rotating the frames according to the derivative. Why is there the factor 1.25 in fprime? The lower coordinate systems and cubes are as I want them, but I'd need the upper frames be rotated with a fixed rotation w.r.t. the lower ones. Both on body but with a relative rotation to each other. And can you make the cubes over the frames so it seems as the frames are inside? And 4 timesteps /bodies should be enough, where do I adjust this? – avermaet Sep 16 '19 at 11:30
• @avermaet The number of steps is controlled by {0,...,4}, 1.25 was just to evaluate fA at 0,1.25,2.5... rather than 0,1,2,.... The x and z dimensions the cuboids are given by 0.25, one can make this a parameter. The problem with making the cuboids much larger will be that they overlap and TikZ has no 3d engine, so it won't look good. – Schrödinger's cat Sep 16 '19 at 11:36
• Yes, thats why I just want 4 cuboids. Or 3d boxes. The frames should appear in the box not below, like it is at the moment. I tried to adjust the number of "boxes/frames" before but then suddenly everything broke. – avermaet Sep 16 '19 at 11:42
• @avermaet I added something along those lines. – Schrödinger's cat Sep 16 '19 at 11:44
• @avermaet Since I see you are playing with cuboids: a version that shows always the visible sides can be found e.g. here. Such cuboids may be a better fit to your problem. (It also uses rounded corners to fix the problem you had with the other one.) – Schrödinger's cat Sep 16 '19 at 16:45