我想在 TikZ 中使用单个 \path 或 \draw 命令来生成表示自行车链轮轮廓的封闭路径。如果链轮有 n 个齿,则路径将由 2n 个连接的圆弧段组成,这些圆弧段具有适当的中心和方向。我使用几行代码来计算圆弧半径,指定它们的中心应放在哪里,并确定它们的起始和终止角度。根据相关的 stackexchange 问题,我编写了一个带有六个输入参数的单个 \def 宏 \centerarc,以精确指定每个圆弧段的绘制位置,并且此宏在返回之前执行 arc() 命令来定义圆弧段。
此宏与其他 \centerarc 宏示例的主要区别在于此宏不包含 \draw 命令。相反,单个 \draw 命令会调用此宏 2n 次,每次调用都以“to”分隔,以连接相邻的段,而这正是我遇到问题的地方。图像结果符合我的预期,但存在大量 pgf 错误,因为 \centerarc 的输入参数与基本 \plot 和 \draw 规范不兼容。(我使用 BaKoMa TeX Word 作为编辑器。)为了消除错误消息,看来我必须更改 \centerarc 的输入参数的设置方式,或者找到一种方法来指示 pgf 忽略输入,因为 \draw 无论如何都不会使用它们。
第二个问题我还没有完全探究,那就是如何在 \draw 命令中插入 foreach 或 for 循环,以避免像所附示例代码中那样多次复制 \centerarc 宏。或者也许有一种更简单的方法可以将 2n 个简单的 \draw 命令的结果合并为一个封闭路径。
我也探索过这种方法的另一种替代方法是使用圆弧段反向剪切出灰色块以形成齿袋和齿尖。看看哪种方法更快会很有趣。一个完整的圆圈可以剪切出齿袋,而一个新月形可以剪切出齿尖。
%&latex
\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfmath}
\usetikzlibrary{calc}
\usetikzlibrary{math}
% #1 = x coordinate of arc-circle center before rotation into place
% #2 = y coordinate of arc-circle center before rotation into place
% $3 = angle to rotate arc-circle into place about origin (degrees)
% #4 = local start of arc angle before rotation (degrees)
% #5 = local end of arc angle before rotation (degrees)
% #6 = arc-circle radius
\def\centerarc(#1:#2:#3)(#4:#5:#6)
{($({cos(#3)*#1-sin(#3)*#2+cos(#3+#4)*#6},
{sin(#3)*#1+cos(#3)*#2+sin(#3+#4)*#6})$)
arc(#3+#4:#3+#5:#6)}
\begin{document}
\begin{tikzpicture}
\tikzmath{% Some math to define and position the 2*\n arc segments
\n = 20; % number of sprocket teeth
\Tp = 360/\n; % angle between teeth in degrees
\lp = 4; % length of chain link (true length = 1/2 inch)
\rp = \lp/(2*sin(\Tp/2)); % sprocket pitch radius
\rr = 0.3*\lp; % link roller radius
\Tpo = acos(\rr/(2*\rp)); % half-angle of tooth-pocket arc
\rt = 0.8*\lp; % tooth-tip radius
\Tt = \Tp/2 - 2*asin(\rr/(2*\rp));
\x = \rp*sin(\Tt);
\Tte = asin(\x/\rt); % half-angle of tooth-tip arc
\A = cos(\Tt) - (\rt/\rp)*cos(\Tte);% locates center of tooth-tip arc
\Tpc = 0.5*\Tp; % half angle between adjacent teeth
}
% For illustration purposes this single \draw command generates
% a pie-slice of the sprocket. I have yet to figure out
% how to use a foreach or for loop to generate the sprocket with
% only two calls to \centerarc. Any suggestions on incorporating
% a foreach or for loop into \draw are welcome, but that is
% not the main topic of this question.
\draw[fill, color = gray!30]
\centerarc(\A*\rp:0:0)(-\Tte:\Tte:\rt) to
\centerarc(\rp:0:\Tpc)(180+\Tpo:180-\Tpo:\rr) to
\centerarc(\A*\rp:0:\Tp)(-\Tte:\Tte:\rt) to
\centerarc(\rp:0:3*\Tpc)(180+\Tpo:180-\Tpo:\rr) to
\centerarc(\A*\rp:0:2*\Tp)(-\Tte:\Tte:\rt) to
(0,0);
\end{tikzpicture}
\end{document}
根据下面给出的第二个示例,这里是链轮绘制的参数化版本。
%&latex
\documentclass{article}
\usepackage{tikz}
\usepackage{pgfmath}
\usetikzlibrary{calc}
\usetikzlibrary{math}
\def\drawsprocket(#1,#2,#3,#4){%
%#1 = x-position of sprocket center.
%#2 = y-position of sprocket center.
%#3 = sprocket rotation angle.
%#4 = number of sprocket teeth.
\begin{scope}%[scale=1/25.4]
\tikzmath{%Some math to define and position the 2*\n arc segments
\n = #4;
\m = \n-1;
\s = 360/\n;
\Tp = 360/\n;
\lp = 0.5in;
\rp = \lp/(2*sin(\Tp/2));
\rr = 0.3*\lp;
\rc = \rp+\rr;
\Tpo = acos(\rr/(2*\rp));
\rt = 0.8*\lp;
\Tt = \Tp/2 - 2*asin(\rr/(2*\rp));
\x = \rp*sin(\Tt);
\Tte = asin(\x/\rt);
\A = cos(\Tt) - (\rt/\rp)*cos(\Tte);
\Ttc = 0.0;
\Tpc = 0.5*\Tp;
\xsl = \A*\rp+cos(\Tte)*(1-\A)*\rp;
\ysl = -sin(\Tte)*(1-\A)*\rp;
\xs = #1+cos(#3)*\xsl-sin(#3)*\ysl;
\ys = #2+sin(#3)*\xsl+cos(#3)*\ysl;
}
\fill[gray!50] (\xs,\ys)
foreach \i in {0,...,\m}
{
arc(\s*\i-\Tte:\s*\i+\Tte:\rt)
arc(\s*(\i+0.5)+180+\Tpo:\s*(\i+0.5)+180-\Tpo:\rr)
}
-- cycle;
\end{scope}
}
\begin{document}
\begin{tikzpicture}[x=1mm, y=1mm, scale=.1]
\drawsprocket(0,0,0,30)
\drawsprocket(-10in,0,0,20)
\drawsprocket(-10in,-3.1in,0,10)
\drawsprocket(-10.75in,-5.5in,0,10)
\end{tikzpicture}
\end{document}
答案1
在我看来,这与 tikzmath 无关,这只是一个扩展问题,可以用通常的方式修复。另一种方法是修改 Ti 的解析器钾Z,我不想讨论这个,也不想玩插入路径之类的。但是,这有效:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfmath}
\usetikzlibrary{calc}
\usetikzlibrary{math}
% #1 = x coordinate of arc-circle center before rotation into place
% #2 = y coordinate of arc-circle center before rotation into place
% $3 = angle to rotate arc-circle into place about origin (degrees)
% #4 = local start of arc angle before rotation (degrees)
% #5 = local end of arc angle before rotation (degrees)
% #6 = arc-circle radius
\def\centerarc(#1:#2:#3)(#4:#5:#6)
{($({cos(#3)*#1-sin(#3)*#2+cos(#3+#4)*#6},
{sin(#3)*#1+cos(#3)*#2+sin(#3+#4)*#6})$)
arc(#3+#4:#3+#5:#6)}
\begin{document}
\begin{tikzpicture}
\tikzmath{% Some math to define and position the 2*\n arc segments
\n = 20; % number of sprocket teeth
\Tp = 360/\n; % angle between teeth in degrees
\lp = 4; % length of chain link (true length = 1/2 inch)
\rp = \lp/(2*sin(\Tp/2)); % sprocket pitch radius
\rr = 0.3*\lp; % link roller radius
\Tpo = acos(\rr/(2*\rp)); % half-angle of tooth-pocket arc
\rt = 0.8*\lp; % tooth-tip radius
\Tt = \Tp/2 - 2*asin(\rr/(2*\rp));
\x = \rp*sin(\Tt);
\Tte = asin(\x/\rt); % half-angle of tooth-tip arc
\A = cos(\Tt) - (\rt/\rp)*cos(\Tte);% locates center of tooth-tip arc
\Tpc = 0.5*\Tp; % half angle between adjacent teeth
}
% For illustration purposes this single \draw command generates
% a pie-slice of the sprocket. I have yet to figure out
% how to use a foreach or for loop to generate the sprocket with
% only two calls to \centerarc. Any suggestions on incorporating
% a foreach or for loop into \draw are welcome, but that is
% not the main topic of this question.
\edef\temp{\noexpand\draw[fill, color = gray!30]
\centerarc(\A*\rp:0:0)(-\Tte:\Tte:\rt) to
\centerarc(\rp:0:\Tpc)(180+\Tpo:180-\Tpo:\rr) to
\centerarc(\A*\rp:0:\Tp)(-\Tte:\Tte:\rt) to
\centerarc(\rp:0:3*\Tpc)(180+\Tpo:180-\Tpo:\rr) to
\centerarc(\A*\rp:0:2*\Tp)(-\Tte:\Tte:\rt) to
(0,0);}
\temp
\end{tikzpicture}
\end{document}
至于您的问题foreach
:是的,您可以这样做。
\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{calc}
\begin{document}
\begin{tikzpicture}
\fill[gray!50] (10,0) foreach \X in {0,...,35} {--(10*\X:10) arc(10*\X:10*\X+5:10)
arc(10*\X+96+180:10*\X+97:0.42) } -- cycle ;
\end{tikzpicture}
\end{document}
这只是一种非常快速的近似方法。也许装饰是一种更干净的方法。