%%% ====================================================================
%%% @METAFONT-file{
%%% author = "Alan Jeffrey",
%%% version = "1.1",
%%% date = "02 June 1992",
%%% time = "13:26:18 BST",
%%% filename = "arrows.mf",
%%% address = "School of Cognitive and Computing Sciences
%%% University of Sussex
%%% Brighton BN1 9QH
%%% UK",
%%% telephone = "+44 273 606755 x 3238",
%%% FAX = "+44 273 678188",
%%% checksum = "02505 188 855 6803",
%%% email = "alanje@cogs.sussex.ac.uk",
%%% codetable = "ISO/ASCII",
%%% keywords = "diagrams, metafont, arrows",
%%% supported = "yes",
%%% abstract = "This is a metafont program which provides
%%% commands for drawing arrows",
%%% docstring = "This is part of the diagramf package which
%%% interfaces TeX and metafont. It is
%%% described in diagramf.tex.
%%%
%%% Copyright 1992 Alan Jeffrey.
%%%
%%% The checksum field above contains a CRC-16
%%% checksum as the first value, followed by the
%%% equivalent of the standard UNIX wc (word
%%% count) utility output of lines, words, and
%%% characters. This is produced by Robert
%%% Solovay's checksum utility.",
%%% package = "diagramf",
%%% dependencies = "none",
%%% maintainer = "Jeremy Gibbons",
%%% address-maintainer = "Department of Computer Science
%%% University of Aukland
%%% Private Bag
%%% Aukland
%%% New Zealand",
%%% email-maintainer = "jeremy@cs.aukuni.ac.nz",
%%% }
%%% ====================================================================
%%%
%%% 25 Oct 1990, v1.0: Released version 1.0.
%%%
%%% 2 Jun 1992, v1.1: Added standard headers.
% This program draws arrows---if you say drawarrow p, where p is a
% path, you get p drawn with an arrowhead at the end. Actually, you
% don't quite get p, as we have to chop a bit off the end, so you get
%
% *
% *
% ******
% *******
% ******
% *
% *
%
% rather than
%
% *
% *
% *******
% *******
% *******
% *
% *
%
% Also the path gets straightened out a bit, so paths which end in
% very tight curves usually get drawn OK.
%
% The parameters we need are
%
% arrowheadcrisp --- the value of crisp (see cmbase) for arrowheads,
% arrowheadheight --- the height of an arrowhead facing right,
% arrowheadwidth --- the width of an arrowhead facing right,
% arrowheadstraight --- the straightness of an arrowhead (from 0 to 1),
% arrowheadline --- the width of line an arrowhead is drawn with.
% arrowpathstraight --- the length of the straight bit added to a path, and
%
% Their default values are ripped off from cmr10 (apart from
% arrowpathstraight, which I just guesstimated).
if unknown arrowheadcrisp: arrowheadcrisp := 0pt; fi
if unknown arrowheadheight: arrowheadheight := 120/36pt; fi
if unknown arrowheadwidth: arrowheadwidth := 60/36pt; fi
if unknown arrowheadstraight: arrowheadstraight := .381966; fi
if unknown arrowheadline: arrowheadline := 11/36pt; fi
if unknown arrowpathstraight: arrowpathstraight := 2.5arrowheadline; fi
% To begin with, a couple of path intersectors --- p joinedpath q
% draws p until it intersects with q, then draws the rest of q.
tertiarydef p joinedpath q =
begingroup
numeric t,u;
(t,u) = p intersectiontimes q;
(subpath (0,t) of p) .. (subpath (u,infinity) of q)
endgroup
enddef;
% And p uptopath q is p until in intersects with q.
tertiarydef p uptopath q =
subpath (0, xpart (p intersectiontimes q)) of p
enddef;
% And a declaration localpen that saves all the variables associated
% with the current pen, and gives you fresh ones to play with.
def localpen =
interim pen_lft:=0;
interim pen_rt:=0;
interim pen_top:=0;
interim pen_bot:=0;
interim currentbreadth:=0;
save currentpen, currentpen_path;
pen currentpen;
path currentpen_path;
enddef;
% pos is nicked from cmbase.
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;
% And arrowheadcrisp.nib is just a scaled pencircle.
pickup pencircle scaled arrowheadcrisp;
arrowheadcrisp.nib := savepen;
% We can now draw an unstraightened arrow. This is just ripped off
% from the cmr symbol font.
def drawunstraightenedarrow expr p =
begingroup;
save x, y, theta;
theta = angle (direction (length p) of p);
begingroup
localpen;
pickup arrowheadcrisp.nib;
z0 = point (length p) of p;
pos3 (arrowheadline,theta+180);
pos4 (arrowheadline,theta+180);
z3 = z0 + (-arrowheadwidth,.5arrowheadheight) rotated theta;
z4 = z0 + (-arrowheadwidth,-.5arrowheadheight) rotated theta;
pos5 (arrowheadline,angle(z3-z0));
pos6 (arrowheadline,angle(z4-z0));
z5l = z6l = z0;
z9 = arrowheadstraight[.5[z3,z4],z0];
filldraw (z5l..z4l{z4-z9})
-- ((z4r{z9-z4}..z5r) joinedpath (z6r..z3r{z3-z9}))
-- (z3l{z9-z3}..z6l)
-- cycle;
endgroup;
draw p uptopath (z4r{z9-z4}..z5r);
endgroup;
enddef;
% We then straighten a path by taking the last section of it, keeping
% its control points, but moving the last point back by
% arrowpathstraight, and putting in a straight line at the end.
def straightenpath expr p =
subpath (0,length p - 1) of p
.. controls (postcontrol (length p - 1) of p)
and (precontrol (length p) of p)
.. arrowpathstraight
* (unitvector (- (direction (length p) of p)))
+ (point (length p) of p)
-- point (length p) of p
enddef;
% Finally, we draw an arrow as an unstraightened arrow of a
% straightened path.
def drawarrow = drawunstraightenedarrow straightenpath enddef;