50 「未完全解决」关于首尾不相连的foreach绘图的优化问题

发布于 2025-08-20 17:09:10

我的目标是绘制如下形式的17*1的相连圆点

image.png

第一版的代码如下:

\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}

image.png

这一版有两处瑕疵:
一是

\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的现有框架下,是否容易通过:

  • 只使用一个循环
  • 不需要在循环外为端点值做特殊处理

来实现呢(换句话说我希望代码越短越好)?

Edited

「我希望代码越短越好」的具体含义是:

让代码语句的处理逻辑直观不拖沓,避免因为特殊判断而导致需要不得已而多写几行

Re-Edited

为了规避「抖机灵」的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}

image.png

查看更多

关注者
0
被浏览
136
2 个回答
shadow
shadow 2天前
这个人懒得不得了,竟然啥也没写
\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}

image.png

用 tzplot 还能更短,但似乎没必要

Sagittarius Rover
我要成为Typst糕手/(ㄒoㄒ)/~~

可以用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根连线的 「循环」不方便的情况)

image.png

虽然点和线的绘制次序改变了,但「17个点16根连线」的问题还是会出现「冗余」的:

\tkzDefPoint(0,-.5){b0}\tkzDrawPoints[size=3pt](b0)

我再蹲一蹲。

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览