summaryrefslogtreecommitdiff
path: root/graphics/pgf/base/doc/pgfmanual-en-library-perspective.tex
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/pgf/base/doc/pgfmanual-en-library-perspective.tex')
-rw-r--r--graphics/pgf/base/doc/pgfmanual-en-library-perspective.tex446
1 files changed, 446 insertions, 0 deletions
diff --git a/graphics/pgf/base/doc/pgfmanual-en-library-perspective.tex b/graphics/pgf/base/doc/pgfmanual-en-library-perspective.tex
new file mode 100644
index 0000000000..fdf3718e91
--- /dev/null
+++ b/graphics/pgf/base/doc/pgfmanual-en-library-perspective.tex
@@ -0,0 +1,446 @@
+
+\section{Three Point Perspective Drawing Library}
+
+\noindent\emph{by Max Snippe}
+
+\begin{tikzlibrary}{perspective}
+ This library provides tools for perspective drawing with one, two, or three
+ vanishing points.
+\end{tikzlibrary}
+
+
+\subsection{Coordinate Systems}
+
+\begin{coordinatesystem}{three point perspective}
+ The |three point perspective| coordinate system is very similar to the |xyz|
+ coordinate system, save that it will display the provided coordinates with a
+ perspective projection.
+ %
+ \begin{key}{/tikz/cs/x=\meta{number} (initially 0)}
+ The $x$ component of the coordinate. Should be given \emph{without} unit.
+ \end{key}
+ %
+ \begin{key}{/tikz/cs/y=\meta{number} (initially 0)}
+ Same as |x|.
+ \end{key}
+ %
+ \begin{key}{/tikz/cs/z=\meta{number} (initially 0)}
+ Same as |x|.
+ \end{key}
+\end{coordinatesystem}
+
+\begin{coordinatesystem}{tpp}
+ The |tpp| coordinate system is an alias for the |three point perspective|
+ coordinate system.
+\end{coordinatesystem}
+
+
+\subsection{Setting the view}
+
+\begin{key}{/tikz/3d view=\marg{azimuth}\marg{elevation}
+ (default \{-30\}\{15\})}
+ With the |3d view| option, the projection of the 3D coordinates on the 2D page
+ is defined. It is determined by rotating the coordinate system by
+ $-\meta{azimuth}$ around the $z$-axis, and by \meta{elevation} around the
+ (new) $x$-axis, as shown below.
+
+ \begin{tikzpicture}[
+ viewpoint/.pic={
+ \draw (22.5:0.45) -- (0,0) -- (-22.5:0.45);
+ \draw (0,0) ++ (22.5:0.35) arc (22.5:-22.5:0.35);
+ \draw (0.225,0) circle (0.02 and 0.09);
+ }]
+ \begin{scope}[3d view={-20}{20}]
+ \draw[->] (-3,0,0) -- (3,0,0) node[pos=1.05]{x};
+ \draw[->] (0,-3,0) -- (0,3,0) node[pos=1.05]{y};
+ \draw[->] (0,0,-1) -- (0,0,3) node[pos=1.05]{z};
+
+ \pgfmathsetmacro\az{50}
+ \begin{scope}[canvas is xy plane at z=0]
+ \draw[->] (0,0) ++(0,-2) arc (-90:-90+\az:2) coordinate[pos=0.5](az);
+ \draw (az) -- ++(-90+\az/2:1) node[below]{\meta{azimuth}};
+ \draw[dashed] (0,0) -- ++(-90+\az:3);
+ \end{scope}
+ \begin{scope}[rotate around z=\az]
+ \pgfmathsetmacro\el{50}
+ \begin{scope}[canvas is yz plane at x=0]
+ \draw[->] (0,0) ++(-2.5,0) arc (180:180-\el:2.5)
+ coordinate[pos=0.5](el);
+ \draw (el) -- ++(180-\el/2:1) node[above]{\meta{elevation}};
+ \draw[dashed] (0,0) --
+ pic[solid,sloped,transform shape,pos=1.2]{viewpoint} ++(180-\el:3);
+ \end{scope}
+ \end{scope}
+ \end{scope}
+ \end{tikzpicture}
+
+ For example, when both \meta{azimuth} and \meta{elevation} are 0$^\circ$,
+ $+z$ will be pointing upward, and $+x$ will be pointing right. The default is
+ as shown below.
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[3d view]
+ \draw[->] (-1,0,0) -- (1,0,0) node[pos=1.1]{x};
+ \draw[->] (0,-1,0) -- (0,1,0) node[pos=1.1]{y};
+ \draw[->] (0,0,-1) -- (0,0,1) node[pos=1.1]{z};
+\end{tikzpicture}
+\end{codeexample}
+\end{key}
+
+\begin{stylekey}{/tikz/isometric view}
+ A special kind of |3d view| is isometric, which can be set with the
+ |isometric view| style. It simply sets |3d view={-45}{35.26}|. The value for
+ \meta{elevation} is determined with $\arctan(1/\sqrt{2})$. In isometric
+ projection the angle between any pair of axes is 120$^\circ$, as shown below.
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[isometric view]
+ \draw[->] (-1,0,0) -- (1,0,0) node[pos=1.1]{x};
+ \draw[->] (0,-1,0) -- (0,1,0) node[pos=1.1]{y};
+ \draw[->] (0,0,-1) -- (0,0,1) node[pos=1.1]{z};
+\end{tikzpicture}
+\end{codeexample}
+\end{stylekey}
+
+
+\subsection{Defining the perspective}
+
+In this section, the following example cuboid will be used with various
+scaling. As a reference, the axes will be shown too, without perspective
+projection.
+%
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\newcommand\simplecuboid[3]{%
+ \fill[gray!80!white] (tpp cs:x=0,y=0,z=#3)
+ -- (tpp cs:x=0,y=#2,z=#3)
+ -- (tpp cs:x=#1,y=#2,z=#3)
+ -- (tpp cs:x=#1,y=0,z=#3) -- cycle;
+ \fill[gray] (tpp cs:x=0,y=0,z=0)
+ -- (tpp cs:x=0,y=0,z=#3)
+ -- (tpp cs:x=0,y=#2,z=#3)
+ -- (tpp cs:x=0,y=#2,z=0) -- cycle;
+ \fill[gray!50!white] (tpp cs:x=0,y=0,z=0)
+ -- (tpp cs:x=0,y=0,z=#3)
+ -- (tpp cs:x=#1,y=0,z=#3)
+ -- (tpp cs:x=#1,y=0,z=0) -- cycle;}
+\newcommand{\simpleaxes}[3]{%
+ \draw[->] (-0.5,0,0) -- (#1,0,0) node[pos=1.1]{x};
+ \draw[->] (0,-0.5,0) -- (0,#2,0) node[pos=1.1]{y};
+ \draw[->] (0,0,-0.5) -- (0,0,#3) node[pos=1.1]{z};}
+
+\begin{tikzpicture}[3d view]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+
+\begin{codeexample}[setup code,hidden]
+\newcommand\simplecuboid[3]{%
+ \fill[gray!80!white] (tpp cs:x=0,y=0,z=#3)
+ -- (tpp cs:x=0,y=#2,z=#3)
+ -- (tpp cs:x=#1,y=#2,z=#3)
+ -- (tpp cs:x=#1,y=0,z=#3) -- cycle;
+ \fill[gray] (tpp cs:x=0,y=0,z=0)
+ -- (tpp cs:x=0,y=0,z=#3)
+ -- (tpp cs:x=0,y=#2,z=#3)
+ -- (tpp cs:x=0,y=#2,z=0) -- cycle;
+ \fill[gray!50!white] (tpp cs:x=0,y=0,z=0)
+ -- (tpp cs:x=0,y=0,z=#3)
+ -- (tpp cs:x=#1,y=0,z=#3)
+ -- (tpp cs:x=#1,y=0,z=0) -- cycle;}
+
+\newcommand{\simpleaxes}[3]{%
+ \draw[->] (-0.5,0,0) -- (#1,0,0) node[pos=1.1]{x};
+ \draw[->] (0,-0.5,0) -- (0,#2,0) node[pos=1.1]{y};
+ \draw[->] (0,0,-0.5) -- (0,0,#3) node[pos=1.1]{z};}
+\end{codeexample}
+
+\begin{key}{/tikz/perspective=\meta{vanishing points}
+ (default p=\{(10,0,0)\},q=\{(0,10,0)\},r=\{(0,0,20)\})}
+ The `strength' of the perspective can be determined by setting the location of
+ the vanishing points. The default values have a stronger perspective towards
+ $x$ and $y$ than towards $z$, as shown below.
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[3d view,perspective]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+%
+ From this example it also shows that the maximum dimensions of the cuboid are
+ no longer 2 by 2 by 2. This is inherent to the perspective projection.
+ %
+ \begin{key}{/tikz/perspective/p=\marg{x,y,z} (initially (0,0,0))}
+ The location of the vanishing point that determines the `strength' of the
+ perspective in $x$-direction can be set with the |p| key.
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ 3d view,
+ perspective={
+ p = {(5,0,0)}}]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+ %
+ Note also that when only |p| is provided, the perspective in $y$ and $z$
+ direction is turned off.
+
+ To turn off the perspective in $x$-direction, one must set the $x$ component
+ of |p| to \texttt{0} (e.g.\ |p={(0,a,b)}|, where \texttt{a} and \texttt{b}
+ can be any number and will be ignored). Or one can provide |q| and |r| and
+ omit |p|.
+
+ By changing the $y$ and $z$ components of |p|, one can achieve various
+ effects.
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ 3d view,
+ perspective={
+ p = {(5,0,1)}}]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ 3d view,
+ perspective={
+ p = {(5,1,0)}}]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ 3d view,
+ perspective={
+ p = {(5,1,1)}}]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+ %
+ \end{key}
+ %
+ \begin{key}{/tikz/perspective/q=\marg{x,y,z} (initially (0,0,0))}
+ Similar to |p|, but can be turned off by setting its $y$ component to
+ \texttt{0}.
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ 3d view,
+ perspective={
+ q = {(0,5,0)}}]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+ %
+ \end{key}
+ %
+ \begin{key}{/tikz/perspective/r=\marg{x,y,z} (initially (0,0,0))}
+ Similar to |p|, but can be turned off by setting its $z$ component to
+ \texttt{0}.
+ %
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ 3d view,
+ perspective={
+ r = {(0,0,5)}}]
+ \simplecuboid{2}{2}{2}
+ \simpleaxes{2}{2}{2}
+\end{tikzpicture}
+\end{codeexample}
+ %
+ \end{key}
+\end{key}
+
+
+\subsection{Shortcomings}
+
+Currently a number of things are not working, mostly due to the fact that PGF
+uses a 2D coordinate system underwater, and perspective projection is a
+non-linear affine transformation which needs to be aware of all three
+coordinates. These three coordinates are currently lost when processing a 3D
+coordinate.
+The issues include, but possibly are not limited to:
+%
+\begin{itemize}
+ \item Keys like |shift|, |xshift|, |yshift| are not working
+ \item Keys like |rotate around x|, |rotate around y|, and |rotate around z|
+ are not working
+ \item Units are not working
+ \item Most keys from the |3d| library are unsupported, e.g.\ all the
+ |canvas is .. plane| keys.
+\end{itemize}
+
+
+\subsection{Examples}
+
+An |r| that lies `below' your drawing can mimic a macro effect.
+%
+\nopagebreak
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ isometric view,
+ perspective={
+ p = {(8,0,0)},
+ q = {(0,8,0)},
+ r = {(0,0,-8)}}]
+
+ \simplecuboid{2}{2}{2}
+
+\end{tikzpicture}
+\end{codeexample}
+
+A peculiar phenomenon inherent to perspective drawing, is that however great
+your coordinate will become in the direction of the vanishing point, it will
+never reach it.
+%
+\nopagebreak
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ isometric view,
+ perspective={
+ p = {(4,0,0)},
+ q = {(0,4,0)}}]
+
+ \node[fill=red,circle,inner sep=1.5pt,label=above:p] at (4,0,0){};
+
+ \foreach \i in {0,...,100}{
+ \filldraw[fill = gray] (tpp cs:x=\i,y=0,z=0)
+ -- (tpp cs:x=\i+0.5,y=0,z=0)
+ -- (tpp cs:x=\i+0.5,y=2,z=0)
+ -- (tpp cs:x=\i,y=2,z=0)
+ -- cycle;}
+\end{tikzpicture}
+\end{codeexample}
+
+Even for simple examples, the added perspective might add another `dimension' to
+your drawing. In this case, two vanishing points give a more intuitive result
+then three would.
+%
+\nopagebreak
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ scale=0.7,
+ 3d view,
+ perspective={
+ p = {(20,0,0)},
+ q = {(0,20,0)}}]
+
+ \filldraw[fill=brown] (tpp cs:x=0,y=0,z=0)
+ -- (tpp cs:x=0,y=4,z=0)
+ -- (tpp cs:x=0,y=4,z=2)
+ -- (tpp cs:x=0,y=2,z=4)
+ -- (tpp cs:x=0,y=0,z=2) -- cycle;
+ \filldraw[fill=red!70!black] (tpp cs:x=0,y=0,z=2)
+ -- (tpp cs:x=5,y=0,z=2)
+ -- (tpp cs:x=5,y=2,z=4)
+ -- (tpp cs:x=0,y=2,z=4) -- cycle;
+ \filldraw[fill=brown!80!white] (tpp cs:x=0,y=0,z=0)
+ -- (tpp cs:x=0,y=0,z=2)
+ -- (tpp cs:x=5,y=0,z=2)
+ -- (tpp cs:x=5,y=0,z=0) -- cycle;
+\end{tikzpicture}
+\end{codeexample}
+
+With the vanishing points nearby, the distortion of parallel lines becomes very
+strong. This might lead to \texttt{Dimension too large} errors.
+%
+\nopagebreak
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ 3d view,
+ perspective={
+ p = {(2,0,0)},
+ q = {(0,2,0)},
+ r = {(0,0,2)}},
+ scale=4,
+ vanishing point/.style={fill,circle,inner sep=2pt}]
+
+ \simplecuboid{3}{1}{2}
+
+ \node[vanishing point,label = right:p] (p) at (2,0,0){};
+ \node[vanishing point,label = left:q] (q) at (0,2,0){};
+ \node[vanishing point,label = above:r] (r) at (0,0,2){};
+
+ \begin{scope}[dotted]
+ \foreach \y in {0,1}{
+ \foreach \z in {0,2}{
+ \draw (tpp cs:x=0,y=\y,z=\z) -- (p.center);}}
+ \foreach \x in {0,3}{
+ \foreach \z in {0,2}{
+ \draw (tpp cs:x=\x,y=0,z=\z) -- (q.center);}}
+ \foreach \x in {0,3}{
+ \foreach \y in {0,1}{
+ \draw (tpp cs:x=\x,y=\y,z=0) -- (r.center);}}
+ \end{scope}
+\end{tikzpicture}
+\end{codeexample}
+
+% A more complex example.
+\iffalse
+Of course these examples can become as complex as desired, but as with any 3D
+drawing using \tikzname, the order of drawing commands is important and can
+become increasingly more complex.
+%
+\nopagebreak
+\begin{codeexample}[preamble={\usetikzlibrary{perspective}}]
+\begin{tikzpicture}[
+ cycle of vertices/.style 2 args={
+ insert path={
+ foreach \i [count=\j,evaluate=\j as \k using
+ {ifthenelse(\j==1,"","-- "}] in {#2}{\k (vert-#1-\i)} -- cycle}},
+ scale=0.7,
+ line join=round,
+ bottom/.style={draw=white!50!black,fill=white!40!black},
+ front/.style={draw=white!50!black,fill=black},
+ side/.style={draw=white!50!black,fill=white!80!black},
+]
+ \begin{scope}[
+ 3d view={-20}{0},
+ perspective={
+ p = {(20,0,0)},
+ q = {(0,20,0)},
+ r = {(5,1,50)},
+ }]
+ \path foreach \x/\y/\z [count=\i] in {
+ 3.5/2.0/0.0,3.5/2.0/4.0,6.0/2.0/4.0,6.5/2.0/3.5,6.5/2.0/0.5,6.0/2.0/0.0,
+ 4.5/2.0/1.0,4.5/2.0/3.0,5.5/2.0/3.0,5.5/2.0/1.0,3.5/0.0/0.0,3.5/0.0/4.0,
+ 6.0/0.0/4.0,6.5/0.0/3.5,6.5/0.0/0.5,6.0/0.0/0.0,4.5/0.0/1.0,4.5/0.0/3.0,
+ 5.5/0.0/3.0,5.5/0.0/1.0%
+ }{(tpp cs:x=\x,y=\y,z=\z) coordinate[name=vert-D-\i]};
+ \filldraw[front,cycle of vertices={D}{1,...,6},
+ cycle of vertices={D}{7,10,9,8}];
+ \filldraw[side,cycle of vertices={D}{10,9,19,20}];
+ \filldraw[bottom,cycle of vertices={D}{8,9,19,18}];
+ \filldraw[front,cycle of vertices={D}{11,...,16},
+ cycle of vertices={D}{17,20,19,18}];
+ \filldraw[side,cycle of vertices={D}{1,2,12,11}];
+ % '3'
+ \path foreach \x/\y/\z [count=\i] in {
+ 0.0/2.0/0.0,0.0/2.0/1.0,2.0/2.0/1.0,2.0/2.0/1.5,0.0/2.0/1.5,0.0/2.0/2.5,
+ 2.0/2.0/2.5,2.0/2.0/3.0,0.0/2.0/3.0,0.0/2.0/4.0,3.0/2.0/4.0,3.0/2.0/0.0,
+ 0.0/0.0/0.0,0.0/0.0/1.0,2.0/0.0/1.0,2.0/0.0/1.5,0.0/0.0/1.5,0.0/0.0/2.5,
+ 2.0/0.0/2.5,2.0/0.0/3.0,0.0/0.0/3.0,0.0/0.0/4.0,3.0/0.0/4.0,3.0/0.0/0.0%
+ }{(tpp cs:x=\x,y=\y,z=\z) coordinate[name=vert-3-\i]};
+ \filldraw[front,cycle of vertices={3}{1,...,12}];
+ \filldraw[side,cycle of vertices={3}{3,4,16,15}];
+ \filldraw[side,cycle of vertices={3}{7,8,20,19}];
+ \filldraw[side,cycle of vertices={3}{1,2,14,13}];
+ \filldraw[side,cycle of vertices={3}{5,6,18,17}];
+ \filldraw[side,cycle of vertices={3}{9,10,22,21}];
+ \filldraw[bottom,cycle of vertices={3}{4,5,17,16}];
+ \filldraw[bottom,cycle of vertices={3}{8,9,21,20}];
+ \filldraw[front,cycle of vertices={3}{13,...,24}];
+ \end{scope}
+\end{tikzpicture}
+\end{codeexample}
+\fi