5

I want to use a single \path or \draw command in TikZ to generate a closed path representing the outline of a bicycle sprocket. If a sprocket has n teeth, the path will be composed of 2n connected circle arc segments appropriately centered and oriented. I use a few lines of code to compute the arc radii, specify where their centers should be placed, and determine their start and end angles. Based on a related stackexchange question, I wrote a single \def macro \centerarc with six input arguments to specify exactly where each arc segment will be drawn, and this macro executes an arc() command to define the arc segment before it returns.

The main difference between this macro and other \centerarc macro examples is this one does not contain a \draw command. Instead, a single \draw command calls this macro 2n times, each call separated by "to", to join adjacent segments, and this is where I am having problems. The image results are what I expected, but there are a lot of pgf errors because the input arguments to \centerarc are not compatible with the basic \plot and \draw specifications. (I am using BaKoMa TeX Word as the editor.) To eliminate the error messages, it appears I must either change how the input arguments to \centerarc are set up or find a way to instruct pgf to ignore the inputs because \draw does not use them anyway.

The second issue, which I haven't explored completely, is how to insert a foreach or for loop into the \draw command to avoid making multiple copies of the \centerarc macro as in the attached example code. Or maybe there is an easier way of joining the results of 2n simple \draw commands into one closed path.

An alternative to this method, which I have also explored, is to use the arc segments to inversely clip out chunks of gray to form the tooth pockets and tips. It will be interesting to see which method is faster. A full circle works to clip out the tooth pockets, and a crescent works to clip off the tooth tips.

%&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}

Segment of twenty-tooth bicycle sprocket

Based on the second example given below, here is a parameterized version of sprocket draw.

%&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}

Bicycle sprocket image drawn by parameterized sprocket model

6

This has IMHO nothing to do with tikzmath, it is just an expansion issue that can be fixed in the usual way. The alternative would be to modify the parser of TiKZ, something that I do not want to discuss, or to play with insert path and so on. However, this works:

\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}

enter image description here

As for your question on foreach: yes, you can do that.

\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}

enter image description here

This is just a very quick approximation. Perhaps decorations are a cleaner way to go.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.