%% $Id: pst-3d-doc.tex 289 2010-02-13 14:35:35Z herbert $
\documentclass[11pt,english,BCOR10mm,DIV12,bibliography=totoc,parskip=false,smallheadings
    headexclude,footexclude,oneside,dvipsnames,svgnames]{pst-doc}
\listfiles

\usepackage[utf8]{inputenc}
\usepackage{pst-3d}
\SpecialCoor
\let\pstFV\fileversion
\let\belowcaptionskip\abovecaptionskip
%
\makeatletter
\renewcommand*\l@subsection{\bprot@dottedtocline{2}{1.5em}{3.6em}}
\renewcommand*\l@subsubsection{\bprot@dottedtocline{3}{3.8em}{4.5em}}
\makeatother
\def\bgImage{}
\lstset{explpreset={pos=l,width=-99pt,overhang=0pt,hsep=\columnsep,vsep=\bigskipamount,rframe={}},
    escapechar=?}
\def\textat{\char064}%
\usepackage{shortvrb}
\MakeShortVerb{|}
\def\la{<}
\def\ra{>}
\def\arc{\mathrm{arc}}
\def\sign{\mathrm{sign}}
\def\PiCTeX{\texttt{PiCTeX}}
\def\endmacro{}

\begin{document}
\title{\texttt{pst-3d}\\basic three dimension functions \\\small v.\pstFV}
\docauthor{Herbert Vo\ss}
\author{Timothy Van Zandt\\Herbert Vo\ss}
\date{\today}

\maketitle

\begin{abstract}
This version of \LPack{pst-3d} uses the extended keyval handling
of \LPack{pst-xkey}.

\vfill
\noindent
Thanks to:  
\end{abstract}

\clearpage
\tableofcontents

\clearpage

\section[PostScript]{PostScript functions \nxLps{SetMatrixThreeD},\nxLps{ProjThreeD}, and \nxLps{SetMatrixEmbed}}
 \xLps{SetMatrixThreeD}\xLps{ProjThreeD}\xLps{SetMatrixEmbed}
The \Index{viewpoint} for 3D coordinates is given by three angles: $\alpha$, $\beta$ and
 $\gamma$. $\alpha$ and $\beta$ determine the direction from which one is
 looking. $\gamma$ then determines the orientation of the observing.

 When $\alpha$, $\beta$ and $\gamma$ are all zero, the observer is looking
 from the negative part of the $y$-axis, and sees the $xz$-plane the way in
 2D one sees the $xy$ plan. Hence, to convert the 3D coordinates to their 2D
 project, $\la x, y, z\ra$ map to $\la x, z\ra$.

 When the orientation is different, we rotate the coordinates, and then
 perform the same projection.

 We move up to latitude $\beta$, over to longitude $\alpha$, and then rotate
 by $\gamma$. This means that we first rotate around $y$-axis by $\gamma$,
 then around $x$-axis by $\beta$, and the around $z$-axis by $\alpha$.

 Here are the matrices:
 \begin{eqnarray*}
   R_z(\alpha) & = & \left[
     \begin{array}{ccc}
       \cos \alpha & -\sin \alpha & 0 \\
       \sin \alpha & cos \alpha   & 0 \\
       0           & 0            & 1
     \end{array} \right] \\
   R_x(\beta) & = & \left[
     \begin{array}{ccc}
       1           & 0            & 0 \\
       0           & \cos \beta   & \sin \beta \\
       0           & -\sin \beta  & \cos \beta
     \end{array} \right] \\
   R_y(\gamma) & = & \left[
     \begin{array}{ccc}
       \cos \gamma & 0            & -\sin \gamma \\
       0           & 1            & 0 \\
       \sin \gamma & 0            & \cos \gamma
     \end{array} \right]
 \end{eqnarray*}

 The rotation of a coordinate is then performed by the matrix $R_z(\alpha)
 R_x(\beta) R_y(\gamma)$. The first and third columns of the matrix are the
 basis vectors of the plan upon which the 3D coordinates are project (the old
 basis vectors were $\la 1, 0, 0\ra$ and $\la 0, 0, 1$\ra; rotating these
 gives the first and third columns of the matrix).

 These new basis vectors are:
 \begin{eqnarray*}
   \tilde{x} & = & \left[
     \begin{array}{c}
       \cos\alpha \cos\gamma - \sin\beta \sin\alpha \sin\gamma \\
       \sin\alpha \cos\gamma + \sin\beta \cos\alpha \sin\gamma \\
       \cos\beta \sin\gamma
     \end{array} \right] \\
   \tilde{z} & = & \left[
     \begin{array}{c}
       -\cos\alpha \sin\gamma - \sin\beta \sin\alpha \cos\gamma \\
       -\sin\alpha \sin\gamma + \sin\beta \cos\alpha \cos\gamma \\
       \cos\beta \cos\gamma
     \end{array} \right]
 \end{eqnarray*}

 Rather than specifying the angles $\alpha$ and $\beta$, the user gives a
 vector indicating where the viewpoint is. This new viewpoint is the rotation
 o the old viewpoint. The old viewpoint is $\la 0, -1, 0\ra$, and so the new
 viewpoint is
 \[
  R_z(\alpha) R_x(\beta) \left[ \begin{array}{c} 0\\-1\\0 \end{array} \right]
  \, = \,
  \left[ \begin{array}{c}
    \cos\beta \sin\alpha \\
    -\cos\beta \cos\alpha \\
    \sin\beta
  \end{array} \right]
  \, = \,
  \left[ \begin{array}{c} v_1 \\ v_2 \\ v_3 \end{array} \right]
 \]
 Therefore,
 \begin{eqnarray*}
   \alpha & = & \arc\tan (v_1 / -v_2) \\
   \beta & = & \arc\tan (v_3 \sin\alpha / v_1)
 \end{eqnarray*}
 Unless $p_1=p_2=0$, in which case $\alpha=0$ and $\beta=\sign(p_3)90$, or
 $p_1=p_3=0$, in which case $\beta=0$.



The syntax of \Lps{SetMatrixThreeD} is
   $v_1$ $v_2$ $v_3$ $\gamma$ SetMatrixThreeD

\Lps{SetMatrixThreeD} first computes
 \[
   \begin{array}{ll}
     a=\sin\alpha & b=\cos\alpha\\
     c=\sin\beta  & d=\cos\beta\\
     e=\sin\gamma & f=\cos\gamma
   \end{array}
 \]
 and then sets \Lps{Matrix3D} to |[|$\tilde{x}$ $\tilde{z}$|]|.


\begin{lstlisting}
/SetMatrixThreeD {
  dup sin /e ED cos /f ED
  /p3 ED /p2 ED /p1 ED
  p1 0 eq
  { /a 0 def /b p2 0 le { 1 } { -1 } ifelse def
    p3 p2 abs
  }
  { p2 0 eq
    { /a p1 0 lt { -1 } { 1 } ifelse def /b 0 def
      p3 p1 abs
    }
    { p1 dup mul p2 dup mul add sqrt dup
      p1 exch div /a ED
      p2 exch div neg /b ED
      p3 p1 a div
    }
    ifelse
  }
  ifelse
  atan dup sin /c ED cos /d ED
  /Matrix3D
  [
    b f mul c a mul e mul sub
    a f mul c b mul e mul add
    d e mul
    b e mul neg c a mul f mul sub
    a e mul neg c b mul f mul add
    d f mul
  ] def
} def
\end{lstlisting}

The syntax of \Lps{ProjThreeD} is $x$ $y$ $z$ \Lps{ProjThreeD} $x'$ $y'$
where $x'=\la x, y, z\ra \cdot \tilde{x}$ and $y'=\la x, y, z\ra \cdot
\tilde{z}$.

\begin{lstlisting}
/ProjThreeD {
  /z ED /y ED /x ED
  Matrix3D aload pop
  z mul exch y mul add exch x mul add
  4 1 roll
  z mul exch y mul add exch x mul add
  exch
} def
\end{lstlisting}

 To embed 2D $\la x, y\ra$ coordinates in 3D, the user specifies the normal
 vector and an angle. If we decompose this normal vector into an angle, as
 when converting 3D coordinates to 2D coordinates, and let $\hat\alpha$,
 $\hat\beta$ and $\hat\gamma$ be the three angles, then when these angles are
 all zero the coordinate $\la x, y\ra$ gets mapped to $\la x, 0, y\ra$, and
 otherwise $\la x, y\ra$ gets mapped to
 \[
   R_z(\hat\alpha) R_x(\hat\beta) R_y(\hat\gamma)
   \left[ \begin{array}{c} x \\ 0 \\ y \end{array} \right]
  \, = \,
   \left[ \begin{array}{c}
    \hat{x}_1 x + \hat{z}_1 y\\
    \hat{x}_2 x + \hat{z}_2 y\\
    \hat{x}_3 x + \hat{z}_3 y
   \end{array} \right]
 \]
 where $\hat{x}$ and $\hat{z}$ are the first and third columns of
 $R_z(\hat\alpha) R_x(\hat\beta) R_y(\hat\gamma)$.

 Now add on a 3D-origin:
 \[
   \left[ \begin{array}{c}
    \hat{x}_1 x + \hat{z}_1 y + x_0\\
    \hat{x}_2 x + \hat{z}_2 y + y_0\\
    \hat{x}_3 x + \hat{z}_3 y + z_0
   \end{array} \right]
 \]

 Now when we project back onto 2D coordinates, we get
 \begin{eqnarray*}
   x' & = & \tilde{x}_1(\hat{x}_1 x + \hat{z}_1 y + x_0) +
            \tilde{x}_2(\hat{x}_2 x + \hat{z}_2 y + y_0) +
            \tilde{x}_3(\hat{x}_3 x + \hat{z}_3 y + z_0)\\
   & = &
   (\tilde{x}_1\hat{x}_1 + \tilde{x}_2\hat{x}_2 + \tilde{x}_3\hat{x}_3) x\\
   + (\tilde{x}_1\hat{z}_1 + \tilde{x}_2\hat{z}_2 + \tilde{x}_3\hat{z}_3) y\\
   + \tilde{x}_1 x_0 + \tilde{x}_2 y_0 + \tilde{z}_3 z_0
   y' & = & \tilde{z}_1(\hat{x}_1 x + \hat{z}_1 y + x_0) +
            \tilde{z}_2(\hat{x}_2 x + \hat{z}_2 y + y_0) +
            \tilde{z}_3(\hat{x}_3 x + \hat{z}_3 y + z_0)\\
   & = &
   (\tilde{z}_1\hat{x}_1 + \tilde{z}_2\hat{x}_2 + \tilde{z}_3\hat{x}_3) x\\
   + (\tilde{z}_1\hat{z}_1 + \tilde{z}_2\hat{z}_2 + \tilde{z}_3\hat{z}_3) y\\
   + \tilde{z}_1 x_0 + \tilde{z}_2 y_0 + \tilde{z}_3 z_0
 \end{eqnarray*}
 Hence, the transformation matrix is:
 \[
   \left[ \begin{array}{c}
   \tilde{x}_1\hat{x}_1 + \tilde{x}_2\hat{x}_2 + \tilde{x}_3\hat{x}_3) \\
   \tilde{z}_1\hat{x}_1 + \tilde{z}_2\hat{x}_2 + \tilde{z}_3\hat{x}_3) \\
   \tilde{x}_1\hat{z}_1 + \tilde{x}_2\hat{z}_2 + \tilde{x}_3\hat{z}_3) \\
   \tilde{z}_1\hat{z}_1 + \tilde{z}_2\hat{z}_2 + \tilde{z}_3\hat{z}_3) \\
   \tilde{x}_1 x_0 + \tilde{x}_2 y_0 + \tilde{z}_3 z_0 \\
   \tilde{z}_1 x_0 + \tilde{z}_2 y_0 + \tilde{z}_3 z_0
   \end{array} \right]
 \]

The syntax of \Lps{SetMatrixEmbed} is
   $x_0$ $y_0$ $z_0$ $\hat{v_1}$ $\hat{v_2}$ $\hat{v_3}$ $\hat{\gamma}$
   $v_1$ $v_2$ $v_3$ $\gamma$ \Lps{SetMatrixEmbed}

\Lps{SetMatrixEmbed} first sets |<x1 x2 x3 y1 y2 y3>| to the basis vectors for
 the viewpoint projection (the tilde stuff above). Then it sets |Matrix3D| to
 the basis vectors for the embedded plane. Finally, it sets the
 transformation matrix to the matrix given above.

\begin{lstlisting}
/SetMatrixEmbed {
  SetMatrixThreeD
  Matrix3D aload pop
  /z3 ED /z2 ED /z1 ED /x3 ED /x2 ED /x1 ED
  SetMatrixThreeD
  [
  Matrix3D aload pop
  z3 mul exch z2 mul add exch z1 mul add 4 1 roll
  z3 mul exch z2 mul add exch z1 mul add
  Matrix3D aload pop
  x3 mul exch x2 mul add exch x1 mul add 4 1 roll
  x3 mul exch x2 mul add exch x1 mul add
  3 -1 roll 3 -1 roll 4 -1 roll 8 -3 roll 3 copy
  x3 mul exch x2 mul add exch x1 mul add 4 1 roll
  z3 mul exch z2 mul add exch z1 mul add
  ]
  concat
} def
\end{lstlisting}


\section{Keywords}
\subsection{\nxLkeyword{viewpoint}}

\begin{lstlisting}
\let\pssetzlength\pssetylength
\define@key[psset]{pst-3d}{viewpoint}{%
  \pst@expandafter\psset@@viewpoint#1 {} {} {} \@nil
  \let\psk@viewpoint\pst@tempg}
\def\psset@@viewpoint#1 #2 #3 #4\@nil{%
  \begingroup
    \pssetxlength\pst@dima{#1}%
    \pssetylength\pst@dimb{#2}%
    \pssetzlength\pst@dimc{#3}%
    \xdef\pst@tempg{%
      \pst@number\pst@dima \pst@number\pst@dimb \pst@number\pst@dimc}%
  \endgroup}
\psset[pst-3d]{viewpoint=1 -1 1}
\end{lstlisting}

\subsection{\nxLkeyword{viewangle}}

\begin{lstlisting}
\define@key[psset]{pst-3d}{viewangle}{\pst@getangle{#1}\psk@viewangle}
\psset[pst-3d]{viewangle=0}
\end{lstlisting}

\subsection{\nxLkeyword{normal}}

\begin{lstlisting}
\define@key[psset]{pst-3d}{normal}{%
  \pst@expandafter\psset@@viewpoint#1 {} {} {} \@nil
  \let\psk@normal\pst@tempg}
\psset[pst-3d]{normal=0 0 1}
\end{lstlisting}


\subsection{\nxLkeyword{embedangle}}
\begin{lstlisting}
\define@key[psset]{pst-3d}{embedangle}{\pst@getangle{#1}\psk@embedangle}
\psset[pst-3d]{embedangle=0}
\end{lstlisting}


\section{Transformation matrix}

\begin{lstlisting}
/TMSave {
  tx@Dict /TMatrix known not { /TMatrix { } def /RAngle { 0 } def } if end
  /TMatrix [ TMatrix CM ] cvx def
} def
/TMRestore { CP /TMatrix [ TMatrix setmatrix ] cvx def moveto } def
/TMChange {
  TMSave
  /cp [ currentpoint ] cvx def % ??? Check this later.
  CM
} def
\end{lstlisting}
 Set standard coor. system , with |pt| units and origin at \Index{currentpoint}.
 This let's us rotate, or whatever, around \TeX's current point, without
 having to worry about strange coordinate systems that the dvi-to-ps
 driver might be using.
\begin{lstlisting}
CP T STV
\end{lstlisting}

 Let M = old matrix (on stack), and M' equal current matrix. Then
 go from M' to M by applying  M Inv(M').
\begin{lstlisting}
CM matrix invertmatrix    % Inv(M')
matrix concatmatrix       % M Inv(M')
\end{lstlisting}
 Now modify transformation matrix:
\begin{lstlisting}
exch exec
\end{lstlisting}
Now apply M Inv(M')
\begin{lstlisting}
concat cp moveto
\end{lstlisting}


\section{Macros}
\subsection{\nxLcs{ThreeDput}}

\begin{lstlisting}
\def\ThreeDput{\pst@object{ThreeDput}}
\def\ThreeDput@i{\@ifnextchar({\ThreeDput@ii}{\ThreeDput@ii(\z@,\z@,\z@)}}
\def\ThreeDput@ii(#1,#2,#3){%
  \pst@killglue\pst@makebox{\ThreeDput@iii(#1,#2,#3)}}
\def\ThreeDput@iii(#1,#2,#3){%
  \begingroup
  \use@par
  \if@star\pst@starbox\fi
  \pst@makesmall\pst@hbox
  \pssetxlength\pst@dima{#1}%
  \pssetylength\pst@dimb{#2}%
  \pssetzlength\pst@dimc{#3}%
  \leavevmode
  \hbox{%
    \pst@Verb{%
        { \pst@number\pst@dima
          \pst@number\pst@dimb
          \pst@number\pst@dimc
          \psk@normal
          \psk@embedangle
          \psk@viewpoint
          \psk@viewangle
          \tx@SetMatrixEmbed
        } \tx@TMChange}%
    \box\pst@hbox
    \pst@Verb{\tx@TMRestore}}%
  \endgroup
  \ignorespaces}
\end{lstlisting}

\section{Arithmetic}\label{Arithmetic}

 {\verb+\pst@divide+}
 This is adapted from Donald Arseneau's |shapepar.sty|.
 Syntax:
 \begin{verbatim}
   \pst@divide{<numerator>}{<denominator>}{<command>}
   \pst@@divide{<numerator>}{<denominator>}
 \end{verbatim}
 <numerator> and <denominator> should be dimensions. |\pst@divide| sets
 <command> to <num>/<den> (in points). |\pst@@divide| sets |\pst@dimg| to
 <num>/<den>.
    \begin{lstlisting}
 \def\pst@divide#1#2#3{%
  \pst@@divide{#1}{#2}%
  \pst@dimtonum\pst@dimg{#3}}
 \def\pst@@divide#1#2{%
  \pst@dimg=#1\relax
  \pst@dimh=#2\relax
  \pst@cntg=\pst@dimh
  \pst@cnth=67108863
  \pst@@@divide\pst@@@divide\pst@@@divide\pst@@@divide
  \divide\pst@dimg\pst@cntg}
    \end{lstlisting}
 The number 16 is the level of uncertainty. Use a lower power of 2 for more
 accuracy (2 is most precise). But if you change it, you must change the
 repetions of |\pst@@@divide| in |\pst@@divide| above:
 \[
   \mbox{precision}^{\mbox{repetitions}} = 65536
 \]
 (E.g., $16^4 = 65536$).
\begin{lstlisting}
 \def\pst@@@divide{%
  \ifnum
    \ifnum\pst@dimg<\z@-\fi\pst@dimg<\pst@cnth
    \multiply\pst@dimg\sixt@@n
  \else
    \divide\pst@cntg\sixt@@n
  \fi}
\end{lstlisting}

 {\verb+\pst@pyth+}
 Syntax:
 \begin{verbatim}
   \pst@pyth{<dim1>}{<dim2>}{<dimen register>}
 \end{verbatim}
 <dimen register> is set to $((dim1)^2+(dim2)^2)^{1/2}$.

 The algorithm is copied from \PiCTeX, by Michael Wichura (with permission).
 Here is his description:
 \begin{quote}
 Suppose $x>0$, $y>0$. Put $s = x+y$. Let $z = (x^2+y^2)^{1/2}$. Then $z =
 s\times f$, where
 \[
   f = (t^2 + (1-t)^2)^{1/2} = ((1+\tau^2)/2)^{1/2}
 \]
 and $t = x/s$  and  $\tau = 2(t-1/2)$.
 \end{quote}
    \begin{lstlisting}
\def\pst@pyth#1#2#3{%
  \begingroup
    \pst@dima=#1\relax
    \ifnum\pst@dima<\z@\pst@dima=-\pst@dima\fi  % dima=abs(x)
    \pst@dimb=#2\relax
    \ifnum\pst@dimb<\z@\pst@dimb=-\pst@dimb\fi  % dimb=abs(y)
    \advance\pst@dimb\pst@dima         % dimb=s=abs(x)+abs(y)
    \ifnum\pst@dimb=\z@
      \global\pst@dimg=\z@             % dimg=z=sqrt(x^2+y^2)
    \else
      \multiply\pst@dima 8\relax              % dima= 8abs(x)
      \pst@@divide\pst@dima\pst@dimb     % dimg =8t=8abs(x)/s
      \advance\pst@dimg -4pt            % dimg = 4tau = (8t-4)
      \multiply\pst@dimg 2
      \pst@dimtonum\pst@dimg\pst@tempa
      \pst@dima=\pst@tempa\pst@dimg           % dima=(8tau)^2
      \advance\pst@dima 64pt         % dima=u=[64+(8tau)^2]/2
      \divide\pst@dima 2\relax                      % =(8f)^2
      \pst@dimd=7pt                % initial guess at sqrt(u)
      \pst@@pyth\pst@@pyth\pst@@pyth            % dimd=sqrt(u)
      \pst@dimtonum\pst@dimd\pst@tempa
      \pst@dimg=\pst@tempa\pst@dimb
      \global\divide\pst@dimg 8             % dimg=z=(8f)*s/8
    \fi
  \endgroup
  #3=\pst@dimg}
\def\pst@@pyth{%                      dimd = g <-- (g + u/g)/2
  \pst@@divide\pst@dima\pst@dimd
  \advance\pst@dimd\pst@dimg
  \divide\pst@dimd 2\relax}
    \end{lstlisting}


 {\verb+\pst@sinandcos+}
 Syntax:
 \begin{verbatim}
   \pst@sinandcos{<dim>}{<int>}
 \end{verbatim}
 <dim>, in |sp| units, should equal 100,000 times the angle, in degrees
 between 0 and 90. <int> should equal the angle's quadrant (0, 1, 2 or 3).
 |\pst@dimg| is set to $\sin(\theta)$ and |\pst@dimh| is set to
 $\cos(\theta)$ (in pt's).

 The algorithms uses the usual McLaurin expansion.
    \begin{lstlisting}
\def\pst@sinandcos#1{%
  \begingroup
    \pst@dima=#1\relax
    \pst@dima=.366022\pst@dima     %Now 1pt=1/32rad
    \pst@dimb=\pst@dima   % dimb->32sin(angle) in pts
    \pst@dimc=32\p@       % dimc->32cos(angle) in pts
    \pst@dimtonum\pst@dima\pst@tempa
    \pst@cntb=\tw@
    \pst@cntc=-\@ne
    \pst@cntg=32
    \loop
    \ifnum\pst@dima>\@cclvi % 256
      \pst@dima=\pst@tempa\pst@dima
      \divide\pst@dima\pst@cntg
      \divide\pst@dima\pst@cntb
      \ifodd\pst@cntb
        \advance\pst@dimb \pst@cntc\pst@dima
        \pst@cntc=-\pst@cntc
      \else
        \advance\pst@dimc by \pst@cntc\pst@dima
      \fi
      \advance\pst@cntb\@ne
    \repeat
    \divide\pst@dimb\pst@cntg
    \divide\pst@dimc\pst@cntg
    \global\pst@dimg\pst@dimb
    \global\pst@dimh\pst@dimc
  \endgroup}
    \end{lstlisting}


 {\verb+\pst@getsinandcos+}
 |\pst@getsinandcos| normalizes the angle to be in the first quadrant, sets
 |\pst@quadrant| to 0 for the first quadrant, 1 for the second, 2 for the
 third, and 3 for the fourth, invokes |\pst@sinandcos|, and sets |\pst@sin|
 to the sine and |\pst@cos| to the cosine.
    \begin{lstlisting}
\def\pst@getsinandcos#1{%
  \pst@dimg=100000sp
  \pst@dimg=#1\pst@dimg
  \pst@dimh=36000000sp
  \pst@cntg=0
  \loop
  \ifnum\pst@dimg<\z@
    \advance\pst@dimg\pst@dimh
  \repeat
  \loop
  \ifnum\pst@dimg>\pst@dimh
    \advance\pst@dimg-\pst@dimh
  \repeat
  \pst@dimh=9000000sp
  \def\pst@tempg{%
    \ifnum\pst@dimg<\pst@dimh\else
      \advance\pst@dimg-\pst@dimh
      \advance\pst@cntg\@ne
      \ifnum\pst@cntg>\thr@@ \advance\pst@cntg-4 \fi
      \expandafter\pst@tempg
    \fi}%
  \pst@tempg
  \chardef\pst@quadrant\pst@cntg
  \ifdim\pst@dimg=\z@
    \def\pst@sin{0}%
    \def\pst@cos{1}%
  \else
    \pst@sinandcos\pst@dimg
    \pst@dimtonum\pst@dimg\pst@sin
    \pst@dimtonum\pst@dimh\pst@cos
  \fi}
    \end{lstlisting}


 \section{Tilting}

 {\verb+\pstilt+}
    \begin{lstlisting}
\def\pstilt#1{\pst@makebox{\pstilt@{#1}}}
\def\pstilt@#1{%
  \begingroup
    \leavevmode
    \pst@getsinandcos{#1}%
    \hbox{%
      \ifcase\pst@quadrant
        \kern\pst@cos\dp\pst@hbox
        \pst@dima=\pst@cos\ht\pst@hbox
        \ht\pst@hbox=\pst@sin\ht\pst@hbox
        \dp\pst@hbox=\pst@sin\dp\pst@hbox
      \or
        \kern\pst@sin\ht\pst@hbox
        \pst@dima=\pst@sin\dp\pst@hbox
        \ht\pst@hbox=\pst@cos\ht\pst@hbox
        \dp\pst@hbox=\pst@cos\dp\pst@hbox
      \or
        \kern\pst@cos\ht\pst@hbox
        \pst@dima=\pst@sin\dp\pst@hbox
        \pst@dimg=\pst@sin\ht\pst@hbox
        \ht\pst@hbox=\pst@sin\dp\pst@hbox
        \dp\pst@hbox=\pst@dimg
      \or
        \kern\pst@sin\dp\pst@hbox
        \pst@dima=\pst@sin\ht\pst@hbox
        \pst@dimg=\pst@cos\ht\pst@hbox
        \ht\pst@hbox=\pst@cos\dp\pst@hbox
        \dp\pst@hbox=\pst@dimg
      \fi
      \pst@Verb{%
        { [ 1 0
            \pst@cos\space \ifnum\pst@quadrant>\@ne neg \fi
            \pst@sin\space
            \ifnum\pst@quadrant>\z@\ifnum\pst@quadrant<\thr@@ neg \fi\fi
            \ifodd\pst@quadrant exch \fi
            0 0
          ] concat
        } \tx@TMChange}%
      \box\pst@hbox
      \pst@Verb{\tx@TMRestore}%
      \kern\pst@dima}%
  \endgroup}
    \end{lstlisting}


 {\verb+\psTilt+}
    \begin{lstlisting}
\def\psTilt#1{\pst@makebox{\psTilt@{#1}}}
\def\psTilt@#1{%
  \begingroup
    \leavevmode
    \pst@getsinandcos{#1}%
    \hbox{%
      \ifodd\pst@quadrant
        \pst@@divide{\dp\pst@hbox}{\pst@cos\p@}%
        \ifnum\pst@quadrant=\thr@@\kern\else\pst@dima=\fi\pst@sin\pst@dimg
        \pst@@divide{\ht\pst@hbox}{\pst@cos\p@}%
        \ifnum\pst@quadrant=\@ne\kern\else\pst@dima=\fi\pst@sin\pst@dimg
      \else
        \ifdim\pst@sin\p@=\z@
          \@pstrickserr{\string\psTilt\space angle cannot be 0 or 180}\@ehpa
          \def\pst@sin{.7071}%
          \def\pst@cos{.7071}%
        \fi
        \pst@@divide{\dp\pst@hbox}{\pst@sin\p@}%
        \ifnum\pst@quadrant=\z@\kern\else\pst@dima=\fi\pst@cos\pst@dimg
        \pst@@divide{\ht\pst@hbox}{\pst@sin\p@}%
        \ifnum\pst@quadrant=\tw@\kern\else\pst@dima=\fi\pst@cos\pst@dimg
      \fi
      \ifnum\pst@quadrant>\@ne
        \pst@dimg=\ht\pst@hbox
        \ht\pst@hbox=\dp\pst@hbox
        \dp\pst@hbox=\pst@dimg
      \fi
      \pst@Verb{%
        { [ 1 0
            \pst@cos\space \pst@sin\space
            \ifodd\pst@quadrant exch \fi
            \tx@Div
            \ifnum\pst@quadrant>\z@\ifnum\pst@quadrant<\thr@@ neg \fi\fi
            \ifnum\pst@quadrant>\@ne -1 \else 1 \fi
            0 0
          ] concat
        } \tx@TMChange}%
      \box\pst@hbox
      \pst@Verb{\tx@TMRestore}%
      \kern\pst@dima}%
  \endgroup}
    \end{lstlisting}


 {\verb+\psset@Tshadowsize,\psTshadowsize+}
\begin{lstlisting}
\define@key[psset]{pst-3d}{Tshadowsize}{%
  \pst@checknum{#1}\psTshadowsize}
\psset[pst-3d]{Tshadowsize=1}
\end{lstlisting}


{\verb+\psset@Tshadowangle,\psk@Tshadowangle+}
\begin{lstlisting}
\define@key[psset]{pst-3d}{Tshadowangle}{%
  \pst@getangle{#1}\psk@Tshadowangle}
\psset[pst-3d]{Tshadowangle=60}
\end{lstlisting}


 {\verb+\psset@Tshadowcolor,\psTshadowcolor+}
\begin{lstlisting}
\define@key[psset]{pst-3d}{Tshadowcolor}{%
  \pst@getcolor{#1}\psTshadowcolor}
\psset[pst-3d]{Tshadowcolor=lightgray}
\end{lstlisting}


 {\verb+\psshadow+}
\begin{lstlisting}
\def\psshadow{\def\pst@par{}\pst@object{psshadow}}
\def\psshadow@i{\pst@makebox{\psshadow@ii}}
\def\psshadow@ii{%
  \begingroup
    \use@par
    \leavevmode
    \pst@getsinandcos{\psk@Tshadowangle}%
    \hbox{%
      \lower\dp\pst@hbox\hbox{%
        \pst@Verb{%
          { [ 1 0
              \pst@cos\space \psTshadowsize mul
              \ifnum\pst@quadrant>\@ne neg \fi
              \pst@sin\space \psTshadowsize mul
              \ifnum\pst@quadrant>\z@\ifnum\pst@quadrant<\thr@@ neg \fi\fi
              \ifodd\pst@quadrant exch \fi
              0 0
            ] concat
          } \tx@TMChange}}%
      \hbox to\z@{{\@nameuse{\psTshadowcolor}\copy\pst@hbox\hss}}%
      \pst@Verb{\tx@TMRestore}%
      \box\pst@hbox}%
  \endgroup}
    \end{lstlisting}

\section{Affin Transformations}

\begin{BDef}
\Lcs{psAffinTransform}\OptArgs\Largb{transformation matrix}\Largb{object}
\end{BDef}

\begin{LTXexample}[width=3cm]
\pspicture(3,6)\psset{linewidth=4pt,arrows=->}
\psline(0,0)(1.5,0)(3,3)\rput*(2.25,1.5){foo}
\psAffinTransform{0.5 0 0 2 0 0}{\color{red}%
  \psline[linecolor=red](0,0)(1.5,0)(3,3)\rput*(2.25,1.5){foo}}%
\endpspicture
\end{LTXexample}

The transformation matrix must be a list of 6 values divided by a space.
For a translation modify the last two values of $1 0 0 1 dx dy$. The values for
$dx$ and $dy$ must be of the unit pt! For a rotation
we have the transformation matrix

\begin{align}
\left[\begin{aligned} \cos(\alpha) & \sin(\alpha) & 0 \\
-\sin(\alpha) & \cos(\alpha) & 0 \\
0 & 0 & 1\end{aligned}\right]
\end{align}

For \Lcs{psAffinTransform} the four values have to be modifies \texttt{a cos a sin a sin neg a cos 0 0}.
Tilting can be done with $sx 0 0 sy 0 0$. All effects can be combined.

\begin{LTXexample}[width=3cm]
\pspicture(3,6)\psset{linewidth=4pt,arrows=->}
\psline(0,0)(1.5,0)(3,3)\rput*(2.25,1.5){foo}
\psAffinTransform{0.5 0.8 0.3 2 20 -20}{\color{red}%
  \psline[linecolor=red](0,0)(1.5,0)(3,3)\rput*(2.25,1.5){foo}}%
\endpspicture
\end{LTXexample}


\clearpage
\section{List of all optional arguments for \texttt{pst-3d}}

\xkvview{family=pst-3d,columns={key,type,default}}





\nocite{*}
\bgroup
\RaggedRight
\bibliographystyle{plain}
\bibliography{pst-3d-doc}
\egroup

\printindex





\end{document}