TikZ 中的正多边形与圆形

TikZ 中的正多边形与圆形

这个问题是一种延续这个答案。如果使用方形,则仍不清楚节点内容周围的空白来自哪里,我想了解这一点。给出以下 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会受到高度赞赏。

更新:从评论来看,这个问题确实还有解释的空间,总之,我想回答一下这些问题。

  1. 如何才能拥有一个Circle形状(或tikzstyle)来精确绘制给定节点内容周围Circle的通讯员内切圆?regular polygon
  2. 我的 MWE 中的黑色圆圈和正方形之间的差异从何而来?
  3. 如果更简单(我也可以使用其他方法),如何才能得到一个形状(或 tikzstyle),其具有与给定节点内容相对应的Regular Polygon内切圆?circle

                 图MWE

答案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

使用throughTi 库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因为我们试图放大圆圈)。它应该适用于任何节点内容,无论其宽度大于其高度还是反之亦然。几点说明:

  • 在这种方法中,必须分别在选项之前或选项内部使用nameat键声明节点名称和节点位置。
  • Circle inner sep在样式之前必须指定A Circle,但如果有其他需要,则可以轻松改进。

这里是代码:

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

在此处输入图片描述

相关内容