![TikZ 中的正多边形与圆形](https://linux22.com/image/477749/TikZ%20%E4%B8%AD%E7%9A%84%E6%AD%A3%E5%A4%9A%E8%BE%B9%E5%BD%A2%E4%B8%8E%E5%9C%86%E5%BD%A2.png)
这个问题是一种延续这个答案。如果使用方形,则仍不清楚节点内容周围的空白来自哪里,我想了解这一点。给出以下 MWE
\documentclass[tikz, border=1mm]{standalone}
\usetikzlibrary{shapes.geometric}
\begin{document}
\begin{tikzpicture}[every node/.style={draw, inner sep=0}]
\node[regular polygon,regular polygon sides=4] (a) {XX};
\node[regular polygon,regular polygon sides=100, blue] (b) {XX};
\node[circle] (c) {XX};
\foreach \a in {north,south,east,west,north east,south east,north west,south west}{
\fill[red] (a.\a) circle(0.5pt);
\fill[yellow] (b.\a) circle(0.25pt);
\fill[orange] (c.\a) circle(0.25pt);
}
\end{tikzpicture}
\end{document}
我有点惊讶的是,黑色圆圈的半径小于多边形内切圆的半径,因为手册上pgf
说
[...] 多边形的边界是总是使用内切圆构造,其半径经过计算以紧密贴合节点内容(包括任何
inner sep
)。
为了展示我的期望和我想要的结果,我在 MWE 中添加了一个蓝色的“假圆圈”,作为一个有 100 条边的正多边形。有没有办法画出这样的蓝色圆圈使用圆形,即\node[circle, ...]{XX};
?对于我来说,用手玩inner sep
不是一个选择。
作为澄清/补充信息,我感兴趣的是让节点形状在更广泛的背景下使用,即与正方形无关。同时收到关于为什么尽管四边形多边形留下了很大的空间,但还是inner sep=0
会受到高度赞赏。
更新:从评论来看,这个问题确实还有解释的空间,总之,我想回答一下这些问题。
- 如何才能拥有一个
Circle
形状(或tikzstyle)来精确绘制给定节点内容周围Circle
的通讯员内切圆?regular polygon
- 我的 MWE 中的黑色圆圈和正方形之间的差异从何而来?
- 如果更简单(我也可以使用其他方法),如何才能得到一个形状(或 tikzstyle),其具有与给定节点内容相对应的
Regular Polygon
内切圆?circle
答案1
中的“内圆”shapes.geometric
的半径为内容框最长边的一半加上内分隔符,再乘以1.4142136
,约为sqrt(2)
。因此,要获得具有此行为的圆形,您可以定义一个新形状,假设Circle
(大写 C)是对现有形状的轻微修改ellipse
。
\documentclass[tikz, border=7pt, convert={density=4200}]{standalone}
\usetikzlibrary{shapes.geometric}
\makeatletter
\pgfdeclareshape{Circle}
%
% Draws a circle around the text
% (based on the original ellipse shape)
%
{%
\savedanchor\centerpoint{%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgf@y=.5\ht\pgfnodeparttextbox%
\advance\pgf@y by-.5\dp\pgfnodeparttextbox%
}%
\savedanchor\radius{%
%
% Calculate ``height radius''
%
\pgf@y=.5\ht\pgfnodeparttextbox%
\advance\pgf@y by.5\dp\pgfnodeparttextbox%
\pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}%
\advance\pgf@y by\pgf@yb%
%
% Calculate ``width radius''
%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}%
\advance\pgf@x by\pgf@xb%
%
% Adjust
%
% ==============================
% added to ellipse shape to become circle
\ifdim\pgf@y>\pgf@x%
\pgf@x\pgf@y%
\else%
\pgf@y\pgf@x%
\fi%
% ==============================
\pgf@x=1.4142136\pgf@x%
\pgf@y=1.4142136\pgf@y%
%
% Adjust height, if necessary
%
\pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}%
\ifdim\pgf@y<.5\pgf@yc%
\pgf@y=.5\pgf@yc%
\fi%
%
% Adjust width, if necessary
%
\pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}%
\ifdim\pgf@x<.5\pgf@xc%
\pgf@x=.5\pgf@xc%
\fi%
%
% Add outer sep
%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
\advance\pgf@x by\pgf@xb%
\advance\pgf@y by\pgf@yb%
}%
%
% Anchors
%
\anchor{center}{\centerpoint}%
\anchor{mid}{\centerpoint\pgfmathsetlength\pgf@y{.5ex}}%
\anchor{base}{\centerpoint\pgf@y=0pt}%
\anchor{north}
{
\pgf@process{\radius}
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@y by\pgf@ya
}%
\anchor{south}
{
\pgf@process{\radius}
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@y by-\pgf@ya
}%
\anchor{west}
{
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by-\pgf@xa
}%
\anchor{mid west}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by-\pgf@xa%
\pgfmathsetlength\pgf@y{.5ex}
}%
\anchor{base west}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by-\pgf@xa%
\pgf@y=0pt
}%
\anchor{north west}
{
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by-0.707107\pgf@xa
\advance\pgf@y by0.707107\pgf@ya
}%
\anchor{south west}
{
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by-0.707107\pgf@xa
\advance\pgf@y by-0.707107\pgf@ya
}%
\anchor{east}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by\pgf@xa
}%
\anchor{mid east}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by\pgf@xa%
\pgfmathsetlength\pgf@y{.5ex}
}%
\anchor{base east}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by\pgf@xa%
\pgf@y=0pt
}%
\anchor{north east}
{
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by0.707107\pgf@xa
\advance\pgf@y by0.707107\pgf@ya
}%
\anchor{south east}
{
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by0.707107\pgf@xa
\advance\pgf@y by-0.707107\pgf@ya
}%
\anchorborder{
\edef\pgf@marshal{%
\noexpand\pgfpointborderellipse
{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}
{\noexpand\radius}%
}%
\pgf@marshal%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\centerpoint%
\advance\pgf@x by\pgf@xa%
\advance\pgf@y by\pgf@ya%
}%
%
% Background path
%
\backgroundpath
{
\pgf@process{\radius}%
\pgfutil@tempdima=\pgf@x%
\pgfutil@tempdimb=\pgf@y%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
\advance\pgfutil@tempdima by-\pgf@xb%
\advance\pgfutil@tempdimb by-\pgf@yb%
\pgfpathellipse{\centerpoint}{\pgfqpoint{\pgfutil@tempdima}{0pt}}{\pgfqpoint{0pt}{\pgfutil@tempdimb}}%
}%
}%
\makeatother
\begin{document}
\begin{tikzpicture}[nodes={draw, inner sep=0}]
\node[regular polygon,regular polygon sides=4] (a) {XX};
\node[Circle, blue] (b) {XX};
\node[circle] (c) {XX};
\foreach \a in {north,south,east,west,north east,south east,north west,south west}{
\fill[red] (a.\a) circle(0.5pt);
\fill[yellow] (b.\a) circle(0.25pt);
\fill[orange] (c.\a) circle(0.25pt);
}
\end{tikzpicture}
\end{document}
附录:
如果你想走另一种方式,并在标准circle
节点样式周围创建一个外接多边形,而不使用低级技巧,你可以定义circumscribed polygon
它来append after command
添加大小合适的regular polygon
。由于种种原因,这不是一个强大的代码,它只是一个概念验证:
\documentclass[tikz,border=7pt,convert={density=4200}]{standalone}
\usetikzlibrary{calc,shapes.geometric}
% don't tell me to not use tikzstyle ;)
\tikzstyle{circumscribed polygon}[draw]=[
circle,draw=none,fill=none,shade=none,
append after command={
let \p1=($(\tikzlastnode.west)-(\tikzlastnode.east)$),
\n1 = {(veclen(\p1)-\pgflinewidth)/2.828427} % 2*sqrt(2) = 2.8284271247461903
in
(\tikzlastnode.center) node[regular polygon, inner sep=\n1, #1]{}
}
]
\begin{document}
\begin{tikzpicture}[inner sep=1mm]
\foreach~in {3,...,7}
\node[circumscribed polygon={draw=blue!~0!green,regular polygon sides=~}] {XX};
\node[circle,draw=red] {XX};
\end{tikzpicture}
\end{document}
答案2
使用through
Ti 库钾z。
\documentclass[tikz, border=1mm]{standalone}
\usetikzlibrary{shapes.geometric,through}
\begin{document}
\begin{tikzpicture}[every node/.style={draw, inner sep=0}]
\node[regular polygon,regular polygon sides=4] (a) {XX};
\node (b) [draw,blue, circle through=(a.north)] at (a.center) {XX};
\node[circle] (c) {XX};
\foreach \a in {north,south,east,west,north east,south east,north west,south west}{
\fill[red] (a.\a) circle(0.5pt);
\fill[yellow] (b.\a) circle(0.25pt);
\fill[orange] (c.\a) circle(0.25pt);
}
\end{tikzpicture}
\end{document}
答案3
只是为了分享一种不同的方法来实现Kpym 在他的非常好的回答中声明一个新的形状,我认为可以简单地设置一个Circle
样式,正确设置圆形的最小尺寸(在这种特殊情况下,内容永远不会超过minimum size
因为我们试图放大圆圈)。它应该适用于任何节点内容,无论其宽度大于其高度还是反之亦然。几点说明:
- 在这种方法中,必须分别在选项之前或选项内部使用
name
和at
键声明节点名称和节点位置。 Circle
inner sep
在样式之前必须指定ACircle
,但如果有其他需要,则可以轻松改进。
这里是代码:
\documentclass[tikz, border=1mm]{standalone}
\usetikzlibrary{shapes.geometric}
\tikzset{%
Square/.style={regular polygon, regular polygon sides=4},
Circle/.style={%
circle,
/utils/exec={%
\pgfmathsetmacro\polygonIncircleDiameter{
sqrt(2)*max(width("#1")+2*\pgfshapeinnerxsep, height("#1") + depth("#1") + 2 * \pgfshapeinnerysep)
}
},
minimum size=\polygonIncircleDiameter,
node contents={#1}
}
}
\begin{document}
\begin{tikzpicture}
\node[inner sep=0, Square, draw=cyan] at (0,0) {xx};
\node[inner sep=0, Circle={xx}, draw=blue];
\node[Square, draw=cyan] at (1,0) {i};
\node[Circle={i}, draw=blue, at={(1,0)}];
\end{tikzpicture}
\end{document}
答案4
此解决方案使用calc
库来计算正多边形的内半径。这样就可以计算外接圆的最小宽度。
\documentclass[tikz, border=1mm]{standalone}
\usetikzlibrary{shapes.geometric, calc}
\begin{document}
\begin{tikzpicture}
\node[inner sep=0, regular polygon, regular polygon sides=4, draw=cyan] (a) {xx};
\path let \p1=($(a.center)-(a.side 1)$) in node[circle, inner sep=0, minimum width={2*veclen(\x1,\y1)-\pgflinewidth}, draw=blue] {};
\node[inner sep=0, draw=cyan, regular polygon, regular polygon sides=7] (b) at (1,0) {i};
\path let \p1=($(b.center)-(b.side 1)$) in node[circle, inner sep=0, minimum width={2*veclen(\x1,\y1)-\pgflinewidth}, draw=blue] at (b) {};
\end{tikzpicture}
\end{document}