[mod.computers.laser-printers] Metafont parameters for Imagen 24/300?

ramey%tilde%ti-csl.CSNET@RELAY.CS.NET (Joe Ramey) (08/28/86)

Has anyone found good values for blacker, fillin, and o_correction
for the Imagen 24/300?  I have been playing with it for a while,
and it's becoming more difficult to tell what I am looking for
in the output.  One strange thing I have noticed is that the lowercase
y in cmr10 at low magnifications (like magstep .5) looks funny;
the bulb on the tail is hard to make appear (the tail just curls around
about 180 degrees, but there is no bulb).  I can make it appear
with blacker set to 1.5 or so, or with o_correction set to .99 (this
makes other things look real funny though).  At high magnification (magstep
3) the tail looks just fine with various parameters settings.

If you have good parameters for this printer, let me know.  At least
that way I'll have a place to start from!

Joe Ramey
TI Computer Science Center, Dallas

nb@COYOTE.STANFORD.EDU (Neenie Billawala) (08/30/86)

**************
	Dear Joe - 
	In response to your question, the following is a copy of a note
	I sent to someone else who asked a similar question:
	How to get the CM fonts to work better on a "write-white" machine?
	I hope it helps. (And if it works, would you send me a sample? Thanks)
	-- neenie
**************

The problem in getting a like result with write-white(ww)/write-black(wb)
machines from the same pixel pattern lies in the fact that the effective
size of each pixel differs; the size is typically smaller in ww machines.
This means that you won't get the same variations in line thickness.

Theoretically, one pixel on a 300dpi printer should have a width of 1/300 
of an inch. On a ww machine, it's typically less; on a wb machine, 
it's usually a bit more. So the gradations of thickness may look 
something like the following:

# of pixels	"ideal width"		ww width		wb width

   1		1 * 1/300inch		.8 * 1/300inch		1.2*1/300inch 
   2		2 * 1/300inch		1.8 * 1/300inch		2.2*1/300inch 
   3		3 * 1/300inch		2.8 * 1/300inch		3.2*1/300inch 
   4		4 * 1/300inch		3.8 * 1/300inch		4.2*1/300inch 
   10		10 * 1/300inch		9.8 * 1/300inch		10.2*1/300inch

So, you can see, the greater the number of pixels, the less important
the .4 pixel difference becomes. The greatest discrepancy and problems
occur with lines one pixel wide, where the % of difference is the greatest.
Given these limitations, it is not possible to get exactly the same 
results on two such separate machines.

Increasing the amount of "blacker" has the effect of adding that
absolute amount to certain values; i.e., blacker:=2 would always add 
2 pixels to the stem, no matter the resolution. 

A while back, someone came by with the same problem for a similar machine.
We tried 1) some higher settings of blacker 2) selectively adding blacker 
to some values 3) setting a mimimum line thickness. Both 1) and 2) often 
created unwanted character distortions. The (tfm) widths wanted to be 
the same, and when e.g., each line in a character was increased by one; 
the shapes were often distorted, counter (inside) shapes seemed to suffer 
the most. A first attempt with 3) showed promise, and though the result 
was not as dark as the wb machine, the feeling of CM was retained. 
However, in the first attempt, we did not manage to change all of the 
thicknesses to 2 pixels. DEK made a global correction, which should keep 
minimum thicknesses to 2 pixels. Looking at the pixel patterns, this fix 
appears to work. However, the man who has the ww printer and who originally 
came by with this problem, is part of the University and has been traveling, 
so I haven't seen any concrete results yet. Such is the way of Academia! 

The following is an adjusted cmbase.mf file. The changes are found in 
2 lines of the <font_setup> def with the comment "% "WRITE WHITE" ONLY!".  
Just use this file, or add the changes to yours. Then run a test, using 
your original mode_setup specifications. Let me know how it goes. 
Would you also send me a copy of your results? Thanks. Good luck.

Neenie Billawala

Computer Science Department
Stanford University
Stanford CA  94305



************************************************************************
% The base file for Computer Modern (a supplement to {\tt plain.mf})

cmbase:=1; % when |cmbase| is known, this file has been input

let cmchar=\; % `|cmchar|' should precede each character
let generate=input; % `|generate|' should follow the parameters

autorounding:=0; smoothing:=0; % we do our own rounding
def autorounded = interim autorounding:=2 enddef;

newinternal slant,fudge,math_spread,superness,superpull,beak_darkness,ligs;
boolean square_dots,hefty,serifs,
 monospace,variant_g,low_asterisk,math_fitting;

boolean dark,dark.dark,skewed,skewed.skewed; % for fast option testing
dark=skewed=false; dark.dark=skewed.skewed=true;

vardef Vround primary y = y_:=vround y;
 if y_<min_Vround: min_Vround else: y_ fi enddef;
newinternal y_,min_Vround;

vardef serif(suffix $,$$,@)	% serif at |z$| for stroke from |z$$|
  (expr darkness,jut) suffix modifier =
 pickup crisp.nib; numeric bracket_height; pair downward;
 bracket_height=if dark.modifier: 1.5 fi\\ bracket;
 if y$<y$$: y@2=min(y$+bracket_height,y$$);
  top y@1-slab=bot y@0+eps=tiny.bot y$; downward=z$-z$$;
  if y@1>y@2: y@2:=y@1; fi
 else: y@2=max(y$-bracket_height,y$$);
  bot y@1+slab=top y@0-eps=tiny.top y$; downward=z$$-z$;
  if y@1<y@2: y@2:=y@1; fi fi
 y@3=y@2; z@3=whatever[z$,z$$];
 if jut<0: z@2+penoffset downward of currentpen =
   z$l+penoffset downward of pen_[tiny.nib]+whatever*downward;
  lft x@0=lft x@1=tiny.lft x$l+jut;
  if x@3<x@2+eps: x@3:=x@2+eps; fi
 else: z@2-penoffset downward of currentpen =
   z$r-penoffset downward of pen_[tiny.nib]+whatever*downward;
   rt x@0=rt x@1=tiny.rt x$r+jut;
   if x@3>x@2-eps: x@3:=x@2-eps; fi fi
 pair corner; ypart corner=y@1; corner=z@2+whatever*downward;
 filldraw z@2{z$-z$$}
  ...darkness[corner,.5[z@1,z@2] ]{z@1-z@2}
  ...{jut,0}z@1--z@0--(x$,y@0)--z@3--cycle; % the serif
 labels (@1,@2); enddef;

def dish_serif(suffix $,$$,@)(expr left_darkness,left_jut)
  (suffix @@)(expr right_darkness,right_jut) suffix modifier =
 serif($,$$,@,left_darkness,-left_jut) modifier;
 serif($,$$,@@,right_darkness,right_jut) modifier;
 if dish>0: pickup tiny.nib; numeric dish_out,dish_in;
  if y$<y$$: dish_out=bot y$; dish_in=dish_out+dish; let rev_=reverse;
  else: dish_out=top y$; dish_in=dish_out-dish; let rev_=relax; fi
  erase fill rev_
   ((x@1,dish_out)..(x$,dish_in){right}..(x@@1,dish_out)--cycle);
 fi enddef;

def nodish_serif(suffix $,$$,@)(expr left_darkness,left_jut)
  (suffix @@)(expr right_darkness,right_jut) suffix modifier =
 serif($,$$,@,left_darkness,-left_jut) modifier;
 serif($,$$,@@,right_darkness,right_jut) modifier; enddef;

vardef sloped_serif.l(suffix $,$$,@)(expr darkness,jut,drop) =
 pickup crisp.nib; pos@2(slab,90);
 lft x@0=tiny.lft x$l; rt x@1=tiny.rt x$r; top y@1=tiny.top y$r;
 lft x@2=lft x@0-jut; y@2r=y@1-drop;
 y@0=max(y@2l-bracket,y$$)-eps;
 if drop>0: erase fill z@1--top z@1
   --(x@2r,top y@1)--z@2r--cycle; fi % erase excess at top
 filldraw z@1--z@2r--z@2l{right}
  ...darkness[(x@0,y@2l),.5[z@2l,z@0] ]{z@0-z@2l}
  ...{down}z@0--(x@1,y@0)--cycle;	% sloped serif
 labels(@0,@1,@2); enddef;

vardef sloped_serif.r(suffix $,$$,@)(expr darkness,jut,drop) =
 pickup crisp.nib; pos@2(slab,-90);
 rt x@0=tiny.rt x$r; lft x@1=tiny.lft x$l; bot y@1=tiny.bot y$l;
 rt x@2=rt x@0+jut; y@2r=y@1+drop;
 y@0=min(y@2l+bracket,y$$)+eps;
if drop>0: erase fill z@1--bot z@1
  --(x@2r,bot y@1)--z@2r--cycle; fi % erase excess at bottom
 filldraw z@1--z@2r--z@2l{left}
  ...darkness[(x@0,y@2l),.5[z@2l,z@0] ]{z@0-z@2l}
  ...{up}z@0--(x@1,y@0)--cycle;	% sloped serif
 labels(@0,@1,@2); enddef;

vardef term.l(suffix $,$$)(expr d,t,s)= % ``robust'' sans-serif terminal
 path p_; p_=z$l{d}..tension t..z$$l;
 pair d_; d_=(x$$l-x$l,s*(y$$l-y$l));
 if (abs angle direction 1 of p_ < abs angle d_)<>(x$l<x$$l):
  p_:=z$l{d}..tension atleast t..{d_}z$$l; fi
 p_ enddef;
vardef term.r(suffix $,$$)(expr d,t,s)=
 path p_; p_=z$r{d}..tension t..z$$r;
 pair d_; d_=(x$$r-x$r,s*(y$$r-y$r));
 if (abs angle direction 1 of p_ < abs angle d_)<>(x$r<x$$r):
  p_:=z$r{d}..tension atleast t..{d_}z$$r; fi
 p_ enddef;
def rterm=reverse term enddef;

vardef arm(suffix $,$$,@)(expr darkness,jut) =	% arm from |z$| to |z$$|
 x@0=good.x(x$$r-jut); y@0=y$r;
 if serifs: y@1=y$l; z@1=z$$l+whatever*(z$$r-z@0);
  z@2=.5[z$l,z@1];
  filldraw z$$l{z@1-z$$l}...darkness[z@1,.5[z@2,z$$l] ]...z@2
   ---z$l--z$r--z@0--z$$r--cycle; % arm and beak
 else: filldraw z$l--z$r--z@0--z$$r--cycle; fi	% sans-serif arm
 penlabels(@0,@1,@2); enddef;

def pi_stroke = pickup fine.nib;
 pos1(hair,0); pos2(vstem,-90); pos3(vstem,-90);
 x1-.5hair=hround -.5hair; x2=2u; x3=w-1.5u;
 y1=x_height-x_height/3.141592653589793; y2=y3; top y3l=x_height;
 filldraw circ_stroke z3e---z2e...{x1-x2,3.14159(y1-y2)}z1e enddef;

def bulb(suffix $,$$,$$$) =
 z$$$r=z$$r;
 path_.l:=z$l{x$$r-x$r,0}...{0,y$$r-y$r}z$$l;
 filldraw path_.l--z$$r{0,y$r-y$$r}...{x$r-x$$r,0}z$r--cycle; % link
 path_.r:=z$$$l{0,y$r-y$$r}..z$$$r{0,y$$r-y$r}; % near-circle
 filldraw subpath(0,xpart(path_.r intersectiontimes path_.l)) of path_.r
  --z$$r{0,y$$r-y$r}..cycle; % bulb
 enddef;

def v_bulb(suffix $,$$)= % |pos$| is known
 y$$+.5curve=x_height+oo; x$$+.5curve=w-u;
 numeric theta; theta=angle(4(x$-x$$),y$-y$$); pos$$(curve,theta+90);
 filldraw z$$l{dir theta}..tension atleast 1 and 1..{down}z$l
  --z$r{up}...{-dir theta}z$$r..cycle;	% bulb
 enddef;

def dot(suffix $,$$) =
 filldraw if square_dots: (x$l,y$$l)--(x$r,y$$l)
   --(x$r,y$$r)--(x$l,y$$r)--cycle	% squarish dot
  else: z$l...z$$l...z$r...z$$r...cycle	fi % roundish dot
 enddef;

def comma(suffix $,@)(expr dot_size,jut,depth) =
 pickup fine.nib; pos$(dot_size,90);
 if square_dots: pos$'(dot_size,0); z$'=z$; dot($',$);	% squarish dot
  comma_join_:=max(fine.breadth,floor .7dot_size);
  comma_bot_:=max(fine.breadth,floor .5dot_size);
  pos@0(comma_join_,0); pos@1(comma_join_,0);
  pos@2(comma_bot_,0); y@0=y$; y@1=y$l; y@2=y@1-depth;
  x@0r=x@1r=x$'r; rt x@2r=good.x(x$-eps);
  filldraw stroke z@0e--z@1e..z@2e;	% tail
 else: pos@1(vair,90); pos@2(vair,0); pos@3(vair,-45);
  z@1r=z$r; rt x@2r=hround(x$+.5dot_size+jut)+2eps; x@3=x$-.5u;
  y@2=1/3[y@1,y@3]; bot y@3r=vround(y$-.5dot_size-depth);
  y_:=ypart((z@1{right}...z@2{down}...z@3)
   intersectiontimes (z$l{right}..{left}z$r)); if y_<0: y_:=1; fi
  filldraw z$r{left}..subpath (0,y_) of (z$l{right}..{left}z$r)--cycle; % dot
  filldraw stroke z@1e{right}...z@2e{down}...z@3e; fi	% tail
 penlabels(@1,@2,@3); enddef;

def ammoc(suffix $,@)(expr dot_size,jut,depth) = % reversed comma
 pickup fine.nib; pos$(dot_size,90);
 if square_dots: pos$'(dot_size,0); z$'=z$; dot($',$);	% squarish dot
  comma_join_:=max(fine.breadth,floor .7dot_size);
  comma_top_:=max(fine.breadth,floor .5dot_size);
  pos@0(comma_join_,0); pos@1(comma_join_,0);
  pos@2(comma_top_,0); y@0=y$; y@1=y$r; y@2=y@1+depth;
  x@0l=x@1l=x$'l; lft x@2l=good.x(x$+eps);
  filldraw stroke z@0e--z@1e..z@2e;	% tail
 else: pos@1(vair,90); pos@2(vair,0); pos@3(vair,-45);
  z@1l=z$l; lft x@2l=hround(x$-.5dot_size-jut)-2eps; x@3=x$+.5u;
  y@2=1/3[y@1,y@3]; top y@3l=vround(y$+.5dot_size+depth);
  y_:=ypart((z@1{left}...z@2{up}...z@3)
   intersectiontimes (z$r{left}..{right}z$l)); if y_<0: y_:=1; fi
  filldraw z$l{right}..subpath (0,y_) of (z$r{left}..{right}z$l)--cycle; % dot
  filldraw stroke z@1e{left}...z@2e{up}...z@3e; fi	% tail
 penlabels(@1,@2,@3); enddef;

%%% @ from to %%%% temporary formatting change
vardef diag_in(suffix from,$)(expr sharpness)(suffix $$) =
 pickup tiny.nib; save from_x,y_;
 if y.from>y$: bot else: top fi\\ y_=y$;
 (from_x,y_)=whatever[z.from,z$];
 sharpness[z$,(from_x,y_)]{z$-z.from}
  ...{z$$-z$}z$+sharpness*length(z$-(from_x,y_))*unitvector(z$$-z$) enddef;

vardef diag_out(suffix $)(expr sharpness)(suffix $$,to) =
 pickup tiny.nib; save to_x,y_;
 if y.to>y$: bot else: top fi\\ y_=y$;
 (to_x,y_)=whatever[z$$,z.to];
 z$$-sharpness*length(z$$-(to_x,y_))*unitvector(z$$-z$){z$$-z$}
  ...{z.to-z$$}sharpness[z$$,(to_x,y_)] enddef;

vardef diag_end(suffix from,$)(expr sharpness_in,sharpness_out)(suffix $$,to)=
 save from_x,to_x,y_,x_,xx_;
 if y.from>y$: tiny.bot else: tiny.top fi\\ y_=y$; % we assume that |y$=y$$|
 (from_x,y_)=whatever[z.from,z$]; (to_x,y_)=whatever[z$$,z.to];
 if x$$>x$: x_=x$+sharpness_in*length(z$-(from_x,y_));
  xx_=x$$-sharpness_out*length(z$$-(to_x,y_));
  if xx_<x_: xx_:=x_:=.5[xx_,x_]; fi
 else: x_=x$-sharpness_in*length(z$-(from_x,y_));
  xx_=x$$+sharpness_out*length(z$$-(to_x,y_));
  if xx_>x_: xx_:=x_:=.5[xx_,x_]; fi fi
 sharpness_in[z$,(from_x,y_)]{z$-z.from}
  ...{z$$-z$}(x_,y$)..(xx_,y$){z$$-z$}
  ...{z.to-z$$}sharpness_out[z$$,(to_x,y_)] enddef;
%%% at from to %%%% restore normal formatting

vardef special_diag_end(suffix $$,$,@,@@) = % for top middle of w's
 if x@r<=x$r: diag_end($$r,$r,1,1,@l,@@l)
 else: z0=whatever[z$$l,z$l]=whatever[z@l,z@@l];
  diag_end($$r,$r,1,1,$l,0)--z0 fi enddef;

def prime_points_inside(suffix $,$$) =
 theta_:=angle(z$r-z$l);
 penpos$'(whatever,theta_);
 if y$$>y$: z$'=(0,pen_top) rotated theta_ + whatever[z$l,z$r];
  theta_:=angle(z$$-z$)-90;
 else: z$'=(0,pen_bot) rotated theta_ + whatever[z$l,z$r];
  theta_:=angle(z$$-z$)+90; fi
 z$'l+(pen_lft,0) rotated theta_=z$l+whatever*(z$-z$$);
 z$'r+(pen_rt,0) rotated theta_=z$r+whatever*(z$-z$$);
 enddef;

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 diag_ratio(expr a,b,y,c) = % assuming that $a>\vert b/y\vert$,
% compute the value $\alpha=(x\6{++}y)/y$ such that $ax+b\alpha=c$
 numeric a_,b_; b_=b/y; a_=a*a-b_*b_;
 (a*(c++y*sqrt a_)-b_*c)/a_/y enddef;

def f_stroke(suffix $,$$,@,left_serif,right_serif)(expr left_jut,right_jut)=
 pickup tiny.nib; bot y$=0;
 penpos@0(x$r-x$l,0); x@0l=x$l; top y@0=x_height;
 filldraw stroke z$e--z@0e;	% stem
 pickup fine.nib; pos@0'(x$r-x$l-(hround stem_corr)+tiny,180);
 y@0'=y@0; lft x@0'r=tiny.lft x$l;
 penpos@1(x@0'l-x@0'r,180); x@1=x@0'; y@1+.5vair=.5[x_height,h];
 pos@2(vair,90); top y@2r=h+oo;
 if serifs: x@2=.6[x@1,x$$r]; (x@,y@2r)=whatever[z@2l,z@1l];
  x@2r:=min(x@,.5[x@2,x$$r]); pos@3(hair,0); bulb(@2,@3,$$);	% bulb
  filldraw stroke z@0'e--z@1e & super_arc.e(@1,@2);	% arc
  dish_serif($,@0,left_serif,1/3,left_jut,right_serif,1/3,right_jut); % serif
 else: x@2=.6[x@1,x$$]; y@1l:=1/3[y@1l,y@2l];
  filldraw stroke z@0'e--z@1e & super_arc.e(@1,@2)
   & term.e(@2,$$,right,.9,4); fi	% arc and terminal
 penlabels(@0,@1,@2); enddef;

def h_stroke(suffix $,@,@@,$$) =
 penpos$$(x@@r-x@@l,0); x$$=x@@; bot y$$=0;
 y@@=1/3[bar_height,x_height];
 penpos$''(x$r-x$l,0); x$''=x$; y$''=1/8[bar_height,x_height];
 filldraw stroke z$''e--z$e;	% thicken the lower left stem
 penpos@0(min(rt x$r-lft x$l,thin_join)-fine,180); pickup fine.nib;
 rt x@0l=tiny.rt x$r; y@0=y$'';
 pos@1(vair,90); pos@@'(x@@r-x@@l+tiny,0); z@@'=z@@;
 x@1=.5[rt x@0l,rt x@@'r]; top y@1r=x_height+oo;
 (x@,y@1l)=whatever[z@1r,z@0l]; x@1l:=x@;
 filldraw stroke z@0e{up}...{right}z@1e
  &{{interim superness:=hein_super; super_arc.e(@1,@@')}};	% arch
 pickup tiny.nib; filldraw stroke z@@e--z$$e;	% right stem
 labels(@0); penlabels(@1); enddef;

def hook_out(suffix $,$$,$$$)suffix modifier= % |x$| and |x$$$| (only) are known
 pos$(stem,0); pos$$(vair,90);
 x$$$:=hround(x$$$+.5hair-eps)-.5hair; pos$$$(hair,180);
 y$=1/4x_height; bot y$$l=-oo; y$$$=1/3x_height;
 if skewed.modifier: x$$=x$+1.25u;
  filldraw stroke z$e{-u,-x_height}...z$$e{right}...{up}z$$$e;	% hook
 else: x$$=x$+1.5u;
  filldraw stroke z$e{down}...z$$e{right}
   ...{x$$$-(x$+2.5u),x_height}z$$$e; fi enddef;	% hook

def hook_in(suffix $,$$,$$$)suffix modifier= % |x$| and |x$$$| (only) are known
 x$:=hround(x$-.5hair)+.5hair; pos$(hair,180);
 pos$$(vair,90); pos$$$(stem,0);
 y$=2/3x_height; top y$$r=x_height+oo; y$$$=3/4x_height;
 if skewed.modifier: x$$=x$$$-1.25u;
  filldraw stroke z$e{up}...z$$e{right}...{-u,-x_height}z$$$e;	% hook
 else: x$$=x$$$-1.5u;
  filldraw stroke z$e{x$$$-2.5u-x$,x_height}
   ...z$$e{right}...{down}z$$$e; fi enddef;	% hook

def ital_arch(suffix $,$$,$$$) = % |z$| and |z$$$| (only) are known
 pos$'(hair,180); z$'=z$;
 pos$$(vair,90); pos$$$(stem,0);
 {{interim superness := more_super; x$$=.6[x$,x$$$];
 top y$$r=x_height+oo; y$$$=.65x_height;
 filldraw stroke z$'e{up}...super_arc.e($$,$$$);}} enddef;	% stroke

def compute_spread(expr normal_spread,big_spread)=
 spread#:=math_spread[normal_spread,big_spread];
 spread:=ceiling(spread#*hppp)+eps; enddef;

def v_center(expr h_sharp) =
 .5h_sharp+math_axis#, .5h_sharp-math_axis# enddef;

def circle_points =
 x4=x8=.5[x2,x6]; x1=x3=superness[x4,x2]; x5=x7=superness[x4,x6];
 y2=y6=.5[y4,y8]; y1=y7=superness[y2,y8]; y3=y5=superness[y2,y4];
 enddef;
def draw_circle =
 draw z8{right}...z1{z2-z8}...z2{down}...z3{z4-z2}...z4{left}
  ...z5{z6-z4}...z6{up}...z7{z8-z6}...cycle enddef;

def left_paren(expr min_breadth, max_breadth) =
 pickup fine.nib; pos1(hround min_breadth,0);
 pos2(hround max_breadth,0); pos3(hround min_breadth,0);
 rt x1r=rt x3r=hround(w-1.25u+.5min_breadth); lft x2l=hround 1.25u;
 top y1=h; y2=.5[y1,y3]; bot y3=1-d;
 filldraw stroke z1e{3(x2e-x1e),y2-y1}...z2e
  ...{3(x3e-x2e),y3-y2}z3e;	% arc
 penlabels(1,2,3); enddef;

def right_paren(expr min_breadth, max_breadth) =
 pickup fine.nib; pos1(hround min_breadth,0);
 pos2(hround max_breadth,0); pos3(hround min_breadth,0);
 lft x1l=lft x3l=hround(1.25u-.5min_breadth); rt x2r=hround(w-1.25u);
 top y1=h; y2=.5[y1,y3]; bot y3=1-d;
 filldraw stroke z1e{3(x2e-x1e),y2-y1}...z2e
  ...{3(x3e-x2e),y3-y2}z3e;	% arc
 penlabels(1,2,3); enddef;

def left_bracket(expr breadth,do_top,do_bot) =
 pickup crisp.nib;
 numeric thickness; thickness=hround breadth;
 pos1(thickness,0); pos2(thickness,0);
 top y1=h; bot y2=1-d; lft x1l=lft x2l=hround(2.5u-.5thickness);
 filldraw stroke z1e--z2e;	% stem
 pos3(thickness,90); pos4(thickness,90);
 pos5(thickness,90); pos6(thickness,90);
 x3=x5=x1l; rt x4=rt x6=hround(w-.75u+.5thickness);
 y3r=y4r=y1; y5l=y6l=y2;
 if do_top: filldraw stroke z3e--z4e; fi	% upper bar
 if do_bot: filldraw stroke z5e--z6e; fi	% lower bar
 penlabels(1,2,3,4,5,6); enddef;

def right_bracket(expr breadth,do_top,do_bot) =
 pickup crisp.nib;
 numeric thickness; thickness=hround breadth;
 pos1(thickness,0); pos2(thickness,0);
 top y1=h; bot y2=1-d; rt x1r=rt x2r=hround(w-2.5u+.5thickness);
 filldraw stroke z1e--z2e;	% stem
 pos3(thickness,90); pos4(thickness,90);
 pos5(thickness,90); pos6(thickness,90);
 x3=x5=x1r; lft x4=lft x6=hround(.75u-.5thickness);
 y3r=y4r=y1; y5l=y6l=y2;
 if do_top: filldraw stroke z3e--z4e; fi	% upper bar
 if do_bot: filldraw stroke z5e--z6e; fi	% lower bar
 penlabels(1,2,3,4,5,6); enddef;

def left_curly(expr min_breadth, max_breadth) =
 pickup fine.nib;
 forsuffixes $=1,1',4,4',7,7': pos$(hround min_breadth,0); endfor
 forsuffixes $=2,3,5,6: pos$(hround max_breadth,0); endfor
 x2=x3=x5=x6; x1=x1'=x7=x7'=w-x4=w-x4';
 lft x4l=hround(1.5u-.5min_breadth); lft x2l=hround(.5w-.5max_breadth);
 top y1=h; bot y7=1-d; .5[y4,y4']=.5[y1,y7]=.5[y2,y6]=.5[y3,y5];
 y1-y2=y3-y4=(y1-y4)/4;
 y1-y1'=y4-y4'=y7'-y7=vround(min_breadth-fine);
 filldraw z1l{3(x2l-x1l),y2-y1}...z2l---z3l...{3(x4l-x3l),y4-y3}z4l
  --z4'l{3(x5l-x4l),y5-y4'}...z5l---z6l...{3(x7l-x6l),y7-y6}z7l
  --z7r--z7'r{3(x6r-x7r),y6-y7'}...z6r---z5r
  ...{3(x4r-x5r),.5[y4,y4']-y5}.5[z4r,z4'r]{3(x3r-x4r),y3-.5[y4,y4']}
  ...z3r---z2r...{3(x1r-x2r),y1'-y2}z1'r--z1r--cycle;	% stroke
 penlabels(1,2,3,4,5,6,7); enddef;

def right_curly(expr min_breadth, max_breadth) =
 pickup fine.nib;
 forsuffixes $=1,1',4,4',7,7': pos$(hround min_breadth,0); endfor
 forsuffixes $=2,3,5,6: pos$(hround max_breadth,0); endfor
 x2=x3=x5=x6; x1=x1'=x7=x7'=w-x4=w-x4';
 lft x1l=hround(1.5u-.5min_breadth); lft x2l=hround(.5w-.5max_breadth);
 top y1=h; bot y7=1-d; .5[y4,y4']=.5[y1,y7]=.5[y2,y6]=.5[y3,y5];
 y1-y2=y3-y4=(y1-y4)/4;
 y1-y1'=y4-y4'=y7'-y7=vround(min_breadth-fine);
 filldraw z1r{3(x2r-x1r),y2-y1}...z2r---z3r...{3(x4r-x3r),y4-y3}z4r
  --z4'r{3(x5r-x4r),y5-y4'}...z5r---z6r...{3(x7r-x6r),y7-y6}z7r
  --z7l--z7'l{3(x6l-x7l),y6-y7'}...z6l---z5l
  ...{3(x4l-x5l),.5[y4,y4']-y5}.5[z4l,z4'l]{3(x3l-x4l),y3-.5[y4,y4']}
  ...z3l---z2l...{3(x1l-x2l),y1'-y2}z1'l--z1l--cycle;	% stroke
 penlabels(1,2,3,4,5,6,7); enddef;

def left_angle(expr breadth) =
 pickup pencircle scaled breadth;
 x1=x3=good.x(w-u)+eps; lft x2=hround u-eps;
 top y1=h+eps; .5[y1,y3]=y2=good.y .5[-d+eps,h];
 draw z1--z2--z3;	% diagonals
 labels(1,2,3); enddef;

def right_angle(expr breadth) =
 pickup pencircle scaled breadth;
 x1=x3=good.x u-eps; rt x2=hround(w-u)+eps;
 top y1=h+eps; .5[y1,y3]=y2=good.y .5[-d+eps,h];
 draw z1--z2--z3;	% diagonals
 labels(1,2,3); enddef;

def big_slash(expr breadth) =
 adjust_fit(-letter_fit#,-letter_fit#); pickup pencircle scaled breadth;
 rt x1=hround(w-u); lft x2=hround u; top y1=h+eps; bot y2=1-d-eps;
 draw z1--z2;	% diagonal
 labels(1,2); enddef;

def big_blash(expr breadth) =
 adjust_fit(-letter_fit#,-letter_fit#); pickup pencircle scaled breadth;
 lft x1=hround u; rt x2=hround(w-u); top y1=h+eps; bot y2=1-d-eps;
 draw z1--z2;	% diagonal
 labels(1,2); enddef;

def big_sqrt =
 adjust_fit(0,-letter_fit#); pickup rule.nib;
 x1=good.x 4/9w; x2=good.x(w+.5); bot y1=-d; bot y2=0;
 draw z1--z2;	% diagonal
 pickup crisp.nib; pos3(max(curve,rule_thickness),0);
 x3l=1.5[x2,x1]; y3=.5[y1,y2];
 pos4(rule_thickness,0); x4=x1; bot y4=-d;
 pos5(vair,-45); x5l=good.x(x3l-u); z5l=whatever[z3r,z2];
 z6=z5r+whatever*(z2-z3r)=whatever[z3l,z4l];
 z7=whatever[z1,z2]=z3r+whatever*(z4l-z3l);
 filldraw z5r--z6--z4l--z4--z7--z3r--z5l--cycle;	% left diagonal and serif
 penlabels(1,2,3,4,5,6,7); enddef;

def big_hat =
 adjust_fit(0,0);
 pickup crisp.nib; pos2(.6[vair,curve],90); top y2r=h+o; x2=.5w;
 x1=w-x3=good.x -eps; y1=y3=.5[x_height,y2];
 pos1(hair,angle(z2-z1)+90); pos3(hair,angle(z3-z2)+90);
 filldraw stroke z1e--z2e--z3e;	% diagonals
 penlabels(1,2,3); enddef;

def big_tilde =
 adjust_fit(0,0); pickup crisp.nib;
 numeric theta; theta=angle(1/6(w-vair),1/4(h-x_height));
 numeric mid_width; mid_width=.4[vair,stem];
 pos1(vair,theta+90); pos2(vair,theta+90);
 pos3(vair,theta+90); pos4(vair,theta+90);
 z2-z1=z4-z3=(mid_width-crisp)*dir theta;
 lft x1r=w-rt x4l=0; top y4r=h;
 bot y1l=vround(bot y1l+min(2/3[x_height,h],y3l-.25vair)-top y1r);
 pair delta; ypart delta=3(y3l-y1l); delta=whatever*dir theta;
 filldraw z1l..controls(z1l+delta)and(z3l-delta)..z3l..z4l
  --z4r..controls(z4r-delta)and(z2r+delta)..z2r..z1r--cycle;	% stroke
 penlabels(1,2,3,4); enddef;

def beginarithchar(expr c) = % ensure consistent dimensions for $+$, $-$, etc.
 if monospace: beginchar(c,14u#,27/7u#+math_axis#,27/7u#-math_axis#);
 else: beginchar(c,14u#,6u#+math_axis#,6u#-math_axis#); fi
 italcorr math_axis#*slant-.5u#;
 adjust_fit(0,0); enddef;

newinternal l,r,shrink_fit; % adjustments to spacing

def normal_adjust_fit(expr left_adjustment,right_adjustment) =
 l:=-hround(left_adjustment*hppp)-letter_fit;
 interim xoffset:=-l;
 charwd:=charwd+2letter_fit#+left_adjustment+right_adjustment;
 r:=l+hround(charwd*hppp)-shrink_fit;
 w:=r-hround(right_adjustment*hppp)-letter_fit;
 enddef;

def mono_adjust_fit(expr left_adjustment,right_adjustment) =
 numeric expansion_factor;
 mono_charwd#=2letter_fit#
   +expansion_factor*(charwd+left_adjustment+right_adjustment);
 forsuffixes $=u,jut,cap_jut,beak_jut,apex_corr:
   $:=$.#*expansion_factor*hppp; endfor
 l:=-hround(left_adjustment*expansion_factor*hppp)-letter_fit;
 interim xoffset:=-l;
 r:=l+mono_charwd-shrink_fit;
 w:=r-hround(right_adjustment*expansion_factor*hppp)-letter_fit;
 charwd:=mono_charwd#; charic:=mono_charic#;
 enddef;

extra_endchar:=extra_endchar&"r:=r+shrink_fit;w:=r-l;";

def ignore_math_fit(expr left_adjustment,right_adjustment) = enddef;
def do_math_fit(expr left_adjustment,right_adjustment) =
 l:=l-hround(left_adjustment*hppp); interim xoffset:=-l;
 charwd:=charwd+left_adjustment+right_adjustment;
 r:=l+hround(charwd*hppp)-shrink_fit;
 charic:=charic-right_adjustment;
 if charic<0: charic:=0; fi enddef;
def zero_width = charwd:=0; r:=l-shrink_fit enddef;
def change_width = if not monospace: % change width by $\pm1$
 if r+shrink_fit-l=floor(charwd*hppp): w:=w+1; r:=r+1;
 else: w:=w-1; r:=r-1; fi fi enddef;
def padded expr del_sharp =
 charht:=charht+del_sharp; chardp:=chardp+del_sharp enddef;

def font_setup =
 if monospace: let adjust_fit=mono_adjust_fit;
  def mfudged=fudged enddef;
  mono_charic#:=body_height#*slant;
  if mono_charic#<0: mono_charic#:=0; fi
  mono_charwd#:=9u#; define_whole_pixels(mono_charwd);
 else: let adjust_fit=normal_adjust_fit;
  def mfudged= enddef; fi
 if math_fitting: let math_fit=do_math_fit
 else: let math_fit=ignore_math_fit fi;
 define_pixels(u,width_adj,serif_fit,cap_serif_fit,jut,cap_jut,beak,
  bar_height,dish,bracket,beak_jut,stem_corr,vair_corr,apex_corr);
 define_blacker_pixels(notch_cut,cap_notch_cut);
 define_whole_pixels(letter_fit,fine,crisp,tiny);
 define_whole_vertical_pixels(body_height,asc_height,
  cap_height,fig_height,x_height,comma_depth,desc_depth,serif_drop);
 define_whole_blacker_pixels(thin_join,hair,stem,curve,flare,
  dot_size,cap_hair,cap_stem,cap_curve);
 define_whole_vertical_blacker_pixels(vair,bar,slab,cap_bar,cap_band);
 define_corrected_pixels(o,apex_o);
 forsuffixes $=hair,stem,cap_stem:
  fudged$.#:=fudge*$.#; fudged$:=hround(fudged$.#*hppp+blacker);
  forever: exitif fudged$>.9fudge*$; fudged$:=fudged$+1; endfor endfor
 rule_thickness:=ceiling(rule_thickness#*hppp);
 heavy_rule_thickness:=ceiling(3rule_thickness#*hppp);
 oo:=vround(.5o#*hppp*o_correction)+eps;
 apex_oo:=vround(.5apex_o#*hppp*o_correction)+eps;
 lowres_fix(stem,curve,flare) 1.3;
 lowres_fix(stem,curve) 1.2;
 lowres_fix(cap_stem,cap_curve) 1.2;
 lowres_fix(hair,cap_hair) 1.2;
 lowres_fix(cap_band,cap_bar,bar,slab) 1.2;
 stem':=hround(stem-stem_corr); cap_stem':=hround(cap_stem-stem_corr);
 vair':=vround(vair+vair_corr);
 vstem:=vround .8[vair,stem]; cap_vstem:=vround .8[vair,cap_stem];
 ess:=(ess#/stem#)*stem; cap_ess:=(cap_ess#/cap_stem#)*cap_stem;
 dw:=(curve#-stem#)*hppp; bold:=curve#*hppp+blacker;
 dh#:=.6designsize;
 stem_shift#:=if serifs: 2stem_corr# else: 0 fi;
 more_super:=max(superness,sqrt .77superness);
 hein_super:=max(superness,sqrt .81225258superness); % that's $2^{-.3}$
 clear_pen_memory;
 if fine=0: fine:=1; fi
 forsuffixes $=fine,crisp,tiny:
%%% fine $ %%%% temporary formatting convention for MFT
  if $>fudged.hair: $:=fudged.hair; fi
  $.breadth:=$;
  pickup if $=0: nullpen else: pencircle scaled $; $:=$-eps fi;
  $.nib:=savepen; breadth_[$.nib]:=$;
  forsuffixes $$=lft,rt,top,bot: shiftdef($.$$,$$ 0); endfor endfor
%%% @ $ %%%% restore ordinary formatting for $
 min_Vround:=max(fine.breadth,crisp.breadth,tiny.breadth,2); % "WRITE WHITE" ONLY!
 if min_Vround<vround min_Vround: min_Vround:=vround min_Vround; fi
 if flare<vround flare: flare:=vround flare; fi
 forsuffixes $=vair,bar,slab,cap_bar,cap_band,vair',vstem,cap_vstem,bold:
  if $<min_Vround: $:=min_Vround; fi endfor
 pickup pencircle scaled rule_thickness; rule.nib:=savepen;
 math_axis:=good.y(math_axis#*hppp);
 pickup pencircle scaled if hefty:(.6[vair,fudged.hair]) else:fudged.hair fi;
 light_rule.nib:=savepen;
 pickup pencircle xscaled cap_curve yscaled cap_hair rotated 30;
 cal.nib:=savepen;
 pair cal.extension; cal.extension:=(.75cap_curve,0) rotated 30;
 pickup pencircle xscaled cap_curve yscaled cap_hair rotated 70;
 tilted.nib:=savepen;
 pickup pencircle xscaled curve yscaled cap_hair rotated 70;
 med_tilted.nib:=savepen;
 pickup pencircle xscaled cap_stem yscaled cap_hair rotated 30;
 med_cal.nib:=savepen;
 pickup pencircle xscaled stem yscaled cap_hair rotated 30;
 light_cal.nib:=savepen;
 pickup pencircle xscaled(cap_curve+dw) yscaled cap_hair rotated 30;
 heavy_cal.nib:=savepen;
 bot_flourish_line:=-.5u-o;
 pair bend; bend=(.5u,0);
 pair flourish_change; flourish_change=(4u,.2asc_height);
 join_radius:=u;
 currenttransform:=identity slanted slant
  yscaled aspect_ratio scaled granularity;
 if currenttransform=identity: let t_=relax
 else: def t_ = transformed currenttransform enddef fi;
 numeric paren_depth#; .5[body_height#,-paren_depth#]=math_axis#;
 numeric asc_depth#; .5[asc_height#,-asc_depth#]=math_axis#;
 body_depth:=desc_depth+body_height-asc_height;
 shrink_fit:=1+hround(2letter_fit#*hppp)-2letter_fit;
 if not string mode: if mode<=smoke: shrink_fit:=0; fi fi
forsuffixes $=thin_join,hair,curve,flare,dot_size,cap_hair,cap_curve,
 vair,bar,slab,cap_bar,cap_band,stem',cap_stem',vair',fudged.hair,
 fudged.stem,fudged.cap_stem: $:=max($,2); endfor % "WRITE WHITE" ONLY!
 enddef;

def shiftdef(suffix $)(expr delta) =
 vardef $ primary x = x+delta enddef enddef;

def makebox(text rule) =
 for y=0,asc_height,body_height,x_height,bar_height,-desc_depth,-body_depth:
  rule((l,y)t_,(r,y)t_); endfor % horizontals
 for x=l,r:   rule((x,-body_depth)t_,(x,body_height)t_); endfor % verticals
 for x=u*(1+floor(l/u)) step u until r-1:
  rule((x,-body_depth)t_,(x,body_height)t_); endfor % more verticals
 if charic<>0:
  rule((r+charic*pt,h.o_),(r+charic*pt,.5h.o_)); fi % italic correction
 enddef;
def maketicks(text rule) =
 for y=0,h.o_,-d.o_:
  rule((l,y),(l+10,y)); rule((r-10,y),(r,y)); endfor % horizontals
 for x=l,r:
  rule((x,10-d.o_),(x,-d.o_)); rule((x,h.o_-10),(x,h.o_)); endfor % verticals
 if charic<>0:
  rule((r+charic*pt,h.o_-10),(r+charic*pt,h.o_)); fi % italic correction
 enddef;
rulepen:=pensquare;

vardef stroke text t =
 forsuffixes e = l,r: path_.e:=t; endfor
 if cycle path_.l:
  errmessage "Beware: `stroke' isn't intended for cycles"; fi
 path_.l -- reverse path_.r -- cycle enddef;

vardef circ_stroke text t =
 forsuffixes e = l,r: path_.e:=t; endfor
 if cycle path_.l:
  errmessage "Beware: `stroke' isn't intended for cycles"; fi
 path_.l -- reverse path_.r .. cycle enddef;

vardef super_arc.r(suffix $,$$) = % outside of super-ellipse
 pair center,corner;
 if y$=y$r: center=(x$$r,y$r); corner=(x$r,y$$r);
 else: center=(x$r,y$$r); corner=(x$$r,y$r); fi
 z$.r{corner-z$.r}...superness[center,corner]{z$$.r-z$.r}
  ...{z$$.r-corner}z$$.r enddef;

vardef super_arc.l(suffix $,$$) = % inside of super-ellipse
 pair center,corner;
 if y$=y$r: center=(x$$l,y$l); corner=(x$l,y$$l);
 else: center=(x$l,y$$l); corner=(x$$l,y$l); fi
 z$l{corner-z$l}...superness[center,corner]{z$$l-z$l}
  ...{z$$l-corner}z$$l enddef;

vardef pulled_super_arc.r(suffix $,$$)(expr superpull) =
 pair center,corner;
 if y$=y$r: center=(x$$r,y$r); corner=(x$r,y$$r);
 else: center=(x$r,y$$r); corner=(x$$r,y$r); fi
 z$r{corner-z$r}...superness[center,corner]{z$$r-z$r}
  ...{z$$r-corner}z$$r enddef;

vardef pulled_super_arc.l(suffix $,$$)(expr superpull) =
 pair center,corner,outer_point;
 if y$=y$r: center=(x$$l,y$l); corner=(x$l,y$$l);
  outer_point=superness[(x$$r,y$r),(x$r,y$$r)];
 else: center=(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[center,corner],outer_point]{z$$l-z$l}
  ...{z$$l-corner}z$$l enddef;

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

vardef serif_arc(suffix $,$$) =
 z${x$$-x$,0}...(.75[x$,x$$],.25[y$,y$$]){z$$-z$}...{0,y$$-y$}z$$ enddef;

vardef penpos@#(expr b,d) =
 if known b: if b<=0: errmessage "bad penpos"; fi fi
 (x@#r-x@#l,y@#r-y@#l)=(b,0) rotated d;
 x@#=.5(x@#l+x@#r); y@#=.5(y@#l+y@#r) enddef;

newinternal currentbreadth;
vardef pos@#(expr b,d) =
 if known b: if b<=currentbreadth: errmessage "bad pos"; fi fi
 (x@#r-x@#l,y@#r-y@#l)=(b-currentbreadth,0) rotated d;
 x@#=.5(x@#l+x@#r); y@#=.5(y@#l+y@#r) enddef;
def numeric_pickup_ primary q =
 currentpen:=pen_[q];
 pen_lft:=pen_lft_[q];  pen_rt:=pen_rt_[q];
 pen_top:=pen_top_[q];  pen_bot:=pen_bot_[q];
 currentpen_path:=pen_path_[q];
 if known breadth_[q]: currentbreadth:=breadth_[q]; fi enddef;

vardef ic# = charic enddef;
vardef h# = charht enddef;
vardef w# = charwd enddef;
vardef d# = chardp enddef;

let {{=begingroup; let }}=endgroup;
def .... = .. tension atleast .9 .. enddef;
def less_tense = save ...; let ...=.... enddef;
def ?? = hide(showvariable x,y) enddef;

let semi_ =;; let colon_ = :; let endchar_ = endchar;
def iff expr b = if b:let next_=use_it else:let next_=lose_it fi; next_ enddef;
def use_it = let : = restore_colon; enddef;
def restore_colon = let : = colon_; enddef;
def lose_it = let endchar=fi; inner cmchar; let ;=fix_ semi_ if false enddef;
def fix_=let ;=semi_; let endchar=endchar_; outer cmchar; enddef;
def always_iff = let : = endgroup; killboolean enddef;
def killboolean text t = use_it enddef;
outer cmchar;