%%% ====================================================================
%%%  @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;
