Tikz:: shift and rotate in 3d?

Here's a solution, but only for translation (so far). It uses the fact that internaly TikZ handles 3D points as 2D ones. So your 3D shift vector is saved in the coordinate mytranslation which then is a 2D point and thus can be passed to shift. The thick lines are just to illustrate that the translation is done correctly:

\documentclass{standalone}
\usepackage{tikz}

\newcommand{\translatepoint}[1]%
{   \coordinate (mytranslation) at (#1);
}

\newcommand{\somedrawing}%
{   \coordinate (a) at (0,0,0);
    \coordinate (b) at (5,1,0);
    \coordinate (c) at (2,4,0);
    \coordinate (d) at (1,-1,-4);
    \draw (a) -- (b) (a) -- (c) (a) -- (d) (b) -- (c) (b) -- (d) (c) -- (d);
}

\begin{document}

\begin{tikzpicture}[x={(0.866cm,0.5cm)},y={(-0.866cm,0.5cm)},z={(0cm,1cm)}]
    \somedrawing    

    \translatepoint{5,0,0}
    \draw[very thick,red] (0,0,0) -- (5,0,0);
    \begin{scope}[shift=(mytranslation),draw=red]
        \somedrawing
    \end{scope}

    \translatepoint{0,6,0}
    \draw[very thick,blue] (0,0,0) -- (0,6,0);
    \begin{scope}[shift=(mytranslation),draw=blue]
        \somedrawing
    \end{scope}

    \translatepoint{0,0,8}
    \draw[very thick,green!50!gray] (0,0,0) -- (0,0,8);
    \begin{scope}[shift=(mytranslation),draw=green!50!gray]
        \somedrawing
    \end{scope}

    \translatepoint{-5,0,-2}
    \draw[very thick,orange] (0,0,0) -- (-5,0,-2);
    \begin{scope}[shift=(mytranslation),draw=orange]
        \somedrawing
    \end{scope}
\end{tikzpicture}

\end{document}

enter image description here


Edit 1: I finally managed the rotation, but, that was a bitch. I put the mathematical foundation for RPY rotations first, a really nice matrix. Then I borrowed an idea from Andrew Stacey from this question: finding out where the (cartesian) unit vectors point via \pgfgetlastxy. Then it was only writing the matrix in Tikz notation, using \pgfgetlastxy once again and there you go!

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{arrows}
\usepackage{amsmath}

\newcommand{\rotateRPY}[3]% roll, pitch, yaw
{   \pgfmathsetmacro{\rollangle}{#1}
    \pgfmathsetmacro{\pitchangle}{#2}
    \pgfmathsetmacro{\yawangle}{#3}

    % to what vector is the x unit vector transformed, and which 2D vector is this?
    \pgfmathsetmacro{\newxx}{cos(\yawangle)*cos(\pitchangle)}
    \pgfmathsetmacro{\newxy}{sin(\yawangle)*cos(\pitchangle)}
    \pgfmathsetmacro{\newxz}{-sin(\pitchangle)}
    \path (\newxx,\newxy,\newxz);
    \pgfgetlastxy{\nxx}{\nxy};

    % to what vector is the y unit vector transformed, and which 2D vector is this?
    \pgfmathsetmacro{\newyx}{cos(\yawangle)*sin(\pitchangle)*sin(\rollangle)-sin(\yawangle)*cos(\rollangle)}
    \pgfmathsetmacro{\newyy}{sin(\yawangle)*sin(\pitchangle)*sin(\rollangle)+ cos(\yawangle)*cos(\rollangle)}
    \pgfmathsetmacro{\newyz}{cos(\pitchangle)*sin(\rollangle)}
    \path (\newyx,\newyy,\newyz);
    \pgfgetlastxy{\nyx}{\nyy};

    % to what vector is the z unit vector transformed, and which 2D vector is this?
    \pgfmathsetmacro{\newzx}{cos(\yawangle)*sin(\pitchangle)*cos(\rollangle)+ sin(\yawangle)*sin(\rollangle)}
    \pgfmathsetmacro{\newzy}{sin(\yawangle)*sin(\pitchangle)*cos(\rollangle)-cos(\yawangle)*sin(\rollangle)}
    \pgfmathsetmacro{\newzz}{cos(\pitchangle)*cos(\rollangle)}
    \path (\newzx,\newzy,\newzz);
    \pgfgetlastxy{\nzx}{\nzy};
}

\tikzset{RPY/.style={x={(\nxx,\nxy)},y={(\nyx,\nyy)},z={(\nzx,\nzy)}}}

\begin{document}

$R=\begin{pmatrix}
    \cos \alpha \cos \beta
&   \textcolor{red}{\cos \alpha \sin \beta \sin \gamma - \sin \alpha \cos \gamma}
&   \cos \alpha \sin \beta \cos \gamma + \sin \alpha \sin \gamma \\
    \textcolor{red}{\sin \alpha \cos \beta}
&   \sin \alpha \sin \beta \sin \gamma + \cos \alpha \cos \gamma
&   \textcolor{red}{\sin \alpha \sin \beta \cos \gamma - \cos \alpha \sin \gamma} \\
    - \sin \beta
&   \textcolor{red}{\cos \beta \sin \gamma}
&   \cos \beta \cos \gamma
\end{pmatrix}\\p'=R\cdot p$

\begin{tikzpicture}
    \draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
    \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
    \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);

    \rotateRPY{0}{0}{45}
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
        \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
        \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);
    \end{scope}
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 0,0,45};
\end{tikzpicture}
\begin{tikzpicture}
    \draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
    \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
    \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);

    \rotateRPY{0}{30}{0}
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
        \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
        \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);
    \end{scope}
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 0,30,0};
\end{tikzpicture}

\begin{tikzpicture}
\draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
    \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
    \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);

    \rotateRPY{80}{0}{0}
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
        \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
        \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);
    \end{scope}
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 80,0,0};
\end{tikzpicture}
\begin{tikzpicture}[x={(0.866cm,-0.5cm)},y={(-0.866cm,-0.5cm)},z={(0cm,1cm)}]
\draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
    \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
    \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);

    \rotateRPY{13}{171}{55}
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \draw[-latex] node at (3.5,0,0) {x} (0,0,0) -- (3,0,0);
        \draw[-latex] node at (0,3.5,0) {y} (0,0,0) -- (0,3,0);
        \draw[-latex] node at (0,0,3.5) {z} (0,0,0) -- (0,0,3);
    \end{scope}
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 13,171,55};
\end{tikzpicture}

\end{document}

enter image description here


Edit 2: Now you can pass a point to the command and determine to what new xyz coordinates it is mapped. Also, inspired by Herbert's solution, there now is a better example featuring cubes and arrows:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{arrows,3D}

\newcommand{\savedx}{0}
\newcommand{\savedy}{0}
\newcommand{\savedz}{0}

\newcommand{\somedrawing}%
{   \coordinate (a) at (-2,-2,-2);
    \coordinate (b) at (-2,-2,2);
    \coordinate (c) at (-2,2,-2);
    \coordinate (d) at (-2,2,2);
    \coordinate (e) at (2,-2,-2);
    \coordinate (f) at (2,-2,2);
    \coordinate (g) at (2,2,-2);
    \coordinate (h) at (2,2,2);
    \draw (a)--(b) (a)--(c) (a)--(e) (b)--(d) (b)--(f) (c)--(d) (c)--(g) (d)--(h) (e)--(f) (e)--(g) (f)--(h) (g)--(h);
    \fill (a) circle (0.1cm);
    \fill (d) ++(0.1cm,0.1cm) rectangle ++(-0.2cm,-0.2cm);
}

\newcommand{\rotateRPY}[4][0/0/0]% point to be saved to \savedxyz, roll, pitch, yaw
{   \pgfmathsetmacro{\rollangle}{#2}
    \pgfmathsetmacro{\pitchangle}{#3}
    \pgfmathsetmacro{\yawangle}{#4}

    % to what vector is the x unit vector transformed, and which 2D vector is this?
    \pgfmathsetmacro{\newxx}{cos(\yawangle)*cos(\pitchangle)}% a
    \pgfmathsetmacro{\newxy}{sin(\yawangle)*cos(\pitchangle)}% d
    \pgfmathsetmacro{\newxz}{-sin(\pitchangle)}% g
    \path (\newxx,\newxy,\newxz);
    \pgfgetlastxy{\nxx}{\nxy};

    % to what vector is the y unit vector transformed, and which 2D vector is this?
    \pgfmathsetmacro{\newyx}{cos(\yawangle)*sin(\pitchangle)*sin(\rollangle)-sin(\yawangle)*cos(\rollangle)}% b
    \pgfmathsetmacro{\newyy}{sin(\yawangle)*sin(\pitchangle)*sin(\rollangle)+ cos(\yawangle)*cos(\rollangle)}% e
    \pgfmathsetmacro{\newyz}{cos(\pitchangle)*sin(\rollangle)}% h
    \path (\newyx,\newyy,\newyz);
    \pgfgetlastxy{\nyx}{\nyy};

    % to what vector is the z unit vector transformed, and which 2D vector is this?
    \pgfmathsetmacro{\newzx}{cos(\yawangle)*sin(\pitchangle)*cos(\rollangle)+ sin(\yawangle)*sin(\rollangle)}
    \pgfmathsetmacro{\newzy}{sin(\yawangle)*sin(\pitchangle)*cos(\rollangle)-cos(\yawangle)*sin(\rollangle)}
    \pgfmathsetmacro{\newzz}{cos(\pitchangle)*cos(\rollangle)}
    \path (\newzx,\newzy,\newzz);
    \pgfgetlastxy{\nzx}{\nzy};

    % transform the point given by #1
    \foreach \x/\y/\z in {#1}
    {   \pgfmathsetmacro{\transformedx}{\x*\newxx+\y*\newyx+\z*\newzx}
        \pgfmathsetmacro{\transformedy}{\x*\newxy+\y*\newyy+\z*\newzy}
        \pgfmathsetmacro{\transformedz}{\x*\newxz+\y*\newyz+\z*\newzz}
        \xdef\savedx{\transformedx}
        \xdef\savedy{\transformedy}
        \xdef\savedz{\transformedz}     
    }
}

\tikzset{RPY/.style={x={(\nxx,\nxy)},y={(\nyx,\nyy)},z={(\nzx,\nzy)}}}

\begin{document}

\begin{tikzpicture}
    \somedrawing
    \rotateRPY{0}{0}{101}
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \somedrawing
    \end{scope}
    \draw[canvas is xy plane at z=2,-latex,thick, blue] (-2,2) arc (135:236:2.828);
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 0,0,101};
\end{tikzpicture}
\begin{tikzpicture}
    \somedrawing    
    \rotateRPY{0}{55}{0}
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \somedrawing
    \end{scope}
    \draw[canvas is xz plane at y=2,-latex,thick, blue] (-2,2) arc (135:80:2.828);
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 0,55,0};
\end{tikzpicture}

\begin{tikzpicture}
    \somedrawing    
    \rotateRPY{61}{0}{0}
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \somedrawing
    \end{scope}
    \draw[canvas is yz plane at x=-2,-latex,thick, blue] (2,2) arc (45:106:2.828);
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 71,0,0};
\end{tikzpicture}
\begin{tikzpicture}%[x={(1cm,1cm)},y={(-1cm,1cm)},z={(-2cm,-1cm)}]
    \somedrawing    
    \rotateRPY[-2/2/2]{13}{171}{55}
    \node[fill=white,fill opacity=0.7,text opacity=1,align=left,text=blue] at (5,2)  {-2 $\longrightarrow$ \savedx \\ 2 $\longrightarrow$ \savedy \\ 2 $\longrightarrow$ \savedz};  
    \begin{scope}[draw=red, text=red,fill=red,densely dashed,RPY]
        \somedrawing
    \end{scope}
    \draw[blue,ultra thick] (-2,2,2) -- (\savedx,2,2) -- (\savedx,\savedy,2) -- (\savedx,\savedy,\savedz) circle (0.25);
    \rotateRPY[-2/-2/-2]{13}{171}{55}
    \node[fill=white,fill opacity=0.7,text opacity=1,align=left,text=green!50!gray] at (5,0)  {-2 $\longrightarrow$ \savedx \\ -2 $\longrightarrow$ \savedy \\ -2 $\longrightarrow$ \savedz};
    \draw[green!50!gray,ultra thick] (-2,-2,-2) -- (\savedx,-2,-2) -- (\savedx,\savedy,-2) -- (\savedx,\savedy,\savedz) circle (0.25);
    \node[fill=white,fill opacity=0.7,text opacity=1] {RPY: 13,171,55};
\end{tikzpicture}

\end{document}

enter image description here


an example with PStricks. Run it with xelatex

\documentclass{article}
\pagestyle{empty}
\setlength\parindent{0pt}
\usepackage{pst-solides3d}
\begin{document}
\psset{viewpoint=20 60 20 rtp2xyz,lightsrc=10 15 7,Decran=20}
\begin{pspicture}(-5,-5)(6,5)
\psSolid[object=grille,base=-3 3 -3 3,fillcolor=red!50]
\axesIIID(4,4,3)
\psSolid[object=cube,a=2,ngrid=3,RotX=45,RotY=30,fillcolor=yellow!50](-2,0,0)
\psSolid[object=cube,a=2,ngrid=3,transform={.75 3 .5 scaleOpoint3d}](2,0,1)
\psSolid[object=cube,a=2,ngrid=3,RotZ=30,transform={ 3 -2 0 addv3d },action=draw](-2,0,0)
\end{pspicture}
\end{document}
  • 1st cube: rotated at the x and y axis (center of the box at (-2,0,0) )
  • 2nd: scaled by x=0.75, y=3, z=0.5 (center at (2,0,1) )
  • 3rd: rotated at the z axis and moved by (3,-2,0) (center at (-2,0,0) )

enter image description here

Tags:

Tikz Pgf