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:
Version 1
You define x
and 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}
\begin{tikzpicture}[scale=1] \definePrism[angle=30]{(0,0),(0,2),(2,2),(2,0)}{0,1,1,1} \end{tikzpicture}
- minhthien_2016
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}
ERROR: Undefined control sequence. --- TeX said --- <recently read> \c@lor@to@ps l.9 \psframe(-6,-4)(6,9)
- student
action=draw
- user2478
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 - user2478
auto-pst-pdf
works for me, action-draw
works too. Is it possible to control the dash pattern in some way? - student
\pstVerb{SolidesDict begin /pointilles {[6.25 3.75] 1.25 setdash } def end }
that is the original definition. You can insert this command before the pspicture
environment and change the values 6.25 3.75 which represents line--space. This sequence may also contain more than two values - user2478
\psset{unit=0.5,viewpoint=1000 20 30 rtp2xyz,Decran=1000,action=draw}%,dash=0.2 0.4}
- user2478
linejoin' undefined in families
pstricks'. --- TeX said --- See the xkeyval package documentation for explanation. Type H <return> for immediate help. ... l.244 \setIIIDplotDefaults - student
pstricks.tex
is out of date and I suppose also some other files. - user2478
I've modified @Alain Matthes' version 2 code such that one can pass a piece of code that is then expanded in the right scope, allowing one to draw additional lines with access to the vertices. I'm not trying to take credit for anything here, Alain clearly did 99% of the work, and even over 5 years later his code is still very helpful. It just took me a bit to put this example together so I wanted to share it (I undid the (unintentional?) x/y coordinate swapping from his code, too).
\documentclass[preview]{standalone}
\usepackage{tikz}
\usetikzlibrary{3d}
\usetikzlibrary{calc}
\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#4{%
\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 = {(1cm,0cm)},
y = {(0cm,1cm)},
z = {(-\absz cm,-\ordz 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)};
#4;
\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[draw=none] (B\si)--(B\ni)--(F\ni);
\else
\draw (F\ni)--(B\ni);
\ifnum \lasti=1
\draw (B\si)--(B\ni);
\else
\draw[draw=none] (B\si)--(B\ni);
\fi
\fi
\global\let\lasti\i
}%
\endgroup}
\begin{document}
\begin{figure}
\centering
\begin{tikzpicture}[scale=1]
\def\smallHeight{1.0}
\def\largeHeight{3.0}
\def\width{5}
\def\angle{30}
\def\depth{5}
\def\coeff{0.25}
\pgfmathsetmacro{\ol}{0.8} % overlap
\pgfmathsetmacro{\nol}{1.0-\ol}
\definePrism[angle=\angle,zF=\depth,coeff=\coeff]%
{
(\width,0),
(0,0),
(0,\largeHeight),
(\ol*\width,\ol*\smallHeight + \nol*\largeHeight),
(\width,\smallHeight)
}{1,0,0,1,1}{
\draw[-{latex},semithick] ($(F3)!0.25!(F5)+(0,-0.2)$) -- ($(F3)!0.75!(F5)+(0,-0.2)$);
}
\definePrism[angle=\angle,zF=\depth,coeff=\coeff]%
{
(\ol*\width,\ol*\smallHeight+\nol*\largeHeight),
(-\nol*\width,-\nol*\smallHeight+\largeHeight+\nol*\largeHeight),
(-\nol*\width,\ol*\smallHeight+\largeHeight+\nol*\largeHeight),
(\ol*\width,\ol*\smallHeight+\largeHeight+\nol*\largeHeight)
}{1,0,1,1}{
\draw[-{latex},semithick] ($(F1)!0.25!(F2)+(0,0.2)$) -- ($(F1)!0.75!(F2)+(0,0.2)$);
}
\end{tikzpicture}
\caption{A thrust fault}
\end{figure}
\begin{figure}
\centering
\begin{tikzpicture}[scale=1]
\def\height{0.2}
\def\width{1.5}
\def\angle{30}
\def\depth{5}
\def\coeff{0.25}
\pgfmathsetmacro{\ol}{0.5} % overlap
\pgfmathsetmacro{\nol}{1.0-\ol}
\definePrism[angle=\angle,zB=-\nol*\depth,zF=\ol*\depth,coeff=\coeff]%
{
(0,0),
(0,\height),
(\width,\height),
(\width,0)
}{0,1,1,1}{
\draw[-{latex},semithick]
($(F3)!0.25!(B3)+(-0.2,0)$) -- ($(F3)!0.75!(B3)+(-0.2,0)$);
}
\definePrism[angle=\angle,zB=0,zF=\depth,coeff=\coeff]%
{
(\width,0),
(\width,\height),
(2*\width,\height),
(2*\width,0)
}{0,1,1,1}{
%% NB: Instead of figuring out what parts of the first parallelepiped,
%% should not be drawn, we simply draw over it here. If the background is
%% not white, the result will not be the same, naturally.
\path[fill=white] (B1)--(B2)--(F2)--(F1)--cycle;
\path[fill=white] (F1)--(F2)--(F3)--(F4)--cycle;
\draw[fill=white] (F2)--(B2)--(B3)--(F3)--cycle;
\draw[-{latex},semithick]
($(B2)!0.25!(F2)+(0.2,0)$) -- ($(B2)!0.75!(F2)+(0.2,0)$);
}
\end{tikzpicture}
\caption{A strike-slip fault}
\end{figure}
\end{document}