我的目标是绘制如下形式的17*1的相连圆点
第一版的代码如下:
\documentclass[border=6pt]{standalone}
\usepackage{tkz-euclide}
\begin{document}
\begin{tikzpicture}
\tkzDefPoint(0,-.5){b0}\tkzDrawPoints[size=3pt](b0)
\foreach \x[remember=\x as \lastx (initially 0)] in {1,...,16}{
\ifodd\x\relax
\tkzDefPoint(\x*0.5,.5){b\x}
\else
\tkzDefPoint(\x*0.5,-0.5){b\x}
\fi
\tkzDrawSegments(b\lastx,b\x)
\tkzDrawPoints[size=3pt](b\x)
}
\end{tikzpicture}
\end{document}
这一版有两处瑕疵:
一是
\tkzDefPoint(0,-.5){b0}\tkzDrawPoints[size=3pt](b0)
太麻烦。
二是绘制点的时机不太对,我希望点在最后绘制
要实现目的是简单的,多来一次循环即可:
\documentclass[border=6pt]{standalone}
\usepackage{tkz-euclide}
\begin{document}
\begin{tikzpicture}
\tkzDefPoint(0,-.5){b0}
\foreach \x[remember=\x as \lastx (initially 0)] in {1,...,16}{
\ifodd\x\relax
\tkzDefPoint(\x*0.5,.5){b\x}
\else
\tkzDefPoint(\x*0.5,-0.5){b\x}
\fi
\tkzDrawSegments(b\lastx,b\x)
}
\foreach \x in {0,...,16}{
\tkzDrawPoints[size=3pt](b\x)
}
\end{tikzpicture}
\end{document}
但这需要两个循环,也并不优雅....
对于一个「并不算太复杂的\foreach
」循环目标
在pgffor
的现有框架下,是否容易通过:
来实现呢(换句话说我希望代码越短越好)?
「我希望代码越短越好」的具体含义是:
让代码语句的处理逻辑直观不拖沓,避免因为特殊判断而导致需要不得已而多写几行
为了规避「抖机灵」的MWE:
\documentclass[border=6pt]{standalone}
\usepackage{tkz-euclide}
\pgfmathsetseed{42}
\begin{document}
\begin{tikzpicture}
\tkzDefPoint(0,-.5){b0}\tkzDrawPoints[size=3pt](b0)
\foreach \x[remember=\x as \lastx (initially 0)] in {1,...,16}{
\pgfmathrandominteger{\yy}{-2}{2}
\tkzDefPoint(\x*0.5,\yy pt){b\x}
\tkzDrawSegments(b\lastx,b\x)
\tkzDrawPoints[size=3pt](b\x)
}
\end{tikzpicture}
\end{document}
\documentclass[tikz,border=1cm]{standalone}
\begin{document}
\begin{tikzpicture}[nodes={draw,fill=gray!50,circle,inner sep=1pt}]
\foreach \x in {0,2,...,14}
{%
\begin{scope}[xshift=\x cm]
\node (a) at (0,0) {};
\node (b) at (1,2) {};
\node (c) at (2,0) {};
\draw (a) -- (b) -- (c);
\end{scope}
}
\end{tikzpicture}
\end{document}
用 tzplot 还能更短,但似乎没必要
可以用on background layer
来避免第二个循环
\documentclass[border=6pt]{standalone}
\usepackage{tkz-euclide}
\usetikzlibrary{backgrounds}
\pgfmathsetseed{42}
\begin{document}
\begin{tikzpicture}
\tkzDefPoint(0,-.5){b0}\tkzDrawPoints[size=3pt](b0)
\foreach \x[remember=\x as \lastx (initially 0)] in {1,...,16}{
\begin{scope}[on background layer]
\pgfmathrandominteger{\yy}{-2}{2}
\tkzDefPoint(\x*0.5,\yy pt){b\x}
\tkzDrawSegments(b\lastx,b\x)
\end{scope}
\tkzDrawPoints[size=3pt](b\x)
}
\end{tikzpicture}
\end{document}
上面的例子中的\pgfmathrandominteger
是我刻意构造的,就是为了避免被「抖机灵」(是我的 恶意 ,我希望 直面 这种 17个点16根连线的 「循环」不方便的情况)
虽然点和线的绘制次序改变了,但「17个点16根连线」的问题还是会出现「冗余」的:
\tkzDefPoint(0,-.5){b0}\tkzDrawPoints[size=3pt](b0)
我再蹲一蹲。
感谢!您提出了巧妙的方式来规避这一问题。
但本问题更想要的是「逻辑上的一致连贯性」,上述方法一定程度上依赖了这个「山」型结构。如果这些点的出现位置是不规律的,那么可能比较难巧妙地抖机灵。
为了阻止某种抖机灵来避免「17个点16条连线」的不一致现象,我新增了原问题的MWE.
或者说,我希望
tikz
或者pgf
有内置(built-in)功能来「轻松」实现这一功能(我觉得应该就是remember=\x as \lastx (initially 0)
)。我有一个新的想法,可见我自己的回答。
如果想要更短的话...
也可以用一个
\path
语句完成,这可以避免无意义的assignment ofa
,b
andc
:(如有可能,我会尽可能追求短hhhh)
@u70550 如果圆圈坐标不规律,可能很难使用 foreach,本质上这个问题是如何获取每个圆圈的位置。在每个圆圈位置明确(但坐标不一定容易写出)的情况下,使用相对坐标(包括极坐标)是一种有效的方式。剩下的就是连线了。如果想批量产出 node 或者 line,使用 tzplot 可能也不错。