此 MWE 绘制了多个自行车链节轮廓,但还没有将链节端到端连接成链段的自动化程序。每个链节由两个滚轮组成,我将其称为第一个和第二个。链节的局部 xy 坐标系的原点以第一个滚轮为中心,其 x 轴指向第二个滚轮。下一个链节的参考系的原点(在其第一个滚轮的中心)将连接到当前链节的第二个滚轮的中心。\drawlink 宏的当前版本将链节的第一个滚轮(其参考系的原点)的绝对 x 和 y 坐标作为前两个参数,并将该框架的绝对旋转作为第三个参数。利用这三个量,可以相对于全局框架以任何位置和方向绘制链节。
为了简化从链接组装链段,我想修改 \drawlink 宏以采用前一个链接的第二个滚轮的绝对位置及其绝对角度,采用当前链接相对于前一个链接的角度,并返回当前链接的第二个滚轮的绝对位置及其绝对角度。
因此,我正在寻找一个程序,从 \drawlink 宏返回当前链接的第二个滚轮的绝对位置及其绝对角度,并将这些量连同偏移角度一起传递回对 \drawlink 宏的下一次调用。然后 \drawchain 宏只需提供链接之间的相对角度,其余部分由 \drawlink 宏处理。
%&latex
\documentclass{article}
\usepackage{tikz}
\usepackage{pgfmath}
\usetikzlibrary{calc}
\usetikzlibrary{math}
\usepackage{xstring}
\def\drawlink(#1,#2,#3,#4){%
%#1 = x-position of first roller center.
%#2 = y-position of first roller center.
%#3 = link rotation angle.
%#4 = link gray saturation: 0 to 100
\begin{scope}
\tikzmath{%Some math to define and position the link components
\lp = 0.5in;
\re = 0.3299*\lp;
\rc = 0.4284*\lp;
\Th = 41.25;
\Thc = 90 - \Th;
\Tp = \Thc + #3;
\Tn = \Thc - #3;
\xs = #1 + cos(\Tp)*\re;
\ys = #2 + sin(\Tp)*\re;
}
\fill[gray!#4] (\xs,\ys)
arc(\Tp:360-\Tn):\re)
arc(180-\Tn:\Tp:\rc)
arc(-180+\Tp:180-\Tn:\re)
arc(-\Tn:-180+\Tp:\rc)
-- cycle;
\end{scope}
}
\begin{document}
\begin{tikzpicture}[x=1mm, y=1mm, scale=0.25]
\pgfdeclarelayer{top}
\pgfsetlayers{main,top}
\pgfonlayer{main}
\foreach \i in {1,...,5}{
\drawlink(\i in,0,0,50)
}
\endpgfonlayer
\pgfonlayer{top}
\foreach \i in {0.5,1.5,...,5.5}{
\drawlink(\i in,0,0,100)
}
\endpgfonlayer
\end{tikzpicture}
\end{document}
答案1
我不会这样做。相反,我会使用一张我使用装饰多次放置在路径上的图片。请注意,我没有调整你的代码,而是专注于“将某物放入图片”和“在装饰中重复”的方法。不过,我真的很喜欢你在这里使用图层的巧妙想法!
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\usetikzlibrary{math}
\usetikzlibrary{decorations.markings}
\tikzset{pics/.cd,
link/.style={code={\begin{scope}
\tikzmath{%Some math to define and position the link components
\lp = 0.5in;
\re = 0.3299*\lp;
\rc = 0.4284*\lp;
\Th = 41.25;
\Thc = 90 - \Th;
\Tp = \Thc;
\Tn = \Thc;
}
\fill[gray!#1] (0,0)%(\xs,\ys)
arc(\Tp:360-\Tn):\re)
arc(180-\Tn:\Tp:\rc)
arc(-180+\Tp:180-\Tn:\re)
arc(-\Tn:-180+\Tp:\rc)
-- cycle;
\end{scope}
}}}
\begin{document}
\begin{tikzpicture}
\pgfdeclarelayer{top}
\pgfsetlayers{main,top}
\pgfonlayer{main}
\path[decorate,decoration={markings,
mark=between positions 0 and 1 step 2.9in
with {\pic[scale=0.1]{link=30};}
}] (0,0) -- (9in,0);
\endpgfonlayer
\pgfonlayer{top}
\path[decorate,decoration={markings,
mark=between positions 0 and 1 step 2.9in
with {\pic[scale=0.1]{link=80};}
}] (1.45in,0) -- (9in,0);
\endpgfonlayer
\end{tikzpicture}
\end{document}
附录:我只是好奇是否有可能让 Ti钾Z 沿着路径绘制一条链。我认为答案是肯定的。以下帖子一点也不精致。特别是,我用一个更简单、更不花哨的版本替换了你的好链接。唯一的原因是这个东西是以为中心的(0,0)
。如果你想出一个具有更直观的参数化的形状,也可以使用它。我还没有太注意路径闭合的要求。我复制了这个例子拥有一条有点像自行车链条的路径,但路径的细节并不重要。唯一可能重要的是,此例程将找到曲线上相隔给定距离(链的尺寸减去其圆半径的两倍)的点。这是通过计算适当的交叉点(并“巧妙地”选择相关的交叉点)来实现的。
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings,intersections}
\tikzset{pics/.cd,
mylink/.style={code={
\fill[gray!#1] (-0.6,0.6) to[out=-50,in=-110,looseness=0.7] (0.6,0.6)
arc(140:-140:0.9)
-- (0.6,-0.6) to[out=110,in=50,looseness=0.7] (-0.6,-0.6) arc(-40:-320:0.9);
}}}
\begin{document}
\begin{tikzpicture}
\pgfdeclarelayer{top}
\pgfsetlayers{main,top}
% tangents are from https://tex.stackexchange.com/a/7209/121799
\pgfmathsetmacro{\rone}{10}
\pgfmathsetmacro{\rtwo}{8}
\pgfmathsetmacro{\mid}{\rone/(\rone + \rtwo)}
\pgfmathsetmacro{\out}{\rone/(\rone - \rtwo)}
\node[circle,minimum size=2 * \rone cm,inner sep=0pt] (c1) at (21.1,0) {};
\node[circle,minimum size=2 * \rtwo cm,inner sep=0pt] (c2) at (0,0) {};
\path (c1.center) -- node[coordinate,pos=\mid] (mid) {} (c2.center);
\path (c1.center) -- node[coordinate,pos=\out] (out) {} (c2.center);
% \draw[red] (tangent cs:node=c2,point={(out)}) -- (tangent cs:node=c1,point={(out)});
% \draw[red] (tangent cs:node=c2,point={(out)},solution=2) -- (tangent cs:node=c1,point={(out)},solution=2);
% end https://tex.stackexchange.com/a/7209/121799
\path[name path=chain,postaction={decorate,decoration={markings,
mark=at position 0 with {\xdef\clen{\pgfdecoratedpathlength}}}},
draw=blue,thick] let
\p1=($(tangent cs:node=c2,point={(out)})-(c2.center)$),
\n1={atan2(\y1,\x1)},
\p2=($(tangent cs:node=c1,point={(out)})-(c1.center)$),
\n2={atan2(\y2,\x2)},
\p3=($(tangent cs:node=c1,point={(out)},solution=2)-(c1.center)$),
\n3={atan2(\y3,\x3)},
\p4=($(tangent cs:node=c2,point={(out)},solution=2)-(c2.center)$),
\n4={atan2(\y4,\x4)} in
(tangent cs:node=c2,point={(out)}) --
(tangent cs:node=c1,point={(out)}) arc(\n2:\n3:\rone)
-- (tangent cs:node=c2,point={(out)},solution=2) arc(\n4:\n1+360:\rtwo);
\coordinate (p0pt) at (tangent cs:node=c2,point={(out)});
\path[name path=c0] (p0pt) circle (2.9in);
\fill[name intersections={of=chain and c0,total=\t}] foreach \i in {1,...,\t}
{(intersection-\i) circle(3pt) node[below] {\i}};
\path (intersection-1) coordinate (p1pt);
\pgfmathsetmacro{\Nmax}{int(\clen/(2.6cm))}
\typeout{\Nmax}
\foreach \X [evaluate=\X as \Y using {int(\X-1)},evaluate=\X as \Z using {int(\X+1)}] in {1,...,\Nmax} % \Nmax
{
\path[name path=c\X] (p\X pt) circle (2.6cm);
\fill[name intersections={of=chain and c\X,total=\t}] foreach \i in {1,...,\t}
{let
\p1=($(intersection-\i)-(p\Y pt)$),\n1={ifthenelse(int(veclen(\x1,\y1)/1pt)<10,int(-1),int(\Z/1pt))}
in %\pgfextra{\typeout{\X:\i:\n1}}
(intersection-\i) coordinate (p\n1) };
\ifodd\X
\pgfonlayer{main}
\path let \p1=($(p\X pt)-(p\Z pt)$),\n1={atan2(\y1,\x1)}
in ($(p\X pt)!0.5!(p\Z pt)$) pic[rotate=\n1]{mylink=30};
\endpgfonlayer
\else
\pgfonlayer{top}
\path let \p1=($(p\X pt)-(p\Z pt)$),\n1={atan2(\y1,\x1)}
in ($(p\X pt)!0.5!(p\Z pt)$) pic[rotate=\n1]{mylink=80};
\endpgfonlayer
\fi
}
\pgfonlayer{top}
\path let \p1=($(p\Nmax pt)-(p1pt)$),\n1={atan2(\y1,\x1)}
in ($(p\Nmax pt)!0.5!(p1pt)$) pic[rotate=\n1]{mylink=80};
\endpgfonlayer
\end{tikzpicture}
\end{document}
你也可以制作动画:
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings,intersections}
\tikzset{pics/.cd,
mylink/.style={code={
\fill[gray!#1] (-0.6,0.6) to[out=-50,in=-110,looseness=0.7] (0.6,0.6)
arc(140:-140:0.9)
-- (0.6,-0.6) to[out=110,in=50,looseness=0.7] (-0.6,-0.6) arc(-40:-320:0.9);
}}}
\begin{document}
\foreach \nn in {0,...,9}
{\begin{tikzpicture}
\pgfdeclarelayer{top}
\pgfsetlayers{main,top}
% tangents are from https://tex.stackexchange.com/a/7209/121799
\pgfmathsetmacro{\rone}{10}
\pgfmathsetmacro{\rtwo}{8}
\pgfmathsetmacro{\mid}{\rone/(\rone + \rtwo)}
\pgfmathsetmacro{\out}{\rone/(\rone - \rtwo)}
\node[circle,minimum size=2 * \rone cm,inner sep=0pt] (c1) at (21.1,0) {};
\node[circle,minimum size=2 * \rtwo cm,inner sep=0pt] (c2) at (0,0) {};
\path (c1.center) -- node[coordinate,pos=\mid] (mid) {} (c2.center);
\path (c1.center) -- node[coordinate,pos=\out] (out) {} (c2.center);
% \draw[red] (tangent cs:node=c2,point={(out)}) -- (tangent cs:node=c1,point={(out)});
% \draw[red] (tangent cs:node=c2,point={(out)},solution=2) -- (tangent cs:node=c1,point={(out)},solution=2);
% end https://tex.stackexchange.com/a/7209/121799
\path[name path=chain,postaction={decorate,decoration={markings,
mark=at position 0 with {\xdef\clen{\pgfdecoratedpathlength}
\pgfmathsetmacro{\Nmax}{int(\clen/(2.6cm))}
\xdef\Nmax{\Nmax}},
mark=at position {2*\nn/(10*(\Nmax))} with {\coordinate (start) at (0,0);}
}},
draw=blue,thick] let
\p1=($(tangent cs:node=c2,point={(out)})-(c2.center)$),
\n1={atan2(\y1,\x1)},
\p2=($(tangent cs:node=c1,point={(out)})-(c1.center)$),
\n2={atan2(\y2,\x2)},
\p3=($(tangent cs:node=c1,point={(out)},solution=2)-(c1.center)$),
\n3={atan2(\y3,\x3)},
\p4=($(tangent cs:node=c2,point={(out)},solution=2)-(c2.center)$),
\n4={atan2(\y4,\x4)} in
(tangent cs:node=c2,point={(out)}) --
(tangent cs:node=c1,point={(out)}) arc(\n2:\n3:\rone)
-- (tangent cs:node=c2,point={(out)},solution=2) arc(\n4:\n1+360:\rtwo);
\coordinate (p0pt) at (start) ;% (tangent cs:node=c2,point={(out)});
\path[name path=c0] (p0pt) circle (2.9in);
\fill[name intersections={of=chain and c0,total=\t}] foreach \i in {1,...,\t}
{(intersection-\i) circle(3pt) node[below] {\i}};
\path (intersection-1) coordinate (p1pt);
\typeout{\nn:\Nmax}
\foreach \X [evaluate=\X as \Y using {int(\X-1)},evaluate=\X as \Z using {int(\X+1)}] in {1,...,\Nmax} % \Nmax
{
\path[name path=c\X] (p\X pt) circle (2.6cm);
\fill[name intersections={of=chain and c\X,total=\t}] foreach \i in {1,...,\t}
{let
\p1=($(intersection-\i)-(p\Y pt)$),\n1={ifthenelse(int(veclen(\x1,\y1)/1pt)<10,int(-1),int(\Z/1pt))}
in %\pgfextra{\typeout{\X:\i:\n1}}
(intersection-\i) coordinate (p\n1) };
\ifodd\X
\pgfonlayer{main}
\path let \p1=($(p\X pt)-(p\Z pt)$),\n1={atan2(\y1,\x1)}
in ($(p\X pt)!0.5!(p\Z pt)$) pic[rotate=\n1]{mylink=30};
\endpgfonlayer
\else
\pgfonlayer{top}
\path let \p1=($(p\X pt)-(p\Z pt)$),\n1={atan2(\y1,\x1)}
in ($(p\X pt)!0.5!(p\Z pt)$) pic[rotate=\n1]{mylink=80};
\endpgfonlayer
\fi
}
\pgfonlayer{top}
\path let \p1=($(p\Nmax pt)-(p1pt)$),\n1={atan2(\y1,\x1)}
in ($(p\Nmax pt)!0.5!(p1pt)$) pic[rotate=\n1]{mylink=80};
\endpgfonlayer
\end{tikzpicture}}
\end{document}