50 是否可以实现对一些可构成凸多边形的点实现自动智能在其外侧添加标签?

发布于 2025-07-31 00:24:11

本问题来自这个问题的评论区,为了避免有趣的实现思路被掩盖在其他问题的评论区中,另开一个问题。

\input{centroid_label.tex}
\LabelPts{A, B, E, M}

image.png

image.png

这个命令的思路是, 给某些点加标签时, 先计算它们的质心, 根据各个点与质心的角度, 决定标签的方位.

相信大家都有过需要写大量的语句来实现对多个坐标点添加标签的位置控制,这并不优雅,也比较麻烦。

Claim1: 假定这里涉及的N个点必定可以形成「凸多边形」,因为非凸多边形在正常画图的时候比较少见,也不太会想一次性做标号(如有必要可以新开一个问题😀)

Claim2: 下面的"质心"概念是大佬在评论区提出的,事实上只是反映凸多边形"中心"/到各个顶点距离基本相同的一个定义,可供参考的定义如下(Powered By Gemini 2.5pro):

image.png

Claim3: 本问题不一定要局限在tkz-euclide,只要能准确控制「标号位置」、「标号距离」即可。例子中用tkz也只是因为代码行数短,同时定义多个点更方便。

如下MWE,我不希望用6行来控制他们的标签位置

\documentclass[tikz,border=5mm]{standalone}
\usepackage{tkz-euclide}
\begin{document}
\begin{tikzpicture}
  \tkzDefPoints{-1/-1/A, 1/-2/B, 3/0/C, 2/4/D, 0/5/E,-3/2/F}  
  \tkzDrawPolygons[thick](A,...,F)
  \tkzLabelPoints(A,...,F)
\end{tikzpicture}
\end{document}

image.png

查看更多

关注者
0
被浏览
144
2 个回答
Sagittarius Rover
Sagittarius Rover 20小时前
我要成为Typst糕手/(ㄒoㄒ)/~~

一个基于tkz-euclide的可能方案,有大量瑕疵:

  • "质心"可以最好地近似「N个点的"最小覆盖圆"的圆心」吗?
  • 图中使用\tkzAutoLabelPoints来调整dist也并不完美,点A,B,C,F偏远;点DE偏近
  • \tkzDefBarycentricPoint(A=1,B=1,C=1,D=1,E=1,F=1)语法冗杂,而\tkzCentroid(A,B,C)仅支持三个点
  • 暂时没有做封装...
\documentclass[tikz,border=5mm]{standalone}
\usepackage{tkz-euclide}
\begin{document}
\begin{tikzpicture}
  \tkzDefPoints{-1/-1/A, 1/-2/B, 3/0/C, 2/4/D, 0/5/E,-3/2/F}  
  \tkzDrawPolygons[thick](A,...,F)
% \tkzLabelPoints(A,...,F) % No!
% \tkzCentroid(A,B,C) %怎么只支持三个点呢..真可惜
\tkzDefBarycentricPoint(A=1,B=1,C=1,D=1,E=1,F=1)
\tkzGetPoint{centroid}
\tkzDrawPoint(centroid)
\tkzAutoLabelPoints[center = centroid,dist= .12](A,...,F)
\end{tikzpicture}
\end{document}

image.png

抛砖引玉了~ 期待@u817 老师提供更general方案的补充


Edited:

使用\pathpos..对位置的控制相对好一些了,但是却不能很好的融入tkz-euclide的框架里...

这里的各个label和点的距离是「路径(centeroid--\x)的长度*0.1」,因为不好找到精准的最小覆盖圆(因为多点情况下这不存在),长度不相等,这是利用pos的瑕疵...

\documentclass[tikz,border=5mm]{standalone}
\usepackage{tkz-euclide}
\begin{document}
\begin{tikzpicture}
  \tkzDefPoints{-1/-1/A, 1/-2/B, 3/0/C, 2/4/D, 0/5/E,-3/2/F}  
  \tkzDrawPolygons[thick](A,...,F)
% \tkzLabelPoints(A,...,F) % No!
% \tkzCentroid(A,B,C) %怎么只支持三个点呢..真可惜
\tkzDefBarycentricPoint(A=1,B=1,C=1,D=1,E=1,F=1)
\tkzGetPoint{centroid}
\tkzDrawPoint(centroid)
% \tkzAutoLabelPoints[center = centroid,dist= .12](A,...,F)
\foreach \x in {A,...,F}{
    \path (centroid) -- (\x) node [text=magenta,pos=1.1] {\x};
}
\end{tikzpicture}
\end{document}

image.png

shadow
shadow 6小时前
这个人懒得不得了,竟然啥也没写

用纯 tikz 给一个弱的解答。思路是先求出多边形的重心,然后在重心到顶点射线的方向上的合适位置放置标签,用 calc 库计算坐标。

\documentclass[tikz,border=1cm]{standalone}
\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}
  \foreach \x/\y in {%
    (0,0)/a,
    (1,1)/b,
    (3,2)/c,
    (4,-1)/d,
  (2,-2)/e}
  { \node[fill, circle, inner sep =0pt, minimum size = 3pt] (\y) at \x {}; }
  \draw plot coordinates {(a) (b) (c) (d) (e) (a)};

  \coordinate (O) at ($0.2*(a)+ 0.2*(b)+ 0.2*(c)+ 0.2*(d)+ 0.2*(e)$);

  \fill[red] (O) circle(2pt);% 重心

  \foreach \x in {a,c,d,e}
  {\node at ($(O)!1.15!(\x)$){$\x$};}

  \node at ($(O)!1.22!(b)$){$b$};

\end{tikzpicture}

\end{document}

image.png

不难看到,用重心作为射线的起点并不完美,上图中的 b 标签就不能合适放置,故而只能单独绘制。

对于在圆上的凸多边形,存在到所有顶点距离相等的点,用该点作为射线起点比较合适,但对应一般的凸多边形不存在这样的点,所以仅仅用重心并不合适。

以上操作,本质上和逐个绘制标签没有区别,仅仅是用 foreach 简化操作。

撰写答案

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

发布
问题

分享
好友

手机
浏览

扫码手机浏览