%
% Copyright (c) 2012, Michael Ummels <michael.ummels@rwth-aachen.de>
%
% This Font Software is licensed under the SIL Open Font License,
% Version 1.1. This license is in the accompanying file OFL.txt, and
% is also available with a FAQ at: http://scripts.sil.org/OFL
%

design_size := 10;
font_size design_size * pt#;

if known ps_output:
  font_version := "1.008";
  font_comment := "Copyright (c) 2012, Michael Ummels. This Font Software is licensed under the SIL Open Font License, Version 1.1.";
fi

u# := 0.6pt#;
asc_height# := 7.54pt#; % 8.56pt#;
cap_height# := 7.07pt#; %7.37pt#;
desc_depth# := 2.2pt#; % 2.94pt#;
x_height# := 5.46pt#;
math_axis# := 2.75pt#;
if weight_index = 0: % Book
  line_thickness# := 0.64pt#;
  rule_thickness# := 0.56pt#;
  dot_size# := 0.75pt#;
elseif weight_index = 1: % Regular
  line_thickness# := 0.74pt#;
  rule_thickness# := 0.58pt#;
  dot_size# := 0.84pt#;
elseif weight_index = 2: % Medium
  line_thickness# := 0.86pt#;
  rule_thickness# := 0.6pt#;
  dot_size# := 0.94pt#;
else: % Bold
  line_thickness# := 1.0pt#;
  rule_thickness# := 0.64pt#;
  dot_size# := 1.06pt#;
fi;

side_bearing# := 1.5u#;
small_op_size# := 8u#; % radius of small operators
med_op_size# := 12.5u#; % radius of medium operators
plus_size# := 9u#;
large_op_size# := 18u#; % radius of large operators
order_width# := 8u#; % width of equal sign
turnstile_width# := 11u#; % width of turnstile symbols
equal_spread# := .7math_axis#; % distance between the lines of the equal sign
greater_spread# := 10/4equal_spread#; % distance between the ends of the greater sign
arrow_horiz_len# := 12.5u#; % length of horizontal arrows
arrow_vert_len# := 12.5u#; % length of vertical arrows
arrow_diag_len# := 1/2(arrow_horiz_len# + arrow_vert_len#);
arrow_spread# := 1.6equal_spread#;
delim_height# := 4.9pt#; % half the height of normal delimiters
bigop_height# := 10.7pt#; % height of big operators

mode_setup;

define_pixels(u, asc_height, cap_height, desc_depth, delim_height, bigop_height, x_height);
define_whole_pixels(dot_size, small_op_size, med_op_size, large_op_size, plus_size,
  order_width, turnstile_width, equal_spread, greater_spread,
  arrow_horiz_len, arrow_vert_len, arrow_diag_len, arrow_spread);

if known ps_output:
  define_pixels(math_axis, line_thickness, rule_thickness, side_bearing);
else:
  math_axis      := good.y(math_axis# * hppp);
  line_thickness := ceiling(line_thickness# * hppp);
  rule_thickness := ceiling(rule_thickness# * hppp);
  side_bearing   := ceiling(side_bearing# * hppp);
fi

stroke_through_thickness := 9/10line_thickness;

% Macros

% Redefine clockwise and counterclockwise (turningnumber seems more stable)
if known ps_output:
  vardef counterclockwise primary p =
    (if turningnumber p>0: p else: (reverse p) fi)
  enddef;

  vardef clockwise primary p =
    (if turningnumber p<0: p else: (reverse p) fi)
  enddef;
fi

% Selects the n-th element of a list
def select(expr n)(text values) =
  begingroup;
    i := 0;
    for v = values:
      result := v;
      exitif i = n;
      i := i + 1;
    endfor;
    result
  endgroup
enddef;

% Splits a length at the math axis
def vcentre(expr size) =
  size/2 + math_axis#, size/2 - math_axis#
enddef;

current_char := -1;

def beginsymbol(expr width, height, depth) =
  current_char := current_char + 1;
  beginchar(current_char, width, height, depth);
    if not known ps_output:
      proofrule((side_bearing, math_axis),(w - side_bearing, math_axis));
      proofrule((side_bearing, h),(side_bearing, -d));
      proofrule((w - side_bearing, h),(w - side_bearing,  -d));
    fi
enddef;

def beginoperator(expr size, ratio) =
  beginsymbol(size + 2side_bearing#, vcentre(ratio * size));
    pair centre;
    centre := (w/2, (h-d)/2);
    radius := w/2 - side_bearing - 1/2line_thickness;
enddef;

def beginbigop(expr xscale, yscale) =
  beginsymbol(xscale * 3/2order_width# + 2side_bearing#, vcentre(yscale * bigop_height#));
    pair centre;
    centre := (w/2, (h-d)/2);
    op_width  := xscale * 3/2order_width;
    op_height := yscale * bigop_height;
enddef;

def beginsquarebigop(expr xscale, yscale) =
  beginsymbol(xscale * bigop_height# + 2side_bearing#, vcentre(yscale * bigop_height#));
    pair centre;
    centre := (w/2, (h-d)/2);
    op_width  := xscale * bigop_height;
    op_height := yscale * bigop_height;
enddef;

def beginarrow(expr angle, scale, spread) =
  arrow_len# := scale *
    if     angle mod 180 =  0: arrow_horiz_len#
    elseif angle mod 180 = 90: arrow_vert_len#
    else:                      arrow_diag_len#
    fi;
  arrow_len := scale *
    if     angle mod 180 =  0: arrow_horiz_len
    elseif angle mod 180 = 90: arrow_vert_len
    else:                      arrow_diag_len
    fi;

  beginsymbol(arrow_len# * abs(cosd(angle)) + (spread + line_thickness#) * abs(sind(angle)) + 2side_bearing#, vcentre(arrow_len# * abs(sind(angle)) + (spread + line_thickness#) * abs(cosd(angle))));
    pair centre, head, head_ex, foot, foot_ex;

    centre := (w/2, (h-d)/2);
    head := centre + (arrow_len - line_thickness)/2 * dir angle;
    head_ex := centre + arrow_len/2 * dir angle;
    foot := centre - (arrow_len - line_thickness)/2 * dir angle;
    foot_ex := centre - arrow_len/2 * dir angle;
enddef;

def beginorder(expr sign, width, spread) =
  beginsymbol(width + 2side_bearing#, vcentre(spread + line_thickness#));
    pair centre, left_ex, right_ex, left_point, right_point;
    centre := (w/2, (h-d)/2);
    left_ex := centre - sign * (w/2 - side_bearing) * right;
    left_point := centre - sign * (w/2 - side_bearing - line_thickness/2) * right;
    right_ex := centre + sign * (w/2 - side_bearing) * right;
    right_point := centre + sign * (w/2 - side_bearing - line_thickness/2) * right;
enddef;

def beginturnstile(expr angle, scale) =
  beginsymbol(abs(sind(angle) + scale * cosd(angle)) * turnstile_width# + 2side_bearing#, abs(min(scale, 1 + (scale - 1)/2) * sind(angle) + cosd(angle)) * cap_height#, abs(max(0, (scale - 1)/2) * sind(angle)) * cap_height#);
    pair foot;

    if angle mod 180 = 0:
      len := scale * turnstile_width;
      spread := cap_height - line_thickness;
    else:
      len := scale * cap_height;
      spread := turnstile_width - line_thickness;;
    fi
    foot = (w/2, (h - d)/2) - (len - line_thickness)/2 * dir angle;
enddef;

% Strokes a pen path
vardef stroke text t =
  forsuffixes e = l, r:
    path_.e := t;
  endfor
  path_.r -- reverse path_.l -- cycle
enddef;

% Shapes

def circle(expr centre, radius) =
  (centre + radius * right){up} ...
  (centre + radius * dir 45){dir 135} ...
  (centre + radius * up){left} ...
  (centre + radius * dir 135){dir 225} ...
  (centre + radius * left){down} ...
  (centre + radius * dir 225){dir 315} ...
  (centre + radius * down){right} ...
  (centre + radius * dir 315){dir 45} ...
  cycle
enddef;

def square(expr centre, radius, angle) =
  (centre + sqrt(2) * radius * dir (angle + 45)) --
  (centre + sqrt(2) * radius * dir (angle + 135)) --
  (centre + sqrt(2) * radius * dir (angle + 225)) --
  (centre + sqrt(2) * radius * dir (angle + 315)) --
  cycle
enddef;

def triangle(expr centre, radius, angle) =
  (centre + radius * dir angle) --
  (centre + radius * dir (angle + 120)) --
  (centre + radius * dir (angle + 240)) --
  cycle
enddef;

def reg_poly_points(suffix $)(expr n, centre, radius, angle) =
  for i = 0 upto n-1:
    z$[i] = centre + radius * dir (angle + i/n * 360);
  endfor;
enddef;

def dot(expr centre, radius) =
  superellipse(centre + radius * right, centre + radius * up,
    centre - radius * right, centre - radius * up, 0.6)
enddef;

% Draw macros

def draw_straight(expr orig, dest, thick, extend) =
  begingroup;
    pair p[].l, p[].r;

    theta := angle (dest - orig);
    if extend:
      1/2[p1.l,p1.r] = orig - 1/2thick * dir theta;
      1/2[p2.l,p2.r] = dest + 1/2thick * dir theta;
    else:
      1/2[p1.l,p1.r] = orig;
      1/2[p2.l,p2.r] = dest;
    fi
    p1.l - p1.r = p2.l - p2.r = thick * dir (theta + 90);
    fill stroke p1.e -- p2.e;
  endgroup;
enddef;

def draw_line(expr orig, dest, extend) =
  draw_straight(orig, dest, line_thickness, extend);
enddef;

def draw_circle(expr centre, radius, thick) =
  fill circle(centre, radius + 1/2thick);
  unfill circle(centre, radius - 1/2thick);
enddef;

def filldraw_circle(expr centre, radius, thick) =
  fill circle(centre, radius + 1/2thick);
enddef;

def draw_square(expr centre, radius, angle, thick) =
  fill square(centre, radius + 1/2thick, angle);
  unfill square(centre, radius - 1/2thick, angle);
enddef;

def filldraw_square(expr centre, radius, angle, thick) =
  fill square(centre, radius + 1/2thick, angle);
enddef;

def draw_triangle(suffix $)(expr centre, radius, angle, thick) =
  fill triangle(centre, radius + thick, angle);
  unfill triangle(centre, radius - thick, angle);
enddef;

def filldraw_triangle(suffix $)(expr centre, radius, angle, thick) =
  fill triangle(centre, radius + thick, angle);
enddef;

def draw_sim(suffix $)(expr lc, rc, spread, thick) =
  theta := angle (length(rc - lc), 10spread);
  signum := cosd (angle (rc - lc)) + sind (angle (lc - rc));

  z0$.l = lc;
  z4$.r = rc;
  z2$ = 1/2[lc, rc];
  z4$.r = rc;
  1/2[z1$,z3$] = z2$;
  z1$ = 1/4[lc, rc] + 1/6thick * dir (angle (rc - lc)) +
    signum * spread * dir (angle (rc - lc) + 90);

  penpos0$(5/6thick, angle(rc - lc) - signum * (90 - theta));
  penpos1$(thick, angle(rc - lc) - signum * 90);
  penpos2$(thick, angle(rc - lc) - signum * (theta + 90 - 5));
  penpos3$(thick, angle(rc - lc) - signum * 90);
  penpos4$(5/6thick, angle(rc - lc) - signum * (90 - theta));

  fill stroke z0$.e{dir (angle(rc - lc) + signum * theta)} .. {dir angle(rc - lc)}z1$.e .. {dir (angle(rc - lc) - signum * (theta - 5))}z2$.e .. {dir angle(rc - lc)}z3$.e .. {dir (angle(rc - lc) + signum * theta)}z4$.e;

  penlabels(0$,1$,3$,4$);  
enddef;

def draw_bump(suffix $)(expr sign, lc, rc, rad, thick) =
  z0$ = lc;
  z1$ = rc;
  z2$ = 1/2[lc, rc] + sign * rad * dir (angle (rc - lc) + 90);
  z3$ = 1/2[lc, rc] - rad * dir (angle (rc - lc));
  1/2[z3$,z4$] = 1/2[lc, rc];

  penpos0$(thick, angle (rc - lc) + sign * 90);
  penpos1$(thick, angle (rc - lc) + sign * 90);
  penpos2$(thick, angle (rc - lc) + sign * 90);
  penpos3$(thick, angle (rc - lc));
  penpos4$(thick, angle (rc - lc));

  z5$ = z3$.r;
  z6$ = z4$.l;

  penpos5$(thick, angle (rc - lc) + sign * 90);
  penpos6$(thick, angle (rc - lc) + sign * 90);

  path p$, q$;
  numeric s$, t$;

  p$ = z3$.l{dir (angle(rc - lc) + sign * 90)} .. {rc - lc}z2$.r;
  q$ = z2$.r{rc - lc} .. {dir (angle(rc - lc) - sign * 90)}z4$.r;
  s$ = xpart (p$ intersectiontimes (z0$.r -- z1$.r));
  t$ = xpart (q$ intersectiontimes (z0$.r -- z1$.r));

  fill z0$.r -- point s$ of p$ & subpath (s$,1) of p$ & subpath (0,t$) of q$ & point t$ of q$ -- z1$.r -- z1$.l -- z6$l. -- z6${dir (angle (rc - lc) + sign * 90)} .. z2$.l{lc - rc} .. {dir (angle (rc - lc) - sign * 90)}z5$ -- z5$.l -- z0$.l -- cycle;

  penlabels(0$,1$,2$,3$,4$,5$,6$);
enddef;

def draw_less(suffix $)(expr lc, rc, spread, thick, closed) =
  theta := angle((length(rc - lc) - thick/2) * right + spread/2 * up);

  z2$ = lc + 1/2thick * dir (angle (rc - lc));
  1/2[z0$.r,z1$.r] = rc;
  z0$ = z2$ + whatever * dir (angle (rc - lc) + theta);
  z1$ = z2$ + whatever * dir (angle (rc - lc) - theta);

  penpos0$(thick, angle(rc - lc) - 90 + theta);
  penpos1$(thick, angle(rc - lc) + 90 - theta);
  penpos3$(thick, angle(rc - lc) - 90 + theta);
  penpos4$(thick, angle(rc - lc) + 90 - theta);

  z3$.l = z0$.l + whatever * (z2$ - z0$);
  z4$.l = z1$.l + whatever * (z2$ - z1$);
  1/2[z3$.l,z4$.l] = lc;
  z5$ = z0$.r + whatever * (z2$ - z0$);
  z5$ = z1$.r + whatever * (z2$ - z1$);

  fill z0$.l -- z3$.l -- z4$.l -- z1$.l -- z1$.r -- z5$ -- z0$.r -- cycle;

  if closed:
    penpos6$(thick, angle(rc - lc));
    penpos7$(thick, angle(rc - lc));
    z6$.l = whatever[z0$.l,z3$.l];
    z6$.r = whatever[z0$.r,z1$.r];
    z7$.l = whatever[z1$.l,z4$.l];
    z7$.r = whatever[z0$.r,z1$.r];
    fill z0$.l -- z6$.l -- z7$.l -- z1$.l -- z7$.r -- z6$.r -- cycle;
  fi;

  penlabels(0$,1$,3$,4$,5$,6$,7$);
enddef;

def draw_prec(suffix $)(expr lc, rc, spread, thick, closed) =
  theta := 43;

  z0$ - z1$ = spread * dir  (angle (rc - lc) + 90);
  1/2[z0$.r,z1$.l] = rc;
  z2$ = lc;
  z2$' = lc + 1/2thick * dir angle(rc - lc);

  penpos0$(thick, angle(rc - lc) - theta);
  penpos1$(thick, angle(rc - lc) + 180 + theta);
  penpos2$(thick, angle(rc - lc) - 90);
  penpos2$'(thick, angle(rc - lc) - 90);

  fill stroke z2$.e -- z2$'.e{dir angle(rc - lc)} .. {dir (angle (rc - lc) + 90 - theta)}z0$.e;
  fill stroke z2$.e -- z2$'.e{dir angle(rc - lc)} .. {dir (angle (rc - lc) - 90 + theta)}z1$.e;

  if closed:
    z3$ = point 1/2 of (z0${dir (angle (rc - lc) - 90 - theta + 10)}
      .. {dir (angle (rc - lc) - 90 + theta - 10)}z1$);
    penpos3$(thick, angle(rc - lc));

    fill z0$.l .. z3$.l .. z1$.r -- z1$.l .. z3$.r .. z0$.r -- cycle;
  fi;

  penlabels(0$,1$,2$,3$);
enddef;

def draw_subset(suffix $)(expr lc, rc, spread, thick) =
  1/2[z0$,z1$] = rc;
  1/2[z2$,z3$] = (4spread / 9abs(rc - lc))[z4$, rc];
  z0$ - z1$ = z2$ - z3$ = spread * dir (angle (rc - lc) + 90);
  z4$ = lc + 1/2thick * dir (angle (rc - lc));

  penpos0$(thick, angle(rc - lc) - 90);
  penpos1$(thick, angle(rc - lc) + 90);
  penpos2$(thick, angle(rc - lc) - 90);
  penpos3$(thick, angle(rc - lc) + 90);
  penpos4$(thick, angle(rc - lc));

  fill stroke z0$.e -- z2$.e{lc - rc} .. z4$.e .. {rc - lc}z3$.e -- z1$.e;

  penlabels(0$,1$,2$,3$,4$)
enddef;

def draw_smile(suffix $)(expr sign, lc, rc, spread, thick, round) =
  z0$ = lc + sign * 1/2spread * dir (angle(rc - lc) + 90) +
    whatever * (rc - lc);
  z0$.l = lc +  whatever *  dir (angle(rc - lc) + 90);
  z1$ = rc + sign * 1/2spread * dir (angle(rc - lc) + 90) +
     whatever * (rc - lc);
  z1$.l = rc + whatever *  dir (angle(rc - lc) + 90);
  z2$ = 1/2[lc,rc] - sign * 1/2spread * dir (angle(rc - lc) + 90);

  if round:
    theta := angle (length(lc - rc), 5spread);
  else:
    theta := angle (length(lc - rc), 2spread);
  fi;

  penpos0$(thick, angle(rc - lc) + sign * (90 - theta));
  penpos1$(thick, angle(rc - lc) + sign * (90 + theta));

  if round:
    penpos2$(thick, angle(rc - lc) + sign * 90);

    fill stroke z0$.e{dir (angle(rc - lc) - sign * theta)} ..
      {rc - lc}z2$.e{rc - lc} .. {dir (angle(rc - lc) + sign * theta)}z1$.e;
  else:
    penpos2$(thick / cosd theta, angle(rc - lc) + sign * 90);

    fill stroke z0$.e -- z2$.e -- z1$.e;
  fi;

  penlabels(0$, 1$, 2$);
enddef;

def stroke_through_angle(expr pos, spread, angle) =
  begingroup;
    stroke_len := 1/2spread / cosd (90 - angle);

    draw_straight(pos + stroke_len * dir angle, pos - stroke_len * dir angle, stroke_through_thickness, true);
  endgroup;
enddef;

def stroke_through(expr pos, spread) =
  stroke_through_angle(pos, spread, 75);
enddef;

def stroke_through_arrow(expr pos, alpha, spread)(text angles) =
  begingroup;
    stroke_dir := alpha + select(alpha / 45)(angles);
    stroke_len := 1/2spread / sind (stroke_dir - alpha);

    draw_straight(pos + stroke_len * dir stroke_dir, pos - stroke_len * dir stroke_dir, stroke_through_thickness, true);
  endgroup;
enddef;

def draw_product(expr centre, width, height, sign, thick, serifs) =
  if serifs:
    thicker := 11/8thick;
    thinner := 5/8thick;
  else:
    thicker := 4/3thick;
    thinner := thick;
  fi

  z1r - z0r = z3r - z2r = width * right;
  y2r - y0l = sign * height;
  x2r = x0r;
  1/2[1/2[z0l,z1l], 1/2[z2r,z3r]] = centre;
  z4 - z0 = z1 - z5 = min(3thicker, 2/5width) * right;
  x6 = x8 = 1/2[x0,x4];
  x7 = x9 = 1/2[x1,x5];
  if serifs:
    y6 - y0 = y7 - y1 = sign * 1/4(x4 - x0);
    y2 - y8 = y3 - y9 = sign * 1/4(x4 - x0);
  else:
    y6 = y7 = y0l;
    y8 = y9 = y2l;
  fi

  penpos0(thinner, sign * 100);
  penpos1(thinner, sign * 80);
  if serifs:
    penpos2(thinner, sign * 93);
    penpos3(thinner, sign * 87);
  else:
    penpos2(thicker, sign * 90);
    penpos3(thicker, sign * 90);
  fi
  penpos4(thinner, sign * 80);
  penpos5(thinner, sign * 100);
  penpos6(thicker, 0);
  penpos7(thicker, 0);
  penpos8(thicker, 0);
  penpos9(thicker, 0);

  y10 = y11 = y2r - sign * 1/2[thinner,thicker];
  x10 = x6r;
  x11 = x7l;

  if serifs:
    fill z0l -- z4l -- z4r{dir (sign * 165)} ... {sign * up}z6r -- z10 -- z11 -- z7l{sign * down} ... {dir (-sign * 165)}z5r -- z5l -- z1l -- z1r{dir (sign * 165)} ... {sign * up}z7r -- z9r{sign * up} ... {dir (sign * 15)}z3l -- z3r -- z2r -- z2l{dir (-sign * 15)} ... {sign * down}z8l -- z6l{sign * down} ... {dir (-sign * 165)}z0r -- cycle;
    penlabels(0,1,2,3,4,5,6,7,8,9,10,11);
  else:
    fill z6l -- z8l -- z2l -- z2r -- z3r -- z3l -- z9r -- z7r -- z7l -- z9l -- z8r -- z6r -- cycle;
    penlabels(2,3,6,7,8,9);
  fi
enddef;

def draw_sum(suffix $)(expr centre, width, height, thick, serifs) =
  thicker := 11/8thick;
  thinner := 1/2thick;
  alpha := angle(width, height - thicker);

  z1$ - z0$ = z3$ - z2$ = width * right;
  z2$ - z0$ = height * up;
  1/2[1/2[z0$,z1$], 1/2[z2$,z3$]] = centre;
  z4$ - z1$ = z3$ - z5$.l = 3/2thicker * up;
  if serifs:
    z6$ = whatever[z0$,z1$] + thicker/2 * up = z4$ - whatever * dir 77;
    z3$ - z7$ = 2/3thicker * up;
  else:
    z6$l = z1$;
    z3$ - z7$ = thicker * up;
  fi
  z8$r = z2$ + whatever * right;
  z8$l = z2$ + whatever * down;
  z10$r = z0$ + whatever * up;
  z10$l = z0$ + whatever * right;
  z9$' = 1/4[z7$,z8$l];
  z11$' = 1/4[z6$r,z10$r];
  z12$ = centre;

  if serifs:
    penpos4$(thinner, 167);
    penpos5$(thinner, 180);
    penpos6$(thicker, 90);
    penpos8$(5/6thicker, 77);
    penpos10$(3/4thicker, 103);
    penpos12$(thicker / sind alpha, 10);
  else:
    penpos6$(thicker, 90);
    penpos8$(thicker, 90);
    penpos10$(thicker, 90);
    penpos12$(thicker / sind alpha, 0);
  fi

  z9$ = z12$r + whatever * (z8$l - z12$l) = z7$ + whatever * right;
  z11$ = z12$r + whatever * (z10$r - z12$l);
  y11$ = y10$r;

  if serifs:
    fill z10$l -- z6$l -- z4$l -- z4$r{-dir 77} ... {z11$ - z11$'}z11$' -- z11$ -- z12$r -- z9$ -- z9$'{z9$' - z9$} ... {-dir 113}z5$r -- z5$l -- z3$ -- z8$r -- z8$l -- z12$l -- z10$r -- cycle;
    penlabels(3$,4$,5$,6$,7$,8$,9$,10$,11$,12$);
  else:
    fill z10$l -- z6$l -- z6$r -- z11$ -- z12$r -- z9$ -- z7$ -- z3$ -- z8$r -- z8$l -- z12$l -- z10$r -- cycle;
    penlabels(3$,6$,7$,8$,9$,10$,11$,12$);
  fi
enddef;

def draw_integral(suffix $)(expr scale, centre, thick) =
  thicker := 4/3thick;

  penpos0$(thicker, 0);
  penpos1$(thicker, 0);
  penpos2$(9/8thick, -105);
  penpos3$(thicker, 0);
  penpos4$(thick, -90);

  z0$ = 1/2[z1$,z3$] = 1/2[z2$,z4$];
  z1$ - z3$ = whatever * up;
  z2$ - z4$ = whatever * dir 75;

  x0$ = xpart centre;
  y2$l = h;
  y6$r = -d;
  y1$ = 2/3[y0$,y2$];

  penpos5$(9/8thick,-105);
  penpos6$(9/8thick,-82);

  y5$l = y2$l - 1/12thick;
  x5$r = 5/4[x1$, x2$];
  y6$l = y4$l;
  x6$r = 5/4[x3$, x4$];

  ucorr := max (x2$r, x1$r + 3/8thick) - x2$r;
  x2$ := x2$ + ucorr;
  x2$l := x2$l + ucorr;
  x2$r := x2$r + ucorr;
  x5$ := x5$ + ucorr;
  x5$r := x5$r + ucorr;
  x5$l := x5$l + ucorr;

  lcorr := min (x4$l, x1$l - 3/8thick) - x4$l;
  x4$ := x4$ + lcorr;
  x4$l := x4$l + lcorr;
  x4$r := x4$r + lcorr;
  x6$ := x6$ + lcorr;
  x6$r := x6$r + lcorr;
  x6$l := x6$l + lcorr;

  fill z5$l .. z2$l ... {down}z1$l -- z3$l{down} ... z4$l{left} .. z6$l -- z6$r
    .. {up}z3$r -- z1$r{up} .. z2$r{right} .. z5$r -- cycle;

  penlabels(0$,1$,2$,3$,4$,5$,6$);
enddef;

def draw_arrowhead_left(expr pos, angle, spread, thick) =
  begingroup;
    pair p[], p[].l, p[].r;

    p1 = pos;
    p2 = pos + sqrt(2) * (spread + 1/2thick)/2 * dir (angle + 135);
    1/2[p1.l, p1.r] = p1;
    1/2[p2.l, p2.r] = p2;
    p1.r - p1 = thick/(2 * sind 45) * dir angle;
    p2.r - p2 = thick/2 * dir (angle + 45);
    p3.l = whatever[p2.l,p1.l];
    p3.l = pos + 1/2thick * dir (angle - 90) + whatever * dir angle;
    p3.r - p1.r = whatever * dir (angle - 105);
    p3.r = pos + 1/2thick * dir (angle - 90) + whatever * dir angle;
    fill p1.r -- p2.r -- p2.l -- p3.l -- p3.r -- cycle;
  endgroup;
enddef;

def draw_arrowhead_right(expr pos, angle, spread, thick) =
  begingroup;
    pair p[], p[].l, p[].r;

    p1 = pos;
    p2 = pos + sqrt(2) * (spread + 1/2thick)/2 * dir (angle - 135);
    1/2[p1.l, p1.r] = p1;
    1/2[p2.l, p2.r] = p2;
    p1.r - p1 = thick/(2 * sind 45) * dir angle;
    p2.r - p2 = thick/2 * dir (angle - 45);
    p3.l = whatever[p2.l,p1.l];
    p3.l = pos + 1/2thick * dir (angle + 90) + whatever * dir angle;
    p3.r - p1.r = whatever * dir (angle + 105);
    p3.r = pos + 1/2thick * dir (angle + 90) + whatever * dir angle;
    fill p1.r -- p3.r -- p3.l -- p2.l -- p2.r -- cycle;
  endgroup;
enddef;

def draw_arrowhead(expr pos, angle, spread, thick) =
  begingroup;
    pair p[], p[].l, p[].r;
  
    p1 = pos;
    p2 = pos + sqrt(2) * spread/2 * dir (angle + 135);
    p3 = pos + sqrt(2) * spread/2 * dir (angle - 135);
    1/2[p1.l, p1.r] = p1;
    1/2[p2.l, p2.r] = p2;
    1/2[p3.l, p3.r] = p3;
    p1.r - p1 = thick/(2 * sind 45) * dir angle;
    p2.r - p2 = thick/2 * dir (angle + 45);
    p3.r - p3 = thick/2 * dir (angle - 45);

    fill p1.r -- p2.r -- p2.l -- p1.l -- p3.l -- p3.r -- cycle;
  endgroup;
enddef;

% intersect the arrowhead curve with a path
def arrowhead_intersection(expr pos, angle, spread, p) =
  (p intersectionpoint
    ((pos + sqrt(2) * spread/2 * dir (angle + 135)) --
     pos -- (pos + sqrt(2) * spread/2 * dir (angle - 135)))
  )
enddef;

def draw_bracket(expr sign, thick, draw_top, draw_mid, draw_bot, draw_double) =
  penpos0(thick, 90 - sign * 90);
  penpos1(thick, 90 - sign * 90);
  penpos2(thick, 90);
  penpos3(thick, 90);
  penpos4(thick, 90);
  penpos5(thick, 90);
  penpos6(thick, 0);
  penpos7(thick, 0);

  x3 - x2 = x5 - x4 = sign * (w - 2side_bearing);
  1/2[x2,x3] = w/2;

  if draw_top:
    y1 = h;
  else:
    y1 = h + 1/2line_thickness;
  fi;

  if draw_bot:
    y0 = -d;
  else:
    y0 = -d - 1/2line_thickness;
  fi;

  x1 = x0;
  z6 = 1/2[z2l,z3l] + sign * 1/2thick * right;
  z7 = 1/2[z4r,z5r] + sign * 1/2thick * right;
  y2l = y3l;
  y4r = y5r;
  z2l = z0l;
  z4r = z1l;

  if draw_mid:
    fill stroke z0e -- z1e;
  else:
    if draw_bot: fill stroke z0e -- z0e + (w - 2side_bearing) * up; fi;
    if draw_top: fill stroke z1e -- z1e + (w - 2side_bearing) * down; fi;
  fi;
  if draw_top: fill stroke z4e -- z5e; fi;
  if draw_bot: fill stroke z2e -- z3e; fi;
  if draw_double: fill stroke z6e -- z7e; fi;
enddef;

def draw_angle(suffix $)(expr shift, sign, thick) =
  x0$ = x1$ = x2$ + sign * (w - 2side_bearing -2abs shift - thick);

  top y1$ = h;
  bot y0$ = -d;
  1/2[y0$,y1$] = y2$;
  1/2[x0$,x2$] = w/2 + shift;

  theta := angle(z0$ - z2$) + 90;

  penpos0$ (thick, theta);
  penpos1$ (thick, -theta);
  penpos2$ (thick * cosd theta, 0);

  fill stroke z0$e -- z2$e -- z1$e;

  penlabels(0$, 1$, 2$);
enddef;

def draw_paren(expr sign, thick) =
  penpos0(thick,  90 - sign * 45);
  penpos1(thick, -90 + sign * 45);
  penpos2(thick,  90 - sign * 90);

  x0 = x1 = x2 + sign * (w - 2side_bearing - thick);
  y1.l =  h;
  y0.l = -d;
  1/2[y0,y1] = y2;
  1/2[x0r,x2l] = w/2;

  fill stroke z0e{3(x2e - x0e), y2e - y0e} .. z2e .. {3(x1e - x2e), y1e - y2e}z1e;

  penlabels(0,1,2);
enddef;

def draw_brace(expr centre, size, width, alpha, thick, top_size, mid_size, bot_size) =
  penpos1(5/6thick, alpha + 90);
  penpos2(thick, alpha);
  penpos2'(thick,alpha);
  penpos3(thick, alpha);
  penpos3'(thick,alpha);
  penpos4(11/12thick, alpha+90);
  penpos5(thick, alpha+180);
  penpos5'(thick, alpha+180);
  penpos6(thick, alpha+180);
  penpos6'(thick, alpha+180);
  penpos7(5/6thick, alpha+90);

  z1r - z7l = size * dir (alpha + 90);

  centre - 1/2[z1,z7] = z4 - centre = width/2 * dir alpha;

  z0 = centre;

  z3 = z0 + (1/3width + 1/2thick) * dir (alpha + 90);
  z5 = z0 - (1/3width + 1/2thick) * dir (alpha + 90);

  z2 = z0 + (size/2 - 1/3width - thick) * dir (alpha + 90);
  z6 = z0 - (size/2 - 1/3width - thick) * dir (alpha + 90);

  z3' = z0 + (mid_size/2 + 1/2line_thickness) * dir (alpha + 90);
  z5' = z0 - (mid_size/2 + 1/2line_thickness) * dir (alpha + 90);

  z2' = z0 + (size/2 - top_size - 1/2line_thickness) * dir (alpha + 90);
  z6' = z0 - (size/2 - bot_size - 1/2line_thickness) * dir (alpha + 90);

  beta := 0;

  if top_size > 0:
    fill stroke z1e{dir alpha} .. {dir (alpha - 90)}z2e -- z2'e;
    penlabels(1,2,2');
  elseif bot_size > 0:
    fill stroke z7e{dir alpha} .. {dir (alpha + 90)}z6e -- z6'e;
    penlabels(6',6,7);
  elseif mid_size > 0:
    fill stroke z3'e -- z3e{dir (alpha - 90)} .. {dir alpha}z4e;
    fill stroke z5'e -- z5e{dir (alpha + 90)} .. {dir alpha}z4e;
    penlabels(3',3,4,5,5');
  else:
    fill stroke z1e{dir alpha} .. z2e{dir (alpha - 90)} -- z3e{dir (alpha - 90)} .. z4e{dir alpha};
    fill stroke z7e{dir alpha} .. {dir (alpha + 90)}z6e -- z5e{dir (alpha + 90)} .. {dir alpha}z4e;
    penlabels(1,2,3,4,5,6,7);
  fi;
enddef;

def draw_root(expr thick) =
  penpos0(rule_thickness, -90);
  penpos0'(rule_thickness, -90);
  penpos2(3/2thick, 0);

  y0l = h;
  x0 = w;
  z0' = z0 + 1/2line_thickness * right;
  y1 = -d;
  x1 = 4/9w;
  x2 = 2/9w;
  y2  = 1/2[y0, y1];
  z1' = z1 + thick * dir (angle (z1 - z2l) + 90);
  y6 = h;
  z6 = z0r + thick * dir (angle (z0r - z1') + 90) + whatever * (z0r - z1');

  penpos3(1/2thick, angle (z1 - z2l));

  z3l = z2r + 5/2thick * dir (angle (z1 - z2l) - 90);
  z4 = z6 + whatever * (z0 - z1') = z2r + whatever * (z2l - z1);
  z5 = whatever[z2l, z1] = z3r + whatever * dir (angle (z1 - z2l) - 90);

  fill z3r -- z5 -- z1 -- z1' -- z0r -- z0'r -- z0'l -- z6 -- z4 -- z2r -- z3l -- cycle;

  penlabels (0,0',1,1',2,3,4,5,6);
enddef;

def draw_root_top(expr thick) =
  y0 = h - 1/2rule_thickness;
  x0 = w;
  y1 = -d;
  x1 = x2 = 4/9w + 1/2thick;
  y2 = h - 1/2thick;

  draw_straight(z1, z2, thick, true);
  draw_straight((x1,y0), z0, rule_thickness, true);
enddef;

def draw_root_bot(expr thick) =
  penpos0(thick, 0);
  penpos0'(thick, -90);
  penpos2(3/2thick, 0);

  y0 = h + 1/2thick;
  x0l = x1;
  y1 = -d;
  x1 = 4/9w;
  x2l = 1/9w;
  y2  = 1/2[y0, y1];
  z1' = z1 + whatever * dir (angle (z1 - z2l) + 90);
  x1' = x0r;

  penpos3(1/2thick, angle (z1 - z2l));

  z3l = z2r + 5/2thick * dir (angle (z1 - z2l) - 90);
  z4 = z0l + whatever * up = z2r + whatever * (z2l - z1);
  z5 = whatever[z2l, z1] = z3r + whatever * dir (angle (z1 - z2l) - 90);

  fill z3r -- z5 -- z1 -- z1' -- z0r -- z0l -- z4 -- z2r -- z3l -- cycle;

  penlabels (0,1,1',2,3,4,5);
enddef;

% Weierstrass macros

def ellipse_set(suffix $,@,@@,$$) =
  % given |z$,x@,z$$|, find |y@| and |z@@|
  % such that the path |z${x@-x$,0}..z@{0,y@-y$}..{z$$-z@@}z@@|
  % is consistent with an ellipse
  % and such that the line |z@@--z$$| has a given |slope|
  alpha_ := slope * (x@ - x$);
  beta_  := y$$ - y$ - slope * (x$$ - x$);
  gamma_ := alpha_ / beta_;
  y@  - y$  = .5(beta_ - alpha_ * gamma_);
  x@@ - x$  = -2gamma_ * (x@ - x$) / (1 + gamma_ * gamma_);
  y@@ - y$$ = slope * (x@@ - x$$)
enddef;

vardef super_arc.r(suffix $,$$) =
  % outside of super-ellipse

  pair centre, corner;

  if y$ = y$r:
    centre = (x$$r, y$r);
    corner = (x$r, y$$r);
  else:
    centre = (x$r, y$$r);
    corner = (x$$r, y$r);
  fi
  z$.r{corner - z$.r} ... superness[centre,corner]{z$$.r - z$.r}
                      ... {z$$.r - corner}z$$.r
enddef;

vardef super_arc.l(suffix $,$$) =
  % inside of super-ellipse

  pair centre, corner;
  if y$ = y$r:
    centre = (x$$l, y$l);
    corner = (x$l, y$$l);
  else:
    centre = (x$l, y$$l);
    corner = (x$$l, y$l);
  fi
  z$l{corner - z$l} ... superness[centre,corner]{z$$l - z$l}
                    ... {z$$l - corner}z$$l
enddef;

vardef pulled_super_arc.r(suffix $,$$)(expr superpull) =
  pair centre, corner;

  if y$ = y$r:
    centre = (x$$r, y$r);
    corner = (x$r, y$$r);
  else:
    centre = (x$r, y$$r);
    corner = (x$$r, y$r);
  fi
  z$r{corner - z$r} ... superness[centre,corner]{z$$r - z$r}
                    ... {z$$r - corner}z$$r
enddef;

vardef pulled_super_arc.l(suffix $,$$)(expr superpull) =
  pair centre, corner, outer_point;

  if y$ = y$r:
    centre = (x$$l, y$l);
    corner = (x$l, y$$l);
    outer_point = superness[(x$$r, y$r), (x$r, y$$r)];
  else:
    centre = (x$l, y$$l);
    corner = (x$$l, y$l);
    outer_point = superness[(x$r, y$$r), (x$$r, y$r)];
  fi
  z$l{corner - z$l}
   ... superpull[superness[centre,corner], outer_point]{z$$l - z$l}
   ... {z$$l - corner}z$$l
enddef;

vardef pulled_arc@#(suffix $,$$) =
  pulled_super_arc@#($,$$)(superpull)
enddef;