用 Tikz 绘制圆形填充?

用 Tikz 绘制圆形填充?

可以画出附图吗?在此处输入图片描述

我的尝试:

\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{fit,backgrounds}
\begin{document}
\begin{tikzpicture}[cable/.style={circle, fill=cyan!70!black, minimum size=5mm, inner sep=0pt, outer sep=0pt}]
\node[cable] (center) at (0,0) {};
\foreach \i in {0,1,...,6}
    \node[cable] (1-\i) at (60*\i:5mm) {};
    \fill[red!20] circle (0.26);
\end{tikzpicture}
\end{document}

答案1

这是一个自动化解决方案。我们定义一个命令\circlesqueeze,该命令接受两个参数,其中一个是可选的。必需的参数是用逗号分隔的圆圈列表。该命令

\circlesqueeze{1/-1/.5,0/-1/.85,.3/.5/.7,1.3/1.2/.6,1/0/.5}

在 a 内tikzpicture会挤压出 5 个圆。每个圆的语法是x/y/r(x,y)圆心,r是半径。因此在上面的例子中,第一个圆以(1,-1)为圆心,半径为.5。第二个圆以(0,-1)为圆心,半径.85为 ,依此类推。单位为厘米。

在此处输入图片描述

可选参数是圆之间的最小间距。默认值为.05cm。下面是将间距缩小到的示例.03cm

\circlesqueeze[.03]{0/0/1,1/1/.5,0/1.5/.7,1.6/1.4/.25,1.6/0/.8,2/1/.5,1/2/.5}

在此处输入图片描述

如果要更改line width,则必须使用命令 全局执行\lw,最初设置为.4。您可以使用 更改它\renewcommand。您可以使用\clip命令获取与原始图像相似的图片。我估算了中心和半径:

\renewcommand{\lw}{1}
\begin{tikzpicture}[line width=\lw]
\clip (-4.5,-4.5) rectangle (6,5);
\circlesqueeze[.1]{.2/0/3,2/5/3,-2.6/3/2.1,-3.7/-2.3/3.1,1.5/-4/2.2,6.4/0/4}
\end{tikzpicture}

在此处输入图片描述

基本算法如下:

  • 所有的圆都画好了。我们要删除相应的圆弧,并用线段代替。
  • 对于每对圆,将它们圆心之间的距离与半径之和进行比较。如果距离在圆之间造成足够大的间隙,则不执行任何操作。
  • 如果圆很接近(或重叠),则计算(m)连接两个中心(中心轴)的线上的一点,该点位于两个需要修改的圆弧之间,但更靠近较小圆的中心,以便两个扁平段的长度相同。
  • 找到两个圆与垂直于中心轴的线的交点,这些线与 的间距相等(m)
  • 用粗白弧覆盖这些交点之间的圆弧以“擦除”它。注意:如果背景颜色不是白色,则需要更改。
  • 为了让平面线段与剩余的圆完美连接,\eps从稍远的第二个交点处绘制一小段(距离= )(m),然后沿着第一对交点,重新连接到圆。这是一条双线(外侧为白色,内侧为黑色),用于遮盖原始圆的任何不想要的残余部分。

已知的问题:

  • 一个圆不能包含另一个圆的圆心。
  • 任何点都不能位于两个以上圆的内部。
  • 如果平面部分之间没有足够的圆弧,则可能会发生糟糕的事情。这通常可以通过调整线条粗细和间距来解决。
  • 如果可选参数太小或太大,则可能会发生不好的事情。这取决于圆圈的间距。
  • 很慢。

以下是代码:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{intersections,calc}
\usepackage{ifthen}

\newcommand{\eps}{.01} % arc-line connector length in cm
\newcommand{\lw}{.4} % line width. Be careful if defining locally.

\newcommand{\circlesqueeze}[2][.05]{
\foreach \xa/\ya/\ra in {#2}
    {
    \draw (\xa,\ya) circle[radius=\ra]; % draw all circles
    }
\foreach [var=\xa, var=\ya, var=\ra, count=\na] in {#2}
\foreach [var=\xb, var=\yb, var=\rb, count=\nb] in {#2}
    {
    \ifthenelse{\na<\nb} % compare each pair of circles once
        {
            \pgfmathparse{#1+\ra+\rb-veclen(\xb-\xa,\yb-\ya)}
            \ifthenelse{\lengthtest{\pgfmathresult pt > 0 pt}} % if circles are too close
            {
            \coordinate(c1) at (\xa,\ya); \coordinate(c2) at (\xb,\yb); % circle centers
            \path[name path=line0] (c1)--(c2); % center axis
            \path[name path=circ1] (c1) circle[radius=\ra];
            \path[name path=circ2] (c2) circle[radius=\rb];
            \path[name intersections={of=line0 and circ1, by={i1}},
                name intersections={of=line0 and circ2, by={i2}}];
            \coordinate (u12) at ($(c1)!1cm!(c2)-(c1)$); % unit vector from c1 to c2
            \path 
                let \n1={max(\ra,\rb)}, \n2={min(\ra,\rb)}, 
                    \n3={(.5*\n2/\n1)*(\ra>=\rb)+(1-.5*\n2/\n1)*(\ra<\rb)} in % n3=.5 would be equally spaced. Otherwise, closer to smaller circle
                coordinate (m) at ($\n3*(i2)+{(1-\n3)}*(i1)$);
            \path[name path=insideline1] % perpendicular to center axis
                let \p0=(u12),
                    \p1=(m)
                in (\x1-\ra*\y0-#1*.5*\x0,\y1+\ra*\x0-#1*.5*\y0)--(\x1+\ra*\y0-#1*.5*\x0,\y1-\ra*\x0-#1*.5*\y0);
            \path[name path=insideline2]
                let \p0=(u12),
                    \p1=(m)
                in (\x1-\ra*\y0+#1*.5*\x0,\y1+\ra*\x0+#1*.5*\y0)--(\x1+\ra*\y0+#1*.5*\x0,\y1-\ra*\x0+#1*.5*\y0);
            \path[name path=outsideline1] % a little farther apart
                let \p0=(u12),
                    \p1=(m)
                in (\x1-\ra*\y0-#1*.5*\x0-\eps*\x0,\y1+\ra*\x0-#1*.5*\y0-\eps*\y0)--(\x1+\ra*\y0-#1*.5*\x0-\eps*\x0,\y1-\ra*\x0-#1*.5*\y0-\eps*\y0);
            \path[name path=outsideline2]
                let \p0=(u12),
                    \p1=(m)
                in (\x1-\ra*\y0+#1*.5*\x0+\eps*\x0,\y1+\ra*\x0+#1*.5*\y0+\eps*\y0)--(\x1+\ra*\y0+#1*.5*\x0+\eps*\x0,\y1-\ra*\x0+#1*.5*\y0+\eps*\y0);
            \path[name intersections={of=circ1 and insideline1, by={a1,a2}}];
            \path[name intersections={of=circ1 and outsideline1, by={b1,b2}}];
            \path[name intersections={of=circ2 and insideline2, by={a3,a4}}];
            \path[name intersections={of=circ2 and outsideline2, by={b3,b4}}];
            \draw[white, line width=2*\lw] % first circle
                let \p1=($(a1)-(c1)$),
                    \p2=($(a2)-(c1)$),
                    \n0= {\ra}, % Radius
                    \n1 = {atan2(\y1,\x1)}, % angle 1
                    \n2 = {atan2(\y2,\x2)}, % angle 2
                    \n3 = {\n2+360*(\n1-\n2>180)-360*(\n1-\n2<-180)} % force shorter arc
                in (a1) arc(\n1:\n3:\n0);
            \draw[white, line width=2*\lw] % second circle
                let \p1=($(a3)-(c2)$),
                    \p2=($(a4)-(c2)$),
                    \n0= {\rb},
                    \n1 = {atan2(\y1,\x1)},
                    \n2 = {atan2(\y2,\x2)},
                    \n3 = {\n2+360*(\n1-\n2>180)-360*(\n1-\n2<-180)}
                in (a3) arc(\n1:\n3:\n0);
            \draw[line join=round, white, double=black, double distance=\lw] (b1)--(a1)--(a2)--(b2);
            \draw[line join=round, white, double=black, double distance=\lw] (b3)--(a3)--(a4)--(b4);
            }{} % if dist >= #1 do nothing
        }{}% if \na >= \nb do nothing (only do each pair of circles once)
    }
}

\begin{document}

\begin{tikzpicture}[line width=\lw]
\circlesqueeze{1/-1/.5,0/-1/.85,.3/.5/.7,1.3/1.2/.6,1/0/.5}
\end{tikzpicture}

\begin{tikzpicture}[line width=\lw]
\circlesqueeze[.03]{0/0/1,1/1/.5,0/1.5/.7,1.6/1.4/.25,1.6/0/.8,2/1/.5,1/2/.5}
\end{tikzpicture}

\renewcommand{\lw}{1}
\begin{tikzpicture}[line width=\lw]
\clip (-4.5,-4.5) rectangle (6,5);
\circlesqueeze[.1]{.2/0/3,2/5/3,-2.6/3/2.1,-3.7/-2.3/3.1,1.5/-4/2.2,6.4/0/4}
\end{tikzpicture}

\end{document}

答案2

使用Asymptote,您可以从这样的事情开始:

// circpacking.asy
// 
// run 
//   asy circpacking.asy
//
// to get a standalone circpacking.pdf
//
settings.outformat="pdf";
size(6cm);
pen linePen=darkblue+0.7bp;

pair o=(0.47,0);
real r0=0.2;
pair[] Ok={( 0.53, 0.48),(-0.32, 0.20),( 0.31,-0.55),( 0.78,-0.24),( 0.82, 0.12),};
real[] rk={0.28,0.62,0.37,0.19,0.17,};

int n=Ok.length;
real sq=0.08;

guide g0=circle(o,r0);
guide[] gk; gk.cyclic=true;
transform tr;
for(int i=0;i<n;++i){
  tr=shift(sq*(o-Ok[i])); 
  Ok[i]=tr*Ok[i];
  gk.push(circle(Ok[i],rk[i]));
}

guide trunc(int k){
  pair[] xp;
  guide q;
  xp.append(intersectionpoints(gk[k],gk[k-1]));
  xp.append(intersectionpoints(gk[k],g0));
  xp.append(intersectionpoints(gk[k],gk[k+1]));
  q=xp[0]--xp[1]
    &arc(Ok[k],xp[1],xp[4])--xp[5]
    &arc(Ok[k],xp[5],xp[2])--xp[3]
    &arc(Ok[k],xp[3],xp[0])&cycle;
  tr=shift(sq*0.3*(Ok[k]-o)); 
  q=tr*q;
  return q;
}

guide trunc0(){
  pair[] xp; guide q;
  for(int i=0;i<n;++i){
    xp.append(intersectionpoints(g0,gk[i]));
  }
  q=xp[0]--xp[1]
    &arc(o,xp[1],xp[2])--xp[3]
    &arc(o,xp[3],xp[4])--xp[5]
    &arc(o,xp[5],xp[6])--xp[7]
    &arc(o,xp[7],xp[9])--xp[8]
    &arc(o,xp[8],xp[0])
    &cycle;
  return q;
}
for(int i=0;i<n;++i){
  draw(trunc(i),linePen);
}
draw(trunc0(),linePen);
clip(box(o-2*r0*(1,1),o+2*r0*(1,1)));

在此处输入图片描述

这个想法是,从相接圆的斯坦纳链开始,将链中的所有圆向被包围的圆移动,找到所有的交点,直接切开重叠部分,并稍微向后移动所有截断的圆以产生一些间隙。


编辑

这是将上述asymptote代码通过.svg格式转换TikZsvg2tikz

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\begin{document}
\definecolor{c00003f}{RGB}{0,0,63}
\def \globalscale {1.000000}
\begin{tikzpicture}[y=0.80pt, x=0.80pt, yscale=-\globalscale, xscale=\globalscale, inner sep=0pt, outer sep=0pt]
    \begin{scope}[cm={{0.99626,0.0,0.0,0.99626,(41.5276,138.898)}}]
      \path[draw=c00003f,line cap=round,line join=round,line width=0.562pt,miter limit=10.04] (121.8530,43.4044) -- (145.4980,24.3523) .. controls (152.8360,14.4281) and (157.1750,2.1513) .. (157.1750,-11.1389) .. controls (157.1750,-44.1405) and (130.4220,-70.8936) .. (97.4204,-70.8936) .. controls (70.8777,-70.8936) and (48.3770,-53.5876) .. (40.5863,-29.6438) -- (62.6986,37.4991) .. controls (65.5025,39.5043) and (68.4870,41.2732) .. (71.6231,42.7764) -- (109.1410,47.4744) .. controls (113.5770,46.5924) and (117.8350,45.2196) .. (121.8530,43.4044) -- cycle;
    \end{scope}
    \begin{scope}[cm={{0.99626,0.0,0.0,0.99626,(41.5276,138.898)}}]
      \path[draw=c00003f,line cap=round,line join=round,line width=0.562pt,miter limit=10.04] (58.6962,38.8146) -- (36.5965,-28.3310) .. controls (12.8622,-63.8082) and (-27.5709,-87.1681) .. (-73.4600,-87.1681) .. controls (-146.5380,-87.1681) and (-205.7790,-27.9268) .. (-205.7790,45.1511) .. controls (-205.7790,118.2290) and (-146.5380,177.4700) .. (-73.4600,177.4700) .. controls (-56.3476,177.4700) and (-39.9938,174.2220) .. (-24.9818,168.3080) -- (39.4559,114.1780) .. controls (41.2222,111.2950) and (42.8812,108.3390) .. (44.4273,105.3150) -- (58.8082,48.3489) .. controls (58.8334,47.2860) and (58.8461,46.2200) .. (58.8461,45.1511) .. controls (58.8461,43.0269) and (58.7960,40.9143) .. (58.6962,38.8146) -- cycle;
    \end{scope}
    \begin{scope}[cm={{0.99626,0.0,0.0,0.99626,(41.5276,138.898)}}]
      \path[draw=c00003f,line cap=round,line join=round,line width=0.562pt,miter limit=10.04] (42.4082,117.7020) -- (-22.0387,171.8220) .. controls (-24.4716,179.4210) and (-25.7851,187.5210) .. (-25.7851,195.9280) .. controls (-25.7851,239.5460) and (9.5744,274.9060) .. (53.1925,274.9060) .. controls (96.8107,274.9060) and (132.1700,239.5460) .. (132.1700,195.9280) .. controls (132.1700,187.5340) and (130.8610,179.4470) .. (128.4350,171.8580) -- (104.9390,136.2890) .. controls (101.9690,133.7100) and (98.8053,131.3500) .. (95.4719,129.2320) -- (53.3114,116.9720) .. controls (53.2718,116.9720) and (53.2322,116.9720) .. (53.1925,116.9720) .. controls (49.5343,116.9720) and (45.9342,117.2200) .. (42.4082,117.7020) -- cycle;
    \end{scope}
    \begin{scope}[cm={{0.99626,0.0,0.0,0.99626,(41.5276,138.898)}}]
      \path[draw=c00003f,line cap=round,line join=round,line width=0.562pt,miter limit=10.04] (107.1520,134.8290) -- (130.6250,170.4120) .. controls (135.8100,172.8190) and (141.5880,174.1620) .. (147.6790,174.1620) .. controls (170.0770,174.1620) and (188.2340,156.0050) .. (188.2340,133.6070) .. controls (188.2340,117.9240) and (179.3330,104.3210) .. (166.3070,97.5734) -- (137.4190,94.3609) .. controls (134.0410,95.2416) and (130.8340,96.5470) .. (127.8590,98.2167) -- (108.4510,123.2800) .. controls (107.5850,126.5770) and (107.1240,130.0380) .. (107.1240,133.6070) .. controls (107.1240,134.0160) and (107.1300,134.4230) .. (107.1520,134.8290) -- cycle;
    \end{scope}
    \begin{scope}[cm={{0.99626,0.0,0.0,0.99626,(41.5276,138.898)}}]
      \path[draw=c00003f,line cap=round,line join=round,line width=0.562pt,miter limit=10.04] (137.6100,92.6742) -- (166.4940,95.8951) .. controls (181.2740,91.3063) and (192.0080,77.5236) .. (192.0080,61.2340) .. controls (192.0080,41.1933) and (175.7620,24.9470) .. (155.7210,24.9470) .. controls (152.6640,24.9470) and (149.6950,25.3251) .. (146.8590,26.0369) -- (123.2120,45.0971) .. controls (121.3490,48.8433) and (120.1140,52.9571) .. (119.6460,57.3006) -- (129.6540,86.4646) .. controls (131.9970,88.8845) and (134.6740,90.9791) .. (137.6100,92.6742) -- cycle;
    \end{scope}
    \begin{scope}[cm={{0.99626,0.0,0.0,0.99626,(41.5276,138.898)}}]
      \path[draw=c00003f,line cap=round,line join=round,line width=0.562pt,miter limit=10.04] (108.8560,49.7248) -- (71.3386,45.0229) .. controls (68.2199,46.1067) and (65.2658,47.5420) .. (62.5235,49.2814) -- (48.1261,106.2530) .. controls (49.7824,109.1980) and (51.7779,111.9260) .. (54.0597,114.3850) -- (96.2278,126.6520) .. controls (100.0570,125.6470) and (103.6760,124.1230) .. (107.0050,122.1600) -- (126.4140,97.0975) .. controls (127.3320,93.8808) and (127.8820,90.5090) .. (128.0160,87.0304) -- (118.0060,57.8663) .. controls (115.3660,54.7351) and (112.2850,51.9889) .. (108.8560,49.7248) -- cycle;
    \end{scope}
\end{tikzpicture}
\end{document}

相关内容