\documentclass{article}

\usepackage{axodraw4j}
\begin{document}

\section{Gluon: linear}
Test that I understand the algorithm.  The top gluon is done by
axodraw's \verb+\Gluon+ macro, and the bottom by repeated invocations
of \verb+\Bezier+:
\begin{center}
  \begin{picture}(40,30)(0,-5)
    \Gluon(0,20)(40,20){5}{3}
% Head
    \Bezier(0,0)(0.5,2.5)(2.5,5)(7,5)
    \SetColor{Red}
    \Bezier(7,5)(14.5,5)(14.5,-5)(10,-5)
% Loop 1
\SetColor{Black}
   \Bezier(10,-5)(5.5,-5)(5.5,5)(15,5)
   \SetColor{Red}
    \Bezier(15,5)(24.5,5)(24.5,-5)(20,-5)
% Loop 2
\SetColor{Black}
    \Bezier(20,-5)(15.5,-5)(15.5,5)(25,5)
\SetColor{Red}
    \Bezier(25,5)(34.5,5)(34.5,-5)(30,-5)
% Tail
\SetColor{Black}
    \Bezier(30,-5)(25.5,-5)(25.5,5)(33,5)
\SetColor{Red}
    \Bezier(33,5)(37.5,5)(39.5,2.5)(40,0)
  \end{picture}
\end{center}

The gluon line is rotated until it starts at the origin and goes in
the $x$ direction.  Let the gluon be drawn from start point $(0,0)$ to
$(L,0)$, with $N$ windings and amplitude $A$.  The amplitude is half
of JD's value.  It contains a total of $N+1$ segments.  I've written
the code as if a \verb+Bezier+ subroutine is available, the actual
code is written in terms of \verb+moveto+ and \verb+curveto+.
\begin{verbatim}
   delta = L/(N+1);   // Length of one segment.
                      // In the example, N=3, L=40, A=5
                      // So delta = 10
   // Head is segment 0:
   Bezier( 0,0,
           0.05*delta, 0.5*A,
           0.25*delta, A,
           0.7*delta, A );
   Bezier( 0.7*delta, A,
           delta+0.9*abs(A), A,
           delta+0.9*abs(A), -A)
           delta, -A );
   for ( int j = 1; j < N; j++ ) {
       xj = j * delta;
       // Segment j, 0 < j < N
       Bezier( xj,-A,
               xj-0.9*abs(A), -A,
               xj-0.9*abs(A), A,
               xj+0.5*delta, A );
       Bezier( xj+0.5*delta, A,
               xj+delta+0.9*abs(A), A,
               xj+delta+0.9*abs(A), -A,
               xj+delta, -A );
   }
   // Tail = segment N
   Bezier( L-delta,-A,
           L-delta-0.9*abs(A), -A,
           L-delta-0.9*abs(A), A,
           L-0.7*delta, A );
   Bezier( L-0.7*delta, A,
           L-0.25*delta, A,
           L-0.05*delta, 0.5*A,
           L,0 );
\end{verbatim}

%=========================
\section{Gluon arcs and loops}

A gluon arc is initially drawn as an anticlockwise arc centered on the
origin and starting on the $x$-axis.  The desired arc is then obtained
by transforming this:
\begin{itemize}
\item If the arc is clockwise, the $y$-axis is inverted.
\item Then the arc is rotated and shifted to get the specified placement.
\end{itemize}

In the following code, the gluon arc is centered on the origin, starts
on the $x$-axis, and goes clockwise.  The radius of the arc is $r$,
the opening angle is $\theta$, the number of wiggles is $N$, and the
amplitude is $A$ (which again is half Jaxodraw's value).  The opening
angle is specified in degrees, and has been renormalized to lie in the
range $0<\theta\leq360$, and $\theta=360$ is used to signal a closed loop, which is
treated differently than a non-closed arc.  As written, the code
assumes the existence of functions/methods named \verb+MoveTo+ and
\verb+CurveTo+, in terms of which a \verb+PolarCurveTo+ function is
defined.

The control points of each piece of the gluon line are arranged so
that the path drawn is exactly perpendicular to the radii at the
innermost and outermost points of the path.  There's undoubtedly some
nicer way of writing the code.
\begin{verbatim}
   theta = theta * pi /180;  // Convert to radians
   if (Making Loop) {
      delta = theta / N;    // Size of one segment
   }
   else {
      delta = theta / (N+1);    // Size of one segment
   }
   if (Making loop) {
      //  NO special head part of line
      MoveTo( r-A, 0 );
   }
   else {
      //  Special head part of line
      MoveTo( r, 0 );
      PolarCurveTo( r+0.5*A, 0.05*delta,
                    (r+A)/cos(0.45*delta), 0.25*delta,
                    r+A, 0.7*delta );
      PolarCurveTo((r+A)/cos(0.3*delta+0.9*abs(A)/r), delta + 0.9*abs(A)/r,
                   (r-A)/cos(0.9*abs(A)/r), delta + 0.9*abs(A)/r,
                   r-A, delta );
   }
   int j1 = 2;
   int j2 = N;
   if (Making Loop) {
      j1 = 1;
   }
   for ( int j = j1; j <= j2; j++ ) {
       thetaj = (j-1) * delta;
       PolarCurveTo( (r-A)/cos(0.9*abs(A)/r), thetaj-0.9*abs(A)/r,
                     (r+A)/cos(0.5*delta+0.9*abs(A)/r), thetaj-0.9*abs(A)/r,
                     r+A,  thetaj+0.5*delta );
       PolarCurveTo( (r+A)/cos(0.5*delta+0.9*abs(A)/r), thetaj+delta+0.9*abs(A)/r,
                     (r-A)/cos(0.9*abs(A)/r), thetaj+delta+0.9*abs(A)/r,
                     r-A, thetaj+delta );
   }
   if ( NOT Making loop ) {
      // Tail
      PolarCurveTo( (r-A)/cos(0.9*abs(A)/r), theta - delta - 0.9*abs(A)/r,
                    (r+A)/cos(0.3*delta+0.9*abs(A)/r), theta - delta - 0.9*abs(A)/r,
                    r+A,  theta - 0.7*delta );
      PolarCurveTo( (r+A)/cos(0.45*delta), theta - 0.25*delta,
                    r+0.5*A, theta - 0.05*delta,
                    r,  theta );
   }

//--------------

   void PolarCurveTo( double r1, double theta1,
                 double r2, double theta2,
                 double r3, double theta3 )
   {
       CurveTo( r1*cos(theta1), r1*sin(theta1),
                r2*cos(theta2), r2*sin(theta2),
                r3*cos(theta3), r3*sin(theta3) );
   }
\end{verbatim}

\end{document}
