我怎样才能简化 some 定位与 someforeach loops
或 some own styles
?这是原图:
这是我的 MWE:
\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}[every node/.style={font=\tiny},scale=1.5,xscale=1.2]
\coordinate (a) at (0:1.5);
\coordinate (b) at (60:1);
\coordinate (c) at (120:1);
\coordinate (d) at (180:1.5);
\coordinate (e) at (240:1);
\coordinate (f) at (300:1);
\draw[dashed] (a) -- (b) -- (c) -- (d);
\draw (d) -- (e) -- (f) -- (a);
\draw (a) -- (0,3);
\draw (0,3) -- ($(b)!.5!(0,3)$);
\draw[dashed] (c) -- ($(c)!.5!(0,3)$);
\draw ($(c)!.5!(0,3)$) -- (0,3);
\draw[dashed] (b) -- ($(b)!.5!(0,3)$);
\draw (0,3) -- (d);
\draw (0,3) -- (e);
\draw (0,3) -- (f);
\draw ($(a)!.5!(0,3)$) -- ($(b)!.5!(0,3)$) -- ($(c)!.5!(0,3)$) -- ($(d)!.5!(0,3)$) -- ($(e)!.5!(0,3)$) -- ($(f)!.5!(0,3)$) -- cycle;
\fill[black,opacity=.3] ($(a)!.5!(0,3)$) -- ($(b)!.5!(0,3)$) -- ($(c)!.5!(0,3)$) -- ($(d)!.5!(0,3)$) -- ($(e)!.5!(0,3)$) -- ($(f)!.5!(0,3)$) -- cycle;
\fill[gray,opacity=.3] ($(a)!.5!(0,3)$) -- ($(b)!.5!(0,3)$) -- (b) -- (a) -- cycle;
\fill[gray,opacity=.3] ($(b)!.5!(0,3)$) -- ($(c)!.5!(0,3)$) -- (c) -- (b) -- cycle;
\fill[gray,opacity=.3] ($(d)!.5!(0,3)$) -- ($(e)!.5!(0,3)$) -- (e) -- (d) -- cycle;
\fill[gray,opacity=.3] ($(c)!.5!(0,3)$) -- ($(d)!.5!(0,3)$) -- (d) -- (c) -- cycle;
\fill[gray,opacity=.3] ($(e)!.5!(0,3)$) -- ($(f)!.5!(0,3)$) -- (f) -- (e) -- cycle;
\fill[black,opacity=.3] ($(f)!.5!(0,3)$) -- ($(a)!.5!(0,3)$) -- (a) -- (f) -- cycle;
\draw[dashed] ([xshift=-.75cm]$(a)!.5!(0,3)$) -- (0,0);
\draw[fill=white,radius=.1em] (0,0) circle node[right] {$O_1$};
\draw ([xshift=-.75cm]$(a)!.5!(0,3)$) -- (0,3);
\draw[fill=white,radius=.1em] ([xshift=-.75cm]$(a)!.5!(0,3)$) circle node[above right=-3.5] {$O_1'$};
\node[above right=-2] at (b) {$A_i$};
\node[above left=-2] at (b) {$A_2'$};
\node[above right=-2] at (c) {$A_1'$};
\draw[fill=white,radius=.1em] (b) circle;
\draw[fill=white,radius=.1em] (c) circle;
\node[left] at (d) {$A_n$};
\node[below] at (e) {$A_1$};
\node[below] at (f) {$A_2$};
\draw[fill=white,radius=.1em] (0,3) circle node[above] {$O$};
\node[above left=-2] at ($(d)!.5!(0,3)$) {$A_n'$};
\node[above right=-4] at ($(b)!.5!(0,3)$) {$A_i'$};
\draw[fill=white,radius=.1em] ($(a)!.5!(0,3)$) circle;
\draw[fill=white,radius=.1em] ($(b)!.5!(0,3)$) circle;
\draw[fill=white,radius=.1em] ($(c)!.5!(0,3)$) circle;
\draw[fill=white,radius=.1em] ($(d)!.5!(0,3)$) circle;
\draw[fill=white,radius=.1em] ($(e)!.5!(0,3)$) circle;
\draw[fill=white,radius=.1em] ($(f)!.5!(0,3)$) circle;
\end{tikzpicture}
\end{document}
这也是输出:
奖金:通常怎样才能清理代码?
答案1
因为在我看来这是一个非常好的问题,所以我想收集一些我从其他人或 pgfmanual 那里学到的技巧。
钛钾Z 非常有文化,它能理解字母表,所以你可以进行循环
{a,...,f}
。你也可以做双循环。
可以将数字转换为字母。我不知道我的方法是否最优雅,但可以定义一个计数器,设置它,然后使用它将
\alph
其转换为字母。(我不声称自己是这个技巧的先行者,如果其他地方有更优雅的方法,我也不会感到惊讶。我只是搜索的时间不够长。)我从 @percusse 那里学到的一个技巧(如果我没记错的话)是这样做
\draw plot[samples at={a,...,f},variable=\x] (\x);
连接
a
到b
...f
。我在写这个答案时学到了一个可能更强大的技巧,那就是
foreach
风格。示例如下代码所示。还有Loop Space 的答案,但我不敢尝试。请注意,这确实不是根本没有暗示有什么问题,我只是犹豫是否使用它。编辑:正如@Max Snippe 指出的那样,一种更优雅的方式就是简单地说\fill[black,opacity=0.3] (a') foreach \p in {b,...,f}{ -- (\p')} -- cycle;
我还添加了三个低透明度的正面,使 3D 感更加明显。
\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{calc}
\newcounter{cheat}
\begin{document}
\begin{tikzpicture}[every node/.style={font=\tiny},scale=1.5,xscale=1.2]
\foreach \X [count=\Y,evaluate=\Y as \Z using {int(60*(\Y-1))}]
in {a,...,f}
{\pgfmathtruncatemacro{\Cheat}{int(mod(\Y-1,3))}
\ifnum\Cheat=0
\coordinate (\X) at (\Z:1.5);
\else
\coordinate (\X) at (\Z:1);
\fi
}
\draw[dashed] (a) -- (b) -- (c) -- (d);
\draw (d) -- (e) -- (f) -- (a);
\draw (a) -- (0,3);
% define primed coordinates for later use
\foreach \X in {a,...,f}
{\coordinate (\X') at ($(\X)!.5!(0,3)$);}
\draw (0,3) -- (b');
\draw[dashed] (c) -- (c');
\draw (c') -- (0,3);
\draw[dashed] (b) -- (b');
\foreach \X in {d,e,f}
{\draw (0,3) -- (\X);}
% foreach style from https://tex.stackexchange.com/a/124105/121799
\fill[black,opacity=.3,foreach/.style={insert path=--(#1')}] (a') [foreach/.list={b,...,f}]
-- cycle;
\foreach \X [count=\Y,evaluate=\Y as \Z using {ifthenelse(\Y==5,6,int(mod(\Y+1,6)))}]
in {a,...,f} {\setcounter{cheat}{\Z}
\def\NextX{\alph{cheat}}
\draw (\X') -- (\NextX');
\fill[gray,opacity=.3] (\NextX') -- (\X') --
(\X) -- (\NextX) -- cycle;
}
\draw[dashed] ([xshift=-.75cm]$(a)!.5!(0,3)$) -- (0,0);
\draw[fill=white,radius=.1em] (0,0) circle node[right] {$O_1$};
\draw ([xshift=-.75cm]$(a)!.5!(0,3)$) -- (0,3);
\draw[fill=white,radius=.1em] ([xshift=-.75cm]$(a)!.5!(0,3)$) circle node[above right=-3.5] {$O_1'$};
\node[above right=-2] at (b) {$A_i$};
\node[above left=-2] at (b) {$A_2'$};
\node[above right=-2] at (c) {$A_1'$};
\draw[fill=white,radius=.1em] (b) circle;
\draw[fill=white,radius=.1em] (c) circle;
\node[left] at (d) {$A_n$};
\node[below] at (e) {$A_1$};
\node[below] at (f) {$A_2$};
\draw[fill=white,radius=.1em] (0,3) circle node[above] {$O$};
\node[above left=-2] at ($(d)!.5!(0,3)$) {$A_n'$};
\node[above right=-4] at ($(b)!.5!(0,3)$) {$A_i'$};
\foreach \X in {a,...,f}
{\draw[fill=white,radius=.1em] ($(\X)!.5!(0,3)$) circle;}
\foreach \X/\Y in {d/e,e/f,f/a}
{\fill[opacity=0.15,gray] (\X) -- (\X') -- (\Y') -- (\Y) -- cycle;}
\end{tikzpicture}
\end{document}
答案2
改进 marmot 的好答案,添加一些循环来附加节点,并进一步简化(例如,添加 Max Snippe 的提示):
\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{calc}
\newcounter{cheat}
\begin{document}
\begin{tikzpicture}[every node/.style={font=\tiny},scale=1.5,xscale=1.2]
\foreach \X [count=\Y,evaluate=\Y as \Z using {int(60*(\Y-1))}]
in {a,...,f}
{\pgfmathtruncatemacro{\Cheat}{int(mod(\Y-1,3))}
\ifnum\Cheat=0
\coordinate (\X) at (\Z:1.5);
\else
\coordinate (\X) at (\Z:1);
\fi}
\coordinate (h) at (0,3);
\coordinate (g) at (0,0);
\draw[dashed] (a) -- (b) -- (c) -- (d);
\draw (d) -- (e) -- (f) -- (a);
\draw (a) -- (h);
\foreach \X in {a,...,g}
{\coordinate (\X') at ($(\X)!.5!(0,3)$);}
\foreach \X in {b,c,g}
{\draw[dashed] (\X) -- (\X');
\draw (h) -- (\X');}
\foreach \X in {d,e,f}
{\draw (h) -- (\X);}
\fill[black,opacity=.3] (a') foreach \X in {b,...,f} { -- (\X') } -- cycle;
\fill[gray,opacity=.3] (a) foreach \X in {f,f',a'} { -- (\X) } -- cycle;
\foreach \X [count=\Y,evaluate=\Y as \Z using {ifthenelse(\Y==5,6,int(mod(\Y+1,6)))}]
in {a,...,f}
{\setcounter{cheat}{\Z}
\def\NextX{\alph{cheat}}
\draw (\X') -- (\NextX');
\fill[gray,opacity=.3] (\NextX') -- (\X') -- (\X) -- (\NextX) -- cycle;}
\foreach \X in {b,c,g,h}
{\draw[fill=white,radius=.1em] (\X) circle;}
\foreach \X in {a,...,g}
{\draw[fill=white,radius=.1em] (\X') circle;}
\foreach \X/\Y/\Z
in {e/below/A_1,c/below/A_1',
f/below/A_2,b/below/A_2',
d/left/A_n, d'/left/A_n',
b/right/A_i,b'/right/A_i',
g/right/O_1,h/right/O}
{\node[\Y] at (\X) {$\Z$};}
\node[below right=-2.5] at (g') {$O_1'$};
\end{tikzpicture}
\end{document}