在整个 tikzpicture、范围或节点中查找内容的质心

在整个 tikzpicture、范围或节点中查找内容的质心

TikZ 是否允许相对容易地实现在 tikzpicture、范围或节点中查找内容的质心?你能演示一下吗?

假设唯一的假设是直观的,即每个 1pt 点都有一些单位权重。对于简单的绘图,如三角形、填充三角形等,很容易手动找到它,但在更复杂的情况下(许多半径不相等的圆 [如果这些圆被填充,结果显然会有所不同] 等),TikZ 的帮助将不胜感激。

边注:考虑混合绘图(在一张图片中填充和未填充)是没有意义的(通常),因此对于填充和仅路径绘图,解决方案可能(并且,如果有的话,可能会)不同。不过,通用解决方案将是最好的。

使用 Ryan 解决方案的示例

我实在忍不住就不举我自己的例子了。抱歉!

\documentclass{minimal}
\usepackage{tikz}
\usepackage[a5paper,margin=16mm,top=4cm]{geometry}
\usetikzlibrary{decorations.markings,scopes}
\newcommand\globallist[2]{\global\edef#1{#1#2}}
\tikzset{bary markings/.style = {
    decoration = {
        markings,
        mark = between positions 0 and 1 step .1 with {
            \edef\number{\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}}
            \coordinate (r\number);
            \globallist\refpoints{r\number=1,}
        }
    },
    postaction = {decorate}
}}
\def\refpoints{}
\def\docentroid{
    \coordinate (fake) at (5,0);
    \globallist\refpoints{fake=0}
    \draw[fill] (barycentric cs:\refpoints) circle (2mm);
    \global\def\refpoints{}
}
\begin{document}
\pagestyle{empty}
\begin{tikzpicture}[y=3mm, x=3mm, yscale=-1, inner sep=0pt, outer sep=0pt]
    \draw[bary markings]
        (161.8225,329.7121) .. controls (156.5960,329.7121) and
        (152.9749,330.3097) .. (150.9593,331.5050) .. controls (148.9436,332.7004) and
        (147.9358,334.7394) .. (147.9358,337.6222) .. controls (147.9358,339.9191) and
        (148.6858,341.7472) .. (150.1858,343.1066) .. controls (151.7092,344.4425) and
        (153.7717,345.1105) .. (156.3733,345.1105) .. controls (159.9592,345.1105) and
        (162.8303,343.8449) .. (164.9866,341.3136) .. controls (167.1663,338.7589) and
        (168.2561,335.3722) .. (168.2561,331.1535) -- (168.2561,329.7121) --
        (161.8225,329.7121)(174.7249,327.0402) -- (174.7249,349.5050) --
        (168.2561,349.5050) -- (168.2561,343.5285) .. controls (166.7795,345.9191) and
        (164.9397,347.6886) .. (162.7366,348.8371) .. controls (160.5335,349.9621) and
        (157.8381,350.5246) .. (154.6507,350.5246) .. controls (150.6194,350.5246) and
        (147.4085,349.3996) .. (145.0179,347.1496) .. controls (142.6507,344.8761) and
        (141.4671,341.8410) .. (141.4671,338.0441) .. controls (141.4671,333.6144) and
        (142.9436,330.2746) .. (145.8968,328.0246) .. controls (148.8733,325.7746) and
        (153.3030,324.6496) .. (159.1858,324.6496) -- (168.2561,324.6496) --
        (168.2561,324.0168) .. controls (168.2561,321.0402) and (167.2717,318.7434) ..
        (165.3030,317.1261) .. controls (163.3577,315.4855) and (160.6155,314.6652) ..
        (157.0764,314.6652) .. controls (154.8264,314.6652) and (152.6350,314.9348) ..
        (150.5022,315.4738) .. controls (148.3694,316.0129) and (146.3186,316.8215) ..
        (144.3499,317.8996) -- (144.3499,311.9230) .. controls (146.7171,311.0090) and
        (149.0139,310.3293) .. (151.2405,309.8839) .. controls (153.4671,309.4152) and
        (155.6350,309.1809) .. (157.7444,309.1808) .. controls (163.4397,309.1809) and
        (167.6936,310.6574) .. (170.5061,313.6105) .. controls (173.3186,316.5637) and
        (174.7248,321.0402) .. (174.7249,327.0402);
    \docentroid
\end{tikzpicture}
\end{document}

字母“a”的质心

答案1

这是基于 Gonzalo 使用重心坐标系的想法的一个奇怪的建议。使用该decorations.markings库,您可以定期标记曲线。使用这些计算出的参考点,您可以进行巨大的重心计算以找到近似质心。即:

\documentclass{article}
\usepackage{tikz,nopageno}
\usetikzlibrary{decorations.markings,scopes}
\newcommand{\globallist}[2]{%
 \global\edef#1{#1#2}%
}
\tikzset{bary markings/.style = {
  decoration = {
   markings,
   mark = between positions 0 and 1 step .1 with
    {
     \edef\number{\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}}
     \coordinate (r\number);
     \globallist\refpoints{r\number=1,}
    }
  },
  postaction = {decorate}
 }
}
\def\refpoints{}
\def\docentroid{
 \coordinate (fake) at (5,0);
 \globallist\refpoints{fake=0}
 \node [circle = 3pt, fill = black] at (barycentric cs:\refpoints) {};
 \global\def\refpoints{}
}
\begin{document}
 \begin{tikzpicture}
  { [shift = {(0,0)}]
   \draw [bary markings] (90:2cm) -- (210:2cm) -- (-30:2cm) -- cycle;
   \docentroid
  }
  { [shift = {(2.5cm,0)}]
   \draw [bary markings] (0,0) .. controls (1,1) and (2,-1) .. (3,0) -- (3,2) -- (0,2) -- cycle;
   \docentroid;
  }
  { [shift = {(6.5cm,0)}]
   \draw [bary markings]
    (0,0) parabola bend (2,2) (3,1) .. controls (2.5, -1) and (1,-1/3) .. (1,-1) -- cycle;
   \docentroid
  }
  { [shift = {(10cm, 3cm)}]
   \draw [bary markings] (0,0) -- (1,0) -- (1,-4) -- (4,-4) -- (4,-5) -- (0,-5) -- cycle;
   \docentroid
  }
 \end{tikzpicture}
\end{document}

在此处输入图片描述

最后一个例子演示了(根据 xport 的要求)如何找到一个非常非凸区域的质心。

对不熟悉的人的解释。这里重要的计算不是重心坐标,而是标记点,它们由以下公式构成:

decoration = {
 markings,
 mark = between positions 0 and 1 step .1 with
  {
   \edef\number{\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}}
   \coordinate (r\number);
   \globallist\refpoints{r\number=1,}
  }
 },
 postaction = {decorate}
}

正如手册(v2.10,第 30.5 节)所解释的那样,markings装饰会破坏原始路径,但由于我仅使用它来生成坐标,因此我必须将其作为后置操作应用(因此,它只会破坏路径的副本)。我选择在曲线上只放置 10 个(好吧,11 个)标记,以避免不必要的减速,因为装饰以稳固的速度进行。此外,正如 przemoc 所指出的,当涉及非常大或非常小的数字时,数值计算可能会出错。

我还将重心坐标的未来参数收集到一个列表中\refpoints,并用一个快速而粗糙的宏进行组装\globallist

\newcommand{\globallist}[2]{%
 \global\edef#1{#1#2}%
}
\def\refpoints{}

我想使用\pgfkeys(即.append处理程序)来组装列表,但事实证明标记是在 TeX 组中执行的,因此需要全局设置列表,而我无法弄清楚如何强制\pgfkeys这样做。

一旦路径准备好,就可以计算质心:

\def\docentroid{
 \coordinate (fake) at (5,0);
 \globallist\refpoints{fake=0}
 \node [circle = 3pt, fill = black] at (barycentric cs:\refpoints) {};
 \global\def\refpoints{}
}

坐标的要点(fake)是要占用列表末尾的逗号\refpoints。可惜的是,尽管barycentric cs:采用了逗号分隔的分配列表node=weight,但该列表没有 PGF 键列表的便利性,并且不允许使用空格或尾随逗号。希望这个问题会在未来的版本中得到修复,但无论如何,给出(fake)零权重会让 TikZ 忽略它。

答案2

请参阅第 13.2.2 节重心系统pgfmanual 的。一个小例子:

\documentclass{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\coordinate (A) at (90:3cm);
\coordinate (B) at (210:3cm);
\coordinate (C) at (-30:3cm);
\draw [thick,gray] (A) -- (B) -- (C) -- cycle;
\draw[fill=blue]  (A) circle [radius=4pt];
\draw[fill=red]  (B) circle [radius=6pt];
\draw[fill=green]  (C) circle [radius=8pt];
\node at (barycentric cs:A=4,B=6,C=8) {TikZ};
\end{tikzpicture}

\end{document}

在此处输入图片描述

相关内容