%   This is the metafont for the feynfont font, release 0.4.3, 2022 July 20
%
%   Copyright 1991, 1994, 2001, 2002, 2005, 2008-10, Norman Gray.
%   See the file LICENCE for licence details.
%
%   Mercurial revision 0a471f8ed572, 2022-07-20 11:23 +0100, tag 0.4.3 + 0
%
%
%
%   When I look at the property list of the generated TFM (using
%   tftopl) it starts with `(FAMILY CMR)': but this isn't in the cmr
%   family.  I can't find anything in cmbase.mf which would cause
%   this.  Perhaps I need to read the Metafont Book more closely.


mode_setup; font_setup;

% a# is the position of the characters above the baseline.
a# := on_math_axis * math_axis#; % math_axis is defined by cmr

% Feyn macros
input feynmac;

define_pixels (module,bigarrow,littlearrow,blobr,a);
define_blacker_pixels (linewidth,thinlinewidth);

pickup pencircle scaled linewidth;
diagram_pen := savepen;

% general definitions
phangle := 75;                  % photon angle

squash := 0.75;                 % the amount by which some loops are squashed

% The caller must set the following parameters to values such as these
%boson_wiggles := 4;             %this must be an even number
%boson_wiggles_loop_small := 4;
%boson_wiggles_loop_normal := 6;
%boson_wiggles_loop_large := 8;


%   All the character positions between 0 and hex"7F"
%   have characters in them.  Not all of these characters are ones
%   which should appear on paper; some (such as `s' or `l') only
%   appear in ligatures, and others shouldn't appear at all.  If,
%   however, there are no characters in these positions, some DVI
%   readers (including TFtoPL and OzTeX for example) complain about a
%   `bad TFM file'.  These locations are therefore occupied by the
%   character generated by the errorchar macro, which is 0pt wide, and
%   1module# high.  This character doesn't generate any real error,
%   but the glyph will be manifestly peculiar on paper.
%
%   Add code to extra_beginchar so that we keep a record of all the
%   characters that we generate, so that we can generate an errochar
%   character for each of the codepoints that we've skipped.  `charcode'
%   is defined in the expansion of beginchar()

numeric donechar[];
string  donecharerror;
donecharerror := "Duplicate character";
extra_beginchar := extra_beginchar & "if known donechar[charcode]: errmessage donecharerror; fi donechar[charcode] := 1;";

path charpath, charpathb;
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%   Digits 0x30--0x39.  Obtain these from the cmr source file: romand.mf.
input romand;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%   Fermions

def path_fermion (expr scale_sharp, ang) =
  begingroup
    save scale;
    scale := hround(scale_sharp*hppp);
    if ang > 0:                 % slopes upward
      (0,a) .. (scale*(cosd ang), scale*(abs sind ang)+a)
    else :
      (0,scale*(abs sind ang)+a) .. (scale*(cosd ang), a)
    fi
  endgroup
enddef;

threechars ("f", "fermion",
  path_fermion(2module#, 0), 0.5, 2module#, 0, 0,
    (0,0.1module), "top");

begingroup                      % make closed fermion loop, for phi^4 theory
  clearxy;
  save height;
  height# := 2module#;
  define_pixels(height);
  z2 = (0, height);             %top of loop
  y1 = y3 = 2y2/3;
  x1+x3 = 0;
  x1-x3 = 2height/3;
  charpath := origin .. z1 .. z2 .. z3 .. origin;
  threechars ("k", "fermion loop",
      charpath shifted (0,a), 2,
      0, 2module#, 0,
      0, "top");
endgroup;    

beginchar (hex"21", module#, 0, 0);
  "short fermion";
  pen;
  draw path_fermion(module#, 0);
endchar;


%   The following characters are in boxes the same vertical size as the black
%   bit of the character, but they project out of the top by an amount equal to
%   the height of the math axis, and are that same height clear of the bottom
%   of the box.
%
%%%% -90 <= ang <= +90, or all hell will break loose

threechars ("e", "upward fermion",
  path_fermion(2module#, 45), 0.5,
    2module#*(cosd 45), 2module#*(abs sind 45), 0,
    0, "ulft");

threechars ("d", "downward fermion",
  path_fermion(2module#, -45), 0.5,
    2module#*(cosd -45), 2module#*(abs sind -45), 0,
    0, "urt");
  
threechars ("b", "vertically upward fermion",
  path_fermion(2module#, 90), 0.5,
    2module#*(cosd 90), 2module#*(abs sind 90), 0,
    0, "urt");

charpath := path_fermion(2module#, 0);
beginchar("m", 2module#, 0, 0); "massive fermion";
  pen;
  draw charpath shifted (0,linewidth);
  draw charpath shifted (0,-linewidth);
  annotate_at(point 0.5 of charpath shifted (0,linewidth), "top");
endchar;

beginchar("M", 2module#, 0, 0); "r-arrowed massive fermion";
  pen;
  draw charpath shifted (0,linewidth);
  draw charpath shifted (0,-linewidth);
  drawarrow (bigarrow, point 0.5 of charpath, 0);
  annotate_at(point 0.5 of charpath shifted (0,linewidth), "top");
endchar;

beginchar(byte"m"-hex"60", 2module#, 0, 0); "l-arrowed massive fermion";
  pen;
  draw charpath shifted (0,linewidth);
  draw charpath shifted (0,-linewidth);
  drawarrow (bigarrow, point 0.5 of charpath, 180);
  annotate_at(point 0.5 of charpath shifted (0,linewidth), "top");
endchar;

charpath := path_fermion(module#, 0);
beginchar(hex"23", module#, 0, 0); "short massive fermion";
  pen;
  draw charpath shifted (0,linewidth);
  draw charpath shifted (0,-linewidth);
  %drawarrow (littlearrow, point 0.5 of charpath, 0);
  annotate_at(point 0.5 of charpath shifted (0,linewidth), "top");
endchar;

begingroup
  clearxy;
  save width;
  width# := 4module#;
  define_pixels(width);
  x2-x0 = 2(x1-x0) = width;
  x1 = 0;
  y0 = y2 = 0;
  y1 = 2squash*module;
  charpath := z0 .. z1 .. z2;

  threechars("l", "fermion loop",
    charpath shifted (0,a), 1,
    0, 2squash*module#+a#, 0,
    0, "top");
  threechars("n", "fermion loop, inverted",
    charpath yscaled -1 shifted (0,a), 1,
    0, a#, 0,
    0, "bot");
  threechars("o", "fermion loop, small",
    charpath scaled 0.66667 shifted (0,0.66667a), 1,
    0, module#+a#, 0,
    0, "top");
  threechars("w", "fermion loop, small, inverted",
    charpath xscaled 0.66667 yscaled -0.66667 shifted(0,0.66667a), 1,
    0, module#+a#, 0,
    0, "bot");
endgroup;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Gauge bosons
%

def path_boson (expr scale_sharp, ang, taper) =
  begingroup
    save scale;
    clearxy;
    scale := hround(scale_sharp*hppp);
    x1 = 0;
    x99 = scale*(cosd ang);
    if ang > 0 :                % slopes upward
      y1 = a;
      y99 = scale*(abs sind ang) + a;
    else :
      y1 = scale*(abs sind ang) + a;
      y99 = a;
    fi
    for i = 3 upto boson_wiggles:
      z[i] - z[i-1] = z2-z1;
    endfor
    z99 - z[boson_wiggles] = z2-z1;
    def ::(expr b) = {dir (ang+b)} looselink {dir (ang-b)} enddef;

    z1 ::(phangle)z2
    for i = 3 step 2 until boson_wiggles:
      ::(-phangle) z[i] ::(phangle)z[i+1]
    endfor
    if taper <> 0 :
      {dir (ang-phangle)} .. tension 1 and 0.8 .. {dir (ang+phangle/2)}
    else :
      ::(-phangle)
    fi
    z99
  endgroup
enddef;

% the following is a simpler version of the above, without the
% boson_wiggles, to document what it's supposed to be doing
def path_boson_orig (expr scale_sharp, ang, taper) =
  begingroup
    save scale;
    clearxy;
    scale := hround(scale_sharp*hppp);
    x1 = 0; x5 = scale*(cosd ang);
    if ang > 0 :                % slopes upward
      y1 = a;
      y5 = scale*(abs sind ang) + a;
    else :
      y1 = scale*(abs sind ang) + a;
      y5 = a;
    fi
    z2-z1 = z3-z2 = z4-z3 = z5-z4;
    def ::(expr b) = {dir (ang+b)} looselink {dir (ang-b)} enddef;

    z1 ::(phangle) z2 ::(-phangle) z3 ::(phangle) z4
    if taper <> 0 :
      {dir (ang-phangle)} .. tension 1 and 0.8 .. {dir (ang+phangle/2)}
    else :
      ::(-phangle)
    fi
    z5
  endgroup
enddef;

threechars ("g", "gluon",
  path_boson(2module#, 0, 0), boson_wiggles/2,
  2module#, 0, 0,
  (0, 0.2module), "top");
threechars ("u", "upward gluon",
  path_boson(2module#, 45, 0), boson_wiggles/2,
  2module#*(cosd 45), 2module#*(abs sind 45), 0,
  0, "ulft");
threechars ("v", "downward gluon",
  path_boson(2module#, -45, 0), boson_wiggles/2,
  2module#*(cosd -45), 2module#*(abs sind -45), 0,
  0, "urt");
threechars (hex"7D",
  "vertical gluon",
  path_boson(2module#, 90, 1), boson_wiggles/2,
  0, 2module#, 0,
  0, "urt");

% plus or minus phangle, depending on whether n is odd or even
def pm_angle(expr n) =
  if odd n: -1 else: 1 fi*phangle
enddef;

% a gluon quarter loop, in the upper-right quadrant:
%   wid:    radius of loop in modules
%   nopts:  number of points
%   inv:    if 1, the loop goes from the axis to the top;
%           if 0, from the top down to the axis
%   negang: if 1, negate the photon angle (so it wiggles oppositely);
%           if 0, don't
%   taper:  if 1 or 3, the line tapers as it approaches the axis
%           if 2 or 3, the line tapers as it approaches the top
%           if 0, the line does not taper
% (I can't help feeling this macro has become more complicated than it
% really need be...)
def path_quadloop (expr wid, nopts, inv, negang, taper) =
  begingroup
    save halfwidth, myangle;
    clearxy;
    halfwidth# := wid*module#;
    define_pixels(halfwidth);
    myangle = if negang <> 0: -phangle else: phangle fi;
    z0 = (halfwidth, 0);        % z0 is on the axis
    for x = 1 upto nopts:
      z[x] = z0 rotated (x*90/nopts);
    endfor
    if inv = 0:
      def ::(expr p,ang) = p{p rotated(-90-ang)} looselink enddef;
      if (taper = 2) or (taper = 3):
        z[nopts]{dir(0-myangle/2)} .. tension 0.8 and 1 .. 
      else:
        ::(z[nopts], pm_angle(nopts+negang))
      fi
      for x=nopts-1 downto 2:
        ::(z[x], pm_angle(x+negang))
      endfor
      if (taper = 1) or (taper = 3):
        z[1]{z[1] rotated(-90+myangle)} .. tension 1 and 0.8 .. {dir -(90+myangle/2)}
      else:
        ::(z[1], pm_angle(1+negang))
      fi
      z0
    else:
      def ::(expr p,ang) = looselink {p rotated (90+ang)}p enddef;
      if (taper = 1) or (taper = 3):
        z0 {dir (90+myangle/2)} .. tension 0.8 and 1 .. z[1]{z[1] rotated(90-myangle)}
      else:
        z0{dir (90+myangle)}
        ::(z[1], pm_angle(1+negang))
      fi
      for x=1 upto nopts-1:
        ::(z[x], pm_angle(x+negang))
      endfor
      if (taper = 2) or (taper = 3):
        .. tension 0.8 and 1 .. {z[nopts] rotated (90+myangle/2)}z[nopts]
      else:
        ::(z[nopts], pm_angle(nopts+negang))
      fi
    fi
  endgroup
enddef;

% next_odd: evaluate to the next odd number greater than or equal to n
def next_odd(expr n) =
  (2*floor(n/2)+1)
enddef;

threechars ("q", "gluon, quadrant 1",
  path_quadloop(2, boson_wiggles_loop_normal, 1, 0, 3) xscaled -1 shifted (0,a),
    next_odd(2boson_wiggles_loop_normal/3),
    0, 2module#, 0, % height is 2module#, not 2module#+a#, so that
                    % they line up OK in \Diagram
    0, "ulft");
threechars ("r", "gluon, quadrant 2",
  path_quadloop(2, boson_wiggles_loop_normal, 0, 0, 3) shifted (0,a),
    next_odd(boson_wiggles_loop_normal/2),
    0, 2module#, 0,
    0, "urt");
threechars ("s", "gluon, quadrant 3",
  path_quadloop(2, boson_wiggles_loop_normal, 0, 1, 3) yscaled -1 shifted (0,a),
    next_odd(boson_wiggles_loop_normal/2),
    0, a#, a#-2module#,
    0, "lrt");
threechars ("t", "gluon, quadrant 4",
  path_quadloop(2, boson_wiggles_loop_normal, 1, 1, 3) scaled -1 shifted (0,a),
    next_odd(2boson_wiggles_loop_normal/3),
    0, a#, a#-2module#,
    0, "llft");
  
% The two loops following have the annotation off-centre, to keep
% it clear of the wiggles.  Would it look better being "top" and "bot"
% again, but with a non-zero offset in the second-last argument?
% These two are vertically squashed so that they take up less than 2
% modules vertically, which means in turn that {gl glu} can sit in a
% two-loop diagram without crashing into the baseline.
threechars ("y",  "gluon half loop",
  ((path_quadloop(2, boson_wiggles_loop_normal, 1, 0, 1) xscaled -1)
    .. path_quadloop(2, boson_wiggles_loop_normal, 0, 0, 1)) yscaled squash shifted (0,a),
  boson_wiggles_loop_normal+1,
  0, 2squash*module#+a#, 0,
  0, "urt");
threechars ("z",  "gluon half loop, inverted",
  ((path_quadloop(2, boson_wiggles_loop_normal, 1, 1, 1) scaled -1)
    .. (path_quadloop(2, boson_wiggles_loop_normal, 0, 1, 1) yscaled -1)) yscaled squash shifted (0,a),
  boson_wiggles_loop_normal+1,
  0, a#, a#-2module#,
  0, "llft");

% Small and large boson half loops are at positions which are not characters.
% That's OK -- they can still be accessed by ligatures.
% 7b='{', 7c='|'
threechars (hex"7B", "large gluon half loop",
  ((path_quadloop(2.66667, boson_wiggles_loop_large, 1, 0, 1) xscaled -1)
    .. path_quadloop(2.66667, boson_wiggles_loop_large, 0, 0, 1)) shifted (0,a),
  1.5boson_wiggles_loop_large,
  0, 2.66667module#+a#, 0,
  0, "urt");
threechars (hex"7C", "small gluon half loop",
  ((path_quadloop(1.3333, boson_wiggles_loop_small, 1, 0, 1) xscaled -1)
    .. path_quadloop(1.3333, boson_wiggles_loop_small, 0, 0, 1)) shifted (0,a),
  1.5boson_wiggles_loop_small,
  0, 1.3333module#+a#, 0,
  0, "llft");

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Ghosts

ghost_points = 2(boson_wiggles + 1); % should be at least 8?
def draw_ghost(expr a, b, apos) =
  begingroup
    % pattern for ghost_points=10: "-_--_--_--_-"
    clearxy;
    z1 = a; z[ghost_points] = b;
    z2-z1 = z[ghost_points]-z[ghost_points-1];
    for i = 2 step 2 until (ghost_points-1):
      z2-z1 = z[i+1]-z[i];
    endfor
    z4-z3 = 2(z2-z1);
    for i = 5 step 2 until (ghost_points-2):
      z4-z3 = z[i+1]-z[i];
    endfor
    pen;
    draw z1--z2; draw z[ghost_points-1]--z[ghost_points];
    for i = 3 step 2 until (ghost_points-2):
      draw z[i]--z[i+1];
    endfor
    annotate_at(0.5[z1,z[ghost_points]], apos);
  endgroup
enddef;
% the following is a simpler version of the above, without the
% ghost_points parameter, to document what it's supposed to be doing
def draw_ghost_orig(expr a, b, apos) =
  begingroup
    clearxy;
    z1 = a;  z10 = b;
    z4-z3 = 2(z2-z1);
    z4-z3 = z6-z5 = z8-z7;
    z2-z1 = z3-z2 = z5-z4 = z7-z6 = z9-z8 = z10-z9;
    pen;
    draw z1..z2; draw z3..z4; draw z5..z6; draw z7..z8; draw z9..z10;
    annotate_at(0.5[z5,z6], apos);
  endgroup
enddef;

beginchar ("h", 2module#, 0, 0); "ghost";
  pen;
  draw_ghost((0,a), (w,a), "top");
endchar;
beginchar (byte "h"-hex"20", 2module#, 0, 0); "r-arrowed ghost";
  pen;
  draw_ghost((0,a), (w,a), "top");
  drawarrow (littlearrow, .5[(0,a), (w,a)], 0);
endchar;
beginchar (byte "h"-hex"60", 2module#, 0, 0); "l-arrowed ghost";
  pen;
  draw_ghost((0,a), (w,a), "top");
  drawarrow (littlearrow, .5[(0,a), (w,a)], 180);
endchar;
beginchar ("i", 2module#*(cosd 45), 2module#*(sind 45), 0); "upward ghost";
  pen;
  draw_ghost((0,a), (w,h+a), "ulft");
endchar;
beginchar (byte"i"-hex"20", 2module#*(cosd 45), 2module#*(sind 45), 0);
  "r-arrowed upward ghost";
  pen;
  draw_ghost((0,a), (w,h+a), "ulft");
  drawarrow (littlearrow, .5[(0,a), (w,h+a)], 45);
endchar;
beginchar (byte"i"-hex"60", 2module#*(cosd 45), 2module#*(sind 45), 0);
  "l-arrowed upward ghost";
  pen;
  draw_ghost((0,a), (w,h+a), "ulft");
  drawarrow (littlearrow, .5[(0,a), (w,h+a)], 45+180);
endchar;
beginchar ("j", 2module#*(cosd 45), 2module#*(sind 45), 0);
  "downward ghost";
  pen;
  draw_ghost((0,h+a), (w,a), "urt");
endchar;
beginchar (byte"j"-hex"20", 2module#*(cosd 45), 2module#*(sind 45), 0);
  "r-arrowed downward ghost";
  pen;
  draw_ghost((0,h+a), (w,a), "urt");
  drawarrow (littlearrow, .5[(0,a), (w,h+a)], -45);
endchar;
beginchar (byte"j"-hex"60", 2module#*(cosd 45), 2module#*(sind 45), 0);
  "l-arrowed downward ghost";
  pen;
  draw_ghost((0,h+a), (w,a), "urt");
  drawarrow (littlearrow, .5[(0,a), (w,h+a)], -45+180);
endchar;

% ghost loops
begingroup
  clearxy; clearit;             % clear current picture
  picture ghostloop;
  pair refpt, arrowpoint;
  refpt := (-2module, 0);
  for i=0 upto 23:
    z[i] = refpt rotated -(i/24*180) yscaled squash shifted (0,a);
  endfor
  arrowpoint := z[12];
  transform below;
  below := identity rotatedaround ((0,a), 180);
  pen;
  for i=0 step 2 until 22:
    draw z[i]--z[i+1];
  endfor
  ghostloop := currentpicture; clearit;
  beginchar (hex"7E", 0, 2squash*module#+a#, 0); "ghost loop";
    addto currentpicture also ghostloop;
    annotate_at(arrowpoint, "top");
  endchar;
  beginchar (hex"7E"-hex"20", 0, 2squash*module#+a#, 0); "r-arrowed ghost loop";
    addto currentpicture also ghostloop;
    drawarrow(littlearrow, arrowpoint, 0);
    annotate_at(arrowpoint, "top");
  endchar;
  beginchar (hex"7E"-hex"60", 0, 2squash*module#+a#, 0); "l-arrowed ghost loop";
    addto currentpicture also ghostloop;
    drawarrow(littlearrow, arrowpoint, 180);
    annotate_at(arrowpoint, "top");
  endchar;
  beginchar (hex"7F", 0, a#, 0); "ghost loop, inverted";
    addto currentpicture also ghostloop transformed below;
    annotate_at(arrowpoint transformed below, "top");
  endchar;
  beginchar (hex"7F"-hex"20", 0, a#, 0); "r-arrowed ghost loop, inverted";
    addto currentpicture also ghostloop transformed below;
    drawarrow(littlearrow, arrowpoint transformed below, 0);
    annotate_at(arrowpoint transformed below, "top");
  endchar;
  beginchar (hex"7F"-hex"60", 0, a#, 0); "l-arrowed ghost loop, inverted";
    addto currentpicture also ghostloop transformed below;
    drawarrow(littlearrow, arrowpoint transformed below, 180);
    annotate_at(arrowpoint transformed below, "top");
  endchar;
endgroup;

beginchar (hex"22", module#, 0, 0);			"short ghost";
  pen;
  z1 = (0,a);  z6 = (w,a);
  z4-z3 = 2(z2-z1);
  z2-z1 = z3-z2 = 1/2(z4-z3) = z5-z4 = z6-z5;
  draw z1..z2; draw z3..z4; draw z5..z6;
  annotate_at(0.5[z3,z4], "top")
endchar;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Odds and sods

beginchar (hex"60", 2module#, 0, 0);
  "spacer";
endchar;

beginchar (hex"40", module#, 0, 0);
  "short spacer";
endchar;

beginchar ("c", 2blobr#, blobr# + a#, blobr#);	"complete vertex";
  pen;
  draw (0,a) .. (w,a) .. cycle;
  annotate_at((w/2,w/2+a), "top");
endchar;

%beginchar ("d", module#/2, 0, 0);		"weeny fermion";
%  pen;
%  draw (0,a)..(w,a);
%endchar;
%
%beginchar ("k", module#/2, 0, 0);		"weeny massive fermion";
%  pen;
%  y1 - a = y2 - a = a - y3 = a - y4 = module#/3.5;
%  x1 = x3 = 0;
%  x2 = x4 = w;
%  draw z1--z2;
%  draw z3--z4;
%endchar;
%
%beginchar ("l", module#, 0, 0);			"short massive fermion";
%  pen;
%  y1 - a = y2 - a = a - y3 = a - y4 = module#/3.5;
%  x1 = x3 = 0;
%  x2 = x4 = w;
%  draw z1--z2;
%  draw z3--z4;
%endchar;

%beginchar ("n", 4module#, 2module#-a#, 2module#-a#);
%  pen;						"fermion loop";
%  z0 = (0,a); z1 = (w,a);
%  draw z0{dir  phangle} ..tension 1.15.. {dir -phangle}z1;
%  draw z0{dir -phangle} ..tension 1.15.. {dir  phangle}z1;
%endchar;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Other symbols

garrow("a", 0, 1);
garrow(hex"03", 180, 1);

beginchar ("p", 2blobr#, blobr# + a#, blobr# - a#);
  pen;						"proper vertex";
  picture p[];
  pair t[];
  fill (-blobr, 0) .. (blobr, 0) .. cycle;
  p1 := currentpicture; clearit;
  draw (-blobr, 0) .. (blobr, 0) .. cycle;
  p2 := currentpicture; clearit;
  t1 = 5/6[origin, (0,blobr)] shifted (-blobr, 0);
  t7 = 5/6[origin, (0,blobr)] shifted (+blobr, 0);
  forsuffixes s = 2,3,4,5,6 :
    t[s]   = t[s-1] shifted (0, -blobr/3);
    t[s+6] = t[s+5] shifted (0, -blobr/3);
  endfor
  forsuffixes s = 1,2,3,4,5,6,7,8,9,10,11,12 :
    z[s] = t[s] rotated 45;
  endfor
  forsuffixes s = 1,2,3,4,5,6 :
    draw z[s] -- z[s+6]; 
  endfor
  addto currentpicture also p1;
  cull currentpicture keeping (2,2);  % & the two pictures
  addto currentpicture also p2;
  currentpicture := currentpicture shifted (blobr,a);
  labels (range 1 thru 12);
  annotate_at((blobr,blobr+a), "top");
endchar;

beginchar ("P", 2blobr#, blobr#+a#, blobr#-a#); % see complete vertex "c"
  pen;                                         "proper vertex 2";
  fill (0,a) .. (w,a) .. cycle;% withcolor black;
  annotate_at((w/2,w/2+a), "top");
endchar;

beginchar ("x", 0, a#, -a#); "counterterm";
  pen;
  -x1 = -x2 = x3 = x4;
  y1 = -y2 = y3 = -y4;
  z3 = (2blobr/3, 0) rotated 45;
  draw z1 .. z4;
  draw z2 .. z3;
  currentpicture := currentpicture shifted (0,a);
  annotate_at(0.5[z1,z3] shifted (0,a), "top");
endchar;

beginchar (hex"20", module#, a#, 0);		"space block";
  pen;
  message "spacer: width=" & decimal w & ", height=" & decimal h;
  draw origin--(w,h);
  draw (0,h)--(w,0);
endchar;


% Now generate an errorchar() in each of the code positions we've skipped
for n = 0 upto hex"7F":
  if not known(donechar[n]):
    beginchar (n, 0, module#, 0); errorchar(h); endchar;
  fi
endfor


%   Construct the ligature tables.
ligtable "a" : % arrow
  "A" =: "a",     % right-arrow, for symmetry
  "V" =: hex"03"; % left-arrow

ligtable "f" :	% fermion
"A" =: "F",	% right-arrowed
"V" =: hex"06",	% left-arrowed
"u" =: "e",	% upward
"d" =: "d",	% downward
"v" =: "b",	% vertical
"s" =: hex"21",	% short
"l" =: "l",     % loop
"0" =: hex"60";	% spacer

ligtable "e" :	% upward fermion, fe
"A" =: "E",	% arrowed
"V" =: hex"05";
  
ligtable "d" :	% downward fermion, fd
"A" =: "D",
"V" =: hex"04";
  
ligtable "b" :	% vertical fermion, fv
"A" =: "B",
"V" =: hex"02";

ligtable hex"21" :	% short fermion
"0" =: hex"40";	% short spacer

ligtable "k" :  % fermion closed loop
"A" =: "K",   % arrowed
"V" =: hex"0b";

ligtable "l" :  % fermion loop
"u" =: "n",     % upside down
"o" =: "k",     % closed loop (for scalar theory)
"S" =: "o",     % small
"A" =: "L",
"V" =: hex"0C";

ligtable "g" :	% gluon
"A" =: "G",
"V" =: hex"07",
"u" =: "u",
"d" =: "v",
"v" =: oct"175",
"l" =: "y",	% gluon half-loop
"1" =: "q",	% gluon quarter-loop, 1st quadrant (upper-left)
"2" =: "r",	% 2nd
"3" =: "s",	% 3rd
"4" =: "t";	% 4th

ligtable "m" :	% massive fermion
"A" =: "M",
"V" =: hex"0D",
"s" =: hex"23";

ligtable "n" :  % inverted fermion
"A" =: "N",
"V" =: hex"0E";

ligtable "o" :  % fermion loop small
"u" =: "w",     % upside down
"A" =: "O",
"V" =: hex"0F";

ligtable "q" :	% gluon, 1st quadrant
"A" =: "Q",
"V" =: hex"11";

ligtable "r" :	% gluon, 2nd quadrant
"A" =: "R",
"V" =: hex"12";

ligtable "s" :	% gluon, 3rd quadrant
"A" =: "S",
"V" =: hex"13";

ligtable "t" :	% gluon, 4th quadrant
"A" =: "T",
"V" =: hex"14";

ligtable "u" :	% upward gluon
"A" =: "U",
"V" =: hex"15";

ligtable "v" :	% downward gluon
"A" =: "V",
"V" =: hex"16";

ligtable "w" : % fermion loop, small, upside-down
"A" =: "W",
"V" =: oct"027";

ligtable oct"175" :	% vertical gluon
"A" =: oct"135",
"V" =: oct"035";

ligtable "y" :	% gluon half-loop
"A" =: "Y",
"V" =: hex"19",
"B" =: hex"7B", % large
"S" =: hex"7C", % small
"u" =: "z";	% ...upside down

ligtable hex"7B" : % large gluon half loop
"A" =: hex"5B",
"V" =: hex"1B";

ligtable hex"7C" : % small gluon half loop
"A" =: hex"5C",
"V" =: hex"1C";

ligtable "z" :	% upside-down gluon loop
"A" =: "Z",
"V" =: hex"1A";

ligtable "h" :	% ghost
"A" =: "H",
"V" =: hex"08",
"u" =: "i",	% upward
"d" =: "j",	% downward
"s" =: hex"22",	% short
"l" =: hex"7E"; % ghost loop

ligtable hex"7E" : % ghost loop
"A" =: hex"5E",    % r-arrowed
"V" =: hex"1E",    % l-arrowed
"u" =: hex"7F";    % upside down

ligtable hex"7F" : % ghost loop inverted
"A" =: hex"5F",    % r-arrowed
"V" =: hex"1F";    % l-arrowed

ligtable "i" :	% upward ghost
"A" =: "I",
"V" =: hex"09";

ligtable "j" :	% downward ghost
"A" =: "J",
"V" =: hex"0A";
