diff options
Diffstat (limited to 'Master/texmf-dist/metapost/mfpic/grafbase.mp')
-rw-r--r-- | Master/texmf-dist/metapost/mfpic/grafbase.mp | 3575 |
1 files changed, 2309 insertions, 1266 deletions
diff --git a/Master/texmf-dist/metapost/mfpic/grafbase.mp b/Master/texmf-dist/metapost/mfpic/grafbase.mp index 08e9f3de9b1..225150795f1 100644 --- a/Master/texmf-dist/metapost/mfpic/grafbase.mp +++ b/Master/texmf-dist/metapost/mfpic/grafbase.mp @@ -8,86 +8,80 @@ %% %% ------------------------------------------------------------------- %% -%% 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. +%% Copyright 2002--2006, Daniel H. Luecking %% %% 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 +%% LaTeX Project Public License, either version 1.3b 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.3b or later is part of all distributions of LaTeX version +%% 2005/12/01 or later. %% -%% 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. +%% Mfpic has maintenance status "author-maintained". The Current Maintainer +%% is Daniel H. Luecking. There are several Base Interpreters associated +%% with mfpic: plain TeX, LaTeX, plain Metafont and plain MetaPost. %% -%% 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."; +if (known grafbaseversion) or (known grafbase): + message "Grafbase (" & jobname & "): 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; + +string fileversion, filedate; +fileversion := "0.9"; filedate := "2006/05/26"; + +message " Loading grafbase macros, version " & fileversion & " " & + filedate & "."; + +def GBmsg expr s = message "Grafbase (" & jobname & "): " & s; enddef; +def GBwarn expr s = GBmsg "Warning, " & s; enddef; +def GBerrmsg (expr s) expr t = errhelp t; + errmessage "Grafbase (" & jobname & "): " & s; errhelp ""; +enddef; + +boolean MFPIC; MFPIC := false; def checkversions (expr g)= - numeric grafbaseversion; grafbaseversion := g; - if unknown mfpicversion : % no mfpic, or < 0.63 + numeric grafbaseversion; grafbaseversion := g; + if unknown mfpicversion: % no mfpic, or < 0.63 GBmsg "Recent mfpic not detected."; - elseif g = mfpicversion : + elseif g = mfpicversion: MFPIC := true; else: - GBerrmsg ("version mismatch") - "The installation may be broken: mfpic and grafbase " & - "versions do not match."; + message ""; + GBwarn "Version mismatch: " + & "mfpic and grafbase versions do not match."; + message ""; fi enddef; -checkversions (70); +checkversions (90); -if unknown base_name : input plain; -elseif not string base_name : input plain; -elseif base_name <> "plain" : input plain; +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; +if known color Geamparalele din Babadag: + 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."; +if not METAPOST: + GBerrmsg ("wrong compiler.") + "This file is for Metapost. For Metafont use grafbase.mf."; fi -if (unknown debug) or (not boolean debug) : - boolean debug; debug := false; -fi +if not boolean debug: boolean debug; debug := false; fi def GBdebug = begingroup - save >>; def >> = message enddef; - >> "Grafbase DEBUG: "; + save >>; def >> = message enddef; + >> "Grafbase DEBUG"; enddef; def GBenddebug = >> "End DEBUG"; @@ -95,77 +89,78 @@ def GBenddebug = enddef; vardef mftitle expr t = - t; message t; + if string t: t; message t; fi 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 : +pt# := pt; bp# := bp; +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; +numeric unitlen, xscale, yscale, xneg, xpos, yneg, ypos; -newinternal radian, pi, deg; -deg := 1; pi := 3.14159; -radian := 180/pi; +unitlen := 1 bp#; +xscale := 7.2; +yscale := 7.2; +xneg := 0; xpos := 10; +yneg := 0; ypos := 10; +newinternal deg, pi, radian; +deg := 1; pi := 3.14159; +radian := 57.29578; +numeric degree; degree := deg; -newinternal penwd; penwd := 0.5pt; +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; + setvariable (pen) (drawpen) pencircle scaled penwd; + save currentpen; pen currentpen; pickup drawpen; enddef; -numeric hatchwd; hatchwd := 0.5bp; -pen hatchpen; hatchpen := pencircle scaled hatchwd; +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; +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 + if ClipOn and (ClipPath > 0): clipsto (v, ClipPath); fi enddef; def noclip (text t) = - hide( save ClipOn; boolean ClipOn; ClipOn := false; t) + hide ( setboolean (ClipOn) false; t) enddef; -boolean showbbox; showbbox := false; +boolean showbbox; showbbox := false; -def _wc_ = withcolor enddef; +def _wc_ = withcolor enddef; -color currentcolor, fillcolor, drawcolor, hatchcolor, +color currentcolor, drawcolor, fillcolor, 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 + 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 gray (expr g) = (snapto g)*white enddef; vardef makeclr (expr r, g, b) = (r, g, b) @@ -183,12 +178,13 @@ vardef RGB (expr R, G, B) = rgb (R/255, G/255, B/255) enddef; -vardef named (suffix c) = forceclr (c) enddef; +vardef named (suffix c) = + if unknown c: black else: forceclr (c) fi +enddef; vardef forceclr (expr c) = - if unknown c : black - elseif numeric c : gray (c) - elseif color c : c - else : black + if numeric c: gray (c) + elseif color c: c + else: black fi enddef; @@ -200,55 +196,70 @@ 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 +def list (suffix v) (text lst) = + v := 0; for _itm = lst: v[incr v] := _itm; endfor + if v = 0: + GBerrmsg ("no list to process!") + "An attempt was made to produce an array from a " + & "list of expressions having no valid entries."; + fi enddef; def map (text proc) (text lst) = - hide(_map := 0;) - for _a = lst : - if _map = 0 : hide(_map := 1;) else: , fi - proc(_a) + 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); +vardef knownnumericarray suffix arr = + setboolean (_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]; + _kna := (known arr[_idx]) and (numeric arr[_idx]); endfor fi _kna enddef; -def copyarray(suffix from, to) = - to := 0; - for _idx = 1 upto from: - to[incr to] := from[_idx]; - endfor +def copyarray (suffix src, dest) = + for _idx = 1 upto src: dest[_idx] := src[_idx]; endfor + dest := src; enddef; def maparr (text proc) (suffix p) = - for _idx = 1 upto p: proc (p[_idx]); endfor + for _idx = 1 upto p: proc (p[_idx]); endfor enddef; -def textpairs (suffix p) (text t) = - numeric p; pair p[]; list (p) (t); +def textpairs = gsetarray (pair) enddef; + +def setuniquepairs (suffix p) (text t) = + save p; pair p[]; + setpairs (_up) (t); + if _up > 0: + p := 1; p1 := _up1; + for _i = 2 upto _up: + if _up[_i] <> p[p]: p[incr p] := _up[_i]; fi + endfor + else: + p := 0; + fi 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 floorpair (expr p) = (floor (xpart p), floor (ypart p)) enddef; +vardef ceilingpair (expr p) = + (ceiling (xpart p), ceiling (ypart 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 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 ) ) @@ -257,22 +268,147 @@ 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 +vardef minpair (suffix p) = setpair (_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 +vardef maxpair (suffix p) = setpair (_mp) p1; + for _idx = 2 upto p - 1: _mp := pairmax (_mp, p[_idx]); endfor pairmax (_mp, p[p]) enddef; +primarydef Z xprod W = (xpart Z * ypart W - xpart W * ypart Z) enddef; + +def force_initial (expr p) (suffix f) = + hide( setnumeric (_n) length f; + f := p + if _n = 0: + {0,0} + else: + ..controls post0 (f) and pre 1 (f).. subpath (1,_n) of f + fi;) +enddef; + +def force_terminal (expr p) (suffix f) = + hide(setpath (_f) reverse f; + force_initial (p) (_f); + f := reverse _f;) +enddef; + +def force_equal_ends (suffix f, g) = + hide(save _p; pair _p; + _p := .5[pnt[length f] (f), pnt0(g)]; + force_terminal (_p) (f); force_initial (_p) (g);) +enddef; + +def replace_ends_of_cycle (expr p) (suffix f) = +hide( +if cycle f: + save _n; _n := length f; + f := p + if _n = 0: &cycle + else: .. controls post0 (f) and pre 1 (f) .. + if _n = 1: cycle + else: subpath (1, _n - 1) of f .. + controls post[_n - 1](f) and pre[_n](f) .. cycle + fi + fi; +fi) +enddef; + +pair thetimes; +numeric _Xtime, _Ytime; +tertiarydef a intersects b = + begingroup + thetimes := a intersectiontimes b; + _Xtime := xpart thetimes; + _Ytime := ypart thetimes; + (_Xtime > -1) + endgroup +enddef; + +tertiarydef a misses b = ((a intersectiontimes b) < origin) enddef; + +vardef makepicture (expr s) = + if picture s: s + elseif string s: s infont defaultfont scaled defaultscale + elseif path s: picpath (s) + else: nullpicture + fi +enddef; + +vardef onepointpath (expr cyclic, q) = + q if cyclic: &cycle else: {0,0} fi +enddef; + +vardef fallbackpath (expr cyclic, p) (text t) = + onepointpath (cyclic, p) +enddef; + +def even = not odd enddef; + +primarydef a divides b = + ((b mod a) = 0) +enddef; + +def beginimage = + begingroup + newpicture (currentpicture); +enddef; +def endimage = + ; currentpicture + endgroup +enddef; + +def makeimage (suffix name) (expr refpt) = + setpair (_image_reference_point) zconv(refpt); + setpicture (name) beginimage +enddef; +def concludeimage = + endimage shifted + -_image_reference_point +enddef; + +def setvariable (text kind) (suffix name) = + save name; kind name; name := +enddef; +def gsetvariable (text kind) (suffix name) = kind name; name := +enddef; + +def setnumeric (suffix name) = save name; name := enddef; +def setboolean = setvariable (boolean) enddef; +def setpair = setvariable (pair) enddef; +def setpath = setvariable (path) enddef; +def setcolor = setvariable (color) enddef; +def setpicture = setvariable (picture) enddef; +def settension (suffix tn) expr tens = + setnumeric (tn) if tens > 0: tens else: default_tension fi; +enddef; +def fixtension (suffix tn) = if tn < .75: tn := .75; fi enddef; + +def newpicture (suffix pic) = setpicture (pic) nullpicture; enddef; +def convertpath (suffix g) expr f = setpath (g) zconv (f); enddef; + +def setarray (text kind) (suffix name) = + save name; kind name[]; list (name) +enddef; +def setpairs = setarray (pair) enddef; +def gsetarray (text kind) (suffix name) = + numeric name; kind name[]; list (name) +enddef; + + +def setbbox (suffix ll, ur) = + save ll, ur; pair ll, ur; getbbox (ll, ur) +enddef; + +def setsplit (suffix s) expr ss = + setnumeric (s) emax (1, ceiling ss); +enddef; + transform ztr, vtr; def setztr = - if debug : + if debug: GBdebug; >> "w_ = " & decimal w_ & "bp"; >> "h_ = " & decimal h_ & "bp"; @@ -287,65 +423,63 @@ def setztr = 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 : + vtr := identity xscaled xscale yscaled yscale scaled (unitlen*hppp); + ztr := identity shifted (-xneg, -yneg) transformed vtr; + if debug: GBdebug; - >> "ztr: "; + >> "ztr is"; show ztr; - >> "vtr: "; + >> "vtr is"; 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; +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; +def active_plane = currentpicture enddef; -boolean overlaylabels; -overlaylabels = false; +boolean overlaylabels, underlaylabels, havebackground; +overlaylabels := false; +underlaylabels := false; +havebackground := false; def initpic = setztr; resizedrawpen (penwd); - if ClipOn : ClipPath := 1; + if ClipOn: ClipPath := 1; ClipPath1 := rect (origin, (w_, h_)); fi - if debug : + 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; + newpicture (foreground_labels); + newpicture (background_labels); + havebackground := false; + save labelbb; pair labelbb.ll, labelbb.ur; labelbb.ll := labelbb.ur := origin; enddef; -def mfpicenv = enddef; -def endmfpicenv = enddef; +def mfpicenv = enddef; +def endmfpicenv = enddef; def bounds (expr a, b, c, d) = - xneg := a; xpos := b; - yneg := c; ypos := 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_beginmfpic; extra_beginmfpic := ""; string extra_endmfpic; extra_endmfpic := ""; def beginmfpic (expr ch) = beginfig (ch); gcode := ch; - save w_, h_, d_; numeric w_, h_, d_; + save w_, h_, d_; charwd := (xpos-xneg)*xscale*unitlen; charht := (ypos-yneg)*yscale*unitlen; chardp := 0; @@ -358,52 +492,59 @@ enddef; def endmfpic = scantokens extra_endmfpic; - if debug : + 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 + 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 : + 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); + _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; + _ur := pairmax (_ur, _ll + eps*(1, 1)); + setbounds active_plane to rect (_ll, _ur); + if havebackground: + addto background_labels also active_plane; + active_plane := background_labels; + background_labels := nullpicture; + fi + addto active_plane also foreground_labels; + foreground_labels := nullpicture; endfig; enddef; -pair label_adjust; label_adjust := (0, 0); -numeric label_sep; label_sep := 0; +pair label_adjust; +label_adjust := origin; +numeric label_sep, labelpath_sep ; +label_sep := 0; labelpath_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; + save _lab, _ll, _ur; picture _lab; pair _ll, _ur; + _lab := makepicture (s); + pathdims (origin, _lab) (_ll, _ur); + readjustdims (_ll, _ur) (label_sep); + _lab := thegblabel (ref_shift (hf, vf, BL, _ll, _ur), r, _lab); + save _b; pair _b; + for _itm = pts: + _b := zconv (_itm); + if overlaylabels: + addto foreground_labels also _lab shifted _b _wc_ tlabelcolor; + elseif underlaylabels: + addto background_labels also _lab shifted _b _wc_ tlabelcolor; + havebackground := true; else: addto active_plane also _lab shifted _b _wc_ tlabelcolor; labelbb.ll := pairmin (_b + llcorner _lab, labelbb.ll); @@ -418,7 +559,7 @@ 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] ) + (vf)[if BL: 0 else: (ypart ll) fi, ypart ur] ) enddef; vardef thegblabel (expr z, r, p) = @@ -435,98 +576,89 @@ vardef textellipse (expr lbl, rat, loc) = xellipse (false, .5, .5, false, 0) (origin, lbl, rat, loc) enddef; -boolean roundends; roundends := true; +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 + pathdims (xy, lbl) (ll, ur); + readjustdims (ll, ur) (labelpath_sep) + _r := if numeric rad: rad + elseif not boolean rad: 0 + elseif rad: emin (xpart(ur-ll), ypart (ur-ll))/sqrt(2) + else: 0 fi; - if _r = 0 : - f := rect(ll, ur); + 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 + p1 := ur - _r*dir(45); + p3 := ll + _r*dir(45); + p2 := (xpart p3, ypart p1); + p4 := (xpart p1, ypart p3); + q := if _r < 0: reverse fi quartercircle scaled 2_r; + f := + (q shifted p1)--(q rotated 90 shifted p2) + --(q rotated 180 shifted p3) + --(q rotated -90 shifted p4)--cycle; + fi - invvconv(thegblabel(ref_shift(a, b, c, ll, ur), rot, f)) shifted loc + readjustdims (ll, ur) (label_sep - labelpath_sep); + invvconv (thegblabel (ref_shift(a, b, c, ll, ur), rot, f)) shifted loc enddef; -def textovalx = xellipse (true) enddef; -def textellipsex = xellipse (false) 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 : + 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 + pathdims (xy, lbl) (ll, ur); + readjustdims (ll, ur) (labelpath_sep) + cc := .5[ll, ur]; (ww, hh) = ur - cc; - if (ww = 0) or (hh = 0) : % make a line: + if (ww = 0) or (hh = 0): 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); + save aa, bb; + aa := ww ++ if aspect: ww else: hh fi *mult; + bb := hh ++ if aspect: hh else: ww fi /mult; + f := ellipse (cc, aa, bb, 0); fi - invvconv(thegblabel (ref_shift (a, b, c, ll, ur), r, f)) shifted loc + readjustdims (ll, ur) (label_sep - labelpath_sep); + 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; +def pathdims (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; + setpicture (_lbl) makepicture (lbl); 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; +def readjustdims (suffix ll, ur) (expr s) = + ll := ll - s*(1,1); + ur := ur + s*(1,1); +enddef; + +newinternal reallysmall; reallysmall := 3epsilon; +newinternal nottoosmall; nottoosmall := eps/2 + 2epsilon; +def signof (expr X) = if X < 0: - fi enddef; +def TruncateWarn expr s = + GBwarn s & " is too large or undefined, so it will be truncated."; +enddef; vardef secd primary X = - save temp; temp := cosd(X); - if abs(temp) < reallysmall : - TruncateWarn "Secant"; + setnumeric (temp) cosd(X); + if abs(temp) < reallysmall: + TruncateWarn "Secant or Tangent"; temp := signof (temp) reallysmall; fi 1/temp @@ -534,17 +666,31 @@ 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"; + setnumeric (temp) sind(X); + if abs(temp) < reallysmall: + TruncateWarn "Cosecant or Cotangent"; 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 acos primary X = + if abs X > 1: + TruncateWarn "Argument of arccosine"; + angle (signof(X) 1, 0) + else: + angle (X, 1 +-+ X) + fi +enddef; +vardef asin primary X = + if abs X > 1: + TruncateWarn "Argument of arcsine"; + angle (0, signof(X) 1) + else: + angle (1 +-+ X, X) + fi +enddef; vardef atan primary X = angle (1, X) enddef; vardef sin primary X = sind (X*radian) enddef; @@ -554,28 +700,28 @@ 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 degrees (expr t) = t*radian enddef; +vardef radians (expr t) = t/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 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 Arg primary Z = (angle Z)/radian enddef; +vardef Log primary Z = (ln (abs Z), Arg Z) enddef; +vardef cis primary T = dir (T*radian) enddef; +vardef zexp primary Z = (exp (xpart Z)) * cis (ypart Z) enddef; +vardef sgn primary Z = if not (Z = origin): unitvector fi Z enddef; vardef cosh primary X = - save temp; temp := 2 exp (-abs(X)); - if temp < reallysmall : + setnumeric (temp) 2 exp (-abs(X)); + if temp < reallysmall: TruncateWarn "Cosh"; temp := reallysmall; fi @@ -583,8 +729,8 @@ vardef cosh primary X = enddef; vardef sinh primary X = - save temp; temp := 2 exp (-abs(X)); - if temp < reallysmall : + setnumeric (temp) 2 exp (-abs(X)); + if temp < reallysmall: TruncateWarn "Sinh"; temp := reallysmall; fi @@ -592,164 +738,222 @@ vardef sinh primary X = enddef; vardef sech primary X = - save temp; temp := exp(-(abs (X))); + setnumeric (temp) exp(-(abs (X))); 2temp/(1 + temp*temp) enddef; vardef tanh primary X = - save temp; temp := exp(-2(abs (X))); + setnumeric (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 : + save temp, tempa; temp := exp(-(abs (X))); + tempa := (1 - temp*temp)/2; + if tempa < reallysmall: TruncateWarn "Csch"; - signof (X) 2temp / reallysmall - else: - signof (X) 2temp / (1 - temp*temp) + tempa := reallysmall; fi + signof (X) temp / tempa enddef; vardef coth primary X = - save temp; temp := tanh(X); - if abs(temp) < reallysmall : + setnumeric (temp) tanh(X); + if abs(temp) < reallysmall: TruncateWarn "Coth"; - temp := signof (temp) reallysmall; + temp := signof (X) 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."; + if y < 1: + TruncateWarn "acosh"; 0 else: - ln (y + (y+-+1)) + ln (y + (y +-+ 1)) fi enddef; -vardef asinh primary y = ln (y + (y++1)) 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 + 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."; + TruncateWarn "atanh"; signof (y) infinity fi enddef; -vardef polar (expr p) = (xpart p) * dir (ypart p) enddef; -def id (expr x) = x enddef; +vardef polar primary 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; +primarydef x**y = + if y=2: x*x + elseif (x = floor x) and (abs y = floor y): + 1 for n=1 upto y: *x endfor + else: takepower y of x + fi +enddef; +let ^ = **; +transform T_stack[]; +numeric 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; + 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 bcoords = hide ( T_push (ztr) ) enddef; +def ecoords = hide ( T_pop (ztr); vtr := vectorpart ztr ) enddef; + +vardef vectorpart primary T = T shifted -(origin transformed T) enddef; def apply_t (text Transformer) = ztr := identity Transformer transformed ztr; - vtr := ztr shifted - zconv(origin); + vtr := vectorpart ztr; enddef; -def xslant = slanted enddef; % (x+sy, y). +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 + 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). +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 + 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; +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) +vardef transformedpath (text Transformer) expr f = f Transformer enddef; -vardef scaledpath (expr p, s) expr f = - f shifted -p scaled s shifted p + +def rotatedpath (expr p, th) = + transformedpath ( + transformed vtr + rotatedaround (p transformed vtr, th) + transformed (inverse vtr) + ) enddef; -vardef xslantedpath (expr b, s) expr f = - f shifted (0, -b) slanted s shifted (0, b) +def reflectedpath (expr p, q) = + transformedpath ( + transformed vtr + reflectedabout (p transformed vtr, q transformed vtr) + transformed (inverse vtr) + ) enddef; -def slantedpath = xslantedpath enddef; -vardef yslantedpath (expr a, s) expr f = - f shifted (-a, 0) yslant s shifted (0, a) + +def scaledpath (expr p, s) = + transformedpath (shifted -p scaled s shifted p) enddef; -vardef xscaledpath (expr a, s) expr f = - f shifted (-a, 0) xscaled s shifted (a, 0) +def xscaledpath (expr a, s) = + transformedpath (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) +def yscaledpath (expr b, s) = + transformedpath (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) + +def slantedpath = xslantedpath enddef; +def xslantedpath (expr b, s) = + transformedpath (shifted (0, -b) slanted s shifted (0, b)) enddef; -vardef xyswappedpath expr f = f xyswap enddef; -vardef transformedpath (text Transformer) expr f = - f Transformer +def yslantedpath (expr a, s) = + transformedpath (shifted (-a, 0) yslant s shifted (0, a)) enddef; +def shiftedpath (expr v) = transformedpath (shifted v) enddef; + +def xyswappedpath = transformedpath (xyswap) 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); + save flag, flo, fhi, lo, hi, n; + boolean flag; flag = true; + convertpath (g) f; + n := length f; + + flo := snapto emin(a,b); + if flo = 0: + lo := 0; + elseif flo < 1: + setuplengtharray (cum, tot, idx) g; + flag := false; + lo := gettime (cum, idx) (flo*tot); else: - tb := gettime (cumlen, idx) (b*totlen); - ta := gettime (cumlen, idx) (a*totlen); + lo := n; fi - subpath (ta, tb) of f + + fhi := snapto emax (a,b); + if flo = fhi: + hi := lo; + elseif fhi < 1: + if flag: setuplengtharray (cum, tot, idx) g; fi + hi := gettime (cum, idx) (fhi*tot); + else: + hi := n; + fi + + if a > b: reverse fi subpath (lo, hi) of f +enddef; + +vardef gsubpath (expr a, b) expr f = subpath (a, b) of f enddef; + +def setuplengtharray (suffix cum, tot, idx) = + save cum, tot, idx; idx := 0; tot := makelengtharray (cum) +enddef; + +vardef pathtime@# (suffix p) = + if @# <= 0: 0 + elseif @# >= 1: length p + else: + setuplengtharray (cum, tot, idx) p; + gettime (cum, idx) (@#*tot) + fi +enddef; + +vardef pathpoint (expr frac) (suffix p) = + convertpath (_pp) p; pnt[pathtime[frac] (_pp)] (p) 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; +def orto (suffix u) (expr v) = addto u also v; enddef; + +def coloraddon (expr clr) (suffix v) = + addto active_plane also v _wc_ clr; +enddef; + +def _orto (suffix u, v) = + addto u also v; +enddef; vardef interior expr c = - save v; picture v; v := nullpicture; + newpicture (v); addto v contour (c.t_); v enddef; + vardef interiors suffix cc = - save _ints; picture _ints; _ints := nullpicture; + newpicture (_ints); for _idx = 1 upto cc: addto _ints also interior cc[_idx]); endfor @@ -757,28 +961,29 @@ vardef interiors suffix cc = enddef; def clipto (suffix vt) expr c = + if path c: clip vt to c; + fi enddef; def clipsto (suffix vt, cc) = begingroup - save _cl, _cl_; picture _cl, _cl_; _cl_ := nullpicture; + save _cl, _cl_; picture _cl, _cl_; _cl_ := nullpicture; for _idx = 1 upto cc: - _cl := vt; clip _cl to cc[_idx]; addto _cl_ also _cl; + _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 + setpicture (_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; + setpicture (_cl) vt; clip _cl to c; + newpicture (_pn); + addto _pn also (interior c ) _wc_ fillcolor; + addto _pn also _cl _wc_ background; _pn enddef; @@ -789,8 +994,8 @@ enddef; numeric minpenwd; minpenwd := .05bp; % 1 pixel at 1440dpi vardef picpath expr d = - save v; picture v; v := nullpicture; - if penwd >= minpenwd : + newpicture (v); + if penwd >= minpenwd: shpath (v, drawpen) (d); fi v @@ -802,59 +1007,56 @@ def picdot (suffix v) (expr w, p) = enddef; vardef setdot (expr apath, sc) = - if cycle apath : interior - else : picpath + if cycle apath: interior + else: picpath fi - (apath scaled emax(sc, minpenwd)) + (apath scaled emax (sc, minpenwd)) enddef; vardef shaded (expr clr) expr c = - if cycle c : - save v; picture v; - v := nullpicture; + if cycle c: + newpicture (v); addto v contour c _wc_ clr; v - else: picpath c % should we? or just make it null? + 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; +vardef fillwith (suffix v) (expr pic, dims, ll, ur) = + newpicture (b); 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 +def thatchf (suffix v) (expr CT, sp, a, b) = + begingroup + setnumeric (_sp) signof (ypart b - ypart 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 + endgroup 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; + picture atile.pic; atile.pic := nullpicture; + pair atile.dims; + atile.dims := (width, height)*unit; 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 : + def active_plane = atile.pic enddef; + save ztr, vtr; transform ztr, vtr; + ztr := identity scaled unit; vtr := ztr; + save xneg, xpos, yneg, ypos; + xneg := 0; xpos := width; yneg := 0; ypos := height; + save ClipOn; boolean ClipOn; + if clipit: ClipOn := true; - save ClipPath; path ClipPath[]; - ClipPath = 1; - ClipPath[1] = rect(origin, (atile.wd, atile.ht)); + setarray (path) (ClipPath) (rect(origin, atile.dims)); else: ClipOn := false; fi @@ -865,88 +1067,173 @@ def endtile = 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) + (known atile.pic ) and (picture atile.pic) and + (known atile.dims) and (pair atile.dims ) 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 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 +def getbbox (suffix ll, ur) expr g = + 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); +def safedraw = colorsafedraw (drawcolor) enddef; +def colorsafedraw (expr clr) expr d = + begingroup + setpicture (v) picpath d; + DoClip (v); coloraddon (clr, v); + endgroup enddef; -def NoCycleWarn expr s = - GBmsg s & " cannot be applied to an open path. " - & "The path will be drawn instead."; +def NoCycle (expr s) expr p = + GBwarn s & " cannot be applied to an open path." + & " The path will be drawn instead."; + safedraw p; enddef; -def safefill = colorsafefill (fillcolor) enddef; +def safefill = colorsafefill (fillcolor) enddef; vardef colorsafefill (expr clr) expr c = - if cycle c : - save v; picture v; v := interior c; + if cycle c: + setpicture (v) interior c; DoClip (v); - coloraddto (clr) (active_plane, v); - else: NoCycleWarn "fill"; safedraw c; + coloraddon (clr, v); + else: NoCycle("fill") c; fi enddef; def safeunfill expr c = - if cycle c : noclip (colorsafefill (background) c); - else: NoCycleWarn "unfill"; safedraw c; + if cycle c: noclip (colorsafefill (background) c); + else: NoCycle("unfill") c; fi enddef; def safeclip expr c = - if cycle c : clipto (active_plane) c; - else: NoCycleWarn "clip"; safedraw c; + if cycle c: clipto (active_plane) c; + else: NoCycle("clip") 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") - ""; +hide ( + if (not path f) and (not pair f): + GBerrmsg ("improper expression type.") + "The second argument to `store' must be a path or pair."; fi - if not path fs : path fs; fi + if not path fs: path fs; fi fs := f ) enddef; -vardef stored (suffix fs) expr f = store (fs) f; f enddef; +vardef stored (suffix fs) expr f = store (fs) f; f enddef; -def drawn = colordrawn (drawcolor) enddef; +def drawn = colordrawn (drawcolor) enddef; vardef colordrawn (expr clr) expr f = - colorsafedraw (clr) (zconv (f)); f + colorsafedraw (clr) (zconv (f)); f +enddef; + +def zigzag = colorzigzag (drawcolor) enddef; +def colorzigzag (expr clr) = colorwiggle (false, clr, 0) enddef; +def sinewave = colorsinewave (drawcolor) enddef; +def colorsinewave = colorwiggle (true) enddef; + +vardef colorwiggle (expr smth, clr, tens, blen, elen, len, wid) expr f = + convertpath (g) f; + setuplengtharray (cumlen, totlen, ct) g; + save B; + if cycle f: + B := 0; + else: + B := abs(blen)/_rescale_factor; + totlen := totlen - B - abs(elen)/_rescale_factor; + fi + setnumeric (n) 2*round (totlen/len*_rescale_factor); + if n < 2: + colorsafedraw (clr) g; + else: + save T, U, X, Y, Z, p; + pair U, X, Y, Z; path p; + T := if cycle f: 0 else: gettime (cumlen, ct) (B) fi; + Z := pnt[T] (g); + p :=if not cycle f: (subpath (0,T) of g) + if smth: {curl 0} ..tension tens.. else: -- fi + fi + for i = 1 upto n: + hide( + T := gettime (cumlen, ct) (B+(i/n)*totlen); + X := Z; Z := pnt[T] (g); + Y := .5[X,Z]; U := sgn (Z-X); + ) + (Y + (U zscaled (0, if even i: - fi wid))) + if smth: {U}..tension tens.. else: -- fi + endfor + if cycle f: cycle + else: if smth: {curl 0} fi (subpath (T, length g) of g) + fi; + newpicture (v); + shpath (v, drawpen) (p); + DoClip(v); coloraddon (clr, v); + fi + f enddef; -def filled = colorfilled (fillcolor) enddef; +def corkscrew = colorcorkscrew (drawcolor) enddef; +vardef colorcorkscrew (expr clr, tens, blen, elen, len, wid) expr f = + convertpath (g) f; + setuplengtharray (cumlen, totlen, ct) g; + save B; + if cycle f: + B := 0; + else: + B := abs(blen)/_rescale_factor; + totlen := totlen - B - abs(elen)/_rescale_factor; + fi + setnumeric (n) round (totlen/len*_rescale_factor); + if n < 2: + colorsafedraw (clr) g; + else: + save T, U, X, Y, Z, p; + pair U, X, Y, Z; path p; + T := if cycle f: 0 else: gettime (cumlen, ct) (B) fi; + Z := pnt[T] (g); + p :=if (not cycle f) and (B > 0): (subpath (0,T) of g)-- fi + for i = 1 upto n: + hide( + T := gettime (cumlen, ct) (B+(i/n)*totlen); + X := Z; Z := pnt[T] (g); + Y := .5[X,Z]; U := sgn (Z-X); + ) + (X + (U zscaled (0,-wid))){ U}..tension tens.. + (Y + (U zscaled (0, wid))){-U}..tension tens.. + endfor + if cycle f: cycle + else: + {U}(Z + (U zscaled (0,-wid))) + if elen <> 0: --(subpath(T, length g) of g) fi + fi; + newpicture (v); + shpath (v, drawpen) (p); + DoClip(v); coloraddon (clr, v); + fi + f +enddef; + +def filled = colorfilled (fillcolor) enddef; vardef colorfilled (expr clr) expr c = - colorsafefill (clr) zconv (c); 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; +vardef unfilled expr c = safeunfill zconv (c); c enddef; +vardef Clip expr c = safeclip zconv (c); c enddef; -numeric shadewd; shadewd := 0.5bp; +numeric shadewd; shadewd := 0.5bp; path shadedotpath; -shadedotpath := fullcircle; % unitsquare; +shadedotpath := fullcircle; 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; + convertpath (g) f; + setnumeric (gr) 1 - (.88*abs(shadewd)/sp)**2; + if not cycle g: NoCycle("shade") g; + elseif gr <= 0: safefill g; else: colorsafefill (gr*white) g; fi @@ -955,647 +1242,407 @@ enddef; polkadotwd := 5bp; mindotspace := 1bp; -path polkadotpath; polkadotpath := fullcircle; +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) : + convertpath (g) f; + if not cycle g: NoCycle("polkadot") 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); + setbbox (ll, ur) g; + save dx, dy, dshift; pair dshift; + dx := sp/2; dy := dx*sqrt 3; + dshift := (xpart(ur - ll) mod dx, ypart (ur - ll) mod dy)/2; + save p, dims; pair p, dims; + p := ll + dshift; 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); + setpicture (thepolkadot) setdot (polkadotpath, polkadotwd); + newpicture (v); + fillwith (v) (thepolkadot, dims, p, ur); + fillwith (v) (thepolkadot, dims, p + (dx, dy), ur); + DoClip (v); clipto (v) g; + coloraddon (fillcolor, v); fi f enddef; -def thatch = colorthatch (hatchcolor) 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; + convertpath (g) f; + if not cycle g: NoCycle("hatch") 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); + newpicture (v); + setbbox (ll, ur) g rotated -theta; + thatchf (v, identity rotated theta, sp, ll, ur); + DoClip (v); clipto (v) (g); + coloraddon (clr, v); 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 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 +def xhatch = colorxhatch (hatchcolor) enddef; +def colorxhatch (expr clr, sp) = + colorthatch (clr) (sp, 45) colorthatch (clr) (sp, -45) enddef; +vardef NoTile (suffix atile) expr g = + GBwarn str atile & " is not a valid tile for tess()." + & " The path will be drawn instead."; + safedraw g; +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; + convertpath (_g) c; + if not cycle _g: NoCycle("tess") _g; + elseif not is_tile (atile): NoTile (atile) _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); + setbbox (_ll, _ur) _g; + newpicture (_ts); + fillwith (_ts) (atile.pic, atile.dims, _ll, _ur); + DoClip (_ts); clipto (_ts) _g; + _orto (active_plane, _ts); 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 +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 _rescale_factor: _rescale_factor := 0.1in; fi +numeric last_dot_size; last_dot_size := 0; 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."; + convertpath (_g) f; + save _dpat; + if not mkdasharrays (pat) (_dpat): + GBwarn "Dash pattern " & str pat + & " undefined. Path will be drawn instead."; safedraw _g; - elseif pat.rep < 2 : % no "spaces" + elseif _dpat.rep < 2: 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]; + save _dl; + forsuffixes _s = start, rep, finish: + _dl._s := 0; + for i = 1 upto _dpat._s: + _dpat._s[i] := _dpat._s[i]/_rescale_factor; + _dl._s := _dl._s + _dpat._s[i]; endfor endfor - if _dl.rep = 0 : - GBmsg "Dash pattern " & str pat & " has length 0. " & - "Path will be drawn instead."; + + if _dl.rep = 0: + GBwarn "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; + setuplengtharray (_cumlen, _totlen, _ct) _g; + save _n, _sf, _no_dots; + boolean _no_dots; _no_dots := true; + _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; + forsuffixes _s = start, rep, finish: + for _i = 1 upto _dpat._s: + if (_dpat._s[_i] = 0) and _no_dots: _no_dots := false; + else: _dpat._s[_i] := _dpat._s[_i]*_sf; + fi 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); + if _no_dots: + else: + if unknown plot_pic: + save plot_pic; path plot_pic; + plot_pic := dotpath; + fi; + last_dot_size := + if known plot_pic.size: plot_pic.size else: penwd fi; + setpicture (dashingdot) makesymbol (plot_pic, last_dot_size); 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 : + save _t, _d, _v; + picture _v; _v := nullpicture; + _d0 := 0; _t0 := 0; + dashit (_dpat.start) (_v); + + 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); + _t0 := gettime (_cumlen, _ct) (_d0); + dashit (_dpat.rep) (_v); endfor - % add _m patterns and reset. - DoClip(_v); - coloraddto (drawcolor) (active_plane, _v); + DoClip (_v); + coloraddon (drawcolor, _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); + _t0 := gettime (_cumlen, _ct) (_d0); + dashit (_dpat.finish) (_v); + DoClip (_v); + coloraddon (drawcolor, _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)); +vardef makelengtharray (suffix clen) suffix p = + setsplit (_s) segment_split; + numeric clen[]; + clen := _s * length p; clen0 := 0; + for _i = 1 upto clen: + clen[_i] := clen[_i-1] + abs (pnt[_i/_s] (p) - pnt[(_i-1)/_s] (p)) / + _rescale_factor; 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) + 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 + setnumeric (_gtl) emax (arr[ct], emin (arr[arr], lngth)); + setsplit (_s) segment_split; + forever: exitif ( (arr[ct] <= _gtl) and (_gtl <= arr[ct+1]) ); + next ct; endfor - if arr[ct] = arr[ct+1] : ct - else: ( ct + (_gtl - arr[ct]) / (arr[ct+1] - arr[ct]) ) - fi /_s + if arr[ct] = arr[ct+1]: ct + else: ( ct + (_gtl - arr[ct]) / (arr[ct+1] - arr[ct]) ) + fi /_s enddef; +def next suffix X = X := X + 1; 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; + if odd _k: + if pos[_k] = 0: + _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: + else: _d0 := _d1 + pos[_k]; - _t0 := gettime(_cumlen, _ct) (_d0); + _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]; + list (pat) (t); + if (pat = 0) or (odd (pat) and (pat > 1)): + pat[incr pat] := 0; + fi +enddef; + +vardef mkdasharrays (suffix src, dest) = + save _bad; boolean _bad; _bad := false; + forsuffixes _s = start, rep, finish: + numeric dest._s, dest._s[]; + boolean _bad._s; + if knownnumericarray src._s: + copyarray (src._s) (dest._s); + _bad._s := false; + else: + _bad := _bad._s := true; + fi endfor - pat.finish := 1; - pat.finish[1] := pat.rep[1]*dash_finish; + % _bad = one of the three arrays not copied. + if _bad: + if knownnumericarray src: _bad := false; + if _bad.rep: % make dest.rep = src + copyarray (src) (dest.rep); + fi + if _bad.start: % shrink first dash to get dest.start + copyarray (src) (dest.start); + dest.start1 := dash_start*src1; + fi + if _bad.finish: % use partial first dash for dest.finish + dest.finish := 1; + dest.finish1 := dash_finish*src1; + fi + fi + fi + not _bad enddef; -vardef DASHED (expr dlen, dgap) expr f = - save dashes; dashpat (dashes) (dlen, dgap); +vardef Dashed (expr dlen, dgap) expr f = + save dashes; dashpat (dashes) (dlen, dgap); gendashed (dashes) f enddef; -let dashed_ = dashed; -def dashed = DASHED enddef; +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); + save dots; dashpat (dots) (0, dgap); + setpicture (plot_pic) makesymbol (spath, sc); + plot_pic.size := sc; gendashed (dots) f enddef; -path dotpath; dotpath := fullcircle; -vardef dotted (expr dsize, dgap) expr f = - doplot (dotpath, dsize, dgap) f -enddef; +path dotpath; dotpath := fullcircle; +def dotted = doplot (dotpath) 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) + if size > 0: + 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); fi + f 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 +def showcontrols = colorshowcontrols (pointcolor) enddef; +vardef colorshowcontrols (expr clr, syma, symb, size) expr f = + save shpre, shpost; + pair shpre[], shpost[]; + shpre := 0; shpost := 0; + for a = 0 upto (length f) if cycle f: - 1 fi: + shpre [incr shpre] := pre [a] (f); + shpost[incr shpost] := post[a] (f); + colorsafedraw (clr) + (zconv (shpre[shpre]--pnt[a](f)--shpost[shpost])); endfor - if dashtype = 0 : - SetdataWarn "dashes"; - defaultdashes; + if size > 0: + if not numeric syma: dosymbols (clr, syma, size) (shpre) ; fi + if not numeric symb: dosymbols (clr, symb, size) (shpost); fi fi -enddef; -def getdashpat expr n = dashtype[n mod dashtype] enddef; - -def SetdataWarn expr s = - GBmsg "Command setdata"& s &"() failed; using defaults." + f 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 +def doubledraw = colordoubledraw (drawcolor) enddef; +vardef colordoubledraw (expr clr, sep) expr f = + convertpath (g) f; + colorsafedraw (clr) (parapath ( sep/2) g); + colorsafedraw (clr) (parapath (-sep/2) g); + f 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; +vardef centerit (expr pic) = + pic shifted -(0.5[urcorner pic, llcorner pic]) 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; +vardef makesymbol (expr spath, sc) = + if picture spath : + spath + elseif path spath: setdot (spath, sc) + elseif string spath: + spath infont defaultfont scaled defaultscale + else: + GBwarn "Undefined symbol for plotting, " + & "dotpath will be used instead."; + setdot (dotpath, sc) 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 : + if filled: plotsymbol (SolidCircle, ptwd) (t); - else : + else: begingroup; - save clearsymbols; boolean clearsymbols; clearsymbols := true; + setboolean (clearsymbols) true; plotsymbol (Circle, ptwd) (t); endgroup fi enddef; -boolean clearsymbols; clearsymbols := false; +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); + if path pth: + ( pnt0 (pth) = pnt[length pth] (pth) ) and (not cycle pth) + and (length pth > 0) + else: false 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 +def clearopenpath expr f = + if clearable (f): safeunfill f & cycle; 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 +def plotsymbol = colorplotsymbol (pointcolor) enddef; +def colorplotsymbol (expr clr, spath, sc) (text t) = + if sc > 0: + begingroup + setpairs (_cpls) (t); + if _cpls > 0: dosymbols (clr, spath, sc) (_cpls); fi + endgroup 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 +def dosymbols (expr clr, spath, sc) (suffix arr) = + if clearsymbols and clearable (spath): + addsymbols (background, makesymbol (spath&cycle, sc)) (arr); fi + addsymbols (clr, makesymbol (spath, sc)) (arr); 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; +def addsymbols (expr clr, symb) (suffix arr) = + newpicture (_pls); + for _idx = 1 upto arr: + picdot (_pls, symb, zconv (arr[_idx])); 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 + DoClip (_pls); coloraddon (clr, _pls); 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; +def putimage (suffix pic) (text t) = + newpicture (_pti); + for _itm = t: + addto _pti also + (pic shifted zconv (_itm)); + DoClip (_pti); addto active_plane also _pti; + _pti := nullpicture; 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; +def arrowdraw (expr hlen) (expr f) = + store (curpath) headpath (hlen, 0, 0) drawn f; 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 +def xaxis (expr hlen) = arrowdraw (hlen) ((xneg, 0)--(xpos, 0)); 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 +def yaxis (expr hlen) = arrowdraw (hlen) ((0, yneg)--(0, ypos)); enddef; +def axes (expr hlen) = xaxis (hlen); yaxis (hlen); enddef; -def arrowdraw (expr hlen) (expr f) = - store (curpath) headpath (hlen, 0, 0) drawn f; -enddef; +laxis := baxis := raxis := taxis := 0; -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; +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; -laxis := baxis := raxis := taxis := 0; +vardef axis@# (expr len) = headpath (len, 0, 0) axisline@# enddef; -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@# +vardef borderrect = + rect((xneg+laxis,yneg+baxis),(xpos-raxis,ypos-taxis)) enddef; - numeric inside, outside, centered, onleft, onright, ontop, onbottom; inside := -2; outside := -1; @@ -1609,63 +1656,97 @@ 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; + pair _U, _P; path _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 + _tic := (-_U--(0,0)) shifted (_tp*_U) scaled len; for _a = t: - safedraw ((_tic1--_tic2) shifted zconv (loc + _a*pdir)); + safedraw (_tic 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 xmarks = axismarks ( 90, xtick, origin, right) enddef; +def ymarks = axismarks (-90, ytick, origin, up) enddef; def lmarks = axismarks (-90, ltick, (xneg + laxis, 0), up) enddef; -def bmarks = axismarks ( 90, btick, (0, yneg + baxis), right) 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; +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; +path griddotpath; griddotpath := fullcircle; +def grid = vargrid (0.5bp) enddef; +vardef vargrid (expr dsize, xsp, ysp) = + 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))); + for n = ceiling ((xneg + laxis)/xsp) upto floor ((xpos - raxis)/xsp): + for m = ceiling ((yneg + baxis)/ysp) upto floor ((ypos - taxis)/ysp): + picdot (gridpic, gdot, zconv ((n*xsp, m*ysp))); endfor endfor - coloraddto (pointcolor) (active_plane) (gridpic); + coloraddon (pointcolor, gridpic); enddef; +def vgrid = vargrid 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)); + 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)); + 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); + 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); +def vectorfield (expr len, xsp, ysp) (text fcn) (text cond) = + save _vf, _is_OK; + vardef _vf (expr x,y) = ((0,0)--(fcn)) shifted (x,y) enddef; + vardef _is_OK (expr x,y) = cond enddef; + mkvectorfield (len, xsp, ysp) (_vf, _is_OK); enddef; + +vardef mkvectorfield (expr len, xsp, ysp) (suffix vf, isOK) = + for n = ceiling ((xneg + laxis)/xsp) upto floor ((xpos - raxis)/xsp): + for m = ceiling ((yneg + baxis)/ysp) upto floor ((ypos - taxis)/ysp): + if isOK (n*xsp,m*ysp): arrowdraw (len) (vf(n*xsp,m*ysp)); fi + endfor + endfor +enddef; + +def plrvectorfield (expr len, rsp, tsp) (text fcn) (text cond) = + save _vf, _is_OK, _A, _B, _C, _D; + _A := xneg + laxis; _B := xpos + raxis; + _C := yneg + baxis; _D := ypos + taxis; + vardef _vf (expr r,t) = ((0,0)--(fcn)) shifted (r*dir t) enddef; + vardef _is_OK (expr r,t) = + save _X, _Y; _X := r*cosd t; _Y := r*sind t; + (cond) and (_A < _X) and (_X < _B) and (_C < _Y) and (_Y < _D) + enddef; + mkplrvectorfield (len, rsp, tsp) (_vf, _is_OK); +enddef; + +vardef mkplrvectorfield (expr len, rsp, tsp) (suffix vf, isOK) = + save rmin, rmax, tmin, tmax; + getpolarbounds; + if rmin = 0: + if isOK (0,tmin): arrowdraw (len) (vf (0,tmin)); fi + rmin := rsp; + fi + for n = ceiling (rmin/rsp) upto floor (rmax/rsp): + for m = ceiling (tmin/tsp) upto floor (tmax/tsp): + if isOK (n*rsp,m*tsp): arrowdraw (len) (vf (n*rsp,m*tsp)); fi + endfor + endfor +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)) ); + for rad = (if rstart = 0: rstep else: rstart fi) + step rstep until rstop: + orto (X, picpath zconv (arcplr (origin, tstart, tstop, rad)) ); endfor enddef; def patchrays (suffix X) (expr tstart, tstop, tstep, rstart, rstop) = @@ -1674,116 +1755,130 @@ def patchrays (suffix X) (expr tstart, tstop, tstep, rstart, rstop) = 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); +def plrpatch (expr rstart, rstop, rstep, tstart, tstop, tstep) = +begingroup + newpicture (v); + patcharcs (v) (rstart, rstop, rstep, tstart, tstop); + coloraddon (drawcolor, v); + v := nullpicture; + patchrays (v) (tstart, tstop, tstep, rstart, rstop); + coloraddon (drawcolor, v); +endgroup enddef; def gridarcs (expr rstep) = beginpolargrid; - if rmin = 0 : % add "circle" of radius 0 - picdot (gridpic, setdot(griddotpath, penwd), zconv(origin)); + if rmin = 0: + picdot (gridpic, setdot (griddotpath, penwd), zconv (origin)); fi - rmin := rstep * floor(rmin/rstep + 1); - rmax := rstep*ceiling(rmax/rstep - 1); + 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); + tmin := tstep * ceiling (tmin/tstep); + tmax := tstep * floor (tmax/tstep); patchrays (gridpic) (tmin, tmax, tstep, rmin, rmax); endpolargrid (drawcolor, .5penwd); enddef; +def polargrid (expr rstep, tstep) = + gridarcs (rstep); gridrays (tstep); +enddef; + +def polargridpoints (expr dsize, rstep, tstep) = + beginpolargrid; + setpicture (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 beginpolargrid = - begingroup; - save p, r, t, rmax, rmin, tmax, tmin; +begingroup; + save rmax, rmin, tmax, tmin; + getpolarbounds; + newpicture (gridpic); +enddef; + +def getpolarbounds = + save p, r, t; 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 : + 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 + 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 : + if (xneg < 0) and (xpos > 0) and (yneg < 0) and (ypos > 0): + tmin := 0; tmax := 360; + elseif (p0 = origin): tmin := 0; tmax := 90; + elseif (p1 = origin): tmin := -90; tmax := 0; + elseif (p2 = origin): tmin := -180; tmax := -90; + elseif (p3 = origin): 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 + t := t0 + anglefromto (p0, p[j]); + 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); + if (xneg < 0) and (0 < xpos): + rmin := emin (abs(yneg), abs(ypos)); + elseif (yneg < 0) and (0 < ypos): + rmin := emin (abs(xneg), abs(xpos)); + else: + 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); + clipto (gridpic) rect ( zconv ((xneg, yneg)) - size*(1,1), + zconv ((xpos, ypos)) + size*(1,1) ); + coloraddon (clr, 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 ( arcplr (origin, 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 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); + 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; + for _uncle = 1 upto Bob - 1: + (Bob1 - Bob0) rotated (360/Bob*_uncle) = 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 + save A, B, C, zz; pair A, B, C, zz; + B := pnt[n + 1] (t); C := pnt[n + 2] (t); zz = whatever[B,C]; - zz = A + whatever*((C-B) rotated 90); + zz = pnt[n](t) + whatever*((C-B) rotated 90); zz enddef; @@ -1800,11 +1895,11 @@ vardef median expr n of t = enddef; vardef anglebisectorpt expr n of t = - save A, B, C; pair A, B, C; + 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; + save zz; pair zz; zz = whatever[B,C]; zz = A + whatever*((B-A) rotated (.5*cornerangle (A,B,C))); zz @@ -1814,232 +1909,417 @@ vardef anglebisector expr n of t = (pnt[n](t))--(anglebisectorpt n of t) enddef; +vardef anglefromto (expr u, v) = + if (u = origin) or (v = origin): 0 + else: angle (v rotated (-angle u)) + fi +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))) + if (A = B) and (B = C) : 60 + elseif (A=B) or (A=C) : 90 + else: anglefromto (B - A, C - A) fi enddef; vardef mkpath (expr smooth, tens, cyclic) (suffix pts) = - if smooth : mksmooth (tens, cyclic, pts) - else : mkpoly (cyclic, pts) - fi + if smooth: mksmooth (tens) + else: mkpoly + fi (cyclic, pts) enddef; vardef mkpoly (expr cyclic) (suffix pts) = for _i = 1 upto pts-1: pts[_i]-- endfor - pts[pts] if cyclic : -- cycle fi + pts[pts] if cyclic: -- cycle else: {0,0} fi enddef; vardef polyline (expr cyclic) (text t) = - save _pl; textpairs (_pl) (t); mkpoly (cyclic, _pl) + setpairs (_pl) (t); + if _pl=0: NoPoints ("polyline", _pl); fi + mkpoly (cyclic, _pl) +enddef; + +def NoPoints (expr s) (suffix pts) = + GBwarn s & " attempted with empty list."; pts[incr pts] := origin; +enddef; + +vardef turtle (text t) = + setnumeric (_tu) 0; + pair _tu[]; _tu0 := origin; + for _a = t: _tu[incr _tu] := _tu[_tu - 1] + _a; endfor + if _tu = 0: NoPoints("turtle", _tu); fi + mkpoly (false, _tu) enddef; vardef mksmooth (expr tens, cyclic) (suffix pts) = - pts1 - if pts = 1 : - if cyclic : &cycle fi + if pts = 1: onepointpath (cyclic, pts1) else: - if cyclic : - {pts[2]-pts[pts]} - fi + settension (_tn) tens; fixtension (_tn); + pts1 if cyclic: {pts[2]-pts[pts]} fi for _i = 2 upto pts-1: - ..tension tens..pts[_i]{pts[_i+1]-pts[_i-1]} + ..tension _tn..pts[_i]{pts[_i+1]-pts[_i-1]} + endfor + ..tension _tn..pts[pts] + if cyclic: {pts[1]-pts[pts-1]}..tension _tn..cycle fi + fi +enddef; + +vardef mktenser (expr tens, cyclic) (suffix pts) = + if pts = 1: onepointpath (cyclic, pts1) + else: + settension (_tn) tens; fixtension (_tn); + pts1 if cyclic: {pts[2]-pts[pts]} fi + for _i = 2 upto pts-1: + ..tension atleast _tn..pts[_i]{pts[_i+1]-pts[_i-1]} + endfor + ..tension atleast _tn..pts[pts] + if cyclic: {pts[1]-pts[pts-1]}..tension atleast _tn..cycle fi + fi +enddef; + +vardef mkconvex (expr tens, cyclic) (suffix pts) = + save _B, _d, _tmp; pair _d[]; + settension (_tn) tens; fixtension (_tn); + if pts < 4: mktenser (_tn, cyclic) (pts) + else: + for _j = 2 upto pts - 1: + _B[_j] := sqrt(abs((pts[_j]-pts[_j-1])xprod(pts[_j+1]-pts[_j]))); + endfor + if cyclic: + _B1 := sqrt(abs((pts1 - pts[pts])xprod(pts2 - pts1))); + _B[pts] := sqrt(abs((pts[pts]-pts[pts-1])xprod(pts1 - pts[pts]))); + else: + _B1 := _B2; + _B[pts] := _B[pts-1]; + fi + for _j = 2 upto pts - 1: + _tmp := _B[_j-1] + _B[_j+1]; + _d[_j] := + if _tmp = 0: origin % signal to use curl1 + else: + ( _B[_j+1]*(pts[_j] - pts[_j-1]) + + _B[_j-1]*(pts[_j+1] - pts[_j]) )/_tmp + fi; endfor - ..tension tens..pts[pts] - if cyclic : - {pts[1]-pts[pts-1]}..tension tens..cycle + if cyclic: + _tmp := _B[pts] + _B2; + _d1 := + if _tmp = 0: origin + else: + (_B2*(pts1 - pts[pts]) + _B[pts]*(pts2 - pts1))/_tmp + fi; + _tmp := _B[pts-1] + _B1; + _d[pts] := + if _tmp = 0: origin + else: + ( _B1*(pts[pts] - pts[pts-1]) + + _B[pts-1]*(pts1 - pts[pts]) )/_tmp + fi; + else: + _d1 := origin; _d[pts] := origin; fi + pts1 + for _j = 1 upto pts-1: + {if _d[_j] = origin: curl1 else: _d[_j] fi} + ..tension atleast _tn..pts[_j+1] + endfor + {if _d[pts] = origin: curl1 else: _d[pts] fi} + if cyclic: ..tension atleast _tn..cycle fi fi enddef; -def curve = tcurve (default_tension) enddef; +numeric default_tension; default_tension := 1; +def curve = tcurve (default_tension) enddef; vardef tcurve (expr tens, cyclic) (text t) = - save _tc; textpairs (_tc) (t); mksmooth (tens, cyclic, _tc) + setpairs (_tc) (t); mksmooth (tens, cyclic, _tc) +enddef; + +def ccurve = tccurve (default_tension) enddef; +vardef tccurve (expr tens, cyclic) (text t) = + setuniquepairs (_tcc) (t); mkconvex (tens, cyclic, _tcc) 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 + settension (_tn) tens; fixtension (_tn); + pts1 + for _i = 2 upto pts: ..tension _tn..pts[_i] endfor + if cyclic: ..tension _tn..cycle else: {0,0} fi enddef; -def bezier = tbezier (default_tension) enddef; +def bezier = tbezier (default_tension) enddef; vardef tbezier (expr tens, cyclic) (text t) = - save _tsb; textpairs (_tsb) (t); mkbezier (tens, cyclic) (_tsb) + setpairs (_tbs) (t); + if _tbs=0: NoPoints ("bezier", _tbs); fi + mkbezier (tens, cyclic) (_tbs) 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 + if pts=1: {0,0} + else: + for _i = 2 step 2 until pts - 1: + ..controls 1/3[pts[_i], pts[_i-1] ] and 1/3[pts[_i], pts[_i+1] ].. + pts[_i+1] + endfor + if cyclic: + ..controls 1/3[ pts[pts], pts[pts - 1] ] + and 1/3[ pts[pts], pts1 ]..cycle + fi + fi enddef; vardef qbezier (expr cyclic) (text t) = - save _qbz; textpairs (_qbz) (t); mkqbezier (cyclic) (_qbz) + setpairs (_qbz) (t); + if _qbz=0: NoPoints ("qbezier", _qbz); fi + if _qbz=1: onepointpath (cyclic, _qbz1) + else: + if (cyclic and odd _qbz) or (not cyclic and even _qbz): + _qbz[incr _qbz] := _qbz[_qbz-1]; + fi + mkqbezier (cyclic) (_qbz) + fi enddef; -vardef openqbs (text t) = - save _oq; textpairs (_oq) (t); mkqbs (_oq) +vardef fcncontrol (expr ftens, X, Y, Z) = + Y if (xpart(Z-Y) <> 0) and (xpart(Y-X) <> 0): + + xpart(Z-Y)/3/xpart(Z-X)*(Z - X)/ftens fi enddef; -vardef closedqbs (text t) = - save _cq; textpairs (_cq) (t); - _cq[incr _cq] := _cq1; _cq[incr _cq] := _cq2; - mkqbs (_cq) & cycle +vardef mkfcnpath (expr ftens) (suffix q) = + settension (_tn) ftens; + if _tn <= 0: _tn := 1; fi + for _i = 1 upto q - 1: + q[_i]..controls fcncontrol (_tn) (q[_i-1], q[_i], q[_i+1]) + and fcncontrol (_tn) (q[_i+2], q[_i+1], q[_i]).. + endfor + q[q]{0,0} enddef; +def fcncurve = functioncurve (default_tension) enddef; +def tfcncurve = functioncurve enddef; +vardef functioncurve (expr ftens) (text t) = + settension (_ftens) ftens; if _ftens < 1/3: _ftens := 1/3; fi + setuniquepairs (_fc) (t); + if _fc > 1: _fc0 := _fc1; _fc[_fc+1] := _fc[_fc]; fi + mkfcnpath (_ftens) (_fc) +enddef; + +def openqbs = qspline (false) enddef; +def closedqbs = qspline (true) 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]] + 0.5[ b1, b2] + if b<3: {0,0} + else: + for _i = 2 upto b-1: + ..controls 1/6[ b[_i], b[_i-1] ] and 1/6[ b[_i], b[_i+1] ].. + 0.5[ b[_i], b[_i+1] ] + endfor + fi 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 +vardef qspline (expr cyclic) (text t) = + setpairs (_qs) (t); + if _qs=0: NoPoints ("qspline", _qs); fi + if _qs=1: _qs[incr _qs] := _qs1; fi + if cyclic: + _qs[incr _qs] := _qs1; _qs[incr _qs] := _qs2; + fi + mkqbs (_qs) if cyclic: & cycle fi enddef; +vardef mkcbs (suffix b) = + (b[1]+4b[2]+b[3])/6 + if b < 4: {0,0} + else: + for _i = 3 upto b-1: + ..controls 1/3[ b[_i-1], b[_i] ] and 1/3[ b[_i], b[_i-1] ] + .. (b[_i-1] + 4b[_i] + b[_i+1])/6 + endfor + fi +enddef; + +def mkopencbs = mkcbs enddef; vardef mkclosedcbs (suffix b) = - mkopencbs (b) & opencbs (b[b-2],b[b-1],b[b], b1, b2, b3) & cycle + mkcbs (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) +def opencbs = cspline (false) enddef; +def closedcbs = cspline (true) enddef; + +vardef cspline (expr cyclic) (text t) = + setpairs (_cs) (t); + if _cs=0: NoPoints ("cspline", _cs); fi + for _idx = _cs upto 2: _cs[incr _cs] := _cs[_idx]; endfor + if cyclic: + for _idx = 1 upto 3: _cs[incr _cs] := _cs[_idx]; endfor + fi + mkcbs (_cs) if cyclic: & cycle fi +enddef; +def init_spline_eqns (suffix pts) = + save _spl_pre, _spl_post; + pair _spl_pre[], _spl_post[]; + for j= 2 upto pts - 1: + _spl_post[j] + _spl_pre[j] = 2pts[j]; + _spl_pre[j+1]+2_spl_pre[j] = 2_spl_post[j]+_spl_post[j-1]; + endfor enddef; -vardef closedcbs (text t) = - save _clc; textpairs (_clc) (t); mkclosedcbs (_clc) + +def closed_spline_eqns (suffix pts) = + _spl_post1 + _spl_pre1 = 2pts1; + _spl_post[pts] + _spl_pre[pts] = 2pts[pts]; + _spl_pre2 + 2_spl_pre1 = 2_spl_post1 + _spl_post[pts]; + _spl_pre1+2_spl_pre[pts] = 2_spl_post[pts]+_spl_post[pts-1]; 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) +def relaxed_spline_eqns (suffix pts) = + _spl_pre2 + pts1 = 2_spl_post1; + pts[pts] + _spl_post[pts-1] = 2_spl_pre[pts]; +enddef; + +vardef mksplinepath (expr closed) (suffix pts) = + pts1..controls _spl_post1 and + for j = 2 upto pts if not closed: -1 fi: + _spl_pre[j]..pts[j]..controls _spl_post[j] and + endfor + if closed: _spl_pre1..cycle else: _spl_pre[pts]..pts[pts] fi +enddef; + +def mkspline (expr closed) (suffix pts) = + init_spline_eqns (pts); + if closed: closed_spline_eqns (pts); + else: relaxed_spline_eqns (pts); fi + mksplinepath (closed) (pts) 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]).. +vardef dospline (expr closed) (text the_list) = + setpairs (_sp) (the_list); + if _sp=0: NoPoints ("dospline", _sp); fi + if _sp=1: _sp[incr _sp] := _sp1; fi + mkspline (closed) (_sp) +enddef; + +def init_fcnspl_eqns (suffix pts) = + save _dx, _sl; numeric _dx[], _sl[]; + _dx1 := xpart (pts2 - pts1); + for j = 2 upto pts - 1: + _dx[j] := xpart (pts[j+1] - pts[j]); + _sl[j + 1]*_dx[j] + _sl[j-1]*_dx[j-1] + 2_sl[j]*(_dx[j] + _dx[j-1]) + = 3*ypart(pts[j+1] - pts[j-1]); 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) +def periodic_fcnspl_eqns (suffix pts) = + _sl1 = _sl[pts]; + _sl2*_dx1 + 2_sl1*_dx1 + 2_sl[pts]*_dx[pts-1] + _sl[pts-1]*_dx[pts-1] + = 3 * ypart (pts[2] - pts[pts-1]); 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) +def relaxed_fcnspl_eqns (suffix pts) = + _sl2*_dx1 + 2_sl1*_dx1 = 3 * ypart(pts2 - pts1); + _sl[pts-1]*_dx[pts-1] + 2_sl[pts]*_dx[pts-1] + = 3 * ypart(pts[pts] - pts[pts-1]); +enddef; + +vardef mkfcnsplpath (suffix pts) = + pts1..controls (pts1 + (1, _sl1)/3*_dx1) and + for j = 2 upto pts - 1: + (pts[j] - (1, _sl[j])/3*_dx[j-1]) ..pts[j].. + controls (pts[j] + (1,_sl[j])/3*_dx[j]) and + endfor + (pts[pts] - (1,_sl[pts])*_dx[pts-1]/3)..pts[pts] 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} +vardef mkfcnspline (expr periodic) (suffix pts) = + init_fcnspl_eqns (pts); + if periodic: periodic_fcnspl_eqns (pts); + else: relaxed_fcnspl_eqns (pts); + fi + mkfcnsplpath (pts) enddef; -vardef arc (expr center, from, sweep) = - if (center = from) or (sweep = 0) : - from--from +vardef fcnspline (expr periodic) (text the_list) = + setpairs (_fs) (the_list); + if _fs<2: + if _fs=0: NoPoints ("fcnspline", _fs); fi + onepointpath (false, _fs1) else: - save to; pair to; - to := from rotatedabout (center, sweep); - mkarc (center, from, to, sweep) + mkfcnspline (periodic) (_fs) 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] +vardef mkarc (expr center, begpt, endpt, sweep) = + if (sweep = 0): begpt--endpt 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 + setnumeric (n) ceiling (abs(sweep)/45); + setpair (d) (begpt - center) rotated (signof (sweep) 90); + begpt{d} + for j = 1 upto n-1: + ..(begpt rotatedabout (center, j/n*sweep)){d rotated (j/n*sweep)} + endfor ..endpt{d rotated sweep} 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 +vardef arc (expr center, begpt, sweep) = + if (center = begpt) or (sweep = 0): begpt--begpt + else: + mkarc (center, begpt, begpt rotatedabout (center, sweep), sweep) + fi enddef; +def arccps = arc 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)} +vardef arcpps (expr begpt, endpt, sweep) = + if begpt = endpt: begpt--endpt + else: + setpair (cd) unitvector (endpt-begpt); + if abs(sweep) <= 45: + begpt{cd rotated (-sweep/2)}..endpt{cd rotated (sweep/2)} + elseif abs(sweep) <= 90: + save m; pair m; + m = begpt + whatever*( cd rotated (-sweep/4)); + m = 0.5[begpt, endpt] + whatever*(cd rotated 90); + begpt{cd rotated (-sweep/2)}..m{cd}..endpt{cd rotated (sweep/2)} else: - from{cd rotated (-sweep/2)}..midarc(from, to, sweep){cd} - ..to{cd rotated (sweep/2)} + setnumeric (ang) 90 - ((sweep/2) mod 180); + if abs(ang) = 90: + GBwarn "undefined arc. A line segment will be used instead."; + begpt--endpt + else: + save c; pair c; + c = begpt + whatever*(cd rotated ang); + c = if abs(ang) < 30: + (0.5)[begpt, endpt] + whatever*(cd rotated 90) + else: + endpt + whatever*(-cd rotated -ang) + fi; + mkarc (c, begpt, endpt, sweep) + fi fi - else: - save center; pair center; - center := arccenter (from, to, sweep); - mkarc (center, from, to, sweep) fi enddef; +vardef arcpp (expr small, begpt, endpt, rad) = + save full, ang; full := signof (rad) 360; + if 2*abs(rad) > abs(begpt - endpt): + ang := if not small: full - fi 2*asin (abs(begpt-endpt)/(2rad)); + else: ang := signof (rad) 180; + fi + arcpps (begpt, endpt, ang) +enddef; +def arcppr (expr begpt, endpt, rad, small) = + arcpp (small, begpt, endpt, rad) +enddef; + vardef arcplr (expr center, frtheta, totheta, rad) = - if rad = 0 : - center -- center + 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 + mkarc (center, center + rad*dir frtheta, + center + rad*dir totheta, totheta - frtheta) fi enddef; -vardef arcalt (expr center, radius, anglefrom, angleto) = - arcplr (center, anglefrom, angleto, radius) + +vardef arcalt (expr center, radius, frtheta, totheta) = + arcplr (center, frtheta, totheta, radius) enddef; vardef arcppp (expr first, second, third) = @@ -2054,32 +2334,33 @@ 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 + arcpps (one, two, 2*cornerangle (three, one, two)) + & arcpps (two, three, 2*cornerangle (one, two, three)) + & arcpps (three, one, 2*cornerangle (two, three, one)) + & cycle enddef; vardef circlepps (expr one, two, sweep) = - save ang, full; numeric ang[], full; + save ang, full; full := signof (sweep) 360; - ang1 := sweep mod (full); - ang2 := full - ang1; - arcpps (one, two, ang1) & arcpps (two, one, ang2) & cycle + ang := sweep mod full; + arcpps (one, two, ang) & arcpps (two, one, full - ang) & cycle +enddef; +vardef circlepp (expr small, one, two, rad) = + arcpp (small, one, two, rad) & arcpp (not small, two, one, rad) & cycle +enddef; +def circleppr (expr one, two, rad, small) = + circleppr (one, two, rad, small) enddef; - vardef pathcenter expr p = - save a, cntr, n; pair cntr, a[]; + save a, cntr, n; pair cntr, a[]; n := length p; a1 = pnt 0 (p); a3 = pnt [n/2] (p); - if cycle p : + if cycle p: a2 = pnt [n/4] (p); a4 = pnt [3n/4] (p); else: @@ -2096,146 +2377,909 @@ vardef circumcircle expr t = enddef; vardef incircle expr t = - save A, B, C; pair A, B, C; + 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)) + save a, b, c, D, E, F; + D := abs (B-A) = a + b; + E := abs (C-B) = b + c; + F := abs (A-C) = a + c; + circleppp ((a/D)[A,B], (b/E)[B,C], (c/F)[C,A]) 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 + save A, B, C; pair A, B, C; + A := pnt[n] (t); + B := pnt[n + 1] (t); 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)) + save a, b, c, D, E, F; + D := abs (B-A) = a - b; + E := abs (C-B) = b + c; + F := abs (C-A) = a - c; + circleppp ((a/D)[A,B], (b/E)[B,C], (c/F)[A,C]) 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 + save m; m := length t if not cycle t: + 1 fi; + pnt0(t)/m for k = 1 upto m - 1: + pnt[k](t)/m endfor 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; +vardef mkfcn (expr sm, 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) + mkpath (sm, tens, false, _p) enddef; -def tfcn (expr smooth) = mkfcn (smooth, default_tension) enddef; -def parafcn (expr smooth) = tparafcn (smooth, default_tension) enddef; +def tfcn (expr sm) = mkfcn (sm, default_tension) enddef; + +def parafcn (expr sm) = tparafcn (sm, default_tension) enddef; vardef tparafcn (expr sm, tn) (expr bmin, bmax, bst) (text pf) = - save _fp; vardef _fp (expr t) = pf enddef; + 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) +vardef xfcn (expr sm) (expr xmin, xmax, st) (text _fx) = + save _fp; vardef _fp (expr _x) = (_x, _fx(_x)) enddef; + mkfcn (sm, 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) +def function (expr sm) = tfunction (sm, default_tension) enddef; +vardef tfunction (expr sm, tens, xmin, xmax, st) (text _fx) = + save _fp; vardef _fp (expr x) = (x, _fx) enddef; + mkfcn (sm, 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) = +def btwnfcn (expr sm) = tbtwnfcn (sm, default_tension) enddef; +vardef tbtwnfcn (expr sm, tn, 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) +def belowfcn (expr sm) = tbelowfcn (sm, default_tension) enddef; +vardef tbelowfcn (expr sm, tn, xlo, xhi, st)(text _fx) = + (xlo,0)--(xhi,0)-- + (reverse tfunction (sm, tn, xlo, xhi, st)(_fx))--cycle +enddef; + +vardef rfcn (expr sm, tmin, tmax, st) (text ft) = + save _fq; vardef _fq (expr t) = (ft(t)) * (dir t) enddef; + mkfcn (sm, default_tension) (tmin, tmax, st) (_fq) +enddef; + +def plrfcn (expr sm) = tplrfcn (sm, default_tension) enddef; +vardef tplrfcn (expr sm, tens, tmin, tmax, st) (text ft) = + save _fq; vardef _fq (expr t) = (ft) * (dir t) enddef; + mkfcn (sm, tens) (tmin, tmax, st) (_fq) +enddef; + +def btwnplrfcn (expr sm) = tbtwnplrfcn (sm, default_tension) enddef; +vardef tbtwnplrfcn (expr sm, tn, tlo, thi, st)(text _ft)(text _gt)= + tplrfcn (sm, tn, tlo, thi, st) (_ft) -- + ( reverse tplrfcn (sm, tn, tlo, thi, st) (_gt) ) -- cycle +enddef; + +def plrregion (expr sm) = tplrregion (sm, default_tension) enddef; +vardef tplrregion (expr sm, tn, tlo, thi, st) (text _ft) = + (0,0)--tplrfcn (sm, tn, tlo, thi, st ) (_ft)--cycle +enddef; +numeric tolerancefactor; +tolerancefactor := .02; +vardef mklevelset (expr sm, tens, X, Y, t, a, b, c, d) = + save _inside_; + vardef _inside_ (expr U, V) = + inside_levelset (U, V) and (a < U) and (U < b) + and (c < V) and (V < d) + enddef; + if not _inside_ (X, Y): + GBwarn "Invalid seed point for levelset."; + pairmax((a,c), pairmin((X,Y), (b,d)))&cycle + else: + save ls, W, A, B, prev, curr, seed; + pair ls[], prev, curr, seed; + seed := (X,Y); + ls := 0; W := 0; + + save _first_, _next_, get_next; + vardef _first_ (expr U) = _inside_ (U, Y) enddef; + vardef _next_ (expr ang) = + _inside_ (X_curr + t * cosd ang, Y_curr + t * sind ang) + enddef; + def get_next (expr angA, angB) = + X_curr := xpart curr; Y_curr := ypart curr; + ls[incr ls] := curr + t * dir (solve _next_ (angA, angB)); + prev := curr; curr := ls[ls]; + W := W + anglefromto (prev - seed, curr - seed); + enddef; + + interim tolerance := t*tolerancefactor; + ls[incr ls] := (solve _first_ (X, b), Y); + curr := ls[ls]; + interim tolerance := radian*tolerancefactor; + get_next (180, 0); + for n = 3 upto max_points: + A := angle (curr - prev); + get_next (A + 120, A - 120); + exitif ((abs(W) > 180) or (ls > 10)) + and (abs(ls[ls] - ls1) < 1.2t); + endfor + mkpath (sm, tens, true) (ls) + fi +enddef; + +numeric max_points; +max_points := 2000; + +def levelset (expr s) = tlevelset (s, default_tension) enddef; +vardef tlevelset (expr smth, tens, seed, seg) (text cond) = + save inside_levelset, _t; + vardef inside_levelset (expr x, y) = cond enddef; + _t := if seg <= 0: emax (xpos-xneg, ypos-yneg)/max_points * 20 + else: seg fi; + mklevelset (smth, tens, xpart seed, ypart seed, _t) + (xneg, xpos, yneg, ypos) +enddef; + +vardef lclosed expr f = + f + if not cycle f: + if pnt0(f) = pnt[infinity](f): & else: -- fi cycle + fi +enddef; + +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: pnt0(f)..tension t..pnt1(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 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) +def bclosed = bclosedt (default_tension) enddef; +vardef bclosedt (expr t) expr f = + f + if not cycle f: + if pnt0(f) = pnt[infinity](f): & else: ..tension t.. fi cycle + fi +enddef; + +def uclosed = bclosed enddef; +def uclosedt = bclosedt enddef; + +def cbcontrols (suffix b, t) = + b1 := 2[t3, t2]; + b2 := 2[t2, t1]; + b3 := 2[b1, b2]; + b4 := 2[b2, b3]; 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; +vardef cbclosed expr f = + save n; n := length f; + if cycle f: f + elseif n = 0: f&cycle + else: + save p, q, t; pair p[], q[], t[]; + t1 := pnt0(f); t2 := post0(f); t3 := pre1(f); + cbcontrols (p, t); % defines p1 to p4 + t1 := pnt[n](f); t2 := pre[n](f); t3 := post[n-1](f); + cbcontrols (q, t); % 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 arccomplement expr p = + if cycle p: onepointpath (false, pnt0(p)) + else: + setnumeric (nn) length p; + setpairs (pp) (pnt0(p), pnt[.5nn](p), pnt[nn](p)); + arcpps (pp3,pp1,2*cornerangle(pp2,pp3,pp1)) + fi +enddef; + +vardef cutoffbefore (expr b) expr f = + save t, n; n := length f; + if n > 0: + for k = 1 upto n: + exitif (subpath (0,k) of f) intersects b; + endfor + if _Xtime < 0: + cuttings := pnt0 (f){0,0}; + f + else: + cuttings := subpath (0,_Xtime) of f; + subpath (_Xtime, n) of f + fi + else: f + fi +enddef; + +vardef cutoffafter (expr b) expr f = + setpath (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); + setpair (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; exitif v <> origin; + v := pre [ n ] (p) - w; exitif v <> origin; + v := pnt [ n ] (p) - w; exitif v <> origin; + endfor + sgn v +enddef; + +vardef trivial expr p = (__dir (p) = origin) enddef; + +newinternal hdwdr, hdten; +boolean hfilled; + +def headshape (expr wr, tens, fil) = + interim hdwdr := wr; + interim hdten := if tens>0: tens else: default_tension fi; + if hdten < .75: hdten := .75; fi + setboolean (hfilled) fil; + mkheadpaths; +enddef; +def mkheadpaths = + save Arrowhead, Leftharpoon, Rightharpoon; + path Arrowhead, Leftharpoon, Rightharpoon, + Arrowhead.clear, Leftharpoon.clear, Rightharpoon.clear; + Rightharpoon := (0,0){down}..tension hdten..(.5hdwdr,-1); + Rightharpoon.clear := Rightharpoon--(.5hdwdr,0)--cycle; + Leftharpoon := (reverse Rightharpoon) xscaled -1; + Leftharpoon.clear := (reverse Rightharpoon.clear) xscaled -1; + Arrowhead := Leftharpoon & Rightharpoon; + Arrowhead.clear := Leftharpoon.clear & Rightharpoon.clear & cycle; + if hfilled: + Arrowhead := Arrowhead--cycle; + Rightharpoon := Rightharpoon--(0,-1)--cycle; + Leftharpoon := Leftharpoon--(0,-1)--cycle; + fi +enddef; +headshape (1,1,false); + +def head = ahead enddef; + +vardef ahead (expr clr, front, back, hwr, tens, filled) = + settension (_tn) tens; fixtension (_tn); + if front <> back: + setpair (side) (hwr/2) * ((front-back) rotated 90); + setpath (f) (back + side)..tension _tn.. + {front-back}front{back-front}..tension _tn..(back - side); + if clearhead: + safeunfill (back - side)--(front-side)--(front+side)-- + (back+side) & f & cycle; + colorsafedraw (background) (back - side)--(front-side)-- + (front+side)--(back+side) & f & cycle; + fi + if filled: + f := f--cycle; + colorsafefill (clr) f; + fi + colorsafedraw (clr) f; + fi +enddef; + +def headpath = Gheadpath (false) (Arrowhead) enddef; +def headpathx = Gheadpath (true) (Arrowhead) enddef; + +def colorheadpath = colorGheadpath (false) (Arrowhead) enddef; +def colorheadpathx = colorGheadpath (true) (Arrowhead) enddef; + +def Gheadpath (expr trim) (suffix ah) = + colorGheadpath (trim) (ah) (headcolor) +enddef; +vardef colorGheadpath +(expr trim) (suffix ah) (expr clr, sc, rot, pos) expr f = + if (sc <> 0) and (known ah) and (path ah): + convertpath (_g) f; + setpair (_P) predirection[length _g] (_g); + if _P <> origin: + _P := _P rotated rot; + setnumeric (_ang) anglefromto (up, _P); + _P := pnt[length _g] (_g) - pos * _P; + setpair (_tip) if known ah.tip: ah.tip else: origin fi; + + if trim: + if known ah.clear: + safeunfill (ah.clear shifted - _tip) + scaled sc + rotated _ang + shifted _P; + fi + setnumeric (_ys) max(bp, penwd, last_dot_size); + safeunfill cut_path + xscaled sc yscaled _ys + rotated _ang shifted _P; + fi + if cycle ah: colorsafefill else: colorsafedraw fi (clr) + (ah shifted -_tip) + scaled sc + rotated _ang + shifted _P; + fi + fi + f +enddef; + +def tailpath (suffix sh) = colortailpath (sh) (headcolor) enddef; +vardef colortailpath (suffix sh) (expr clr, sc, rot, pos) expr f = + if (sc <> 0) and (known sh) and (path sh): + convertpath (_g) f; + setpair(_P) postdirection0 (_g); + if _P <> origin: + _P := _P rotated rot; + if cycle sh: colorsafefill else: colorsafedraw fi (clr) + (sh if known sh.tip: shifted -sh.tip fi) + scaled sc + rotated anglefromto (up, _P) + shifted (pnt0 (_g) + pos * _P); + fi + fi + f +enddef; + +def midpath (suffix sh) = colormidpath (sh) (headcolor) enddef; +vardef colormidpath (suffix sh) (expr clr, sc, rot, pos) expr f = + if (sc <> 0) and (known sh) and (path sh): + convertpath (_g) f; + setnumeric (_t) pathtime[pos] (_g); + setpair (_P) postdirection[_t] (_g); + if _P <> origin: + _P := _P rotated rot; + if cycle sh: colorsafefill else: colorsafedraw fi (clr) + sh scaled sc + rotated anglefromto (up, _P) + shifted (pnt[_t] (_g)); + fi + fi + f +enddef; + +vardef signeddeviate primary X = + (uniformdeviate 1)[-X,X] +enddef; +vardef scaledeviate (expr W, A) = + 2 ** (signeddeviate W) * dir A +enddef; +vardef polardeviate primary R = + (uniformdeviate abs(R)) * dir uniformdeviate 360 +enddef; +vardef xydeviate primary Z = + (signeddeviate (xpart Z), signeddeviate (ypart Z)) +enddef; + +vardef randompair (expr maxshift) = + if numeric maxshift: polardeviate (maxshift) + elseif pair maxshift: xydeviate (maxshift) + else: (0,0) + fi +enddef; + +vardef detrivialized expr f = + save g; path p, g[]; g := 0; + for k = 1 upto length f: + p := subpath (k-1,k) of f; + if not trivial p: g[incr g] := p; fi endfor - _tot := pieangle[piewedge]; - pair piecenter; piecenter := cent; + if g = 0: onepointpath (cycle f, pnt0(f)) + else: g1 for k = 2 upto g: &g[k] endfor if cycle f: &cycle fi + fi +enddef; + +vardef randompath (expr maxshift, weirdness) expr f = + save g, n; path g; + g := detrivialized f; + n := length g; + if n = 0: + f shifted randompair (maxshift) + else: + save X, U, V; + pair X[], U[], V[]; + if cycle g: n := n - 1; fi + for k = 0 upto n: + X[k] := pnt[k](g); + U[k] := X[k] - pre[k](g); + V[k] := post[k](g) - X[k]; + endfor + save A, B; + for k := 0 upto n: + X[k] := X[k] shifted randompair (maxshift); + A := anglefromto (U[k],V[k]); + B := signeddeviate (30weirdness); + U[k] := X[k] - (U[k] zscaled scaledeviate (weirdness,B)); + B := B - A + A * (2 ** signeddeviate weirdness); + V[k] := X[k] + (V[k] zscaled scaledeviate (weirdness,B)); + endfor + X0 for k = 1 upto n: + .. controls V[k-1] and U[k] .. X[k] + endfor + if cycle g: + .. controls V[n] and U0 .. cycle + fi + fi +enddef; + +vardef randomlines (expr maxshift) expr f = + save g, n; path g; + g := detrivialized f; + n := length g; + if n = 0: + f shifted randompair (maxshift) + else: + if cycle g: n := n - 1; fi + (pnt0(g) shifted randompair (maxshift)) + for k = 1 upto n: + -- (pnt[k](g) shifted randompair (maxshift)) + endfor + if cycle g: + -- cycle + fi + fi +enddef; +vardef parasegment (expr d, segs, f) = + if d = 0: f + else: + save u, v, t; pair u[], v[]; + for n = 0 upto segs: + t := n/segs; + u[n] := postdirection [t] (f); + v[n] := pnt[t] (f) + (u[n] zscaled (0,d)); + endfor + v0{u0} + for n = 1 upto segs: ...v[n]{u[n]} endfor + fi +enddef; + +vardef parapath (expr d) expr f = + if d = 0: + f + else: + save a, g, h, p, q, s, t, u, v, w; + path g[], h, p[], q[]; + numeric a, s, t; + pair u, v, w, w[]; + s := emax (3, emin (segment_split, ceiling (max_points/5/length f))); + p := 0; + for i = 1 upto length f: + h := subpath (i-1, i) of f; + if not trivial h: + q[incr p] := h; + p[p] := parasegment (d, s, h); + fi + endfor + if p = 0: + f + else: + a := if d>0: - fi 180; + h := p1; + for i = 1 upto p-1: + u := predirection 1 (q[i]); + v := postdirection 0 (q[i+1]); + w1 := pnt 1 (q[i]) - (u zscaled (0,d)); + w2 := pnt 0 (q[i+1]) - (v zscaled (0,d)); + w3 := pnt [infinity] (h); + w4 := pnt 0 (p[i+1]); + g0 := arcpps(w3, w1, a); + g1 := h & g0; + g2 := arcpps(w2, w4, a) & p[i+1]; + if (p[i] & g0) intersects reverse g2: + s := length g2 - _Ytime; + t := length h - length p[i] + _Xtime; + g1 := subpath (0, t) of g1; + g2 := subpath (s, length g2) of g2; + force_equal_ends (g1, g2); + h := g1 & g2; + else: + h := h .. p[i+1]; + fi + endfor + + if cycle f: + u := predirection 1 (q[p]); + v := postdirection 0 (q[1]); + w1 := pnt 1 (q[p]) - (u zscaled (0,d)); + w2 := pnt 0 (q[1]) - (v zscaled (0,d)); + w3 := pnt [infinity] (h); + w4 := pnt 0 (p[1]); + g3 := arcpps(w3, w1, a); + g0 := arcpps(w2, w4, a); + g1 := g0 & h & g3; + g2 := g0 & p[1]; + if (p[p] & g3) intersects reverse g2: + s := length g2 - _Ytime; + t := length g0 + length h - length p[p] + _Xtime; + g1 := subpath (s, t) of g1; + force_equal_ends (g1, g1); + h := g1 & cycle; + else: + h := h..cycle; + fi + fi + h + fi + fi +enddef; + +vardef turnangle@# (expr f) = + anglefromto(predirection@# (f), postdirection@#(f)) +enddef; + +def setdatadashes (text lst) = + save __type; __type := 0; + forsuffixes _itm = lst: + if knownnumericarray _itm : + copyarray (_itm) (__type[__type]); + next __type; + else: GBwarn "Improper dash pattern in setdatadashes."; + fi + endfor + if __type > 1: + save dashtype; dashtype := __type; + for _j = 0 upto dashtype - 1: + copyarray (__type[_j]) (dashtype[_j]); + endfor + else: + SetdataWarn "dashes"; + fi +enddef; +def getdashpat expr n = dashtype[n mod dashtype] enddef; + +def SetdataWarn expr s = + GBwarn "command setdata"& s &"() failed. Previous values retained."; +enddef; + +numeric Solid, Simpledash, Simpledot, Dotdash, Dotdashdot, Dotdashdash; +dashpat (Solid) (0); +dashpat (Simple_dash) (3bp, 4bp); +dashpat (Simple_dot) (0, 4bp); +dashpat (Dot_dash) (0, 4bp, 3bp, 4bp); +dashpat (Dot_dash_dot) (0, 4bp, 3bp, 4bp, 0, 4bp); +dashpat (Dot_dash_dash) (0, 4bp, 3bp, 4bp, 3bp, 4bp); + +numeric dashtype, dashtype[], dashtype[][]; +def defaultdashes = + setdatadashes (Solid, Simple_dash, Simple_dot, + Dot_dash, Dot_dash_dot, Dot_dash_dash); +enddef; +defaultdashes; + +def setdatasymbols (text lst) = + save __type; path __type[]; + __type := 0; + for _itm = lst: + if (known _itm) and (path _itm): + __type[__type] := _itm; + next __type; + else: + GBwarn "Improper path in setdatasymbols()."; + fi + endfor + if __type > 1: + save pointtype; pointtype := __type; + path pointtype[]; + for _j = 0 upto pointtype - 1: + pointtype[_j] := __type[_j]; + endfor + else: + SetdataWarn "symbols"; + fi +enddef; +def getsymbol expr n := pointtype[n mod pointtype] enddef; + +def DeclareGBSymbols (text S) = + forsuffixes _itm = S: + path _itm; + path _itm.clear; + pair _itm.tip; + endfor +enddef; +DeclareGBSymbols( + Triangle, Square, Circle, Diamond, Star, Plus, Cross, + Asterisk, Crossbar, Leftbar, Rightbar, Righthook, + Lefthook, SolidTriangle, SolidSquare, SolidCircle, + SolidDiamond, SolidStar +); + +vardef undo_cycle expr f = subpath (0, length f) of f enddef; + +SolidTriangle := (up--(dir 210)--(dir -30)--cycle) scaled .78; +Triangle := undo_cycle SolidTriangle; + +Triangle.clear := SolidTriangle.clear := + ((dir -30)--(cosd 30,1)--(cosd 210,1)--(dir 210)--up--cycle) + scaled .78; + +SolidSquare := (up--(-1,1)--(-1,-1)--(1,-1)--(1,1)--cycle) scaled .443; +Square := undo_cycle SolidSquare; + +SolidCircle := fullcircle rotated 90; +Circle := undo_cycle SolidCircle; +Circle.clear := SolidCircle.clear := + halfcircle--(-.5,.5)--(.5,.5)--cycle; + +SolidDiamond := (up--left--down--right--cycle) + scaled .522 yscaled 1.44; +Diamond := undo_cycle SolidDiamond; +Diamond.clear := SolidDiamond.clear := + (right--(1,1)--(-1,1)--left--up--cycle) scaled .522 yscaled 1.44; + +Plus := ((0,0)--up--down--(0,0)--left--right) scaled .65; +Plus.clear := (right--(1,1)--(-1,1)--(left)--cycle) scaled .65; + +Cross := ((0,0)--(dir 45)--(dir -135)--(0,0)--(dir -45)--(dir 135)) + scaled .65; +Cross.clear := ((0,0)--(dir -45)--dir(45)--(dir 135)--(dir -135)--cycle) + scaled .65; + +Asterisk := ((0,0)--up--down--(0,0)--(dir 30)--(dir -150) + --(0,0)--(dir -30)--(dir 150)) scaled .6; +Asterisk.clear := ((0,0)--(dir -30)--(cosd 30,1)--(cosd 150,1) + --(dir -150)--cycle) scaled .6; + +Crossbar := ((0,0)--left--right) scaled .65; +Crossbar.clear := rect (right,(-1,.5)) scaled .65; + +Leftbar := ((0,0)--left); +Rightbar := ((0,0)--right); +Leftbar.clear := rect((0,0),(-1,.5)); +Rightbar.clear := rect((0,0),(1,.5)); + +Righthook := arcpps((0,0),(1,0),180); +Lefthook := Righthook xscaled -1; +Righthook.clear := Righthook--cycle; +Lefthook.clear := Lefthook--cycle; + +vardef mkstar (expr n, m) (suffix A) = + save ang; ang := 360/n; + A1 := up; A3 := up rotated ang; + A2 = (whatever)[A1, A1 rotated ( ang*m)]; + A2 = (whatever)[A3, A3 rotated (-ang*m)]; + for i = 4 upto 2n: + A[i] := A[i-2] rotated ang; + endfor + A := 2n; + mkpoly (true, A) +enddef; + +save _A; pair _A[]; +SolidStar := mkstar (5, 2, _A) scaled .84; +Star := undo_cycle SolidStar; +Star.clear := polyline (true) + (_A9, _A10, _A1, _A2, _A3, (xpart _A3, 1), (xpart _A9, 1)) scaled .84; +SolidStar.clear := Star.clear; + +forsuffixes S = + Triangle, Square, Circle, Diamond, Star, Plus, Cross, + Asterisk, Crossbar, Leftbar, Rightbar, Righthook, + Lefthook, SolidTriangle, SolidSquare, SolidCircle, + SolidDiamond, SolidStar : + S.tip := point 0 of S; +endfor +vardef gcd (expr n, m) = + save a, b, r; + a := emax (abs(m), abs(n)); + b := emin (abs(m), abs(n)); + if b > 0: + forever: + r := a mod b; + exitif r < 1; + a := b; b := r; + endfor + b + else: + a + fi +enddef; + +vardef lcm (expr n, m) = + n*m/gcd(n, m) +enddef; + +path cut_path; cut_path := (.5,0)--(.5,.71)--(-.5,.71)--(-.5,0)--cycle; + +numeric pointtype; path pointtype[]; +def defaultsymbols = + setdatasymbols( Circle, Cross, SolidDiamond, Square, Plus, + Triangle, SolidCircle, Star, SolidTriangle); +enddef; +defaultsymbols; + +def setdatacolors (text lst) = + save __type; color __type[]; + __type := 0; + for _itm = lst: + if (known _itm) and (color _itm): + __type[__type] := _itm; + next __type; + else: GBwarn "Improper color in setdatacolors()."; + fi + endfor + if __type > 1: + save colortype; colortype := __type; + color colortype[]; + for _j = 0 upto colortype - 1: + colortype[_j] := __type[_j]; + endfor + else: + SetdataWarn "colors"; + fi +enddef; +def getcolor expr n = colortype[n mod colortype] enddef; + +color dBlue, dOrange, dGreen, dMagenta, dCyan, dYellow; +dBlue := 0.80blue + .2white; +dOrange := 0.66yellow + .34red; +dGreen := 0.80green; +dMagenta := 0.85magenta; +dCyan := 0.85cyan; +dYellow := 0.85yellow; + +numeric colortype; color colortype[]; +def defaultcolors = + setdatacolors(black, red, dBlue, dOrange, dGreen, + dMagenta, dCyan, dYellow); +enddef; +defaultcolors; + +def computepie (suffix dat) (expr sign, ang, cent, rad) (text data) = +begingroup + save _tot, _max, _toobig; + _max := 0; dat := 0; + for _val = data: + dat[incr dat] := _val; + _max := emax (_max, _val); + endfor + if dat=0: GBwarn "piechart attempted with empty list."; + _toobig := 1; + else: + _toobig := infinity/dat; + fi + if _max > _toobig: + for _idx = 1 upto dat: + dat[_idx] := dat[_idx]/_toobig; + endfor + fi + for _idx = 2 upto dat: + dat[_idx] := dat[_idx - 1] + dat[_idx]; + endfor + _tot := dat[dat]; + for _idx = dat downto 2: + dat[_idx] := ang + sign*dat[_idx-1]/_tot*360; + endfor + dat1 := ang; dat[dat + 1] := ang + 360sign; +endgroup +enddef; + +def piechart (expr sign, ang, cent, rad) (text data) = + save _dat; + computepie (_dat) (sign, ang, cent, rad) (data); + mkpiewedges (_dat, cent, rad); +enddef; + +def mkpiewedges (suffix dat) (expr cent, rad) = + numeric piewedge, piedirection, pieangle, pieangle[]; + pair piecenter, piedirection[]; 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] ]); + piecenter := cent; + piedirection := pieangle := piewedge := dat; + for _idx = 1 upto dat: + pieangle[_idx] := dat[_idx]; + piewedge[_idx] := sector (piecenter, rad, dat[_idx], dat[_idx+1]); + piedirection[_idx] := dir(0.5[ dat[_idx], dat[_idx+1] ]); endfor - piedirection := pieangle := piewedge; enddef; -def barchart (expr start, sep, r, vert)(text data) = +def namedpiechart (suffix nm) (expr sign, ang, cent, rad) (text data) = + save _dat; + computepie (_dat) (sign, ang, cent, rad) (data); + setnumeric (nm) _dat; + pair nm.center, nm.direction[]; + path nm.wedge[]; + nm.center := cent; + for _idx = 1 upto _dat: + nm.wedge[_idx] := sector (cent, rad, _dat[_idx], _dat[_idx+1]); + nm.direction[_idx] := dir(0.5[ _dat[_idx], _dat[_idx+1] ]); + endfor +enddef; + +def barchart (expr firstbar, 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; + 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; + for _nn = 1 upto chartbar: + barstart[_nn] := firstbar + sep*(_nn-1); + barlength[_nn] := barend[_nn]; + chartbar[_nn] := rect ((barbegin[_nn], 0), ( barend[_nn], barwd)) + shifted (0, barstart[_nn]) if vert: xyswap fi; endfor enddef; +def namedbarchart (suffix nm) (expr first, sep, r, vert) (text data) = + save nm; +begingroup + save _bb, _ee, _ww; + path nm.bar[]; + nm := 0; _ww := r*sep; + for _itm = data: + _ee := if pair _itm: ypart _itm else: _itm fi; + _bb := if pair _itm: xpart _itm else: 0 fi; + nm.bar[incr nm] := rect ((_bb, 0), ( _ee, _ww) ) + shifted (0, first + sep*(nm-1)) if vert: xyswap fi; + endfor +endgroup +enddef; + picture totalpicture; boolean totalnull, currentnull; def clearit = @@ -2246,7 +3290,7 @@ enddef; def keepit = addto totalpicture also currentpicture; currentpicture := nullpicture; - totalnull := currentnull; + totalnull := totalnull or currentnull; currentnull := true; enddef; @@ -2256,13 +3300,13 @@ def addto_currentpicture = enddef; def mergeit (text do) = - if totalnull : + if totalnull: do currentpicture - elseif currentnull : + elseif currentnull: do totalpicture else: begingroup - save _v_; picture _v_; + save _v_; picture _v_; _v_ := currentpicture; addto _v_ also totalpicture; do _v_ @@ -2270,13 +3314,12 @@ def mergeit (text do) = fi enddef; -def shipit_ = - mergeit (shipout) -enddef; -def shipit = shipit_ enddef; +boolean noship; noship := false; +def shipit = if noship: else: mergeit (shipout) fi enddef; -numeric gcode; gcode := 0; +numeric gcode; gcode := 0; +input dvipsnam.mp; % end grafbase.mp endinput. %% |