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