%% %% This is file `grafbase.mp', %% generated with the docstrip utility. %% %% The original source files were: %% %% grafbase.dtx (with options: `MP') %% %% ------------------------------------------------------------------- %% %% Copyright 2002--2003, Daniel H. Luecking %% %% Mfpic consists of the 3 files mfpic.dtx, grafbase.dtx and mfpic.ins %% and the 5 files they generate: mfpic.tex, mfpic.sty, grafbase.mf, %% grafbase.mp, and dvipsnam.mp. %% %% Documentation, examples, and ancillary files are separate. See %% readme.1st for a complete list. %% %% Mfpic may be distributed and/or modified under the conditions of the %% LaTeX Project Public License, either version 1.2 of this license or (at %% your option) any later version. The latest version of this license is in %% %% http://www.latex-project.org/lppl.txt %% %% and version 1.2 or later is part of all distributions of LaTeX version %% 1999/12/01 or later. %% %% With respect to the proposed draft LPPL-1.3: mfpic has maintenance %% status "maintained". The Current Maintainer is Daniel H. Luecking. There %% are several Base Interpreters: TeX, LaTeX, MetaPost and Metafont. %% string fileversion, filedate; fileversion := "0.7a beta"; filedate := "2004/04/16"; def GBmsg expr s = message "Grafbase: " & s; enddef; def GBerrmsg (expr s) expr t = errhelp t; errmessage "Grafbase: "& s; errhelp ""; enddef; if (known grafbaseversion) or (known grafbase) : GBmsg "You have loaded grafbase more than once! " & "Please make sure that it is loaded only once."; endinput; fi boolean grafbase; grafbase := true; boolean MFPIC; MFPIC := false; def checkversions (expr g)= numeric grafbaseversion; grafbaseversion := g; if unknown mfpicversion : % no mfpic, or < 0.63 GBmsg "Recent mfpic not detected."; elseif g = mfpicversion : MFPIC := true; else: GBerrmsg ("version mismatch") "The installation may be broken: mfpic and grafbase " & "versions do not match."; fi enddef; checkversions (70); if unknown base_name : input plain; elseif not string base_name : input plain; elseif base_name <> "plain" : input plain; fi boolean METAPOST; if known color Maurits Cornelis Escher : METAPOST := true; else: METAPOST := false; fi if not METAPOST : GBerrmsg ("wrong compiler") "You may have input to Metafont a file designed for Metapost. " & "Instead of the file grafbase.mp, Metafont should be using " & "grafbase.mf. Make sure the extension was not changed."; fi if (unknown debug) or (not boolean debug) : boolean debug; debug := false; fi def GBdebug = begingroup save >>; def >> = message enddef; >> "Grafbase DEBUG: "; enddef; def GBenddebug = >> "End DEBUG"; endgroup enddef; vardef mftitle expr t = t; message t; enddef; pt# := 1pt; def t_ = transformed currenttransform enddef; if unknown aspect_ratio: aspect_ratio := 1; fi if unknown hppp : hppp := 1 fi; if unknown currenttransform : transform currenttransform; currenttransform := identity yscaled aspect_ratio; fi interim warningcheck := 0; numeric unitlen, xscale, yscale, xneg, xpos, yneg, ypos; unitlen := 1 bp; xscale := 7.2; % (xscale * unitlen) = 1/10 inch yscale := 7.2; % (yscale * unitlen) = 1/10 inch xneg := 0; xpos := 10; yneg := 0; ypos := 10; newinternal radian, pi, deg; deg := 1; pi := 3.14159; radian := 180/pi; newinternal penwd; penwd := 0.5pt; pen drawpen; def resizedrawpen (expr s) = interim penwd := s; setvariable (pen) (drawpen) (pencircle scaled penwd); save currentpen; pen currentpen; pickup drawpen; enddef; numeric hatchwd; hatchwd := 0.5bp; pen hatchpen; hatchpen := pencircle scaled hatchwd; boolean clipall; clipall := false; boolean ClipOn; ClipOn := false; path ClipPath[]; numeric ClipPath; ClipPath = 0; boolean truebbox; truebbox := false; def DoClip (suffix v) = if ClipOn and (ClipPath > 0) : clipsto (v, ClipPath); fi enddef; def noclip (text t) = hide( save ClipOn; boolean ClipOn; ClipOn := false; t) enddef; boolean showbbox; showbbox := false; def _wc_ = withcolor enddef; color currentcolor, fillcolor, drawcolor, hatchcolor, headcolor, pointcolor, tlabelcolor, background; currentcolor := fillcolor := drawcolor := hatchcolor := headcolor := pointcolor := tlabelcolor := black; background := white; vardef snapto expr t = if unknown t : 0 elseif not (numeric t) : 0 elseif t < 0 : 0 elseif t > 1 : 1 else : t fi enddef; vardef gray (expr g) = (snapto g)*white enddef; vardef makeclr (expr r, g, b) = (r, g, b) enddef; vardef rgb (expr r, g, b) = makeclr (snapto r, snapto g, snapto b) enddef; vardef cmyk (expr c, m, y, k) = rgb (1-c-k, 1-m-k, 1-y-k) enddef; vardef RGB (expr R, G, B) = rgb (R/255, G/255, B/255) enddef; vardef named (suffix c) = forceclr (c) enddef; vardef forceclr (expr c) = if unknown c : black elseif numeric c : gray (c) elseif color c : c else : black fi enddef; color red, green, blue, cyan, magenta, yellow; red := rgb (1, 0, 0); green := rgb (0, 1, 0); blue := rgb (0, 0, 1); cyan := rgb (0, 1, 1); magenta := rgb (1, 0, 1); yellow := rgb (1, 1, 0); vardef list (suffix v) (text lst) = v := 0; for _itm = lst: v[incr v] := _itm; endfor enddef; def map (text proc) (text lst) = hide(_map := 0;) for _a = lst : if _map = 0 : hide(_map := 1;) else: , fi proc(_a) endfor enddef; vardef knownarray suffix arr = save _kna; boolean _kna; _kna := (known arr) and (numeric arr); if _kna : _kna := (arr = floor arr) and (arr >= 1); for _idx = 1 upto arr : exitif not _kna; _kna := known arr[_idx]; endfor fi _kna enddef; def copyarray(suffix from, to) = to := 0; for _idx = 1 upto from: to[incr to] := from[_idx]; endfor enddef; def maparr (text proc) (suffix p) = for _idx = 1 upto p: proc (p[_idx]); endfor enddef; def textpairs (suffix p) (text t) = numeric p; pair p[]; list (p) (t); enddef; vardef chpair (text proc) (expr p) = (proc (xpart p), proc (ypart p)) enddef; vardef floorpair (expr p) = chpair (floor) (p) enddef; vardef ceilingpair (expr p) = chpair (ceiling) (p) enddef; vardef emin (expr a, b) = if a < b : a else: b fi enddef; vardef emax (expr a, b) = if a > b : a else: b fi enddef; vardef pairmin (expr z, w) = ( emin (xpart z, xpart w), emin (ypart z, ypart w ) ) enddef; vardef pairmax (expr z, w) = ( emax (xpart z, xpart w), emax (ypart z, ypart w ) ) enddef; vardef minpair (suffix p) = save _mp; pair _mp; _mp := p1; for _idx = 2 upto p - 1 : _mp := pairmin(_mp, p[_idx]); endfor pairmin (_mp, p[p]) enddef; vardef maxpair (suffix p) = save _mp; pair _mp; _mp := p1; for _idx = 2 upto p - 1: _mp := pairmax(_mp, p[_idx]); endfor pairmax (_mp, p[p]) enddef; transform ztr, vtr; def setztr = if debug : GBdebug; >> "w_ = " & decimal w_ & "bp"; >> "h_ = " & decimal h_ & "bp"; >> "unitlen = " & decimal unitlen & "bp"; >> "xneg = " & decimal xneg; >> "xpos = " & decimal xpos; >> "yneg = " & decimal yneg; >> "ypos = " & decimal ypos; >> "xscale = " & decimal xscale; >> "yscale = " & decimal yscale; GBenddebug; fi save ztr, vtr; transform ztr, vtr; vtr := identity xscaled (xscale) yscaled (yscale) scaled (unitlen*hppp); ztr := identity shifted (-(xneg, yneg)) transformed vtr; if debug : GBdebug; >> "ztr: "; show ztr; >> "vtr: "; show vtr; GBenddebug; fi enddef; vardef zconv (expr a) = a transformed ztr enddef; vardef invzconv (expr a) = a transformed (inverse ztr) enddef; vardef vconv (expr v) = v transformed vtr enddef; vardef invvconv (expr v) = v transformed (inverse vtr) enddef; def active_plane = currentpicture enddef; boolean overlaylabels; overlaylabels = false; def initpic = setztr; resizedrawpen (penwd); if ClipOn : ClipPath := 1; ClipPath1 := rect (origin, (w_, h_)); fi if debug : GBdebug; >> "Drawing nominal bounding box around picture"; GBenddebug; noclip ( safedraw rect (origin, (w_, h_)) ); fi save current_labels; picture current_labels; current_labels := nullpicture; save labelbb; pair labelbb.ll, labelbb.ur; labelbb.ll := labelbb.ur := origin; enddef; def mfpicenv = enddef; def endmfpicenv = enddef; def bounds (expr a, b, c, d) = xneg := a; xpos := b; yneg := c; ypos := d; enddef; def setvariable (text kind) (suffix name) (expr value) = save name; kind name; name := value; enddef; string extra_beginmfpic; extra_beginmfpic := ""; string extra_endmfpic; extra_endmfpic := ""; def beginmfpic (expr ch) = beginfig (ch); gcode := ch; save w_, h_, d_; numeric w_, h_, d_; charwd := (xpos-xneg)*xscale*unitlen; charht := (ypos-yneg)*yscale*unitlen; chardp := 0; w_ := charwd; h_ := charht; d_ := chardp; initpic; scantokens extra_beginmfpic; enddef; def endmfpic = scantokens extra_endmfpic; if debug : GBdebug; >> "width = " & decimal w_ & "bp"; >> "height = " & decimal h_ & "bp"; GBenddebug; fi DoClip (active_plane); if clipall : clipto (active_plane) rect(origin, (w_, h_)); fi if showbbox : noclip ( safedraw rect (origin, (w_, h_)) ); fi save _ll, _ur; pair _ll, _ur; if truebbox : _ll := llcorner active_plane; _ur := urcorner active_plane; elseif clipall: _ll := origin; _ur := (w_,h_); else: % expand to accomodate labels _ll := pairmin((0, 0 ), labelbb.ll); _ur := pairmax((w_, h_), labelbb.ur); fi _ur := pairmax(_ur, _ll + eps*(1, 1)); setbounds active_plane to rect(_ll, _ur); addto active_plane also current_labels; endfig; enddef; pair label_adjust; label_adjust := (0, 0); numeric label_sep; label_sep := 0; vardef newgblabel (expr hf, vf, BL, r) (expr s) (text pts) = save _lab, _ll, _ur; picture _lab; pair _ll, _ur; _lab := if picture s : s elseif string s : s infont defaultfont scaled defaultscale elseif path s : picpath (s) else : nullpicture fi; labeldims (origin, _lab) (_ll, _ur); _lab := thegblabel(ref_shift (hf, vf, BL, _ll, _ur), r, _lab); save _b; pair _b; for _itm = pts : _b := zconv(_itm); if overlaylabels : addto current_labels also _lab shifted _b _wc_ tlabelcolor; else: addto active_plane also _lab shifted _b _wc_ tlabelcolor; labelbb.ll := pairmin (_b + llcorner _lab, labelbb.ll); labelbb.ur := pairmax (_b + urcorner _lab, labelbb.ur); fi endfor enddef; vardef gblabel (expr a, b, c, d, r) (expr s) (text t) = newgblabel (b, d, (c = 0) and (d = 0), r) (s) (t); enddef; vardef ref_shift (expr hf, vf, BL, ll, ur) = - ( (hf)[xpart ll, xpart ur], (vf)[if BL: 0 else: (ypart ll) fi, ypart ur] ) enddef; vardef thegblabel (expr z, r, p) = ((p shifted z) rotated r) shifted label_adjust enddef; vardef textrect (expr lbl, rad, loc) = textrectx (.5, .5, false, 0) (origin, lbl, rad, loc) enddef; vardef textoval (expr lbl, mult, loc) = xellipse (true, .5, .5, false, 0) (origin, lbl, mult, loc) enddef; vardef textellipse (expr lbl, rat, loc) = xellipse (false, .5, .5, false, 0) (origin, lbl, rat, loc) enddef; boolean roundends; roundends := true; vardef textrectx (expr a, b, c, rot, xy, lbl, rad, loc) = save ll, ur, _r, f, zz; pair ll, ur, zz; path f; labeldims (xy, lbl) (ll, ur); _r := if boolean rad : if rad : emin (xpart (ur-ll), ypart (ur-ll))/sqrt(2) else: 0 fi elseif numeric rad : rad else: 0 fi; if _r = 0 : f := rect(ll, ur); else: save p, q; pair p[]; path q; p1 := ur - _r*dir(45); % center of upper right arc p3 := ll + _r*dir(45); % lower left p2 := (xpart p3, ypart p1); % upper left p4 := (xpart p1, ypart p3); % lower right q := quartercircle scaled 2_r; if _r > 0: f := (q shifted p1) -- (q rotated 90 shifted p2) -- (q rotated 180 shifted p3) -- (q rotated -90 shifted p4) -- cycle; else: f := (q shifted p1) -- (q rotated -90 shifted p4) -- (q rotated 180 shifted p3) -- (q rotated 90 shifted p2) -- cycle; fi fi invvconv(thegblabel(ref_shift(a, b, c, ll, ur), rot, f)) shifted loc enddef; def textovalx = xellipse (true) enddef; def textellipsex = xellipse (false) enddef; vardef xellipse (expr aspect, a, b, c, r, xy, lbl, mult, loc) = if mult = 0 : textrectx (a, b, c, r) (xy, lbl, 0, loc) else: save ll, ur, cc, ww, hh, f; pair ll, ur, cc; path f; labeldims (xy, lbl) (ll, ur); cc := .5[ll, ur]; % center (ww, hh) = ur - cc; if (ww = 0) or (hh = 0) : % make a line: f = (ll--ur); else: save aa, bb, mm; mm := if aspect : ww/hh*mult else: mult fi; aa := ww ++ hh*mm; bb := aa/mm; f := ellipse(cc, aa, bb, 0); fi invvconv(thegblabel (ref_shift (a, b, c, ll, ur), r, f)) shifted loc fi enddef; def labeldims (expr xy, lbl) (suffix ll, ur) = if pair lbl : ll := xy; ur := lbl; else: save _lbl; picture _lbl; _lbl := if picture lbl : lbl elseif string lbl : lbl infont defaultfont scaled defaultscale elseif path lbl : picpath (lbl) else : nullpicture fi; ll := llcorner _lbl; ur := urcorner _lbl; fi ll := ll - label_sep*(1, 1); ur := ur + label_sep*(1, 1); enddef; newinternal nottoosmall; nottoosmall := eps/2 + 2epsilon; newinternal reallysmall; reallysmall := 3epsilon; def signof (expr X) = if X < 0 : - fi enddef; def TruncateWarn expr s = GBmsg s & " too large; truncating"; enddef; vardef secd primary X = save temp; temp := cosd(X); if abs(temp) < reallysmall : TruncateWarn "Secant"; temp := signof (temp) reallysmall; fi 1/temp enddef; vardef tand primary X = sind(X)*secd(X) enddef; vardef cscd primary X = save temp; temp := sind(X); if abs(temp) < reallysmall : TruncateWarn "Cosecant"; temp := signof(temp) reallysmall; fi 1/temp enddef; vardef cotd primary X = cosd(X)*cscd(X) enddef; vardef acos primary X = angle (X, 1 +-+ X) enddef; vardef asin primary X = angle (1 +-+ X, X) enddef; vardef atan primary X = angle (1, X) enddef; vardef sin primary X = sind (X*radian) enddef; vardef cos primary X = cosd (X*radian) enddef; vardef tan primary X = tand (X*radian) enddef; vardef cot primary X = cotd (X*radian) enddef; vardef sec primary X = secd (X*radian) enddef; vardef csc primary X = cscd (X*radian) enddef; vardef invcos primary X = (acos X)/radian enddef; vardef invsin primary X = (asin X)/radian enddef; vardef invtan primary X = (atan X)/radian enddef; vardef exp primary X = mexp (256 * X) enddef; vardef ln primary X = (mlog X) / 256 enddef; def log = ln enddef; vardef logbase (expr B) primary X = (mlog X)/(mlog B) enddef; def logtwo = logbase( 2) enddef; def logten = logbase(10) enddef; vardef Arg primary Z = (angle Z)/radian enddef; vardef Log primary Z = (ln(abs(Z)), Arg (Z)) enddef; vardef cis primary T = dir(radian*T) enddef; vardef zexp primary Z = (exp (xpart Z))*(cis(ypart Z)) enddef; vardef sgn primary Z = if Z = origin : origin else: unitvector Z fi enddef; vardef cosh primary X = save temp; temp := 2 exp (-abs(X)); if temp < reallysmall : TruncateWarn "Cosh"; temp := reallysmall; fi 1/temp + temp/4 enddef; vardef sinh primary X = save temp; temp := 2 exp (-abs(X)); if temp < reallysmall : TruncateWarn "Sinh"; temp := reallysmall; fi signof (X) (1/temp - temp/4) enddef; vardef sech primary X = save temp; temp := exp(-(abs (X))); 2temp/(1 + temp*temp) enddef; vardef tanh primary X = save temp; temp := exp(-2(abs (X))); signof (X) (1 - temp)/(1 + temp) enddef; vardef csch primary X = save temp; temp := exp(-(abs (X))); if abs(1 - temp*temp) < reallysmall : TruncateWarn "Csch"; signof (X) 2temp / reallysmall else: signof (X) 2temp / (1 - temp*temp) fi enddef; vardef coth primary X = save temp; temp := tanh(X); if abs(temp) < reallysmall : TruncateWarn "Coth"; temp := signof (temp) reallysmall; fi 1/temp enddef; vardef acosh primary y = if y < 1 : GBerrmsg ("Undefined function: acosh " & decimal y) "If you proceed, a value of 0 will be used. " & "Expect more errors later."; 0 else: ln (y + (y+-+1)) fi enddef; vardef asinh primary y = ln (y + (y++1)) enddef; vardef atanh primary y = if abs (y) < 1 : (ln(1+y) - ln(1-y))/2 else: GBerrmsg ("Undefined function: atanh " & decimal y) "If you proceed, a value of plus or minus infinity " & "will be used. Expect more errors later."; signof (y) infinity fi enddef; vardef polar (expr p) = (xpart p) * dir (ypart p) enddef; def id (expr x) = x enddef; transform T_stack[]; T_stack := 0; def T_push (expr T) = T_stack[incr T_stack] := T; enddef; def T_pop (suffix $) = if T_stack > 0 : $ := T_stack[T_stack]; T_stack := T_stack - 1; fi enddef; def bcoords = hide ( T_push (ztr); T_push (vtr) ) enddef; def ecoords = hide ( T_pop (vtr); T_pop (ztr) ) enddef; def apply_t (text Transformer) = ztr := identity Transformer transformed ztr; vtr := ztr shifted - zconv(origin); enddef; def xslant = slanted enddef; % (x+sy, y). def yslant primary s = % (x, y+sx). transformed begingroup save _T; transform _T; origin transformed _T = origin; (1, 0) transformed _T = (1, s); (0, 1) transformed _T = (0, 1); _T endgroup enddef; def zslant primary p = % (xu+yv, xv+yu), where p = (u, v). transformed begingroup save _T; transform _T; xpart _T = ypart _T = 0; xxpart _T = yypart _T = xpart p; xypart _T = yxpart _T = ypart p; _T endgroup enddef; def xyswap = zslant (0, 1) enddef; def boost primary X = zslant (cosh X, sinh X) enddef; vardef rotatedpath (expr p, th) expr f = f transformed vtr rotatedaround (p transformed vtr, th) transformed (inverse vtr) enddef; vardef scaledpath (expr p, s) expr f = f shifted -p scaled s shifted p enddef; vardef xslantedpath (expr b, s) expr f = f shifted (0, -b) slanted s shifted (0, b) enddef; def slantedpath = xslantedpath enddef; vardef yslantedpath (expr a, s) expr f = f shifted (-a, 0) yslant s shifted (0, a) enddef; vardef xscaledpath (expr a, s) expr f = f shifted (-a, 0) xscaled s shifted (a, 0) enddef; vardef yscaledpath (expr b, s) expr f = f shifted (0, -b) yscaled s shifted (0, b) enddef; vardef shiftedpath (expr v) expr f = f shifted v enddef; vardef reflectedpath (expr p, q) expr f = f transformed vtr reflectedabout (p transformed vtr, q transformed vtr) transformed (inverse vtr) enddef; vardef xyswappedpath expr f = f xyswap enddef; vardef transformedpath (text Transformer) expr f = f Transformer enddef; vardef partialpath (expr a, b) expr f = save p; path p; p := zconv (f) scaled (1/unit_of_length); save cumlen, totlen, idx, ta, tb; totlen := makelengtharray(cumlen) p; idx := 0; if a <= b: ta := gettime (cumlen, idx) (a*totlen); tb := gettime (cumlen, idx) (b*totlen); else: tb := gettime (cumlen, idx) (b*totlen); ta := gettime (cumlen, idx) (a*totlen); fi subpath (ta, tb) of f enddef; vardef gsubpath (expr a, b) expr f = subpath (a, b) of f enddef; def coloraddto (expr clr) (suffix u) (expr v) = addto u also v _wc_ clr; enddef; def orto (suffix u) (expr v) = addto u also v; enddef; vardef interior expr c = save v; picture v; v := nullpicture; addto v contour (c.t_); v enddef; vardef interiors suffix cc = save _ints; picture _ints; _ints := nullpicture; for _idx = 1 upto cc: addto _ints also interior cc[_idx]); endfor _ints enddef; def clipto (suffix vt) expr c = clip vt to c; enddef; def clipsto (suffix vt, cc) = begingroup save _cl, _cl_; picture _cl, _cl_; _cl_ := nullpicture; for _idx = 1 upto cc: _cl := vt; clip _cl to cc[_idx]; addto _cl_ also _cl; endfor vt := _cl_; endgroup enddef; vardef Clipped (suffix vt) expr c = save _Cl; picture _Cl; _Cl := vt; clipto (_Cl) c; _Cl enddef; let clipped_ = clipped; def clipped = Clipped enddef; vardef picneg (suffix vt) expr c = save _pn; picture _pn; _pn := nullpicture; addto _pn (interior c) _wc_ fillcolor; addto _pn also (Clipped (vt) c) _wc_ background; _pn enddef; def shpath (suffix v) (expr q, f) = addto v doublepath (f.t_) withpen (q.t_); enddef; numeric minpenwd; minpenwd := .05bp; % 1 pixel at 1440dpi vardef picpath expr d = save v; picture v; v := nullpicture; if penwd >= minpenwd : shpath (v, drawpen) (d); fi v enddef; def picdot (suffix v) (expr w, p) = addto v also (w shifted p); enddef; vardef setdot (expr apath, sc) = if cycle apath : interior else : picpath fi (apath scaled emax(sc, minpenwd)) enddef; vardef shaded (expr clr) expr c = if cycle c : save v; picture v; v := nullpicture; addto v contour c _wc_ clr; v else: picpath c % should we? or just make it null? fi enddef; vardef filledwith (expr pic, dims, ll, ur) = save b, v; picture b, v; b := v := nullpicture; for s = xpart ll step xpart dims until xpart ur: addto b also pic shifted (s, 0); endfor for s = ypart ll step ypart dims until ypart ur: addto v also b shifted (0, s); endfor v enddef; vardef thatchf (suffix v) (expr CT, sp, a, b) = save _sp; _sp = signof (ypart(b - a)) abs(sp); for _y = _sp*( ceiling ((ypart a)/_sp) ) step _sp until ypart b: shpath (v, hatchpen) ( ( (xpart a, _y)--(xpart b, _y) ) transformed CT ); endfor enddef; def tile (suffix atile) (expr unit, width, height, clipit) = picture atile.pic; atile.pic := nullpicture; numeric atile.wd, atile.ht; (atile.wd, atile.ht) = (width, height)*unit; boolean atile.clipon; atile.clipon := clipit; begingroup save active_plane; def active_plane = atile.pic enddef; save ztr, vtr; transform ztr, vtr; ztr := identity scaled unit; vtr := ztr; save ClipOn; boolean ClipOn; if clipit : ClipOn := true; save ClipPath; path ClipPath[]; ClipPath = 1; ClipPath[1] = rect(origin, (atile.wd, atile.ht)); else: ClipOn := false; fi enddef; def endtile = DoClip (active_plane); endgroup enddef; vardef is_tile (suffix atile) = (known atile.pic ) and (picture atile.pic ) and (known atile.wd ) and (numeric atile.wd ) and (known atile.ht ) and (numeric atile.ht ) and (known atile.clipon) and (boolean atile.clipon) enddef; vardef pnt@# (expr p) = point @# of p enddef; vardef pre@# (expr p) = precontrol @# of p enddef; vardef post@# (expr p) = postcontrol @# of p enddef; vardef gbbox (expr g) (suffix ll, ur) = ll := llcorner g; ur := urcorner g; if showbbox : noclip ( safedraw rect (ll, ur) ); fi enddef; def safedraw = colorsafedraw (drawcolor) enddef; vardef colorsafedraw (expr clr) expr d = save v; picture v; v := picpath d; DoClip (v); coloraddto (clr) (active_plane, v); enddef; def NoCycleWarn expr s = GBmsg s & " cannot be applied to an open path. " & "The path will be drawn instead."; enddef; def safefill = colorsafefill (fillcolor) enddef; vardef colorsafefill (expr clr) expr c = if cycle c : save v; picture v; v := interior c; DoClip (v); coloraddto (clr) (active_plane, v); else: NoCycleWarn "fill"; safedraw c; fi enddef; def safeunfill expr c = if cycle c : noclip (colorsafefill (background) c); else: NoCycleWarn "unfill"; safedraw c; fi enddef; def safeclip expr c = if cycle c : clipto (active_plane) c; else: NoCycleWarn "clip"; safedraw c; fi enddef; def store (suffix fs) expr f = hide( if (not path f) and (not pair f) : GBerrmsg ("Second argument to `store' must be a path or pair") ""; fi if not path fs : path fs; fi fs := f ) enddef; vardef stored (suffix fs) expr f = store (fs) f; f enddef; def drawn = colordrawn (drawcolor) enddef; vardef colordrawn (expr clr) expr f = colorsafedraw (clr) (zconv (f)); f enddef; def filled = colorfilled (fillcolor) enddef; vardef colorfilled (expr clr) expr c = colorsafefill (clr) zconv (c); c enddef; vardef unfilled expr c = safeunfill zconv (c); c enddef; vardef Clip expr c = safeclip zconv(c); c enddef; numeric shadewd; shadewd := 0.5bp; path shadedotpath; shadedotpath := fullcircle; % unitsquare; vardef shade (expr sp) expr f = save g; path g; g := zconv (f); save gr; numeric gr; gr := 1 - (.88*abs(shadewd)/sp)**2; if not cycle g : NoCycleWarn "shade"; safedraw g; elseif gr <= 0 : safefill g; else: colorsafefill (gr*white) g; fi f enddef; polkadotwd := 5bp; mindotspace := 1bp; path polkadotpath; polkadotpath := fullcircle; vardef polkadot (expr sp) expr f = save g; path g; g := zconv (f); if not cycle g : NoCycleWarn "polkadot"; safedraw g; elseif sp <= emax (2*polkadotwd/3, mindotspace) : safefill g; else: save ll, ur; pair ll, ur; gbbox (g, ll, ur); save dx, dy; dx := sp/2; dy := dx*(sqrt 3); hshift := ((xpart (ur - ll)) mod dx)/2; vshift := ((ypart (ur - ll)) mod dy)/2; save p, dims; pair p, dims; p := ll + (hshift, vshift); dims := 2(dx, dy); save v, thepolkadot; picture v, thepolkadot; thepolkadot := setdot (polkadotpath, polkadotwd); v := filledwith (thepolkadot, dims, p, ur); p := p + (dx, dy); orto (v, filledwith (thepolkadot, dims, p, ur)); DoClip (v); clipto (v) g; coloraddto (fillcolor) (active_plane) (v); fi f enddef; def thatch = colorthatch (hatchcolor) enddef; vardef colorthatch (expr clr) (expr sp, theta) expr f = save g; path g; g := zconv (f); if not cycle g : NoCycleWarn "hatch"; safedraw g; elseif sp <= abs(hatchwd) : colorsafefill (clr) g; else: save v; picture v; v := nullpicture; save CT; transform CT; CT := identity rotated theta; save ll, ur; pair ll, ur; gbbox (g transformed inverse CT, ll, ur); thatchf (v, CT, sp, ll, ur); DoClip(v); coloraddto (clr) (active_plane) (Clipped (v) g); fi f enddef; def hhatch (expr sp) = thatch (sp, 0) enddef; def vhatch (expr sp) = thatch (sp, 90) enddef; def lhatch (expr sp) = thatch (sp, -45) enddef; def rhatch (expr sp) = thatch (sp, 45) enddef; def xhatch = colorxhatch (hatchcolor) enddef; vardef colorxhatch (expr clr, sp) expr f = colorthatch (clr) (sp, 45) colorthatch (clr) (sp, -45) f enddef; vardef tess (suffix atile) expr c = save _g; path _g; _g := zconv (c); if not is_tile (atile) : GBerrmsg ("Tile parameter " & str atile & " of tess() is invalid") "This tile may be undefined or incorrectly defined. " & "If you proceed, tess() will be abandoned and the curve " & "merely drawn."; safedraw _g; elseif not cycle _g : NoCycleWarn "tess"; safedraw _g; else: save _ll, _ur; pair _ll, _ur; gbbox (_g, _ll, _ur); save _ts; picture _ts; _ts := filledwith (atile.pic, (atile.wd, atile.ht), _ll, _ur); DoClip (_ts); orto (active_plane, Clipped (_ts) _g); fi c enddef; if unknown segment_split : segment_split := 8; fi if unknown dashsize : dashsize := 3bp; fi if unknown dashgap : dashgap := dashsize + 2penwd; fi if unknown dash_finish : dash_finish := .5; fi if unknown dash_start : dash_start := .5; fi if unknown unit_of_length : unit_of_length := 0.1in; fi vardef gendashed (suffix pat) expr f = save _g; path _g; _g := zconv(f); if (unknown pat.rep) : % no "pattern" GBmsg "Dash pattern " & str pat & " undefined. " & "Path will be drawn instead."; safedraw _g; elseif pat.rep < 2 : % no "spaces" safedraw _g; else: save _dl, _tmppat; forsuffixes _s = start, rep, finish : _dl._s := 0; _tmppat._s := pat._s; for i = 1 upto pat._s : _tmppat._s[i] := pat._s[i]/unit_of_length; _dl._s := _dl._s + _tmppat._s[i]; endfor endfor if _dl.rep = 0 : GBmsg "Dash pattern " & str pat & " has length 0. " & "Path will be drawn instead."; safedraw _g; else: save _p; path _p; _p := _g scaled (1/unit_of_length); save _cumlen, _totlen, _n, _sf; _totlen := makelengtharray(_cumlen) _p; _sf := scale_adjust (_n, _dl)(_totlen); if _n < 0 : safedraw _g; else: forsuffixes _s = start, rep, finish : for _i = 1 upto _tmppat._s : _tmppat._s[_i] := _tmppat._s[_i]*_sf; endfor _dl._s := _dl._s*_sf; endfor save dashingdot; picture dashingdot; if known plot_pic : dashingdot := makesymbol(plot_pic, penwd); else: dashingdot := makesymbol(dotpath, penwd); fi save _ct, _t, _d, _v; picture _v; _v := nullpicture; _ct := 0; % Begin with pat.start _d0 := 0; _t0 := 0; dashit (_tmppat.start) (_v); % then pat.rep if _n > 0 : save _m; _m := ceiling sqrt(_n); for _j = 0 step _m until _n - 1 : for _i = 0 upto _m - 1 : exitif (_i + _j) > _n - 1; _d0 := _dl.start + (_j + _i)*_dl.rep; _t0 := gettime(_cumlen, _ct) (_d0); dashit (_tmppat.rep) (_v); endfor % add _m patterns and reset. DoClip(_v); coloraddto (drawcolor) (active_plane, _v); _v := nullpicture; endfor fi % and finally, pat.finish _d0 := _totlen - _dl.finish; _t0 := gettime(_cumlen, _ct) (_d0); dashit (_tmppat.finish) (_v); DoClip(_v); coloraddto (drawcolor) (active_plane, _v); fi fi fi f enddef; vardef makelengtharray (suffix clen) expr p = save _s; _s := emax (1, ceiling segment_split); clen := _s*length p; clen[0] := 0; for _i = 1 upto clen : clen[_i] := clen[_i-1] + abs (pnt[_i/_s] (p) - pnt[(_i-1)/_s] (p)); endfor clen[clen] enddef; vardef scale_adjust (suffix n, pl) (expr lngth) = n := (lngth - pl.start - pl.finish)/pl.rep; n := if n < 0 : -1 else: round(n) fi; lngth/(pl.start + emax(n, 0)*pl.rep + pl.finish) enddef; vardef gettime (suffix arr, ct) (expr lngth) = save _gtl, _s; _s := emax(1, ceiling segment_split); _gtl := emax (arr[ct], emin (arr[arr], lngth)); forever: exitif ( (arr[ct] <= _gtl) and (_gtl <= arr[ct+1]) ); ct := ct + 1; % need to exit *before* incrementing endfor if arr[ct] = arr[ct+1] : ct else: ( ct + (_gtl - arr[ct]) / (arr[ct+1] - arr[ct]) ) fi /_s enddef; def dashit (suffix pos) (suffix pic) = for _k = 1 upto pos: if odd _k : % draw a dash of length pos[_k] if pos[_k] = 0 : % point required _d1 := _d0; _t1 := _t0; picdot (pic, dashingdot, pnt [_t0] (_g)); else: _d1 := _d0 + pos[_k]; _t1 := gettime (_cumlen, _ct) (_d1); shpath (pic, drawpen) (subpath (_t0, _t1) of _g); fi else: % find the start of the next dash: _d0 := _d1 + pos[_k]; _t0 := gettime(_cumlen, _ct) (_d0); fi endfor enddef; def dashpat (suffix pat) (text t) = pat.rep := 0; for _itm = t: pat.rep[incr pat.rep] := _itm; endfor; if odd (pat.rep) and (pat.rep > 1): pat.rep[incr pat.rep] := 0; fi pat.start := 1; pat.start[1] := pat.rep[1]*dash_start; for _idx = 2 upto pat.rep : pat.start[incr pat.start] := pat.rep[_idx]; endfor pat.finish := 1; pat.finish[1] := pat.rep[1]*dash_finish; enddef; vardef DASHED (expr dlen, dgap) expr f = save dashes; dashpat (dashes) (dlen, dgap); gendashed (dashes) f enddef; let dashed_ = dashed; def dashed = DASHED enddef; vardef doplot (expr spath, sc, dgap) expr f = save dots; dashpat (dots) (0, dgap); save plot_pic; picture plot_pic; plot_pic := makesymbol (spath, sc); gendashed (dots) f enddef; path dotpath; dotpath := fullcircle; vardef dotted (expr dsize, dgap) expr f = doplot (dotpath, dsize, dgap) f enddef; vardef plotnodes (expr symbol, size) expr f = save _pln; pair _pln[]; _pln := 0; for _a = 0 upto (length f) if cycle f : - 1 fi : _pln[incr _pln] := pnt[_a] (f); endfor dosymbols (drawcolor, symbol, size) (_pln); f enddef; vardef centerit (expr pic) = pic shifted -(0.5[urcorner pic, llcorner pic]); enddef; vardef makesymbol (expr spath, sc) = if path spath : setdot (spath, sc) elseif picture spath : spath elseif string spath : spath infont defaultfont scaled defaultscale else: GBmsg "Undefined symbol for plotting, using dotpath instead."; setdot (dotpath, sc) fi enddef; path Triangle, Square, Circle, Diamond, Star, Plus, Cross, Asterisk, SolidTriangle, SolidSquare, SolidCircle, SolidDiamond, SolidStar; Triangle := (for n = 0 upto 2: (up rotated 120n)-- endfor up) scaled .78; SolidTriangle := Triangle & cycle; Square := (for n = 0 upto 3: dir (90n + 45)-- endfor dir 45) scaled .63; SolidSquare := Square & cycle; Circle := halfcircle & halfcircle rotated 180; SolidCircle := Circle & cycle; Diamond := (Square rotated 45) xscaled (1/1.2) yscaled 1.2; SolidDiamond := Diamond & cycle; Plus := (origin for n = 0 upto 3: --(up rotated 90n)--origin endfor) scaled .65; Cross := Plus rotated 45; Asterisk := (origin for n = 0 upto 5: --(up rotated 60n)--origin endfor) scaled .6; pair zz; zz = (whatever)[up, up rotated 144]; zz = (whatever)[up rotated 72, up rotated -72]; Star := (for n = 0 upto 4: (up rotated 72n)--(zz rotated 72n)-- endfor up) scaled .84; SolidStar := Star & cycle; save zz; numeric dashtype; forsuffixes s = start, rep, finish : numeric dashtype[].s, dashtype[].s[]; endfor def defaultdashes = dashpat (dashtype0) (0); % solid dashpat (dashtype1) (3bp, 4bp); % dashed dashpat (dashtype2) (0, 4bp); % dotted dashpat (dashtype3) (0, 4bp, 3bp, 4bp); % dot-dash dashpat (dashtype4) (0, 4bp, 3bp, 4bp, 0, 4bp);% dot-dash-dot dashpat (dashtype5) (0, 4bp, 3bp, 4bp, 3bp, 4bp);% dot-dash-dash dashtype := 6; enddef; defaultdashes; vardef isdashpat suffix pat = (knownarray pat.start) and (knownarray pat.finish) and (knownarray pat.rep) enddef; def setdatadashes (text lst) = save dashtype; dashtype := 0; forsuffixes _itm = lst : if isdashpat _itm : forsuffixes _s = start, rep, finish : copyarray (_itm._s, dashtype[dashtype]._s); endfor dashtype := dashtype + 1; else: GBmsg "Improper dash pattern in setdatadashes."; fi endfor if dashtype = 0 : SetdataWarn "dashes"; defaultdashes; fi enddef; def getdashpat expr n = dashtype[n mod dashtype] enddef; def SetdataWarn expr s = GBmsg "Command setdata"& s &"() failed; using defaults." enddef; def setdatasymbols (text lst) = save pointtype; path pointtype[]; pointtype := 0; for _itm = lst : if (known _itm) and (path _itm): pointtype[pointtype] := _itm; pointtype := pointtype + 1; else: GBmsg "Improper path in setdatasymbols()."; fi endfor if pointtype = 0: SetdataWarn "symbols"; defaultsymbols; fi enddef; def getsymbol expr n := pointtype[n mod pointtype] enddef; numeric pointtype; path pointtype[]; def defaultsymbols = pointtype0 := Circle; pointtype1 := Cross; pointtype2 := SolidDiamond; pointtype3 := Square; pointtype4 := Plus; pointtype5 := Triangle; pointtype6 := SolidCircle; pointtype7 := Star; pointtype8 := SolidTriangle; pointtype := 9; enddef; defaultsymbols; def setdatacolors (text lst) = save colortype; color colortype[]; colortype := 0; for _itm = lst : if (known _itm) and (color _itm) : colortype[colortype] := _itm; colortype := colortype + 1; else: GBmsg "Improper color in setdatacolors()."; fi endfor if colortype = 0 : SetdataWarm "colors"; defaultcolors; fi enddef; def getcolor expr n = colortype[n mod colortype] enddef; numeric colortype; color colortype[]; def defaultcolors = colortype0 := black; colortype1 := red; colortype2 := 0.80blue + .2white; % blue colortype3 := 0.66yellow + .34red; % orange colortype4 := 0.80green; % green colortype5 := 0.85magenta; % magenta colortype6 := 0.85cyan; % cyan colortype7 := 0.85yellow; % yellow colortype := 8; enddef; defaultcolors; vardef bpoint (expr ptwd, b) = fullcircle scaled ptwd shifted b enddef; def pointd (expr ptwd, filled) (text t) = if filled : plotsymbol (SolidCircle, ptwd) (t); else : begingroup; save clearsymbols; boolean clearsymbols; clearsymbols := true; plotsymbol (Circle, ptwd) (t); endgroup fi enddef; boolean clearsymbols; clearsymbols := false; vardef clearable (expr pth) = false if path pth : if (not cycle pth) and (length pth > 0): if ( pnt0 (pth) = pnt[length pth] (pth) ) : or true fi fi fi enddef; def plotsymbol = colorplotsymbol (pointcolor) enddef; vardef colorplotsymbol (expr clr, spath, sc) (text t) = save _cpls; textpairs (_cpls) (t); dosymbols (clr, spath, sc) (_cpls); enddef; vardef dosymbols (expr clr, spath, sc) (suffix arr) = save one_symbol, _pls; picture one_symbol, _pls; if clearsymbols and clearable (spath): addsymbols (background, spath&cycle, sc) (arr); fi addsymbols (clr, spath, sc) (arr); enddef; def addsymbols (expr clr, spath, sc) (suffix arr) = one_symbol := makesymbol (spath, sc); _pls := nullpicture; for _idx = 1 upto arr: picdot (_pls, one_symbol, zconv(arr[_idx])); endfor DoClip (_pls); coloraddto (clr) (active_plane) (_pls); enddef; vardef lclosed expr f = f if not cycle f : --cycle fi enddef; numeric default_tension; default_tension := 1; def sclosed = sclosedt (default_tension) enddef; vardef sclosedt (expr t) expr f = if cycle f : f else: save n; n := length f; if n = 0 : f&cycle elseif n = 1 : f..tension t..cycle else : (pnt0 (f)) { (pnt1(f)) - (pnt[n] (f)) }..tension t ..(subpath (1, n-1) of f)..tension t ..(pnt[n](f)) { pnt0(f) - pnt[n-1](f) } ..tension t..cycle fi fi enddef; def bclosed = bclosedt (default_tension) enddef; vardef bclosedt (expr t) expr f = f if not cycle f : ..tension t..cycle fi enddef; def uclosed = bclosed enddef; def bsplinecontrols (suffix b) expr f = b := 4; b1 := 2[pre 1(f), post0(f)]; b2 := 2[post0(f), pnt 0(f)]; b3 := 2[b1, b2]; b4 := 2[b2, b3]; enddef; vardef cbclosed expr f = if cycle f : f elseif (length f)=0 : f&cycle else: save p, q; pair p[], q[]; bsplinecontrols (p) f; % defines p1 to p4 bsplinecontrols (q) reverse f; % defines q1 to q4 f..controls q2 and q3..opencbs (q1,q4,p4,p1) ..controls p3 and p2..cycle fi enddef; vardef qbclosed expr f = if cycle f : f else: save n; n := length f; if n = 0 : f&cycle else: save p; pair p[]; p := 4; p1 := (3/2)[pnt[n](f), pre[n](f)]; p2 := 2[p1, pnt[n](f)]; p4 := (3/2)[pnt 0 (f), post0 (f)]; p3 := 2[p4, pnt 0 (f)]; f & mkqbs (p) & cycle fi fi enddef; vardef makesector expr p = (pathcenter p)--p--cycle enddef; vardef cutoffbefore (expr b) expr f = save w, t, u, n; n:= length f; pair w; for k = 1 upto n : w := (subpath (0,k) of f) intersectiontimes b; exitif w > left; endfor if debug : GBdebug; >> "Intersectiontimes:"; show w; GBenddebug; fi t := xpart w; if t < 0: cuttings := pnt0 (f); f else: cuttings := subpath (0,t) of f; subpath (t, n) of f fi enddef; vardef cutoffafter (expr b) expr f = save g; path g; g := cutoffbefore (b) reverse f; cuttings := reverse cuttings; reverse g enddef; vardef trimmedpath (expr btrim, etrim) expr f = save g, h; path g, h; g := invvconv (fullcircle scaled 2btrim) shifted pnt0(f); h := invvconv (fullcircle scaled 2etrim) shifted pnt[length f] (f); cutoffafter (h) cutoffbefore (g) f enddef; vardef predirection@# (expr p) = - postdirection[length p - @#] (reverse p) enddef; vardef postdirection@# (expr p) = save _n; _n := length (p); save v; pair v; v := __dir (subpath (@#, @# + _n) of p); if v = origin : v := - __dir (subpath (@#, @# - _n) of p); fi v enddef; vardef __dir (expr p) = save v, w; pair v, w; w := pnt0 (p); v := origin; for n = 1 upto length (p) : v := post[n-1] (p) - w; if v = origin : v := pre[n] (p) - w; if v = origin : v := pnt[n] (p) - w; fi fi exitif v <> origin; endfor v enddef; newinternal hdwdr, hdten; interim hdwdr := 1; interim hdten := 1; boolean hfilled; hfilled := false; def headshape (expr wr, tens, fil) = interim hdwdr := wr; interim hdten := tens; save hfilled; boolean hfilled; hfilled := fil; enddef; def head = ahead enddef; vardef ahead (expr clr, front, back, hwr, tens, filled) = if front <> back : save side; pair side; side := (hwr/2) * ((front-back) rotated 90); save f; path f; f := (back + side)..tension tens.. {front-back}front{back-front}..tension tens.. (back - side) if filled : --cycle; colorsafefill (clr) f fi; colorsafedraw (clr) f; fi enddef; def headpath = colorheadpath (headcolor) enddef; vardef colorheadpath (expr clr, hlen, hrot, hback) expr f = if hlen <> 0 : save g; path g; g := zconv (f); save P; pair P[]; P2 := pnt[length g] (g); P1 := predirection[length g] (g); if P1 <> (0, 0) : P3 := (unitvector P1) rotated hrot; P4 := P2 - (hback * P3); P5 := P4 - (hlen * P3); ahead (clr, P4, P5, hdwdr, hdten, hfilled); fi fi f enddef; def arrowdraw (expr hlen) (expr f) = store (curpath) headpath (hlen, 0, 0) drawn f; enddef; def xaxis (expr hlen) = arrowdraw (hlen) ((xneg, 0)--(xpos, 0)); enddef; def yaxis (expr hlen) = arrowdraw (hlen) ((0, yneg)--(0, ypos)); enddef; def axes (expr hlen) = xaxis (hlen); yaxis (hlen); enddef; laxis := baxis := raxis := taxis := 0; vardef axisline.x = (xneg + laxis, 0)--(xpos - raxis, 0) enddef; vardef axisline.y = (0, yneg + baxis)--(0, ypos - taxis) enddef; vardef axisline.l = axisline.y shifted (xneg + laxis, 0) enddef; vardef axisline.b = axisline.x shifted (0, yneg + baxis) enddef; vardef axisline.r = axisline.y shifted (xpos - raxis, 0) enddef; vardef axisline.t = axisline.x shifted (0, ypos - taxis) enddef; vardef axis@# (expr len) = headpath (len, 0, 0) axisline@# enddef; numeric inside, outside, centered, onleft, onright, ontop, onbottom; inside := -2; outside := -1; onright := 1; onleft := 2; centered := .5[onright, onleft]; onbottom := onright; ontop := onleft; ltick := rtick := ttick := btick := inside; xtick := ytick := centered; vardef axismarks (expr inang, tp, loc, pdir) (expr len) (text t) = save _tp, _U, _P, _tic, _ticang; pair _U, _P, _tic[]; _ticang := if tp<0 : inang else: 90 fi; _tp := abs(tp) - 1; _U := unitvector (vconv (pdir)) rotated _ticang; _tic1 := (_tp - 1) * len * _U; % start of mark _tic2 := _tp * len * _U; % end of mark for _a = t: safedraw ((_tic1--_tic2) shifted zconv (loc + _a*pdir)); endfor enddef; def xmarks = axismarks ( 90, xtick, (0, 0), right) enddef; def ymarks = axismarks (-90, ytick, (0, 0), up) enddef; def lmarks = axismarks (-90, ltick, (xneg + laxis, 0), up) enddef; def bmarks = axismarks ( 90, btick, (0, yneg + baxis), right) enddef; def rmarks = axismarks ( 90, rtick, (xpos - raxis, 0), up) enddef; def tmarks = axismarks (-90, ttick, (0, ypos - taxis), right) enddef; path griddotpath; griddotpath := fullcircle; def grid = vgrid (0.5bp) enddef; vardef vgrid (expr dsize, xspace, yspace) = save gdot, gridpic; picture gdot, gridpic; gdot := setdot (griddotpath, dsize); gridpic := nullpicture; for n = ceiling(xneg/xspace) upto floor(xpos/xspace): for m = ceiling(yneg/yspace) upto floor(ypos/yspace): picdot (gridpic, gdot, zconv((n*xspace, m*yspace))); endfor endfor coloraddto (pointcolor) (active_plane) (gridpic); enddef; def hgridlines (expr ysp) = for n = ceiling((yneg + baxis)/ysp) upto floor((ypos - taxis)/ysp) : safedraw zconv((xneg + laxis, n*ysp)--(xpos - raxis, n*ysp)); endfor enddef; def vgridlines (expr xsp) = for n = ceiling((xneg + laxis)/xsp) upto floor((xpos - raxis)/xsp) : safedraw zconv((n*xsp, yneg + baxis)--(n*xsp, ypos - taxis)); endfor enddef; def gridlines (expr xsp, ysp) = vgridlines (xsp); hgridlines (ysp); enddef; vardef plrpatch (expr rstart, rstop, rstep, tstart, tstop, tstep) = save v; picture v; v := nullpicture; patcharcs (v) (rstart, rstop, rstep, tstart, tstop); coloraddto (drawcolor) (active_plane, v); v := nullpicture; patchrays (v) (tstart, tstop, tstep, rstart, rstop); coloraddto (drawcolor) (active_plane, v); enddef; def patcharcs (suffix X) (expr rstart, rstop, rstep, tstart, tstop) = for rad = (if rstart=0: rstep else: rstart fi) step rstep until rstop: orto (X, picpath zconv (arcplr ((0, 0), tstart, tstop, rad)) ); endfor enddef; def patchrays (suffix X) (expr tstart, tstop, tstep, rstart, rstop) = for _ang = tstart step tstep until tstop: orto (X) (picpath zconv ((rstart*dir _ang)--(rstop*dir _ang))); endfor enddef; def polargrid (expr rstep, tstep) = gridarcs (rstep); gridrays (tstep); enddef; def polargridpoints (expr dsize, rstep, tstep) = beginpolargrid; save gdot; picture gdot; gdot := setdot (griddotpath, dsize); if rmin = 0: picdot (gridpic, gdot, zconv(origin)); rmin := rstep; fi for n = ceiling (rmin/rstep) upto floor (rmax/rstep) : for m = ceiling (tmin/tstep) upto floor (tmax/tstep) : picdot ( gridpic, gdot, zconv ( polar((n*rstep, m*tstep)) ) ); endfor endfor endpolargrid (pointcolor, .5dsize); enddef; def gridarcs (expr rstep) = beginpolargrid; if rmin = 0 : % add "circle" of radius 0 picdot (gridpic, setdot(griddotpath, penwd), zconv(origin)); fi rmin := rstep * floor(rmin/rstep + 1); rmax := rstep*ceiling(rmax/rstep - 1); patcharcs (gridpic) (rmin, rmax, rstep, tmin, tmax); endpolargrid (drawcolor, .5penwd); enddef; def gridrays (expr tstep) = beginpolargrid; tmin := tstep*ceiling(tmin/tstep); tmax := tstep * floor(tmax/tstep); patchrays (gridpic) (tmin, tmax, tstep, rmin, rmax); endpolargrid (drawcolor, .5penwd); enddef; def beginpolargrid = begingroup; save p, r, t, rmax, rmin, tmax, tmin; pair p[]; % Four corners: p0 := (xneg, yneg); p1 := (xneg, ypos); p2 := (xpos, ypos); p3 := (xpos, yneg); r0 := abs(p0); rmax := r0; for j = 1 upto 3 : r[j] := abs(p[j]); if rmax < r[j] : rmax := r[j]; fi endfor rmin := 0; if (xneg < 0) and (xpos > 0) and (yneg < 0) and (ypos > 0) : tmin := 0; tmax := 360; elseif (p0 = (0,0)) : tmin := 0; tmax := 90; elseif (p1 = (0,0)) : tmin := -90; tmax := 0; elseif (p2 = (0,0)) : tmin := -180; tmax := -90; elseif (p3 = (0,0)) : tmin := 90; tmax := 180; else : tmax := tmin := t0 := angle p0; for j = 1 upto 3: t := t0 + angle (p[j] rotated -t0); if tmax < t : tmax := t; fi if tmin > t : tmin := t; fi endfor if (xneg < 0) and (xpos > 0) : % (1) rmin := emin(abs(yneg), abs(ypos)); elseif (yneg < 0) and (ypos > 0) : % (2) rmin := emin(abs(xneg), abs(xpos)); else : % (3) rmin := min(r0, r1, r2, r3); fi fi save gridpic; picture gridpic; gridpic := nullpicture; enddef; def endpolargrid (expr clr, size)= clipto (gridpic) rect ( zconv((xneg, yneg)) - size*(1,1), zconv((xpos, ypos)) + size*(1,1) ); coloraddto (clr) (active_plane) (gridpic); endgroup enddef; vardef polarpatch (expr rstart, rstop, rstep, tstart, tstop, tstep) = plrpatch (rstart, rstop, rstep, tstart, tstop, tstep); safedraw zconv ( arcplr ((0, 0), tstart, tstop, rstop) ); safedraw zconv ( ((rstart, 0)--(rstop, 0)) rotated tstop ); enddef; vardef rect (expr ll, ur) = ll--(xpart ur, ypart ll)--ur--(xpart ll, ypart ur)--cycle enddef; vardef triangle (expr A, B, C) = A--B--C--cycle enddef; vardef regularpolygon (expr n) (suffix Bob) (text eqns) = pair Bob[]; Bob := emax(round (abs (n)), 2); eqns; for _uncle = 1 upto Bob - 1 : (Bob1 - Bob0) rotated (360*_uncle/Bob) = Bob[_uncle+1] - Bob0; endfor mkpoly (true) (Bob) enddef; vardef altitudept expr n of t = save A, B, C, zz; pair A, B, C, zz; A := pnt[n] (t); B := pnt[n + 1] (t); % wraps around a cyclic path C := pnt[n + 2] (t); zz = whatever[B,C]; zz = A + whatever*((C-B) rotated 90); zz enddef; vardef altitude expr n of t = (pnt[n](t))--(altitudept n of t) enddef; vardef medianpt expr n of t = 0.5[pnt[n + 1] (t), pnt[n + 2] (t)] enddef; vardef median expr n of t = (pnt[n](t))--(medianpt n of t) enddef; vardef anglebisectorpt expr n of t = save A, B, C; pair A, B, C; A := pnt[n ] (t); B := pnt[n + 1] (t); C := pnt[n + 2] (t); save zz; pair zz; zz = whatever[B,C]; zz = A + whatever*((B-A) rotated (.5*cornerangle (A,B,C))); zz enddef; vardef anglebisector expr n of t = (pnt[n](t))--(anglebisectorpt n of t) enddef; vardef cornerangle (expr A, B, C) = if (A = B) and (B = C) : 60 elseif (B = C) : 0 elseif (A = B) or (A = C) : 90 else: angle ((C - A) rotated (-angle (B - A))) fi enddef; vardef mkpath (expr smooth, tens, cyclic) (suffix pts) = if smooth : mksmooth (tens, cyclic, pts) else : mkpoly (cyclic, pts) fi enddef; vardef mkpoly (expr cyclic) (suffix pts) = for _i = 1 upto pts-1: pts[_i]-- endfor pts[pts] if cyclic : -- cycle fi enddef; vardef polyline (expr cyclic) (text t) = save _pl; textpairs (_pl) (t); mkpoly (cyclic, _pl) enddef; vardef mksmooth (expr tens, cyclic) (suffix pts) = pts1 if pts = 1 : if cyclic : &cycle fi else: if cyclic : {pts[2]-pts[pts]} fi for _i = 2 upto pts-1: ..tension tens..pts[_i]{pts[_i+1]-pts[_i-1]} endfor ..tension tens..pts[pts] if cyclic : {pts[1]-pts[pts-1]}..tension tens..cycle fi fi enddef; def curve = tcurve (default_tension) enddef; vardef tcurve (expr tens, cyclic) (text t) = save _tc; textpairs (_tc) (t); mksmooth (tens, cyclic, _tc) enddef; vardef mkbezier (expr tens, cyclic) (suffix pts) = for _i = 1 upto pts-1 : pts[_i]..tension tens.. endfor pts[pts] if cyclic : ..tension tens..cycle fi enddef; def bezier = tbezier (default_tension) enddef; vardef tbezier (expr tens, cyclic) (text t) = save _tsb; textpairs (_tsb) (t); mkbezier (tens, cyclic) (_tsb) enddef; vardef mkqbezier (expr cyclic) (suffix pts) = save _mqb; _mqb := pts; if (cyclic and odd pts) or not (cyclic or odd pts): pts[incr _mqb] := pts[pts]; fi if cyclic : pts[incr _mqb] := pts1; fi pts1 for _i = 2 step 2 until _mqb - 1 : ..controls 1/3[pts[_i],pts[_i-1]] and 1/3[pts[_i], pts[_i+1]] ..pts[_i+1] endfor if cyclic : &cycle fi enddef; vardef qbezier (expr cyclic) (text t) = save _qbz; textpairs (_qbz) (t); mkqbezier (cyclic) (_qbz) enddef; vardef openqbs (text t) = save _oq; textpairs (_oq) (t); mkqbs (_oq) enddef; vardef closedqbs (text t) = save _cq; textpairs (_cq) (t); _cq[incr _cq] := _cq1; _cq[incr _cq] := _cq2; mkqbs (_cq) & cycle enddef; vardef mkqbs (suffix b) = for _i = 1 upto b-2: 0.5[b[_i], b[_i+1]] ..controls 1/6[b[_i+1], b[_i]] and 1/6[b[_i+1], b[_i+2]].. endfor 0.5[b[b-1], b[b]] enddef; vardef mkopencbs (suffix b) = for _i = 1 upto b-3: (b[_i]+4b[_i+1]+b[_i+2])/6 ..controls 1/3[b[_i+1], b[_i+2]] and 2/3[b[_i+1], b[_i+2]].. endfor (b[b-2]+4b[b-1]+b[b])/6 enddef; vardef mkclosedcbs (suffix b) = mkopencbs (b) & opencbs (b[b-2],b[b-1],b[b], b1, b2, b3) & cycle enddef; vardef opencbs (text t) = save _oc; textpairs (_oc) (t); mkopencbs (_oc) enddef; vardef closedcbs (text t) = save _clc; textpairs (_clc) (t); mkclosedcbs (_clc) enddef; vardef fcncontrol (expr ftens, X, Y, Z) = save dl, dr, before, after; pair before, after; before := Y - X; after := Z - Y; dl := xpart (before); dr := xpart (after); if (dr = 0) or (dl = 0): Y + abs(dr)/ftens * sgn before else: Y + abs(dr)/ftens * unitvector (before*dr/dl + after*dl/dr) fi enddef; vardef mkfcnpath (expr ftens) (suffix q) = for _i = 1 upto q - 1: q[_i]..controls fcncontrol (ftens) (q[_i-1], q[_i], q[_i+1]) and fcncontrol (ftens) (q[_i+2], q[_i+1], q[_i]).. endfor q[q] enddef; def fcncurve = functioncurve (emax(1.2default_tension, eps)) enddef; vardef functioncurve (expr ftens) (text t) = save _fc; textpairs (_fc) (t); if _fc > 1 : _fc0 := _fc1; _fc[_fc+1] := _fc[_fc]; fi mkfcnpath (ftens)(_fc) enddef; vardef turtle (text t) = save _tu; pair _tu[]; _tu := 0; _tu0 := (0, 0); for _a = t: _tu[incr _tu] := _tu[_tu - 1] + _a; endfor mkpoly (false, _tu) enddef; vardef mkarc (expr center, from, to, sweep) = save n, d; pair d; n := ceiling (abs(sweep)/45); d := (from - center) rotated (signof (sweep) 90); from{d} for j = 1 upto n-1 : ..(from rotatedabout (center, j/n*sweep)){d rotated (j/n*sweep)} endfor ..to{d rotated sweep} enddef; vardef arc (expr center, from, sweep) = if (center = from) or (sweep = 0) : from--from else: save to; pair to; to := from rotatedabout (center, sweep); mkarc (center, from, to, sweep) fi enddef; def arccps = arc enddef; vardef arccenter (expr from, to, sweep) = save ang, c; pair c; ang := 90 - (sweep mod 360)/2; % -90 < ang <= 90 if (abs(ang) = 90) or (from = to) : GBmsg "The central point of this arc is undefined. " & "Using midpoint of chord instead."; 0.5[from, to] else: save cd; pair cd; cd := to - from; c = from + whatever*(cd rotated ang); if abs(ang) < 30 : c = (0.5)[from, to] + whatever*(cd rotated 90); else: c = to + whatever*(-cd rotated -ang); fi c fi enddef; vardef midarc (expr from, to, sweep) = save m, cd; pair m, cd; cd := to - from; m = from + whatever*( cd rotated (-sweep/4)); m = 0.5[from, to] + whatever*(cd rotated 90); m enddef; vardef arcpps (expr from, to, sweep) = if ((sweep mod 360) = 0) or (from = to) : GBmsg "Undefined arc. A line segment will be used instead."; from--to elseif abs(sweep) <= 90 : save cd; pair cd; cd := to - from; if abs(sweep) <= 45 : from{cd rotated (-sweep/2)}..to{cd rotated (sweep/2)} else: from{cd rotated (-sweep/2)}..midarc(from, to, sweep){cd} ..to{cd rotated (sweep/2)} fi else: save center; pair center; center := arccenter (from, to, sweep); mkarc (center, from, to, sweep) fi enddef; vardef arcplr (expr center, frtheta, totheta, rad) = if rad = 0 : center -- center else: save from, to; pair from, to; from := center + rad*dir frtheta; to := center + rad*dir totheta; if frtheta = totheta : from--to else: mkarc (center, from, to, totheta - frtheta) fi fi enddef; vardef arcalt (expr center, radius, anglefrom, angleto) = arcplr (center, anglefrom, angleto, radius) enddef; vardef arcppp (expr first, second, third) = arcpps (first, second, 2*cornerangle (third, first, second)) & arcpps (second, third, 2*cornerangle (first, second, third)) enddef; vardef ellipse (expr center, radx, rady, angle) = fullcircle xscaled (2*radx) yscaled (2*rady) rotated angle shifted center enddef; vardef circle (expr center, rad) = fullcircle scaled (2*rad) shifted center enddef; vardef circlecp (expr center, point) = mkarc (center, point, point, 360) & cycle enddef; vardef circleppp (expr one, two, three) = save ang; numeric ang[]; ang0 := cornerangle(three, one, two); ang1 := cornerangle(one, two, three); ang2 := cornerangle(two, three, one); arcpps (one, two, 2ang0) & arcpps (two, three, 2ang1) & arcpps (three, one, 2ang2) & cycle enddef; vardef circlepps (expr one, two, sweep) = save ang, full; numeric ang[], full; full := signof (sweep) 360; ang1 := sweep mod (full); ang2 := full - ang1; arcpps (one, two, ang1) & arcpps (two, one, ang2) & cycle enddef; vardef pathcenter expr p = save a, cntr, n; pair cntr, a[]; n := length p; a1 = pnt 0 (p); a3 = pnt [n/2] (p); if cycle p : a2 = pnt [n/4] (p); a4 = pnt [3n/4] (p); else: a2 := a3; a4 := pnt[n] (p); fi cntr = .5[a1, a3] + whatever*((a3 - a1) rotated 90); cntr = .5[a2, a4] + whatever*((a4 - a2) rotated 90); cntr enddef; vardef circumcircle expr t = circleppp (pnt0 (t), pnt1 (t), pnt2 (t)) enddef; vardef incircle expr t = save A, B, C; pair A, B, C; A := pnt0 (t); B := pnt1 (t); C := pnt2 (t); % Find the tangent points on the sides. E.g., a is the common % distance from A to the tangent points on the adjacent sides. save a, b, c; a + b = abs (B-A); b + c = abs (C-B); a + c = abs (A-C); circleppp (A + a*unitvector (B-A), B + b*unitvector (C-B), C + c*unitvector (A-C)) enddef; vardef excircle expr n of t = save A, B, C; pair A, B, C; A := pnt[n] (t); B := pnt[n + 1] (t); % wraps around C := pnt[n + 2] (t); save a, b, c; a - b = abs (B-A); b + c = abs (C-B); a - c = abs (C-A); circleppp (A + a*unitvector(B-A), B + b*unitvector(C-B), C + c*unitvector(C-A)) enddef; vardef ninepointcircle expr t = circleppp (medianpt 0 of t, medianpt 1 of t, medianpt 2 of t) enddef; vardef circumcenter expr t = pathcenter circumcircle t enddef; vardef incenter expr t = pathcenter incircle t enddef; vardef excenter expr n of t = pathcenter excircle n of t enddef; vardef ninepointcenter expr t = pathcenter ninepointcircle t enddef; vardef barycenter expr t = save n, m; n := length t; m := n + 1; save xxx; xxx : = pnt0 (t)/m for k = 1 upto n-1 : + pnt[k] (t)/m endfor; if cycle t: xxx*(1 + 1/n) else: xxx + pnt[n] (t)/m fi enddef; vardef sector (expr center, rad, frtheta, totheta) = center -- arcalt (center, rad, frtheta, totheta) -- cycle enddef; vardef mkfcn (expr smooth, tens) (expr bmin, bmax, bst) (text pf) = save _p; pair _p[]; _p := 0; save _dx, _n, _r; numeric _dx, _n, _r; if bmax = bmin : _n := 1; else: _r := bmax - bmin; _dx := max (abs(bst), nottoosmall*abs(_r), epsilon); _n := emax (round(abs(_r)/_dx), 1); fi for _i = 0 upto _n: _p[incr _p] := pf(bmin + _i/_n*_r); endfor mkpath (smooth, tens, false, _p) enddef; def tfcn (expr smooth) = mkfcn (smooth, default_tension) enddef; def parafcn (expr smooth) = tparafcn (smooth, default_tension) enddef; vardef tparafcn (expr sm, tn) (expr bmin, bmax, bst) (text pf) = save _fp; vardef _fp (expr t) = pf enddef; mkfcn (sm, tn) (bmin, bmax, bst) (_fp) enddef; vardef xfcn (expr smooth) (expr xmin, xmax, st) (text _fx) = save _fp; vardef _fp (expr _x) = (_x, _fx(_x)) enddef; mkfcn (smooth, default_tension) (xmin, xmax, st) (_fp) enddef; def function (expr smooth) = tfunction (smooth, default_tension) enddef; vardef tfunction (expr smooth, tens) (expr xmin, xmax, st) (text _fx) = save _fp; vardef _fp (expr x) = (x, _fx) enddef; mkfcn (smooth, tens) (xmin, xmax, st) (_fp) enddef; def btwnfcn (expr sm) = tbtwnfcn (sm, default_tension) enddef; vardef tbtwnfcn (expr sm, tn)(expr xlo, xhi, st)(text _fx)(text _gx) = tfunction (sm, tn) (xlo, xhi, st) (_fx) -- ( reverse tfunction (sm, tn) (xlo, xhi, st) (_gx) ) -- cycle enddef; vardef rfcn (expr smooth) (expr tmin, tmax, st) (text ft) = save _fq; vardef _fq (expr t) = (ft(t)) * (dir t) enddef; mkfcn (smooth, default_tension) (tmin, tmax, st) (_fq) enddef; def plrfcn (expr smooth) = tplrfcn (smooth, default_tension) enddef; vardef tplrfcn (expr smooth, tens) (expr tmin, tmax, st) (text ft) = save _fq; vardef _fq (expr t) = (ft) * (dir t) enddef; mkfcn (smooth, tens) (tmin, tmax, st) (_fq) enddef; vardef piechart (expr sign, ang, cent, rad) (text data) = save _sum, _tot; numeric piewedge; piewedge := 0; numeric pieangle, pieangle[]; pieangle0 := 0; for _val = data : pieangle[incr piewedge] := pieangle[piewedge - 1] + _val; endfor _tot := pieangle[piewedge]; pair piecenter; piecenter := cent; path piewedge[]; numeric piedirection; pair piedirection[]; pieangle[piewedge + 1] = ang + sign*360; for _n = piewedge downto 1 : pieangle[_n] := ang + sign*pieangle[_n - 1]/_tot*360; piewedge[_n] = sector(cent, rad, pieangle[_n], pieangle[_n+1]); piedirection[_n] := dir(0.5[ pieangle[_n], pieangle[_n+1] ]); endfor piedirection := pieangle := piewedge; enddef; def barchart (expr start, sep, r, vert)(text data) = numeric barbegin, barbegin[], barend, barend[], barlength, barlength[], barstart, barstart[], chartbar, barwd; path chartbar[]; chartbar := 0; barwd := r*sep; for _itm = data : barend[incr chartbar] := if pair _itm: ypart _itm else: _itm fi; barbegin[chartbar] := if pair _itm: xpart _itm else: 0 fi; endfor barbegin := barend := barlength := barstart := chartbar; for _n = 1 upto chartbar : barstart[_n] := start + sep*(_n-1); barlength[_n] := barend[_n]; chartbar[_n] := rect ((barbegin[_n], 0), ( barend[_n], barwd) ) shifted (0, barstart[_n]) if vert: xyswap fi; endfor enddef; picture totalpicture; boolean totalnull, currentnull; def clearit = currentpicture := totalpicture := nullpicture; currentnull := totalnull := true; enddef; def keepit = addto totalpicture also currentpicture; currentpicture := nullpicture; totalnull := currentnull; currentnull := true; enddef; def addto_currentpicture = currentnull := false; addto currentpicture enddef; def mergeit (text do) = if totalnull : do currentpicture elseif currentnull : do totalpicture else: begingroup save _v_; picture _v_; _v_ := currentpicture; addto _v_ also totalpicture; do _v_ endgroup fi enddef; def shipit_ = mergeit (shipout) enddef; def shipit = shipit_ enddef; numeric gcode; gcode := 0; % end grafbase.mp endinput. %% %% End of file `grafbase.mp'.