# Draw a prism in TikZ or PSTricks

Is there a way to define an polygon in plane and output an (orthogonal) prism with that polygon as its base? The prism should be drawn in 3D in parallel oblique perspective with controllable height h, scaling factor k and angle α. Would be great if something like this is possible in TikZ or PSTricks.

So I want a command \prism which takes the list of points (which define the polygon in a plane), α,k and h as an argument and give me the prism as output.

Perhaps I should make clear what I mean by k and α: For example if you draw a cube in 3D you draw one line, then another one in an angle α = 45° but with k = 1/2 the length of the first one etc.

I think this is called parallel oblique projection (α = 45° and k = 1 would be called cavalier projection, α = 63,4° and k=1/2 cabinet projection). Even though it would be interesting for further purposes, I don't want a one-point perspective projection.

In the picture above the lines in the background are not dashed. However I want dashed background lines. If you have a better picture of those projections, feel free to replace it.

Here are some references about projection types:

-
I opened the question to pstricks, since it is really important for me to get this problem solved. Would be great if it is possible in tikz because I love this, but pstricks or some other solution would be fine too. – student Dec 10 '11 at 9:46

base contains the list of the x/y polygon coordinates and axe defines the direction vector "x y z" of the prism, which is by default axe=0 0 1

\documentclass{article}
\usepackage{pst-solides3d}
\begin{document}

\psset{unit=0.5,lightsrc=10 5 50,viewpoint=50 20 30 rtp2xyz,Decran=50}
\begin{pspicture*}(-6,-4)(6,9)
\psframe(-6,-4)(6,9)
\psSolid[object=grille,base=-4 4 -4 4,fillcolor=red!30]
\psSolid[object=prisme,h=6,fillcolor=blue!10,
base=0 1 -1 0 0 -2 1 -1 0 0]
\axesIIID(4,4,6)(4.5,4.5,8)
\end{pspicture*}
%
\begin{pspicture*}(-6,-4)(6,9)
\psframe(-6,-4)(6,9)
\psSolid[object=grille,base=-4 4 -4 4,fillcolor=red!30]
\psSolid[object=prisme,fillcolor=blue!10,
axe=0 1 2,h=8,base=0 -2 1 -1 0 0 0 1 -1 0]
\psPoint(0,4.2,8.4){V}
\psline[linecolor=blue,arrowscale=2]{->}(0,0)(V)
\axesIIID(4,4,4)(4.5,4.5,8)
\end{pspicture*}

\end{document}


Simple Boxes with pst-3dplot

\documentclass{article}
\usepackage{pst-3dplot}
\begin{document}
\psset{coorType=1,Alpha=135}
\begin{pspicture}(-1,-2)(5,2.25)
%\pstThreeDCoor[xMin=-1,xMax=4,yMin=-1,yMax=4,zMin=-1,zMax=4]
\pstThreeDBox[hiddenLine=false](0,0,0)(0,0,3)(3,0,0)(0,3,0)
\end{pspicture}
%
\psset{coorType=2}
\begin{pspicture}(-3,-2)(2,2.25)
%\pstThreeDCoor[xMin=-1,xMax=4,yMin=-1,yMax=4,zMin=-1,zMax=4]
\pstThreeDBox[hiddenLine](0,0,0)(0,0,3)(3,0,0)(0,3,0)
\end{pspicture}

\end{document}


\documentclass{article}
\usepackage{pst-3dplot}
\begin{document}

\psset{coorType=2}
\begin{pspicture}(-2,-2.25)(2,5)
\pstThreeDCoor[xMin=-2,xMax=2,yMin=-2,yMax=5,zMin=-2,zMax=6]
\pstThreeDLine(0,0,0)(0,3,0)(-2,0,0)(0,-3,0)(1,-3,0)(0,0,0)
\pstThreeDLine(1,2,5)(1,5,5)(-1,2,5)(1,-1,5)(2,-1,5)(1,2,5)
\pstThreeDLine(0,0,0)(1,2,5)
\pstThreeDLine(0,3,0)(1,5,5)
\pstThreeDLine[linestyle=dashed](-2,0,0)(-1,2,5)
\pstThreeDLine[linestyle=dashed](0,-3,0)(1,-1,5)
\pstThreeDLine(1,-3,0)(2,-1,5)
\end{pspicture}

\end{document}


and an automatic solution which needs the latest pst-3dplot.tex from http://texnik.dante.de/tex/generic/pst-3dplot/. The Macro \psThreeDPrism will move later to CTAN and also very later I'll realize hidden lines. move=x y is the translation vector for the upper polygon

\documentclass{article}
\usepackage{pst-3dplot}
\begin{document}

\psset{coorType=2}
\begin{pspicture}(-3,-2)(2,5)
\pstThreeDCoor[xMin=-2,xMax=2,yMin=-2,yMax=5,zMin=-2,zMax=7]
\pstThreeDPrism[height=6,move=1 2](0,0,0)(0.5,3,0)(-2,0,0)(0,-3,0)(1,-3,0)(0,0,0)
\end{pspicture}

\end{document}


-
Thanks, looks great. Is it possible to get the prism's drawn like in Altermundus's answer (the orientation is ok, just white sides and dashed background lines? – student Dec 10 '11 at 10:11
If I try this, I get an error: ERROR: Undefined control sequence. --- TeX said --- <recently read> \c@lor@to@ps l.9 \psframe(-6,-4)(6,9) – student Dec 10 '11 at 10:14
use action=draw – Herbert Dec 10 '11 at 10:16
run it with xelatex or use the sequence latex->dvips->ps2pdf or use package auto-pst-pdf and run it with pdflatex -shell-escape <file>. See tug.org/PSTricks/main.cgi?file=pdf/pdfoutput – Herbert Dec 10 '11 at 10:18
Thanks, auto-pst-pdf works for me, action-draw works too. Is it possible to control the dash pattern in some way? – student Dec 10 '11 at 10:28

Version 1

You define xand y to get correct a and k. It's not the unique way and it's also possible to reduce the code with a macro.

\documentclass[]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{3d}
\begin{document}

\begin{tikzpicture}[x  = {(-0.65cm,-0.45cm)},
y  = {(0.65cm,-0.45cm)},
z  = {(0cm,0.8cm)},
scale = 2]

\begin{scope}[canvas is zy plane at x=5]
\draw (0,0) coordinate (a1)
-- (3,2) coordinate (a2)
-- (3,4) coordinate (a3)
-- (2,5) coordinate (a4)
-- (0,4) coordinate (a5)--cycle ;
\end{scope}

\begin{scope}[canvas is zy plane at x=0]
\path (0,0) coordinate (b1)
(3,2) coordinate (b2)
(3,4) coordinate (b3)
(2,5) coordinate (b4)
(0,4) coordinate (b5);
\end{scope}

\draw (b2)--(b3)--(b4)--(b5);

\foreach \i in {2,...,5}
\draw (a\i)--(b\i);

\draw[dashed] (b5)--(b1)--(b2) (a1)--(b1);
\end{tikzpicture}
\end{document}


Version 2 I changed the name of the nodes. Bi for vertices of the Background face and Fi for vertices of the Front face. Now I created a macro to define the points. You need to give the coordinates, the coefficient and alpha (l'angle de fuite).

The code for the first picture is

\begin{tikzpicture}[scale=1.6]
\definePrism{(0,0),
(1,0),
(1,1),
(0,1)}{0}{1}{.5}{30}
\begin{scope}[x  = {(0cm,1cm)},
y  = {(1cm,0)},
z  = {(-\ordz cm,-\absz cm)}]
\begin{scope}[canvas is yz plane at x=0]
\draw[dotted] (0,0) circle (1cm);
\draw[<->] (1,0) arc (0:-90:1cm);
\draw[dotted,blue] (0,0)--(0,-1);
\node[text width=2cm] at (0.5,-2) {fuite\\ $\alpha=30^{\circ}$};
\node[text width=2cm] at (-0.6,0.2) {$-k\cos(\alpha)$\\
$-k\sin(\alpha)$};
\end{scope}
\end{scope}
\end{tikzpicture}


Now a complete example

\documentclass[]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{3d}

\newcommand {\definePrism}[5]
{\pgfmathsetmacro{\absz}{#4*sin(#5)} \pgfmathsetmacro{\ordz}{#4*cos(#5)}
\begin{scope}[x  = {(0cm,1cm)},
y  = {(1cm,0)},
z  = {(-\ordz cm,-\absz cm)}]
\begin{scope}[canvas is xy plane at z=#2]
\path \foreach \coord [count=\ni] in {#1} {\coord coordinate (B\ni)};
\end{scope}
\begin{scope}[canvas is xy plane at z=#3]
\path  \foreach \coord [count=\ni] in {#1} {\coord coordinate (F\ni)};
\end{scope}
\end{scope}
}
\begin{document}

\begin{tikzpicture}[scale=1]

\definePrism{(0,0),
(3,2),
(3,4),
(2,5),
(0,2)}{0}{8}{.7}{45}

\draw (F1) \foreach \i in {2,...,5} {--(F\i)} -- cycle;
\draw (B2)--(B3)--(B4);
\draw[dashed] (B4)--(B5)--(B1)--(B2);

\draw          (F2)--(B2)
(F3)--(B3)
(F4)--(B4);
\draw[dashed]  (F1)--(B1)
(F5)--(B5);
\end{tikzpicture}
\end{document}


version 2 with macro \definePrism

 \definePrism[options]{list 1}{list 2}
options angle (default=45) coeff (default=.5) zB (default=0) zF (default=2)
list 1 (x1,y1),(x2,y2),...,(xn,yn)
list 2  s1,s2,...,sn with sn = 0 or 1---> 0 if  Bn is hidden
coordinates defined : B1,B2,...,Bn and F1,F2,...,Fn


Only problem : how to determine s1,s2,...,sn automatically . I know some algorithms but too complicated with TeX

\documentclass[]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{3d}

\pgfkeys{
/definePrism/.cd,
angle/.code                = {\def\dpangle{#1}},
coeff/.code                = {\def\dpcoeff{#1}},
zB/.code                    = {\def\zB{#1}},
zF/.code                    = {\def\zF{#1}},}
\makeatletter
\def\definePrism{\pgfutil@ifnextchar[{\define@Prism}{\define@Prism[]}}
\def\define@Prism[#1]#2#3{%
\begingroup
\pgfkeys{/definePrism/.cd, angle=45,coeff=.5,zB=0,zF=2}
\pgfqkeys{/definePrism}{#1}
\pgfmathsetmacro{\absz}{\dpcoeff*sin(\dpangle)}
\pgfmathsetmacro{\ordz}{\dpcoeff*cos(\dpangle)}
\begin{scope}[x  = {(0cm,1cm)},
y  = {(1cm,0)},
z  = {(-\ordz cm,-\absz cm)}]
\begin{scope}[canvas is xy plane at z=\zB]
\path \foreach \coord [count=\ni] in {#2} {%
\coord   coordinate  (B\ni)
};
\end{scope}
\begin{scope}[canvas is xy plane at z=\zF]
\path  \foreach \coord [count=\ni] in {#2} {%
\coord coordinate (F\ni)
};
\end{scope}
\end{scope}

\foreach \k [count=\ni] in {#3} {%
\global\let\nb\ni
\global\let\lasti\k}
\draw (F1) \foreach \i in {2,...,\nb} {--(F\i)} -- cycle;

\foreach \i  [count=\ni,count=\si from \nb] in {#3}{
\ifnum \ni > \nb \pgfmathtruncatemacro{\ni}{1} \fi
\ifnum \si > \nb \pgfmathtruncatemacro{\si}{1} \fi
\ifnum \i  = 0
\draw[dashed] (B\si)--(B\ni)--(F\ni);
\else
\draw (F\ni)--(B\ni);
\ifnum \lasti=1
\draw (B\si)--(B\ni);
\else
\draw[dashed] (B\si)--(B\ni);
\fi
\fi
\global\let\lasti\i
}%
\endgroup}
\begin{document}

\begin{tikzpicture}[scale=1]
\definePrism[angle=30,zF=8]{(0,0),(4,1),(3,4),(2,3),(0,2)}{0,1,1,1,1}
\end{tikzpicture}
\begin{tikzpicture}[scale=1]
\definePrism[angle=30]{(0,0),(0,2),(2,2),(2,0)}{0,1,1,1}
\end{tikzpicture}
\end{document}


-
Thanks, that's exaclty that type of image that I want. However, how to make a macro which takes a list of points (which define the polygon in the plane), \alpha, k and h as arguments and returns the image? Perhaps the problem is that the number of points is variable? – student Dec 7 '11 at 15:13
No the list of points is not the main problem but there is a big problem with dashed edges. – Alain Matthes Dec 7 '11 at 15:36
Yes I see. Don't know if there is an algorithm to determine the background edges automatically. However this is what I need. – student Dec 10 '11 at 9:35
I think your answer is great, but only the first step in the right direction. I need that everything is drawn automatically, define only the polygon and so on. So even though I voted your answer up, I am not going to accept it, because it's really important for me to get this fully automated... – student Dec 10 '11 at 9:39
@user4011 A possibility would be to give for with each point of the polygon the state ( a boolean) in the background face (hidden or not). I's not obvious to know automatically the state of a point. I'm very interesting if someone knows how to do this ! – Alain Matthes Dec 10 '11 at 10:07