我的尝试:
\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
格式转换TikZ
为svg2tikz:
\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}