diff options
Diffstat (limited to 'Master/texmf-dist/metapost/mfpic/grafbase.mp')
-rw-r--r-- | Master/texmf-dist/metapost/mfpic/grafbase.mp | 2283 |
1 files changed, 2283 insertions, 0 deletions
diff --git a/Master/texmf-dist/metapost/mfpic/grafbase.mp b/Master/texmf-dist/metapost/mfpic/grafbase.mp new file mode 100644 index 00000000000..08e9f3de9b1 --- /dev/null +++ b/Master/texmf-dist/metapost/mfpic/grafbase.mp @@ -0,0 +1,2283 @@ +%% +%% 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'. |