summaryrefslogtreecommitdiff
path: root/metapost/context/base/mpiv
diff options
context:
space:
mode:
Diffstat (limited to 'metapost/context/base/mpiv')
-rw-r--r--metapost/context/base/mpiv/metafun.mpiv58
-rw-r--r--metapost/context/base/mpiv/mp-abck.mpiv269
-rw-r--r--metapost/context/base/mpiv/mp-apos.mpiv102
-rw-r--r--metapost/context/base/mpiv/mp-asnc.mpiv177
-rw-r--r--metapost/context/base/mpiv/mp-back.mpiv205
-rw-r--r--metapost/context/base/mpiv/mp-bare.mpiv93
-rw-r--r--metapost/context/base/mpiv/mp-base.mpiv956
-rw-r--r--metapost/context/base/mpiv/mp-butt.mpiv77
-rw-r--r--metapost/context/base/mpiv/mp-char.mpiv1116
-rw-r--r--metapost/context/base/mpiv/mp-chem.mpiv1731
-rw-r--r--metapost/context/base/mpiv/mp-core.mpiv1561
-rw-r--r--metapost/context/base/mpiv/mp-cows.mpiv156
-rw-r--r--metapost/context/base/mpiv/mp-crop.mpiv194
-rw-r--r--metapost/context/base/mpiv/mp-figs.mpiv47
-rw-r--r--metapost/context/base/mpiv/mp-fobg.mpiv87
-rw-r--r--metapost/context/base/mpiv/mp-form.mpiv30
-rw-r--r--metapost/context/base/mpiv/mp-func.mpiv87
-rw-r--r--metapost/context/base/mpiv/mp-grap.mpiv1706
-rw-r--r--metapost/context/base/mpiv/mp-grid.mpiv142
-rw-r--r--metapost/context/base/mpiv/mp-grph.mpiv348
-rw-r--r--metapost/context/base/mpiv/mp-idea.mpiv30
-rw-r--r--metapost/context/base/mpiv/mp-luas.mpiv99
-rw-r--r--metapost/context/base/mpiv/mp-mlib.mpiv1450
-rw-r--r--metapost/context/base/mpiv/mp-page.mpiv664
-rw-r--r--metapost/context/base/mpiv/mp-shap.mpiv218
-rw-r--r--metapost/context/base/mpiv/mp-step.mpiv376
-rw-r--r--metapost/context/base/mpiv/mp-symb.mpiv351
-rw-r--r--metapost/context/base/mpiv/mp-text.mpiv163
-rw-r--r--metapost/context/base/mpiv/mp-tool.mpiv2651
29 files changed, 15144 insertions, 0 deletions
diff --git a/metapost/context/base/mpiv/metafun.mpiv b/metapost/context/base/mpiv/metafun.mpiv
new file mode 100644
index 000000000..b1d4f32e7
--- /dev/null
+++ b/metapost/context/base/mpiv/metafun.mpiv
@@ -0,0 +1,58 @@
+%D \module
+%D [ file=metafun.mp,
+%D version=2000.07.15,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=format generation file,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D First we input John Hobby's metapost plain file. However, because we want to
+%D prevent dependency problems and in the end even may use a patched version,
+%D we prefer to use a copy.
+
+prologues := 0 ;
+mpprocset := 1 ;
+
+input "mp-base.mpiv" ;
+input "mp-tool.mpiv" ;
+input "mp-mlib.mpiv" ;
+% "mp-core.mpiv" ; % todo: namespace and cleanup
+input "mp-luas.mpiv" ; % experimental
+input "mp-page.mpiv" ; % todo: namespace and cleanup
+input "mp-butt.mpiv" ; % todo: namespace and cleanup
+input "mp-shap.mpiv" ; % will be improved
+input "mp-grph.mpiv" ; % todo: namespace and cleanup
+input "mp-grid.mpiv" ; % todo: namespace and cleanup
+input "mp-form.mpiv" ; % under (re)construction
+input "mp-figs.mpiv" ; % obsolete, needs checking
+input "mp-func.mpiv" ; % under construction
+% "mp-text.mpiv" ; % loaded on demand
+% "mp-char.mpiv" ; % loaded on demand
+% "mp-step.mpiv" ; % loaded on demand
+% "mp-chem.mpiv" ; % loaded on demand
+
+string metafunversion ; metafunversion =
+ "metafun iv" & " " &
+ decimal year & "-" &
+ decimal month & "-" &
+ decimal day & " " &
+ if ((time div 60) < 10) : "0" & fi
+ decimal (time div 60) & ":" &
+ if ((time-(time div 60)*60) < 10) : "0" & fi
+ decimal (time-(time div 60)*60) ;
+
+let normalend = end ;
+
+if known mplib :
+ def end = ; message "" ; message metafunversion ; message "" ; endinput ; enddef ;
+ def bye = ; message "" ; message metafunversion ; message "" ; endinput ; enddef ;
+else :
+ def end = ; message "" ; message metafunversion ; message "" ; normalend ; enddef ;
+fi ;
+
+% dump ; % obsolete in mplib
diff --git a/metapost/context/base/mpiv/mp-abck.mpiv b/metapost/context/base/mpiv/mp-abck.mpiv
new file mode 100644
index 000000000..abd7d8848
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-abck.mpiv
@@ -0,0 +1,269 @@
+%D \module
+%D [ file=mp-abck.mpiv,
+%D version=2012.02.19, % was mp-core: 1999.08.01, anchoring
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=anchored background macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+if known context_abck : endinput ; fi ;
+
+boolean context_abck ; context_abck := true ;
+
+path multiregs[], % region used for multipar (tracing only)
+ multipars[], % effective area (shape)
+ multibox ; % main boundingbox (of main region)
+
+string multikind[] ; % region state: single | first | middle | last (new method)
+
+numeric multilocs[], % 1=begin 2=between 3=end (old method)
+ nofmultipars ; % number of calculated areas
+
+numeric par_strut_height,
+ par_strut_depth,
+ par_line_height ;
+
+nofmultipars := 0 ;
+par_strut_height := 0 ;
+par_strut_depth := 0 ;
+par_line_height := 0 ;
+
+def boxgridoptions = withcolor .8red enddef ;
+def boxlineoptions = withcolor .8blue enddef ;
+def boxfilloptions = withcolor .8white enddef ;
+
+numeric boxgridtype ; boxgridtype := 0 ;
+numeric boxlinetype ; boxlinetype := 1 ;
+numeric boxfilltype ; boxfilltype := 1 ;
+numeric boxdashtype ; boxdashtype := 0 ;
+pair boxgriddirection ; boxgriddirection := up ;
+numeric boxgridwidth ; boxgridwidth := 1pt ;
+numeric boxlinewidth ; boxlinewidth := 1pt ;
+numeric boxlineradius ; boxlineradius := 0 ;
+numeric boxlineoffset ; boxlineoffset := 0 ;
+numeric boxfilloffset ; boxfilloffset := 0 ;
+numeric boxgriddistance ; boxgriddistance := .5cm ;
+numeric boxgridshift ; boxgridshift := 0 ;
+
+def abck_show_path(expr p, r, c) =
+ draw p withpen pencircle scaled .5pt withcolor c ;
+ if length(p) > 2 :
+ begingroup ; save _c_ ; path _c_ ; _c_ := fullcircle scaled r ;
+ for i=0 upto length(p) if cycle p : -1 fi :
+ fill _c_ shifted point i of p withcolor white ;
+ draw _c_ shifted point i of p withpen pencircle scaled .5pt withcolor c ;
+ endfor ;
+ fi ;
+enddef ;
+
+vardef abck_draw_path(expr p) =
+ if (length p > 2) and (bbwidth(p) > 1) and (bbheight(p) > 1) :
+ save pp ; path pp ;
+ pp := p if (boxlineradius>0) and (boxlinetype=2) : cornered boxlineradius fi ;
+ if boxfilltype > 0 :
+ if boxfilloffset > 0 :
+ interim linejoin := mitered ;
+ filldraw pp boxfilloptions withpen pencircle scaled (2*boxfilloffset) ;
+ else :
+ fill pp boxfilloptions ;
+ fi ;
+ fi ;
+ if boxlinetype > 0 :
+ draw pp boxlineoptions withpen pencircle scaled boxlinewidth ;
+ fi ;
+ fi ;
+enddef ;
+
+def abck_grid_line(expr start, width) =
+ % 1 = normal, 2 = with background (i.e. no shine-through)
+ if boxdashtype = 2 :
+ draw start -- start shifted (width,0)
+ withpen pencircle scaled boxgridwidth
+ boxfilloptions ;
+ fi ;
+ draw start -- start shifted (width,0)
+ if boxdashtype > 0 :
+ dashed evenly
+ fi
+ withpen pencircle scaled boxgridwidth
+ boxgridoptions ;
+enddef ;
+
+vardef abck_baseline_grid(expr pxy, pdir, at_baseline) =
+ save width ; width := bbwidth(pxy) ;
+ save height ; height := bbheight(pxy) ;
+ if (par_line_height > 0) and (height > 1) and (width > 1) and (boxgridwidth > 0) :
+ save i, grid, bb ; picture grid ; pair start ; path bb ;
+ grid := image ( % fails with inlinespace
+ if pdir = up :
+ for i = if at_baseline : par_strut_depth else : 0 fi step par_line_height until max(height,par_line_height) :
+ abck_grid_line(llcorner pxy shifted (0,+i),width) ;
+ endfor ;
+ else :
+ for i = if at_baseline : par_strut_height else : 0 fi step par_line_height until height :
+ abck_grid_line(ulcorner pxy shifted (0,-i),width) ;
+ endfor ;
+ fi ;
+ ) ;
+ clip grid to pxy ;
+ bb := boundingbox grid ;
+ grid := grid shifted (0,boxgridshift) ;
+ setbounds grid to bb ;
+ grid
+ else :
+ nullpicture
+ fi
+enddef ;
+
+vardef abck_graphic_grid(expr pxy, dx, dy, x, y) =
+ if (bbheight(pxy) > dy) and (bbwidth(pxy) > dx) and (boxgridwidth > 0) :
+ save grid ; picture grid ;
+ grid := image (
+ for i = xpart llcorner pxy step dx until xpart lrcorner pxy :
+ draw (i,ypart llcorner pxy) -- (i,ypart ulcorner pxy) withpen pencircle scaled boxgridwidth ;
+ endfor ;
+ for i = ypart llcorner pxy step dy until ypart ulcorner pxy :
+ draw (xpart llcorner pxy,i) -- (xpart lrcorner pxy,i) withpen pencircle scaled boxgridwidth ;
+ endfor
+ ) shifted (x,y) ;
+ clip grid to pxy ;
+ grid
+ else :
+ nullpicture
+ fi
+enddef ;
+
+def draw_multi_pars =
+ for i=1 upto nofmultipars :
+ abck_draw_path(multipars[i]) ;
+ if boxgridtype = 1 :
+ draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) ;
+ elseif boxgridtype = 2 :
+ draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,false) ;
+ elseif boxgridtype = 3 :
+ draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) ;
+ draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight) ;
+ elseif boxgridtype = 4 :
+ draw abck_baseline_grid(multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight/2) ;
+ elseif boxgridtype = 11 :
+ draw abck_graphic_grid(multipars[i],boxgriddistance,boxgriddistance,boxgriddistance/2,boxgriddistance/2) ;
+ elseif boxgridtype = 12 :
+ draw abck_graphic_grid(multipars[i],boxgriddistance,boxgriddistance,0,0) ;
+ fi ;
+ endfor ;
+enddef ;
+
+def show_multi_pars =
+ for i=1 upto nofmultipars :
+ abck_show_path(multipars[i], 6pt, .5blue) ;
+ endfor ;
+enddef ;
+
+def show_multi_kind =
+ for i=1 upto nofmultipars :
+ fill multipars[i]
+ withcolor
+ if multikind[i] = "single" : yellow
+ elseif multikind[i] = "first" : red
+ elseif multikind[i] = "middle" : green
+ elseif multikind[i] = "last" : blue
+ fi
+ withtransparency (1,.5)
+ ;
+ endfor ;
+enddef ;
+
+def multi_side_draw_options = enddef ;
+
+def draw_multi_side =
+ begingroup ; save p ; picture p ;
+ for i=1 upto nofmultipars :
+ p := image ( fill leftboundary multipars[i]
+ shifted (-boxlineoffset,0)
+ rightenlarged boxlinewidth boxlineoptions ;
+ ) ;
+ setbounds p to multipars[i] ;
+ draw p ;
+ endfor ;
+ endgroup ;
+enddef ;
+
+def draw_multi_side_path text t =
+ begingroup ; save p ; picture p ;
+ for i=1 upto nofmultipars :
+ p := image ( draw leftboundary multipars[i]
+ shifted (-boxlineoffset,0)
+ withpen pensquare scaled boxlinewidth boxlineoptions t ;
+ ) ;
+ setbounds p to multipars[i] ;
+ draw p ;
+ endfor ;
+ endgroup ;
+enddef ;
+
+% some extras
+
+path posboxes[],
+ posregions[] ;
+
+numeric multipages[],
+ nofposboxes ;
+
+nofposboxes := 0 ;
+
+% For the moment we keep these as they can be in use but they will
+% disappear.
+
+pair lxy[], rxy[], cxy[], llxy[], lrxy[], ulxy[], urxy[] ;
+path pxy[] ;
+numeric hxy[], wxy[], dxy[], nxy[] ;
+
+def box_found (expr n,x,y,w,h,d) =
+ not ((x=0) and (y=0) and (w=0) and (h=0) and (d=0))
+enddef ;
+
+def initialize_box_pos (expr pos,n,x,y,w,h,d) =
+ pair lxy, rxy, cxy, llxy, lrxy, ulxy, urxy ;
+ path pxy ; numeric hxy, wxy, dxy, nxy;
+ lxy := (x,y) ;
+ llxy := (x,y-d) ;
+ lrxy := (x+w,y-d) ;
+ urxy := (x+w,y+h) ;
+ ulxy := (x,y+h) ;
+ wxy := w ;
+ hxy := h ;
+ dxy := d ;
+ rxy := lxy shifted (wxy,0) ;
+ pxy := llxy--lrxy--urxy--ulxy--cycle ;
+ cxy := center pxy ;
+ nxy := n ;
+ freeze_box(pos) ;
+enddef ;
+
+def freeze_box (expr pos) =
+ lxy[pos] := lxy ;
+ llxy[pos] := llxy ;
+ lrxy[pos] := lrxy ;
+ urxy[pos] := urxy ;
+ ulxy[pos] := ulxy ;
+ wxy[pos] := wxy ;
+ hxy[pos] := hxy ;
+ dxy[pos] := dxy ;
+ rxy[pos] := rxy ;
+ pxy[pos] := pxy ;
+ cxy[pos] := cxy ;
+ nxy[pos] := nxy ;
+enddef ;
+
+def initialize_box (expr n,x,y,w,h,d) =
+ numeric bpos ; bpos := 0 ; initialize_box_pos(bpos,n,x,y,w,h,d) ;
+enddef ;
+
+def anchor_box (expr n,x,y,w,h,d) =
+ currentpicture := currentpicture shifted (-x,-y) ;
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-apos.mpiv b/metapost/context/base/mpiv/mp-apos.mpiv
new file mode 100644
index 000000000..7b7737754
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-apos.mpiv
@@ -0,0 +1,102 @@
+%D \module
+%D [ file=mp-apos.mpiv,
+%D version=2012.02.19, % was mp-core: 1999.08.01, anchoring
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=anchored background macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+if known context_apos : endinput ; fi ;
+
+boolean context_apos ; context_apos := true ;
+
+path posboxes[],
+ posregions[] ;
+
+numeric multipages[],
+ nofposboxes ;
+
+nofposboxes := 0 ;
+
+def boxlineoptions = withcolor .8blue enddef ;
+def boxfilloptions = withcolor .8white enddef ;
+
+def connect_positions =
+ if nofposboxes = 2 :
+ pickup pencircle scaled boxlinewidth ;
+ path pa ; pa := posboxes[1] enlarged boxlineoffset ;
+ path pb ; pb := posboxes[2] enlarged boxlineoffset ;
+ if pospages[1] = pospages[2] :
+ draw posboxes[1] boxlineoptions ;
+ path pc ; pc := center pa {up} .. {down} center pb ;
+ pair cc ; cc := (pc intersection_point pa) ;
+ if intersection_found :
+ pc := pc cutbefore cc ;
+ cc := (pc intersection_point pb) ;
+ if intersection_found :
+ pc := pc cutafter cc ;
+ drawarrow pc boxlineoptions ;
+ drawarrow reverse pc boxlineoptions ;
+ fi ;
+ fi ;
+ elseif pospages[1] == RealPageNumber :
+ draw posboxes[1] boxlineoptions ;
+ path pc ; pc := center pa {up} ... {right} urcorner (posregions[1] enlarged (20pt,20pt)) ;
+ pair cc ; cc := (pc intersection_point pa) ;
+ if intersection_found :
+ pc := pc cutbefore cc ;
+ drawarrow pc boxlineoptions ;
+ fi ;
+ elseif pospages[2] == RealPageNumber :
+ draw posboxes[2] boxlineoptions ;
+ path pc ; pc := ulcorner (posregions[2] enlarged (20pt,20pt)) {right} ... {down} center pb ;
+ pair cc ; cc := (pc intersection_point pb) ;
+ if intersection_found :
+ pc := pc cutafter cc ;
+ drawarrow pc boxlineoptions ;
+ fi ;
+ fi ;
+ fi ;
+enddef ;
+
+% anch-bar:
+
+def anch_sidebars_draw (expr p_b_self, p_e_self, y_b_self, y_e_self, h_b_self, d_e_self,
+ x, y, w, h, alternative, distance, linewidth, linecolor, topoffset, bottomoffset) =
+ % beware, we anchor at (x,y)
+ begingroup ;
+ if alternative = 1 :
+ interim linecap := rounded ;
+ else :
+ interim linecap := butt ;
+ fi ;
+ save a, b ; pair a, b ;
+ if p_b_self = p_e_self :
+ a := (-distance,y_b_self+h_b_self-y) ;
+ b := (-distance,y_e_self-d_e_self-y) ;
+ elseif RealPageNumber = p_b_self :
+ a := (-distance,y_b_self+h_b_self-y) ;
+ b := (-distance,0) ;
+ elseif RealPageNumber = p_e_self :
+ a := (-distance,h) ;
+ b := (-distance,y_e_self-d_e_self-y) ;
+ else :
+ a := (-distance,h) ;
+ b := (-distance,0) ;
+ fi ;
+ a := (xpart a, min(ypart a + topoffset, h)) ;
+ b := (xpart b, max(ypart b - bottomoffset,0)) ;
+ draw
+ a -- b
+ if alternative = 1 :
+ dashed (withdots scaled (linewidth/2))
+ fi
+ withpen pencircle scaled linewidth
+ withcolor linecolor ;
+ endgroup ;
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-asnc.mpiv b/metapost/context/base/mpiv/mp-asnc.mpiv
new file mode 100644
index 000000000..2626e4d58
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-asnc.mpiv
@@ -0,0 +1,177 @@
+%D \module
+%D [ file=mp-asnc.mpiv,
+%D version=2012.02.19, % was mp-core: 1999.08.01, anchoring
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=anchored background macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+if known context_asnc : endinput ; fi ;
+
+boolean context_av ; context_asnc := true ;
+
+% will be replaced
+
+numeric sync_n[], sync_p[][], sync_w[][], sync_h[][], sync_d[][], sync_t[][] ;
+pair sync_xy[][] ; color sync_c[][] ;
+
+def ResetSyncTasks =
+ path SyncPaths[] ; numeric SyncTasks[], NOfSyncPaths, CurrentSyncClass ;
+ NOfSyncPaths := CurrentSyncClass := 0 ;
+ if unknown SyncLeftOffset : numeric SyncLeftOffset ; SyncLeftOffset := 0 ; fi ;
+ if unknown SyncWidth : numeric SyncWidth ; SyncWidth := 0 ; fi ;
+ if unknown SyncThreshold : numeric SyncThreshold ; SyncThreshold := LineHeight ; fi ;
+ if unknown SyncColor : color SyncColor ; SyncColor := .5white ; fi ;
+ if (SyncLeftOffset = 0) and (SyncWidth = 0) :
+ SyncWidth := if known TextWidth : TextWidth else : -1cm fi ;
+ fi ;
+enddef ;
+
+ResetSyncTasks ;
+
+vardef SyncBox(expr n, i, leftoffset, width, topoffset, bottomoffset) =
+ save o ; pair o ; o := (xpart llcorner PlainTextArea,ypart sync_xy[n][i]) ;
+ o shifted (leftoffset,sync_h[n][i]+topoffset) --
+ o shifted (width+leftoffset,sync_h[n][i]+topoffset) --
+ o shifted (width+leftoffset,bottomoffset) --
+ o shifted (leftoffset,bottomoffset) -- cycle
+enddef ;
+
+def SetSyncColor(expr n, i, c) =
+ sync_c[n][i] := c ;
+enddef ;
+
+def SetSyncThreshold(expr n, i, th) =
+ sync_th[n][i] := th ;
+enddef ;
+
+vardef TheSyncColor(expr n, i) =
+ if known sync_c[n][i] : sync_c[n][i] else : SyncColor fi
+enddef ;
+
+vardef TheSyncThreshold(expr n, i) =
+ if known sync_th[n][i] : sync_th[n][i] else : SyncThreshold fi
+enddef ;
+
+vardef PrepareSyncTasks(expr n, collapse, extendtop, prestartnext) =
+ ResetSyncTasks ;
+ if known sync_n[n] :
+ CurrentSyncClass := n ;
+ save ok, l, d ; boolean ok ; ok := false ; NOfSyncPaths := l := 0 ;
+ for i=1 upto sync_n[n] :
+ if RealPageNumber > sync_p[n][i] :
+ l := i ;
+ elseif RealPageNumber = sync_p[n][i] :
+ NOfSyncPaths := NOfSyncPaths + 1 ;
+ if not ok :
+ if i>1 :
+ if sync_t[n][i-1] = sync_t[n][i] :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ else :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i-1, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i-1 ;
+ NOfSyncPaths := NOfSyncPaths + 1 ;
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ fi ;
+ else :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ fi ;
+ else :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ fi ;
+ ok := true ;
+ fi ;
+ endfor ;
+ if (NOfSyncPaths = 0) and (l > 0) :
+ NOfSyncPaths := 1 ;
+ SyncPaths[NOfSyncPaths] := SyncBox(n, l, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := l ;
+ fi ;
+ if NOfSyncPaths > 0 :
+ for i = 1 upto NOfSyncPaths-1 :
+ SyncPaths[i] := topboundary SyncPaths[i] -- reverse topboundary SyncPaths[i+1] -- cycle ;
+ endfor ;
+ if unknown SyncThresholdMethod :
+ numeric SyncThresholdMethod ; SyncThresholdMethod := 2 ;
+ fi ;
+ if extendtop :
+ if SyncThresholdMethod = 1 :
+ if NOfSyncPaths>1 :
+ d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[2]]) ;
+ if (SyncTasks[2]>1) and (d > 0pt) and (d <= TheSyncThreshold(n,sync_t[n][SyncTasks[2]])) and (sync_p[n][SyncTasks[2]] = RealPageNumber) :
+ SyncPaths[2] := SyncPaths[2] topenlarged PaperHeight ;
+ fi ;
+ fi ;
+ else :
+ for i = 1 upto NOfSyncPaths :
+ d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[i]]) ;
+ if (d > 0) and (d <= TheSyncThreshold(n,sync_t[n][SyncTasks[i]])) and (sync_p[n][SyncTasks[i]] = RealPageNumber) :
+ SyncPaths[i] := SyncPaths[i] topenlarged PaperHeight ;
+ fi ;
+ endfor ;
+ fi ;
+ fi ;
+ if prestartnext :
+ if NOfSyncPaths>1 :
+ if SyncTasks[NOfSyncPaths] < sync_n[n] : % there is a next one
+ d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[NOfSyncPaths]+1]) ;
+ if (d > 0) and (d <= TheSyncThreshold(n, sync_t[n][SyncTasks[i]])) and (sync_p[n][SyncTasks[NOfSyncPaths]+1] = RealPageNumber+1) :
+ SyncPaths[NOfSyncPaths+1] :=
+ (xpart ulcorner SyncPaths[NOfSyncPaths],ypart llcorner PlainTextArea) --
+ (xpart urcorner SyncPaths[NOfSyncPaths],ypart llcorner PlainTextArea) --
+ lrcorner SyncPaths[NOfSyncPaths] --
+ llcorner SyncPaths[NOfSyncPaths] -- cycle ;
+ SyncTasks[NOfSyncPaths+1] := SyncTasks[NOfSyncPaths]+1 ;
+ NOfSyncPaths := NOfSyncPaths + 1 ;
+ fi ;
+ fi ;
+ fi ;
+ else :
+ if NOfSyncPaths>1 :
+ d := ypart (sync_xy[n][SyncTasks[NOfSyncPaths]] - llcorner PlainTextArea) ;
+ if (d < TheSyncThreshold(n, SyncTasks[NOfSyncPaths])) :
+ NOfSyncPaths := NOfSyncPaths - 1 ;
+ SyncPaths[NOfSyncPaths] := SyncPaths[NOfSyncPaths] bottomenlarged PaperHeight ;
+ fi ;
+ fi ;
+ fi ;
+ if (NOfSyncPaths>1) and collapse :
+ save j ; numeric j ; j := 1 ;
+ for i = 2 upto NOfSyncPaths :
+ if sync_t[n][SyncTasks[i]] = sync_t[n][SyncTasks[j]] :
+ SyncPaths[j] := boundingbox image (draw SyncPaths[i] ; draw SyncPaths[j] ; ) ;
+ SyncTasks[j] := SyncTasks[i] ;
+ else :
+ j := j + 1 ;
+ SyncPaths[j] := SyncPaths[i] ;
+ SyncTasks[j] := SyncTasks[i] ;
+ fi ;
+ endfor ;
+ NOfSyncPaths := j ;
+ fi ;
+ fi ;
+ fi ;
+enddef ;
+
+def SyncTask(expr n) =
+ if known SyncTasks[n] : SyncTasks[n] else : 0 fi
+enddef ;
+
+def FlushSyncTasks =
+ for i = 1 upto NOfSyncPaths :
+ ProcessSyncTask(SyncPaths[i], TheSyncColor(CurrentSyncClass,sync_t[CurrentSyncClass][SyncTasks[i]])) ;
+ endfor ;
+enddef ;
+
+def ProcessSyncTask(expr p, c) =
+ fill p withcolor c ;
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-back.mpiv b/metapost/context/base/mpiv/mp-back.mpiv
new file mode 100644
index 000000000..f588adea9
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-back.mpiv
@@ -0,0 +1,205 @@
+%D \module
+%D [ file=mp-back.mp,
+%D version=2000.05.31,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=backgrounds,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_back : endinput ; fi ;
+
+boolean context_back ; context_back := true ;
+
+def some_hash ( expr hash_width ,
+ hash_height ,
+ hash_linewidth ,
+ hash_linecolor ,
+ hash_angle ,
+ hash_gap ) =
+
+ stripe_gap := hash_gap ;
+ stripe_angle := hash_angle ;
+ drawoptions (withpen pencircle scaled hash_linewidth
+ withcolor hash_linecolor) ;
+ path p ; p := unitsquare xscaled hash_width yscaled hash_height ;
+ stripe_path_a () (draw) p ; % next we move it all to quadrant 1
+ currentpicture := currentpicture shifted urcorner currentpicture ;
+
+enddef ;
+
+def some_double_back (expr back_type ,
+ back_width ,
+ back_height ,
+ back_delta ,
+ back_linewidth ,
+ back_linecolor ,
+ back_fillcolor ,
+ back_topcolor ,
+ back_bottomcolor ,
+ back_leftcolor ,
+ back_rightcolor ) =
+
+ numeric ww ; ww := back_width ;
+ numeric hh ; hh := back_height ;
+ numeric dd ; dd := back_delta ;
+
+ color back_nillcolor ; back_nillcolor := back_topcolor ;
+
+ path p ; p := fullsquare xscaled ww yscaled hh ;
+ path q ; q := fullsquare xscaled (ww-2dd) yscaled (hh-2dd) ;
+ path r ; r := llcorner p --
+ lrcorner p shifted (-3dd,0) .. controls lrcorner p ..
+ lrcorner p shifted (0, 3dd) --
+ urcorner p shifted (0,-3dd) .. controls urcorner p ..
+ urcorner p shifted (-3dd,0) --
+ ulcorner p -- cycle ;
+ path s ; s := r xscaled ((ww-2dd)/ww) yscaled ((hh-2dd)/hh) ;
+ path t ; t := llcorner p --
+ lrcorner p --
+ urcorner p shifted (0,-3dd) .. controls urcorner p ..
+ urcorner p shifted (-3dd,0) --
+ ulcorner p shifted ( 3dd,0) .. controls ulcorner p ..
+ ulcorner p shifted (0,-3dd) --
+ llcorner p -- cycle ;
+ path u ; u := t xscaled ((ww-2dd)/ww) yscaled ((hh-2dd)/hh) ;
+ path v ; v := llcorner p shifted ( 3dd,0) --
+ lrcorner p shifted (-3dd,0) .. controls lrcorner p ..
+ lrcorner p shifted (0, 3dd) --
+ urcorner p shifted (0,-3dd) .. controls urcorner p ..
+ urcorner p shifted (-3dd,0) --
+ ulcorner p shifted ( 3dd,0) .. controls ulcorner p ..
+ ulcorner p shifted (0,-3dd) ..
+ llcorner p shifted (0, 3dd) .. controls llcorner p .. cycle ; % {down} .. cycle ;
+ path w ; w := t xscaled ((ww-2dd)/ww) yscaled ((hh-2dd)/hh) ;
+ path a ; a := llcorner p -- ulcorner p --
+ ulcorner q -- llcorner q -- cycle ;
+ path b ; b := llcorner p -- lrcorner p --
+ lrcorner q -- llcorner q -- cycle ;
+ path c ; c := lrcorner p -- urcorner p --
+ urcorner q -- lrcorner q -- cycle ;
+ path d ; d := ulcorner p -- urcorner p --
+ urcorner q -- ulcorner q -- cycle ;
+ path e ; e := llcorner p -- lrcorner p --
+ urcorner p -- urcorner q --
+ lrcorner q -- llcorner q -- cycle ;
+ path f ; f := llcorner p -- ulcorner p --
+ urcorner p -- urcorner q --
+ ulcorner q -- llcorner q -- cycle ;
+
+ linecap := butt ; pickup pencircle scaled back_linewidth ;
+
+ if back_type=1 :
+
+ fill p withcolor back_fillcolor ;
+ fill a withcolor back_leftcolor ;
+ fill b withcolor back_bottomcolor ;
+ fill c withcolor back_rightcolor ;
+ fill d withcolor back_topcolor ;
+ draw a withcolor back_linecolor ;
+ draw d withcolor back_linecolor ;
+ draw b withcolor back_linecolor ;
+ draw c withcolor back_linecolor ;
+
+ elseif back_type=2 :
+
+ fill p withcolor back_fillcolor ;
+ fill e withcolor back_bottomcolor ;
+ fill f withcolor back_topcolor ;
+ draw e withcolor back_linecolor ;
+ draw f withcolor back_linecolor ;
+
+ elseif back_type=3 :
+
+ fill v withcolor back_nillcolor ;
+ fill w withcolor back_fillcolor ;
+ draw v withcolor back_linecolor ;
+ draw w withcolor back_linecolor ;
+
+ elseif back_type=4 :
+
+ fill t withcolor back_nillcolor ;
+ fill u withcolor back_fillcolor ;
+ draw t withcolor back_linecolor ;
+ draw u withcolor back_linecolor ;
+
+ elseif back_type=5 :
+
+ t := t rotatedaround(center t,180) ;
+ u := u rotatedaround(center u,180) ;
+
+ fill t withcolor back_nillcolor ;
+ fill u withcolor back_fillcolor ;
+ draw t withcolor back_linecolor ;
+ draw u withcolor back_linecolor ;
+
+ elseif back_type=6 :
+
+ r := r rotatedaround(center r,180) ;
+ s := s rotatedaround(center s,180) ;
+
+ fill r withcolor back_nillcolor ;
+ fill s withcolor back_fillcolor ;
+ draw r withcolor back_linecolor ;
+ draw s withcolor back_linecolor ;
+
+ elseif back_type=7 :
+
+ fill r withcolor back_nillcolor ;
+ fill s withcolor back_fillcolor ;
+ draw r withcolor back_linecolor ;
+ draw s withcolor back_linecolor ;
+
+fi ;
+
+enddef ;
+
+endinput ;
+
+beginfig (1) ;
+
+some_double_back (1, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, .6white, .7white, .6white)
+
+currentpicture := currentpicture shifted (0,-3cm) ;
+
+some_double_back (2, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, .6white, white, white)
+
+currentpicture := currentpicture shifted (0,-3cm) ;
+
+some_double_back (3, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, white, white, white)
+
+currentpicture := currentpicture shifted (0,-3cm) ;
+
+some_double_back (4, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, white, white, white)
+
+currentpicture := currentpicture shifted (0,-3cm) ;
+
+some_double_back (5, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, white, white, white)
+
+currentpicture := currentpicture shifted (0,-3cm) ;
+
+some_double_back (6, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, white, white, white)
+
+currentpicture := currentpicture shifted (0,-3cm) ;
+
+some_double_back (7, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, white, white, white)
+
+currentpicture := currentpicture shifted (0,-3cm) ;
+
+some_double_back (8, 4.5cm, 1.5cm, .25cm, 1mm,
+ .5white, .8white, .7white, white, white, white)
+
+endfig ;
+
+end .
diff --git a/metapost/context/base/mpiv/mp-bare.mpiv b/metapost/context/base/mpiv/mp-bare.mpiv
new file mode 100644
index 000000000..c6194b1ee
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-bare.mpiv
@@ -0,0 +1,93 @@
+%D \module
+%D [ file=mp-bare.mpiv,
+%D version=2014.10.31,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=plain plugins,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_bare : endinput ; fi ;
+boolean context_bare ; context_bare := true ;
+
+numeric mfun_tt_w[], mfun_tt_h[], mfun_tt_d[] ;
+numeric mfun_tt_n ; mfun_tt_n := 0 ;
+picture mfun_tt_p ; mfun_tt_p := nullpicture ;
+picture mfun_tt_o ; mfun_tt_o := nullpicture ;
+picture mfun_tt_c ; mfun_tt_c := nullpicture ;
+
+if unknown mfun_trial_run :
+ boolean mfun_trial_run ;
+ mfun_trial_run := false ;
+fi ;
+
+if unknown mfun_first_run :
+ boolean mfun_first_run ;
+ mfun_first_run := true ;
+fi ;
+
+def mfun_reset_tex_texts =
+ mfun_tt_n := 0 ;
+ mfun_tt_p := nullpicture ;
+ mfun_tt_o := nullpicture ; % redundant
+ mfun_tt_c := nullpicture ; % redundant
+enddef ;
+
+def mfun_flush_tex_texts =
+ addto currentpicture also mfun_tt_p
+enddef ;
+
+extra_beginfig := extra_beginfig & "mfun_reset_tex_texts ;" ;
+extra_endfig := "mfun_flush_tex_texts ; mfun_reset_tex_texts ; " & extra_endfig ;
+
+vardef colordecimals primary c =
+ if cmykcolor c :
+ decimal cyanpart c & ":" & decimal magentapart c & ":" & decimal yellowpart c & ":" & decimal blackpart c
+ elseif rgbcolor c :
+ decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c
+ else :
+ decimal c
+ fi
+enddef ;
+
+vardef rawtextext(expr str) = % todo: avoid currentpicture
+ if str = "" :
+ nullpicture
+ else :
+ mfun_tt_n := mfun_tt_n + 1 ;
+ mfun_tt_c := nullpicture ;
+ if mfun_trial_run :
+ mfun_tt_o := nullpicture ;
+ addto mfun_tt_o doublepath origin _op_ ; % save drawoptions
+ addto mfun_tt_c doublepath unitsquare
+ withprescript "tx_number=" & decimal mfun_tt_n
+ withprescript "tx_stage=trial"
+ withprescript "tx_color=" & colordecimals colorpart mfun_tt_o
+ withpostscript str ;
+ addto mfun_tt_p also mfun_tt_c ;
+ elseif known mfun_tt_d[mfun_tt_n] :
+ addto mfun_tt_c doublepath unitsquare
+ xscaled mfun_tt_w[mfun_tt_n]
+ yscaled (mfun_tt_h[mfun_tt_n] + mfun_tt_d[mfun_tt_n])
+ shifted (0,-mfun_tt_d[mfun_tt_n])
+ withprescript "tx_number=" & decimal mfun_tt_n
+ withprescript "tx_stage=final" ;
+ else :
+ addto mfun_tt_c doublepath unitsquare ; % unitpicture
+ fi ;
+ mfun_tt_c
+ fi
+enddef ;
+
+primarydef str infont name = % nasty hack
+ if name = "" :
+ rawtextext(str)
+ else :
+ rawtextext("\definedfont[" & name & "]" & str)
+ fi
+enddef ;
+
diff --git a/metapost/context/base/mpiv/mp-base.mpiv b/metapost/context/base/mpiv/mp-base.mpiv
new file mode 100644
index 000000000..28eb57fb8
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-base.mpiv
@@ -0,0 +1,956 @@
+% This is a reformatted copy of the plain.mp file. We use a copy
+% because (1) we want to make sure that there are no unresolved
+% dependencies, and (2) we may patch this file eventually.
+
+% This file gives the macros for plain MetaPost It contains all the
+% features of plain METAFONT except those specific to font-making.
+% There are also a number of macros for labeling figures, etc.
+
+% For practical reasons I have moved some new code here (and might
+% remove some code as well). After all, there is no development in
+% this format.
+
+string base_name, base_version ;
+
+base_name := "plain" ;
+base_version := "1.004 for metafun iv" ;
+
+message "loading metafun, including plain.mp version " & base_version ;
+
+delimiters () ; % this makes parentheses behave like parentheses
+
+def upto = step 1 until enddef ;
+def downto = step -1 until enddef ;
+
+def exitunless expr c =
+ exitif not c
+enddef ;
+
+let relax = \ ; % ignore the word relax, as in TeX
+let \\ = \ ; % double relaxation is like single
+
+def [[ = [ [ enddef ;
+def ]] = ] ] enddef ;
+
+def -- =
+ {curl 1} .. {curl 1}
+enddef ;
+
+def --- =
+ .. tension infinity ..
+enddef ;
+
+def ... =
+ .. tension atleast 1 ..
+enddef ;
+
+def gobble primary g =
+enddef ;
+
+primarydef g gobbled gg =
+enddef ;
+
+def hide(text t) =
+ exitif numeric begingroup t ; endgroup ;
+enddef ;
+
+def ??? =
+ hide (
+ interim showstopping := 1 ;
+ showdependencies
+ )
+enddef ;
+
+def stop expr s =
+ message s ;
+ gobble readstring
+enddef ;
+
+warningcheck :=1 ;
+tracinglostchars :=1 ;
+
+def interact = % sets up to make "show" commands stop
+ hide (
+ showstopping := 1 ;
+ tracingonline := 1 ;
+ )
+enddef ;
+
+def loggingall = % puts tracing info into the log
+ tracingcommands := 3 ;
+ tracingtitles := 1 ;
+ tracingequations := 1 ;
+ tracingcapsules := 1 ;
+ tracingspecs := 2 ;
+ tracingchoices := 1 ;
+ tracinglostchars := 1 ;
+ tracingstats := 1 ;
+ tracingoutput := 1 ;
+ tracingmacros := 1 ;
+ tracingrestores := 1 ;
+enddef ;
+
+def tracingall = % turns on every form of tracing
+ tracingonline := 1 ;
+ showstopping := 1 ;
+ loggingall ;
+enddef ;
+
+def tracingnone = % turns off every form of tracing
+ tracingcommands := 0 ;
+ tracingtitles := 0 ;
+ tracingequations := 0 ;
+ tracingcapsules := 0 ;
+ tracingspecs := 0 ;
+ tracingchoices := 0 ;
+ tracinglostchars := 0 ;
+ tracingstats := 0 ;
+ tracingoutput := 0 ;
+ tracingmacros := 0 ;
+ tracingrestores := 0 ;
+enddef ;
+
+%% dash patterns
+
+vardef dashpattern(text t) =
+ save on, off, w ;
+ let on = _on_ ;
+ let off = _off_ ;
+ w = 0 ;
+ nullpicture t
+enddef ;
+
+tertiarydef p _on_ d =
+ begingroup save pic ;
+ picture pic;
+ pic = p ;
+ addto pic doublepath (w,w) .. (w+d,w) ;
+ w := w + d ;
+ pic shifted (0,d)
+ endgroup
+enddef ;
+
+tertiarydef p _off_ d =
+ begingroup w := w + d ;
+ p shifted (0,d)
+ endgroup
+enddef ;
+
+%% basic constants and mathematical macros
+
+% numeric constants
+
+newinternal eps, epsilon, infinity, _ ;
+
+eps := .00049 ; % this is a pretty small positive number
+epsilon := 1/256/256 ; % but this is the smallest
+infinity := 4095.99998 ; % and this is the largest
+_ := -1 ; % internal constant to make macros unreadable but shorter
+
+% linejoin and linecap types
+
+newinternal mitered, rounded, beveled, butt, squared ;
+
+mitered := 0 ; rounded := 1 ; beveled := 2 ;
+butt := 0 ; rounded := 1 ; squared := 2 ;
+
+% pair constants
+
+pair right, left, up, down, origin;
+
+origin = (0,0) ;
+up = -down = (0,1) ;
+right = -left = (1,0) ;
+
+% path constants
+
+path quartercircle, halfcircle, fullcircle, unitsquare ;
+
+fullcircle = makepath pencircle ;
+halfcircle = subpath (0,4) of fullcircle ;
+quartercircle = subpath (0,2) of fullcircle ;
+unitsquare = (0,0) -- (1,0) -- (1,1) -- (0,1) -- cycle ;
+
+% transform constants
+
+transform identity ;
+
+for z=origin,right,up :
+ z transformed identity = z ;
+endfor
+
+% color constants (all in rgb color space)
+
+color black, white, red, green, blue, cyan, magenta, yellow, background;
+
+black := (0,0,0) ;
+white := (1,1,1) ;
+red := (1,0,0) ;
+green := (0,1,0) ;
+blue := (0,0,1) ;
+cyan := (0,1,1) ;
+magenta := (1,0,1) ;
+yellow := (1,1,0) ;
+
+background := white ; % obsolete
+
+let graypart = greypart ;
+let greycolor = numeric ;
+let graycolor = numeric ;
+
+% color part (will be overloaded)
+
+def colorpart primary t =
+ if colormodel t=7:
+ (cyanpart t, magentapart t, yellowpart t, blackpart t)
+ elseif colormodel t = 5 :
+ (redpart t, greenpart t, bluepart t)
+ elseif colormodel t = 3 :
+ (greypart t)
+ elseif colormodel t = 1 :
+ false
+ elseif defaultcolormodel = 7 :
+ (0,0,0,1)
+ elseif defaultcolormodel = 5 :
+ black
+ elseif defaultcolormodel = 3 :
+ 0
+ else :
+ false
+ fi
+enddef ;
+
+% picture constants
+
+picture blankpicture, evenly, withdots ;
+
+blankpicture = nullpicture ; % display blankpicture...
+evenly = dashpattern(on 3 off 3) ; % dashed evenly
+withdots = dashpattern(off 2.5 on 0 off 2.5) ; % dashed withdots
+
+% string constants
+
+string ditto, EOF ;
+
+ditto = char 34 ; % ASCII double-quote mark
+EOF = char 0 ; % end-of-file for readfrom and write..to
+
+% pen constants
+
+pen pensquare, penrazor, penspeck ;
+
+pensquare = makepen(unitsquare shifted -(.5,.5)) ;
+penrazor = makepen((-.5,0) -- (.5,0) -- cycle) ;
+penspeck = pensquare scaled eps ;
+
+% nullary operators
+
+vardef whatever =
+ save ? ;
+ ?
+enddef ;
+
+% unary operators
+
+let abs = length ;
+
+vardef round primary u =
+ if numeric u :
+ floor(u+.5)
+ elseif pair u :
+ (round xpart u, round ypart u)
+ else :
+ u
+ fi
+enddef ;
+
+vardef ceiling primary x =
+ -floor(-x)
+enddef ;
+
+vardef byte primary s =
+ if string s :
+ ASCII
+ fi s
+enddef ;
+
+vardef dir primary d =
+ right rotated d
+enddef ;
+
+vardef unitvector primary z =
+ z/abs z
+enddef ;
+
+vardef inverse primary T =
+ transform T_ ;
+ T_ transformed T = identity ;
+ T_
+enddef ;
+
+vardef counterclockwise primary c =
+ if turningnumber c <= 0 :
+ reverse
+ fi c
+enddef ;
+
+vardef tensepath expr r =
+ for k=0 upto length r - 1 :
+ point k of r ---
+ endfor
+ if cycle r :
+ cycle
+ else :
+ point infinity of r
+ fi
+enddef ;
+
+vardef center primary p =
+ .5[llcorner p, urcorner p]
+enddef ;
+
+% binary operators
+
+primarydef x mod y =
+ (x-y*floor(x/y))
+enddef ;
+
+primarydef x div y =
+ floor(x/y)
+enddef ;
+
+primarydef w dotprod z =
+ (xpart w * xpart z + ypart w * ypart z)
+enddef ;
+
+primarydef x**y =
+ if y = 2 :
+ x*x
+ else :
+ takepower y of x
+ fi
+enddef ;
+
+def takepower expr y of x =
+ if x>0 :
+ mexp(y*mlog x)
+ elseif (x=0) and (y>0) :
+ 0
+ else :
+ 1
+ if y = floor y :
+ if y >= 0 :
+ for n=1 upto y :
+ *x
+ endfor
+ else :
+ for n=-1 downto y :
+ /x
+ endfor
+ fi
+ else :
+ hide(errmessage "Undefined power: " & decimal x & "**" & decimal y)
+ fi
+ fi
+enddef ;
+
+% for big number systems:
+%
+% primarydef x**y =
+% if y = 1 :
+% x
+% elseif y = 2 :
+% x*x
+% elseif y = 3 :
+% x*x*x
+% else :
+% takepower y of x
+% fi
+% enddef ;
+%
+% vardef takepower expr y of x =
+% if (x=0) and (y>0) :
+% 0
+% else :
+% 1
+% if y = floor y :
+% if y >= 0 :
+% for n=1 upto y :
+% *x
+% endfor
+% else :
+% for n=-1 downto y :
+% /x
+% endfor
+% fi
+% else :
+% hide(errmessage "Undefined power: " & decimal x & "**" & decimal y)
+% fi
+% fi
+% enddef ;
+
+vardef direction expr t of p =
+ postcontrol t of p - precontrol t of p
+enddef ;
+
+vardef directionpoint expr z of p =
+ a_ := directiontime z of p ;
+ if a_ < 0 :
+ errmessage("The direction doesn't occur") ;
+ fi
+ point a_ of p
+enddef ;
+
+secondarydef p intersectionpoint q =
+ begingroup
+ save x_, y_ ;
+ (x_,y_) = p intersectiontimes q ;
+ if x_ < 0 :
+ errmessage("The paths don't intersect") ;
+ origin
+ else :
+ .5[point x_ of p, point y_ of q]
+ fi
+ endgroup
+enddef ;
+
+tertiarydef p softjoin q =
+ begingroup
+ c_ := fullcircle scaled 2join_radius shifted point 0 of q ;
+ a_ := ypart(c_ intersectiontimes p) ;
+ b_ := ypart(c_ intersectiontimes q) ;
+ if a_ < 0 :
+ point 0 of p{direction 0 of p}
+ else :
+ subpath(0,a_) of p
+ fi
+ ...
+ if b_ < 0 :
+ {direction infinity of q} point infinity of q
+ else :
+ subpath(b_,infinity) of q
+ fi
+ endgroup
+enddef ;
+
+newinternal join_radius, a_, b_ ; path c_ ;
+
+path cuttings ; % what got cut off
+
+tertiarydef a cutbefore b = % tries to cut as little as possible
+ begingroup
+ save t ;
+ (t, whatever) = a intersectiontimes b ;
+ if t < 0 :
+ cuttings := point 0 of a ;
+ a
+ else :
+ cuttings := subpath (0,t) of a ;
+ subpath (t,length a) of a
+ fi
+ endgroup
+enddef ;
+
+tertiarydef a cutafter b =
+ reverse (reverse a cutbefore b)
+ hide(cuttings := reverse cuttings)
+enddef ;
+
+% special operators
+
+vardef incr suffix $ = $:=$+1; $ enddef ;
+vardef decr suffix $ = $:=$-1; $ enddef ;
+
+def reflectedabout(expr w,z) = % reflects about the line w..z
+ transformed
+ begingroup
+ transform T_ ;
+ w transformed T_ = w ;
+ z transformed T_ = z ;
+ xxpart T_ = -yypart T_ ;
+ xypart T_ = yxpart T_ ; % T_ is a reflection
+ T_
+ endgroup
+enddef ;
+
+def rotatedaround(expr z, d) = % rotates d degrees around z
+ shifted -z rotated d shifted z
+enddef ;
+
+let rotatedabout = rotatedaround ; % for roundabout people
+
+vardef min(expr u)(text t) = % t is a list of numerics, pairs, or strings
+ save u_ ;
+ setu_ u ;
+ for uu = t :
+ if uu < u_ :
+ u_ := uu ;
+ fi
+ endfor
+ u_
+enddef ;
+
+vardef max(expr u)(text t) = % t is a list of numerics, pairs, or strings
+ save u_ ;
+ setu_ u ;
+ for uu = t :
+ if uu > u_ :
+ u_ := uu ;
+ fi
+ endfor
+ u_
+enddef ;
+
+def setu_ primary u =
+ if pair u :
+ pair u_
+ elseif string u :
+ string u_
+ fi ;
+ u_=u
+enddef ;
+
+def flex(text t) = % t is a list of pairs
+ hide (
+ n_ := 0 ;
+ for z=t :
+ z_[incr n_] := z ;
+ endfor
+ dz_ := z_[n_]-z_1
+ )
+ z_1 for k=2 upto n_-1 :
+ ... z_[k]{dz_}
+ endfor ... z_[n_]
+enddef ;
+
+newinternal n_; pair z_[],dz_;
+
+def superellipse(expr r,t,l,b,s) =
+ r { up } ... (s[xpart t,xpart r],s[ypart r,ypart t]) { t-r } ...
+ t { left } ... (s[xpart t,xpart l],s[ypart l,ypart t]) { l-t } ...
+ l { down } ... (s[xpart b,xpart l],s[ypart l,ypart b]) { b-l } ...
+ b { right } ... (s[xpart b,xpart r],s[ypart r,ypart b]) { r-b } ... cycle enddef ;
+
+vardef interpath(expr a,p,q) =
+ for t=0 upto length p-1 :
+ a[point t of p, point t of q] .. controls a[postcontrol t of p, postcontrol t of q] and a[precontrol t+1 of p, precontrol t+1 of q] ..
+ endfor
+ if cycle p :
+ cycle
+ else :
+ a[point infinity of p, point infinity of q]
+ fi
+enddef ;
+
+vardef solve@#(expr true_x,false_x)= % @#(true_x)=true, @#(false_x)=false
+ tx_:=true_x; fx_:=false_x;
+ forever :
+ x_ := .5[tx_,fx_] ;
+ exitif abs(tx_-fx_) <= tolerance ;
+ if @#(x_) :
+ tx_
+ else :
+ fx_
+ fi := x_ ;
+ endfor
+ x_ % now x_ is near where @# changes from true to false
+enddef ;
+
+newinternal tolerance, tx_, fx_, x_ ;
+
+tolerance := .01 ;
+
+vardef buildcycle(text ll) =
+ save ta_, tb_, k_, i_, pp_ ; path pp_[] ;
+ k_ = 0 ;
+ for q=ll :
+ pp_[incr k_] = q ;
+ endfor
+ i_ = k_ ;
+ for i=1 upto k_ :
+ (ta_[i], length pp_[i_]-tb_[i_]) = pp_[i] intersectiontimes reverse pp_[i_] ;
+ if ta_[i]<0 :
+ errmessage("Paths "& decimal i &" and "& decimal i_ &" don't intersect") ;
+ fi
+ i_ := i;
+ endfor
+ for i=1 upto k_ :
+ subpath (ta_[i],tb_[i]) of pp_[i] ..
+ endfor
+ cycle
+enddef ;
+
+%% units of measure
+
+mm := 2.83464 ;
+pt := 0.99626 ;
+dd := 1.06601 ;
+bp := 1 ;
+cm := 28.34645 ;
+pc := 11.95517 ;
+cc := 12.79213 ;
+in := 72 ;
+
+vardef magstep primary m = % obsolete
+ mexp(46.67432m)
+enddef ;
+
+%% macros for drawing and filling
+
+def drawoptions(text t) =
+ def _op_ = t enddef
+enddef ;
+
+% parameters that effect drawing
+
+linejoin := rounded ;
+linecap := rounded ;
+miterlimit := 10 ;
+
+drawoptions() ;
+
+pen currentpen ;
+picture currentpicture ;
+
+def fill expr c =
+ addto currentpicture contour c _op_
+enddef ;
+
+def draw expr p =
+ addto currentpicture
+ if picture p :
+ also p
+ else :
+ doublepath p withpen currentpen
+ fi
+ _op_
+enddef ;
+
+def filldraw expr c =
+ addto currentpicture contour c withpen currentpen _op_
+enddef ;
+
+% def drawdot expr z =
+% addto currentpicture contour makepath currentpen shifted z _op_
+% enddef ;
+%
+% testcase DEK:
+%
+% for j=1 upto 9 :
+% pickup pencircle xscaled .4 yscaled .2 ;
+% drawdot (10j,0) withpen pencircle xscaled .5j yscaled .25j rotated 45 ;
+% pickup pencircle xscaled .5j yscaled .25j rotated 45 ;
+% drawdot (10j,10);
+% endfor ;
+%
+% or:
+%
+%\startMPpage
+%
+% def drawdot expr z =
+% addto currentpicture contour (makepath currentpen shifted z) _op_
+% enddef;
+%
+% drawdot origin shifted (0,-3cm) withpen pencircle scaled 2cm ;
+% pickup pencircle scaled 2cm ; drawdot origin withcolor red ;
+
+def drawdot expr p =
+ if pair p :
+ addto currentpicture doublepath p withpen currentpen _op_
+ else :
+ errmessage("drawdot only accepts a pair expression")
+ fi
+enddef ;
+
+def unfill expr c = fill c withcolor background enddef ;
+def undraw expr p = draw p withcolor background enddef ;
+def unfilldraw expr c = filldraw c withcolor background enddef ;
+def undrawdot expr z = drawdot z withcolor background enddef ;
+
+def erase text t =
+ def _e_ =
+ withcolor background hide(def _e_ = enddef ;)
+ enddef ;
+ t _e_
+enddef ;
+
+def _e_ = enddef ;
+
+def cutdraw text t =
+ begingroup
+ interim linecap := butt ;
+ draw t _e_ ;
+ endgroup
+enddef ;
+
+vardef image(text t) =
+ save currentpicture ;
+ picture currentpicture ;
+ currentpicture := nullpicture ;
+ t ;
+ currentpicture
+enddef ;
+
+def pickup secondary q =
+ if numeric q :
+ numeric_pickup_
+ else :
+ pen_pickup_
+ fi q
+enddef ;
+
+def numeric_pickup_ primary q =
+ if unknown pen_[q] :
+ errmessage "Unknown pen" ;
+ clearpen
+ else :
+ currentpen := pen_ [q] ;
+ pen_lft := pen_lft_[q] ;
+ pen_rt := pen_rt_ [q] ;
+ pen_top := pen_top_[q] ;
+ pen_bot := pen_bot_[q] ;
+ currentpen_path := pen_path_[q]
+ fi ;
+enddef ;
+
+def pen_pickup_ primary q =
+ currentpen := q ;
+ pen_lft := xpart penoffset down of currentpen ;
+ pen_rt := xpart penoffset up of currentpen ;
+ pen_top := ypart penoffset left of currentpen ;
+ pen_bot := ypart penoffset right of currentpen ;
+ path currentpen_path ;
+enddef ;
+
+newinternal pen_lft, pen_rt, pen_top, pen_bot, pen_count_ ;
+
+vardef savepen =
+ pen_[incr pen_count_] = currentpen ;
+ pen_lft_ [pen_count_] = pen_lft ;
+ pen_rt_ [pen_count_] = pen_rt ;
+ pen_top_ [pen_count_] = pen_top ;
+ pen_bot_ [pen_count_] = pen_bot ;
+ pen_path_[pen_count_] = currentpen_path ;
+ pen_count_
+enddef ;
+
+def clearpen =
+ currentpen := nullpen;
+ pen_lft := pen_rt := pen_top := pen_bot := 0 ;
+ path currentpen_path ;
+enddef ;
+
+def clear_pen_memory =
+ pen_count_ := 0 ;
+ numeric pen_lft_[], pen_rt_[], pen_top_[], pen_bot_[] ;
+ pen currentpen, pen_[];
+ path currentpen_path, pen_path_[] ;
+enddef ;
+
+vardef lft primary x = x + if pair x: (pen_lft,0) else: pen_lft fi enddef ;
+vardef rt primary x = x + if pair x: (pen_rt,0) else: pen_rt fi enddef ;
+vardef top primary y = y + if pair y: (0,pen_top) else: pen_top fi enddef ;
+vardef bot primary y = y + if pair y: (0,pen_bot) else: pen_bot fi enddef ;
+
+vardef penpos@#(expr b,d) =
+ (x@#r-x@#l,y@#r-y@#l) = (b,0) rotated d ;
+ x@# = .5(x@#l+x@#r) ;
+ y@# = .5(y@#l+y@#r) ; % ; added HH
+enddef ;
+
+path path_.l, path_.r ;
+
+def penstroke text t =
+ forsuffixes e = l, r :
+ path_.e := t ;
+ endfor
+ fill path_.l -- reverse path_.r -- cycle
+enddef ;
+
+%% High level drawing commands
+
+newinternal ahlength, ahangle ;
+
+ahlength := 4 ; % default arrowhead length 4bp
+ahangle := 45 ; % default head angle 45 degrees
+
+vardef arrowhead expr p =
+ save q, e ; path q ; pair e ;
+ e = point length p of p ;
+ q = gobble(p shifted -e cutafter makepath(pencircle scaled 2ahlength)) cuttings ;
+ (q rotated .5ahangle & reverse q rotated -.5ahangle -- cycle) shifted e
+enddef ;
+
+path _apth ;
+
+def drawarrow expr p = _apth := p ; _finarr enddef ;
+def drawdblarrow expr p = _apth := p ; _findarr enddef ;
+
+def _finarr text t =
+ draw _apth t ;
+ filldraw arrowhead _apth t
+enddef ;
+
+def _findarr text t = % this had fill in 0.63 (potential incompatibility)
+ draw _apth t ;
+ filldraw arrowhead _apth withpen currentpen t ;
+ filldraw arrowhead reverse _apth withpen currentpen t ; % ; added HH
+enddef ;
+
+%% macros for labels
+
+newinternal bboxmargin ;
+
+bboxmargin := 2bp ; % this can bite you
+
+vardef bbox primary p =
+ llcorner p - ( bboxmargin, bboxmargin) --
+ lrcorner p + ( bboxmargin,-bboxmargin) --
+ urcorner p + ( bboxmargin, bboxmargin) --
+ ulcorner p + (-bboxmargin, bboxmargin) -- cycle
+enddef ;
+
+string defaultfont ; newinternal defaultscale, labeloffset ;
+
+defaultfont := "cmr10" ;
+defaultscale := 1 ;
+labeloffset := 3bp ;
+
+vardef thelabel@#(expr s,z) = % Position s near z
+ save p ; picture p ;
+ if picture s :
+ p = s
+ else :
+ p = s infont defaultfont scaled defaultscale
+ fi ;
+ p shifted (z + labeloffset*laboff@# - ( labxf@#*lrcorner p + labyf@#*ulcorner p + (1-labxf@#-labyf@#)*llcorner p) )
+enddef ;
+
+def label =
+ draw thelabel
+enddef ;
+
+newinternal dotlabeldiam ;
+
+dotlabeldiam := 3bp ;
+
+vardef dotlabel@#(expr s,z) text t_ =
+ label@#(s,z) t_ ;
+ % label@#(s,z) ;
+ interim linecap := rounded ;
+ draw z withpen pencircle scaled dotlabeldiam t_ ;
+enddef ;
+
+def makelabel =
+ dotlabel
+enddef ;
+
+% this will be overloaded
+
+pair laboff, laboff.lft, laboff.rt, laboff.top, laboff.bot ;
+pair laboff.ulft, laboff.llft, laboff.urt, laboff.lrt ;
+
+laboff = (0,0) ; labxf = .5 ; labyf = .5 ;
+laboff.lft = (-1,0) ; labxf.lft = 1 ; labyf.lft = .5 ;
+laboff.rt = (1,0) ; labxf.rt = 0 ; labyf.rt = .5 ;
+laboff.bot = (0,-1) ; labxf.bot = .5 ; labyf.bot = 1 ;
+laboff.top = (0,1) ; labxf.top = .5 ; labyf.top = 0 ;
+laboff.ulft = (-.7,.7) ; labxf.ulft = 1 ; labyf.ulft = 0 ;
+laboff.urt = (.7,.7) ; labxf.urt = 0 ; labyf.urt = 0 ;
+laboff.llft = -(.7,.7) ; labxf.llft = 1 ; labyf.llft = 1 ;
+laboff.lrt = (.7,-.7) ; labxf.lrt = 0 ; labyf.lrt = 1 ;
+
+vardef labels@#(text t) =
+ forsuffixes $=t :
+ label@#(str$,z$) ;
+ endfor
+enddef ;
+
+% till lhere
+
+vardef dotlabels@#(text t) =
+ forsuffixes $=t:
+ dotlabel@#(str$,z$) ;
+ endfor
+enddef ;
+
+vardef penlabels@#(text t) =
+ forsuffixes $$=l,,r :
+ forsuffixes $=t :
+ makelabel@#(str$.$$,z$.$$) ;
+ endfor
+ endfor
+enddef ;
+
+% range 4 thru 10
+
+def range expr x =
+ _numtok_[x]
+enddef ;
+
+def _numtok_ suffix x =
+ x
+enddef ;
+
+tertiarydef m thru n =
+ m for x=m+1 step 1 until n :
+ , _numtok_[x]
+ endfor
+enddef ;
+
+%% Overall administration
+
+string extra_beginfig, extra_endfig ;
+
+extra_beginfig := "" ;
+extra_endfig := "" ;
+
+def beginfig(expr c) =
+ begingroup
+ charcode := c ;
+ clearxy ;
+ clearit ;
+ clearpen ;
+ pickup defaultpen ;
+ drawoptions() ;
+ scantokens extra_beginfig ;
+enddef ;
+
+def endfig =
+ ; % added by HH
+ scantokens extra_endfig ;
+ shipit ;
+ endgroup
+enddef ;
+
+%% last-minute items
+
+vardef z@# =
+ (x@#,y@#)
+enddef ;
+
+def clearxy =
+ save x, y
+enddef ;
+
+def clearit =
+ currentpicture := nullpicture
+enddef ;
+
+def shipit =
+ shipout currentpicture
+enddef ;
+
+let bye = end ;
+outer end, bye ;
+
+clear_pen_memory ; % initialize the savepen mechanism
+clearit ;
+
+% set default line width
+
+newinternal defaultpen ;
+
+pickup pencircle scaled .5bp ;
+
+defaultpen := savepen ;
diff --git a/metapost/context/base/mpiv/mp-butt.mpiv b/metapost/context/base/mpiv/mp-butt.mpiv
new file mode 100644
index 000000000..6f5b90a7e
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-butt.mpiv
@@ -0,0 +1,77 @@
+%D \module
+%D [ file=mp-butt.mpiv,
+%D version=2000.05.31,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=buttons,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_butt : endinput ; fi ;
+
+boolean context_butt ; context_butt := true ;
+
+def predefinedbutton (expr button_type, button_size, button_linecolor, button_fillcolor) =
+
+ begingroup ;
+
+ save button_linewidth, p, d, l ;
+
+ numeric button_linewidth ; button_linewidth := button_size/10 ;
+
+ drawoptions (withpen pencircle scaled button_linewidth withcolor button_linecolor) ;
+
+ path p ; p := unitsquare scaled button_size ;
+ numeric d ; d := button_size ;
+ numeric l ; l := button_linewidth ;
+
+ fill p withcolor button_fillcolor ;
+ draw p ;
+
+ if button_type = 101 :
+ draw (d-2l,2l)--(2l,.5d)--(d-2l,d-2l)--cycle ;
+ elseif button_type = 102 :
+ draw (2l,2l)--(d-2l,.5d)--(2l,d-2l)--cycle ;
+ elseif button_type = 103 :
+ for i=2l step 2l until d-2l :
+ draw (2l,i)--(2l ,i) ;
+ draw (4l,i)--(d-2l,i) ;
+ endfor ;
+ elseif button_type = 104 :
+ for i=2l step 2l until d-2l :
+ draw (2l ,i)--(d/2-l,i) ;
+ draw (d/2+l,i)--(d-2l ,i) ;
+ endfor ;
+ elseif button_type = 105 :
+ fill fullcircle scaled (.2d) shifted (.5d,.7d) ;
+ fill fullcircle xscaled (.6d) yscaled d shifted (.5d,0) ;
+ clip currentpicture to p ;
+ draw p ;
+ elseif button_type = 106 :
+ draw (2l,2l)--(d-2l,d-2l) ;
+ draw (d-2l,2l)--(2l,d-2l) ;
+ elseif button_type = 107 :
+ p := (3l,d-2l)--(d-3l,d-2l)--(.5d,4l)--cycle ;
+ fill p ; draw p ;
+ draw (.5d,2l) ;
+ elseif button_type = 108 :
+ draw (.5d,2l)--(d-2l,d-2l)--(2l,d-2l)--cycle ;
+ elseif button_type = 109 :
+ draw (.5d,d-2l)--(d-2l,2l)--(2l,2l)--cycle ;
+ elseif button_type = 110 :
+ button_linewidth := button_linewidth/2 ;
+ draw p enlarged (-2l,-l) ;
+ for i=2l step l until d-2l :
+ draw (3l,i)--(d-3l,i) ;
+ endfor ;
+ fi ;
+
+ endgroup ;
+
+enddef ;
+
+let some_button = predefinedbutton
diff --git a/metapost/context/base/mpiv/mp-char.mpiv b/metapost/context/base/mpiv/mp-char.mpiv
new file mode 100644
index 000000000..f604accd8
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-char.mpiv
@@ -0,0 +1,1116 @@
+%D \module
+%D [ file=mp-char.mpiv,
+%D version=2011.10.1, % 1998.10.10,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=charts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+%D This is ancient code .. but I see no need to rewrite it. This is
+%D already a partial rewrite but more could be delegated to \LUA\
+%D when used in \CONTEXT\ but it does not pay off now to look into
+%D that.
+
+%D For historic reason we first build and then flush but we could
+%D as well flush directly which would save us caching.
+
+if unknown context_shap : input "mp-shap.mpiv" ; fi ;
+if known context_flow : endinput ; fi ;
+
+boolean context_flow ; context_flow := true ;
+
+%D settings
+
+numeric flow_grid_width ; flow_grid_width := 60pt ;
+numeric flow_shape_width ; flow_shape_width := 45pt ;
+numeric flow_grid_height ; flow_grid_height := 40pt ;
+numeric flow_shape_height ; flow_shape_height := 30pt ;
+numeric flow_chart_offset ; flow_chart_offset := 2pt ;
+color flow_chart_background_color ; flow_chart_background_color := white ;
+boolean flow_show_mid_points ; flow_show_mid_points := false ;
+boolean flow_show_con_points ; flow_show_con_points := false ;
+boolean flow_show_all_points ; flow_show_all_points := false ;
+numeric flow_shape_line_width ; flow_shape_line_width := 2pt ;
+color flow_shape_line_color ; flow_shape_line_color := .5white ;
+color flow_shape_fill_color ; flow_shape_fill_color := .9white ;
+color flow_connection_line_color ; flow_connection_line_color := .2white ;
+
+numeric flow_connection_line_width ; flow_connection_line_width := flow_shape_line_width ;
+
+numeric flow_connection_smooth_size ; flow_connection_smooth_size := 5pt ;
+numeric flow_connection_arrow_size ; flow_connection_arrow_size := 4pt ;
+numeric flow_connection_dash_size ; flow_connection_dash_size := 3pt ;
+
+numeric flow_max_x ; flow_max_x := 6 ;
+numeric flow_max_y ; flow_max_y := 4 ;
+
+boolean flow_smooth ; flow_smooth := true ;
+boolean flow_peepshape ; flow_peepshape := false ;
+boolean flow_arrowtip ; flow_arrowtip := true ;
+boolean flow_dashline ; flow_dashline := false ;
+boolean flow_forcevalid ; flow_forcevalid := false ;
+boolean flow_touchshape ; flow_touchshape := false ;
+boolean flow_showcrossing ; flow_showcrossing := false ;
+boolean flow_reverse_y ; flow_reverse_y := true ;
+
+picture flow_dash_pattern ; flow_dash_pattern := nullpicture ;
+
+numeric flow_shape_node ; flow_shape_node := 0 ;
+numeric flow_shape_action ; flow_shape_action := 24 ;
+numeric flow_shape_procedure ; flow_shape_procedure := 5 ;
+numeric flow_shape_product ; flow_shape_product := 12 ;
+numeric flow_shape_decision ; flow_shape_decision := 14 ;
+numeric flow_shape_archive ; flow_shape_archive := 19 ;
+numeric flow_shape_loop ; flow_shape_loop := 35 ;
+numeric flow_shape_wait ; flow_shape_wait := 6 ;
+numeric flow_shape_subprocedure ; flow_shape_subprocedure := 20 ;
+numeric flow_shape_singledocument ; flow_shape_singledocument := 32 ;
+numeric flow_shape_multidocument ; flow_shape_multidocument := 33 ;
+numeric flow_shape_right ; flow_shape_right := 66 ;
+numeric flow_shape_left ; flow_shape_left := 67 ;
+numeric flow_shape_up ; flow_shape_up := 68 ;
+numeric flow_shape_down ; flow_shape_down := 69 ;
+
+numeric flow_label_offset ; flow_label_offset := 0 ;
+numeric flow_exit_offset ; flow_exit_offset := 0 ;
+numeric flow_comment_offset ; flow_comment_offset := 0 ;
+
+% vardef some_shape_path (expr type) == imported from mp-shap
+
+def flow_show_shapes(expr n) =
+ flow_begin_chart(n,8,10) ;
+ flow_show_con_points := true ;
+ for i=0 upto 7 :
+ for j=0 upto 9 :
+ flow_new_shape(i+1,j+1,i*10+j);
+ endfor ;
+ endfor ;
+ flow_end_chart ;
+enddef ;
+
+%D connections
+
+def flow_new_chart =
+
+ flow_grid_width := 60pt ;
+ flow_shape_width := 45pt ;
+ flow_grid_height := 40pt ;
+ flow_shape_height := 30pt ;
+ flow_chart_offset := 2pt ;
+ flow_chart_background_color := white ;
+ flow_show_mid_points := false ;
+ flow_show_con_points := false ;
+ flow_show_all_points := false ;
+ flow_shape_line_width := 2pt ;
+ flow_shape_line_color := .5white ;
+ flow_shape_fill_color := .9white ;
+ flow_connection_line_color := .2white ;
+ flow_connection_line_width := flow_shape_line_width ;
+ flow_connection_smooth_size := 5pt ;
+ flow_connection_arrow_size := 4pt ;
+ flow_connection_dash_size := 3pt ;
+ flow_label_offset := 0 ;
+ flow_exit_offset := 0 ;
+ flow_comment_offset := 0 ;
+
+ flow_max_x := 6 ;
+ flow_max_y := 4 ;
+
+ flow_smooth := true ;
+ flow_peepshape := false ;
+ flow_arrowtip := true ;
+ flow_dashline := false ;
+ flow_forcevalid := false ;
+ flow_touchshape := false ;
+ flow_showcrossing := false ;
+ flow_reverse_y := true ;
+
+ flow_dash_pattern := nullpicture ;
+
+ numeric flow_xypoint ; flow_xypoint := 0 ;
+ numeric flow_cpath ; flow_cpath := 0 ;
+
+ pair flow_xypoints [] ;
+ boolean flow_xyfree [][] ;
+ path flow_xypath [][] ;
+ numeric flow_xysx [][] ;
+ numeric flow_xysy [][] ;
+ color flow_xyfill [][] ;
+ color flow_xydraw [][] ;
+ numeric flow_xyline [][] ;
+ boolean flow_xypeep [][] ;
+ picture flow_xytext [][] ;
+ picture flow_xylabel [][] ;
+ picture flow_xyexit [][] ;
+ picture flow_xycomment [][] ;
+ path flow_cpaths [] ;
+ numeric flow_cline [] ;
+ color flow_ccolor [] ;
+ boolean flow_carrow [] ;
+ boolean flow_cdash [] ;
+ boolean flow_ccross [] ;
+ picture flow_tpicture [][] ;
+ picture flow_bpicture [][] ;
+ picture flow_lpicture [][] ;
+ picture flow_rpicture [][] ;
+ path flow_connections[][][] ;
+
+ predefined_shapes[61] := (fullcircle scaled (1.5*predefined_shapes_yradius) xscaled (flow_grid_height/flow_grid_width)) ;
+ predefined_shapes[62] := (fullcircle scaled (2.0*predefined_shapes_yradius) xscaled (flow_grid_height/flow_grid_width)) ;
+
+enddef ;
+
+flow_new_chart ;
+
+def flow_y_pos(expr y) =
+% if flow_reverse_y :
+ flow_max_y + 1 - y
+% else :
+% y
+% fi
+enddef ;
+
+def flow_initialize_grid(expr maxx, maxy) =
+ flow_max_x := maxx ;
+ flow_max_y := maxy ;
+ flow_dsp_x := 0 ;
+ flow_dsp_y := 0 ;
+ for x=1 upto flow_max_x :
+ for y=1 upto flow_max_y :
+ flow_xyfree[x][y] := true ;
+ flow_xyfill[x][y] := flow_shape_fill_color ;
+ flow_xydraw[x][y] := flow_shape_line_color ;
+ flow_xyline[x][y] := flow_shape_line_width ;
+ endfor ;
+ endfor ;
+enddef ;
+
+def flow_scaled_to_grid =
+ xscaled flow_grid_width yscaled flow_grid_height
+enddef ;
+
+def flow_xy_offset(expr x, y) =
+ (x+.5,y+.5)
+enddef ;
+
+def flow_draw_shape(expr x, yy, p, sx, sy) =
+ begingroup ;
+ save y ; numeric y ;
+ y := flow_y_pos(yy) ;
+ flow_xypath [x][y] := (p xscaled sx yscaled sy) shifted flow_xy_offset(x,y) ;
+ flow_xyfree [x][y] := false ;
+ flow_xysx [x][y] := sx ;
+ flow_xysy [x][y] := sy ;
+ flow_xyfill [x][y] := flow_shape_fill_color ;
+ flow_xydraw [x][y] := flow_shape_line_color ;
+ flow_xyline [x][y] := flow_shape_line_width ;
+ flow_xypeep [x][y] := flow_peepshape ;
+ endgroup ;
+enddef ;
+
+vardef flow_i_point (expr x, y, p, t) =
+ begingroup ;
+ save q, ok ; pair q ; boolean ok ;
+ q := flow_xypath[x][y] intersection_point ((p) shifted flow_xy_offset(x,y)) ;
+ ok := true ;
+ if not ok :
+ message (t & " of shape (" & decimal x & "," & decimal y & ") limited") ;
+ fi ;
+ q
+ endgroup
+enddef ;
+
+vardef flow_trimmed (expr x, y, z, t) =
+ if flow_touchshape and t :
+ flow_xyline[x][y]/z
+ else :
+ epsilon
+ fi
+enddef ;
+
+numeric flow_zfactor ; flow_zfactor := 1/3 ;
+
+vardef flow_xy_bottom (expr x, y, z, t) =
+ flow_i_point(x, y, ((0,0)--(0,-2)) shifted (flow_zfactor*z*flow_xysx[x][y],0), "bottom")
+ shifted(0,-flow_trimmed(x,y,flow_grid_height,t))
+enddef ;
+
+vardef flow_xy_top (expr x, y, z, t) =
+ flow_i_point (x, y, ((0,0)--(0,2)) shifted (flow_zfactor*z*flow_xysx[x][y],0), "top")
+ shifted(0,flow_trimmed(x,y,flow_grid_height,t))
+enddef ;
+
+vardef flow_xy_left (expr x, y, z, t) =
+ flow_i_point (x, y, ((0,0)--(-2,0)) shifted (0,flow_zfactor*z*flow_xysy[x][y]), "left")
+ shifted(-flow_trimmed(x,y,flow_grid_width,t),0)
+enddef ;
+
+vardef flow_xy_right (expr x, y, z, t) =
+ flow_i_point (x, y, ((0,0)--(2,0)) shifted (0,flow_zfactor*z*flow_xysy[x][y]), "right")
+ shifted(flow_trimmed(x,y,flow_grid_width,t),0)
+enddef ;
+
+def flow_flush_shapes =
+ for x=1 upto flow_max_x :
+ for y=1 upto flow_max_y :
+ flow_flush_shape(x, y) ;
+ endfor ;
+ endfor ;
+enddef ;
+
+def flow_flush_pictures =
+ for x=1 upto flow_max_x :
+ for y=1 upto flow_max_y :
+ flow_flush_picture(x, y) ;
+ endfor ;
+ endfor ;
+enddef ;
+
+def flow_draw_connection_point(expr x, y, z) =
+ pickup pencircle scaled if (z=0): 2 fi flow_xyline[x][y] ;
+ drawdot flow_xy_bottom(x,y,z,false) flow_scaled_to_grid withcolor (1,0,0) ;
+ drawdot flow_xy_top (x,y,z,false) flow_scaled_to_grid withcolor (0,1,0) ;
+ drawdot flow_xy_left (x,y,z,false) flow_scaled_to_grid withcolor (0,0,1) ;
+ drawdot flow_xy_right (x,y,z,false) flow_scaled_to_grid withcolor (1,1,0) ;
+enddef ;
+
+def flow_flush_shape(expr x, yy) =
+ begingroup ;
+ save y ; numeric y ;
+ y := flow_y_pos(yy) ;
+ if not flow_xyfree[x][y] :
+ pickup pencircle scaled flow_xyline[x][y] ;
+ if flow_xypeep[x][y] :
+ fill (flow_xypath[x][y] peepholed (unitsquare shifted (x,y)))
+ flow_scaled_to_grid withpen pencircle scaled 0
+ withcolor flow_chart_background_color ;
+ else :
+ fill flow_xypath[x][y] flow_scaled_to_grid withcolor flow_xyfill[x][y] ;
+ fi ;
+ draw flow_xypath[x][y] flow_scaled_to_grid withcolor flow_xydraw[x][y] ;
+ if flow_show_con_points or flow_show_all_points :
+ flow_draw_connection_point(x, y, 0) ;
+ fi ;
+ if flow_show_all_points :
+ for i=-1 upto 1 :
+ flow_draw_connection_point(x, y, i) ;
+ endfor ;
+ fi ;
+ fi ;
+ endgroup ;
+enddef ;
+
+vardef flow_points_initialized(expr xfrom, yfrom, xto, yto, n) =
+ if unknown flow_xyfree[xfrom][yfrom] or unknown flow_xyfree[xto][yto] :
+ flow_xypoint := 0 ; false
+ elseif not flow_xyfree[xfrom][yfrom] and not flow_xyfree[xto][yto] :
+ flow_xypoint := n ; true
+ else :
+ flow_xypoint := 0 ; false
+ fi
+enddef ;
+
+def flow_collapse_points = % this can become a core macro
+ begingroup ;
+ % remove redundant points
+ save n ; numeric n ;
+ n := 1 ;
+ for i=2 upto flow_xypoint :
+ if not (flow_xypoints[i] = flow_xypoints[n]) :
+ n := n + 1 ;
+ flow_xypoints[n] := flow_xypoints[i]
+ fi ;
+ endfor ;
+ flow_xypoint := n ;
+ % make straight lines
+ if flow_xypoints[2] = flow_xypoints[flow_xypoint-1] :
+ flow_xypoints[3] := flow_xypoints[flow_xypoint] ;
+ flow_xypoint := 3 ;
+ fi ;
+ endgroup ;
+enddef ;
+
+vardef flow_smooth_connection(expr a,b) =
+ if ypart a = ypart b :
+ a shifted ( if xpart a >= xpart b : - fi (flow_connection_smooth_size/flow_grid_width ),0)
+ else :
+ a shifted (0,if ypart a >= ypart b : - fi (flow_connection_smooth_size/flow_grid_height) )
+ fi
+enddef ;
+
+vardef flow_trim_points =
+ begingroup
+ save p, a, b, d, i ; numeric a, b ; path p ; pair d ;
+ p := for i=1 upto flow_xypoint-1 : flow_xypoints[i]-- endfor flow_xypoints[flow_xypoint] ;
+ if flow_touchshape :
+ a := flow_shape_line_width/flow_grid_width ;
+ b := flow_shape_line_width/flow_grid_height ;
+ else :
+ a := epsilon ;
+ b := epsilon ;
+ fi ;
+ d := direction infinity of p ;
+ flow_xypoints[flow_xypoint] := flow_xypoints[flow_xypoint] shifted
+ if xpart d < 0 : (+a,0) ;
+ elseif xpart d > 0 : (-a,0) ;
+ elseif ypart d < 0 : (0,+b) ;
+ elseif ypart d > 0 : (0,-b) ;
+ else : origin ;
+ fi ;
+ d := direction 0 of p ;
+ flow_xypoints[1] := flow_xypoints[1] shifted
+ if xpart d < 0 : (-a,0) ;
+ elseif xpart d > 0 : (+a,0) ;
+ elseif ypart d < 0 : (0,-b) ;
+ elseif ypart d > 0 : (0,+b) ;
+ else : origin ;
+ fi ;
+ endgroup
+enddef ;
+
+vardef flow_trim_points = enddef ;
+
+vardef flow_connection_path =
+ if flow_reverse_connection : reverse fi (flow_xypoints[1] --
+ for i=2 upto flow_xypoint-1 :
+ if flow_smooth :
+ flow_smooth_connection(flow_xypoints[i],flow_xypoints[i-1]) ..
+ controls flow_xypoints[i] and flow_xypoints[i] ..
+ flow_smooth_connection(flow_xypoints[i],flow_xypoints[i+1]) --
+ else :
+ flow_xypoints[i] --
+ fi
+ endfor
+ flow_xypoints[flow_xypoint])
+enddef ;
+
+def flow_draw_connection(expr i,xfrom,yfrom,xto,yto) = % 'i' is a comment reference
+ if flow_xypoint > 0 :
+ flow_collapse_points ;
+ flow_trim_points ;
+ flow_cpath := flow_cpath + 1 ; % maybe also store as x,y
+ flow_cpaths[flow_cpath] := flow_connection_path flow_scaled_to_grid ;
+ flow_cline[flow_cpath] := flow_connection_line_width ;
+ flow_ccolor[flow_cpath] := flow_connection_line_color ;
+ flow_carrow[flow_cpath] := flow_arrowtip ;
+ flow_cdash[flow_cpath] := flow_dashline ;
+ flow_ccross[flow_cpath] := flow_showcrossing ;
+ if flow_reverse_connection :
+ flow_connections[xto] [yto] [i] := flow_cpaths[flow_cpath] ;
+ else :
+ flow_connections[xfrom][yfrom][i] := flow_cpaths[flow_cpath] ;
+ fi ;
+ else :
+ message("no connection defined") ;
+ fi ;
+ flow_reverse_connection := false ;
+enddef ;
+
+def flow_flush_connections = % protect locals
+ begingroup ;
+ save ip, crossing, cp ; numeric ip ; boolean crossing ; path cp ;
+ ahlength := flow_connection_arrow_size ;
+ flow_dash_pattern := dashpattern(on flow_connection_dash_size off flow_connection_dash_size) ;
+ for i=1 upto flow_cpath :
+ if flow_ccross[i] :
+ crossing := false ;
+ for j=1 upto i :
+ if not (point infinity of flow_cpaths[i] = point infinity of flow_cpaths[j]) :
+ ip := flow_cpaths[i] intersection_point flow_cpaths[j] ;
+ if intersection_found : crossing := true fi ;
+ fi ;
+ endfor ;
+ if crossing :
+ pickup pencircle scaled 2flow_cline[i] ;
+ cp := flow_cpaths[i] ;
+ cp := cp cutbefore point .05 length cp of cp ;
+ cp := cp cutafter point .95 length cp of cp ;
+ draw cp withcolor flow_chart_background_color ;
+ fi ;
+ fi ;
+ pickup pencircle scaled flow_cline[i] ;
+ if flow_carrow[i] :
+ if flow_cdash[i] :
+ drawarrow flow_cpaths[i] withcolor flow_ccolor[i] dashed flow_dash_pattern ;
+ else :
+ drawarrow flow_cpaths[i] withcolor flow_ccolor[i] ;
+ fi ;
+ else :
+ if flow_cdash[i] :
+ draw flow_cpaths[i] withcolor flow_ccolor[i] dashed flow_dash_pattern ;
+ else :
+ draw flow_cpaths[i] withcolor flow_ccolor[i] ;
+ fi ;
+ fi ;
+ flow_draw_midpoint(i) ;
+ endfor ;
+ endgroup ;
+enddef ;
+
+def flow_draw_midpoint (expr n) =
+ begingroup
+ save p ; pair p ;
+ p := point .5*length(flow_cpaths[n]) of flow_cpaths[n];
+ pickup pencircle scaled 2flow_cline[n] ;
+ if flow_show_mid_points :
+ drawdot p withcolor .7white ;
+ fi ;
+ endgroup ;
+enddef ;
+
+def flow_flush_picture(expr x, yy) =
+ begingroup ;
+ save y ; numeric y ;
+ y := flow_y_pos(yy) ; % maybe move this to the makers
+ if known flow_xytext[x][y] :
+ draw flow_xytext[x][y] ;
+ fi ;
+ if known flow_xylabel[x][y] :
+ draw flow_xylabel[x][y] ;
+ fi ;
+ if known flow_xyexit[x][y] :
+ draw flow_xyexit[x][y] ;
+ fi ;
+ if known flow_xycomment[x][y] :
+ draw flow_xycomment[x][y] ;
+ fi ;
+ endgroup ;
+enddef ;
+
+vardef flow_offset(expr x, y) =
+ flow_xy_offset((x+0.5)*flow_grid_width,(flow_max_y-y+1.5)*flow_grid_height)
+ shifted (-flow_xyline[x][y]/4,-flow_xyline[x][y]/4) % terrible hack (some compensation)
+enddef ;
+
+def flow_chart_draw_text(expr x, y, p) =
+ if known flow_xytext[x][y] :
+ addto flow_xytext[x][y] also
+ else :
+ flow_xytext[x][y] :=
+ fi
+ p shifted flow_offset(x,y) ;
+enddef ;
+
+def flow_chart_draw_label (expr x, y, loc, txt) =
+ begingroup ;
+ save p, s ; path p ; picture s ;
+ p := fullsquare xscaled flow_grid_width yscaled flow_grid_height ;
+ p := p shifted flow_offset(x,y) ;
+ s := txt ;
+ setbounds s to boundingbox s enlarged flow_label_offset ;
+ if known flow_xylabel[x][y] :
+ addto flow_xylabel[x][y] also
+ else :
+ flow_xylabel[x][y] :=
+ fi
+ if loc = "tr" : anchored.llft(s,0.5[ulcorner p,urcorner p]) ;
+ elseif loc = "t" : anchored.bot (s,0.5[ulcorner p,urcorner p]) ;
+ elseif loc = "tl" : anchored.lrt (s,0.5[ulcorner p,urcorner p]) ;
+ elseif loc = "br" : anchored.ulft(s,0.5[llcorner p,lrcorner p]) ;
+ elseif loc = "b" : anchored.top (s,0.5[llcorner p,lrcorner p]) ;
+ elseif loc = "bl" : anchored.urt (s,0.5[llcorner p,lrcorner p]) ;
+ elseif loc = "lb" : anchored.urt (s,0.5[ulcorner p,llcorner p]) ;
+ elseif loc = "l" : anchored.rt (s,0.5[ulcorner p,llcorner p]) ;
+ elseif loc = "lt" : anchored.lrt (s,0.5[ulcorner p,llcorner p]) ;
+ elseif loc = "rb" : anchored.ulft(s,0.5[urcorner p,lrcorner p]) ;
+ elseif loc = "r" : anchored.lft (s,0.5[urcorner p,lrcorner p]) ;
+ elseif loc = "rt" : anchored.llft(s,0.5[urcorner p,lrcorner p]) ;
+ else : anchored (s,center p) ;
+ fi ;
+ endgroup ;
+enddef ;
+
+def flow_chart_draw_exit (expr x, y, loc, txt) =
+ begingroup ;
+ save p, s ; path p ; picture s ;
+ p := fullsquare xscaled flow_grid_width yscaled flow_grid_height ;
+ p := p shifted flow_offset(x,y) ;
+ s := txt ;
+ setbounds s to boundingbox s enlarged flow_exit_offset ;
+ if known flow_xyexit[x][y] :
+ addto flow_xyexit[x][y] also
+ else :
+ flow_xyexit[x][y] :=
+ fi
+ if loc = "t" : anchored.top(s,0.5[ulcorner p,urcorner p]) ;
+ elseif loc = "b" : anchored.bot(s,0.5[llcorner p,lrcorner p]) ;
+ elseif loc = "l" : anchored.lft(s,0.5[ulcorner p,llcorner p]) ;
+ elseif loc = "r" : anchored.rt (s,0.5[urcorner p,lrcorner p]) ;
+ else : anchored (s,center p) ;
+ fi ;
+ endgroup ;
+enddef ;
+
+def flow_chart_draw_comment (expr x, y, i, loc, len, txt) = % per connection
+ begingroup ;
+ if known flow_connections[x][y][i] :
+ save p, q, s ; path p, q ; picture s ;
+ p := fullsquare xscaled flow_shape_width yscaled flow_shape_height ;
+ p := p shifted flow_offset(x,y) ;
+ q := flow_connections[x][y][i] ; % already relocated
+ s := txt ;
+ setbounds s to boundingbox s enlarged flow_comment_offset ;
+ if known flow_xycomment[x][y] :
+ addto flow_xycomment[x][y] also
+ else :
+ flow_xycomment[x][y] :=
+ fi
+ if loc = "tr" : anchored.llft(s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
+ elseif loc = "t" : anchored.bot (s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
+ elseif loc = "tl" : anchored.lrt (s,if len = 0 : 0.5[ulcorner p,urcorner p] else : point len along q fi) ;
+ elseif loc = "br" : anchored.ulft(s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
+ elseif loc = "b" : anchored.top (s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
+ elseif loc = "bl" : anchored.urt (s,if len = 0 : 0.5[llcorner p,lrcorner p] else : point len along q fi) ;
+ elseif loc = "lb" : anchored.urt (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
+ elseif loc = "l" : anchored.rt (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
+ elseif loc = "lt" : anchored.lrt (s,if len = 0 : 0.5[ulcorner p,llcorner p] else : point len along q fi) ;
+ elseif loc = "rb" : anchored.ulft(s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
+ elseif loc = "r" : anchored.lft (s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
+ elseif loc = "rt" : anchored.llft(s,if len = 0 : 0.5[urcorner p,lrcorner p] else : point len along q fi) ;
+ elseif loc = "tr:*" : anchored.llft(s,point 0 of q) ;
+ elseif loc = "t:*" : anchored.bot (s,point 0 of q) ;
+ elseif loc = "tl:*" : anchored.lrt (s,point 0 of q) ;
+ elseif loc = "br:*" : anchored.ulft(s,point 0 of q) ;
+ elseif loc = "b:*" : anchored.top (s,point 0 of q) ;
+ elseif loc = "bl:*" : anchored.urt (s,point 0 of q) ;
+ elseif loc = "lb:*" : anchored.urt (s,point 0 of q) ;
+ elseif loc = "l:*" : anchored.rt (s,point 0 of q) ;
+ elseif loc = "lt:*" : anchored.lrt (s,point 0 of q) ;
+ elseif loc = "rb:*" : anchored.ulft(s,point 0 of q) ;
+ elseif loc = "r:*" : anchored.lft (s,point 0 of q) ;
+ elseif loc = "rt:*" : anchored.llft(s,point 0 of q) ;
+ else : anchored (s,point 0 of q) ;
+ fi ;
+ fi ;
+ endgroup ;
+enddef ;
+
+boolean flow_reverse_connection ; flow_reverse_connection := false ;
+
+vardef flow_up_on_grid (expr n) =
+ (xpart flow_xypoints[n],(ypart flow_xypoints[n]+1) div 1)
+enddef ;
+
+vardef flow_down_on_grid (expr n) =
+ (xpart flow_xypoints[n],(ypart flow_xypoints[n]) div 1)
+enddef ;
+
+vardef flow_left_on_grid (expr n) =
+ ((xpart flow_xypoints[n]) div 1, ypart flow_xypoints[n])
+enddef ;
+
+vardef flow_right_on_grid (expr n) =
+ ((xpart flow_xypoints[n]+1) div 1, ypart flow_xypoints[n])
+enddef ;
+
+vardef flow_x_on_grid (expr n, xfrom, xto, zfrom) =
+ if (xfrom = xto) and not (zfrom = 0) :
+ if (zfrom=1) : flow_right_on_grid(2) else : flow_left_on_grid(2) fi
+ elseif xpart flow_xypoints[1] < xpart flow_xypoints[6] :
+ flow_right_on_grid(n)
+ else :
+ flow_left_on_grid(n)
+ fi
+enddef ;
+
+vardef flow_y_on_grid (expr n, yfrom, yto, zfrom) =
+ if (yfrom = yto) and not (zfrom = 0) :
+ if (zfrom = 1) : flow_up_on_grid(2) else : flow_down_on_grid(2) fi
+ elseif ypart flow_xypoints[1] < ypart flow_xypoints[6] :
+ flow_up_on_grid(n)
+ else :
+ flow_down_on_grid(n)
+ fi
+enddef ;
+
+vardef flow_xy_on_grid (expr n, m) =
+ (xpart flow_xypoints[n], ypart flow_xypoints[m])
+enddef ;
+
+vardef flow_down_to_grid (expr a,b) =
+ (xpart flow_xypoints[a], ypart flow_xypoints[if ypart flow_xypoints[a]<ypart flow_xypoints[b] : a else : b fi])
+enddef ;
+
+vardef flow_up_to_grid (expr a,b) =
+ (xpart flow_xypoints[a], ypart flow_xypoints[if ypart flow_xypoints[a]>ypart flow_xypoints[b] : a else : b fi])
+enddef ;
+
+vardef flow_left_to_grid (expr a,b) =
+ (xpart flow_xypoints[if xpart flow_xypoints[a]<xpart flow_xypoints[b] : a else : b fi], ypart flow_xypoints[a])
+enddef ;
+
+vardef flow_right_to_grid (expr a,b) =
+ (xpart flow_xypoints[if xpart flow_xypoints[a]>xpart flow_xypoints[b] : a else : b fi], ypart flow_xypoints[a])
+enddef ;
+
+vardef flow_valid_connection (expr xfrom, yfrom, xto, yto) =
+ begingroup ;
+ save ok, vc, pp ; boolean ok ; pair vc ; path pp ;
+ save flow_xyfirst, flow_xylast ; pair flow_xyfirst, flow_xylast ;
+ % check for slanted lines
+ ok := true ;
+ for i=1 upto flow_xypoint-1 :
+ if not ((xpart flow_xypoints[i]=xpart flow_xypoints[i+1]) or (ypart flow_xypoints[i]=ypart flow_xypoints[i+1])) :
+ ok := false ;
+ fi ;
+ endfor ;
+ if not ok :
+ % message("slanted");
+ false
+ elseif flow_forcevalid :
+ % message("force");
+ true
+ elseif (xfrom=xto) and (yfrom=yto) :
+ % message("self");
+ false
+ else :
+ % check for crossing shapes
+ flow_xyfirst := flow_xypoints[1] ;
+ flow_xylast := flow_xypoints[flow_xypoint] ;
+ flow_trim_points ;
+ pp := for i=1 upto flow_xypoint-1 : flow_xypoints[i]-- endfor flow_xypoints[flow_xypoint] ;
+ flow_xypoints[1] := flow_xyfirst ;
+ flow_xypoints[flow_xypoint] := flow_xylast ;
+ for i=1 upto flow_max_x :
+ for j=1 upto flow_max_y : % was bug: xfrom,yto
+ if not ( ( (i,j)=(xfrom,yfrom) ) or ( (i,j)=(xto,yto) ) ) :
+ if not flow_xyfree[i][j] :
+ vc := pp intersection_point flow_xypath[i][j] ;
+ if intersection_found :
+ ok := false
+ fi ;
+ fi ;
+ fi ;
+ endfor ;
+ endfor ;
+ % if not ok: message("crossing") ; fi ;
+ ok
+ fi
+ endgroup
+enddef ;
+
+def flow_connect_top_bottom (expr n) (expr xfrom, yyfrom, zfrom) (expr xto, yyto, zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
+ flow_xypoints[1] := flow_xy_top(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[6] := flow_xy_bottom(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_up_on_grid(1) ;
+ flow_xypoints[5] := flow_down_on_grid(6) ;
+ flow_xypoints[3] := flow_up_to_grid(2,5) ;
+ flow_xypoints[4] := flow_up_to_grid(2,5) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
+ flow_xypoints[4] := flow_xy_on_grid(3,5) ;
+ fi ;
+ %%%% begin experiment
+ flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
+ flow_xypoints[4] := flow_xypoints[4] shifted (flow_dsp_x,0) ;
+ if flow_dsp_y>0 :
+ flow_xypoints[2] := flow_xypoints[2] shifted (0,flow_dsp_y) ;
+ flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
+ elseif flow_dsp_y<0 :
+ flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
+ flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
+ fi
+ %%%% end experiment
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_left_right (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
+ flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[6] := flow_xy_right(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_left_on_grid(1) ;
+ flow_xypoints[5] := flow_right_on_grid(6) ;
+ flow_xypoints[3] := flow_left_to_grid(2,5) ;
+ flow_xypoints[4] := flow_left_to_grid(2,5) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
+ flow_xypoints[4] := flow_xy_on_grid(5,3) ;
+ fi ;
+ %%%% begin experiment
+ if flow_dsp_y <> 0 :
+ flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
+ flow_xypoints[4] := flow_xypoints[4] shifted (0,-flow_dsp_y) ;
+ fi ;
+ %%%% end experiment
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_left_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
+ flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[5] := flow_xy_top(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_left_on_grid(1) ;
+ flow_xypoints[4] := flow_up_on_grid(5) ;
+ flow_xypoints[3] := flow_left_to_grid(2,5) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_xy_on_grid(2,4) ;
+ fi ;
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_left_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
+ flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[5] := flow_xy_bottom(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_left_on_grid(1) ;
+ flow_xypoints[4] := flow_down_on_grid(5) ;
+ flow_xypoints[3] := flow_left_to_grid(2,5) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_xy_on_grid(2,4) ;
+ fi ;
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_right_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
+ flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[5] := flow_xy_top(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_right_on_grid(1) ;
+ flow_xypoints[4] := flow_up_on_grid(5) ;
+ flow_xypoints[3] := flow_right_to_grid(2,5) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_xy_on_grid(2,4) ;
+ fi ;
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_right_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,5) :
+ flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[5] := flow_xy_bottom(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_right_on_grid(1) ;
+ flow_xypoints[4] := flow_down_on_grid(5) ;
+ flow_xypoints[3] := flow_right_to_grid(2,5) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_xy_on_grid(2,4) ;
+ fi ;
+ %%%% begin experiment
+ flow_xypoints[2] := flow_xypoints[2] shifted (flow_dsp_x,0) ;
+ flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
+ if flow_dsp_y>0 :
+ flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
+ flow_xypoints[4] := flow_xypoints[4] shifted (0,-flow_dsp_y) ;
+ elseif flow_dsp_y<0 :
+ flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
+ flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
+ fi
+ %%%% end experiment
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_left_left (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
+ flow_xypoints[1] := flow_xy_left(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[6] := flow_xy_left(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_left_on_grid(1) ;
+ flow_xypoints[5] := flow_left_on_grid(6) ;
+ flow_xypoints[3] := flow_left_to_grid(2,5) ;
+ flow_xypoints[4] := flow_left_to_grid(5,2) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
+ flow_xypoints[4] := flow_xy_on_grid(5,3) ;
+ fi ;
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_right_right (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
+ flow_xypoints[1] := flow_xy_right(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[6] := flow_xy_right(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_right_on_grid(1) ;
+ flow_xypoints[5] := flow_right_on_grid(6) ;
+ flow_xypoints[3] := flow_right_to_grid(2,5) ;
+ flow_xypoints[4] := flow_right_to_grid(5,2) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_y_on_grid(2,yfrom,yto,zfrom) ;
+ flow_xypoints[4] := flow_xy_on_grid(5,3) ;
+ fi ;
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_top_top (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
+ flow_xypoints[1] := flow_xy_top(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[6] := flow_xy_top(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_up_on_grid(1) ;
+ flow_xypoints[5] := flow_up_on_grid(6) ;
+ flow_xypoints[3] := flow_up_to_grid(2,5) ;
+ flow_xypoints[4] := flow_up_to_grid(5,2) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
+ flow_xypoints[4] := flow_xy_on_grid(3,5) ;
+ fi ;
+ %%%% begin experiment (todo: not value but just + and )
+ if flow_dsp_y <> 0 :
+ flow_xypoints[2] := flow_xypoints[2] shifted (0,flow_dsp_y) ;
+ flow_xypoints[3] := flow_xypoints[3] shifted (0,flow_dsp_y) ;
+ flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
+ flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
+ fi ;
+ %%%% end experiment
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_bottom_bottom (expr n) (expr xfrom,yyfrom,zfrom) (expr xto,yyto,zto) =
+ yfrom := flow_y_pos(yyfrom) ;
+ yto := flow_y_pos(yyto) ;
+ if flow_points_initialized(xfrom,yfrom,xto,yto,6) :
+ flow_xypoints[1] := flow_xy_bottom(xfrom,yfrom,zfrom,true) ;
+ flow_xypoints[6] := flow_xy_bottom(xto,yto,zto,true) ;
+ flow_xypoints[2] := flow_down_on_grid(1) ;
+ flow_xypoints[5] := flow_down_on_grid(6) ;
+ flow_xypoints[3] := flow_down_to_grid(2,5) ;
+ flow_xypoints[4] := flow_down_to_grid(5,2) ;
+ if not flow_valid_connection(xfrom,yfrom,xto,yto) :
+ flow_xypoints[3] := flow_x_on_grid(2,xfrom,xto,zfrom) ;
+ flow_xypoints[4] := flow_xy_on_grid(3,5) ;
+ fi ;
+ %%%% begin experiment
+ flow_xypoints[3] := flow_xypoints[3] shifted (flow_dsp_x,0) ;
+ flow_xypoints[4] := flow_xypoints[4] shifted (flow_dsp_x,0) ;
+ if flow_dsp_y<0 :
+ flow_xypoints[2] := flow_xypoints[2] shifted (0,-flow_dsp_y) ;
+ flow_xypoints[3] := flow_xypoints[3] shifted (0,-flow_dsp_y) ;
+ elseif flow_dsp_y>0 :
+ flow_xypoints[4] := flow_xypoints[4] shifted (0,flow_dsp_y) ;
+ flow_xypoints[5] := flow_xypoints[5] shifted (0,flow_dsp_y) ;
+ fi
+ %%%% end experiment
+ flow_draw_connection(n,xfrom,yyfrom,xto,yyto) ;
+ fi ;
+enddef ;
+
+def flow_connect_bottom_top (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
+ flow_reverse_connection := true ;
+ flow_connect_top_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
+enddef ;
+
+def flow_connect_right_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
+ flow_reverse_connection := true ;
+ flow_connect_left_right (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
+enddef ;
+
+def flow_connect_top_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
+ flow_reverse_connection := true ;
+ flow_connect_left_top (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
+enddef ;
+
+def flow_connect_bottom_left (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
+ flow_reverse_connection := true ;
+ flow_connect_left_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
+enddef ;
+
+def flow_connect_top_right (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
+ flow_reverse_connection := true ;
+ flow_connect_right_top (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
+enddef ;
+
+def flow_connect_bottom_right (expr n) (expr xfrom,yfrom,zfrom) (expr xto,yto,zto) =
+ flow_reverse_connection := true ;
+ flow_connect_right_bottom (n) (xto,yto,zto) (xfrom,yfrom,zfrom) ;
+enddef ;
+
+def flow_draw_test_shape(expr x, y) =
+ flow_draw_shape(x,y,fullcircle, .7, .7) ;
+enddef ;
+
+def flow_draw_test_shapes =
+ for i=1 upto flow_max_x :
+ for j=1 upto flow_max_y :
+ flow_draw_test_shape(i,j) ;
+ endfor ;
+ endfor ;
+enddef;
+
+def flow_draw_test_area =
+ pickup pencircle scaled .5flow_shape_line_width ;
+ draw (unitsquare xscaled flow_max_x yscaled flow_max_y shifted (1,1)) flow_scaled_to_grid withcolor blue ;
+enddef ;
+
+def flow_show_connection(expr n, m) =
+
+ flow_begin_chart(100+n,6,6) ;
+
+ flow_draw_test_area ;
+
+ flow_smooth := true ;
+ flow_arrowtip := true ;
+ flow_dashline := true ;
+
+ flow_draw_test_shape(2,2) ; flow_draw_test_shape(4,5) ;
+ flow_draw_test_shape(3,3) ; flow_draw_test_shape(5,1) ;
+ flow_draw_test_shape(2,5) ; flow_draw_test_shape(1,3) ;
+ flow_draw_test_shape(6,2) ; flow_draw_test_shape(4,6) ;
+
+ if (m=1) :
+ flow_connect_top_bottom (0) (2,2,0) (4,5,0) ;
+ flow_connect_top_bottom (0) (3,3,0) (5,1,0) ;
+ flow_connect_top_bottom (0) (2,5,0) (1,3,0) ;
+ flow_connect_top_bottom (0) (6,2,0) (4,6,0) ;
+ elseif (m=2) :
+ flow_connect_top_top (0) (2,2,0) (4,5,0) ;
+ flow_connect_top_top (0) (3,3,0) (5,1,0) ;
+ flow_connect_top_top (0) (2,5,0) (1,3,0) ;
+ flow_connect_top_top (0) (6,2,0) (4,6,0) ;
+ elseif (m=3) :
+ flow_connect_bottom_bottom (0) (2,2,0) (4,5,0) ;
+ flow_connect_bottom_bottom (0) (3,3,0) (5,1,0) ;
+ flow_connect_bottom_bottom (0) (2,5,0) (1,3,0) ;
+ flow_connect_bottom_bottom (0) (6,2,0) (4,6,0) ;
+ elseif (m=4) :
+ flow_connect_left_right (0) (2,2,0) (4,5,0) ;
+ flow_connect_left_right (0) (3,3,0) (5,1,0) ;
+ flow_connect_left_right (0) (2,5,0) (1,3,0) ;
+ flow_connect_left_right (0) (6,2,0) (4,6,0) ;
+ elseif (m=5) :
+ flow_connect_left_left (0) (2,2,0) (4,5,0) ;
+ flow_connect_left_left (0) (3,3,0) (5,1,0) ;
+ flow_connect_left_left (0) (2,5,0) (1,3,0) ;
+ flow_connect_left_left (0) (6,2,0) (4,6,0) ;
+ elseif (m=6) :
+ flow_connect_right_right (0) (2,2,0) (4,5,0) ;
+ flow_connect_right_right (0) (3,3,0) (5,1,0) ;
+ flow_connect_right_right (0) (2,5,0) (1,3,0) ;
+ flow_connect_right_right (0) (6,2,0) (4,6,0) ;
+ elseif (m=7) :
+ flow_connect_left_top (0) (2,2,0) (4,5,0) ;
+ flow_connect_left_top (0) (3,3,0) (5,1,0) ;
+ flow_connect_left_top (0) (2,5,0) (1,3,0) ;
+ flow_connect_left_top (0) (6,2,0) (4,6,0) ;
+ elseif (m=8) :
+ flow_connect_left_bottom (0) (2,2,0) (4,5,0) ;
+ flow_connect_left_bottom (0) (3,3,0) (5,1,0) ;
+ flow_connect_left_bottom (0) (2,5,0) (1,3,0) ;
+ flow_connect_left_bottom (0) (6,2,0) (4,6,0) ;
+ elseif (m=9) :
+ flow_connect_right_top (0) (2,2,0) (4,5,0) ;
+ flow_connect_right_top (0) (3,3,0) (5,1,0) ;
+ flow_connect_right_top (0) (2,5,0) (1,3,0) ;
+ flow_connect_right_top (0) (6,2,0) (4,6,0) ;
+ else :
+ flow_connect_right_bottom (0) (2,2,0) (4,5,0) ;
+ flow_connect_right_bottom (0) (3,3,0) (5,1,0) ;
+ flow_connect_right_bottom (0) (2,5,0) (1,3,0) ;
+ flow_connect_right_bottom (0) (6,2,0) (4,6,0) ;
+ fi ;
+
+ flow_end_chart ;
+
+enddef ;
+
+def flow_show_connections =
+ for f=1 upto 10 :
+ flow_show_connection(f,f) ;
+ endfor ;
+enddef ;
+
+%D charts
+
+def flow_clip_chart(expr minx, miny, maxx, maxy) =
+ flow_cmin_x := minx ;
+ flow_cmax_x := maxx ;
+ flow_cmin_y := miny ;
+ flow_cmax_y := maxy ;
+enddef ;
+
+def flow_begin_chart(expr n, maxx, maxy) =
+ flow_new_chart ;
+ flow_chart_figure := n ;
+ flow_chart_scale := 1 ;
+ if flow_chart_figure>0:
+ beginfig(flow_chart_figure) ;
+ fi ;
+ flow_initialize_grid (maxx, maxy) ;
+ bboxmargin := 0 ;
+ flow_cmin_x := 1 ;
+ flow_cmax_x := maxx ;
+ flow_cmin_y := 1 ;
+ flow_cmax_y := maxy ;
+enddef ;
+
+def flow_end_chart =
+ begingroup ;
+ save p ; path p ;
+ flow_flush_shapes ;
+ flow_flush_connections ;
+ flow_flush_pictures ;
+ flow_cmin_x := flow_cmin_x ;
+ flow_cmax_x := flow_cmin_x+flow_cmax_x ;
+ flow_cmin_y := flow_cmin_y-1 ;
+ flow_cmax_y := flow_cmin_y+flow_cmax_y ;
+ if flow_reverse_y :
+ flow_cmin_y := flow_y_pos(flow_cmin_y) ;
+ flow_cmax_y := flow_y_pos(flow_cmax_y) ;
+ fi ;
+ p := (((flow_cmin_x,flow_cmin_y)--(flow_cmax_x,flow_cmin_y)--
+ (flow_cmax_x,flow_cmax_y)--(flow_cmin_x,flow_cmax_y)--cycle))
+ flow_scaled_to_grid ;
+ %draw p withcolor red ;
+ p := p enlarged flow_chart_offset ;
+ clip currentpicture to p ;
+ setbounds currentpicture to p ;
+ endgroup ;
+ currentpicture := currentpicture scaled flow_chart_scale ;
+ if flow_chart_figure>0:
+ endfig ;
+ fi ;
+enddef ;
+
+def flow_new_shape(expr x, y, n) =
+ if known n :
+ if (x>0) and (x<=flow_max_x) and (y>0) and (y<=flow_max_y) :
+ flow_draw_shape(x,y,some_shape_path(n), flow_shape_width/flow_grid_width, flow_shape_height/flow_grid_height) ;
+ else :
+ message ("shape outside grid ignored") ;
+ fi ;
+ else :
+ message ("shape not known" ) ;
+ fi ;
+enddef ;
+
+def flow_begin_sub_chart =
+ begingroup ;
+ save flow_shape_line_width, flow_connection_line_width ;
+ save flow_shape_line_color, flow_shape_fill_color, flow_connection_line_color ;
+ color flow_shape_line_color, flow_shape_fill_color, flow_connection_line_color ;
+ save flow_smooth, flow_arrowtip, flow_dashline, flow_peepshape ;
+ boolean flow_smooth, flow_arrowtip, flow_dashline, flow_peepshape ;
+enddef ;
+
+def flow_end_sub_chart =
+ endgroup ;
+enddef ;
+
diff --git a/metapost/context/base/mpiv/mp-chem.mpiv b/metapost/context/base/mpiv/mp-chem.mpiv
new file mode 100644
index 000000000..b861d3f12
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-chem.mpiv
@@ -0,0 +1,1731 @@
+%D \module
+%D [ file=mp-chem.mpiv,
+%D version=2009.05.13,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=chemicals,
+%D author=Hans Hagen \& Alan Braslau,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+%D This module is incomplete and experimental. Okay, it's not that bad but we do need
+%D some disclaimer.
+
+% either consistent setting or not
+
+if known context_chem : endinput ; fi ;
+
+boolean context_chem ; context_chem := true ;
+
+numeric
+ chem_num[], % scratch
+ chem_text_min, chem_text_max,
+ chem_rotation, chem_adjacent, chem_stack_n,
+ chem_substituent, chem_substituent.lft, chem_substituent.rt,
+ chem_setting_offset, chem_text_offset,
+ chem_center_offset, chem_dbl_offset,
+ chem_bb_angle, chem_axis_rulethickness,
+ chem_setting_l, chem_setting_r, chem_setting_t, chem_setting_b,
+ chem_setting_rotation, chem_emwidth, chem_b_length,
+ chem_front_b[] ;
+
+boolean
+ chem_setting_axis,
+ chem_doing_pb, chem_bd_wedge,
+ chem_star[], chem_front[], chem_stacked[], chem_tetra[] ;
+
+string
+ chem_previous ;
+
+path
+ chem_path[], % scratch
+ chem_b_path[], chem_c_path[],
+ chem_r_path[], chem_r_path.lft[], chem_r_path.rt[] ;
+
+pair
+ chem_origin, chem_mirror,
+ chem_pair[], % scratch
+ chem_sb_pair, chem_sb_pair.m, chem_sb_pair.p, chem_sb_pair.b ;
+
+picture
+ chem_pic, % scratch
+ % The use of dashpattern is found to dot the starting point with chem_sb_dash.m...
+ %chem_sb_dash, chem_sb_dash.m, chem_sb_dash.p, chem_sb_dash.b,
+ chem_axis_color ;
+
+transform
+ chem_t ; % scratch
+
+color lightblue ; lightblue := (173/255,216/255,230/255) ;
+
+% debugging
+
+boolean chem_trace_nesting ; chem_trace_nesting := false ;
+boolean chem_trace_text ; chem_trace_text := false ;
+boolean chem_trace_boundingbox ; chem_trace_boundingbox := false ;
+
+chem_axis_color := image(draw origin withcolor lightblue) ;
+chem_setting_axis := false ;
+chem_axis_rulethickness := 1pt ;
+chem_emwidth := 10pt ; % EmWidth or \the\emwidth does not work...
+chem_b_length := 3 chem_emwidth ;
+chem_text_offset := -.3chem_emwidth ; % -.71chem_emwidth ; % 1/sqrt(2)
+chem_center_offset := .5chem_emwidth ;
+chem_dbl_offset := .05 ;
+chem_bb_angle := angle(1,2chem_dbl_offset) ;
+chem_text_min := 0.75 ;
+chem_text_max := 1.25 ;
+chem_dot_factor := 2 ; % *linewidth
+chem_sb_pair := (0.25,0.75) ; %chem_sb_dash := dashpattern(off 0.25 on 0.5 off 0.25) ;
+chem_sb_pair.m := (0.25,1 ) ; %chem_sb_dash.m := dashpattern(off 0.25 on 0.75) ;
+chem_sb_pair.p := (0 ,0.75) ; %chem_sb_dash.p := dashpattern(on 0.75 off 0.25) ;
+chem_sb_pair.b := (0 ,1 ) ; %chem_sb_dash.b := dashpattern(on 1) ;
+
+chem_bd_wedge := true ; % according to IUPAC 2005
+
+def chem_reset =
+ chem_rotation := 0 ;
+ chem_mirror := origin ;
+ chem_adjacent := 0 ;
+ chem_substituent := 0 ;
+ chem_substituent.lft := 0 ;
+ chem_substituent.rt := 0 ;
+ chem_stack_n := 0 ;
+ chem_doing_pb := false ;
+ chem_origin := origin ;
+ chem_previous := "one" ;
+ pair chem_mark_pair[] ;
+enddef ;
+
+chem_reset ;
+
+newinternal numeric
+ one, carbon, alkyl, newmanstagger, newmaneclipsed,
+ three, four, five, six, seven, eight, nine,
+ fivefront, sixfront, chair, boat ;
+
+vardef chem_init_some (suffix $) (expr e) =
+ if not known chem_star[$] : chem_star[$] := false ; fi
+ if not known chem_front[$] : chem_front[$] := false ; fi
+ if not known chem_stacked[$] : chem_stacked[$] := false ; fi
+ if not known chem_tetra[$] : chem_tetra[$] := false ; fi
+
+ % We define all paths as closed, so that they may be indexed mod length.
+ if path(e) :
+ chem_b_path[$] := e if not cycle(e) : -- cycle fi ;
+ chem_num0 := length(chem_b_path[$]) ;
+ else : % polygon
+ chem_num0 := e ;
+ chem_num1 := 360/chem_num0 ;
+ chem_b_path[$] :=
+ (
+ for i=0 upto chem_num0-1 :
+ dir(if chem_star[$] : -i else : (.5-i) fi *chem_num1) --
+ endfor
+ cycle
+ )
+ if chem_front[$] :
+ rotated (chem_num1-90)
+ fi
+ if not chem_star[$] :
+ scaled (.5/(sind .5chem_num1))
+ % carbon-carbon benzene bond length
+ scaled (1.4/1.54)
+ fi ;
+ fi ;
+
+ if chem_front[$] and (not known chem_front_b[$]) :
+ chem_front_b[$] := floor(.5(length chem_b_path[$])) + 1 ;
+ fi
+
+ chem_num2 := 0 ;
+ chem_c_path[$] :=
+ reverse(fullcircle) rotated angle(point 0 of chem_b_path[$])
+ if not chem_star[$] :
+ hide (for i=0 upto chem_num0-1:
+ if abs(point i+.5 of chem_b_path[$]) <
+ abs(point chem_num2+.5 of chem_b_path[$]) :
+ chem_num2 := i ;
+ fi
+ endfor)
+ scaled (2*(abs(point chem_num2+.5 of chem_b_path[$]) - 2chem_dbl_offset))
+ fi ;
+
+ chem_r_path[$] :=
+ if chem_star[$] :
+ chem_b_path[$]
+ else :
+ (
+ for i=0 upto chem_num0-1 :
+ (unitvector point i of chem_b_path[$])
+ shifted point i of chem_b_path[$] --
+ endfor
+ cycle
+ )
+ fi ;
+
+ chem_r_path.lft[$] :=
+ (
+ for i=0 upto chem_num0-1 :
+ if chem_front[$] :
+ up
+ scaled .5
+ shifted point i of chem_b_path[$]
+ elseif chem_star[$] :
+ point i of chem_b_path[$]
+ else :
+ point i+1 of chem_b_path[$]
+ rotatedabout(point i of chem_b_path[$],180)
+ fi --
+ endfor
+ cycle
+ ) ;
+ chem_r_path.rt[$] :=
+ (
+ for i=0 upto chem_num0-1 :
+ if chem_front[$] :
+ down
+ scaled .5
+ shifted point i of chem_b_path[$]
+ elseif chem_star[$] :
+ point i+2 of chem_b_path[$]
+ else :
+ point i-1 of chem_b_path[$]
+ rotatedabout(point i of chem_b_path[$],180)
+ fi --
+ endfor
+ cycle
+ ) ;
+
+enddef ;
+
+% The following is used only once:
+def chem_init_all =
+begingroup
+ save a, b, c, d, e ; numeric a, b, c, d, e ;
+ save lft, rt ; path lft, rt ;
+
+ % tetrahedrial angle
+ a := 2angle(1,sqrt 2) ;
+
+ % solve for chair
+ 2b = 180 - .5a ;
+ 4c = 180 - .5a ;
+ d + e = 360 - 2a ;
+ d = 5e ; % this is the one tunable parameter which fixes the perspective.
+ z2 = z1 shifted dir(90+a+d) ;
+ z3 = z2 shifted dir(270-a) ;
+ z4 = z3 shifted dir(90+a) ;
+ z6 = z1 shifted dir(90+a) ;
+ z5 = z6 shifted dir(270-a) ;
+ z4 = z1 xyscaled (-1,-1) ;
+ z5 = z2 xyscaled (-1,-1) ;
+
+ save indx ; numeric indx ; indx = 2 ; % starting value doesn't matter, really.
+ % polygons
+ three := incr indx ; % 3 (these numbers don't matter - they are just indices)
+ four := incr indx ; % 4
+ five := incr indx ; % 5
+ six := incr indx ; % 6
+ seven := incr indx ; % 7
+ eight := incr indx ; % 8
+ nine := incr indx ; % 9
+
+ chem_init_some(three,3) ;
+ chem_init_some(four, 4) ;
+ chem_init_some(five, 5) ;
+ chem_init_some(six, 6) ;
+ chem_init_some(seven,7) ;
+ chem_init_some(eight,8) ;
+ chem_init_some(nine, 9) ;
+
+ % star-form
+ one := incr indx ; % 10
+ carbon := incr indx ; % 11
+ alkyl := incr indx ; % 12
+ newmanstagger := incr indx ; % 13
+ newmaneclipsed := incr indx ; % 14
+
+ chem_star[one] := true ;
+ chem_star[carbon] := true ; chem_tetra[carbon] := true ;
+ chem_star[alkyl] := true ; chem_tetra[alkyl] := true ;
+ chem_star[newmanstagger] := true ; chem_tetra[newmanstagger] := true ;
+ chem_star[newmaneclipsed] := true ; chem_tetra[newmaneclipsed] := true ;
+ chem_stacked[newmanstagger] := true ;
+ chem_stacked[newmaneclipsed] := true ;
+ chem_init_some(one, 8) ;
+ chem_init_some(carbon, dir(0)--dir(360-a)--dir(180-.5a+b)--dir(180-.5a)) ;
+ chem_init_some(alkyl, dir(0)--dir(360-a)--dir(360-a-90)--dir(90)) ;
+ chem_init_some(newmanstagger, dir(30)--dir(270)--dir(150)--dir(330)--dir(210)--dir(90)) ;
+ chem_init_some(newmaneclipsed, dir(30)--dir(270)--dir(150)--dir(0)--dir(240)--dir(120)) ;
+
+ % front views
+ fivefront := incr indx ; % 15
+ sixfront := incr indx ; % 16
+ chair := incr indx ; % 17
+ boat := incr indx ; % 18
+
+ chem_front[fivefront] := true ; chem_front_b[fivefront] := 3 ;
+ chem_front[sixfront] := true ; chem_front_b[sixfront] := 3 ;
+ chem_init_some(fivefront,5) ;
+ chem_init_some(sixfront, 6) ;
+ % chair
+ chem_front[chair] := true ; chem_front_b[chair] := 4 ;
+ chem_init_some(chair, z1--z2--z3--z4--z5--z6) ;
+ lft := dir(90-a)--down--dir(90+a+d)--down--dir(90+a)--down ;
+ rt := up--dir(270+a)--up--dir(270-a)--up--dir(90+e) ;
+ chem_r_path.lft[chair] :=
+ for i=0 upto 5 : point i of lft shifted point i of chem_b_path[chair] -- endfor
+ cycle ;
+ chem_r_path.rt[chair] :=
+ for i=0 upto 5 : point i of rt shifted point i of chem_b_path[chair] -- endfor
+ cycle ;
+ % boat
+ chem_front[boat] := true ; chem_front_b[boat] := 4 ;
+ chem_init_some(boat,
+ for i=1 upto 4 : point i-1 of chem_b_path[sixfront] -- endfor
+ point 2 of chem_b_path[sixfront] yscaled .5 --
+ point 1 of chem_b_path[sixfront] yscaled .5
+ ) ;
+ lft := dir(30+.5a)--dir(330+.5a)--dir(210-.5a)--dir(150-.5a)--dir(120)--dir(60) ;
+ rt := dir(30-.5a)--dir(330-.5a)--dir(210+.5a)--dir(150+.5a)--dir(120+a)--dir(60-a) ;
+ chem_r_path.lft[boat] :=
+ for i=0 upto 5 : point i of lft shifted point i of chem_b_path[boat] -- endfor
+ cycle ;
+ chem_r_path.rt[boat] :=
+ for i=0 upto 5 : point i of rt shifted point i of chem_b_path[boat] -- endfor
+ cycle ;
+endgroup
+enddef ;
+
+chem_init_all ; % WHY does this not work unless defined and then called?
+
+% Like most often in ConTeXt, we will trap but then silently ignore mistaken use,
+% unless of course the error be too harmful...
+
+% \startchemical
+
+def chem_start_structure(expr i, l, r, t, b, rotation, unit, bond, scale, offset, axis, rulethickness, axiscolor) =
+ save chem_setting_l, chem_setting_r, chem_setting_t, chem_setting_b ;
+
+ chem_emwidth := unit ; % dynamically set for each structure.
+ chem_text_offset := -.3chem_emwidth ; % -.71chem_emwidth ; % 1/sqrt(2)
+ chem_center_offset := .5chem_emwidth ;
+ chem_b_length := chem_emwidth * bond * scale ;
+ % scale (normally 1) scales the structure but not the text.
+
+ if numeric l :
+ chem_setting_l := -l ;
+ fi
+ if numeric r :
+ chem_setting_r := r ;
+ fi
+ if numeric t :
+ chem_setting_t := t ;
+ fi
+ if numeric b :
+ chem_setting_b := -b ;
+ fi
+ chem_setting_rotation := rotation ;
+ chem_setting_offset := offset ;
+ chem_setting_axis := if boolean axis : axis else : (axis<>0) fi ;
+ chem_axis_rulethickness := .75*(rulethickness) ; % axis 50% thinner than frame and bonds.
+ chem_axis_color := image(draw origin withcolor axiscolor) ; % so we handle all color models
+
+ chem_reset ;
+enddef ;
+
+% \stopchemical
+
+vardef chem_stop_structure =
+ % Make sure that all of the saved stack has been restored... (this was a gotcha!)
+ forever :
+ exitif chem_stack_n=0 ;
+ chem_restore ;
+ endfor
+
+ currentpicture := (currentpicture shifted -chem_origin) rotated chem_setting_rotation ;
+
+ save l, r, b, t ;
+ l := min(xpart llcorner currentpicture, xpart lrcorner currentpicture) ;
+ r := max(xpart llcorner currentpicture, xpart lrcorner currentpicture) ;
+ b := min(ypart llcorner currentpicture, ypart ulcorner currentpicture) ;
+ t := max(ypart llcorner currentpicture, ypart ulcorner currentpicture) ;
+
+ if unknown chem_setting_l : chem_setting_l := l ; fi
+ if unknown chem_setting_r : chem_setting_r := r ; fi
+ if unknown chem_setting_b : chem_setting_b := b ; fi
+ if unknown chem_setting_t : chem_setting_t := t ; fi
+
+ if chem_setting_axis : % put it behind the picture
+ chem_pic := currentpicture ; currentpicture := nullpicture ;
+ chem_num0 := .5chem_b_length ;
+ chem_num1 := .2chem_num0 ;
+ % draw the axes to the bounding box of the entire structure,
+ % not necessarily the bounding box of the final figure
+ draw (l,0) -- (r,0)
+ withpen pencircle scaled chem_axis_rulethickness withcolor colorpart(chem_axis_color) ;
+ draw (0,b) -- (0,t)
+ withpen pencircle scaled chem_axis_rulethickness withcolor colorpart(chem_axis_color) ;
+ for i = 0 step chem_num0 until r :
+ draw (i,-chem_num1) -- (i,chem_num1)
+ withpen pencircle scaled chem_axis_rulethickness withcolor colorpart(chem_axis_color) ;
+ endfor
+ for i = 0 step -chem_num0 until l :
+ draw (i,-chem_num1) -- (i,chem_num1)
+ withpen pencircle scaled chem_axis_rulethickness withcolor colorpart(chem_axis_color) ;
+ endfor
+ for i = 0 step chem_num0 until t :
+ draw (-chem_num1,i) -- (chem_num1,i)
+ withpen pencircle scaled chem_axis_rulethickness withcolor colorpart(chem_axis_color) ;
+ endfor
+ for i = 0 step -chem_num0 until b :
+ draw (-chem_num1,i) -- (chem_num1,i)
+ withpen pencircle scaled chem_axis_rulethickness withcolor colorpart(chem_axis_color) ;
+ endfor
+ addto currentpicture also chem_pic ;
+ fi ;
+ if chem_trace_boundingbox :
+ fill boundingbox currentpicture withcolor blue withtransparency(1,.25) ;
+ fi ;
+ setbounds currentpicture to
+ ((chem_setting_l,chem_setting_b) -- (chem_setting_r,chem_setting_b) --
+ (chem_setting_r,chem_setting_t) -- (chem_setting_l,chem_setting_t) -- cycle) ;
+ if chem_trace_boundingbox :
+ fill boundingbox currentpicture withcolor red withtransparency(1,.25) ;
+ fi ;
+enddef ;
+
+% \chemical
+
+vardef chem_start_component = enddef ;
+vardef chem_stop_component = enddef ;
+
+vardef chem_pb = % PB :
+ if chem_trace_nesting :
+ draw boundingbox currentpicture
+ withpen pencircle scaled 1mm withcolor colorpart(chem_axis_color) ;
+ draw origin withpen pencircle scaled 2mm withcolor colorpart(chem_axis_color) ;
+ fi ;
+ chem_doing_pb := true ;
+enddef ;
+
+vardef chem_pe = % PE
+ if chem_trace_nesting :
+ draw boundingbox currentpicture withpen pencircle scaled .5mm withcolor red ;
+ draw origin withpen pencircle scaled 1mm withcolor red ;
+ fi ;
+ currentpicture := currentpicture shifted -chem_origin ;
+ if chem_trace_nesting :
+ draw origin withpen pencircle scaled .5mm withcolor green ;
+ fi ;
+ chem_origin := origin ;
+ chem_doing_pb := false ;
+enddef ;
+
+vardef chem_do (expr pos) =
+ if (unknown chem_doing_pb) or (not chem_doing_pb) :
+ pos
+ else :
+ chem_doing_pb := false ;
+ currentpicture := currentpicture shifted -pos ;
+ chem_origin := chem_origin shifted -pos ;
+ origin % nullpicture
+ fi
+enddef ;
+
+
+picture chem_stack_p[] ;
+pair chem_stack_origin[], chem_stack_mirror[] ;
+numeric chem_stack_rotation[] ;
+string chem_stack_previous[] ;
+
+vardef chem_save = % SAVE
+ chem_stack_p [incr chem_stack_n] := currentpicture ;
+ chem_stack_origin [ chem_stack_n] := chem_origin ; chem_origin := origin ;
+ chem_stack_rotation[ chem_stack_n] := chem_rotation ;
+ chem_stack_mirror [ chem_stack_n] := chem_mirror ;
+ chem_stack_previous[ chem_stack_n] := chem_previous ;
+ currentpicture := nullpicture ;
+enddef ;
+
+vardef chem_restore = % RESTORE
+ if chem_stack_n>0 :
+ currentpicture := currentpicture shifted -chem_origin ;
+ addto chem_stack_p [chem_stack_n] also currentpicture ;
+ currentpicture := chem_stack_p [chem_stack_n] ;
+ chem_stack_p[chem_stack_n] := nullpicture ;
+ chem_origin := chem_stack_origin [chem_stack_n] ;
+ chem_rotation := chem_stack_rotation[chem_stack_n] ;
+ chem_mirror := chem_stack_mirror [chem_stack_n] ;
+ chem_previous := chem_stack_previous[chem_stack_n] ;
+ chem_stack_n := chem_stack_n - 1 ;
+ fi ;
+enddef ;
+
+% chem_adj and chem_sub are to be followed by chem_set(n) which does all the work...
+
+vardef chem_adj (suffix $) (expr d, s) = % ADJ
+ % scale s is ignored (for now?)
+ if not chem_front[$] :
+ chem_substituent := 0 ;
+ chem_substituent.lft := 0 ;
+ chem_substituent.rt := 0 ;
+ chem_adjacent := d ;
+ fi
+enddef ;
+
+vardef chem_lsub (suffix $) (expr d, s) = % LSUB
+ chem_sub.lft($,d,s) ;
+enddef ;
+
+vardef chem_rsub (suffix $) (expr d, s) = % RSUB
+ chem_sub.rt ($,d,s) ;
+enddef ;
+
+vardef chem_sub@# (suffix $) (expr d, s) = % SUB
+ % scale s is ignored (for now?)
+ chem_adjacent := 0 ;
+ chem_substituent := 0 ;
+ chem_substituent.lft := 0 ;
+ chem_substituent.rt := 0 ;
+ % then :
+ chem_substituent@# := d ;
+enddef ;
+
+def chem_transformed (suffix $) = % not vardef!
+ scaled chem_b_length
+ if not chem_front[$] :
+ if chem_mirror<>origin : reflectedabout(origin,chem_mirror) fi
+ rotated chem_rotation
+ fi
+enddef ;
+
+vardef chem_draw (expr what, r, c) (text extra) =
+ draw what
+ withpen pencircle scaled r
+ withcolor c %\MPcolor{c}
+ extra ;
+enddef ;
+
+vardef chem_fill (expr what, r, c) (text extra) =
+ fill what
+ withpen pencircle scaled r
+ withcolor c %\MPcolor{c}
+ extra ;
+enddef ;
+
+vardef chem_drawarrow (expr what, r, c) (text extra) =
+ drawarrow what
+ withpen pencircle scaled r
+ withcolor c %\MPcolor{c}
+ extra ;
+enddef ;
+
+vardef chem_set (suffix $) =
+ forsuffixes P = scantokens chem_previous :
+
+ % This is a fairly complicated optimization and ajustement. It took some
+ % thinking to get right, so beware!
+
+ % And then even more time fixing a bug of a rotation +- half the symmetry
+ % angle of a structure depending on the scale and/or the font size
+ % (through chem_b_length).
+
+ % first save the symmetry angle of the structure (as in chem_rot):
+ chem_num0 := if chem_stacked[$] : 3 else : 0 fi ;
+ chem_num9 := if chem_tetra[$] : 360 else :
+ abs(angle(point 0+chem_num0 of chem_b_path[$]) -
+ angle(point 1+chem_num0 of chem_b_path[$]))
+ fi ;
+
+ if (chem_adjacent<>0) and chem_star[P] and chem_star[$] :
+ % nop
+ chem_adjacent := 0 ;
+ elseif (chem_adjacent<>0) and (chem_front[P] or chem_front[$]) :
+ % not allowed for FRONT
+ chem_adjacent := 0 ;
+ elseif chem_adjacent<>0 :
+ chem_substituent := 0 ;
+ chem_substituent.lft := 0 ;
+ chem_substituent.rt := 0 ;
+ % move to the bond midpoint of the first structure
+ chem_pair0 := center (
+ if chem_star[P] :
+ origin -- point (chem_adjacent-1)
+ else :
+ subpath (chem_adjacent-1,chem_adjacent)
+ fi
+ of chem_b_path[P]
+ ) chem_transformed(P) ;
+ % find the closest opposite bond of the second structure
+ chem_pair1 := chem_pair0 rotated if chem_star[P] : 90 else : 180 fi ;
+ chem_num0 := abs(chem_pair1) ;
+ chem_num1 := if chem_tetra[$] : 1 else : length chem_b_path[$] fi ;
+ % only consider even indices (cardinal points) for ONE
+ chem_num2 := if chem_star[$] and not chem_tetra[$] : 2 else : 1 fi ;
+ for i=0 step chem_num2 until chem_num1 :
+ chem_pair2 := (
+ (
+ unitvector
+ center (
+ if chem_star[$] :
+ origin -- point i
+ else :
+ subpath (i,i+1)
+ fi
+ of chem_b_path[$])
+ )
+ scaled chem_num0
+ ) chem_transformed($) ;
+ if i=0 :
+ chem_pair3 := chem_pair2 ;
+ chem_num3 := 0 ;
+ elseif (abs(chem_pair1 shifted -chem_pair2)) < (abs(chem_pair1 shifted -chem_pair3)) :
+ chem_pair3 := chem_pair2 ;
+ chem_num3 := i ;
+ fi
+ endfor
+ if chem_star[$] :
+ chem_pair4 := chem_pair0 shifted
+ -((point (chem_adjacent-1) of chem_b_path[P]) chem_transformed(P)) ;
+ fi
+ % adjust the bond angles
+ chem_num4 := (angle(chem_pair1)-angle(chem_pair3)) zmod chem_num9 ;
+ chem_rotation := chem_rotation + chem_num4 ;
+ if not chem_star[$] :
+ chem_pair4 :=
+ if chem_star[P] :
+ (point chem_num3
+ else :
+ center(subpath (chem_num3,chem_num3+1)
+ fi
+ of chem_b_path[$])
+ chem_transformed($) ;
+ fi
+ if not chem_star[P] :
+ chem_pair4 := chem_pair4 shifted -chem_pair0 ;
+ fi
+ currentpicture := currentpicture shifted chem_pair4 ;
+ chem_origin := chem_origin shifted chem_pair4 ;
+ chem_adjacent := 0 ;
+ fi ;
+
+ % Insure that only one, if any, will be nonzero
+ if ((chem_substituent <> 0) and (chem_substituent.lft <> 0)) or
+ ((chem_substituent <> 0) and (chem_substituent.rt <> 0)) or
+ ((chem_substituent.lft <> 0) and (chem_substituent.rt <> 0)) :
+ chem_substituent := 0 ;
+ chem_substituent.lft := 0 ;
+ chem_substituent.rt := 0 ;
+ fi
+ if (chem_substituent <> 0) or (chem_substituent.lft <> 0) or (chem_substituent.rt <> 0) :
+ % move origin to radical endpoint of the first structure
+ if chem_substituent.lft > 0 :
+ chem_pair0 := point chem_substituent.lft-1 of chem_r_path.lft[P] ;
+ chem_substituent := chem_substituent.lft ;
+ chem_substituent.lft := 0 ;
+ elseif chem_substituent.rt > 0 :
+ chem_pair0 := point chem_substituent.rt-1 of chem_r_path.rt[P] ;
+ chem_substituent := chem_substituent.rt ;
+ chem_substituent.rt := 0 ;
+ else :
+ chem_pair0 := point chem_substituent-1 of chem_r_path[P] ;
+ fi
+ chem_pair1 := chem_pair0 if not chem_star[P] :
+ shifted -(point chem_substituent-1 of chem_b_path[P]) fi ;
+ chem_t := identity chem_transformed(P) ;
+ chem_pair0 := chem_pair0 transformed chem_t ; % radical
+ chem_pair1 := chem_pair1 transformed chem_t ; % recentered (see below)
+ currentpicture := currentpicture shifted -chem_pair0 ;
+ chem_origin := chem_origin shifted -chem_pair0 ;
+ if (not (chem_star[P] and chem_star[$])) or chem_tetra[P] or chem_tetra[$] :
+ if chem_tetra[P] and chem_tetra[$] and ((chem_substituent=1) or (chem_substituent=2)):
+ chem_rotation := (chem_rotation + 180) mod 360 ; % trans-alkane
+ chem_pair2 := (point .5 of chem_b_path[$]) ; % bisector, not chem_transformed
+ if chem_mirror=origin :
+ chem_mirror := chem_pair2 ;
+ else :
+ chem_num0 := angle(chem_mirror)-angle(chem_pair2) ;
+ if (chem_num0>0) and (chem_num0> 180) :
+ chem_num0 := 360 - chem_num0 ;
+ elseif (chem_num0<0) and (chem_num0<-180) :
+ chem_num0 := -360 - chem_num0 ;
+ fi
+ chem_rotation := (chem_rotation + 2chem_num0) mod 360 ;
+ chem_mirror := origin ;
+ fi
+ fi
+ chem_t := identity chem_transformed($) ;
+ chem_pair1 := chem_pair1 rotated 180 ; % opposite direction of radical bond
+ % find the closest node
+ chem_num0 := abs(chem_pair1) ; % distance
+ % search to find the nearest node of $; only consider 1 and 2 for CARBON,ALKYL
+ chem_num1 := if chem_tetra[$] : 1 else : length chem_b_path[$] fi ;
+ % only consider even indices (cardinal points) for ONE
+ chem_num2 := if chem_star[$] and not chem_tetra[$] : 2 else : 1 fi ;
+ for i=0 step chem_num2 until chem_num1 :
+ chem_pair2 := (unitvector(point i of chem_b_path[$]) scaled chem_num0)
+ transformed chem_t ;
+ if i=0 :
+ chem_pair3 := chem_pair2 ;
+ chem_num3 := 0 ;
+ elseif (abs(chem_pair1 shifted -chem_pair2)) <
+ (abs(chem_pair1 shifted -chem_pair3)) :
+ chem_pair3 := chem_pair2 ;
+ chem_num3 := i ;
+ fi
+ endfor
+ if not chem_front[$] : % adjust rotation
+ chem_num4 := angle(chem_pair1)-angle(chem_pair3) ;
+ chem_rotation := (chem_rotation + chem_num4) mod 360 ;
+ fi ;
+ chem_t := identity chem_transformed($) ;
+ chem_pair4 := (point chem_num3 of chem_b_path[$]) transformed chem_t ;
+ if not chem_star[$] :
+ currentpicture := currentpicture shifted chem_pair4 ;
+ chem_origin := chem_origin shifted chem_pair4 ;
+ fi
+ if not chem_front[$] : % adjust rotation
+ chem_rotation := chem_rotation zmod chem_num9 ;
+ fi
+ fi
+ chem_substituent := 0 ;
+ fi ;
+ endfor
+ chem_previous := str $ ;
+enddef ;
+
+% line (f_rom, t_o, r_ule, c_olor)
+
+vardef chem_b@# (suffix $) (expr f, t, r, c) = % B
+ if chem_star[$] :
+ chem_r@#($,f,t,r,c) ;
+ elseif length(str @#)>0 :
+ chem_sb@#($,f,t,r,c) ;
+ else :
+ chem_draw(
+ (subpath (f-1,t) of chem_b_path[$]) chem_transformed($),
+ r,c,) ;
+ fi
+enddef ;
+
+vardef chem_sb@# (suffix $) (expr f, t, r, c) = % SB
+ if chem_star[$] :
+ chem_sr@#($,f,t,r,c) ;
+ else :
+ %chem_draw(
+ % (subpath (f-1,t) of chem_b_path[$]) chem_transformed($),
+ % r,c,dashed chem_sb_dash@# scaled chem_b_length) ;
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath (chem_sb_pair@# shifted (i-1,i-1)) of chem_b_path[$])
+ transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_sd@# (suffix $) (expr f, t, r, c) = % SD
+ if chem_star[$] :
+ chem_rd@#($,f,t,r,c) ;
+ else :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath (chem_sb_pair@# shifted (i-1,i-1)) of chem_b_path[$])
+ transformed chem_t,
+ r,c,dashed evenly) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_r_fragment@# (suffix $) (expr i) =
+ (
+ if chem_star[$] :
+ origin
+ else :
+ point i-1 of chem_b_path[$]
+ fi --
+ point i-1 of chem_r_path@#[$]
+ ) % no ;
+enddef ;
+
+vardef chem_r@# (suffix $) (expr f, t, r, c) = % R
+ if length(str @#)>0 :
+ chem_sr@#($,f,t,r,c) ;
+ else :
+ chem_sr.b($,f,t,r,c) ;
+ fi
+enddef ;
+
+vardef chem_er@# (suffix $) (expr f, t, r, c) = % ER
+ if length(str @#)>0:
+ chem_dr@#($,f,t,r,c) ;
+ else :
+ chem_dr.b($,f,t,r,c) ;
+ fi
+enddef ;
+
+vardef chem_dr@# (suffix $) (expr f, t, r, c) = % DR
+ if not chem_front[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := (subpath chem_sb_pair@# of chem_r_fragment($,i)) ;
+ chem_draw(
+ (chem_path0 paralleled chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ (chem_path0 paralleled -chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_lr@# (suffix $) (expr f, t, r, c) = % LR
+ if length(str @#)>0 :
+ chem_lsr@#($,f,t,r,c) ;
+ else :
+ chem_lsr.b($,f,t,r,c) ;
+ fi
+enddef ;
+
+vardef chem_rr@# (suffix $) (expr f, t, r, c) = % RR
+ if length(str @#)>0 :
+ chem_rsr@#($,f,t,r,c) ;
+ else :
+ chem_rsr.b($,f,t,r,c) ;
+ fi
+enddef ;
+
+vardef chem_eb@# (suffix $) (expr f, t, r, c) = % EB
+ if not chem_star[$] :
+ %chem_draw(
+ % ((subpath (f-1,t) of chem_b_path[$]) paralleled -2chem_dbl_offset)
+ % chem_transformed($),
+ % r,c,dashed chem_sb_dash scaled chem_b_length) ;
+ for i=f upto t :
+ chem_t := identity chem_transformed($) ;
+ chem_draw(
+ ((subpath (chem_sb_pair@# shifted (i-1,i-1)) of chem_b_path[$])
+ paralleled -2chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_ad@# (suffix $) (expr f, t, r, c) = % AD
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_drawarrow(
+ (
+ (subpath
+ if chem_star[$] :
+ chem_sb_pair@# of chem_r_fragment($,i)
+ ) paralleled 5chem_dbl_offset
+ else :
+ (chem_sb_pair@# shifted (i-1,i-1)) of chem_b_path[$]
+ ) paralleled 2chem_dbl_offset
+ fi
+ ) transformed chem_t,
+ r,c,) ;
+ endfor
+enddef ;
+
+vardef chem_au@# (suffix $) (expr f, t, r, c) = % AU
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_drawarrow(
+ ((reverse
+ subpath
+ if chem_star[$] :
+ chem_sb_pair@# of chem_r_fragment($,i)
+ ) paralleled -5chem_dbl_offset
+ else :
+ (chem_sb_pair@# shifted (i-1,i-1)) of chem_b_path[$]
+ ) paralleled -2chem_dbl_offset
+ fi
+ ) transformed chem_t,
+ r,c,) ;
+ endfor
+enddef ;
+
+vardef chem_es@# (suffix $) (expr f, t, r, c) = % ES
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ ((point i-1 of chem_r_path[$]) scaled (xpart chem_sb_pair)) transformed chem_t,
+ chem_dot_factor*r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_ed@# (suffix $) (expr f, t, r, c) = % ED
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ if chem_star[$] :
+ chem_path0 := subpath chem_sb_pair of chem_r_fragment($,i) ;
+ chem_draw(
+ (point 0 of (chem_path0 paralleled -chem_dbl_offset)) transformed chem_t,
+ chem_dot_factor*r,c,) ;
+ chem_draw(
+ (point 0 of (chem_path0 paralleled chem_dbl_offset)) transformed chem_t,
+ chem_dot_factor*r,c,) ;
+ else :
+ chem_draw(
+ ((subpath (chem_sb_pair shifted (i-1,i-1)) of chem_b_path[$])
+ paralleled -2chem_dbl_offset) transformed chem_t,
+ r,c,dashed evenly) ;
+ fi
+ endfor
+enddef ;
+
+vardef chem_ep@# (suffix $) (expr f, t, r, c) = % EP
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair of chem_r_fragment($,i) ;
+ chem_draw(
+ (point 0 of (chem_path0 paralleled -chem_dbl_offset) --
+ point 0 of (chem_path0 paralleled chem_dbl_offset)) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_et@# (suffix $) (expr f, t, r, c) = % ET
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair of chem_r_fragment($,i) ;
+ chem_draw(
+ (point 0 of (chem_path0 paralleled -2chem_dbl_offset)) transformed chem_t,
+ chem_dot_factor*r,c,) ;
+ chem_draw(
+ (point 0 of chem_path0) transformed chem_t,
+ chem_dot_factor*r,c,) ;
+ chem_draw(
+ (point 0 of (chem_path0 paralleled 2chem_dbl_offset)) transformed chem_t,
+ chem_dot_factor*r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_db@# (suffix $) (expr f, t, r, c) = % DB
+ if chem_star[$] :
+ chem_dr@#($,f,t,r,c) ;
+ elseif not chem_front[$] :
+ chem_t := identity chem_transformed($) ;
+ %chem_draw(
+ % ((subpath (f-1,t) of chem_b_path[$]) paralleled -chem_dbl_offset)
+ % transformed chem_t,
+ % r,c,dashed chem_sb_dash@# scaled chem_b_length) ;
+ %chem_draw(
+ % ((subpath (f-1,t) of chem_b_path[$]) paralleled chem_dbl_offset)
+ % transformed chem_t,
+ % r,c,dashed chem_sb_dash@# scaled chem_b_length) ;
+ for i=f upto t :
+ chem_path0 := subpath (chem_sb_pair@# shifted (i-1,i-1)) of chem_b_path[$] ;
+ chem_draw(
+ (chem_path0 paralleled -chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ (chem_path0 paralleled chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ % todo : this should be cut-off where it overlaps a neighboring standard bond.
+ endfor
+ fi
+enddef ;
+
+vardef chem_tb@# (suffix $) (expr f, t, r, c) = % TB
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_draw(
+ (chem_path0 paralleled -2chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ chem_path0 transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ (chem_path0 paralleled 2chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_sr@# (suffix $) (expr f, t, r, c) = % SR
+ chem_t := identity chem_transformed($) ;
+ if chem_stacked[$] :
+ chem_num0 := length chem_b_path[$] ; chem_num1 := floor(.5chem_num0) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath (if i>chem_num1: .5,ypart fi chem_sb_pair@#) of chem_r_fragment($,i))
+ transformed chem_t,
+ r,c,) ;
+ endfor
+ else :
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment($,i))
+ transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_rd@# (suffix $) (expr f, t, r, c) = % RD
+ chem_t := identity chem_transformed($) ;
+ if chem_stacked[$] :
+ chem_num0 := length chem_b_path[$] ; chem_num1 := floor(.5chem_num0) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath (if i>chem_num1: .5,ypart fi chem_sb_pair@#) of chem_r_fragment($,i))
+ transformed chem_t,
+ r,c,dashed evenly) ;
+ endfor
+ else :
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment($,i))
+ transformed chem_t,
+ r,c,dashed evenly) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_rh@# (suffix $) (expr f, t, r, c) = % RH
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment($,i))
+ transformed chem_t,
+ chem_dot_factor*r,c,dashed withdots scaled ((.5chem_b_length/3)/5bp)) ;
+ % not symmetric - needs to be tweaked...
+ endfor
+enddef ;
+
+vardef chem_lrh@# (suffix $) (expr f, t, r, c) = % LRH
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment.lft($,i))
+ transformed chem_t,
+ chem_dot_factor*r,c,dashed withdots scaled ((.5chem_b_length/3)/5bp)) ;
+ % not symmetric - needs to be tweaked...
+ endfor
+enddef ;
+
+vardef chem_rrh@# (suffix $) (expr f, t, r, c) = % RRH
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment.rt($,i))
+ transformed chem_t,
+ chem_dot_factor*r,c,dashed withdots scaled ((.5chem_b_length/3)/5bp)) ;
+ % not symmetric - needs to be tweaked...
+ endfor
+enddef ;
+
+vardef chem_hb@# (suffix $) (expr f, t, r, c) = % HB
+ if chem_star[$] :
+ chem_rh@#($,f,t,r,c)
+ else :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath (chem_sb_pair@# shifted (i-1,i-1)) of chem_b_path[$])
+ transformed chem_t,
+ chem_dot_factor*r,c,dashed withdots scaled ((.5chem_b_length/3)/5bp)) ;
+ % not symmetric - needs to be tweaked...
+ endfor
+ fi
+enddef ;
+
+vardef chem_bb@# (suffix $) (expr f, t, r, c) = % BB
+ if chem_star[$] :
+ chem_rb@#($,f,t,r,c) ;
+ elseif chem_front[$] :
+ chem_t := identity chem_transformed($) ;
+ chem_draw(
+ (subpath (f-1,t) of chem_b_path[$]) transformed chem_t,
+ r,c,) ;
+ chem_num0 := length chem_b_path[$] ; % total number of bonds
+ chem_num1 := chem_front_b[$] ; % number of bonds to be made bold
+ % bold bonds within f and t
+ chem_num2 := if f<0 :((f+1) mod chem_num0) + chem_num0 else : ((f-1) mod chem_num0) + 1 fi ;
+ chem_num3 := if t<0 :((t+1) mod chem_num0) + chem_num0 else : ((t-1) mod chem_num0) + 1 fi ;
+ if chem_num3<chem_num2 :
+ chem_num4 := chem_num3 ;
+ chem_num3 := chem_num2 ;
+ chem_num2 := chem_num4 ;
+ fi
+ if chem_num2<chem_num1 : % Are there any bonds to be made bold?
+ if chem_num2=1 : % Skip the first bold bond.
+ chem_fill(
+ (point chem_num2-1 of chem_b_path[$] --
+ point chem_num2 of chem_b_path[$] shifted (0,-chem_dbl_offset) --
+ point chem_num2 of chem_b_path[$] shifted (0, chem_dbl_offset) --
+ cycle) transformed chem_t,
+ r,c,) ;
+ fi
+ if (chem_num2<=chem_num1-1) and (chem_num3>1) :
+ chem_path0 := subpath (if chem_num2>2 : chem_num2-1 else : 1 fi,
+ if chem_num3<chem_num1 : chem_num3 else : chem_num1-1 fi)
+ of chem_b_path[$] ;
+ chem_fill(
+ (chem_path0 paralleled -chem_dbl_offset --
+ reverse(chem_path0) paralleled -chem_dbl_offset --
+ cycle) transformed chem_t,
+ r,c,) ;
+ fi
+ if chem_num3>=chem_num1 :
+ chem_fill(
+ (point chem_num1 of chem_b_path[$] --
+ point chem_num1-1 of chem_b_path[$] shifted (0,-chem_dbl_offset) --
+ point chem_num1-1 of chem_b_path[$] shifted (0, chem_dbl_offset) --
+ cycle) transformed chem_t,
+ r,c,) ;
+ fi
+ fi
+ fi
+enddef ;
+
+vardef chem_rb@# (suffix $) (expr f, t, r, c) = % RB
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_fill(
+ (point 0 of chem_path0 --
+ point 1 of chem_path0
+ rotatedaround(point 0 of chem_path0, -chem_bb_angle) --
+ point 1 of chem_path0
+ rotatedaround(point 0 of chem_path0, chem_bb_angle) --
+ cycle) transformed chem_t,
+ r,c,) ;
+ endfor
+enddef ;
+
+vardef chem_lrb@# (suffix $) (expr f, t, r, c) = % LRB
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment.lft($,i) ;
+ chem_fill(
+ (point 0 of chem_path0 --
+ point 1 of chem_path0
+ rotatedaround(point 0 of chem_path0, -chem_bb_angle) --
+ point 1 of chem_path0
+ rotatedaround(point 0 of chem_path0, chem_bb_angle) --
+ cycle) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_rrb@# (suffix $) (expr f, t, r, c) = % RRB
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment.rt($,i) ;
+ chem_fill(
+ (point 0 of chem_path0 --
+ point 1 of chem_path0
+ rotatedaround(point 0 of chem_path0, -chem_bb_angle) --
+ point 1 of chem_path0
+ rotatedaround(point 0 of chem_path0, chem_bb_angle) --
+ cycle) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_lsr@# (suffix $) (expr f, t, r, c) = % LSR
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment.lft($,i)) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_rsr@# (suffix $) (expr f, t, r, c) = % RSR
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment.rt($,i)) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_lrd@# (suffix $) (expr f, t, r, c) = % LRD
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment.lft($,i)) transformed chem_t,
+ r,c,dashed evenly) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_rrd@# (suffix $) (expr f, t, r, c) = % RRD
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of chem_r_fragment.rt($,i)) transformed chem_t,
+ r,c,dashed evenly) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_s@# (suffix $) (expr f, t, r, c) = % S
+ if length(str @#)>0 :
+ chem_ss@#($,f,t,r,c) ;
+ else :
+ chem_ss.b($,f,t,r,c) ;
+ fi
+enddef ;
+
+vardef chem_ss@# (suffix $) (expr f, t, r, c) = % SS
+ if not (chem_star[$] or chem_front[$]) :
+ chem_draw(
+ subpath chem_sb_pair@# of (point f-2 of chem_b_path[$] -- point t of chem_b_path[$])
+ chem_transformed($),
+ r,c,) ;
+ fi
+enddef ;
+
+vardef chem_mid@# (suffix $) (expr f, t, r, c) = % MID
+ if length(str @#)>0 :
+ chem_mids@#($,f,t,r,c) ;
+ else :
+ chem_mids.b($,f,t,r,c) ;
+ fi
+enddef ;
+
+vardef chem_mids@# (suffix $) (expr f, t, r, c) = % MIDS
+ if not (chem_star[$] or chem_front[$]) :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_draw(
+ (subpath chem_sb_pair@# of (origin -- point i-1 of chem_b_path[$]))
+ transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_cd (suffix $) (expr r, c) = % CD
+ chem_draw(
+ chem_c_path[$] chem_transformed($),
+ r,c,dashed evenly) ;
+enddef ;
+
+vardef chem_c (suffix $) (expr r, c) = % C
+ chem_draw(
+ chem_c_path[$] chem_transformed($),
+ r,c,) ;
+enddef ;
+
+vardef chem_ccd (suffix $) (expr f, t, r, c) = % CCD
+ chem_num0 := ypart((origin--center(subpath (f-2,f-1) of chem_b_path[$]))
+ intersectiontimes chem_c_path[$]) ;
+ chem_num1 := ypart((origin--center(subpath (t-1,t) of chem_b_path[$]))
+ intersectiontimes chem_c_path[$]) ;
+ if chem_num1>chem_num0 :
+ chem_num0 := chem_num0 + length chem_c_path[$] ;
+ fi
+ chem_draw(
+ subpath (chem_num1,chem_num0) of chem_c_path[$] chem_transformed($),
+ r,c,dashed evenly) ;
+enddef ;
+
+vardef chem_cc (suffix $) (expr f, t, r, c) = % CC
+ chem_num0 := ypart((origin--center(subpath (f-2,f-1) of chem_b_path[$]))
+ intersectiontimes chem_c_path[$]) ;
+ chem_num1 := ypart((origin--center(subpath (t-1,t) of chem_b_path[$]))
+ intersectiontimes chem_c_path[$]) ;
+ if chem_num1>chem_num0 :
+ chem_num0 := chem_num0 + length chem_c_path[$] ;
+ fi
+ chem_draw(
+ subpath (chem_num1,chem_num0) of chem_c_path[$] chem_transformed($),
+ r,c,) ;
+enddef ;
+
+vardef chem_ldb@# (suffix $) (expr f, t, r, c) = % LD
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_draw(
+ chem_path0 transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ (chem_path0 paralleled 2chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_rdb@# (suffix $) (expr f, t, r, c) = % LD
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_draw(
+ chem_path0 transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ (chem_path0 paralleled -2chem_dbl_offset) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_ldd@# (suffix $) (expr f, t, r, c) = % LDD
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_draw(
+ chem_path0 transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ (chem_path0 paralleled 2chem_dbl_offset) transformed chem_t,
+ r,c,dashed evenly) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_rdd@# (suffix $) (expr f, t, r, c) = % RDD
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_draw(
+ chem_path0 transformed chem_t,
+ r,c,) ;
+ chem_draw(
+ (chem_path0 paralleled -2chem_dbl_offset) transformed chem_t,
+ r,c,dashed evenly) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_oe@# (suffix $) (expr f, t, r, c) = % OE
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_path1 := chem_path0 paralleled -.5chem_dbl_offset ;
+ chem_path2 := chem_path0 paralleled .5chem_dbl_offset ;
+ chem_draw(
+ ( point 0 of chem_path0 --
+ .2[point 0 of chem_path0, point infinity of chem_path0]..
+ .3[point 0 of chem_path1, point infinity of chem_path1]..
+ .4[point 0 of chem_path0, point infinity of chem_path0]..
+ .5[point 0 of chem_path2, point infinity of chem_path2]..
+ .6[point 0 of chem_path0, point infinity of chem_path0]..
+ .7[point 0 of chem_path1, point infinity of chem_path1]..
+ .8[point 0 of chem_path0, point infinity of chem_path0]--
+ point infinity of chem_path0) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_bw@# (suffix $) (expr f, t, r, c) = % BW
+ if chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ chem_path1 := chem_path0 paralleled -.5chem_dbl_offset ;
+ chem_path2 := chem_path0 paralleled .5chem_dbl_offset ;
+ chem_draw(
+ ( point 0 of chem_path0..
+ .1[point 0 of chem_path1, point infinity of chem_path1]..
+ .2[point 0 of chem_path0, point infinity of chem_path0]..
+ .3[point 0 of chem_path2, point infinity of chem_path2]..
+ .4[point 0 of chem_path0, point infinity of chem_path0]..
+ .5[point 0 of chem_path1, point infinity of chem_path1]..
+ .6[point 0 of chem_path0, point infinity of chem_path0]..
+ .7[point 0 of chem_path2, point infinity of chem_path2]..
+ .8[point 0 of chem_path0, point infinity of chem_path0]..
+ .9[point 0 of chem_path1, point infinity of chem_path1]..
+ point infinity of chem_path0) transformed chem_t,
+ r,c,) ;
+ endfor
+ fi
+enddef ;
+
+vardef chem_bd@# (suffix $) (expr f, t, r, c) = % BD
+ if chem_star[$] : chem_rbd#@($,f,t,r,c) ; fi
+enddef ;
+
+vardef chem_rbd@# (suffix $) (expr f, t, r, c) = % RBD
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment($,i) ;
+ if chem_bd_wedge :
+ chem_path1 := chem_path0 rotated -chem_bb_angle ;
+ chem_path2 := chem_path0 rotated chem_bb_angle ;
+ else :
+ chem_path1 := chem_path0 paralleled -chem_dbl_offset ;
+ chem_path2 := chem_path0 paralleled chem_dbl_offset ;
+ fi
+ for j=0 upto 3 :
+ chem_draw(
+ (point (j/3) of chem_path1 -- point (j/3) of chem_path2) transformed chem_t,
+ 2r,c,) ;
+ endfor
+ endfor
+enddef ;
+
+vardef chem_lrbd@# (suffix $) (expr f, t, r, c) = % LRBD
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment.lft($,i) ;
+ if chem_bd_wedge :
+ chem_path1 := chem_path0 rotated -chem_bb_angle ;
+ chem_path2 := chem_path0 rotated chem_bb_angle ;
+ else :
+ chem_path1 := chem_path0 paralleled -.5chem_dbl_offset ;
+ chem_path2 := chem_path0 paralleled .5chem_dbl_offset ;
+ fi
+ for j=0 upto 3 :
+ chem_draw(
+ (point (j/3) of chem_path1 -- point (j/3) of chem_path2) transformed chem_t,
+ 2r,c,) ;
+ endfor
+ endfor
+ fi
+enddef ;
+
+vardef chem_rrbd@# (suffix $) (expr f, t, r, c) = % RRBD
+ if not chem_star[$] :
+ chem_t := identity chem_transformed($) ;
+ for i=f upto t :
+ chem_path0 := subpath chem_sb_pair@# of chem_r_fragment.rt($,i) ;
+ if chem_bd_wedge :
+ chem_path1 := chem_path0 rotated -chem_bb_angle ;
+ chem_path2 := chem_path0 rotated chem_bb_angle ;
+ else :
+ chem_path1 := chem_path0 paralleled -.5chem_dbl_offset ;
+ chem_path2 := chem_path0 paralleled .5chem_dbl_offset ;
+ fi
+ for j=0 upto 3 :
+ chem_draw(
+ (point (j/3) of chem_path1 -- point (j/3) of chem_path2) transformed chem_t,
+ 2r,c,) ;
+ endfor
+ endfor
+ fi
+enddef ;
+
+% text, number (no alignment on number);
+
+vardef chem_z@#(suffix $) (expr p) (text t) = % Z
+ draw chem_text@#
+ (t,chem_do(
+ if p=0 :
+ origin
+ else :
+ (point p-1 of chem_b_path[$]) chem_transformed($)
+ fi
+ )) ;
+enddef ;
+
+vardef chem_cz@#(suffix $) (expr p) (text t) = chem_z@#($,p,t) ; enddef ; % CZ ?
+
+vardef chem_midz@#(suffix $) (expr p) (text t) = % MIDZ
+ if not (chem_star[$] or chem_front[$]) :
+ draw chem_text@#
+ (t,chem_do(
+ (xpart chem_sb_pair, 0) scaled (xpart point 0 of chem_b_path[$])
+ chem_transformed($)
+ )) ;
+ fi
+enddef ;
+
+vardef chem_rz@#(suffix $) (expr p) (text t) = % RZ
+ draw chem_text@#
+ (t, chem_do((point p-1 of chem_r_path[$]) chem_transformed($))) ;
+enddef ;
+
+vardef chem_lrz@#(suffix $) (expr p) (text t) = % LRZ
+ if not chem_star[$] :
+ draw chem_text@#
+ (t,
+ chem_do((point p-1 of chem_r_path.lft[$]) chem_transformed($))) ;
+ fi
+enddef ;
+
+vardef chem_rrz@#(suffix $) (expr p) (text t) = % RRZ
+ if not chem_star[$] :
+ draw chem_text@#
+ (t, chem_do((point p-1 of chem_r_path.rt[$]) chem_transformed($))) ;
+ fi
+enddef ;
+
+vardef chem_zn@#(suffix $) (expr p) (text t) = % ZN
+ chem_zt($,p,t) ;
+enddef ;
+
+vardef chem_zt@#(suffix $) (expr p) (text t) = % ZT
+ draw chem_text@#(t,chem_do ((point p-1 of chem_b_path[$]) chem_transformed($)
+ scaled chem_text_min)) ;
+enddef ;
+
+vardef chem_zln@#(suffix $) (expr p) (text t) = % ZLN
+ chem_zlt($,p,t) ;
+enddef ;
+
+vardef chem_zlt@#(suffix $) (expr p) (text t) = % ZLT
+ draw chem_text@#(t, chem_do((point p-1.5 of chem_b_path[$]) chem_transformed($)
+ scaled chem_text_min)) ;
+enddef ;
+
+vardef chem_zrn@#(suffix $) (expr p) (text t) = % ZRN
+ chem_zrt($,p,t) ;
+enddef ;
+
+vardef chem_zrt@#(suffix $) (expr p) (text t) = % ZRT
+ draw chem_text@#(t, chem_do((point p-0.5 of chem_b_path[$]) chem_transformed($)
+ scaled chem_text_min)) ;
+enddef ;
+
+vardef chem_crz@#(suffix $) (expr p) (text t) = % CRZ ????
+ if chem_star[$] :
+ draw chem_text@#(t, chem_do((point p-1 of chem_b_path[$] enlonged chem_center_offset)
+ chem_transformed($))) ;
+ fi
+enddef ;
+
+vardef chem_rn@#(suffix $) (expr i, t) = % RN
+ chem_rt($,i,t) ;
+enddef ;
+
+vardef chem_rt@#(suffix $) (expr p) (text t) = % RT
+ draw chem_text@#(t, chem_do((center chem_r_fragment($,p)) chem_transformed($))) ;
+enddef ;
+
+vardef chem_lrn@#(suffix $) (expr i, t) = % LRN
+ chem_lrt($,i,t) ;
+enddef ;
+
+vardef chem_lrt@#(suffix $) (expr p) (text t) = % LRT
+ draw chem_text@#(t, chem_do((center chem_r_fragment.lft($,p)) chem_transformed($))) ;
+enddef ;
+
+vardef chem_rrn@# (suffix $) (expr i, t) = % RRN
+ chem_rrt($,i,t) ;
+enddef ;
+
+vardef chem_rrt@#(suffix $) (expr p) (text t) = % RRT
+ draw chem_text@#(t, chem_do((center chem_r_fragment.rt($,p)) chem_transformed($))) ;
+enddef ;
+
+vardef chem_symbol(expr t) = draw textext(t) ; enddef ;
+
+vardef chem_align@#(expr pic) =
+ pic
+ if (mfun_labtype@# >= 10) :
+ shifted (0,ypart center pic)
+ fi
+ shifted (-(mfun_labxf@#*lrcorner pic + mfun_labyf@#*ulcorner pic + (1-mfun_labxf@#-mfun_labyf@#)*llcorner pic))
+enddef ;
+
+vardef chem_text@#(expr txt, z) =
+ chem_pic := textext(txt) ;
+ if length(str @#)=0 :
+ chem_pic := chem_align(chem_pic) ;
+ elseif (str @#) = "auto" :
+ if z<>origin :
+ chem_num0 := abs(angle(z rotated chem_setting_rotation)) ;
+ if chem_num0<=60 :
+ chem_pic := chem_align.rt (chem_pic) xshifted chem_text_offset ;
+ elseif chem_num0>=120 :
+ chem_pic := chem_align.lft(chem_pic) xshifted -chem_text_offset ;
+ else :
+ chem_pic := chem_align (chem_pic) ;
+ fi
+ else :
+ chem_pic := chem_align (chem_pic) ;
+ fi
+ else :
+ chem_pic := chem_align@#(chem_pic) shifted (chem_text_offset*mfun_laboff@#) ;
+ fi
+ chem_pic := (chem_pic rotated -chem_setting_rotation) shifted z ;
+
+ if chem_trace_text :
+ draw z withpen pencircle scaled 2pt withcolor red ;
+ draw boundingbox chem_pic withpen pencircle scaled 1pt withcolor red ;
+ fi
+
+ chem_pic
+enddef ;
+
+% transform
+
+% rotations and reflections
+
+vardef chem_rot (suffix $) (expr d, s) = % ROT
+ if not chem_front[$] :
+ if d=0 :
+ chem_rotation := 0
+ else :
+ chem_num0 := if chem_stacked[$] : 3 else : 0 fi ;
+ chem_num1 := .5(angle(point d+chem_num0 of chem_b_path[$]) -
+ angle(point d+chem_num0-1 of chem_b_path[$])) ;
+ chem_rotation := (chem_rotation + s*chem_num1) zmod 360 ;
+ fi
+ fi
+enddef ;
+
+vardef chem_mir (suffix $) (expr d, s) = % MIR
+ % We take the scale factor s to multiply the rotation, but only ONCE.
+ % For example: CARBON,.5MIR12 will give a rotation by 104°
+ if not chem_front[$] :
+ if d=0 : % inversion
+ if chem_mirror=origin :
+ chem_rotation := (chem_rotation + 180*s) zmod 360 ;
+ else :
+ chem_mirror := chem_mirror rotated 90 ;
+ fi
+ else :
+ chem_pair0 := (point d-1 of chem_b_path[$]) scaled s ; % not chem_transformed
+ if chem_mirror=origin :
+ chem_mirror := chem_pair0 ;
+ else :
+ chem_num0 := angle(chem_mirror)-angle(chem_pair0) ;
+ if (chem_num0>0) and (chem_num0> 180) :
+ chem_num0 := 360 - chem_num0 ;
+ elseif (chem_num0<0) and (chem_num0<-180) :
+ chem_num0 := -360 - chem_num0 ;
+ fi
+ chem_num0 := chem_num0 * s ;
+ chem_rotation := (chem_rotation + 2chem_num0) zmod 360 ;
+ chem_mirror := origin ;
+ fi
+ fi
+ fi
+enddef ;
+
+% translations
+
+vardef chem_dir (suffix $) (expr d, s) = % DIR (same as MOV(d-1)MOV(d+1))
+ if not chem_front[$] :
+ if d=0 :
+ currentpicture := currentpicture shifted -chem_origin ;
+ chem_origin := origin ;
+ else :
+ chem_pair0 :=
+ (((point d-2 of chem_b_path[$]) shifted (point d of chem_b_path[$])) scaled s)
+ chem_transformed($) ;
+ currentpicture := currentpicture shifted -chem_pair0 ;
+ chem_origin := chem_origin shifted -chem_pair0 ;
+ fi
+ fi
+enddef ;
+
+vardef chem_mov (suffix $) (expr d, s) = % MOV
+ if d=0 :
+ currentpicture := currentpicture shifted -chem_origin ;
+ chem_origin := origin ;
+ else :
+ chem_pair0 := ((point d-1 of chem_b_path[$]) scaled s) chem_transformed($) ;
+ currentpicture := currentpicture shifted -chem_pair0 ;
+ chem_origin := chem_origin shifted -chem_pair0 ;
+ fi ;
+enddef ;
+
+vardef chem_mark (suffix $) (expr d, s) = % MARK
+ % scale s is ignored
+ if d<>0 :
+ chem_mark_pair[d] := -chem_origin ;
+ fi
+enddef ;
+
+vardef chem_marked (expr d) =
+ if d=0 :
+ chem_origin
+ elseif known chem_mark_pair[d] :
+ chem_mark_pair[d] shifted chem_origin
+ else :
+ origin
+ fi
+enddef ;
+
+vardef chem_number@#(suffix $) (expr p) (text t) = chem_label@#($,p,t) enddef ; % NUMBER
+vardef chem_label@# (suffix $) (expr p) (text t) = % LABEL
+ draw chem_text@#(t,chem_do(chem_marked(p))) ;
+enddef ;
+
+vardef chem_move (suffix $) (expr d, s) = % MOVE
+ chem_pair0 := chem_marked(d) scaled s ;
+ currentpicture := currentpicture shifted -chem_pair0 ;
+ chem_origin := chem_origin shifted -chem_pair0 ;
+enddef ;
+
+vardef chem_diff (suffix $) (expr d, s) = % DIFF
+ chem_pair0 := (chem_marked(d) shifted -chem_origin) scaled s ;
+ currentpicture := currentpicture shifted -chem_pair0 ;
+ chem_origin := chem_origin shifted -chem_pair0 ;
+enddef ;
+
+vardef chem_line (suffix $) (expr f, t, r, c) = % LINE
+ draw if f=t : origin else : chem_marked(f) fi -- chem_marked(t)
+ % no chem_transformed
+ withpen pencircle scaled r
+ withcolor c %\MPcolor{c}
+enddef ;
+
+vardef chem_dash (suffix $) (expr f, t, r, c) = % DASH
+ draw if f=t : origin else : chem_marked(f) fi -- chem_marked(t)
+ % no chem_transformed
+ withpen pencircle scaled r
+ withcolor c %\MPcolor{c}
+ dashed evenly ;
+enddef ;
+
+vardef chem_arrow (suffix $) (expr f, t, r, c) = % ARROW
+ drawarrow if f=t : origin else : chem_marked(f) fi -- chem_marked(t)
+ % no chem_transformed
+ withpen pencircle scaled r
+ withcolor c %\MPcolor{c}
+enddef ;
+
+
+vardef chem_rm (suffix $) (expr d, s) = % RM
+ if (not chem_front[$]) and (d<>0) :
+ chem_pair0 := ((point d-1 of chem_r_path[$]) scaled s) chem_transformed($) ;
+ currentpicture := currentpicture shifted -chem_pair0 ;
+ chem_origin := chem_origin shifted -chem_pair0 ;
+ fi ;
+enddef ;
+
+vardef chem_off (suffix $) (expr d, s) = % OFF
+ if d=0 :
+ currentpicture := currentpicture shifted -chem_origin ;
+ chem_origin := origin ;
+ else :
+ chem_pair0 := (unitvector(point d-1 of chem_b_path[one])) scaled chem_setting_offset*s ;
+ % not chem_transformed
+ currentpicture := currentpicture shifted -chem_pair0 ;
+ chem_origin := chem_origin shifted -chem_pair0 ;
+ fi ;
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-core.mpiv b/metapost/context/base/mpiv/mp-core.mpiv
new file mode 100644
index 000000000..9b7182908
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-core.mpiv
@@ -0,0 +1,1561 @@
+%D \module
+%D [ file=mp-core.mpiv,
+%D version=1999.08.01, % anchoring
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=background macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+if known context_core : endinput ; fi ;
+
+boolean context_core ; context_core := true ;
+
+%D Copied to here .. not used any more.
+
+if unknown NOfTextColumns : numeric NOfTextColumns ; NOfTextColumns := 1 ; fi ;
+if unknown NOfTextAreas : numeric NOfTextAreas ; NOfTextAreas := 1 ; fi ;
+
+def SaveTextAreas =
+ path SavedTextAreas [] ;
+ path SavedTextColumns[] ;
+ numeric NOfSavedTextAreas ;
+ numeric NOfSavedTextColumns ;
+ for i=1 upto NOfTextAreas :
+ SavedTextAreas[i] := TextAreas[i] ;
+ endfor ;
+ for i=1 upto NOfTextColumns :
+ SavedTextColumns[i] := TextColumns[i] ;
+ endfor ;
+ NOfSavedTextAreas := NOfTextAreas ;
+ NOfSavedTextColumns := NOfTextColumns ;
+enddef ;
+
+def ResetTextAreas =
+ path TextAreas[], TextColumns[], PlainTextArea, RegionTextArea ;
+ numeric NOfTextAreas ; NOfTextAreas := 0 ;
+ numeric NOfTextColumns ; NOfTextColumns := 0 ;
+ numeric nofmultipars ; nofmultipars := 0 ;
+ TextAreas[0] := TextColumns[0] := origin -- cycle ;
+enddef ;
+
+ResetTextAreas ; SaveTextAreas ; ;
+
+def RegisterTextArea (expr x, y, w, h, d) =
+ begingroup ;
+ save p ; path p ;
+ p := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
+ if NOfTextAreas>0 :
+ % if needed, concatenate areas
+ if (round(llcorner TextAreas[NOfTextAreas]) = round(ulcorner p)) and
+ (round(lrcorner TextAreas[NOfTextAreas]) = round(urcorner p)) :
+ p :=
+ ulcorner TextAreas[NOfTextAreas] --
+ urcorner TextAreas[NOfTextAreas] --
+ lrcorner p --
+ llcorner p -- cycle ;
+ else :
+ NOfTextAreas := NOfTextAreas + 1 ;
+ fi ;
+ else :
+ NOfTextAreas := NOfTextAreas + 1 ;
+ fi ;
+ TextAreas[NOfTextAreas] := p ;
+ if NOfTextColumns>0 :
+ if (round(xpart llcorner TextColumns[NOfTextColumns]) = round(xpart ulcorner p)) and
+ (round(xpart lrcorner TextColumns[NOfTextColumns]) = round(xpart urcorner p)) :
+ p :=
+ ulcorner TextColumns[NOfTextColumns] --
+ urcorner TextColumns[NOfTextColumns] --
+ lrcorner p --
+ llcorner p -- cycle ;
+ else :
+ NOfTextColumns := NOfTextColumns + 1 ;
+ fi ;
+ else :
+ NOfTextColumns := NOfTextColumns + 1 ;
+ fi ;
+ TextColumns[NOfTextColumns] := p ;
+ endgroup ;
+enddef ;
+
+%D We store a local area in slot zero.
+
+def RegisterPlainTextArea(expr x,y,w,h,d) =
+ PlainTextArea := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
+enddef ;
+
+def RegisterRegionTextArea(expr x,y,w,h,d) =
+ RegionTextArea := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
+ % RegionTextArea := RegionTextArea enlarged 2mm ;
+enddef ;
+
+def RegisterLocalTextArea (expr x, y, w, h, d) =
+ TextAreas[0] := TextColumns[0] := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
+enddef ;
+
+def ResetLocalTextArea =
+ TextAreas[0] := TextColumns[0] := origin -- cycle ;
+enddef ;
+
+ResetLocalTextArea ;
+
+vardef InsideTextArea (expr _i_, _xy_) =
+ (round(xpart _xy_) >= round(xpart llcorner TextAreas[_i_])) and
+ (round(xpart _xy_) <= round(xpart lrcorner TextAreas[_i_])) and
+ (round(ypart _xy_) >= round(ypart llcorner TextAreas[_i_])) and
+ (round(ypart _xy_) <= round(ypart urcorner TextAreas[_i_]))
+enddef ;
+
+vardef InsideSavedTextArea (expr _i_, _xy_) =
+ (round(xpart _xy_) >= round(xpart llcorner SavedTextAreas[_i_])) and
+ (round(xpart _xy_) <= round(xpart lrcorner SavedTextAreas[_i_])) and
+ (round(ypart _xy_) >= round(ypart llcorner SavedTextAreas[_i_])) and
+ (round(ypart _xy_) <= round(ypart urcorner SavedTextAreas[_i_]))
+enddef ;
+
+vardef InsideSomeTextArea (expr _xy_) =
+ save ok ; boolean ok ; ok := false ;
+ for i := 1 upto NOfTextAreas :
+ if InsideTextArea(i,_xy_) :
+ ok := true ; % we can move the exit here
+ fi ;
+ exitif ok ;
+ endfor ;
+ ok
+enddef ;
+
+vardef InsideSomeSavedTextArea (expr _xy_) =
+ save ok ; boolean ok ; ok := false ;
+ for i := 1 upto NOfSavedTextAreas :
+ if InsideSavedTextArea(i,_xy_) :
+ ok := true ;
+ fi ;
+ exitif ok ;
+ endfor ;
+ ok
+enddef ;
+
+vardef TextAreaX (expr x) =
+ numeric _TextAreaX_ ; _TextAreaX_ := 0 ;
+ for i := 1 upto NOfTextAreas :
+ if (round(x) >= round(xpart llcorner TextAreas[i])) and
+ (round(x) <= round(xpart lrcorner TextAreas[i])) :
+ _TextAreaX_ := xpart llcorner TextAreas[i] ;
+ fi ;
+ endfor ;
+ _TextAreaX_
+enddef ;
+
+vardef TextAreaY (expr y) =
+ numeric _TextAreaY_ ; _TextAreaY_ := 0 ;
+ for i := 1 upto NOfTextAreas :
+ if (round(y) >= round(ypart llcorner TextAreas[NOfTextAreas])) and
+ (round(y) <= round(ypart ulcorner TextAreas[NOfTextAreas])) :
+ _TextAreaY_ := ypart llcorner TextAreas[NOfTextAreas] ;
+ fi ;
+ endfor ;
+ _TextAreaY_
+enddef ;
+
+vardef TextAreaXY (expr x, y) =
+ pair _TextAreaXY_ ; _TextAreaXY_ := origin ;
+ for i := 1 upto NOfTextAreas :
+ if (round(x) >= round(xpart llcorner TextAreas[i])) and
+ (round(x) <= round(xpart lrcorner TextAreas[i])) and
+ (round(y) >= round(ypart llcorner TextAreas[i])) and
+ (round(y) <= round(ypart ulcorner TextAreas[i])) :
+ _TextAreaXY_ := llconer TextAreas[i] ;
+ fi ;
+ endfor ;
+ _TextAreaXY_
+enddef ;
+
+vardef TextAreaW (expr x) =
+ numeric _TextAreaW_ ; _TextAreaW_ := 0 ;
+ for i := 1 upto NOfTextAreas :
+ if (round(x) >= round(xpart llcorner TextAreas[i])) and
+ (round(x) <= round(xpart lrcorner TextAreas[i])) :
+ _TextAreaW_ := bbwidth(TextAreas[i]) ;
+ fi ;
+ endfor ;
+ _TextAreaW_
+enddef ;
+
+vardef TextAreaH (expr y) =
+ numeric _TextAreaH_ ; _TextAreaH_ := 0 ;
+ for i := 1 upto NOfTextAreas :
+ if (round(y) >= round(ypart llcorner TextAreas[i])) and
+ (round(y) <= round(ypart ulcorner TextAreas[i])) :
+ _TextAreaH_ := bbheight(TextAreas[i]) ;
+ fi ;
+ endfor ;
+ _TextAreaH_
+enddef ;
+
+vardef TextAreaWH (expr x, y) =
+ pair _TextAreaWH_ ; _TextAreaWH_ := origin ;
+ for i := 1 upto NOfTextAreas :
+ if (round(x) >= round(xpart llcorner TextAreas[i])) and
+ (round(x) <= round(xpart lrcorner TextAreas[i])) and
+ (round(y) >= round(ypart llcorner TextAreas[i])) and
+ (round(y) <= round(ypart ulcorner TextAreas[i])) :
+ _TextAreaWH_ := (bbwidth(TextAreas[i]),bbheight(TextAreas[i])) ;
+ fi ;
+ endfor ;
+ _TextAreaWH_
+enddef ;
+
+%D Till here.
+
+pair lxy[], rxy[], cxy[], llxy[], lrxy[], ulxy[], urxy[] ;
+path pxy[] ;
+numeric hxy[], wxy[], dxy[], nxy[] ;
+
+def box_found (expr n,x,y,w,h,d) =
+ not ((x=0) and (y=0) and (w=0) and (h=0) and (d=0))
+enddef ;
+
+def initialize_box_pos (expr pos,n,x,y,w,h,d) =
+ pair lxy, rxy, cxy, llxy, lrxy, ulxy, urxy ;
+ path pxy ; numeric hxy, wxy, dxy, nxy;
+ lxy := (x,y) ;
+ llxy := (x,y-d) ;
+ lrxy := (x+w,y-d) ;
+ urxy := (x+w,y+h) ;
+ ulxy := (x,y+h) ;
+ wxy := w ;
+ hxy := h ;
+ dxy := d ;
+ rxy := lxy shifted (wxy,0) ;
+ pxy := llxy--lrxy--urxy--ulxy--cycle ;
+ cxy := center pxy ;
+ nxy := n ;
+ freeze_box(pos) ;
+enddef ;
+
+def freeze_box (expr pos) =
+ lxy[pos] := lxy ;
+ llxy[pos] := llxy ;
+ lrxy[pos] := lrxy ;
+ urxy[pos] := urxy ;
+ ulxy[pos] := ulxy ;
+ wxy[pos] := wxy ;
+ hxy[pos] := hxy ;
+ dxy[pos] := dxy ;
+ rxy[pos] := rxy ;
+ pxy[pos] := pxy ;
+ cxy[pos] := cxy ;
+ nxy[pos] := nxy ;
+enddef ;
+
+def initialize_box (expr n,x,y,w,h,d) =
+ numeric bpos ; bpos := 0 ; initialize_box_pos(bpos,n,x,y,w,h,d) ;
+enddef ;
+
+def initialize_area (expr fn,fx,fy,fw,fh,fd,
+ tn,tx,ty,tw,th,td) =
+ numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
+ numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
+ do_initialize_area (fpos, tpos) ;
+enddef ;
+
+def do_initialize_area (expr fpos, tpos) =
+ lxy := lxy[fpos] ;
+ llxy := (xpart llxy[fpos], ypart llxy[tpos]) ;
+ lrxy := lrxy[tpos] ;
+ urxy := (xpart urxy[tpos], ypart urxy[fpos]) ;
+ ulxy := ulxy[fpos] ;
+ wxy := xpart lrxy - xpart llxy ;
+ hxy := hxy[fpos] ;
+ dxy := dxy[tpos] ;
+ rxy := lxy shifted (wxy,0) ;
+ pxy := llxy--lrxy--urxy--ulxy--cycle ;
+ cxy := center pxy ;
+enddef ;
+
+def set_par_line_height (expr ph, pd) =
+ par_strut_height := if ph>0 : ph elseif StrutHeight>0 : StrutHeight else : 8pt fi ;
+ par_strut_depth := if pd>0 : pd elseif StrutDepth >0 : StrutDepth else : 3pt fi ;
+ par_line_height := par_strut_height + par_strut_depth ;
+enddef ;
+
+def initialize_par (expr fn,fx,fy,fw,fh,fd,
+ tn,tx,ty,tw,th,td,
+ mn,mx,my,mw,mh,md,
+ pn,px,py,pw,ph,pd,
+ rw,rl,rr,rh,ra,ri) =
+
+ numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
+ numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
+ numeric mpos ; mpos := 3 ; initialize_box_pos(mpos,mn,mx,my,mw,mh,md) ;
+ numeric ppos ; ppos := 4 ; initialize_box_pos(ppos,pn,px,py,pw,ph,pd) ;
+
+ numeric par_strut_height, par_strut_depth, par_line_height ;
+
+ set_par_line_height (ph, pd) ;
+
+ do_initialize_area (fpos, tpos) ;
+ do_initialize_par (fpos, tpos, mpos, ppos, rw,rl,rr,rh,ra,ri) ;
+
+enddef ;
+
+def initialize_area_par (expr fn,fx,fy,fw,fh,fd,
+ tn,tx,ty,tw,th,td,
+ wn,wx,wy,ww,wh,wd) =
+
+ numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
+ numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
+ numeric wpos ; wpos := 3 ; initialize_box_pos(wpos,wn,wx,wy,ww,wh,wd) ;
+
+ numeric par_strut_height, par_strut_depth, par_line_height ;
+
+ set_par_line_height (wh, wd) ;
+
+ numeric ffpos ; ffpos := 4 ; initialize_box_pos(ffpos,wn,wx,fy,0,wh,wd) ;
+ numeric ttpos ; ttpos := 5 ; initialize_box_pos(ttpos,wn,wx+ww,ty,0,wh,wd) ;
+
+ do_initialize_area (ffpos, ttpos) ;
+
+ numeric mpos ; mpos := 6 ; freeze_box(mpos) ;
+
+ do_initialize_par (fpos, tpos, mpos, ffpos, 0,0,0,0,0,0) ;
+
+enddef ;
+
+def do_initialize_par (expr fpos, tpos, mpos, ppos, rw,rl,rr,rh,ra,ri) =
+
+ pair lref, rref, pref, lhref, rhref ;
+
+ % clip the page area to the left and right skips
+
+ llxy[mpos] := llxy[mpos] shifted (+rl,0) ;
+ lrxy[mpos] := lrxy[mpos] shifted (-rr,0) ;
+ urxy[mpos] := urxy[mpos] shifted (-rr,0) ;
+ ulxy[mpos] := ulxy[mpos] shifted (+rl,0) ;
+
+ % fixate the leftskip, rightskip and hanging indentation
+
+ lref := (xpart llxy[mpos],ypart ulxy[ppos]) ; lhref := lref shifted (rh,0) ;
+ rref := (xpart lrxy[mpos],ypart urxy[ppos]) ; rhref := rref shifted (rh,0) ;
+
+ pref := lxy[ppos] ;
+
+ if nxy[tpos] > nxy[fpos] :
+ if nxy[fpos] = nxy[mpos] :
+ % first of multiple pages
+ llxy[tpos] := llxy[mpos] ;
+ lrxy[tpos] := lrxy[mpos] ;
+ urxy[tpos] := lrxy[mpos] shifted (0,par_line_height) ;
+ ulxy[tpos] := llxy[mpos] shifted (0,par_line_height) ;
+ boxgriddirection := down ;
+ elseif nxy[tpos] = nxy[mpos] :
+ % last of multiple pages
+ llxy[fpos] := ulxy[mpos] shifted (0,-par_line_height) ;
+ lrxy[fpos] := urxy[mpos] shifted (0,-par_line_height) ;
+ urxy[fpos] := urxy[mpos] ;
+ ulxy[fpos] := ulxy[mpos] ;
+ boxgriddirection := up ;
+ else :
+ % middle of multiple pages
+ llxy[fpos] := ulxy[mpos] shifted (0,-par_line_height) ;
+ lrxy[fpos] := urxy[mpos] shifted (0,-par_line_height) ;
+ urxy[fpos] := urxy[mpos] ;
+ ulxy[fpos] := ulxy[mpos] ;
+ llxy[tpos] := llxy[mpos] ;
+ lrxy[tpos] := lrxy[mpos] ;
+ urxy[tpos] := lrxy[mpos] shifted (0,par_line_height) ;
+ ulxy[tpos] := llxy[mpos] shifted (0,par_line_height) ;
+ boxgriddirection := up ;
+ fi ;
+ else :
+ % just one page
+ boxgriddirection := up ;
+ fi ;
+
+ path txy, bxy, pxy, mxy ;
+
+ txy := originpath ; % top
+ bxy := originpath ; % bottom
+ pxy := originpath ; % composed
+
+ boolean lefthang, righthang, somehang ;
+
+ % we only hang on the first of a multiple page background
+
+ if nxy[mpos] > nxy[fpos] :
+ lefthang := righthang := somehang := false ;
+ else :
+ lefthang := (rh>0) ; righthang := (rh<0) ; somehang := false ;
+ fi ;
+
+ if lefthang :
+ mxy := boundingbox (lref -- lref shifted (rh,ra*par_line_height)) ;
+ elseif righthang :
+ mxy := boundingbox (rref -- rref shifted (rh,ra*par_line_height)) ;
+ else :
+ mxy := originpath ;
+ fi ;
+
+ if round(ypart llxy[fpos]) = round(ypart llxy[tpos]) :
+
+ % We have a one-liner. Watch how er use the bottom pos for
+ % determining the height.
+
+ llxy[fpos] := (xpart llxy[fpos], ypart llxy[tpos]) ;
+ ulxy[fpos] := (xpart ulxy[fpos], ypart ulxy[tpos]) ;
+
+ else :
+
+ % We have a multi-liner. For convenience we now correct the
+ % begin and end points for indentation.
+
+ if lefthang and (round(ypart llxy[tpos]) >= round(ypart lrcorner mxy)) :
+ llxy[tpos] := (xpart lhref, ypart llxy[tpos]) ;
+ ulxy[tpos] := (xpart lhref, ypart ulxy[tpos]) ;
+ else :
+ llxy[tpos] := (xpart lref, ypart llxy[tpos]) ;
+ ulxy[tpos] := (xpart lref, ypart ulxy[tpos]) ;
+ fi ;
+
+ if righthang and (round(ypart lrxy[fpos]) >= round(ypart llcorner mxy)) :
+ lrxy[fpos] := (xpart rhref, ypart lrxy[fpos]) ;
+ urxy[fpos] := (xpart rhref, ypart urxy[fpos]) ;
+ else :
+ lrxy[fpos] := (xpart rref, ypart lrxy[fpos]) ;
+ urxy[fpos] := (xpart rref, ypart urxy[fpos]) ;
+ fi ;
+
+ fi ;
+
+ somehang := (ypart ulxy[fpos]>ypart llcorner mxy) and
+ (ypart llxy[tpos]<ypart llcorner mxy) ;
+
+ if round(ypart llxy[fpos]) = round(ypart llxy[tpos]) :
+
+ % A (short) one-liner goes into the top box.
+
+ txy := llxy[fpos] -- lrxy[tpos] -- urxy[tpos] -- ulxy[fpos] -- cycle ;
+
+ elseif (round(ypart llxy[fpos]) = round(ypart ulxy[tpos])) and
+ (round(xpart lrxy[tpos]) < round(xpart llxy[fpos])) :
+
+ % We have a sentence that spans two lines but with only end
+ % of line and begin of line segments. We need to take care of
+ % indentation.
+
+ txy := llxy[fpos] -- lrxy[fpos] -- urxy[fpos] -- ulxy[fpos] -- cycle ;
+ bxy := llxy[tpos] -- lrxy[tpos] -- urxy[tpos] -- ulxy[tpos] -- cycle ;
+
+ elseif (round(ypart llxy[fpos]) = round(ypart ulxy[tpos])) :
+
+ % We have a sentence that spans two lines but with overlap.
+
+ pxy :=
+ llxy[tpos] -- lrxy[tpos] -- urxy[tpos] -- lrxy[fpos] --
+ urxy[fpos] -- ulxy[fpos] -- llxy[fpos] -- ulxy[tpos] -- cycle ;
+
+ elseif lefthang and somehang :
+
+ % We have a sentence that spans more than two lines with
+ % left hanging indentation.
+
+ pxy :=
+ llxy[tpos] -- lrxy[tpos] -- urxy[tpos] --
+ (xpart urxy[fpos],ypart urxy[tpos]) --
+ urxy[fpos] -- ulxy[fpos] -- llxy[fpos] --
+ if round(ypart urxy[tpos]) < round(ypart llcorner mxy) :
+ (xpart lrcorner mxy,ypart llxy[fpos]) --
+ lrcorner mxy --
+ (xpart llxy[tpos],ypart llcorner mxy) --
+ else :
+ (xpart llxy[tpos],ypart llxy[fpos]) --
+ fi
+ cycle ;
+
+ elseif righthang and somehang :
+
+ % We have a sentence that spans more than two lines with
+ % right hanging indentation.
+
+ pxy :=
+ llxy[tpos] -- lrxy[tpos] -- urxy[tpos] --
+ if round(ypart urxy[tpos]) < round(ypart llcorner mxy) :
+ (xpart lrcorner mxy,ypart urxy[tpos]) --
+ lrcorner mxy -- llcorner mxy --
+ else :
+ (xpart urxy[fpos],ypart urxy[tpos]) --
+ fi
+ urxy[fpos] -- ulxy[fpos] -- llxy[fpos] --
+ (xpart llxy[tpos],ypart llxy[fpos]) --
+ cycle ;
+
+ else :
+
+ % We have a sentence that spans more than two lines with
+ % no hanging indentation.
+
+ pxy :=
+ llxy[tpos] -- lrxy[tpos] -- urxy[tpos] --
+ (xpart urxy[fpos],ypart urxy[tpos]) --
+ urxy[fpos] -- ulxy[fpos] -- llxy[fpos] --
+ (xpart llxy[tpos],ypart llxy[fpos]) --
+ cycle ;
+
+ fi ;
+
+ pxy := simplified pxy ;
+ pxy := unspiked pxy ;
+
+enddef ;
+
+TopSkip := 0 ; % will move
+StrutHeight := 0 ; % will move
+
+pair last_multi_par_shift ; last_multi_par_shift := origin ;
+
+def relocate_multipars (expr xy) =
+ last_multi_par_shift := xy ;
+ for i=1 upto nofmultipars :
+ multipars[i] := multipars[i] shifted last_multi_par_shift ;
+ endfor ;
+enddef ;
+
+boolean compensate_multi_par_topskip ;
+boolean span_multi_column_pars ;
+boolean auto_multi_par_hsize ;
+boolean enable_multi_par_fallback ;
+
+compensate_multi_par_topskip := true ;
+span_multi_column_pars := false ;
+auto_multi_par_hsize := false ; % true ;
+enable_multi_par_fallback := true ;
+
+vardef multi_par_at_top (expr i) =
+ (round (ypart ulcorner multipars[i]) = round (ypart ulcorner (TextAreas[multirefs[i]] shifted last_multi_par_shift)))
+enddef ;
+
+numeric nofmultipars ; nofmultipars := 0 ;
+
+boolean obey_multi_par_hang ; obey_multi_par_hang := true ;
+boolean obey_multi_par_more ; obey_multi_par_more := true ;
+boolean snap_multi_par_tops ; snap_multi_par_tops := true ;
+boolean local_multi_par_area ; local_multi_par_area := false ;
+boolean use_multi_par_region ; use_multi_par_region := false ;
+boolean ignore_multi_par_page ; ignore_multi_par_page := false ;
+boolean force_multi_par_chain ; force_multi_par_chain := true ;
+boolean one_piece_multi_par ; one_piece_multi_par := false ;
+boolean check_multi_par_chain ; check_multi_par_chain := true ; % extra page check
+
+boolean multi_column_first_page_hack; multi_column_first_page_hack := true ; % seems to work ok
+
+def simplify_multi_pars = % boundingbox ipv shape als optie
+ for i := 1 upto nofmultipars :
+ multipars[i] := boundingbox multipars[i] ;
+ endfor ;
+enddef ;
+
+def save_multipar (expr i, l, p) =
+ nofmultipars := nofmultipars + 1 ;
+ multirefs[nofmultipars] := i ;
+ multilocs[nofmultipars] := l ;
+ multipars[nofmultipars] := unspiked (simplified p) ;
+enddef ;
+
+def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
+ tn,tx,ty,tw,th,td,
+ wn,wx,wy,ww,wh,wd,
+ pn,px,py,pw,ph,pd,
+ rw,rl,rr,rh,ra,ri) =
+
+% fill PlainTextArea withcolor red ;
+% fill RegionTextArea withcolor green;
+
+ if span_multi_column_pars :
+ begingroup ;
+ save TextAreas ; path TextAreas[] ;
+ save NOfTextAreas ; numeric NOfTextAreas ;
+ for i=1 upto NOfTextColumns :
+ TextAreas[i] := TextColumns[i] ;
+ endfor ;
+ NOfTextAreas := NOfTextColumns ;
+ fi ;
+
+ last_multi_par_shift := origin ;
+
+% save _tx_, _ty_, _fx_, _fy_ ;
+% if use_multi_par_region :
+% _fx_ := fx ; %min(xpart ulcorner RegionTextArea,fx) ;
+% _fy_ := fy ; %min(xpart ulcorner RegionTextArea,fy) ;
+% _tx_ := min(xpart lrcorner RegionTextArea,tx) ;
+% _ty_ := min(xpart lrcorner RegionTextArea,ty) ;
+% else :
+% _fx_ := fx ;
+% _fy_ := fy ;
+% _tx_ := tx ;
+% _ty_ := ty ;
+% fi ;
+
+% numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,_fx_,_fy_,fw,fh,fd) ;
+% numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,_tx_,_ty_,tw,th,td) ;
+ numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
+ numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
+ numeric wpos ; wpos := 3 ; initialize_box_pos(wpos,wn,wx,wy,ww,wh,wd) ;
+ numeric ppos ; ppos := 4 ; initialize_box_pos(ppos,pn,px,py,pw,ph,pd) ;
+
+ if local_multi_par_area :
+ RealPageNumber := fn ;
+ NOfTextAreas := 1 ;
+ NOfSavedTextAreas := 0 ;
+ TextAreas[1] := TextAreas[0] ;
+ TextColumns[1] := TextColumns[0] ;
+ nxy[fpos] := nxy[tpos] := nxy[wpos] := nxy[ppos] := RealPageNumber ;
+ elseif use_multi_par_region :
+ RealPageNumber := fn ;
+ NOfTextAreas := 1 ;
+ NOfSavedTextAreas := 0 ;
+ TextAreas[1] := RegionTextArea ;
+ TextColumns[1] := RegionTextArea ;
+ nxy[fpos] := nxy[tpos] := nxy[wpos] := nxy[ppos] := RealPageNumber ;
+ elseif ignore_multi_par_page :
+ RealPageNumber := fn ;
+ nxy[fpos] := nxy[tpos] := nxy[wpos] := nxy[ppos] := RealPageNumber ;
+ fi ;
+
+ numeric par_strut_height, par_strut_depth, par_line_height ;
+
+ set_par_line_height (ph, pd) ;
+
+ numeric par_hang_indent, par_hang_after, par_indent, par_left_skip, par_right_skip ;
+
+ par_hang_indent := rh ;
+ par_hang_after := ra ;
+ par_indent := ri ;
+ par_left_skip := rl ;
+ par_right_skip := rr ;
+
+ pair par_start_pos ;
+ pair par_stop_pos ;
+
+ par_start_pos := llxy[fpos]
+ if par_indent <0: shifted (-par_indent, 0) fi
+ if par_left_skip<0: shifted (-par_left_skip,0) fi ;
+
+ par_stop_pos := lrxy[tpos]
+ if par_right_skip<0: shifted (par_right_skip,0) fi ; % nasty as the endpos can be shifted by rightskip
+
+ if wxy[wpos]>0 :
+ left_skip := rl + xpart llxy[wpos] - xpart llxy[ppos] ;
+ right_skip := rw - left_skip - ww ;
+ else :
+ left_skip := rl ;
+ right_skip := rr ;
+ fi ;
+
+ path multipar, multipars[] ;
+ numeric multiref, multirefs[] ;
+ numeric multiloc, multilocs[] ; % 1=begin 2=between 3=end
+
+ numeric multi_par_pages ; multi_par_pages := nxy[tpos]-nxy[fpos]+1 ;
+
+ % locals .. why can't i move these outside?
+
+ vardef _pmp_set_multipar_ (expr i) =
+ ( (TextAreas[i] leftenlarged -left_skip) rightenlarged (-right_skip
+ if auto_multi_par_hsize : + rw - bbwidth(TextAreas[i]) fi) )
+ enddef ;
+
+ vardef _pmp_snapped_multi_pos_ (expr p) =
+ if snap_multi_par_tops :
+ if abs(ypart p - ypart ulcorner multipar) < par_line_height :
+ (xpart p,ypart ulcorner multipar)
+ else :
+ p
+ fi
+ else :
+ p
+ fi
+ enddef ;
+
+ vardef _pmp_estimated_par_lines_ (expr h) =
+ round(h/par_line_height)
+ enddef ;
+
+ vardef _pmp_top_multi_par_(expr p) =
+ (round(_pmp_estimated_par_lines_(bbheight(p)*par_line_height))=round(bbheight(p)))
+ enddef ;
+
+ vardef _pmp_multi_par_tsc_(expr p) =
+ if _pmp_top_multi_par_(p) : TopSkipCorrection else : 0 fi
+ enddef ;
+
+ vardef _pmp_estimated_multi_par_height_ (expr n, t) =
+ if round(par_line_height)=0 :
+ 0
+ else :
+ save ok, h ; boolean ok ;
+ numeric h ; h := 0 ;
+ ok := false ;
+ if (nxy[fpos]=RealPageNumber-1) :
+ for i := 1 upto NOfSavedTextAreas :
+ if (InsideSavedTextArea(i,par_start_pos)) :
+ ok := true ;
+ h := h + _pmp_estimated_par_lines_(ypart ulxy[fpos] - ypart llcorner SavedTextAreas[i]) ;
+ elseif ok :
+ h := h + _pmp_estimated_par_lines_(bbheight(SavedTextAreas[i])) ;
+ fi ;
+ endfor ;
+ fi ;
+ if ok :
+ for i := 1 upto n-1 :
+ h := h + _pmp_estimated_par_lines_(bbheight(TextAreas[i])) ;
+ endfor ;
+ else :
+ % already: ok := false ;
+ for i := 1 upto n-1 :
+ if (InsideTextArea(i,par_start_pos)) :
+ ok := true ;
+ h := h + _pmp_estimated_par_lines_(ypart ulxy[fpos] - ypart llcorner TextAreas[i]) ;
+ elseif ok :
+ h := h + _pmp_estimated_par_lines_(bbheight(TextAreas[i])) ;
+ fi ;
+ endfor ;
+ fi ;
+ h
+ fi
+ enddef ;
+
+ vardef _pmp_left_top_hang_ (expr same_area) =
+
+ par_hang_after := ra + _pmp_estimated_par_lines_(py-fy) ;
+
+ if (par_hang_indent>0) and (par_hang_after<0) and obey_multi_par_hang :
+ pair _ul_ ; _ul_ := (xpart ulcorner multipar, ypart _pmp_snapped_multi_pos_(ulxy[fpos]));
+ pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llxy[tpos])) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := min(0,round(par_hang_after + (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ (xpart _ul_ + par_hang_indent, ypart lrxy[fpos]) --
+ (xpart _ul_ + par_hang_indent, ypart _pa_) --
+ (xpart ulcorner multipar, ypart _pa_)
+ else :
+ (xpart ulcorner multipar, ypart lrxy[fpos])
+ fi
+ enddef ;
+
+ vardef _pmp_right_top_hang_ (expr same_area) =
+
+ par_hang_after := ra + _pmp_estimated_par_lines_(py-fy) ;
+
+ if (par_hang_indent<0) and (par_hang_after<0) and obey_multi_par_hang :
+ pair _ur_ ; _ur_ := (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos])) ;
+ pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart _pmp_snapped_multi_pos_(ulxy[tpos]))) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := min(0,round(par_hang_after + (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ (xpart urcorner multipar, ypart _pa_) --
+ (xpart _ur_ + par_hang_indent, ypart _pa_) --
+ (xpart _ur_ + par_hang_indent, ypart _pmp_snapped_multi_pos_(urxy[fpos]))
+ else :
+ (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos]))
+ fi
+ enddef ;
+
+ vardef _pmp_x_left_top_hang_ (expr i, t) =
+ par_hang_after := min(0,ra + _pmp_estimated_multi_par_height_(i,t)) ;
+ if (par_hang_indent>0) and (par_hang_after<0) :
+ pair _ul_ ; _ul_ := ulcorner multipar ;
+ pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
+ if t :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llxy[tpos]));
+ fi ;
+ if abs(ypart _pa_-ypart llxy[tpos])<par_line_height :
+ _pa_ := (xpart _pa_,ypart llxy[tpos]);
+ fi ;
+ if abs(ypart _pa_-ypart llcorner multipar)<par_line_height :
+ _pa_ := (xpart _pa_,ypart llcorner multipar);
+ fi ;
+ (xpart _ul_, ypart _pa_) --
+ (xpart _ul_ + par_hang_indent, ypart _pa_) --
+ (xpart _ul_ + par_hang_indent, ypart _ul_)
+ else :
+ ulcorner multipar
+ fi
+ enddef ;
+
+ vardef _pmp_x_right_top_hang_ (expr i, t) =
+ par_hang_after := min(0,ra + _pmp_estimated_multi_par_height_(i,t)) ;
+ if (par_hang_indent<0) and (par_hang_after<0) :
+ pair _ur_ ; _ur_ := urcorner multipar ;
+ pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
+ if t :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _pmp_snapped_multi_pos_(urxy[tpos]))) ;
+ fi ;
+ (xpart _ur_ + par_hang_indent, ypart _ur_) --
+ (xpart _ur_ + par_hang_indent, ypart _pa_) --
+ (xpart _ur_, ypart _pa_)
+ else :
+ urcorner multipar
+ fi
+ enddef ;
+
+ vardef _pmp_left_bottom_hang_ (expr same_area) =
+ pair _ll_, _sa_, _pa_ ;
+ _sa_ := if same_area : llxy[tpos] else : lrcorner multipar fi ;
+ if (par_hang_indent>0) and (par_hang_after>0) and obey_multi_par_hang :
+ _ll_ := (xpart ulcorner multipar, ypart _pmp_snapped_multi_pos_(ulxy[fpos])) ;
+ _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := max(0,round(par_hang_after - (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ _pa_ --
+ (xpart _pa_ + par_hang_indent,ypart _pa_) --
+ (xpart _pa_ + par_hang_indent,ypart _sa_)
+ else :
+ (xpart llcorner multipar, ypart _sa_)
+ fi
+ enddef ;
+
+ vardef _pmp_right_bottom_hang_ (expr same_area) =
+ pair _lr_, _sa_, _pa_ ;
+ _sa_ := if same_area : _pmp_snapped_multi_pos_(ulxy[tpos]) else : lrcorner multipar fi ;
+ if (par_hang_indent<0) and (par_hang_after>0) and obey_multi_par_hang :
+ _lr_ := (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos])) ;
+ _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
+ if same_area :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _pmp_snapped_multi_pos_(ulxy[tpos]))) ;
+ fi ;
+ if obey_multi_par_more and (round(par_line_height)>0) :
+ par_hang_after := max(0,round(par_hang_after - (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
+ fi ;
+ (xpart _pa_ + par_hang_indent,ypart _sa_) --
+ (xpart _pa_ + par_hang_indent,ypart _pa_) --
+ _pa_
+ else :
+ (xpart lrcorner multipar, ypart _sa_)
+ fi
+ enddef ;
+
+ vardef _pmp_x_left_bottom_hang_ (expr i, t) =
+ pair _ll_, _sa_, _pa_ ;
+ _sa_ := if t : llxy[tpos] else : llcorner multipar fi ;
+ if (par_hang_indent>0) and (ra>0) :
+ par_hang_after := max(0,ra - _pmp_estimated_multi_par_height_(i,t)) ;
+ _ll_ := ulcorner multipar ;
+ _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
+ % we need to compensate for topskip enlarged areas
+ if abs(ypart _pa_ - ypart _sa_) > par_line_height :
+ (xpart _pa_ + par_hang_indent,ypart _sa_) --
+ (xpart _pa_ + par_hang_indent,ypart _pa_) --
+ fi
+ _pa_
+ else :
+ (xpart llcorner multipar, ypart _sa_)
+ fi
+ enddef ;
+
+ vardef _pmp_x_right_bottom_hang_ (expr i, t) =
+ pair _lr_, _sa_, _pa_ ;
+ _sa_ := if t : _pmp_snapped_multi_pos_(ulxy[tpos]) else : llcorner multipar fi ;
+ if (par_hang_indent<0) and (ra>0) :
+ par_hang_after := max(0,ra - _pmp_estimated_multi_par_height_(i, t)) ;
+ _lr_ := urcorner multipar ;
+ _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
+ % we need to compensate for topskip enlarged areas
+ _pa_
+ if abs(ypart _pa_ - ypart _sa_) > par_line_height :
+ -- (xpart _pa_ + par_hang_indent,ypart _pa_)
+ -- (xpart _pa_ + par_hang_indent,ypart _sa_)
+ fi
+ else :
+ (xpart lrcorner multipar, ypart _sa_)
+ fi
+ enddef ;
+
+ % def _pmp_test_multipar_ =
+ % multipar := boundingbox multipar ;
+ % enddef ;
+
+ % first loop
+
+ ii := 0 ; nn := NOfTextAreas+1 ; nofmultipars := 0 ;
+
+ if enable_multi_par_fallback and (nxy[fpos]=RealPageNumber)
+ and (nxy[tpos]=RealPageNumber) and not (InsideSomeTextArea(lxy[fpos]) and InsideSomeTextArea(rxy[tpos])) :
+
+ % fallback
+
+ % multipar :=
+ % llxy[fpos] --
+ % lrxy[tpos] --
+ % urxy[tpos] --
+ % ulxy[fpos] -- cycle ;
+ %
+ % save_multipar (1,1,multipar) ;
+
+ % we need to take the boundingbox because there can be
+ % more lines and we want a proper rectange
+
+ multipar :=
+ ulxy[fpos] --
+ urxy[tpos] --
+ lrxy[fpos] --
+ llxy[tpos] -- cycle ;
+
+ save_multipar (1,1,boundingbox(multipar)) ;
+
+ else :
+
+ % normal
+
+ for i=1 upto NOfTextAreas :
+
+ TopSkipCorrection := 0 ;
+
+ multipar := _pmp_set_multipar_(i) ;
+
+ % watch how we compensate for negative indentation
+
+ if (nxy[fpos]=RealPageNumber) and (InsideTextArea(i,par_start_pos)) :
+
+ % first one in chain
+
+ ii := i ;
+
+ if (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,par_stop_pos)) :
+
+ % in same area
+
+ nn := i ;
+
+ if compensate_multi_par_topskip and (round(LineHeight-ph-pd)=0) :
+
+ TopSkipCorrection := TopSkip - StrutHeight ;
+
+ if round(ypart ulxy[fpos] + TopSkipCorrection) = round(ypart ulcorner TextAreas[i]) :
+ ulxy[fpos] := ulxy[fpos] shifted (0,TopSkipCorrection) ;
+ urxy[fpos] := urxy[fpos] shifted (0,TopSkipCorrection) ;
+ else :
+ TopSkipCorrection := 0 ;
+ fi ;
+
+ fi ;
+
+ if ypart llxy[fpos] = ypart llxy[tpos] :
+
+ multipar :=
+ llxy[fpos] --
+ lrxy[tpos] --
+ _pmp_snapped_multi_pos_(urxy[tpos]) --
+ _pmp_snapped_multi_pos_(ulxy[fpos]) --
+ cycle ;
+
+ save_multipar (i,1,multipar) ;
+
+ elseif (ypart llxy[fpos] = ypart ulxy[tpos]) and (xpart llxy[tpos] < xpart llxy[fpos]) :
+
+ % two loners
+
+ multipar := if obey_multi_par_hang :
+
+ _pmp_right_bottom_hang_(true) --
+ _pmp_right_top_hang_(true) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
+ lrxy[fpos] --
+
+ else :
+
+ llxy[fpos] --
+ (xpart urcorner multipar, ypart llxy[fpos]) --
+ (xpart urcorner multipar, ypart ulxy[fpos]) --
+ _pmp_snapped_multi_pos_(ulxy[fpos]) --
+
+ fi cycle ;
+
+ save_multipar (i,1,multipar) ;
+
+ multipar := _pmp_set_multipar_(i) ;
+
+ multipar := if obey_multi_par_hang :
+
+ _pmp_left_bottom_hang_(true) --
+ llxy[tpos] --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ _pmp_left_top_hang_(true) --
+
+ else :
+
+ (xpart llcorner multipar, ypart llxy[tpos]) --
+ llxy[tpos] --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ (xpart llcorner multipar, ypart ulxy[tpos]) --
+
+ fi cycle ;
+
+ save_multipar (i,1,multipar) ;
+
+ else :
+
+ multipar := if obey_multi_par_hang :
+
+ _pmp_left_bottom_hang_(true) --
+ llxy[tpos] --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ _pmp_right_bottom_hang_(true) --
+ _pmp_right_top_hang_(true) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
+ lrxy[fpos] --
+ _pmp_left_top_hang_(true) --
+
+ else :
+
+ (xpart llcorner multipar, ypart llxy[tpos]) --
+ llxy[tpos] --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ (xpart lrcorner multipar, ypart ulxy[tpos]) --
+ (xpart urcorner multipar, ypart urxy[fpos]) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
+ lrxy[fpos] --
+ (xpart ulcorner multipar, ypart lrxy[fpos]) --
+
+ fi cycle ;
+
+ save_multipar (i,1,multipar) ;
+
+ fi ;
+
+ else :
+
+ multipar := if obey_multi_par_hang :
+
+ _pmp_left_bottom_hang_(false) --
+ _pmp_right_bottom_hang_(false) --
+ _pmp_right_top_hang_(false) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
+ lrxy[fpos] --
+ _pmp_left_top_hang_(false) --
+
+ else :
+
+ llcorner multipar --
+ lrcorner multipar --
+ (xpart urcorner multipar, ypart urxy[fpos]) --
+ _pmp_snapped_multi_pos_(urxy[fpos]) --
+ lrxy[fpos] --
+ (xpart ulcorner multipar, ypart lrxy[fpos]) --
+
+ fi cycle ;
+
+ save_multipar (i,1,multipar) ;
+
+ fi ;
+
+ elseif (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,par_stop_pos)) :
+
+ % last one in chain
+
+ nn := i ;
+
+ if obey_multi_par_hang and obey_multi_par_more :
+
+ multipar :=
+ _pmp_x_left_top_hang_(i,true) --
+ _pmp_x_right_top_hang_(i,true) --
+ _pmp_x_right_bottom_hang_(i,true) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ llxy[tpos] --
+ _pmp_x_left_bottom_hang_(i,true) --
+ cycle ;
+
+ else :
+
+ multipar :=
+ ulcorner multipar --
+ urcorner multipar --
+ (xpart lrcorner multipar, ypart urxy[tpos]) --
+ _pmp_snapped_multi_pos_(ulxy[tpos]) --
+ llxy[tpos] --
+ (xpart llcorner multipar, ypart llxy[tpos]) --
+ cycle ;
+
+ fi ;
+
+ save_multipar (i,3,multipar) ;
+
+ elseif multi_column_first_page_hack and ((nxy[fpos]=RealPageNumber) and (nxy[tpos]>=RealPageNumber) and (NOfTextColumns>1)) :
+
+ save_multipar (i,2,multipar) ;
+
+ else :
+ % handled later
+ fi ;
+
+ endfor ;
+
+
+ % second loop
+
+ if force_multi_par_chain or (ii > 1) :
+
+ for i=ii+1 upto nn-1 :
+
+ % rest of chain / todo : hang
+
+ % hm, the second+ column in column sets now gets lost in a NOfTextColumns
+
+ if (not check_multi_par_chain) or ((nxy[fpos]<RealPageNumber) and (nxy[tpos]>RealPageNumber)) :
+
+ multipar := _pmp_set_multipar_(i) ;
+
+ if obey_multi_par_hang and obey_multi_par_more :
+
+ multipar :=
+ _pmp_x_left_top_hang_(i,false) --
+ _pmp_x_right_top_hang_(i,false) --
+ _pmp_x_right_bottom_hang_(i,false) --
+ _pmp_x_left_bottom_hang_(i,false) --
+ cycle ;
+
+ fi ;
+
+ save_multipar(i,2,multipar) ;
+
+ fi ;
+
+ endfor ;
+
+ fi ;
+
+ % end of normal/fallback
+
+ fi ;
+
+ if span_multi_column_pars :
+ endgroup ;
+ fi ;
+
+ % potential safeguard:
+
+ % for i=1 upto nofmultipars :
+ % if length p <= 4 :
+ % multipars[i] := boundingbox(multipars[i]) ;
+ % fi ;
+ % end ;
+
+ % quick hack for gb:
+
+ one_piece_multi_par := (nofmultipars=1) and (pn=tn) ;
+
+enddef ;
+
+def boxgridoptions = withcolor .8red enddef ;
+def boxlineoptions = withcolor .8blue enddef ;
+def boxfilloptions = withcolor .8white enddef ;
+
+numeric boxgridtype ; boxgridtype := 0 ;
+numeric boxlinetype ; boxlinetype := 1 ;
+numeric boxfilltype ; boxfilltype := 1 ;
+numeric boxdashtype ; boxdashtype := 0 ;
+pair boxgriddirection ; boxgriddirection := up ;
+numeric boxgridwidth ; boxgridwidth := 1pt ;
+numeric boxlinewidth ; boxlinewidth := 1pt ;
+numeric boxlineradius ; boxlineradius := 0pt ;
+numeric boxfilloffset ; boxfilloffset := 0pt ;
+numeric boxgriddistance ; boxgriddistance := .5cm ;
+numeric boxgridshift ; boxgridshift := 0pt ;
+
+def draw_box =
+ draw pxy boxlineoptions withpen pencircle scaled boxlinewidth ;
+ draw lxy -- rxy boxlineoptions withpen pencircle scaled boxgridwidth ;
+enddef ;
+
+def draw_par = % 1 2 3 11 12
+ do_draw_par(pxy) ; do_draw_par(txy) ; do_draw_par(bxy) ;
+ for i = pxy, txy, bxy :
+ if boxgridtype = 1 :
+ boxgriddirection := origin ;
+ draw baseline_grid (i,boxgriddirection,true ) boxgridoptions ;
+ elseif boxgridtype = 2 :
+ boxgriddirection := origin ;
+ draw baseline_grid (i,boxgriddirection,false) boxgridoptions ;
+ elseif boxgridtype = 3 :
+ boxgriddirection := origin ;
+ draw baseline_grid (i,boxgriddirection,true ) boxgridoptions ;
+ draw baseline_grid (i,boxgriddirection,true ) shifted (0,ExHeight) boxgridoptions ;
+ elseif boxgridtype = 4 :
+ boxgriddirection := origin ;
+ draw baseline_grid (i,boxgriddirection,true ) shifted (0,ExHeight/2) boxgridoptions ;
+ elseif boxgridtype = 11 :
+ draw graphic_grid(i,boxgriddistance,boxgriddistance,boxgriddistance/2,boxgriddistance/2) ;
+ elseif boxgridtype = 12 :
+ draw graphic_grid(i,boxgriddistance,boxgriddistance,0,0) ;
+ fi ;
+ endfor ;
+enddef ;
+
+def do_show_par (expr p, r, c) =
+ if length(p) > 2 :
+ for i=0 upto length(p) :
+ draw fullcircle scaled r shifted point i of p withpen pencircle scaled .5pt withcolor c ;
+ endfor ;
+ fi ;
+ draw p withpen pencircle scaled .5pt withcolor c ;
+enddef ;
+
+def show_par =
+ if length(mxy) > 2 :
+ draw mxy dashed evenly withpen pencircle scaled .5pt withcolor .5white ;
+ fi ;
+ do_show_par(txy, 4pt, .5green) ;
+ do_show_par(bxy, 6pt, .5blue ) ;
+ do_show_par(pxy, 8pt, .5red ) ;
+ draw pref withpen pencircle scaled 2pt ;
+enddef ;
+
+def sort_multi_pars =
+ if nofmultipars>1 :
+ begingroup ;
+ save _p_, _n_ ; path _p_ ; numeric _n_ ;
+ for i := 1 upto nofmultipars :
+ if multilocs[i] = 3 :
+ _p_ := multipars[nofmultipars] ;
+ multipars[nofmultipars] := multipars[i] ;
+ multipars[i] := _p_ ;
+ _n_ := multirefs[nofmultipars] ;
+ multirefs[nofmultipars] := multirefs[i] ;
+ multirefs[i] := _n_ ;
+ _n_ := multilocs[nofmultipars] ;
+ multilocs[nofmultipars] := multilocs[i] ;
+ multilocs[i] := _n_ ;
+ fi ;
+ endfor ;
+ endgroup ;
+ fi ;
+enddef ;
+
+def collapse_multi_pars =
+ if nofmultipars>1 :
+ begingroup ;
+ save _nofmultipars_ ; numeric _nofmultipars_ ;
+ _nofmultipars_ := 1 ;
+ sort_multi_pars ; % block not in order: 1, 3, 2....
+ for i:=1 upto nofmultipars-1 :
+ if (round(xpart(llcorner multipars[i]-llcorner multipars[i+1]))=0) and
+ (round(xpart(lrcorner multipars[i]-lrcorner multipars[i+1]))=0) :
+ multilocs[_nofmultipars_] := multilocs[i+1] ;
+ multirefs[_nofmultipars_] := multirefs[i+1] ;
+ multipars[_nofmultipars_] :=
+ ulcorner multipars[_nofmultipars_] --
+ urcorner multipars[_nofmultipars_] --
+ lrcorner multipars[i+1] --
+ llcorner multipars[i+1] -- cycle ;
+ else :
+ _nofmultipars_ := _nofmultipars_ + 1 ;
+ multipars[_nofmultipars_] := multipars[i+1] ;
+ multilocs[_nofmultipars_] := multilocs[i+1] ;
+ multirefs[_nofmultipars_] := multirefs[i+1] ;
+ fi ;
+ endfor ;
+ nofmultipars := _nofmultipars_ ;
+ endgroup ;
+ fi ;
+enddef ;
+
+def draw_multi_pars =
+ for i=1 upto nofmultipars :
+ do_draw_par(multipars[i]) ;
+ if boxgridtype= 1 :
+ draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) ;
+ elseif boxgridtype= 2 :
+ draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,false) ;
+ elseif boxgridtype= 3 :
+ draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) ;
+ draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight) ;
+ elseif boxgridtype= 4 :
+ draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight/2) ;
+ elseif boxgridtype=11 :
+ draw graphic_grid(multipars[i],boxgriddistance,boxgriddistance,boxgriddistance/2,boxgriddistance/2) ;
+ elseif boxgridtype=12 :
+ draw graphic_grid(multipars[i],boxgriddistance,boxgriddistance,0,0) ;
+ fi ;
+ endfor ;
+enddef ;
+
+def show_multi_pars =
+ for i=1 upto nofmultipars :
+ do_show_par(multipars[i], 6pt, .5blue) ;
+ endfor ;
+enddef ;
+
+vardef do_draw_par (expr p) =
+ if (length p>2) and (bbwidth(p)>1) and (bbheight(p)>1) :
+ save pp ; path pp ;
+ if (boxlineradius>0) and (boxlinetype=2) :
+ pp := p cornered boxlineradius ;
+ else :
+ pp := p ;
+ fi ;
+ if boxfilltype>0 :
+ if boxfilloffset>0 :
+ % temporary hack
+ begingroup ;
+ interim linejoin := mitered ;
+ filldraw pp boxfilloptions withpen pencircle scaled (2*boxfilloffset) ;
+ endgroup ;
+ else :
+ fill pp boxfilloptions ;
+ fi ;
+ fi ;
+ if boxlinetype>0 :
+ draw pp boxlineoptions withpen pencircle scaled boxlinewidth ;
+ fi ;
+ fi ;
+enddef ;
+
+vardef baseline_grid (expr pxy, pdir, at_baseline) =
+ save width ; width := bbwidth(pxy) ;
+ save height ; height := bbheight(pxy) ;
+ if (par_line_height>0) and (height>1) and (width>1) and (boxgridwidth>0) :
+ save i, grid, bb ; picture grid ; pair start ; path bb ;
+ def _do_ (expr start) =
+ % 1 = normal, 2 = with background (i.e. no shine-through)
+ if boxdashtype = 2 :
+ draw start -- start shifted (width,0)
+ withpen pencircle scaled boxgridwidth
+ boxfilloptions ;
+ fi ;
+ draw start -- start shifted (width,0)
+ if boxdashtype > 0 :
+ dashed evenly
+ fi
+ withpen pencircle scaled boxgridwidth
+ boxgridoptions ;
+ enddef ;
+ grid := image ( % fails with inlinespace
+ if pdir=up :
+ for i = if at_baseline : par_strut_depth else : 0 fi step par_line_height until max(height,par_line_height) :
+ _do_ (llcorner pxy shifted (0,+i)) ;
+ endfor ;
+ else :
+ for i = if at_baseline : par_strut_height else : 0 fi step par_line_height until height :
+ _do_ (ulcorner pxy shifted (0,-i)) ;
+ endfor ;
+ fi ;
+ ) ;
+ clip grid to pxy ;
+ bb := boundingbox grid ;
+ grid := grid shifted (0,boxgridshift) ;
+ setbounds grid to bb ;
+ grid
+ else :
+ nullpicture
+ fi
+enddef ;
+
+vardef graphic_grid (expr pxy, dx, dy, x, y) =
+ if (bbheight(pxy)>dy) and (bbwidth(pxy)>dx) and (boxgridwidth>0) :
+ save grid ; picture grid ;
+ grid := image (
+ for i = xpart llcorner pxy step dx until xpart lrcorner pxy :
+ draw (i,ypart llcorner pxy) -- (i,ypart ulcorner pxy) withpen pencircle scaled boxgridwidth ;
+ endfor ;
+ for i = ypart llcorner pxy step dy until ypart ulcorner pxy :
+ draw (xpart llcorner pxy,i) -- (xpart lrcorner pxy,i) withpen pencircle scaled boxgridwidth ;
+ endfor
+ ) shifted (x,y) ;
+ clip grid to pxy ;
+ grid
+ else :
+ nullpicture
+ fi
+enddef ;
+
+def anchor_box (expr n,x,y,w,h,d) =
+ currentpicture := currentpicture shifted (-x,-y) ;
+enddef ;
+
+let draw_area = draw_box ;
+let anchor_area = anchor_box ;
+let anchor_par = anchor_box ;
+
+numeric sync_n[], sync_p[][], sync_w[][], sync_h[][], sync_d[][], sync_t[][] ;
+pair sync_xy[][] ; color sync_c[][] ;
+
+def ResetSyncTasks =
+ path SyncPaths[] ; numeric SyncTasks[], NOfSyncPaths, CurrentSyncClass ;
+ NOfSyncPaths := CurrentSyncClass := 0 ;
+ if unknown SyncLeftOffset : numeric SyncLeftOffset ; SyncLeftOffset := 0 ; fi ;
+ if unknown SyncWidth : numeric SyncWidth ; SyncWidth := 0 ; fi ;
+ if unknown SyncThreshold : numeric SyncThreshold ; SyncThreshold := LineHeight ; fi ;
+ if unknown SyncColor : color SyncColor ; SyncColor := .5white ; fi ;
+ if (SyncLeftOffset = 0) and (SyncWidth = 0) :
+ SyncWidth := if known TextWidth : TextWidth else : -1cm fi ;
+ fi ;
+enddef ;
+
+ResetSyncTasks ;
+
+vardef SyncBox(expr n, i, leftoffset, width, topoffset, bottomoffset) =
+ save o ; pair o ; o := (xpart llcorner PlainTextArea,ypart sync_xy[n][i]) ;
+ o shifted (leftoffset,sync_h[n][i]+topoffset) --
+ o shifted (width+leftoffset,sync_h[n][i]+topoffset) --
+ o shifted (width+leftoffset,bottomoffset) --
+ o shifted (leftoffset,bottomoffset) -- cycle
+enddef ;
+
+def SetSyncColor(expr n, i, c) =
+ sync_c[n][i] := c ;
+enddef ;
+
+def SetSyncThreshold(expr n, i, th) =
+ sync_th[n][i] := th ;
+enddef ;
+
+vardef TheSyncColor(expr n, i) =
+ if known sync_c[n][i] : sync_c[n][i] else : SyncColor fi
+enddef ;
+
+vardef TheSyncThreshold(expr n, i) =
+ if known sync_th[n][i] : sync_th[n][i] else : SyncThreshold fi
+enddef ;
+
+vardef PrepareSyncTasks(expr n, collapse, extendtop, prestartnext) =
+ ResetSyncTasks ;
+ if known sync_n[n] :
+ CurrentSyncClass := n ;
+ save ok, l, d ; boolean ok ; ok := false ; NOfSyncPaths := l := 0 ;
+ for i=1 upto sync_n[n] :
+ if RealPageNumber > sync_p[n][i] :
+ l := i ;
+ elseif RealPageNumber = sync_p[n][i] :
+ NOfSyncPaths := NOfSyncPaths + 1 ;
+ if not ok :
+ if i>1 :
+ if sync_t[n][i-1] = sync_t[n][i] :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ else :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i-1, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i-1 ;
+ NOfSyncPaths := NOfSyncPaths + 1 ;
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ fi ;
+ else :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ fi ;
+ else :
+ SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := i ;
+ fi ;
+ ok := true ;
+ fi ;
+ endfor ;
+ if (NOfSyncPaths = 0) and (l > 0) :
+ NOfSyncPaths := 1 ;
+ SyncPaths[NOfSyncPaths] := SyncBox(n, l, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
+ SyncTasks[NOfSyncPaths] := l ;
+ fi ;
+ if NOfSyncPaths > 0 :
+ for i = 1 upto NOfSyncPaths-1 :
+ SyncPaths[i] := topboundary SyncPaths[i] -- reverse topboundary SyncPaths[i+1] -- cycle ;
+ endfor ;
+ if unknown SyncThresholdMethod :
+ numeric SyncThresholdMethod ; SyncThresholdMethod := 2 ;
+ fi ;
+ if extendtop :
+ if SyncThresholdMethod = 1 :
+ if NOfSyncPaths>1 :
+ d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[2]]) ;
+ if (SyncTasks[2]>1) and (d > 0pt) and (d <= TheSyncThreshold(n,sync_t[n][SyncTasks[2]])) and (sync_p[n][SyncTasks[2]] = RealPageNumber) :
+ SyncPaths[2] := SyncPaths[2] topenlarged PaperHeight ;
+ fi ;
+ fi ;
+ else :
+ for i = 1 upto NOfSyncPaths :
+ d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[i]]) ;
+ if (d > 0) and (d <= TheSyncThreshold(n,sync_t[n][SyncTasks[i]])) and (sync_p[n][SyncTasks[i]] = RealPageNumber) :
+ SyncPaths[i] := SyncPaths[i] topenlarged PaperHeight ;
+ fi ;
+ endfor ;
+ fi ;
+ fi ;
+ if prestartnext :
+ if NOfSyncPaths>1 :
+ if SyncTasks[NOfSyncPaths] < sync_n[n] : % there is a next one
+ d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[NOfSyncPaths]+1]) ;
+ if (d > 0) and (d <= TheSyncThreshold(n, sync_t[n][SyncTasks[i]])) and (sync_p[n][SyncTasks[NOfSyncPaths]+1] = RealPageNumber+1) :
+ SyncPaths[NOfSyncPaths+1] :=
+ (xpart ulcorner SyncPaths[NOfSyncPaths],ypart llcorner PlainTextArea) --
+ (xpart urcorner SyncPaths[NOfSyncPaths],ypart llcorner PlainTextArea) --
+ lrcorner SyncPaths[NOfSyncPaths] --
+ llcorner SyncPaths[NOfSyncPaths] -- cycle ;
+ SyncTasks[NOfSyncPaths+1] := SyncTasks[NOfSyncPaths]+1 ;
+ NOfSyncPaths := NOfSyncPaths + 1 ;
+ fi ;
+ fi ;
+ fi ;
+ else :
+ if NOfSyncPaths>1 :
+ d := ypart (sync_xy[n][SyncTasks[NOfSyncPaths]] - llcorner PlainTextArea) ;
+ if (d < TheSyncThreshold(n, SyncTasks[NOfSyncPaths])) :
+ NOfSyncPaths := NOfSyncPaths - 1 ;
+ SyncPaths[NOfSyncPaths] := SyncPaths[NOfSyncPaths] bottomenlarged PaperHeight ;
+ fi ;
+ fi ;
+ fi ;
+ if (NOfSyncPaths>1) and collapse :
+ save j ; numeric j ; j := 1 ;
+ for i = 2 upto NOfSyncPaths :
+ if sync_t[n][SyncTasks[i]] = sync_t[n][SyncTasks[j]] :
+ SyncPaths[j] := boundingbox image (draw SyncPaths[i] ; draw SyncPaths[j] ; ) ;
+ SyncTasks[j] := SyncTasks[i] ;
+ else :
+ j := j + 1 ;
+ SyncPaths[j] := SyncPaths[i] ;
+ SyncTasks[j] := SyncTasks[i] ;
+ fi ;
+ endfor ;
+ NOfSyncPaths := j ;
+ fi ;
+ fi ;
+ fi ;
+enddef ;
+
+def SyncTask(expr n) =
+ if known SyncTasks[n] : SyncTasks[n] else : 0 fi
+enddef ;
+
+def FlushSyncTasks =
+ for i = 1 upto NOfSyncPaths :
+ ProcessSyncTask(SyncPaths[i], TheSyncColor(CurrentSyncClass,sync_t[CurrentSyncClass][SyncTasks[i]])) ;
+ endfor ;
+enddef ;
+
+def ProcessSyncTask(expr p, c) =
+ fill p withcolor c ;
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-cows.mpiv b/metapost/context/base/mpiv/mp-cows.mpiv
new file mode 100644
index 000000000..3ad1a98f5
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-cows.mpiv
@@ -0,0 +1,156 @@
+%D \module
+%D [ file=mp-cows.mpiv,
+%D version=2015.05.27,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=the cow,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_cows : endinput ; fi ;
+
+boolean context_cows ; context_cows := true ;
+
+picture cow ; cow := image (
+ fill (245.449005,600.340027)..controls (242.781006,599.398010) and (239.621002,596.020020)..(237.671997,594.070007)
+ ..controls (236.738007,584.421997) and (244.578003,583.629028)..(250.199005,577.440979)
+ ..controls (258.769989,573.698975) and (251.210999,567.718994)..(256.179993,557.421997)
+ ..controls (257.039001,550.940979) and (257.898010,543.890991)..(255.309006,539.781006)
+ ..controls (249.479996,538.921997) and (247.968994,540.218994)..(246.891006,531.429993)
+ ..controls (246.309006,526.968994) and (231.770004,529.059021)..(229.031006,538.270020)
+ ..controls (227.089996,544.968994) and (221.328003,546.698975)..(217.800995,543.171997)
+ ..controls (213.770004,538.059021) and (215.781006,531.218994)..(217.800995,527.468994)
+ ..controls (224.929993,517.320007) and (212.039001,511.421997)..(205.128998,516.737976)
+ ..controls (199.729996,508.679993) and (211.391006,500.039001)..(207.429993,494.500000)
+ ..controls (205.781006,493.988007) and (204.770004,489.171997)..(185.468994,500.539001)
+ ..controls (180.358994,504.140991) and (167.828003,500.761993)..(168.770004,520.629028)
+ ..controls (168.770004,525.820007) and (165.602005,543.531006)..(162.141006,555.909973)
+ ..controls (159.410004,561.237976) and (156.738007,559.078003)..(156.891006,553.898010)
+ ..controls (157.179993,547.851990) and (162.940994,531.218994)..(155.520004,540.218994)
+ ..controls (153.578003,539.210999) and (156.891006,523.578003)..(156.891006,521.640991)
+ ..controls (162.000000,517.031006) and (157.391006,513.578003)..(154.729996,512.281006)
+ ..controls (151.270004,518.328003) and (149.621002,518.039001)..(147.171997,514.440979)
+ ..controls (141.699005,514.078003) and (144.578003,528.190979)..(140.261993,528.620972)
+ ..controls (137.020004,527.762024) and (139.179993,520.059021)..(138.238007,518.762024)
+ ..controls (132.979996,524.737976) and (130.897995,529.270020)..(127.012001,521.640991)
+ ..controls (126.140999,521.640991) and (122.109001,519.190979)..(120.960999,526.539001)
+ ..controls (117.648003,552.737976) and (107.058998,558.359009)..(93.820297,565.129028)
+ ..controls (92.019501,565.629028) and (84.238297,566.710999)..(79.339798,568.148010)
+ ..controls (73.511703,560.879028) and (58.320301,565.629028)..(56.230499,570.309021)
+ ..controls (54.789101,572.690979) and (54.648399,575.210999)..(54.789101,576.500000)
+ ..controls (52.339802,580.101990) and (55.871101,582.698975)..(59.621101,583.059021)
+ ..controls (62.859402,587.159973) and (68.539101,594.940979)..(71.281303,601.559021)
+ ..controls (72.289101,603.070007) and (74.949203,609.340027)..(78.191399,609.551025)
+ ..controls (74.949203,612.940979) and (74.300797,622.512024)..(82.660202,617.328003)
+ ..controls (87.121101,624.020020) and (92.089798,624.309021)..(95.761703,615.820007)
+ ..controls (102.890999,615.379028) and (102.308998,608.690979)..(115.780998,605.520020)
+ ..controls (122.762001,602.859009) and (132.770004,604.578003)..(140.261993,603.718994)
+ ..controls (136.218994,596.879028) and (127.441002,566.859009)..(132.979996,559.801025)
+ ..controls (140.761993,564.698975) and (141.839996,605.379028)..(157.031006,595.659973)
+ ..controls (160.559006,593.929993) and (159.910004,590.039001)..(164.089996,590.179993)
+ ..controls (170.421997,587.448975) and (169.128998,600.770020)..(172.511993,600.770020)
+ ..controls (176.468994,599.762024) and (183.020004,599.039001)..(186.979996,599.539001)
+ ..controls (197.710999,600.770020) and (206.929993,604.078003)..(223.921997,602.500000)
+ ..controls (231.121002,601.781006) and (238.250000,601.059021)..(245.449005,600.340027)
+ --cycle;
+ fill (305.281006,560.948975)..controls (304.628998,560.948975) and (299.949005,561.237976)..(299.378998,561.237976)
+ ..controls (302.398010,550.440979) and (303.980011,536.468994)..(304.199005,525.309021)
+ ..controls (303.699005,521.351990) and (299.808990,517.460999)..(299.378998,525.671997)
+ ..controls (295.851990,530.859009) and (296.421997,540.070007)..(293.398010,540.289001)
+ ..controls (287.351990,539.640991) and (285.339996,513.218994)..(280.011993,509.328003)
+ ..controls (276.261993,512.281006) and (280.730011,524.020020)..(275.539001,524.737976)
+ ..controls (270.500000,524.020020) and (264.308990,526.679993)..(266.691010,534.460999)
+ ..controls (270.289001,543.020020) and (268.339996,554.762024)..(266.539001,561.601990)
+ ..controls (262.371002,578.590027) and (264.019989,587.090027)..(271.578003,596.090027)
+ --(267.480011,604.512024)..controls (275.398010,608.262024) and (285.621002,604.578003)..(290.019989,602.210999)
+ ..controls (294.621002,600.262024) and (300.238007,595.940979)..(301.101990,587.379028)
+ ..controls (303.339996,578.879028) and (304.421997,569.737976)..(305.281006,560.948975)
+ --cycle;
+ pickup pencircle scaled 2.000000bp;
+ draw (84.378899,618.551025)..controls (88.339798,624.379028) and (92.589798,622.940979)..(96.339798,615.671997)
+ ..controls (101.230003,615.601990) and (102.460999,612.429993)..(104.980003,610.781006)
+ ..controls (122.621002,598.390991) and (147.460999,607.179993)..(167.897995,601.921997)
+ ..controls (180.940994,598.539001) and (190.871002,599.762024)..(200.089996,602.059021)
+ ..controls (220.320007,607.250000) and (246.102005,596.159973)..(263.738007,603.859009)
+ ..controls (274.750000,608.620972) and (284.761993,605.659973)..(292.968994,600.909973)
+ ..controls (297.578003,597.960999) and (299.589996,596.090027)..(300.960999,591.262024)
+ ..controls (306.289001,572.539001) and (306.289001,551.020020)..(309.531006,530.570007)
+ ..controls (309.531006,528.840027) and (312.191010,526.101990)..(312.480011,522.070007)
+ ..controls (315.789001,511.339996) and (316.078003,510.121002)..(317.160004,502.199005)
+ ..controls (317.160004,501.339996) and (326.519989,488.449005)..(325.011993,479.019989)
+ ..controls (323.929993,481.250000) and (323.859009,482.828003)..(321.621002,481.679993)
+ ..controls (320.328003,479.300995) and (320.898010,473.898010)..(322.558990,471.738007)
+ ..controls (320.828003,470.808990) and (318.460999,473.468994)..(317.519989,475.199005)
+ ..controls (318.171997,473.039001) and (317.808990,470.808990)..(316.730011,469.300995)
+ ..controls (315.859009,472.250000) and (316.578003,473.179993)..(315.359009,473.898010)
+ ..controls (313.988007,472.898010) and (314.210999,469.300995)..(314.281006,466.199005)
+ ..controls (313.488007,468.070007) and (311.468994,472.460999)..(312.550995,476.421997)
+ ..controls (312.480011,484.199005) and (308.808990,489.101990)..(310.320007,499.101990)
+ ..controls (310.101990,504.429993) and (307.300995,521.059021)..(304.558990,524.301025)
+ ..controls (303.121002,526.250000) and (306.359009,510.769989)..(306.359009,506.160004)
+ ..controls (306.648010,500.898010) and (307.078003,468.718994)..(306.429993,463.101990)
+ ..controls (306.429993,459.218994) and (306.218994,453.960999)..(307.078003,452.160004)
+ ..controls (308.738007,450.789001) and (309.378998,450.500000)..(309.601990,447.980011)
+ ..controls (309.238007,446.621002) and (308.738007,446.039001)..(307.730011,445.539001)
+ ..controls (306.070007,444.601990) and (307.371002,441.789001)..(306.070007,439.851990)
+ ..controls (304.488007,438.769989) and (304.128998,441.859009)..(303.339996,441.859009)
+ ..controls (302.691010,441.000000) and (303.050995,437.980011)..(302.468994,436.179993)
+ ..controls (299.660004,433.800995) and (292.179993,432.500000)..(289.148010,434.660004)
+ ..controls (289.730011,440.640991) and (291.738007,441.578003)..(295.628998,446.621002)
+ ..controls (298.660004,452.589996) and (297.000000,460.941010)..(296.929993,468.140991)
+ ..controls (295.488007,480.378998) and (289.218994,487.300995)..(289.441010,496.441010)
+ ..controls (287.859009,495.718994) and (286.421997,494.570007)..(284.261993,494.859009)
+ ..controls (283.390991,489.460999) and (286.421997,484.558990)..(284.828003,480.820007)
+ ..controls (281.949005,471.960999) and (277.058990,446.621002)..(279.000000,437.761993)
+ ..controls (280.011993,434.738007) and (278.210999,433.148010)..(277.058990,433.941010)
+ ..controls (276.769989,433.941010) and (276.550995,433.941010)..(276.410004,433.941010)
+ ..controls (276.410004,433.941010) and (276.550995,431.421997)..(275.691010,430.921997)
+ ..controls (274.101990,430.339996) and (273.671997,431.710999)..(272.660004,432.140991)
+ ..controls (271.218994,430.851990) and (272.519989,429.480011)..(271.148010,428.039001)
+ ..controls (267.191010,428.039001) and (261.359009,425.378998)..(257.980011,428.261993)
+ ..controls (257.328003,434.160004) and (263.300995,436.679993)..(266.468994,440.710999)
+ ..controls (268.628998,446.621002) and (271.078003,462.890991)..(267.769989,474.621002)
+ ..controls (267.769989,475.558990) and (264.378998,485.281006)..(261.429993,488.660004)
+ ..controls (258.699005,487.660004) and (257.328003,485.500000)..(253.218994,486.289001)
+ ..controls (252.578003,484.339996) and (253.300995,482.328003)..(252.218994,480.101990)
+ ..controls (251.858994,479.519989) and (249.339996,478.578003)..(249.190994,481.390991)
+ ..controls (248.979996,483.050995) and (248.897995,486.359009)..(248.261993,486.718994)
+ ..controls (243.647995,486.718994) and (233.710999,487.078003)..(231.770004,493.921997)
+ ..controls (219.891006,492.339996) and (215.929993,491.261993)..(206.570007,493.421997)
+ ..controls (196.628998,489.671997) and (183.238007,506.160004)..(174.531006,502.199005)
+ ..controls (172.511993,496.148010) and (173.089996,485.640991)..(171.647995,481.390991)
+ ..controls (169.339996,474.769989) and (171.141006,467.140991)..(171.141006,456.410004)
+ ..controls (170.570007,455.398010) and (169.852005,454.460999)..(168.479996,454.460999)
+ ..controls (168.479996,453.101990) and (169.339996,450.859009)..(168.621002,449.421997)
+ ..controls (167.179993,447.621002) and (165.891006,451.800995)..(165.020004,444.601990)
+ ..controls (163.147995,443.738007) and (157.750000,442.218994)..(155.589996,445.179993)
+ ..controls (155.878998,448.988007) and (158.328003,451.300995)..(160.128998,453.378998)
+ ..controls (161.421997,456.910004) and (160.988007,458.281006)..(160.699005,461.808990)
+ ..controls (160.988007,464.980011) and (161.710999,468.578003)..(161.858994,470.089996)
+ ..controls (161.858994,473.039001) and (162.500000,479.300995)..(161.141006,481.179993)
+ --(159.410004,482.691010)..controls (157.179993,487.218994) and (158.328003,494.640991)..(157.608994,500.261993)
+ ..controls (155.809006,500.691010) and (155.809006,500.980011)..(154.011993,498.308990)
+ ..controls (154.011993,494.421997) and (153.500000,486.359009)..(152.352005,483.839996)
+ ..controls (149.690994,479.808990) and (150.839996,459.648010)..(151.421997,448.558990)
+ ..controls (151.781006,446.468994) and (149.690994,447.699005)..(149.761993,444.738007)
+ ..controls (150.050995,442.800995) and (147.891006,443.589996)..(146.089996,444.601990)
+ ..controls (145.147995,445.179993) and (146.589996,439.781006)..(145.371002,439.558990)
+ ..controls (142.339996,438.839996) and (136.871002,438.191010)..(135.218994,440.710999)
+ ..controls (134.570007,444.601990) and (137.878998,448.058990)..(140.621002,451.011993)
+ ..controls (143.141006,455.828003) and (140.897995,465.699005)..(140.468994,476.281006)
+ --(138.891006,478.218994)..controls (134.858994,483.191010) and (139.608994,496.941010)..(136.511993,506.230011)
+ ..controls (120.019997,514.870972) and (122.109001,519.190979)..(118.730003,537.620972)
+ ..controls (115.128998,557.640991) and (93.378899,567.648010)..(79.058601,567.648010)
+ ..controls (73.441399,563.039001) and (66.238297,563.620972)..(58.539101,567.648010)
+ ..controls (55.660198,569.229980) and (54.429699,573.190979)..(54.500000,576.500000)
+ ..controls (52.628899,580.750000) and (55.218800,582.190979)..(59.621101,583.487976)
+ ..controls (62.710899,587.809021) and (68.621101,594.648010)..(69.191399,597.737976)
+ ..controls (70.339798,601.921997) and (75.531303,608.109009)..(77.761703,609.770020)
+ ..controls (75.820297,613.012024) and (74.808601,615.171997)..(77.109398,618.551025)
+ ..controls (79.558601,620.140991) and (81.789101,616.609009)..(84.378899,618.551025)
+ --cycle;
+) ;
diff --git a/metapost/context/base/mpiv/mp-crop.mpiv b/metapost/context/base/mpiv/mp-crop.mpiv
new file mode 100644
index 000000000..00bcdcb44
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-crop.mpiv
@@ -0,0 +1,194 @@
+%D \module
+%D [ file=mp-crop.mpiv,
+%D version=2011.06.23,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=Cropmarks,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+if known context_crop : endinput ; fi ;
+
+boolean context_crop ; context_crop := true ;
+
+vardef crop_marks_lines (expr box, len, offset, nx, ny) =
+ save p ; picture p ; save w, h, x, y ; numeric w, h, x, y ;
+ p := image (
+ x := if nx = 0 : 1 else : nx - 1 fi ;
+ y := if ny = 0 : 1 else : ny - 1 fi ;
+ w := bbwidth (box) / x ;
+ h := bbheight(box) / y ;
+ for i=0 upto y :
+ draw ((llcorner box) -- (llcorner box) shifted (-len,0)) shifted (-offset,i*h) ;
+ draw ((lrcorner box) -- (lrcorner box) shifted ( len,0)) shifted ( offset,i*h) ;
+ endfor ;
+ for i=0 upto x :
+ draw ((llcorner box) -- (llcorner box) shifted (0,-len)) shifted (i*w,-offset) ;
+ draw ((ulcorner box) -- (ulcorner box) shifted (0, len)) shifted (i*w, offset) ;
+ endfor ;
+ ) ;
+ setbounds p to box ;
+ p
+enddef ;
+
+vardef crop_marks_cmyk =
+ save p ; picture p ; p := image (
+ fill ulcircle scaled 12.5 withcolor (1,0,0,0) ;
+ fill urcircle scaled 12.5 withcolor (0,1,0,0) ;
+ fill lrcircle scaled 12.5 withcolor (0,0,1,0) ;
+ fill llcircle scaled 12.5 withcolor (0,0,0,1) ;
+ draw (-10,0) -- (10,0) ;
+ draw (0,-10) -- (0,10) ;
+ draw fullcircle scaled 12.5 ;
+ ) ;
+ setbounds p to fullsquare scaled 20 ;
+ p
+enddef ;
+
+vardef crop_marks_gray =
+ save p ; picture p ; p := image (
+ fill ulcircle scaled 12.5 withcolor (0.00) ;
+ fill urcircle scaled 12.5 withcolor (0.25) ;
+ fill lrcircle scaled 12.5 withcolor (0.50) ;
+ fill llcircle scaled 12.5 withcolor (0.75) ;
+ draw (-10,0) -- (10,0) ;
+ draw (0,-10) -- (0,10) ;
+ draw (-6,0) -- (6,0) withcolor white ;
+ draw (0,-6) -- (0,6) withcolor white ;
+ draw fullcircle scaled 12.5 ;
+ ) ;
+ setbounds p to fullsquare scaled 20 ;
+ p
+enddef ;
+
+vardef crop_marks_cmykrgb =
+ save p ; picture p ; p := image (
+ fill ulcircle scaled 15 withcolor (1,0,0) ;
+ fill urcircle scaled 15 withcolor (0,1,0) ;
+ fill lrcircle scaled 15 withcolor (0,0,1) ;
+ fill llcircle scaled 15 withcolor (.5,.5,.5) ;
+ fill ulcircle scaled 10 withcolor (1,0,0,0) ;
+ fill urcircle scaled 10 withcolor (0,1,0,0) ;
+ fill lrcircle scaled 10 withcolor (0,0,1,0) ;
+ fill llcircle scaled 10 withcolor (0,0,0,1) ;
+ draw (-10,0) -- (10,0) ;
+ draw (0,-10) -- (0,10) ;
+ draw fullcircle scaled 10 ;
+ draw fullcircle scaled 15 ;
+ ) ;
+ setbounds p to fullsquare scaled 20 ;
+ p
+enddef ;
+
+vardef crop_color(expr c, h, w, dx, dy, ts) =
+ image (
+ save p ; path p ;
+ for i=1 upto 6 :
+ p := fullsquare
+ xscaled w
+ yscaled h
+ shifted (dx,dy-i*h) ;
+ fill p
+ withcolor (crop_colors[i]*c) ;
+ draw textext("\format{'@0.2f'," & decimal crop_colors[i] & "}")
+ scaled ts
+ shifted center p withcolor white ;
+ endfor ;
+ )
+enddef ;
+
+vardef crop_gray(expr c, h, w, dx, dy, ts) =
+ image (
+ save p ; path p ;
+ for i=.05 step .05 until 1 :
+ p := fullsquare
+ xscaled w
+ yscaled h
+ shifted (20*(i-1)*w+dx,dy) ;
+ fill p
+ withcolor (i*c) ;
+ draw textext("\format{'@0.2f'," & decimal i & "}")
+ scaled ts
+ shifted center p withcolor white ;
+ endfor ;
+ )
+enddef ;
+
+% draw crop_marks_cmyk shifted llcorner more ;
+% draw crop_marks_cmyk shifted lrcorner more ;
+% draw crop_marks_cmyk shifted ulcorner more ;
+% draw crop_marks_cmyk shifted urcorner more ;
+
+def page_marks_add_color(expr width, height, length, offset) = % todo: namespace
+
+ path page ; page := fullsquare xscaled width yscaled height ;
+ path more ; more := page enlarged (offset+length/2,offset+length/2) ;
+
+ numeric crop_colors[] ;
+ crop_colors[1] := 1 ;
+ crop_colors[2] := 0.95 ;
+ crop_colors[3] := 0.75 ;
+ crop_colors[4] := 0.50 ;
+ crop_colors[5] := 0.25 ;
+ crop_colors[6] := 0.05 ;
+
+ numeric h ; h := height / 20 ;
+ numeric w ; w := width / 20 ;
+ numeric d ; d := offset + length/2 ;
+
+ draw crop_color((1,0,0,0),h,length,xpart ulcorner page - d, 10h,length/20) ;
+ draw crop_color((0,1,0,0),h,length,xpart ulcorner page - d,3.5h,length/20) ;
+ draw crop_color((0,0,1,0),h,length,xpart ulcorner page - d, -3h,length/20) ;
+
+ draw crop_color((0,1,1,0),h,length,xpart urcorner page + d, 10h,length/20) ;
+ draw crop_color((1,0,1,0),h,length,xpart urcorner page + d,3.5h,length/20) ;
+ draw crop_color((1,1,0,0),h,length,xpart urcorner page + d, -3h,length/20) ;
+
+ draw crop_gray((0,0,0,1),length, w,-xpart llcorner page,-ypart llcorner page + d ,w/20) ;
+ draw crop_gray((1,0,0,0),length/3,w,-xpart llcorner page, ypart llcorner page - d + 1length/3,w/20) ;
+ draw crop_gray((0,1,0,0),length/3,w,-xpart llcorner page, ypart llcorner page - d - 0length/3,w/20) ;
+ draw crop_gray((0,0,1,0),length/3,w,-xpart llcorner page, ypart llcorner page - d - 1length/3,w/20) ;
+
+ setbounds currentpicture to page ;
+
+enddef ;
+
+def page_marks_add_marking(expr width, height, length, offset) = % todo: namespace
+
+ path page ; page := fullsquare xscaled width yscaled height ;
+ path more ; more := page enlarged (offset+length/2,offset+length/2) ;
+
+ draw crop_marks_gray shifted center(topboundary more) shifted (0, offset+length);
+ draw crop_marks_cmyk shifted center(bottomboundary more) shifted (0,-offset-length);
+
+ setbounds currentpicture to page ;
+
+enddef ;
+
+def page_marks_add_lines(expr width, height, length, offset, nx, ny) = % todo: namespace
+
+ path page ; page := fullsquare xscaled width yscaled height ;
+ path more ; more := page enlarged (offset+length/2,offset+length/2) ;
+
+ draw crop_marks_lines(page,length,offset,nx,ny) ;
+
+ setbounds currentpicture to page ;
+
+enddef ;
+
+def page_marks_add_number(expr width, height, length, offset, n) = % todo: namespace
+
+ path page ; page := fullsquare xscaled width yscaled height ;
+ path more ; more := page enlarged (offset+length/2,offset+length/2) ;
+
+ for s=llcorner more, lrcorner more, ulcorner more, urcorner more :
+ draw textext(decimal n) shifted s ;
+ endfor ;
+
+ setbounds currentpicture to page ;
+
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-figs.mpiv b/metapost/context/base/mpiv/mp-figs.mpiv
new file mode 100644
index 000000000..aac7c5ad2
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-figs.mpiv
@@ -0,0 +1,47 @@
+%D \module
+%D [ file=mp-figs.mpiv,
+%D version=2003.01.15,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=figures,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_figs : endinput ; fi ;
+
+boolean context_figs ; context_figs := true ;
+
+% todo: check defined
+
+def registerfigure(expr name,width,height) =
+ begingroup ;
+ save s ; string s ; s := cleanstring(name) ;
+ scantokens( s & "_width := " & decimal(width )) ;
+ scantokens( s & "_height := " & decimal(height)) ;
+ endgroup ;
+enddef ;
+
+vardef figuresize(expr name) =
+ save s, p ; string s ; pair p ;
+ s := cleanstring(name) ;
+ scantokens( "p := " & "(" & s & "_width" & "," & s & "_height" & ")" ) ;
+ p
+enddef ;
+
+vardef figurewidth(expr name) =
+ xpart figuresize(name)
+enddef ;
+
+vardef figureheight(expr name) =
+ ypart figuresize(name)
+enddef ;
+
+let figuredimensions = figuresize ; % for old times sake
+
+def naturalfigure(expr name) =
+ externalfigure name xyscaled(figuresize(name))
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-fobg.mpiv b/metapost/context/base/mpiv/mp-fobg.mpiv
new file mode 100644
index 000000000..f8b709572
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-fobg.mpiv
@@ -0,0 +1,87 @@
+%D \module
+%D [ file=mp-fobg.mp,
+%D version=2004.03.12,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=Formatting Objects,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_fobg : endinput ; fi ;
+
+boolean context_fobg ; context_fobg := true ;
+
+FoNone := 0 ; FoHidden := 1 ; FoDotted := 2 ; FoDashed := 3 ; FoSolid := 4 ;
+FoDouble := 5 ; FoGroove := 6 ; FoRidge := 7 ; FoInset := 8 ; FoOutset := 9 ;
+FoAll := 0 ; FoTop := 1 ; FoBottom := 2 ; FoLeft := 3 ; FoRight := 4 ;
+FoMedium := .5pt ; FoThin := FoMedium/2 ; FoThick := FoMedium*2 ;
+
+color FoBackgroundColor, FoNoColor, FoLineColor[] ; FoNoColor := (-1,-1,-1) ;
+numeric FoLineWidth[], FoLineStyle[] ;
+boolean FoFrame, FoBackground, FoSplit ;
+
+FoFrame := FoBackground := FoSplit := false ;
+FoBackgroundColor := white ;
+FoDashFactor := .5 ;
+FoDotFactor := .375 ;
+
+for i = FoAll upto FoRight :
+ FoLineColor[i] := black ;
+ FoLineWidth[i] := .5pt ;
+ FoLineStyle[i] := FoNone ;
+endfor ;
+
+def DrawFoFrame(expr n, p) =
+ drawoptions(withcolor FoLineColor[n] withpen pencircle scaled FoLineWidth[n]) ;
+ if FoLineStyle[n] = FoNone :
+ % nothing
+ elseif FoLineStyle[n] = FoHidden :
+ % nothing
+ elseif FoLineStyle[n] = FoDotted :
+ draw p dashed (withdots scaled (FoDotFactor*FoLineWidth[n])) ;
+ elseif FoLineStyle[n] = FoDashed :
+ draw p dashed (evenly scaled (FoDashFactor*FoLineWidth[n])) ;
+ elseif FoLineStyle[n] = FoSolid :
+ draw p ;
+ elseif FoLineStyle[n] = FoDouble :
+ draw p enlarged FoLineWidth[n] ; draw p enlarged -FoLineWidth[n] ;
+ elseif FoLineStyle[n] = FoGroove :
+ draw p ;
+ draw p withpen pencircle scaled .5FoLineWidth[n] withcolor (inverted FoLineColor[n] softened .5) ;
+ elseif FoLineStyle[n] = FoRidge :
+ draw p withcolor (inverted FoLineColor[n] softened .5) ;
+ draw p withpen pencircle scaled .5FoLineWidth[n] ;
+ elseif FoLineStyle[n] = FoInset :
+ draw p ; draw p inset 2.5FoLineWidth[n] ;
+ elseif FoLineStyle[n] = FoOutset :
+ draw p ; draw p outset 2.5FoLineWidth[n] ;
+ fi ;
+enddef ;
+
+primarydef p outset d =
+ ((lrcorner p -- urcorner p -- ulcorner p -- llcorner p -- cycle)
+ shifted (d*(-1,1)) cutbefore topboundary p) cutafter leftboundary p
+enddef ;
+
+primarydef p inset d =
+ ((ulcorner p -- llcorner p -- lrcorner p -- urcorner p -- cycle)
+ shifted (d*(1,-1)) cutbefore bottomboundary p) cutafter rightboundary p
+enddef ;
+
+vardef equalpaths(expr p, q) =
+ if length(p) = length(q) :
+ save ok ; boolean ok ; ok := true ;
+ for i = 0 upto length(p)-1 :
+ ok := ok and (round(point i of p) = round(point i of q)) ;
+ endfor ;
+ ok
+ else :
+ false
+ fi
+enddef ;
+
+endinput ;
diff --git a/metapost/context/base/mpiv/mp-form.mpiv b/metapost/context/base/mpiv/mp-form.mpiv
new file mode 100644
index 000000000..88b15e097
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-form.mpiv
@@ -0,0 +1,30 @@
+%D \module
+%D [ file=mp-form.mpiv,
+%D version=2011.10.14,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=form support,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+% The graph package will be replaced by our own variant using
+% MetaPost 2 features and textext.
+
+if known context_form : endinput ; fi ;
+
+boolean context_form ; context_form := true ;
+
+string Fmfont_ ; Fmfont_ := "crap" ;
+
+% The following function accept a number or string that can be
+% converted to a number by \LUA. The first argument is a format
+% where @ can be used instead of %. The number is typeset in math
+% mode and @3e is converted into @.3e.
+
+vardef mfun_format_number(expr fmt, i) =
+ "\ctxlua{metapost.formatnumber('" & fmt & "'," & if string i : i else : decimal i fi & ")}"
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-func.mpiv b/metapost/context/base/mpiv/mp-func.mpiv
new file mode 100644
index 000000000..b1b9d6d5d
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-func.mpiv
@@ -0,0 +1,87 @@
+%D \module
+%D [ file=mp-func.mpiv,
+%D version=2001.12.29,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=function hacks,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+%D Under construction.
+
+if known context_func : endinput ; fi ;
+
+boolean context_func ; context_func := true ;
+
+string mfun_pathconnectors[] ;
+
+mfun_pathconnectors[0] := "," ;
+mfun_pathconnectors[1] := "--" ;
+mfun_pathconnectors[2] := ".." ;
+mfun_pathconnectors[3] := "..." ;
+mfun_pathconnectors[4] := "---" ;
+
+def pathconnectors = mfun_pathconnectors enddef ;
+
+vardef mfun_function (expr f) (expr u, t, b, e, s) =
+ save x ; numeric x ;
+ save c ; string c ; c := if string f : f else : mfun_pathconnectors[f] fi ;
+ for xx := b step s until e :
+ hide (x := xx ;)
+ if xx > b :
+ scantokens(c)
+ fi
+ (scantokens(u),scantokens(t))
+ endfor
+enddef ;
+
+def function = mfun_function enddef ; % let doesn't work here
+def constructedfunction = mfun_function enddef ;
+def straightfunction = mfun_function (1) enddef ;
+def curvedfunction = mfun_function (2) enddef ;
+
+% def punkedfunction = mfun_function (1) enddef ; % same as straightfunction
+% def tightfunction = mfun_function (3) enddef ; % same as curvedfunction
+
+vardef mfun_constructedpath (expr f) (text t) =
+ save ok ; boolean ok ; ok := false ;
+ save c ; string c ; c := if string f : f else : mfun_pathconnectors[f] fi ;
+ for i=t :
+ if ok :
+ scantokens(c)
+ else :
+ ok := true ;
+ fi
+ i
+ endfor
+enddef ;
+
+def constructedpath = mfun_constructedpath enddef ; % let doesn't work here
+def straightpath = mfun_constructedpath (1) enddef ;
+def curvedpath = mfun_constructedpath (2) enddef ;
+
+% def punkedpath = mfun_constructedpath (1) enddef ; % same as straightpath
+% def tightpath = mfun_constructedpath (3) enddef ; % same as curvedpath
+
+vardef mfun_constructedpairs (expr f) (text p) =
+ save i ; i := -1 ;
+ save c ; string c ; c := if string f : f else : mfun_pathconnectors[f] fi ;
+ forever :
+ exitif unknown p[incr(i)] ;
+ if i>0 :
+ scantokens(c)
+ fi
+ p[i]
+ endfor
+enddef ;
+
+def constructedpairs = mfun_constructedpairs enddef ; % let doesn't work here
+def straightpairs = mfun_constructedpairs (1) enddef ;
+def curvedpairs = mfun_constructedpairs (2) enddef ;
+
+% def punkedpairs = mfun_constructedpairs (1) enddef ; % same as straightpairs
+% def tightpairs = mfun_constructedpairs (3) enddef ; % same as curvedpairs
diff --git a/metapost/context/base/mpiv/mp-grap.mpiv b/metapost/context/base/mpiv/mp-grap.mpiv
new file mode 100644
index 000000000..4fd8ee5bd
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-grap.mpiv
@@ -0,0 +1,1706 @@
+%D \module
+%D [ file=mp-grap.mpiv,
+%D version=2012.10.16, % 2008.09.08 and earlier,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=graph packagesupport,
+%D author=Hans Hagen \& Alan Braslau,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_grap : endinput ; fi ;
+
+boolean context_grap ; context_grap := true ;
+
+% Below is a modified graph.mp
+
+show numbersystem, numberprecision ;
+
+%if epsilon/4 = 0 :
+if numbersystem <> "double" :
+ errmessage "The graph macros require the double precision number system." ;
+ endinput ;
+fi
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% $Id : graph.mp,v 1.2 2004/09/19 21 :47 :10 karl Exp $
+% Public domain.
+
+% Macros for drawing graphs
+
+% begingraph(width,height) begin a new graph
+% setcoords(xtype,ytype) sets up a new coordinate system (log,-linear..)
+% setrange(lo,hi) set coord ranges (numeric and string args OK)
+% gdraw <file or path> [with...] draw a line in current coord system
+% gfill <file or path> [with...] fill a region using current coord system
+% gdrawarrow .., gdrawdblarrow.. like gdraw, but with 1 or 2 arrowheads
+% augment<path name>(loc) append given coordinates to a polygonal path
+% glabel<suffix>(pic,loc) place label pic near graph coords or time loc
+% gdotlabel<suffix>(pic,loc) same with dot
+% OUT loc value for labels relative to whole graph
+% gdata(file,s,text) read coords from file ; evaluate t w/ tokens s[]
+% auto.<x or y> default x or y tick locations (for interation)
+% tick.<bot|top|..>(fmt,u) draw centered tick from given side at u w/ format
+% itick.<bot|top|..>(fmt,u) draw inward tick from given side at u w/ format
+% otick.<bot|top|..>(fmt,u) draw outward tick at coord u ; label format fmt
+% grid.<bot|top|..>(fmt,u) draw grid line at u with given side labeled
+% autogrid([itick|.. bot|..],..) iterate over auto.x, auto.y, drawing tick/grids
+% frame.[bot|top..] draw frame (or one side of the frame)
+% graph_frame_needed := false ; after begingraph, not to draw a frame at all
+% graph_background := color ; fill color for frame, if defined
+% endgraph end of graph--the result is a picture
+
+% option `plot <picture>' draws picture at each path knot, turns off pen
+% graph_template.<tickcmd> template paths for tick marks and grid lines
+% graph_margin_fraction.low,
+% graph_margin_fraction.high fractions determining margins when no setrange
+% graph_log_marks[], graph_lin_marks, graph_exp_marks loop text strings used by auto.<x or y>
+% graph_minimum_number_of_marks, graph_log_minimum numeric parameters used by auto.<x or y>
+% Autoform is the format string used by autogrid
+% Autoform_X, Autoform_Y if defined, are used instead
+
+% Other than the above-documented user interface, all externally visible names
+% are of the form X_.<suffix>, Y_.<suffix>, or Z_.<suffix>, or they start
+% with `graph_'
+
+% Used to depend on :
+
+% input string.mp
+
+% Private version of a few marith macros, fixed for double math...
+
+newinternal Mzero ; Mzero := -16384; % Anything at least this small is treated as zero
+newinternal mlogten ; mlogten := mlog(10) ;
+newinternal largestmantissa ; largestmantissa := 2**52 ; % internal double warningcheck
+newinternal singleinfinity ; singleinfinity := 2**128 ;
+newinternal doubleinfinity ; doubleinfinity := 2**1024 ;
+%Mzero := -largestmantissa ; % Note that we get arithmetic overflows if we set to -doubleinfinity
+
+% Safely convert a number to mlog form, trapping zero.
+
+vardef graph_mlog primary x =
+ if unknown x: whatever
+ elseif x=0: Mzero
+ else: mlog(abs x) fi
+enddef ;
+
+vardef graph_exp primary x =
+ if unknown x: whatever
+ elseif x<=Mzero: 0
+ else: mexp(x) fi
+enddef ;
+
+% and add the following for utility/completeness
+% (replacing the definitions in mp-tool.mpiv).
+
+vardef logten primary x =
+ if unknown x: whatever
+ elseif x=0: Mzero
+ else: mlog(abs x)/mlog(10) fi
+enddef ;
+
+vardef ln primary x =
+ if unknown x: whatever
+ elseif x=0: Mzero
+ else: mlog(abs x)/256 fi
+enddef ;
+
+vardef exp primary x =
+ if unknown x: whatever
+ elseif x<= Mzero: 0
+ else: (mexp 256)**x fi
+enddef ;
+
+vardef powten primary x =
+ if unknown x: whatever
+ elseif x<= Mzero: 0
+ else: 10**x fi
+enddef ;
+
+% Convert x from mlog form into a pair whose xpart gives a mantissa and whose
+% ypart gives a power of ten.
+
+vardef graph_Meform(expr x) =
+ if x<=Mzero : origin
+ else :
+ save e, m ; e=floor(x/mlogten)-3; m := mexp(x-e*mlogten) ;
+ if abs m<1000 : m := m*10 ; e := e-1 ; elseif abs m>=10000 : m := m/10 ; e := e+1 ; fi
+ (m, e)
+ fi
+enddef ;
+
+% Modified from above.
+
+vardef graph_Feform(expr x) =
+ interim warningcheck :=0 ;
+ if x=0 : origin
+ else :
+ save e, m ; e=floor(if x<0 : -mlog(-x) else : mlog(x) fi/mlogten)-3; m := x/(10**e) ;
+ if abs m<1000 : m := m*10 ; e := e-1 ; elseif abs m>=10000 : m := m/10 ; e := e+1 ; fi
+ (m, e)
+ fi
+enddef ;
+
+vardef graph_error(expr x,s) =
+ interim showstopping :=0 ;
+ show x ; errmessage s ;
+enddef ;
+
+%%%%%%%%%%%%%%%%%%%%%%%% Data structures, begingraph %%%%%%%%%%%%%%%%%%%%%%%%
+
+vardef Z_@# = (X_@#,Y_@#) enddef ; % used in place of plain.mp's z convention
+
+def graph_suffix(suffix $) = % convert from x or y to X_ or Y_
+ if str$="x" : X_ else : Y_ fi
+enddef ;
+
+% New :
+
+save graph_background ; color graph_background ; % if defined, fill the frame.
+save graph_close_file ; boolean graph_close_file ; graph_close_file = false ;
+
+def begingraph(expr w, h) =
+ begingroup
+ save X_, Y_ ;
+ X_.graph_coordinate_type =
+ Y_.graph_coordinate_type = linear ; % coordinate system for each axis
+ Z_.graph_dimensions = (w,h) ; % dimensions of graph not counting axes etc.
+ %also, Z_.low, Z_.high user-specified coordinate ranges in units used in graph_current_graph
+
+ save graph_finished_graph ;
+ picture graph_finished_graph ; % the finished part of the graph
+ graph_finished_graph = nullpicture ;
+ save graph_current_graph ;
+ picture graph_current_graph ; % what has been drawn in current coords
+ graph_current_graph = nullpicture ;
+ save graph_current_bb ;
+ picture graph_current_bb ; % picture whose bbox is graph_current_graph's w/ linewidths 0
+ graph_current_bb = nullpicture ;
+ save graph_last_drawn ;
+ picture graph_last_drawn ; % result of last gdraw or gfill
+ graph_last_drawn = nullpicture ;
+ save graph_last_path ;
+ path graph_last_path ; % last gdraw or gfill path in data coordinates.
+ save graph_plot_picture ;
+ picture graph_plot_picture ; % a picture from the `plot' option known when plot allowed
+ save graph_foreground ;
+ color graph_foreground ; % drawing color, if set.
+ save graph_label ;
+ picture graph_label[] ; % labels to place around the whole graph when it is done
+ save graph_autogrid_needed ;
+ boolean graph_autogrid_needed ; % whether autogrid is needed
+ graph_autogrid_needed = true ;
+ save graph_frame_needed ;
+ boolean graph_frame_needed ; % whether frame needs to be drawn
+ graph_frame_needed = true ;
+ save graph_number_of_arrowheads ; % number of arrowheads for next gdraw
+ graph_number_of_arrowheads = 0 ;
+
+ if known graph_background : % new feature!
+ fill origin--(w,0)--(w,h)--(0,h)--cycle withcolor graph_background ;
+ fi
+enddef ;
+
+% Additional variables not explained above :
+% graph_modified_lower, graph_modified_higher pairs giving bounds used in auto<x or y>
+% graph_exponent, graph_comma variables and macros used in auto<x or y>
+% graph_modified_bias
+% an offset to graph_modified_lower and graph_modified_higher to ease computing exponents
+% Some additional variables function as constants. Most can be modified by the
+% user to alter the behavior of these macros.
+% Not very modifiable : log, linear,
+% graph_frame_pair_a, graph_frame_pair_b, graph_margin_pair
+% Modifiable : graph_template.suffix,
+% graph_log_marks[], graph_lin_marks, graph_exp_marks,
+% graph_minimum_number_of_marks,
+% graph_log_minimum, Autoform
+
+
+newinternal log, linear ; % coordinate system codes
+log :=1 ; linear :=2;
+
+% note that mp-tool.mpiv defines log as log10.
+
+%%%%%%%%%%%%%%%%%%%%%% Coordinates : setcoords, setrange %%%%%%%%%%%%%%%%%%%%%%
+
+% Graph-related user input is `user graph coordinates' as specified by arguments
+% to setcoords.
+% `Internal graph coordinates' are used for graph_current_graph, graph_current_bb, Z_.low, Z_.high.
+% Their meaning depends on the appropriate component of Z_.graph_coordinate_type :
+% log means internal graph coords = mlog(user graph coords)
+% -log means internal graph coords = -mlog(user graph coords)
+% linear means internal graph coords = (user graph coords)
+% -linear means internal graph coords = -(user graph coords)
+
+
+vardef graph_set_default_bounds = % Set default Z_.low, Z_.high
+ forsuffixes $=low,high :
+ (if known X_$ : whatever else : X_$ fi, if known Y_$ : whatever else : Y_$ fi)
+ = graph_margin_fraction$[llcorner graph_current_bb,urcorner graph_current_bb] +
+ graph_margin_pair$ ;
+ endfor
+enddef ;
+
+pair graph_margin_pair.low, graph_margin_pair.high ;
+graph_margin_pair.high = -graph_margin_pair.low = (.00002,.00002) ;
+
+% Set $, $$, $$$ so that shifting by $ then transforming by $$ and then $$$ maps
+% the essential bounding box of graph_current_graph into (0,0)..Z_.graph_dimensions.
+% The `essential bounding box' is either what Z_.low and Z_.high imply
+% or the result of ignoring pen widths in graph_current_graph.
+
+vardef graph_remap(suffix $,$$,$$$) =
+ save p_ ;
+ graph_set_default_bounds ;
+ pair p_, $ ; $=-Z_.low;
+ p_ = (max(X_.high-X_.low,.9), max(Y_.high-Y_.low,.9)) ;
+ transform $$, $$$ ;
+ forsuffixes #=$$,$$$ : xpart#=ypart#=xypart#=yxpart#=0 ; endfor
+ (Z_.high+$) transformed $$ = p_ ;
+ p_ transformed $$$ = Z_.graph_dimensions ;
+enddef ;
+
+graph_margin_fraction.low=-.07 ; % bbox fraction for default range start
+graph_margin_fraction.high=1.07 ; % bbox fraction for default range stop
+
+def graph_with_pen_and_color(expr q) =
+ withpen penpart q withcolor
+ if colormodel q=1 :
+ false
+ elseif colormodel q=3 :
+ (greypart q)
+ elseif colormodel q=5 :
+ (redpart q, greenpart q, bluepart q)
+ elseif colormodel q=7 :
+ (cyanpart q, magentapart q, yellowpart q, blackpart q)
+ fi
+enddef ;
+
+% Add picture component q to picture @# and change part p to tp,
+% where p is something from q that needs coordinate transformation.
+% The type of p is pair or path.
+% Pair o is the value of p that makes tp (0,0). This implements the trick
+% whereby using 1 instead of 0 for the width or height or the setbounds path
+% for a label picture suppresses shifting in x or y.
+
+%vardef graph_picture_conversion@#(expr q, o)(text tp) =
+% save p ;
+% if stroked q :
+% path p ; p=pathpart q;
+% addto @# doublepath tp graph_with_pen_and_color(q) dashed dashpart q ;
+% elseif filled q :
+% path p ; p=pathpart q;
+% addto @# contour tp graph_with_pen_and_color(q) ;
+% else :
+% interim truecorners :=0 ;
+% pair p ; p=llcorner q;
+% if urcorner q<>p : p := p + graph_coordinate_multiplication(o-p,urcorner q-p) ; fi
+% addto @# also q shifted ((tp)-llcorner q) ;
+% fi
+%enddef ;
+
+% This new version makes gdraw clip the result to the window defined with setrange
+
+vardef graph_picture_conversion@#(expr q, o)(text tp) =
+ save p ;
+ save do_clip, tp_clipped ; boolean do_clip ; do_clip := true ;
+ picture tp_clipped ; tp_clipped := nullpicture;
+ if stroked q :
+ path p ; p=pathpart q;
+ addto tp_clipped doublepath tp graph_with_pen_and_color(q) dashed dashpart q ;
+ %draw bbox tp_clipped withcolor red ;
+ elseif filled q :
+ path p ; p=pathpart q;
+ addto tp_clipped contour tp graph_with_pen_and_color(q) ;
+ %draw bbox tp_clipped withcolor green ;
+ else :
+ if (urcorner q<>llcorner q) : do_clip := false ; fi % Do not clip the axis labels;
+ interim truecorners := 0 ;
+ pair p ; p=llcorner q;
+ if urcorner q<>p : p := p + graph_coordinate_multiplication(o-p,urcorner q-p) ; fi
+ addto tp_clipped also q shifted ((tp)-llcorner q) ;
+ %draw bbox tp_clipped withcolor if do_clip : cyan else : blue fi ;
+ fi
+ if do_clip :
+ clip tp_clipped to origin--(xpart Z_.graph_dimensions,0)--Z_.graph_dimensions--
+ (0,ypart Z_.graph_dimensions)--cycle ;
+ fi
+ addto @# also tp_clipped ;
+enddef ;
+
+def graph_coordinate_multiplication(expr a,b) = (xpart a*xpart b, ypart a*ypart b) enddef ;
+
+vardef graph_clear_bounds@# = numeric @#.low, @#.high ; enddef;
+
+% Finalize anything drawn in the present coordinate system and set up a new
+% system as requested
+
+vardef setcoords(expr tx, ty) =
+ interim warningcheck :=0 ;
+ if length graph_current_graph>0 :
+ save s, S, T ;
+ graph_remap(s, S, T) ;
+ for q within graph_current_graph :
+ graph_picture_conversion.graph_finished_graph(q,-s,p shifted s transformed S transformed T) ;
+ endfor
+ graph_current_graph := graph_current_bb := nullpicture ;
+ fi
+ graph_clear_bounds.X_ ; graph_clear_bounds.Y_;
+ X_.graph_coordinate_type := tx ; Y_.graph_coordinate_type := ty;
+enddef ;
+
+% Set Z_.low and Z_.high to correspond to given range of user graph
+% coordinates. The text argument should be a sequence of pairs and/or strings
+% with 4 components in all.
+
+vardef setrange(text t) =
+ interim warningcheck :=0 ;
+ save r_ ; r_=0;
+ string r_[]s ;
+ for x_=
+ for p_=t : if pair p_ : xpart p_, ypart fi p_, endfor :
+ r_[incr r_] if string x_ : s fi = x_ ;
+ if r_>2 :
+ graph_set_bounds if r_=3 : X_ else : Y_ fi (r_[r_-2] if unknown r_[r_-2] : s fi, x_) ;
+ fi
+ exitif r_=4 ;
+ endfor
+enddef ;
+
+% @# is X_ or Y_ ; l and h are numeric or string
+
+vardef graph_set_bounds@#(expr l, h) =
+ graph_clear_bounds@# ;
+ if @#graph_coordinate_type>0 :
+ @#low = if unknown l :
+ whatever
+ else :
+ if abs @#graph_coordinate_type=log : graph_mlog fi if string l : scantokens fi l
+ fi ;
+ @#high = if unknown h :
+ whatever
+ else :
+ if abs @#graph_coordinate_type=log : graph_mlog fi if string h : scantokens fi h
+ fi ;
+ else :
+ -@#high = if unknown l :
+ whatever
+ else :
+ if abs @#graph_coordinate_type=log : graph_mlog fi if string l : scantokens fi l
+ fi ;
+ -@#low = if unknown h :
+ whatever
+ else :
+ if abs @#graph_coordinate_type=log : graph_mlog fi if string h : scantokens fi h
+ fi ;
+ fi
+enddef ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%% Converting path coordinates %%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Find the result of scanning path p and using macros tx and ty to adjust the
+% x and y parts of each coordinate pair. Boolean parameter c tells whether to
+% force the result to be polygonal.
+
+vardef graph_scan_path(expr p, c)(suffix tx, ty) =
+ if (str tx="") and (str ty="") : p
+ else :
+ save r_ ; path r_;
+ r_ := graph_pair_adjust(point 0 of p, tx, ty)
+ if path p :
+ for t=1 upto length p :
+ if c : --
+ else : ..controls graph_pair_adjust(postcontrol(t-1) of p, tx, ty)
+ and graph_pair_adjust(precontrol t of p, tx, ty) ..
+ fi
+ graph_pair_adjust(point t of p, tx, ty)
+ endfor
+ if cycle p : &cycle fi
+ fi ;
+ if pair p : point 0 of fi r_
+ fi
+enddef ;
+
+vardef graph_pair_adjust(expr p)(suffix tx, ty) = (tx xpart p, ty ypart p) enddef ;
+
+% Convert path p from user graph coords to internal graph coords.
+
+vardef graph_convert_user_path_to_internal primary p =
+ interim warningcheck :=0 ;
+ if known p :
+ graph_scan_path(p,
+ (abs X_.graph_coordinate_type<>linear) or (abs Y_.graph_coordinate_type<>linear),
+ if abs X_.graph_coordinate_type=log : graph_mlog fi,
+ if abs Y_.graph_coordinate_type=log : graph_mlog fi)
+ transformed (identity
+ if X_.graph_coordinate_type<0 : xscaled -1 fi
+ if Y_.graph_coordinate_type<0 : yscaled -1 fi)
+ fi
+enddef ;
+
+% Convert label location t_ from user graph coords to internal graph coords.
+% The label location should be a pair, or two numbers/strings. If t_ is empty
+% or a single item of non-pair type, just return t_. Unknown coordinates
+% produce unknown components in the result.
+
+vardef graph_label_convert_user_to_internal(text t_) =
+ save n_ ; n_=0;
+ interim warningcheck :=0 ;
+ if 0 for x_=t_ : +1 if pair x_ : +1 fi endfor <= 1 :
+ t_
+ else :
+ n_0 = n_1 = 0 ;
+ point 0 of graph_convert_user_path_to_internal (
+ for x_=
+ for y_=t_ : if pair y_ : xpart y_, ypart fi y_, endfor
+ 0, 0 :
+ if known x_ : if string x_ : scantokens fi x_
+ else : hide(n_[n_] :=whatever) 0
+ fi
+ exitif incr n_=2 ;
+ ,endfor) + (n_0,n_1)
+ fi
+enddef ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Reading data files %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Read a line from file f, extract whitespace-separated tokens ignoring any
+% initial "%", and return true if at least one token is found. The tokens
+% are stored in @#1, @#2, .. with "" in the last @#[] entry.
+
+% String manipulation routines for MetaPost
+% It is harmless to input this file more than once.
+
+vardef isdigit primary d =
+ ("0"<=d)and(d<="9")
+enddef ;
+
+% Number of initial characters of string s where `c <character>' is true
+
+vardef graph_cspan(expr s)(text c) =
+ 0
+ for i=1 upto length s:
+ exitunless c substring (i-1,i) of s;
+ + 1
+ endfor
+enddef ;
+
+% String s is composed of items separated by white space. Lop off the first
+% item and the surrounding white space and return just the item.
+
+vardef graph_loptok suffix s =
+ save t, k;
+ k = graph_cspan(s," ">=);
+ if k > 0 :
+ s := substring(k,infinity) of s ;
+ fi
+ k := graph_cspan(s," "<);
+ string t;
+ t = substring (0,k) of s;
+ s := substring (k,infinity) of s;
+ s := substring (graph_cspan(s," ">=),infinity) of s;
+ t
+enddef ;
+
+vardef graph_read_line@#(expr f) =
+ save n_, s_ ; string s_;
+ s_ = readfrom f ;
+ string @#[] ;
+ if s_<>EOF :
+ @#0 := s_ ;
+ @#1 := graph_loptok s_ ;
+ n_ = if @#1="%" : 0 else : 1 fi ;
+ forever :
+ @#[incr n_] := graph_loptok s_ ;
+ exitif @#[n_]="" ;
+ endfor
+ @#1<>""
+ else : false
+ fi
+enddef ;
+
+% Execute c for each line of data read from file f, and stop at the first
+% line with no data. Commands c can use line number i and tokens $1, $2, ...
+% and j is the number of fields.
+
+def gdata(expr f)(suffix $)(text c) =
+ %boolean flag ; % not used?
+ for i=1 upto largestmantissa :
+ exitunless graph_read_line$(f) ;
+ c
+ endfor
+ if graph_close_file :
+ closefrom f ;
+ fi
+enddef ;
+
+% Read a path from file f. The path is terminated by blank line or EOF.
+
+vardef graph_readpath(expr f) =
+ interim warningcheck :=0 ;
+ save s ;
+ gdata(f, s, if i>1 :--fi
+ if s2="" : ( i, scantokens s1)
+ else : (scantokens s1, scantokens s2) fi
+ )
+enddef ;
+
+% Append coordinates t to polygonal path @#. The coordinates can be numerics,
+% strings, or a single pair.
+
+vardef augment@#(text t) =
+ interim warningcheck := 0 ;
+ if not path begingroup @# endgroup :
+ graph_error(begingroup @# endgroup, "Cannot augment--not a path") ;
+ else :
+ def graph_comma= hide(def graph_comma=,enddef) enddef ;
+ if known @# : @# :=@#-- else : @#= fi
+ (for p=t :
+ graph_comma if string p : scantokens fi p
+ endfor) ;
+ fi
+enddef ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Drawing and filling %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Unknown pair components are set to 0 because glabel and gdotlabel understand
+% unknown coordinates as `0 in absolute units'.
+
+vardef graph_unknown_pair_bbox(expr p) =
+ interim warningcheck:=0 ;
+ if known p : addto graph_current_bb doublepath p ;
+ else :
+ save x,y ;
+ z = llcorner graph_current_bb ;
+ if unknown xpart p : xpart p= else : x := fi 0 ;
+ if unknown ypart p : ypart p= else : y := fi 0 ;
+ addto graph_current_bb doublepath (p+z) ;
+ fi
+ graph_current_bb := image(fill llcorner graph_current_bb..urcorner graph_current_bb--cycle) ;
+enddef ;
+
+% Initiate a gdraw or gfill command. This must be done before scanning the
+% argument, because that could invoke the `if known graph_plot_picture' test in a following
+% plot option .
+
+def graph_addto =
+ def graph_errorbar_text = enddef ;
+ color graph_foreground ;
+ path graph_last_path ;
+ graph_last_drawn := graph_plot_picture := nullpicture ; addto graph_last_drawn
+enddef;
+
+% Handle the part of a gdraw command that uses path or data file p.
+
+def graph_draw expr p =
+ if string p : hide(graph_last_path := graph_readpath(p) ;)
+ graph_convert_user_path_to_internal graph_last_path
+ elseif path p or pair p :
+ hide(graph_last_path := p ;)
+ graph_convert_user_path_to_internal p
+ else : graph_error(p,"gdraw argument should be a data file or a path")
+ origin
+ fi
+ withpen currentpen graph_withlist _op_
+enddef ;
+
+% Handle the part of a gdraw command that uses path or data file p.
+
+def graph_fill expr p =
+ if string p : hide(graph_last_path := graph_readpath(p) --cycle ;)
+ graph_convert_user_path_to_internal graph_last_path
+ elseif cycle p : hide(graph_last_path := p ;)
+ graph_convert_user_path_to_internal p
+ else : graph_error(p,"gfill argument should be a data file or a cyclic path")
+ origin..cycle
+ fi graph_withlist _op_
+enddef ;
+
+def gdraw = graph_addto doublepath graph_draw enddef ;
+def gfill = graph_addto contour graph_fill enddef ;
+
+% This is used in graph_draw and graph_fill to allow postprocessing graph_last_drawn
+
+def graph_withlist text t_ = t_ ; graph_post_draw; enddef;
+
+def witherrorbars(text t) text options =
+ hide(
+ def graph_errorbar_text = t enddef ;
+ save pic ; picture pic ; pic := image(draw origin _op_ options ;) ;
+ if color colorpart pic : graph_foreground := colorpart pic ; fi
+ )
+ options
+enddef ;
+
+% new feature: graph_errorbars
+
+picture graph_errorbar_picture ; graph_errorbar_picture := image(draw (left--right) scaled .5 ;) ;
+%picture graph_xbar_picture ; graph_xbar_picture := image(draw (down--up) scaled .5 ;) ;
+%picture graph_ybar_picture ; graph_ybar_picture := image(draw (left--right) scaled .5 ;) ;
+
+vardef graph_errorbars(text t) =
+ if known graph_last_path :
+ save n, p, q ; path p ; pair q ;
+ save pic ; picture pic[] ; pic0 := nullpicture ;
+ pic1 := if known graph_xbar_picture : graph_xbar_picture
+ elseif known graph_errorbar_picture : graph_errorbar_picture rotated 90
+ else : nullpicture fi ;
+ pic2 := if known graph_ybar_picture : graph_ybar_picture
+ elseif known graph_errorbar_picture : graph_errorbar_picture
+ else : nullpicture fi ;
+ if length pic1>0 :
+ pic1 := pic1 scaled graph_shapesize ;
+ setbounds pic1 to origin..cycle ;
+ fi
+ if length pic2>0 :
+ pic2 := pic2 scaled graph_shapesize ;
+ setbounds pic2 to origin..cycle ;
+ fi
+ for i=0 upto length graph_last_path :
+ clearxy ; z = point i of graph_last_path ;
+ n := 1 ;
+ for $=t :
+ if known $ :
+ q := if path $ : if length $>i : point i of $ else : origin fi
+ elseif pair $ : $ elseif numeric $ : ($,$) else : origin fi ;
+ if q<>origin :
+ p := graph_convert_user_path_to_internal ((
+ if n=1 :
+ (-xpart q,0)--(ypart q,0)
+ else :
+ (0,-xpart q)--(0,ypart q)
+ fi ) shifted z) ;
+ addto pic0 doublepath p ;
+ if length pic[n]>0 :
+ if ypart q<>0 :
+ addto pic0 also pic[n] shifted point 1 of p ;
+ fi
+ if xpart q<>0 :
+ addto pic0 also pic[n] rotated 180 shifted point 0 of p ;
+ fi
+ fi
+ fi
+ fi
+ exitif incr n>3 ;
+ endfor
+ endfor
+ if length pic0>0 :
+ save bg, fg ; color bg, fg ;
+ bg := if known graph_background : graph_background else : background fi ;
+ fg := if known graph_foreground : graph_foreground else : black fi ;
+ addto graph_current_graph also pic0 withpen currentpen scaled 2 _op_ withcolor bg ;
+ addto graph_current_graph also pic0 withpen currentpen scaled .5 _op_ withcolor fg ;
+ fi
+ fi
+enddef ;
+
+% Set graph_plot_picture so the postprocessing step will plot picture p at each path knot.
+% Also select nullpen to suppress stroking.
+
+def plot expr p =
+ if known graph_plot_picture :
+ withpen nullpen
+ hide (graph_plot_picture := image(
+ if bounded p : for q within p : graph_addto_currentpicture q endfor % Save memory
+ else : graph_addto_currentpicture p
+ fi graph_setbounds origin..cycle))
+ fi
+enddef ;
+
+% This hides a semicolon that could prematurely end graph_withlist's text argument
+
+def graph_addto_currentpicture primary p = addto currentpicture also p ; enddef;
+def graph_setbounds = setbounds currentpicture to enddef ;
+
+def gdrawarrow = graph_number_of_arrowheads := 1 ; gdraw enddef;
+def gdrawdblarrow = graph_number_of_arrowheads := 2 ; gdraw enddef;
+
+% Post-process the filled or stroked picture graph_last_drawn as follows : (1) update
+% the bounding box information ; (2) transfer it to graph_current_graph unless the pen has
+% been set to nullpen to disable stroking ; (3) plot graph_plot_picture at each knot.
+
+vardef graph_post_draw =
+ save p ; path p ; p = pathpart graph_last_drawn ;
+ graph_unknown_pair_bbox(p) ;
+ if filled graph_last_drawn or not graph_is_null(penpart graph_last_drawn) :
+ addto graph_current_graph also graph_last_drawn ;
+ fi
+ graph_errorbars(graph_errorbar_text) ;
+ if length graph_plot_picture>0 :
+ for i=0 upto length p if cycle p : -1 fi :
+ addto graph_current_graph also graph_plot_picture shifted point i of p ;
+ endfor
+ picture graph_plot_picture ;
+ fi
+ if graph_number_of_arrowheads>0 :
+ graph_draw_arrowhead(p, graph_with_pen_and_color(graph_last_drawn)) ;
+ if graph_number_of_arrowheads>1 :
+ graph_draw_arrowhead(reverse p, graph_with_pen_and_color(graph_last_drawn)) ;
+ fi
+ graph_number_of_arrowheads := 0 ;
+ fi
+enddef ;
+
+vardef graph_is_null(expr p) = (urcorner p=origin) and (llcorner p=origin) enddef ;
+
+vardef graph_draw_arrowhead(expr p)(text w) = % Draw arrowhead for path p, with list w
+ %save r ; r := angle(precontrol infinity of p shifted -point infinity of p) ;
+ addto graph_current_graph also
+ image(fill arrowhead (graph_arrowhead_extent(precontrol infinity of p,point infinity of p)) w ;
+ draw arrowhead (graph_arrowhead_extent(precontrol infinity of p,point infinity of p)) w
+ undashed ;
+%if (r mod 90 <> 0) : % orientation can be wrong due to remapping
+% draw textext("\tfxx " & decimal r) shifted point infinity of p withcolor blue ;
+%fi
+ graph_setbounds point infinity of p..cycle ;
+ ) ; % rotatedabout(point infinity of p,-r) ;
+enddef ;
+
+vardef graph_arrowhead_extent(expr p, q) =
+ if p<>q : (q - 100pt*unitvector(q-p)) -- fi
+ q
+enddef ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Drawing labels %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Argument c is a drawing command that needs an additional argument p that gives
+% a location in internal graph coords. Draw in graph_current_graph enclosed in a setbounds
+% path. Unknown components of p cause the setbounds path to have width or height 1 instead of 0.
+% Then graph_unknown_pair_bbox sets these components to 0 and graph_picture_conversion
+% suppresses subsequent repositioning.
+
+def graph_draw_label(expr p)(suffix $)(text c) =
+ save sdim_ ; pair sdim_;
+ sdim_ := (if unknown xpart p : 1+ fi 0, if unknown ypart p : 1+ fi 0) ;
+ graph_unknown_pair_bbox(p) ;
+ addto graph_current_graph also
+ image(c(p) ; graph_setbounds p--p+sdim_--cycle) _op_
+enddef ;
+
+% Stash the result drawing command c in the graph_label table using with list w and
+% an index based on angle mfun_laboff$.
+
+vardef graph_stash_label(suffix $)(text c) text w =
+ graph_label[1.5+angle mfun_laboff$ /90] = image(c(origin) w) ;
+enddef ;
+
+def graph_label_location primary p =
+ if pair p : graph_draw_label(p)
+ elseif numeric p : graph_draw_label(point p of pathpart graph_last_drawn)
+ else : graph_stash_label
+ fi
+enddef ;
+
+% Place label p at user graph coords t using with list w. (t is a time, a pair
+% or 2 numerics or strings).
+
+vardef glabel@#(expr p)(text t) text w =
+ graph_label_location graph_label_convert_user_to_internal(t) (@#,label@#(p)) w ; enddef;
+
+% Place label p at user graph coords t using with list w and draw a dot there.
+% (t is a time, a pair, or 2 numerics or strings).
+
+vardef gdotlabel@#(expr p)(text t) text w =
+ graph_label_location graph_label_convert_user_to_internal(t) (@#,dotlabel@#(p)) w ; enddef;
+
+def OUT = enddef ; % location text for outside labels
+
+%%%%%%%%%%%%%%%%%%%%%%%%%% Grid lines, ticks, etc. %%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Grid lines and tick marks are transformed versions of the templates below.
+% In the template paths, (0,0) is on the edge of the frame and inward is to
+% the right.
+
+path graph_template.tick, graph_template.itick, graph_template.otick, graph_template.grid ;
+graph_template.tick = (-3.5bp,0)--(3.5bp,0) ;
+graph_template.itick = origin--(7bp,0) ;
+graph_template.otick = (-7bp,0)--origin ;
+graph_template.grid = origin--(1,0) ;
+
+vardef tick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w) ; enddef;
+
+vardef itick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w) ; enddef;
+
+vardef otick@#(expr f,u) text w = graph_tick_label(@#,@,false,f,u,w) ; enddef;
+
+vardef grid@#(expr f,u) text w = graph_tick_label(@#,@,true,f,u,w) ; enddef;
+
+
+% Produce a tick or grid mark for label suffix $, graph_template suffix $$,
+% coordinate value u, and with list w. Boolean c tells whether graph_template$$
+% needs scaling by X_.graph_dimensions or Y_.graph_dimensions,
+% and f gives a format string or a label picture.
+
+def graph_tick_label(suffix $,$$)(expr c, f, u)(text w) =
+ graph_draw_label(graph_label_convert_user_to_internal(graph_generate_label_position($,u)),,
+ draw graph_gridline_picture$($$,c,f,u,w) shifted)
+enddef ;
+
+% Generate label positioning arguments appropriate for label suffix $ and
+% coordinate u.
+
+def graph_generate_label_position(suffix $)(expr u) =
+ if pair u : u elseif xpart mfun_laboff.$=0 : u,whatever else : whatever,u fi
+enddef ;
+
+% Generate a picture of a grid line labeled with coordinate value u, picture
+% or format string f, and with list w. Suffix @# is bot, top, lft, or rt,
+% suffix $ identifies entries in the graph_template table, and boolean c tells
+% whether to scale graph_template$.
+
+vardef graph_gridline_picture@#(suffix $)(expr c, f, u)(text w) =
+ if unknown u : graph_error(u,"Label coordinate should be known") ; nullpicture
+ else :
+ save p ; path p;
+ interim warningcheck :=0 ;
+ graph_autogrid_needed :=false ;
+ p = graph_template$ zscaled -mfun_laboff@#
+ if c : graph_xyscale fi
+ shifted (((.5 + mfun_laboff@# dotprod (.5,.5)) * mfun_laboff@#) graph_xyscale) ;
+ image(draw p w ;
+ label@#(if string f : format(f,u) else : f fi, point 0 of p))
+ fi
+enddef ;
+
+def graph_xyscale = xscaled X_.graph_dimensions yscaled Y_.graph_dimensions enddef ;
+
+% Draw the frame or the part corresponding to label suffix @# using with list w.
+
+vardef frame@# text w =
+ graph_frame_needed :=false ;
+ picture p_ ;
+ p_ = image(draw
+ if str@#<>"" : subpath round(angle mfun_laboff@#*graph_frame_pair_a+graph_frame_pair_b) of fi
+ unitsquare graph_xyscale w) ;
+ graph_draw_label((whatever,whatever),,draw p_ shifted) ;
+enddef ;
+
+pair graph_frame_pair_a ; graph_frame_pair_a=(1,1)/90; % unitsquare subpath is linear in label angle
+pair graph_frame_pair_b ; graph_frame_pair_b=(.75,2.25);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%% Automatic grid selection %%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string graph_log_marks[] ; % marking options per decade for logarithmic scales
+string graph_lin_marks ; % mark spacing options per decade for linear scales
+string graph_exp_marks ; % exponent spacing options for logarithmic scales
+newinternal graph_minimum_number_of_marks, graph_log_minimum ;
+graph_minimum_number_of_marks := 4 ; % minimum number marks generated by auto.x or auto.y
+graph_log_minimum := mlog 3 ; % revert to uniform marks when largest/smallest < this
+
+def Gfor(text t) = for i=t endfor enddef ; % to shorten the mark templates below
+
+graph_log_marks[1]="1,2,5" ;
+graph_log_marks[2]="1,1.5,2,3,4,5,7" ;
+graph_log_marks[3]="1Gfor(6upto10 :,i/5)Gfor(5upto10 :,i/2)Gfor(6upto9 :,i)" ;
+graph_log_marks[4]="1Gfor(11upto20 :,i/10)Gfor(11upto25 :,i/5)Gfor(11upto19 :,i/2)" ;
+graph_log_marks[5]="1Gfor(21upto40 :,i/20)Gfor(21upto50 :,i/10)Gfor(26upto49 :,i/5)" ;
+graph_lin_marks="10,5,2" ; % start with 10 and go down; a final `,1' is appended
+graph_exp_marks="20,10,5,2,1" ;
+
+Ten_to0 = 1 ;
+Ten_to1 = 10 ;
+Ten_to2 = 100 ;
+Ten_to3 = 1000 ;
+Ten_to4 = 10000 ;
+
+% Determine the X_ or Y_ bounds on the range to be covered by automatic grid
+% marks. Suffix @# is X_ or Y_. The result is log or linear to specify the
+% type of grid spacing to use. Bounds are returned in variables local to
+% begingraph..endgraph : pairs graph_modified_lower and graph_modified_higher
+% are upper and lower bounds in
+% `modified exponential form'. In modified exponential form, (x,y) means
+% (x/1000)*10^y, where 1000<=abs x<10000.
+
+vardef graph_bounds@# =
+ interim warningcheck :=0 ;
+ save l, h ;
+ graph_set_default_bounds ;
+ if @#graph_coordinate_type>0 : (l,h) else : -(h,l) fi = (@#low, @#high) ;
+ if abs @#graph_coordinate_type=log :
+ graph_modified_lower := graph_Meform(l)+graph_modified_bias ;
+ graph_modified_higher := graph_Meform(h)+graph_modified_bias ;
+ if h-l >= graph_log_minimum : log else : linear fi
+ else :
+ graph_modified_lower := graph_Feform(l)+graph_modified_bias ;
+ graph_modified_higher := graph_Feform(h)+graph_modified_bias ;
+ linear
+ fi
+enddef ;
+
+pair graph_modified_bias ; graph_modified_bias=(0,3);
+pair graph_modified_lower, graph_modified_higher ;
+
+% Scan graph_log_marks[k] and evaluate tokens t for each m where l<=m<=h.
+
+def graph_scan_marks(expr k, l, h)(text t) =
+ for m=scantokens graph_log_marks[k] :
+ exitif m>h ;
+ if m>=l : t fi
+ endfor
+enddef ;
+
+% Scan graph_log_marks[k] and evaluate tokens t for each m and e where m*10^e belongs
+% between l and h (inclusive), where both l and h are in modified exponent form.
+
+def graph_scan_mark(expr k, l, h)(text t) =
+ for e=ypart l upto ypart h :
+ graph_scan_marks(k, if e>ypart l : 1 else : xpart l/1000 fi,
+ if e<ypart h : 10 else : xpart h/1000 fi, t)
+ endfor
+enddef ;
+
+% Select a k for which graph_scan_mark(k,...) gives enough marks.
+
+vardef graph_select_mark =
+ save k ;
+ k = 0 ;
+ forever :
+ exitif unknown graph_log_marks[k+1] ;
+ exitif 0 graph_scan_mark(incr k, graph_modified_lower, graph_modified_higher, +1)
+ >= graph_minimum_number_of_marks ;
+ endfor
+ k
+enddef ;
+
+% Try to select an exponent spacing from graph_exp_marks. If successful, set @# and
+% return true
+
+vardef graph_select_exponent_mark@# =
+ numeric @# ;
+ for e=scantokens graph_exp_marks :
+ @# = e ;
+ exitif floor(ypart graph_modified_higher/e) -
+ floor(graph_modified_exponent_ypart(graph_modified_lower)/e)
+ >= graph_minimum_number_of_marks ;
+ numeric @# ;
+ endfor
+ known @#
+enddef ;
+
+vardef graph_modified_exponent_ypart(expr p) = ypart p if xpart p=1000 : -1 fi enddef ;
+
+% Compute the mark spacing d between xpart graph_modified_lower and xpart graph_modified_higher.
+
+vardef graph_tick_mark_spacing =
+ interim warningcheck :=0 ;
+ save m, n, d ;
+ m = graph_minimum_number_of_marks ;
+ n = 1 for i=1 upto
+ (mlog(xpart graph_modified_higher-xpart graph_modified_lower) - mlog m)/mlogten :
+ *10 endfor ;
+ if n<=1000 :
+ for x=scantokens graph_lin_marks :
+ d = n*x ;
+ exitif 0 graph_generate_numbers(d,+1)>=m ;
+ numeric d ;
+ endfor
+ fi
+ if known d : d else : n fi
+enddef ;
+
+def graph_generate_numbers(expr d)(text t) =
+ for m = d*ceiling(xpart graph_modified_lower/d) step d until xpart graph_modified_higher :
+ t
+ endfor
+enddef ;
+
+% Evaluate tokens t for exponents e in multiples of d in the range determined
+% by graph_modified_lower and graph_modified_higher.
+
+def graph_generate_exponents(expr d)(text t) =
+ for e = d*floor(graph_modified_exponent_ypart(graph_modified_lower)/d+1)
+ step d until d*floor(ypart graph_modified_higher/d) : t
+ endfor
+enddef ;
+
+% Adjust graph_modified_lower and graph_modified_higher so their exponent parts match
+% and they are in true exponent form ((x,y) means x*10^y). Return the new exponent.
+
+vardef graph_match_exponents =
+ interim warningcheck := 0 ;
+ save e ;
+ e+3 = if graph_modified_lower=graph_modified_bias : ypart graph_modified_higher
+ elseif graph_modified_higher=graph_modified_bias : ypart graph_modified_lower
+ else : max(ypart graph_modified_lower, ypart graph_modified_higher) fi ;
+ forsuffixes $=graph_modified_lower, graph_modified_higher :
+ $ := (xpart $ for i=ypart $ upto e+2 : /(10) endfor, e) ;
+ endfor
+ e
+enddef ;
+
+% Assume e is an integer and either m=0 or 1<=abs(m)<10000. Find m*(10^e)
+% and represent the result as a string if its absolute value would be at least
+% 4096 or less than .1. It is OK to return 0 as a string or a numeric.
+
+vardef graph_factor_and_exponent_to_string(expr m, e) =
+ if (e>3)or(e<-4) :
+ decimal m & "e" & decimal e
+ elseif e>=0 :
+ if abs m<infinity/Ten_to[e] :
+ m*Ten_to[e]
+ else : decimal m & "e" & decimal e
+ fi
+ else :
+ save x ; x=m/Ten_to[-e];
+ if abs x>=.1 : x else : decimal m & "e" & decimal e fi
+ fi
+enddef ;
+
+def auto suffix $ =
+ hide(def graph_comma= hide(def graph_comma=,enddef) enddef)
+ if graph_bounds.graph_suffix($)=log :
+ if graph_select_exponent_mark.graph_exponent :
+ graph_generate_exponents(graph_exponent,
+ graph_comma graph_factor_and_exponent_to_string(1,e))
+ else :
+ graph_scan_mark(graph_select_mark, graph_modified_lower, graph_modified_higher,
+ graph_comma graph_factor_and_exponent_to_string(m,e))
+ fi
+ else :
+ hide(graph_exponent :=graph_match_exponents)
+ graph_generate_numbers(graph_tick_mark_spacing,
+ graph_comma graph_factor_and_exponent_to_string(m,graph_exponent))
+ fi
+enddef ;
+
+string Autoform ; Autoform = "%g";
+
+%vardef autogrid(suffix tx, ty) text w =
+% graph_autogrid_needed :=false ;
+% if str tx<>"" : for x=auto.x : tx(Autoform,x) w ; endfor fi
+% if str ty<>"" : for y=auto.y : ty(Autoform,y) w ; endfor fi
+%enddef ;
+
+% We redefine autogrid, adding the possibility of differing X and Y
+% formats.
+
+% string Autoform_X ; Autoform_X := "@.0e" ;
+% string Autoform_Y ; Autoform_Y := "@.0e" ;
+
+vardef autogrid(suffix tx, ty) text w =
+ graph_autogrid_needed := false ;
+ if str tx <> "" :
+ for x=auto.x :
+ tx (
+ if string Autoform_X :
+ if Autoform_X <> "" :
+ Autoform_X
+ else :
+ Autoform
+ fi
+ else :
+ Autoform
+ fi,
+ x
+ ) w ;
+ endfor
+ fi
+ if str ty <> "" :
+ for y=auto.y :
+ ty (
+ if string Autoform_Y :
+ if Autoform_Y <> "" :
+ Autoform_Y
+ else :
+ Autoform
+ fi
+ else :
+ Autoform
+ fi,
+ y
+ ) w ;
+ endfor
+ fi
+enddef ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% endgraph %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+def endgraph =
+ if graph_autogrid_needed : autogrid(otick.bot, otick.lft) ; fi
+ if graph_frame_needed : frame ; fi
+ setcoords(linear,linear) ;
+ interim truecorners :=1 ;
+ for b=bbox graph_finished_graph :
+ setbounds graph_finished_graph to b ;
+ for i=0 step .5 until 3.5 :
+ if known graph_label[i] :
+ addto graph_finished_graph also graph_label[i] shifted point i of b ;
+ fi
+ endfor
+ endfor
+ graph_finished_graph
+ endgroup
+enddef ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% We format in luatex (using \mathematics{}) ...
+% we could pass via variables and save escaping as that is inefficient
+
+if unknown context_mlib :
+
+ vardef escaped_format(expr s) =
+ "" for n=0 upto length(s) : &
+ if ASCII substring (n,n+1) of s = 37 :
+ "@"
+ else :
+ substring (n,n+1) of s
+ fi
+ endfor
+ enddef ;
+
+ vardef strfmt(expr f, x) = % maybe use mfun_ namespace
+ "\MPgraphformat{" & escaped_format(f) & "}{" & mfun_tagged_string(x) & "}"
+ enddef ;
+
+ vardef varfmt(expr f, x) = % maybe use mfun_ namespace
+ "\MPformatted{" & escaped_format(f) & "}{" & mfun_tagged_string(x) & "}"
+ enddef ;
+
+ vardef format (expr f, x) = textext(strfmt(f,x)) enddef ;
+ vardef formatted(expr f, x) = textext(varfmt(f,x)) enddef ;
+
+fi ;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% A couple of extensions :
+
+% Define a function plotsymbol() returning a picture : 10 different shapes,
+% unfilled outline, interior filled with different shades of the background.
+% This allows overlapping points on a plot to be more distinguishable.
+
+vardef graph_shapesize = (.33BodyFontSize) enddef ;
+
+path graph_shape[] ; % (internal) symbol path
+
+graph_shape[0] := (0,0) ; % point
+graph_shape[1] := fullcircle ; % circle
+graph_shape[2] := (up -- down) scaled .5 ; % vertical bar
+
+for i = 3 upto 9 : % polygons
+ graph_shape[i] :=
+ for j = 0 upto i-1 :
+ (up scaled .5) rotated (360j/i) --
+ endfor cycle ;
+endfor
+
+graph_shape[12] := graph_shape[2] rotated +90 ; % horizontal line
+graph_shape[22] := graph_shape[2] rotated +45 ; % backslash
+graph_shape[32] := graph_shape[2] rotated -45 ; % slash
+graph_shape[13] := graph_shape[3] rotated 180 ; % down triangle
+graph_shape[23] := graph_shape[3] rotated -90 ; % right triangle
+graph_shape[33] := graph_shape[3] rotated +90 ; % left triangle
+graph_shape[14] := graph_shape[4] rotated +45 ; % square
+graph_shape[15] := graph_shape[5] rotated 180 ; % down pentagon
+graph_shape[16] := graph_shape[6] rotated +90 ; % turned hexagon
+graph_shape[17] := graph_shape[7] rotated 180 ;
+graph_shape[18] := graph_shape[8] rotated +22.5 ;
+
+numeric l ;
+
+for j = 5 upto 9 :
+ l := length(graph_shape[j]) ;
+ pair p[] ;
+ for i = 0 upto l :
+ p[i] = whatever [point i of graph_shape[j],
+ point (i+2 mod l) of graph_shape[j]] ;
+ p[i] = whatever [point (i+1 mod l) of graph_shape[j],
+ point (i+l-1 mod l) of graph_shape[j]] ;
+ endfor
+ graph_shape[20+j] := for i = 0 upto l : point i of graph_shape[j]--p[i]--endfor cycle ;
+endfor
+
+path s ; s := graph_shape[4] ;
+path q ; q := s scaled .25 ;
+numeric l ; l := length(s) ;
+
+pair p[] ;
+
+graph_shape[24] := for i = 0 upto l-1 :
+ hide(
+ p[i] = whatever [point i of s, point (i+1 mod l) of s] ;
+ p[i] = whatever [point i of q, point (i-1+l mod l) of q] ;
+ p[i+l] = whatever [point i of s, point (i+1 mod l) of s] ;
+ p[i+l] = whatever [point i+1 of q, point (i+2 mod l) of q] ;
+ )
+ point i of q -- p[i] -- p[i+l] --
+endfor cycle ;
+
+graph_shape[34] := graph_shape[24] rotated 45 ;
+
+% usage : gdraw p plot plotsymbol( 1,1) ; % a filled circle
+% usage : gdraw p plot plotsymbol(14,0) ; % a square
+% usage : gdraw p plot plotsymbol( 4,.5) ; % a 50% filled diamond
+
+def stars(expr f) = plotsymbol(25,f) enddef ; % a 5-point star
+def points(expr f) = plotsymbol( 0,f) enddef ;
+def circles(expr f) = plotsymbol( 1,f) enddef ;
+def crosses(expr f) = plotsymbol(34,f) enddef ;
+def squares(expr f) = plotsymbol(14,f) enddef ;
+def diamonds(expr f) = plotsymbol( 4,f) enddef ; % a turned square
+def uptriangles(expr f) = plotsymbol( 3,f) enddef ;
+def downtriangles(expr f) = plotsymbol(13,f) enddef ;
+def lefttriangles(expr f) = plotsymbol(33,f) enddef ;
+def righttriangles(expr f) = plotsymbol(23,f) enddef ;
+
+% f (fill) is color, numeric or boolean, otherwise background.
+def plotsymbol(expr n, f) text t =
+ if known graph_shape[n] :
+ image(
+ save bg, fg ; color bg, fg ;
+ bg := if known graph_background : graph_background else : background fi ;
+ save pic ; picture pic ; pic := image(draw origin _op_ t ;) ;
+ if color colorpart pic : graph_foreground := colorpart pic ; fi
+ fg := if known graph_foreground : graph_foreground else : black fi ;
+ save p ; path p ; p = graph_shape[n] scaled graph_shapesize ;
+ draw p withcolor bg withpen currentpen scaled 2 ; % halo
+ currentpen := currentpen scaled .5 ;
+ if cycle p :
+ fill p withcolor
+ if known f :
+ if color f :
+ f
+ elseif numeric f :
+ f[bg,fg]
+ elseif boolean f and f :
+ fg
+ else
+ bg
+ fi
+ else :
+ bg
+ fi ;
+ fi
+ draw p _op_ t ;
+ )
+ else :
+ nullpicture
+ fi
+ t
+enddef ;
+
+% standard resistance color code: rainbow sequence (from /usr/share/X11/rgb.txt)
+color resistance_color[] ; string resistance_name[] ;
+resistance_color0 = (0,0,0) ; resistance_name0 = "black" ;
+resistance_color1 = (165/255,42/255,42/255) ; resistance_name1 = "brown" ;
+resistance_color2 = (1,0,0) ; resistance_name2 = "red" ;
+resistance_color3 = (1,165/255,0) ; resistance_name3 = "orange" ;
+resistance_color4 = (1,1,0) ; resistance_name4 = "yellow" ;
+resistance_color5 = (0,1,0) ; resistance_name5 = "green" ;
+resistance_color6 = (0,0,1) ; resistance_name6 = "blue" ;
+resistance_color7 = (148/255,0,211/255) ; resistance_name7 = "darkviolet" ;
+resistance_color8 = (190/255,190/255,190/255) ; resistance_name8 = "gray" ;
+resistance_color9 = (1,1,1) ; resistance_name9 = "white" ;
+
+%def rainbow(expr f) =
+% ((abs(5f) mod 5) + 2 - floor((abs(5f) mod 5) + 2))
+% [resistance_color[ floor((abs(5f) mod 5) + 2)],
+% resistance_color[ceiling((abs(5f) mod 5) + 2)]]
+%enddef ;
+def rainbow(expr f) =
+ hide(numeric n_ ; n_ = (abs(5f) mod 5) + 2 ;)
+ (n_-floor(n_))[resistance_color[floor n_],resistance_color[ceiling n_]]
+enddef ;
+
+% The following extensions are not specific to graph and could be moved to metafun...
+
+% sort a path. Efficient en memory use, not so efficient in sorting long paths...
+
+vardef sortpath (suffix $) (text t) = % t can be "xpart", "ypart", "length", "angle", ...
+ if path $ :
+ if length $ > 0 :
+ save n, k ; n := length $ ;
+ for i=0 upto n :
+ k := i ;
+ for j=i+1 upto n :
+ if t (point j of $) < t (point k of $) :
+ k := j ;
+ fi
+ endfor
+ if k>i :
+ $ := if i>0 : subpath (0,i-1) of $ -- fi
+ point k of $ --
+ subpath (i,k-1) of $
+ if k<n : -- subpath (k+1,n) of $ fi
+ ;
+ fi
+ endfor
+ fi
+ fi
+enddef ;
+
+% convert a polygon path to a smooth path (useful, e.g. as a guide to the eye)
+
+def smoothpath (suffix $) =
+ if path $ :
+ (for i=0 upto length $ :
+ if i>0 : .. fi
+ (point i of $)
+ endfor )
+ fi
+enddef ;
+
+% return a path of a function func(x) with abscissa running from f to t over n intervals
+
+def makefunctionpath (expr f, t, n) (text func) =
+ (for x=f step ((t-f)/(abs n)) until t :
+ if x<>f : -- fi
+ (x, func)
+ endfor )
+enddef ;
+
+% shift a path, point by point
+%
+% example :
+%
+% p1 := addtopath(p0,(.1normaldeviate,.1normaldeviate)) ;
+
+vardef addtopath (suffix p) (text t) =
+ if path p :
+ (for i=0 upto length p :
+ if i>0 : -- fi
+ hide(clearxy ; z = point i of p ;) z shifted t
+ endfor)
+ fi
+enddef ;
+
+% return a new path of a function func(z) using the same abscissa as an existing path
+
+vardef functionpath (suffix p) (text func) =
+ (for i=0 upto length p :
+ if i>0 : .. fi
+ (hide(x := xpart(point i of p))x,func) %(hide(clearxy ; z = point i of p)x,func)
+ endfor )
+enddef ;
+
+% least-squares "fit" to a polynomial
+%
+% example :
+%
+% path p[] ;
+% numeric a[] ; a0 := 1 ; a1 := .1 ; a2 := .01 ; a3 := .001 ; a4 := 0.0001 ;
+% p0 := makefunctionpath(0,5,10,polynomial_function(a,4,x)) ;
+% p1 := addtopath(p0,(0,.001normaldeviate)) ;
+% gdraw p0 ;
+% gdraw p1 plot plotsymbol(1,.5) ;
+%
+% numeric b[] ;
+% polynomial_fit(p1, b, 4, 1) ;
+% gdraw functionpath(p1,polynomial_function(b,4,x)) ;
+%
+% numeric c[] ;
+% linear_fit(p1, c, 1) ;
+% gdraw functionpath(p1,linear_function(c,x)) dashed evenly ;
+
+% a polynomial function :
+%
+% y = a0 + a1 * x + a2 * x^2 + ... + a[n] * x^n
+
+vardef polynomial_function (suffix $) (expr n, x) =
+ (for j=0 upto n : + $[j]*(x**j) endfor) % no ;
+enddef ;
+
+% find the determinant of a (n+1)*(n+1) matrix ; indices run from 0 to n
+
+vardef det (suffix $) (expr n) =
+ hide(
+ numeric determinant ; determinant := 1 ;
+ save jj ; numeric jj ;
+ for k=0 upto n :
+ if $[k][k]=0 :
+ jj := -1 ;
+ for j=0 upto n :
+ if $[k][j]<>0 :
+ jj := j ;
+ exitif true ;
+ fi
+ endfor
+ if jj<0 :
+ determinant := 0 ;
+ exitif true ;
+ fi
+ for j=k upto n : % interchange the columns
+ temp := $[j][jj] ;
+ $[j][jj] := $[j][k] ;
+ $[j][k] := temp ;
+ endfor
+ determinant = -determinant ;
+ fi
+ exitif determinant=0 ;
+ determinant := determinant * $[k][k] ;
+ if k<n : % subtract row k from lower rows to get a diagonal matrix
+ for j=k+1 upto n :
+ for i=k+1 upto n :
+ $[j][i] := $[j][i]-$[j][k]*$[k][i]/$[k][k] ;
+ endfor
+ endfor
+ fi
+ endfor ;
+ )
+ determinant % no ;
+enddef ;
+
+numeric fit_chi_squared ;
+
+% least-squares fit of a polynomial $ of order n to a path p (unweighted)
+%
+% reference : P. R. Bevington, "Data Reduction and Error Analysis for the Physical
+% Sciences", McGraw-Hill, New York 1969.
+
+vardef polynomial_fit (suffix p, $) (expr n) (text t) =
+ if not path p :
+ graph_error(p, "Cannot fit--not a path") ;
+ elseif length p < n :
+ graph_error(p, "Cannot fit--not enough points") ;
+ else :
+ fit_chi_squared := 0 ;
+ % calculate sums of the data
+ save sumx, sumy ; numeric sumx[], sumy[] ;
+ save w ; numeric w ;
+ for i=0 upto 2n :
+ sumx[i] := 0 ;
+ endfor
+ for i=0 upto n :
+ sumy[i] := 0 ;
+ endfor
+ for i=0 upto length p :
+ clearxy ; z = point i of p ;
+ w := 1 ; % weight
+ if known t :
+ if numeric t :
+ w := 1 if t<>0 : /(abs t) fi ;
+ elseif pair t :
+ if t<>origin :
+ w := 1/(abs t) ;
+ fi
+ elseif path t :
+ if length t>= i:
+ if point i of t<>origin :
+ w := 1/(abs point i of t) ;
+ fi
+ else :
+ w := 0 ;
+ fi ;
+ fi
+ fi
+ x1 := w ;
+ for j=0 upto 2n :
+ sumx[j] := sumx[j] + x1 ;
+ x1 := x1 * x ;
+ endfor
+ y1 := y * w ;
+ for j=0 upto n :
+ sumy[j] := sumy[j] + y1 ;
+ y1 := y1 * x ;
+ endfor
+ fit_chi_squared := fit_chi_squared + y*y*w ;
+ endfor
+ % construct matrices and calculate the polynomial coefficients
+ save m ; numeric m[][] ;
+ for j=0 upto n :
+ for k=0 upto n :
+ m[j][k] := sumx[j+k] ;
+ endfor
+ endfor
+ save delta ; numeric delta ;
+ delta := det(m,n) ; % this destroys the matrix m[][], which is OK
+ if delta = 0 :
+ fit_chi_squared := 0 ;
+ for j=0 upto n :
+ $[j] := 0 ;
+ endfor
+ else :
+ for i=0 upto n :
+ for j=0 upto n :
+ for k=0 upto n :
+ m[j][k] := sumx[j+k] ;
+ endfor
+ m[j][i] := sumy[j] ;
+ endfor
+ $[i] := det(m,n) / delta ; % matrix m[][] gets destroyed...
+ endfor
+ for j=0 upto n :
+ fit_chi_squared := fit_chi_squared - 2sumy[j]*$[j] ;
+ for k=0 upto n :
+ fit_chi_squared := fit_chi_squared + $[j]*$[k]*sumx[j+k] ;
+ endfor
+ endfor
+ % normalize by the number of degrees of freedom
+ fit_chi_squared := fit_chi_squared / (length(p) - n) ; % length(p)+1-(n+1)
+ fi
+ fi
+enddef ;
+
+% y = a0 + a1 * x
+%
+% of course a line is just a polynomial of order 1
+
+vardef linear_function (suffix $) (expr x) = polynomial_function($,1,x) enddef ;
+vardef linear_fit (suffix p, $) (text t) = polynomial_fit(p, $, 1, t) ; enddef ;
+
+% and a constant is polynomial of order 0
+
+vardef constant_function (suffix $) (expr x) = polynomial_function($,0,x) enddef ;
+vardef constant_fit (suffix p, $) (text t) = polynomial_fit(p, $, 0, t) ; enddef ;
+
+% y = a1 * exp(a0*x)
+%
+% exp and ln defined in metafun
+
+vardef exponential_function (suffix $) (expr x) = $1*exp($0*x) enddef ;
+
+% since we take a log, this only works for positive ordinates
+
+vardef exponential_fit (suffix p, $) (text t) =
+ save a ; numeric a[] ;
+ save q ; path q[] ; % fit to the log of the ordinate
+ for i=0 upto length p :
+ clearxy ; z = point i of p ;
+ if y>0 :
+ augment.q0(x,ln(y)) ;
+ augment.q1(
+ if known t :
+ if numeric t : (0,ln(t))
+ elseif pair t : (xpart t,ln(ypart t))
+ elseif path t :
+ if length t>=i :
+ hide(z1 = point i of t;)
+ (x1,ln(y1))
+ else :
+ origin
+ fi
+ fi
+ else :
+ (0,1)
+ fi ) ;
+ fi
+ endfor
+ linear_fit(q0,a,q1) ;
+ save e ; e := exp(sqrt(fit_chi_squared)) ;
+ fit_chi_squared := e * e ;
+ $0 := a1 ;
+ $1 := exp(a0) ;
+enddef ;
+
+% y = a1 * x**a0
+
+vardef power_law_function (suffix $) (expr x) = $1*(x**$0) enddef ;
+
+% since we take logs, this only works for positive abscissae and ordinates
+
+vardef power_law_fit (suffix p, $) (text t) =
+ save a ; numeric a[] ;
+ save q ; path q[] ; % fit to the logs of the abscissae and ordinates
+ for i=0 upto length p :
+ clearxy ; z = point i of p ;
+ if (x>0) and (y>0) :
+ augment.q0(ln(x),ln(y)) ;
+ augment.q1(
+ if known t :
+ if numeric t : (0,ln(t))
+ elseif pair t : (ln(xpart t),ln(ypart t))
+ elseif path t :
+ if length t>=i :
+ hide(z1 = point i of t)
+ (ln(x1),ln(y1))
+ else :
+ origin
+ fi
+ fi
+ else :
+ (0,1)
+ fi ) ;
+ fi
+ endfor
+ linear_fit(q0,a,q1) ;
+ save e ; e := exp(sqrt(fit_chi_squared)) ;
+ fit_chi_squared := e * e ;
+ $0 := a1 ;
+ $1 := exp(a0) ;
+enddef ;
+
+% gaussian : y = a2 * exp(-ln(2)*((x-a0)/a1)^2)
+%
+% a1 is the hwhm ; sigma := a1/sqrt(2ln(2)) or a1/1.17741
+
+newinternal lntwo ; lntwo := ln(2) ; % brrr, why not inline it
+
+vardef gaussian_function (suffix $) (expr x) =
+ if $1 = 0 :
+ if x = $0 : $2 else : 0 fi
+ else :
+ $2 * exp(-lntwo*(((x-$0)/$1)**2))
+ fi
+ if known $3 :
+ + $3
+ fi
+enddef ;
+
+% since we take a log, this only works for positive ordinates
+
+vardef gaussian_fit (suffix p, $) (text t) =
+ save a ; numeric a[] ;
+ save q ; path q[] ; % fit to the log of the ordinate
+ for i=0 upto length p :
+ clearxy ; z = point i of p ;
+ if y>0 :
+ augment.q0(x,ln(y)) ;
+ augment.q1(
+ if known t :
+ if numeric t : (0,ln(t))
+ elseif pair t : (xpart t,ln(ypart t))
+ elseif path t :
+ if length t>=i :
+ hide(z1 = point i of t)
+ (x1,ln(y1))
+ else :
+ origin
+ fi
+ fi
+ else :
+ (0,1)
+ fi ) ;
+ fi
+ endfor
+ polynomial_fit(q0,a,2,q1) ;
+ save e ; e := exp(sqrt(fit_chi_squared)) ;
+ fit_chi_squared := e * e ;
+ $1 := sqrt(-lntwo/a2) ;
+ $0 := -.5a1/a2 ;
+ $2 := exp(a0-.25*a1*a1/a2) ;
+ $3 := 0 ; % polynomial_fit will NOT work with a non-zero background!
+enddef ;
+
+% lorentzian: y = a2 / (1 + ((x - a0)/a1)^2)
+
+vardef lorentzian_function (suffix $) (expr x) =
+ if $1 = 0 :
+ if x = $0 : $2 else : 0 fi
+ else :
+ $2 / (1 + ((x - $0)/$1)**2)
+ fi
+ if known $3 :
+ + $3
+ fi
+enddef ;
+
+vardef lorentzian_fit (suffix p, $) (text t) =
+ save a ; numeric a[] ;
+ save q ; path q ; % fit to the inverse of the ordinate
+ for i=0 upto length p :
+ if ypart(point i of p)<>0 :
+ augment.q(xpart(point i of p), 1/ypart(point i of p)) ;
+ fi
+ endfor
+ polynomial_fit(q,a,2,if t <> 0 : 1/(t) else : 0 fi) ;
+ fit_chi_squared := 1/fit_chi_squared ;
+ $0 := -.5a1/a2 ;
+ $2 := 1/(a0-.25a1*a1/a2) ;
+ $1 := sqrt((a0-.25a1*a1/a2)/a2) ;
+ $3 := 0 ; % polynomial_fit will NOT work with a non-zero background!
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-grid.mpiv b/metapost/context/base/mpiv/mp-grid.mpiv
new file mode 100644
index 000000000..b9243b1b9
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-grid.mpiv
@@ -0,0 +1,142 @@
+%D \module
+%D [ file=mp-grid.mpiv,
+%D version=2000.07.10,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=grid support,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+%D Under construction.
+
+if known context_grid : endinput ; fi ;
+
+boolean context_grid ; context_grid := true ;
+
+string fmt_separator ; fmt_separator := "@" ;
+numeric fmt_precision ; fmt_precision := 3 ;
+boolean fmt_initialize ; fmt_initialize := false ;
+boolean fmt_zerocheck ; fmt_zerocheck := true ;
+
+if unknown fmt_loaded : input "mp-form.mpiv" ; fi ;
+
+boolean fmt_pictures ; fmt_pictures := true ;
+
+def do_format = if fmt_pictures : format else : formatstr fi enddef ;
+def do_mformat = if fmt_pictures : Mformat else : Mformatstr fi enddef ;
+
+numeric grid_eps ; grid_eps = eps ;
+
+def hlingrid (expr Min, Max, Step, Length, Width) text t =
+ image (
+ for i=Min step Step until Max+grid_eps :
+ draw (origin--(Width,0)) shifted (0,i*(Length/Max)) t ;
+ endfor ;
+ ) ;
+enddef ;
+
+def vlingrid (expr Min, Max, Step, Length, Height) text t =
+ image (
+ for i=Min step Step until Max+grid_eps :
+ draw (origin--(0,Height)) shifted (i*(Length/Max),0) t ;
+ endfor ;
+ ) ;
+enddef ;
+
+def hloggrid (expr Min, Max, Step, Length, Width) text t =
+ image (
+ for i=max(Min,1) step Step until min(Max,10)+grid_eps :
+ draw (origin--(Width,0)) shifted (0,Length*log(i)) t ;
+ endfor ;
+ ) ;
+enddef ;
+
+def vloggrid (expr Min, Max, Step, Length, Height) text t =
+ image (
+ for i=max(Min,1) step Step until min(Max,10)+grid_eps :
+ draw (origin--(0,Height)) shifted (Length*log(i),0) t ;
+ endfor ;
+ ) ;
+enddef ;
+
+vardef hlintext@#(expr Min, Max, Step, Length, Format) text t =
+ image (
+ for i=Min step Step until Max+grid_eps :
+ draw textext@#(mfun_format_number(Format,i)) shifted (0,i*(Length/Max)) t ;
+ endfor ;
+ )
+enddef ;
+
+vardef vlintext@#(expr Min, Max, Step, Length, Format) text t =
+ image (
+ for i=Min step Step until Max+grid_eps :
+ draw textext@#(mfun_format_number(Format,i)) shifted (i*(Length/Max),0) t ;
+ endfor ;
+ )
+enddef ;
+
+vardef hlogtext@#(expr Min, Max, Step, Length, Format) text t =
+ image (
+ for i=max(Min,1) step Step until min(Max,10)+grid_eps :
+ draw textext@#(mfun_format_number(Format,i)) shifted (0,Length*log(i)) t ;
+ endfor ;
+ )
+enddef ;
+
+vardef vlogtext@#(expr Min, Max, Step, Length, Format) text t =
+ image (
+ for i=max(Min,1) step Step until min(Max,10)+grid_eps :
+ draw textext@#(mfun_format_number(Format,i)) shifted (Length*log(i),0) t ;
+ endfor ;
+ )
+enddef ;
+
+vardef hlinlabel@#(expr Min, Max, Step, Length) text t =
+ image (
+ for i=Min step Step until Max+grid_eps :
+ draw thelabel@#(decimal i,(0,i*(Length/Max))) t ;
+ endfor ;
+ )
+enddef ;
+
+vardef vlinlabel@#(expr Min, Max, Step, Length) text t =
+ image (
+ for i=Min step Step until Max+grid_eps :
+ draw thelabel@#(decimal i,(i*(Length/Max),0)) t ;
+ endfor ;
+ )
+enddef ;
+
+vardef linlog(expr xy) = ( xpart xy, log(ypart xy)) enddef ;
+vardef loglin(expr xy) = (log(xpart xy), ypart xy) enddef ;
+vardef loglog(expr xy) = (log(xpart xy), log(ypart xy)) enddef ;
+vardef linlin(expr xy) = ( (xpart xy), (ypart xy)) enddef ;
+
+vardef loglinpath primary p = processpath (p) (loglin) enddef ;
+vardef linlogpath primary p = processpath (p) (linlog) enddef ;
+vardef loglogpath primary p = processpath (p) (loglog) enddef ;
+vardef linlinpath primary p = processpath (p) (linlin) enddef ;
+
+vardef processpath (expr p) (text pp) =
+ if path p :
+ for i=0 upto length(p)-1 :
+ pp(point i of p) .. controls
+ pp(postcontrol i of p) and
+ pp(precontrol (i+1) of p) ..
+ endfor
+ if cycle p :
+ cycle
+ else :
+ pp(point length(p) of p)
+ fi
+ elseif pair p :
+ pp(p)
+ else :
+ p
+ fi
+enddef ;
+
diff --git a/metapost/context/base/mpiv/mp-grph.mpiv b/metapost/context/base/mpiv/mp-grph.mpiv
new file mode 100644
index 000000000..5938b9f02
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-grph.mpiv
@@ -0,0 +1,348 @@
+%D \module
+%D [ file=mp-grph.mpiv,
+%D version=2000.12.14,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=graphic text support,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+%D Under construction.
+
+if known context_grph : endinput ; fi ;
+
+boolean context_grph ; context_grph := true ;
+
+picture _currentpicture_ ;
+
+numeric _fig_nesting_ ; _fig_nesting_ := 0 ;
+
+def beginfig (expr c) =
+ _fig_nesting_ := _fig_nesting_ + 1 ;
+ if _fig_nesting_ = 1 :
+ begingroup
+ charcode := c ;
+ resetfig ;
+ scantokens extra_beginfig ;
+ fi ;
+enddef ;
+
+def endfig =
+ ; % safeguard
+ if _fig_nesting_ = 1 :
+ scantokens extra_endfig ;
+ shipit ;
+ endgroup ;
+ fi ;
+ _fig_nesting_ := _fig_nesting_ - 1 ;
+enddef;
+
+def resetfig =
+ clearxy ;
+ clearit ;
+ clearpen ;
+ pickup defaultpen ;
+ interim linecap := linecap ;
+ interim linejoin := linejoin ;
+ interim miterlimit := miterlimit ;
+ save _background_ ; color _background_ ; _background_ := background ;
+ save background ; color background ; background := _background_ ;
+ drawoptions () ;
+enddef ;
+
+def protectgraphicmacros =
+ save showtext ;
+ save beginfig ; let beginfig = begingraphictextfig ;
+ save endfig ; let endfig = endgraphictextfig ;
+ save end ; let end = relax ;
+ interim prologues := prologues ;
+ resetfig ; % resets currentpicture
+enddef ;
+
+numeric currentgraphictext ; currentgraphictext := 0 ;
+
+def data_mpo_file = job_name & "-mpgraph.mpo" enddef ;
+def data_mpy_file = job_name & "-mpgraph.mpy" enddef ;
+
+def begingraphictextfig (expr n) =
+ foundpicture := n ;
+ scratchpicture := nullpicture ;
+enddef ;
+
+def endgraphictextfig =
+ if foundpicture = currentgraphictext :
+ expandafter endinput
+ else :
+ scratchpicture := nullpicture ;
+ fi ;
+enddef ;
+
+def loadfigure primary filename =
+ doloadfigure (filename)
+enddef ;
+
+def doloadfigure (expr filename) text figureattributes =
+ begingroup ;
+ save figurenumber, figurepicture, number, fixedplace ;
+ numeric figurenumber ; figurenumber := 0 ;
+ boolean figureshift ; figureshift := true ;
+ picture figurepicture ; figurepicture := currentpicture ;
+ def number primary n = hide(figurenumber := n) enddef ;
+ def fixedplace = hide(figureshift := false) enddef ;
+ protectgraphicmacros ;
+ % defaults
+ interim linecap := rounded ;
+ interim linejoin := rounded ;
+ interim miterlimit := 10 ;
+ %
+ currentpicture := nullpicture ;
+ draw fullcircle figureattributes ; % expand number
+ currentpicture := nullpicture ;
+ def beginfig (expr n) =
+ currentpicture := nullpicture ;
+ if (figurenumber=n) or (figurenumber=0) :
+ let endfig = endinput ;
+ fi ;
+ enddef ;
+ let endfig = relax ;
+ readfile(filename) ;
+ if figureshift :
+ currentpicture := currentpicture shifted -llcorner currentpicture ;
+ fi ;
+ addto figurepicture also currentpicture figureattributes ;
+ currentpicture := figurepicture ;
+ endgroup ;
+enddef ;
+
+% shared between old and new
+
+boolean mfun_gt_color_fill ;
+boolean mfun_gt_color_draw ;
+boolean mfun_gt_shade_fill ;
+boolean mfun_gt_reverse_fill ;
+boolean mfun_gt_outline_fill ;
+picture mfun_gt_picture ;
+
+% this is the old version:
+
+def old_graphictext primary t =
+ hide (
+ if mfun_trial_run :
+ let mfun_graphic_text = mfun_no_graphic_text ;
+ else :
+ let mfun_graphic_text = mfun_do_graphic_text ;
+ fi
+ )
+ mfun_graphic_text(t)
+enddef ;
+
+def mfun_do_graphic_text (expr t) =
+ % withprescript "gt_stage=final"
+ begingroup ;
+ save figurepicture ; picture figurepicture ;
+ figurepicture := currentpicture ; currentpicture := nullpicture ;
+ currentgraphictext := currentgraphictext + 1 ;
+ mfun_finish_graphic_text % picks up directives
+enddef ;
+
+def mfun_no_graphic_text (expr t) text rest =
+ currentgraphictext := currentgraphictext + 1 ;
+ draw unitsquare
+ withprescript "gt_stage=trial"
+ withprescript "gt_index=" & decimal currentgraphictext
+ withpostscript t
+enddef ;
+
+def mfun_finish_graphic_text text rest =
+ protectgraphicmacros ; % resets currentpicture
+ interim linecap := butt ; % normally rounded
+ interim linejoin := mitered ; % normally rounded
+ interim miterlimit := 10 ; % todo
+ let normalwithshade = withshade ;
+ save foundpicture, scratchpicture, str ;
+ save fill, draw, withshade, reversefill, outlinefill ;
+ save withfillcolor, withdrawcolor ; % quite important
+ numeric foundpicture ; picture scratchpicture ; string str ;
+ def draw expr p =
+ % the first, naive implementation was:
+ % addto scratchpicture doublepath p withpen currentpen ;
+ % but it is better to turn lines into fills
+ addto scratchpicture contour boundingbox
+ image (addto currentpicture doublepath p withpen currentpen) ;
+ enddef ;
+ def fill expr p =
+ addto scratchpicture contour p withpen currentpen ;
+ enddef ;
+ def mfun_gt_fill = enddef ; boolean mfun_gt_color_fill ; mfun_gt_color_fill := false ;
+ def mfun_gt_draw = enddef ; boolean mfun_gt_color_draw ; mfun_gt_color_draw := false ;
+ def mfun_gt_shade = enddef ; boolean mfun_gt_shade_fill ; mfun_gt_shade_fill := false ;
+ boolean mfun_gt_reverse_fill ; mfun_gt_reverse_fill := false ;
+ boolean mfun_gt_outline_fill ; mfun_gt_outline_fill := false ;
+ def reversefill =
+ hide(mfun_gt_reverse_fill := true )
+ enddef ;
+ def outlinefill =
+ hide(mfun_gt_outline_fill := true )
+ enddef ;
+ def withshade primary c =
+ hide(def mfun_gt_shade = normalwithshade c enddef ; mfun_gt_shade_fill := true )
+ enddef ;
+ def withfillcolor primary c =
+ hide(def mfun_gt_fill = withcolor c enddef ; mfun_gt_color_fill := true )
+ enddef ;
+ def withdrawcolor primary c =
+ hide(def mfun_gt_draw = withcolor c enddef ; mfun_gt_color_draw := true )
+ enddef ;
+ scratchpicture := nullpicture ;
+ addto scratchpicture doublepath origin rest ; % pre-roll
+ for i within scratchpicture : % Below here is a dirty tricky test!
+ if (urcorner dashpart i) = origin :
+ mfun_gt_outline_fill := false ;
+ fi ;
+ endfor ;
+ scratchpicture := nullpicture ;
+ readfile(data_mpy_file) ;
+ scratchpicture := (scratchpicture shifted -llcorner scratchpicture) scaled (1/10) ;
+ if not mfun_gt_color_draw and not mfun_gt_color_fill :
+ mfun_gt_color_draw := true ;
+ fi
+ if mfun_gt_shade_fill :
+ mfun_gt_color_draw := false ;
+ mfun_gt_color_fill := false ;
+ fi ;
+ currentpicture := figurepicture ;
+ if mfun_gt_shade_fill :
+ for i within scratchpicture :
+ if filled i :
+ addto currentpicture contour pathpart i _op_ rest mfun_gt_shade ;
+ fi ;
+ endfor ;
+ else :
+ if mfun_gt_color_draw and not mfun_gt_reverse_fill :
+ for i within scratchpicture :
+ if mfun_gt_color_fill and mfun_gt_outline_fill :
+ addto currentpicture doublepath pathpart i _op_ rest mfun_gt_fill dashed nullpicture ;
+ fi ;
+ if filled i :
+ addto currentpicture doublepath pathpart i _op_ rest mfun_gt_draw ;
+ fi ;
+ endfor ;
+ fi ;
+ if mfun_gt_color_fill :
+ for i within scratchpicture :
+ if filled i :
+ addto currentpicture contour pathpart i _op_ rest mfun_gt_fill withpen pencircle scaled 0 ;
+ fi ;
+ endfor ;
+ fi ;
+ if mfun_gt_color_draw and mfun_gt_reverse_fill :
+ for i within scratchpicture :
+ if filled i :
+ addto currentpicture doublepath pathpart i _op_ rest mfun_gt_draw ;
+ fi ;
+ endfor ;
+ fi ;
+ for i within scratchpicture :
+ if stroked i :
+ addto currentpicture doublepath pathpart i _op_ rest mfun_gt_draw ;
+ fi ;
+ endfor ;
+ fi ;
+ endgroup ;
+enddef ;
+
+% and this is the new one:
+
+% boolean mfun_gt_color_fill ;
+% boolean mfun_gt_color_draw ;
+% boolean mfun_gt_shade_fill ;
+% boolean mfun_gt_reverse_fill ;
+% picture mfun_gt_picture ;
+
+def mfun_gt_default = % somewhat compatible
+ scaled 11.5
+ withpen pencircle scaled .1
+enddef ;
+
+def new_graphictext primary t = % use outlinetext instead
+ begingroup ;
+ mfun_graphic_text_indeed(t)
+enddef ;
+
+def mfun_graphic_text_indeed(expr t) text rest =
+ interim linecap := butt ; % normally rounded
+ interim linejoin := mitered ; % normally rounded
+ % interim miterlimit := 10 ; % todo
+ %
+ let normalwithshade = withshade ;
+ %
+ save reversefill, outlinefill, withshade, withfillcolor, withdrawcolor ;
+ %
+ def mfun_gt_fill = enddef ;
+ def mfun_gt_draw = enddef ;
+ def mfun_gt_shade = enddef ;
+ %
+ mfun_gt_color_fill := false ;
+ mfun_gt_color_draw := false ;
+ mfun_gt_shade_fill := false ;
+ mfun_gt_reverse_fill := false ;
+ %
+ def reversefill = hide(mfun_gt_reverse_fill := true) enddef ;
+ def outlinefill = enddef ;
+ def withshade primary c = hide(mfun_gt_shade_fill := true; def mfun_gt_shade = normalwithshade c enddef ;) enddef ;
+ def withfillcolor primary c = hide(mfun_gt_color_fill := true; def mfun_gt_fill = withcolor c enddef ;) enddef ;
+ def withdrawcolor primary c = hide(mfun_gt_color_draw := true; def mfun_gt_draw = withcolor c enddef ;) enddef ;
+ %
+ mfun_gt_picture := nullpicture ;
+ addto mfun_gt_picture doublepath origin rest ; % preroll
+ mfun_gt_picture := nullpicture ;
+ %
+ def reversefill = enddef ;
+ def outlinefill = enddef ;
+ def withshade primary c = enddef ;
+ def withfillcolor primary c = enddef ;
+ def withdrawcolor primary c = enddef ;
+ %
+ if mfun_gt_shade_fill :
+ draw outlinetext.f(t)(mfun_gt_shade) rest;
+ elseif mfun_gt_color_fill and mfun_gt_color_draw :
+ if mfun_gt_reverse_fill :
+ draw outlinetext.r(t)(mfun_gt_default mfun_gt_fill rest)(mfun_gt_default mfun_gt_draw rest) ;
+ else :
+ draw outlinetext.b(t)(mfun_gt_default mfun_gt_draw rest)(mfun_gt_default mfun_gt_fill rest);
+ fi ;
+ elseif mfun_gt_color_fill :
+ draw outlinetext.f(t)(mfun_gt_default mfun_gt_fill rest) ;
+ elseif mfun_gt_color_draw :
+ draw outlinetext.d(t)(mfun_gt_default mfun_gt_draw rest) ;
+ else :
+ draw outlinetext.d(t)(mfun_gt_default rest) ;
+ fi ;
+ %
+ endgroup ;
+enddef ;
+
+let graphictext = old_graphictext ;
+%%% graphictext = new_graphictext ; % more than 10 times faster
+
+% example
+%
+% beginfig (1) ;
+% graphictext
+% "\vbox{\hsize10cm \input tufte }"
+% scaled 8
+% withdrawcolor blue
+% withfillcolor red
+% withpen pencircle scaled 2pt ;
+% endfig ;
+%
+% beginfig(1) ;
+% loadfigure "gracht.mp" rotated 20 ;
+% loadfigure "koe.mp" number 1 scaled 2 ;
+% endfig ;
+%
+% end
diff --git a/metapost/context/base/mpiv/mp-idea.mpiv b/metapost/context/base/mpiv/mp-idea.mpiv
new file mode 100644
index 000000000..462d97553
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-idea.mpiv
@@ -0,0 +1,30 @@
+% redpart (1,1,0,0) crashes
+
+% let normalredpart = redpart ;
+% let normalgreenpart = greenpart ;
+% let normalbluepart = bluepart ;
+% let normalcyanpart = cyanpart ;
+% let normalmagentapart = magentapart ;
+% let normalyellowpart = yellowpart ;
+% let normalblackpart = blackpart ;
+
+% vardef redpart expr p = if cmykcolor p : 1 - normalcyanpart p elseif rgbcolor p : normalredpart p else : p fi enddef ;
+% vardef greenpart expr p = if cmykcolor p : 1 - normalmagentapart p elseif rgbcolor p : normalgreenpart p else : p fi enddef ;
+% vardef bluepart expr p = if cmykcolor p : 1 - normalyellowpart p elseif rgbcolor p : normalbluepart p else : p fi enddef ;
+% vardef cyanpart expr p = if cmykcolor p : normalcyanpart p elseif rgbcolor p : 1 - normalredpart p else : p fi enddef ;
+% vardef magentapart expr p = if cmykcolor p : normalmagentapart p elseif rgbcolor p : 1 - normalgreenpart p else : p fi enddef ;
+% vardef yellowpart expr p = if cmykcolor p : normalyellowpart p elseif rgbcolor p : 1 - normalbluepart p else : p fi enddef ;
+% vardef blackpart expr p = if cmykcolor p : normalblackpart p elseif rgbcolor p : 0 else : p fi enddef ;
+
+vardef rcomponent expr p = if rgbcolor p : redpart p elseif cmykcolor p : 1 - cyanpart p else : p fi enddef ;
+vardef gcomponent expr p = if rgbcolor p : greenpart p elseif cmykcolor p : 1 - magentapart p else : p fi enddef ;
+vardef bcomponent expr p = if rgbcolor p : bluepart p elseif cmykcolor p : 1 - yellowpart p else : p fi enddef ;
+vardef ccomponent expr p = if cmykcolor p : cyanpart p elseif rgbcolor p : 1 - redpart p else : p fi enddef ;
+vardef mcomponent expr p = if cmykcolor p : magentapart p elseif rgbcolor p : 1 - greenpart p else : p fi enddef ;
+vardef ycomponent expr p = if cmykcolor p : yellowpart p elseif rgbcolor p : 1 - bluepart p else : p fi enddef ;
+vardef bcomponent expr p = if cmykcolor p : blackpart p elseif rgbcolor p : 0 else : p fi enddef ;
+
+vardef somecolor = (1,1,0,0) enddef ;
+
+fill OverlayBox withcolor (rcomponent somecolor,gcomponent somecolor,bcomponent somecolor) ;
+fill OverlayBox withcolor (ccomponent somecolor,mcomponent somecolor,ycomponent somecolor,bcomponent somecolor) ;
diff --git a/metapost/context/base/mpiv/mp-luas.mpiv b/metapost/context/base/mpiv/mp-luas.mpiv
new file mode 100644
index 000000000..c919ba215
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-luas.mpiv
@@ -0,0 +1,99 @@
+%D \module
+%D [ file=mp-luas.mpiv,
+%D version=2014.04.14,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=\LUA,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+if known context_luas : endinput ; fi ;
+
+% When I prototyped the runscript primitive I was just thinking of a usage like
+% the original \directlua primitive in luatex: genererate something and pipe
+% that back to metapost, and have access to some internals. Instead of compiling
+% the code a the metapost end here we delegate that to the lua end. Only strings
+% get passed. Of course in the end the real usage got a bit beyong the intended
+% usage. So, in addition to some definitions here there are and will be use in
+% other metafun modules too. Of course in retrospect I should have done this five
+% years earlier.
+
+boolean context_luas ; context_luas := true ;
+
+% First variant:
+%
+% let lua = runscript ;
+%
+% Second variant:
+%
+% vardef lua (text t) =
+% runscript(for s = t : s & endfor "")
+% enddef;
+%
+% Third variant:
+%
+% vardef lua (text t) =
+% runscript("" for s = t :
+% if string s :
+% & s
+% elseif numeric s :
+% & decimal s
+% elseif boolean s :
+% & if s : "true" else "false" fi
+% fi endfor)
+% enddef;
+%
+% Fourth variant:
+
+vardef mlib_luas_luacall(text t) =
+ runscript("" for s = t :
+ if string s :
+ & s
+ elseif numeric s :
+ & decimal s
+ elseif boolean s :
+ & if s : "true" else "false" fi
+ fi endfor
+ )
+enddef ;
+
+vardef mlib_luas_lualist(expr c)(text t) =
+ save b ; boolean b ; b := false ;
+ runscript(c & "(" for s = t :
+ if b :
+ & ","
+ else :
+ hide(b := true)
+ fi
+ if string s :
+ & ditto & s & ditto
+ elseif numeric s :
+ & decimal s
+ elseif boolean s :
+ & if s : "true" else "false" fi
+ fi endfor & ")"
+ )
+enddef ;
+
+def luacall = mlib_luas_luacall enddef ; % why no let
+
+vardef lualist@#(text t) = mlib_luas_lualist(str @#)(t) enddef ;
+
+string mlib_luas_s ; % saves save/restore
+
+vardef lua@#(text t) =
+ mlib_luas_s := str @# ;
+ if length(mlib_luas_s) > 0 :
+ mlib_luas_lualist(mlib_luas_s,t)
+ else :
+ mlib_luas_luacall(t)
+ fi
+enddef ;
+
+vardef MP@#(text t) =
+ mlib_luas_lualist("MP." & str @#,t)
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-mlib.mpiv b/metapost/context/base/mpiv/mp-mlib.mpiv
new file mode 100644
index 000000000..2c84d01c2
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-mlib.mpiv
@@ -0,0 +1,1450 @@
+%D \module
+%D [ file=mp-mlib.mpiv,
+%D version=2008.03.21,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=plugins,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if unknown mplib : endinput ; fi ;
+if known context_mlib : endinput ; fi ;
+
+boolean context_mlib ; context_mlib := true ;
+
+%D Color and transparency
+%D
+%D Separable:
+
+newinternal normaltransparent ; normaltransparent := 1 ;
+newinternal multiplytransparent ; multiplytransparent := 2 ;
+newinternal screentransparent ; screentransparent := 3 ;
+newinternal overlaytransparent ; overlaytransparent := 4 ;
+newinternal softlighttransparent ; softlighttransparent := 5 ;
+newinternal hardlighttransparent ; hardlighttransparent := 6 ;
+newinternal colordodgetransparent ; colordodgetransparent := 7 ;
+newinternal colorburntransparent ; colorburntransparent := 8 ;
+newinternal darkentransparent ; darkentransparent := 9 ;
+newinternal lightentransparent ; lightentransparent := 10 ;
+newinternal differencetransparent ; differencetransparent := 11 ;
+newinternal exclusiontransparent ; exclusiontransparent := 12 ;
+
+%D Nonseparable:
+
+newinternal huetransparent ; huetransparent := 13 ;
+newinternal saturationtransparent ; saturationtransparent := 14 ;
+newinternal colortransparent ; colortransparent := 15 ;
+newinternal luminositytransparent ; luminositytransparent := 16 ;
+
+vardef transparency_alternative_to_number(expr name) =
+ if string name :
+ if expandafter known scantokens(name & "transparent") :
+ scantokens(name & "transparent")
+ else :
+ 0
+ fi
+ elseif name < 17 :
+ name
+ else :
+ 0
+ fi
+enddef ;
+
+def namedcolor (expr n) =
+ 1
+ withprescript "sp_type=named"
+ withprescript "sp_name=" & n
+enddef ;
+
+% def spotcolor(expr n, v) =
+% 1
+% withprescript "sp_type=spot"
+% withprescript "sp_name=" & n
+% withprescript "sp_value=" & (if numeric v : decimal v else : v fi)
+% enddef ;
+%
+% def multitonecolor(expr name, fractions, components, value) =
+% 1
+% withprescript "sp_type=multitone"
+% withprescript "sp_name=" & name
+% withprescript "sp_fractions=" & decimal fractions
+% withprescript "sp_components=" & components
+% withprescript "sp_value=" & value
+% enddef ;
+
+def spotcolor(expr n, v) =
+ 1
+ withprescript "sp_type=spot"
+ withprescript "sp_name=" & n
+ withprescript "sp_value=" & colordecimals v
+enddef ;
+
+def multitonecolor(expr name)(text t) =
+ 1
+ withprescript "sp_type=multitone"
+ withprescript "sp_name=" & name
+ withprescript "sp_value=" & colordecimalslist(t)
+enddef ;
+
+def transparent(expr a, t)(text c) = % use withtransparency instead
+ 1 % this permits withcolor x intoshade y
+ withprescript "tr_alternative=" & decimal transparency_alternative_to_number(a)
+ withprescript "tr_transparency=" & decimal t
+ withcolor c
+enddef ;
+
+% def withtransparency(expr a, t) =
+% withprescript "tr_alternative=" & decimal transparency_alternative_to_number(a)
+% withprescript "tr_transparency=" & decimal t
+% enddef ;
+
+let transparency = pair ;
+
+% def withtransparency expr t =
+% withprescript "tr_alternative=" & decimal transparency_alternative_to_number(xpart t)
+% withprescript "tr_transparency=" & decimal ypart t
+% enddef ;
+%
+% withtransparency (1,.5)
+% withtransparency ("normal",.5)
+
+def withtransparency (expr t) (text rest) =
+ if pair t :
+ withprescript "tr_alternative=" & decimal transparency_alternative_to_number(xpart t)
+ withprescript "tr_transparency=" & decimal ypart t
+ else :
+ mfun_with_transparency (transparency_alternative_to_number(t))
+ fi rest
+enddef ;
+
+def mfun_with_transparency (expr a) expr t =
+ withprescript "tr_alternative=" & decimal a
+ withprescript "tr_transparency=" & decimal t
+enddef ;
+
+def cmyk(expr c, m, y, k) = % provided for downward compability
+ (c,m,y,k)
+enddef ;
+
+% Texts (todo: better strut ratio, now .7 hardcoded, should be passed)
+
+newinternal textextoffset ; textextoffset := 0 ;
+
+%%%%%%% mfun_tt_w[], mfun_tt_h[], mfun_tt_d[] ; % we can consider using colors (less hash space)
+color mfun_tt_b ;
+numeric mfun_tt_n ; mfun_tt_n := 0 ;
+picture mfun_tt_p ; mfun_tt_p := nullpicture ;
+picture mfun_tt_o ; mfun_tt_o := nullpicture ;
+picture mfun_tt_c ; mfun_tt_c := nullpicture ;
+
+if unknown mfun_trial_run :
+ boolean mfun_trial_run ;
+ mfun_trial_run := false ;
+else :
+ % already defined before the format is loaded
+fi ;
+
+if unknown mfun_first_run :
+ boolean mfun_first_run ;
+ mfun_first_run := true ;
+else :
+ % already defined before the format is loaded
+fi ;
+
+def mfun_reset_tex_texts =
+ mfun_tt_n := 0 ;
+ mfun_tt_p := nullpicture ;
+ mfun_tt_o := nullpicture ; % redundant
+ mfun_tt_c := nullpicture ; % redundant
+enddef ;
+
+def mfun_flush_tex_texts =
+ addto currentpicture also mfun_tt_p
+enddef ;
+
+extra_endfig := "mfun_flush_tex_texts ;" & extra_endfig ;
+extra_beginfig := extra_beginfig & "mfun_reset_tex_texts ;" ;
+
+% We collect and flush them all, as we can also have temporary textexts
+% that gets never really flushed but are used for calculations. So, we
+% flush twice: once in location in order to pick up e.g. color properties,
+% and once at the end because we need to flush missing ones.
+
+% see mp-keep.mpiv for older code
+
+% vardef rawtextext(expr s) = % todo: avoid currentpicture
+% if s = "" :
+% nullpicture
+% else :
+% mfun_tt_n := mfun_tt_n + 1 ;
+% mfun_tt_c := nullpicture ;
+% if mfun_trial_run :
+% mfun_tt_o := nullpicture ;
+% addto mfun_tt_o doublepath origin _op_ ; % save drawoptions
+% addto mfun_tt_c doublepath unitsquare
+% withprescript "tx_number=" & decimal mfun_tt_n
+% withprescript "tx_stage=trial"
+% withprescript "tx_color=" & colordecimals colorpart mfun_tt_o
+% withpostscript s ;
+% addto mfun_tt_p also mfun_tt_c ;
+% elseif known mfun_tt_d[mfun_tt_n] :
+% addto mfun_tt_c doublepath unitsquare
+% xscaled mfun_tt_w[mfun_tt_n]
+% yscaled (mfun_tt_h[mfun_tt_n] + mfun_tt_d[mfun_tt_n])
+% shifted (0,-mfun_tt_d[mfun_tt_n])
+% withprescript "tx_number=" & decimal mfun_tt_n
+% withprescript "tx_stage=final" ;
+% else :
+% addto mfun_tt_c doublepath unitsquare ; % unitpicture
+% fi ;
+% mfun_tt_c
+% fi
+% enddef ;
+
+boolean mfun_onetime_textext ; mfun_onetime_textext := false ;
+
+vardef rawtextext(expr s) = % todo: avoid currentpicture
+ if s = "" :
+ mfun_onetime_textext := false ;
+ nullpicture
+ else :
+ mfun_tt_n := mfun_tt_n + 1 ;
+ mfun_tt_c := nullpicture ;
+ if mfun_trial_run :
+ mfun_tt_o := nullpicture ;
+ addto mfun_tt_o doublepath origin _op_ ; % save drawoptions
+ addto mfun_tt_c doublepath unitsquare
+ withprescript "tx_number=" & decimal mfun_tt_n
+ withprescript "tx_stage=trial"
+ withprescript "tx_color=" & colordecimals colorpart mfun_tt_o
+ withpostscript s ;
+ if not mfun_onetime_textext :
+ addto mfun_tt_p also mfun_tt_c
+ withprescript "tx_global=yes" ;
+ fi ;
+ else :
+ mfun_tt_b := lua.mp.tt_dimensions(mfun_tt_n) ;
+ addto mfun_tt_c doublepath unitsquare
+ xscaled redpart mfun_tt_b
+ yscaled (greenpart mfun_tt_b + bluepart mfun_tt_b)
+ shifted (0,- bluepart mfun_tt_b)
+ withprescript "tx_number=" & decimal mfun_tt_n
+ withprescript "tx_stage=final" ;
+ fi ;
+ mfun_onetime_textext := false ;
+ mfun_tt_c
+ fi
+enddef ;
+
+% More text
+
+defaultfont := "Mono" ;
+defaultscale := 1 ;
+
+extra_beginfig := extra_beginfig & "defaultscale:=1;" ;
+
+vardef fontsize expr name =
+ save size ; numeric size ;
+ size := bbwidth(textext("\MPfontsizehskip{" & name & "}")) ;
+ if size = 0 :
+ 12pt
+ else :
+ size
+ fi
+enddef ;
+
+pair mfun_laboff ; mfun_laboff := (0,0) ;
+pair mfun_laboff.lft ; mfun_laboff.lft := (-1,0) ;
+pair mfun_laboff.rt ; mfun_laboff.rt := (1,0) ;
+pair mfun_laboff.bot ; mfun_laboff.bot := (0,-1) ;
+pair mfun_laboff.top ; mfun_laboff.top := (0,1) ;
+pair mfun_laboff.ulft ; mfun_laboff.ulft := (-.7,.7) ;
+pair mfun_laboff.urt ; mfun_laboff.urt := (.7,.7) ;
+pair mfun_laboff.llft ; mfun_laboff.llft := -(.7,.7) ;
+pair mfun_laboff.lrt ; mfun_laboff.lrt := (.7,-.7) ;
+
+pair mfun_laboff.d ; mfun_laboff.d := mfun_laboff ;
+pair mfun_laboff.dlft ; mfun_laboff.dlft := mfun_laboff.lft ;
+pair mfun_laboff.drt ; mfun_laboff.drt := mfun_laboff.rt ;
+pair mfun_laboff.origin ; mfun_laboff.origin := origin ;
+pair mfun_laboff.raw ; mfun_laboff.raw := origin ;
+
+pair mfun_laboff.l ; mfun_laboff.l := mfun_laboff.lft ;
+pair mfun_laboff.r ; mfun_laboff.r := mfun_laboff.rt ;
+pair mfun_laboff.b ; mfun_laboff.b := mfun_laboff.bot ;
+pair mfun_laboff.t ; mfun_laboff.t := mfun_laboff.top ;
+pair mfun_laboff.l_t ; mfun_laboff.l_t := mfun_laboff.ulft ;
+pair mfun_laboff.r_t ; mfun_laboff.r_t := mfun_laboff.urt ;
+pair mfun_laboff.l_b ; mfun_laboff.l_b := mfun_laboff.llft ;
+pair mfun_laboff.r_b ; mfun_laboff.r_b := mfun_laboff.lrt ;
+pair mfun_laboff.t_l ; mfun_laboff.t_l := mfun_laboff.ulft ;
+pair mfun_laboff.t_r ; mfun_laboff.t_r := mfun_laboff.urt ;
+pair mfun_laboff.b_l ; mfun_laboff.b_l := mfun_laboff.llft ;
+pair mfun_laboff.b_r ; mfun_laboff.b_r := mfun_laboff.lrt ;
+
+mfun_labxf := 0.5 ;
+mfun_labxf.lft := mfun_labxf.l := 1 ;
+mfun_labxf.rt := mfun_labxf.r := 0 ;
+mfun_labxf.bot := mfun_labxf.b := 0.5 ;
+mfun_labxf.top := mfun_labxf.t := 0.5 ;
+mfun_labxf.ulft := mfun_labxf.l_t := mfun_labxf.t_l := 1 ;
+mfun_labxf.urt := mfun_labxf.r_t := mfun_labxf.t_r := 0 ;
+mfun_labxf.llft := mfun_labxf.l_b := mfun_labxf.b_l := 1 ;
+mfun_labxf.lrt := mfun_labxf.r_b := mfun_labxf.b_r := 0 ;
+
+mfun_labxf.d := mfun_labxf ;
+mfun_labxf.dlft := mfun_labxf.lft ;
+mfun_labxf.drt := mfun_labxf.rt ;
+mfun_labxf.origin := 0 ;
+mfun_labxf.raw := 0 ;
+
+mfun_labyf := 0.5 ;
+mfun_labyf.lft := mfun_labyf.l := 0.5 ;
+mfun_labyf.rt := mfun_labyf.r := 0.5 ;
+mfun_labyf.bot := mfun_labyf.b := 1 ;
+mfun_labyf.top := mfun_labyf.t := 0 ;
+mfun_labyf.ulft := mfun_labyf.l_t := mfun_labyf.t_l := 0 ;
+mfun_labyf.urt := mfun_labyf.r_t := mfun_labyf.t_r := 0 ;
+mfun_labyf.llft := mfun_labyf.l_b := mfun_labyf.b_l := 1 ;
+mfun_labyf.lrt := mfun_labyf.r_b := mfun_labyf.b_r := 1 ;
+
+mfun_labyf.d := mfun_labyf ;
+mfun_labyf.dlft := mfun_labyf.lft ;
+mfun_labyf.drt := mfun_labyf.rt ;
+mfun_labyf.origin := 0 ;
+mfun_labyf.raw := 0 ;
+
+mfun_labtype := 0 ;
+mfun_labtype.lft := mfun_labtype.l := 1 ;
+mfun_labtype.rt := mfun_labtype.r := 2 ;
+mfun_labtype.bot := mfun_labtype.b := 3 ;
+mfun_labtype.top := mfun_labtype.t := 4 ;
+mfun_labtype.ulft := mfun_labtype.l_t := mfun_labtype.t_l := 5 ;
+mfun_labtype.urt := mfun_labtype.r_t := mfun_labtype.t_r := 6 ;
+mfun_labtype.llft := mfun_labtype.l_b := mfun_labtype.b_l := 7 ;
+mfun_labtype.lrt := mfun_labtype.r_b := mfun_labtype.b_r := 8 ;
+mfun_labtype.d := 10 ;
+mfun_labtype.dlft := 11 ;
+mfun_labtype.drt := 12 ;
+mfun_labtype.origin := 0 ;
+mfun_labtype.raw := 0 ;
+
+% installlabel.foo ( 0, 1, 1, (.5,-1) ) ;
+
+vardef installlabel@# (expr type, x, y, offset) =
+ numeric labtype@# ; labtype@# := type ;
+ pair laboff @# ; laboff @# := offset ;
+ numeric labxf @# ; labxf @# := x ;
+ numeric labyf @# ; labyf @# := y ;
+enddef ;
+
+% we save the plain variant
+
+vardef plain_thelabel@#(expr p,z) =
+ if string p :
+ plain_thelabel@#(rawtextext("\definedfont[" & defaultfont & "]" & p) scaled defaultscale,z)
+ else :
+ p shifted (z + labeloffset*laboff@# - (labxf@#*lrcorner p + labyf@#*ulcorner p + (1-labxf@#-labyf@#)*llcorner p))
+ fi
+enddef;
+
+def plain_label = % takes two arguments, contrary to textext that takes one
+ normaldraw plain_thelabel
+enddef ;
+
+let mfun_label = label ;
+let mfun_thelabel = thelabel ;
+
+def useplainlabels = % somehow let doesn't work for all code
+ def label = plain_label enddef ;
+ def thelabel = plain_thelabel enddef ;
+enddef ;
+
+def usemetafunlabels =
+ let label = mfun_label ;
+ let thelabel = mfun_thelabel ;
+enddef ;
+
+vardef dotlabel@#(expr s,z) text t_ =
+ label@#(s,z) t_ ;
+ interim linecap := rounded ;
+ normaldraw z withpen pencircle scaled dotlabeldiam t_ ;
+enddef ;
+
+plain_compatibility_data := plain_compatibility_data & "save label, thelabel ;" & "useplainlabels ;" ;
+
+% next comes own own:
+
+vardef thetextext@#(expr p,z) =
+ % interim labeloffset := textextoffset ;
+ if string p :
+ thetextext@#(rawtextext(p),z)
+ elseif numeric p :
+ thetextext@#(rawtextext(decimal p),z)
+ else :
+ p
+ if (mfun_labtype@# >= 10) :
+ shifted (0,ypart center p)
+ fi
+ shifted (z + textextoffset*mfun_laboff@# - (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
+ fi
+enddef ;
+
+vardef textext@#(expr p) = % no draw here
+ thetextext@#(p,origin)
+enddef ;
+
+vardef onetimetextext@#(expr p) = % no draw here
+ mfun_onetime_textext := true ;
+ thetextext@#(p,origin)
+enddef ;
+
+vardef thelabel@#(expr p,z) =
+ if string p :
+ thelabel@#(rawtextext("\definedfont[" & defaultfont & "]" & p) scaled defaultscale,z)
+ else :
+ p shifted (z + labeloffset*mfun_laboff@# - (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
+ fi
+enddef;
+
+def label = % takes two arguments, contrary to textext that takes one
+ normaldraw thelabel
+enddef ;
+
+vardef anchored@#(expr p, z) = % beware: no "+ mfun_laboff@#" here (never!)
+ p
+ if (mfun_labtype@# >= 10) :
+ shifted (0,ypart center p)
+ fi
+ shifted (z + (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
+enddef ;
+
+let normalinfont = infont ;
+
+primarydef s infont name = % nasty hack
+ if name = "" :
+ textext(s)
+ else :
+ textext("\definedfont[" & name & "]" & s)
+ fi
+enddef ;
+
+% Helper
+
+string mfun_prescript_separator ; mfun_prescript_separator := char(13) ;
+
+% Shades
+
+% for while we had this:
+
+newinternal shadefactor ; shadefactor := 1 ; % currently obsolete
+pair shadeoffset ; shadeoffset := origin ; % currently obsolete
+boolean trace_shades ; trace_shades := false ; % still there
+
+% def withlinearshading (expr a, b) =
+% withprescript "sh_type=linear"
+% withprescript "sh_domain=0 1"
+% withprescript "sh_factor=" & decimal shadefactor
+% withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
+% withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
+% enddef ;
+%
+% def withcircularshading (expr a, b, ra, rb) =
+% withprescript "sh_type=circular"
+% withprescript "sh_domain=0 1"
+% withprescript "sh_factor=" & decimal shadefactor
+% withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
+% withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
+% withprescript "sh_radius_a=" & decimal ra
+% withprescript "sh_radius_b=" & decimal rb
+% enddef ;
+%
+% def withshading (expr how)(text rest) =
+% if how = "linear" :
+% withlinearshading(rest)
+% elseif how = "circular" :
+% withcircularshading(rest)
+% else :
+% % nothing
+% fi
+% enddef ;
+%
+% def withfromshadecolor expr t =
+% withprescript "sh_color=into"
+% withprescript "sh_color_a=" & colordecimals t
+% enddef ;
+
+% def withtoshadecolor expr t =
+% withprescript "sh_color=into"
+% withprescript "sh_color_b=" & colordecimals t
+% enddef ;
+
+% but this is nicer
+
+% fill fullcircle scaled 10cm
+% withshademethod "circular"
+% withshadevector (5cm,1cm)
+% withshadecenter (.1,.5)
+% withshadedomain (.2,.6)
+% withshadefactor 1.2
+% withshadecolors (red,green)
+% ;
+
+path mfun_shade_path ;
+numeric mfun_shade_step ; mfun_shade_step := 0 ;
+
+def withshadestep =
+ hide(mfun_shade_step := mfun_shade_step + 1 ;)
+ mfun_withshadestep
+enddef ;
+
+def mfun_withshadestep (text t) =
+ withprescript "sh_step=" & decimal mfun_shade_step
+ t
+enddef ;
+
+primarydef p withshademethod m =
+ hide(
+ mfun_shade_path := p ;
+ mfun_shade_step := 1 ;
+ )
+ p
+ withprescript "sh_domain=0 1"
+ withprescript "sh_color=into"
+ withprescript "sh_color_a=" & colordecimals white
+ withprescript "sh_color_b=" & colordecimals black
+ if m = "linear" :
+ withprescript "sh_type=linear"
+ withprescript "sh_factor=1"
+ withprescript "sh_center_a=" & ddecimal llcorner p
+ withprescript "sh_center_b=" & ddecimal urcorner p
+ else :
+ withprescript "sh_type=circular"
+ withprescript "sh_factor=1.2"
+ withprescript "sh_center_a=" & ddecimal center p
+ withprescript "sh_center_b=" & ddecimal center p
+ withprescript "sh_radius_a=" & decimal 0
+ withprescript "sh_radius_b=" & decimal ( max (
+ (xpart center p - xpart llcorner p) ++ (ypart center p - ypart llcorner p),
+ (xpart center p - xpart ulcorner p) ++ (ypart ulcorner p - ypart center p),
+ (xpart lrcorner p - xpart center p) ++ (ypart center p - ypart lrcorner p),
+ (xpart urcorner p - xpart center p) ++ (ypart urcorner p - ypart center p)
+ ) )
+ fi
+enddef ;
+
+def withshadevector expr a =
+ withprescript "sh_center_a=" & ddecimal (point xpart a of mfun_shade_path)
+ withprescript "sh_center_b=" & ddecimal (point ypart a of mfun_shade_path)
+enddef ;
+
+def withshadecenter expr a =
+ withprescript "sh_center_a=" & ddecimal (
+ center mfun_shade_path shifted (
+ xpart a * bbwidth (mfun_shade_path)/2,
+ ypart a * bbheight(mfun_shade_path)/2
+ )
+ )
+enddef ;
+
+def withshadedomain expr d =
+ withprescript "sh_domain=" & ddecimal d
+enddef ;
+
+def withshadefactor expr f =
+ withprescript "sh_factor=" & decimal f
+enddef ;
+
+% def withshadebound (expr a) =
+% if mfun_shade_step > 0 :
+% withprescript "sh_bound_" & decimal mfun_shade_step & "=" & decimal a
+% fi
+% enddef ;
+
+def withshadefraction expr a =
+ if mfun_shade_step > 0 :
+ withprescript "sh_fraction_" & decimal mfun_shade_step & "=" & decimal a
+ fi
+enddef ;
+
+def withshadecolors (expr a, b) =
+ if mfun_shade_step > 0 :
+ withprescript "sh_color=into"
+ withprescript "sh_color_a_" & decimal mfun_shade_step & "=" & colordecimals a
+ withprescript "sh_color_b_" & decimal mfun_shade_step & "=" & colordecimals b
+ else :
+ withprescript "sh_color=into"
+ withprescript "sh_color_a=" & colordecimals a
+ withprescript "sh_color_b=" & colordecimals b
+ fi
+enddef ;
+
+primarydef a shadedinto b = % withcolor red shadedinto green
+ 1 % does not work with transparency
+ withprescript "sh_color=into"
+ withprescript "sh_color_a=" & colordecimals a
+ withprescript "sh_color_b=" & colordecimals b
+enddef ;
+
+primarydef p withshade sc =
+ p withprescript mfun_defined_cs_pre[sc]
+enddef ;
+
+def defineshade suffix s =
+ mfun_defineshade(str s)
+enddef ;
+
+def mfun_defineshade (expr s) text t =
+ expandafter def scantokens s = t enddef ;
+enddef ;
+
+def shaded text s =
+ s
+enddef ;
+
+% Old macros:
+
+def withcircularshade (expr a, b, ra, rb, ca, cb) =
+ withprescript "sh_type=circular"
+ withprescript "sh_domain=0 1"
+ withprescript "sh_factor=1"
+ withprescript "sh_color_a=" & colordecimals ca
+ withprescript "sh_color_b=" & colordecimals cb
+ withprescript "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
+ withprescript "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
+ withprescript "sh_radius_a=" & decimal ra
+ withprescript "sh_radius_b=" & decimal rb
+enddef ;
+
+def withlinearshade (expr a, b, ca, cb) =
+ withprescript "sh_type=linear"
+ withprescript "sh_domain=0 1"
+ withprescript "sh_factor=1"
+ withprescript "sh_color_a=" & colordecimals ca
+ withprescript "sh_color_b=" & colordecimals cb
+ withprescript "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
+ withprescript "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
+enddef ;
+
+% replaced (obsolete):
+
+def set_linear_vector (suffix a,b)(expr p,n) =
+ if (n=1) : a := llcorner p ; b := urcorner p ;
+ elseif (n=2) : a := lrcorner p ; b := ulcorner p ;
+ elseif (n=3) : a := urcorner p ; b := llcorner p ;
+ elseif (n=4) : a := ulcorner p ; b := lrcorner p ;
+ elseif (n=5) : a := .5[ulcorner p,llcorner p] ; b := .5[urcorner p,lrcorner p] ;
+ elseif (n=6) : a := .5[llcorner p,lrcorner p] ; b := .5[ulcorner p,urcorner p] ;
+ elseif (n=7) : a := .5[lrcorner p,urcorner p] ; b := .5[llcorner p,ulcorner p] ;
+ elseif (n=8) : a := .5[urcorner p,ulcorner p] ; b := .5[lrcorner p,llcorner p] ;
+ else : a := .5[ulcorner p,llcorner p] ; b := .5[urcorner p,lrcorner p] ;
+ fi ;
+enddef ;
+
+def set_circular_vector (suffix ab,r)(expr p,n) =
+ if (n=1) : ab := llcorner p ;
+ elseif (n=2) : ab := lrcorner p ;
+ elseif (n=3) : ab := urcorner p ;
+ elseif (n=4) : ab := ulcorner p ;
+ else : ab := center p ; r := .5r ;
+ fi ;
+enddef ;
+
+def circular_shade (expr p, n, ca, cb) =
+ begingroup ;
+ save ab, r ; pair ab ; numeric r ;
+ r := (xpart lrcorner p - xpart llcorner p) ++ (ypart urcorner p - ypart lrcorner p) ;
+ set_circular_vector(ab,r)(p,n) ;
+ fill p withcircularshade(ab,ab,0,r,ca,cb) ;
+ if trace_shades :
+ drawarrow ab -- ab shifted (0,r) withpen pencircle scaled 1pt withcolor .5white ;
+ fi ;
+ endgroup ;
+enddef ;
+
+def linear_shade (expr p, n, ca, cb) =
+ begingroup ;
+ save a, b ; pair a, b ;
+ set_linear_vector(a,b)(p,n) ;
+ fill p withlinearshade(a,b,ca,cb) ;
+ if trace_shades :
+ drawarrow a -- b withpen pencircle scaled 1pt withcolor .5white ;
+ fi ;
+ endgroup ;
+enddef ;
+
+string mfun_defined_cs_pre[] ; numeric mfun_defined_cs ; mfun_defined_cs := 0 ;
+
+vardef define_circular_shade (expr a, b, ra, rb, ca, cb) =
+ mfun_defined_cs := mfun_defined_cs + 1 ;
+ mfun_defined_cs_pre[mfun_defined_cs] := "sh_type=circular"
+ & mfun_prescript_separator & "sh_domain=0 1"
+ & mfun_prescript_separator & "sh_factor=1"
+ & mfun_prescript_separator & "sh_color_a=" & colordecimals ca
+ & mfun_prescript_separator & "sh_color_b=" & colordecimals cb
+ & mfun_prescript_separator & "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
+ & mfun_prescript_separator & "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
+ & mfun_prescript_separator & "sh_radius_a=" & decimal ra
+ & mfun_prescript_separator & "sh_radius_b=" & decimal rb
+ ;
+ mfun_defined_cs
+enddef ;
+
+vardef define_linear_shade (expr a, b, ca, cb) =
+ mfun_defined_cs := mfun_defined_cs + 1 ;
+ mfun_defined_cs_pre[mfun_defined_cs] := "sh_type=linear"
+ & mfun_prescript_separator & "sh_domain=0 1"
+ & mfun_prescript_separator & "sh_factor=1"
+ & mfun_prescript_separator & "sh_color_a=" & colordecimals ca
+ & mfun_prescript_separator & "sh_color_b=" & colordecimals cb
+ & mfun_prescript_separator & "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
+ & mfun_prescript_separator & "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
+ ;
+ mfun_defined_cs
+enddef ;
+
+% I lost the example code that uses this:
+%
+% vardef define_sampled_linear_shade(expr a,b,n)(text t) =
+% mfun_defined_cs := mfun_defined_cs + 1 ;
+% mfun_defined_cs_pre[mfun_defined_cs] := "ssh_type=linear"
+% & mfun_prescript_separator & "ssh_center_a=" & ddecimal (a shifted shadeoffset)
+% & mfun_prescript_separator & "ssh_center_b=" & ddecimal (b shifted shadeoffset)
+% & mfun_prescript_separator & "ssh_nofcolors=" & decimal n
+% & mfun_prescript_separator & "ssh_domain=" & domstr
+% & mfun_prescript_separator & "ssh_extend=" & extstr
+% & mfun_prescript_separator & "ssh_colors=" & colstr
+% & mfun_prescript_separator & "ssh_bounds=" & bndstr
+% & mfun_prescript_separator & "ssh_ranges=" & ranstr
+% ;
+% mfun_defined_cs
+% enddef ;
+%
+% vardef define_sampled_circular_shade(expr a,b,ra,rb,n)(text t) =
+% mfun_defined_cs := mfun_defined_cs + 1 ;
+% mfun_defined_cs_pre[mfun_defined_cs] := "ssh_type=circular"
+% & mfun_prescript_separator & "ssh_center_a=" & ddecimal (a shifted shadeoffset)
+% & mfun_prescript_separator & "ssh_radius_a=" & decimal ra
+% & mfun_prescript_separator & "ssh_center_b=" & ddecimal (b shifted shadeoffset)
+% & mfun_prescript_separator & "ssh_radius_b=" & decimal rb
+% & mfun_prescript_separator & "ssh_nofcolors=" & decimal n
+% & mfun_prescript_separator & "ssh_domain=" & domstr
+% & mfun_prescript_separator & "ssh_extend=" & extstr
+% & mfun_prescript_separator & "ssh_colors=" & colstr
+% & mfun_prescript_separator & "ssh_bounds=" & bndstr
+% & mfun_prescript_separator & "ssh_ranges=" & ranstr
+% ;
+% mfun_defined_cs
+% enddef ;
+
+% vardef predefined_linear_shade (expr p, n, ca, cb) =
+% save a, b, sh ; pair a, b ;
+% set_linear_vector(a,b)(p,n) ;
+% define_linear_shade (a,b,ca,cb)
+% enddef ;
+%
+% vardef predefined_circular_shade (expr p, n, ca, cb) =
+% save ab, r ; pair ab ; numeric r ;
+% r := (xpart lrcorner p - xpart llcorner p) ++ (ypart urcorner p - ypart lrcorner p) ;
+% set_circular_vector(ab,r)(p,n) ;
+% define_circular_shade(ab,ab,0,r,ca,cb)
+% enddef ;
+
+% Layers
+
+def onlayer primary name =
+ withprescript "la_name=" & name
+enddef ;
+
+% Figures
+
+% def externalfigure primary filename =
+% doexternalfigure (filename)
+% enddef ;
+%
+% def doexternalfigure (expr filename) text transformation =
+% if true : % a bit incompatible esp scaled 1cm now scaled the natural size
+% draw rawtextext("\externalfigure[" & filename & "]") transformation ;
+% else :
+% draw unitsquare transformation withprescript "fg_name=" & filename ;
+% fi ;
+% enddef ;
+
+def withmask primary filename =
+ withprescript "fg_mask=" & filename
+enddef ;
+
+def externalfigure primary filename =
+ if false :
+ rawtextext("\externalfigure[" & filename & "]")
+ else :
+ image (
+ addto currentpicture doublepath unitsquare
+ withprescript "fg_name=" & filename ;
+ )
+% unitsquare
+% withpen pencircle scaled 0
+% withprescript "fg_name=" & filename
+ fi
+enddef ;
+
+def figure primary filename =
+ rawtextext("\externalfigure[" & filename & "]")
+enddef ;
+
+% Positions
+
+def register (expr tag, width, height, offset) =
+% draw image (
+ addto currentpicture doublepath unitsquare xscaled width yscaled height shifted offset
+ withprescript "ps_label=" & tag ;
+% ) ; % no transformations
+enddef ;
+
+% outlines (todo: pass around less arguments)
+
+numeric currentoutlinetext ; currentoutlinetext := 0 ;
+
+vardef mfun_do_outline_text_flush (expr kind, n, x, y) (text t) =
+ if kind = "f" :
+ mfun_do_outline_text_f (n, x, y) (t)
+ elseif kind = "d" :
+ mfun_do_outline_text_d (n, x, y) (t)
+ elseif kind = "b" :
+ mfun_do_outline_text_b (n, x, y) (t)
+ elseif kind = "r" :
+ mfun_do_outline_text_r (n, x, y) (t)
+ elseif kind = "p" :
+ mfun_do_outline_text_p (n, x, y) (t)
+ else :
+ mfun_do_outline_text_n (n, x, y) (t)
+ fi ;
+enddef ;
+
+numeric mfun_do_outline_n ; mfun_do_outline_n := 0 ;
+
+vardef mfun_do_outline_text_f (expr n, x, y) (text t) =
+ mfun_do_outline_n := 0 ;
+ for i=t :
+ mfun_do_outline_n := mfun_do_outline_n + 1 ;
+ if mfun_do_outline_n = n :
+ fill i shifted(x,y) mfun_do_outline_options_f
+ else :
+ nofill i shifted(x,y)
+ fi ;
+ endfor ;
+enddef ;
+
+vardef mfun_do_outline_text_d (expr n, x, y) (text t) =
+ for i=t :
+ draw i shifted(x,y) mfun_do_outline_options_d ;
+ endfor ;
+enddef ;
+
+vardef mfun_do_outline_text_p (expr n, x, y) (text t) =
+ for i=t :
+ draw i shifted(x,y) ;
+ endfor ;
+enddef ;
+
+vardef mfun_do_outline_text_b (expr n, x, y) (text t) =
+ mfun_do_outline_n := 0 ;
+ for i=t :
+ mfun_do_outline_n := mfun_do_outline_n + 1 ;
+ if mfun_do_outline_n = n :
+ fill i shifted(x,y) mfun_do_outline_options_f
+ else :
+ nofill i shifted(x,y)
+ fi ;
+ endfor ;
+ for i=t :
+ draw i shifted(x,y) mfun_do_outline_options_d ;
+ endfor ;
+enddef ;
+
+vardef mfun_do_outline_text_r (expr n, x, y) (text t) =
+ mfun_do_outline_n := 0 ;
+ for i=t :
+ draw i shifted(x,y) mfun_do_outline_options_d ;
+ endfor ;
+ for i=t :
+ mfun_do_outline_n := mfun_do_outline_n + 1 ;
+ if mfun_do_outline_n = n :
+ fill i shifted(x,y) mfun_do_outline_options_f
+ else :
+ nofill i shifted(x,y)
+ fi ;
+ endfor ;
+enddef ;
+
+vardef mfun_do_outline_text_n (expr n, x, y) (text t) =
+ mfun_do_outline_n := 0 ;
+ for i=t :
+ mfun_do_outline_n := mfun_do_outline_n + 1 ;
+ if mfun_do_outline_n = n : fill else : nofill fi i shifted(x,y) ;
+ endfor ;
+enddef ;
+
+vardef mfun_do_outline_text_set_f (text f) text r =
+ def mfun_do_outline_options_f = f enddef ;
+ def mfun_do_outline_options_r = r enddef ;
+enddef ;
+
+vardef mfun_do_outline_text_set_d (text d) text r =
+ def mfun_do_outline_options_d = d enddef ;
+ def mfun_do_outline_options_r = r enddef ;
+enddef ;
+
+vardef mfun_do_outline_text_set_b (text f) (text d) text r =
+ def mfun_do_outline_options_f = f enddef ;
+ def mfun_do_outline_options_d = d enddef ;
+ def mfun_do_outline_options_r = r enddef ;
+enddef ;
+
+vardef mfun_do_outline_text_set_r (text d) (text f) text r =
+ def mfun_do_outline_options_d = d enddef ;
+ def mfun_do_outline_options_f = f enddef ;
+ def mfun_do_outline_options_r = r enddef ;
+enddef ;
+
+vardef mfun_do_outline_text_set_n text r =
+ def mfun_do_outline_options_r = r enddef ;
+enddef ;
+
+vardef mfun_do_outline_text_set_p =
+enddef ;
+
+def mfun_do_outline_options_d = enddef ;
+def mfun_do_outline_options_f = enddef ;
+def mfun_do_outline_options_r = enddef ;
+
+vardef outlinetext@# (expr t) text rest =
+ save kind ; string kind ; kind := str @# ;
+ currentoutlinetext := currentoutlinetext + 1 ;
+ image ( normaldraw image (
+ if mfun_trial_run :
+ % lua.mp.report("set outline text",currentoutlinetext);
+ normaldraw unitsquare
+ withprescript "ot_stage=trial"
+ withprescript "ot_index=" & decimal currentoutlinetext
+ withprescript "ot_kind=" & kind
+ withpostscript t ;
+ else :
+ % lua.mp.report("get outline text",currentoutlinetext);
+ if kind = "f" :
+ mfun_do_outline_text_set_f rest ;
+ elseif kind = "d" :
+ mfun_do_outline_text_set_d rest ;
+ elseif kind = "b" :
+ mfun_do_outline_text_set_b rest ;
+ elseif kind = "r" :
+ mfun_do_outline_text_set_r rest ;
+ elseif kind = "p" :
+ mfun_do_outline_text_set_p ;
+ else :
+ mfun_do_outline_text_set_n rest ;
+ fi ;
+ lua.mp.get_outline_text(currentoutlinetext) ;
+ fi ;
+ ) mfun_do_outline_options_r ; )
+enddef ;
+
+% A few helpers:
+
+numeric mfun_c_b_llx, mfun_c_b_h, mfun_c_b_w, mfun_c_b_l ;
+
+vardef checkedbounds(expr llx,lly,urx,ury) =
+ mfun_c_b_llx := min(xpart llcorner currentpicture,llx) ;
+ mfun_c_b_urx := max(xpart urcorner currentpicture,urx) ;
+ mfun_c_b_lly := min(ypart llcorner currentpicture,lly) ;
+ mfun_c_b_ury := max(ypart urcorner currentpicture,ury) ;
+ (mfun_c_b_llx,mfun_c_b_lly) --
+ (mfun_c_b_urx,mfun_c_b_lly) --
+ (mfun_c_b_urx,mfun_c_b_ury) --
+ (mfun_c_b_llx,mfun_c_b_ury) -- cycle
+enddef ;
+
+vardef checkbounds(expr llx,lly,urx,ury) =
+ setbounds currentpicture to checkedbounds(llx,lly,urx,ury) ;
+enddef ;
+
+vardef strut(expr ht,dp) =
+ setbounds currentpicture to checkedbounds(0,0,ht,dp) ;
+enddef ;
+
+vardef rule(expr wd,ht,dp) =
+ image (fill (0,-dp)--(wd,-dp)--(wd,ht)--(0,ht)--cycle)
+enddef ;
+
+
+% Housekeeping
+
+extra_beginfig := extra_beginfig & "currentgraphictext := 0 ; " ;
+extra_beginfig := extra_beginfig & "currentoutlinetext := 0 ; " ;
+extra_endfig := extra_endfig & "finishsavingdata ; " ;
+extra_endfig := extra_endfig & "mfun_reset_tex_texts ; " ;
+
+% Bonus
+
+vardef verbatim(expr s) =
+ ditto & "\detokenize{" & s & "}" & ditto
+enddef ;
+
+% New
+
+def bitmapimage(expr xresolution, yresolution, data) =
+ image (
+ addto currentpicture doublepath unitsquare
+ withprescript "bm_xresolution=" & decimal xresolution
+ withprescript "bm_yresolution=" & decimal yresolution
+ withpostscript data ;
+ )
+enddef ;
+
+% Experimental:
+%
+% property p ; p = properties(withcolor (1,1,0,0)) ;
+% fill fullcircle scaled 20cm withproperties p ;
+
+let property = picture ;
+
+vardef properties(text t) =
+ image(draw unitcircle t)
+enddef ;
+
+if metapostversion < 1.770 :
+
+ def withproperties expr p =
+ if colormodel p = 3 :
+ withcolor greypart p
+ elseif colormodel p = 5 :
+ withcolor (redpart p,greenpart p,bluepart p)
+ elseif colormodel p = 7 :
+ withcolor (cyanpart p,magentapart p,yellowpart p,blackpart p)
+ fi
+ enddef ;
+
+else :
+
+ def withproperties expr p =
+ if colormodel p = 3 :
+ withcolor greypart p
+ elseif colormodel p = 5 :
+ withcolor (redpart p,greenpart p,bluepart p)
+ elseif colormodel p = 7 :
+ withcolor (cyanpart p,magentapart p,yellowpart p,blackpart p)
+ fi
+ withprescript prescriptpart p
+ withpostscript postscriptpart p
+ enddef ;
+
+fi ;
+
+% Experimental:
+
+primarydef t asgroup s = % s = isolated|knockout
+ begingroup
+ save grouppicture, wrappedpicture, groupbounds ;
+ picture grouppicture, wrappedpicture ; path groupbounds ;
+ grouppicture := if picture t : t else : image(draw t) fi ;
+ groupbounds := boundingbox grouppicture ;
+ wrappedpicture:= nullpicture ;
+ addto wrappedpicture contour groupbounds
+ withprescript "gr_state=start"
+ withprescript "gr_type=" & s
+ withprescript "gr_llx=" & decimal xpart llcorner groupbounds
+ withprescript "gr_lly=" & decimal ypart llcorner groupbounds
+ withprescript "gr_urx=" & decimal xpart urcorner groupbounds
+ withprescript "gr_ury=" & decimal ypart urcorner groupbounds ;
+ addto wrappedpicture also grouppicture ;
+ addto wrappedpicture contour groupbounds
+ withprescript "gr_state=stop" ;
+ wrappedpicture
+ endgroup
+enddef ;
+
+% Also experimental ... needs to be made better ... so it can change!
+
+string mfun_auto_align[] ;
+
+mfun_auto_align[0] := "rt" ;
+mfun_auto_align[1] := "urt" ;
+mfun_auto_align[2] := "top" ;
+mfun_auto_align[3] := "ulft" ;
+mfun_auto_align[4] := "lft" ;
+mfun_auto_align[5] := "llft" ;
+mfun_auto_align[6] := "bot" ;
+mfun_auto_align[7] := "lrt" ;
+mfun_auto_align[8] := "rt" ;
+
+def autoalign(expr n) =
+ scantokens mfun_auto_align[round((n mod 360)/45)]
+enddef ;
+
+% draw textext.autoalign(60) ("\strut oeps 1") ;
+% draw textext.autoalign(160)("\strut oeps 2") ;
+% draw textext.autoalign(260)("\strut oeps 3") ;
+% draw textext.autoalign(360)("\strut oeps 4") ;
+
+% new
+%
+% passvariable("version","1.0") ;
+% passvariable("number",123) ;
+% passvariable("string","whatever") ;
+% passvariable("point",(1,2)) ;
+% passvariable("triplet",(1,2,3)) ;
+% passvariable("quad",(1,2,3,4)) ;
+% passvariable("boolean",false) ;
+% passvariable("path",fullcircle scaled 1cm) ;
+
+% we could use the new lua interface but there is not that much gain i.e.
+% we still need to serialize
+
+vardef mfun_point_to_string(expr p,i) =
+ decimal xpart (point i of p) & " " &
+ decimal ypart (point i of p) & " " &
+ decimal xpart (precontrol i of p) & " " &
+ decimal ypart (precontrol i of p) & " " &
+ decimal xpart (postcontrol i of p) & " " &
+ decimal ypart (postcontrol i of p)
+enddef ;
+
+vardef mfun_transform_to_string(expr t) =
+ decimal xxpart t & " " & % rx
+ decimal xypart t & " " & % sx
+ decimal yxpart t & " " & % sy
+ decimal yypart t & " " & % ry
+ decimal xpart t & " " & % tx
+ decimal ypart t % ty
+enddef ;
+
+vardef mfun_numeric_to_string(expr n) =
+ decimal n
+enddef ;
+
+vardef mfun_pair_to_string(expr p) =
+ decimal xpart p & " " &
+ decimal ypart p
+enddef ;
+
+vardef mfun_rgbcolor_to_string(expr c) =
+ decimal redpart c & " " &
+ decimal greenpart c & " " &
+ decimal bluepart c
+enddef ;
+
+vardef mfun_cmykcolor_to_string(expr c) =
+ decimal cyanpart c & " " &
+ decimal magentapart c & " " &
+ decimal yellowpart c & " " &
+ decimal blackpart c
+enddef ;
+
+vardef mfun_greycolor_to_string(expr n) =
+ decimal n
+enddef ;
+
+vardef mfun_path_to_string(expr p) =
+ mfun_point_to_string(p,0) for i=1 upto length(p) : & " " & mfun_point_to_string(p,i) endfor
+enddef ;
+
+vardef mfun_boolean_to_string(expr b) =
+ if b : "true" else : "false" fi
+enddef ;
+
+% def passvariable(expr key, value) =
+% special
+% if numeric value : "1:" & key & "=" & mfun_numeric_to_string(value)
+% elseif pair value : "4:" & key & "=" & mfun_pair_to_string(value)
+% elseif rgbcolor value : "5:" & key & "=" & mfun_rgbcolor_to_string(value)
+% elseif cmykcolor value : "6:" & key & "=" & mfun_cmykcolor_to_string(value)
+% elseif boolean value : "3:" & key & "=" & mfun_boolean_to_string(value)
+% elseif path value : "7:" & key & "=" & mfun_path_to_string(value)
+% elseif transform value : "8:" & key & "=" & mfun_transform_to_string(value)
+% else : "2:" & key & "=" & value
+% fi ;
+% enddef ;
+
+vardef tostring(expr value) =
+ if numeric value : mfun_numeric_to_string(value)
+ elseif pair value : mfun_pair_to_string(value)
+ elseif rgbcolor value : mfun_rgbcolor_to_string(value)
+ elseif cmykcolor value : mfun_cmykcolor_to_string(value)
+ elseif greycolor value : mfun_greycolor_to_string(value)
+ elseif boolean value : mfun_boolean_to_string(value)
+ elseif path value : mfun_path_to_string(value)
+ elseif transform value : mfun_transform_to_string(value)
+ else : value
+ fi
+enddef ;
+
+vardef mfun_tagged_string(expr value) =
+ if numeric value : "1:" & mfun_numeric_to_string(value)
+ elseif pair value : "4:" & mfun_pair_to_string(value)
+ elseif rgbcolor value : "5:" & mfun_rgbcolor_to_string(value)
+ elseif cmykcolor value : "6:" & mfun_cmykcolor_to_string(value)
+ elseif boolean value : "3:" & mfun_boolean_to_string(value)
+ elseif path value : "7:" & mfun_path_to_string(value)
+ elseif transform value : "8:" & mfun_transform_to_string(value)
+ else : "2:" & value
+ fi
+enddef ;
+
+% amore flexible variant for passing data to context
+
+vardef mfun_point_to_lua(expr p,i) =
+ "{" &
+ decimal xpart (point i of p) & "," &
+ decimal ypart (point i of p) & "," &
+ decimal xpart (precontrol i of p) & "," &
+ decimal ypart (precontrol i of p) & "," &
+ decimal xpart (postcontrol i of p) & "," &
+ decimal ypart (postcontrol i of p)
+ & "}"
+enddef ;
+
+vardef mfun_transform_to_lua(expr t) =
+ "{" &
+ decimal xxpart t & "," & % rx
+ decimal xypart t & "," & % sx
+ decimal yxpart t & "," & % sy
+ decimal yypart t & "," & % ry
+ decimal xpart t & "," & % tx
+ decimal ypart t % ty
+ & "}"
+enddef ;
+
+vardef mfun_numeric_to_lua(expr n) =
+ decimal n
+enddef ;
+
+vardef mfun_pair_to_lua(expr p) =
+ "{" &
+ decimal xpart p & "," &
+ decimal ypart p
+ & "}"
+enddef ;
+
+vardef mfun_rgbcolor_to_lua(expr c) =
+ "{" &
+ decimal redpart c & "," &
+ decimal greenpart c & "," &
+ decimal bluepart c
+ & "}"
+enddef ;
+
+vardef mfun_cmykcolor_to_lua(expr c) =
+ "{" &
+ decimal cyanpart c & "," &
+ decimal magentapart c & "," &
+ decimal yellowpart c & "," &
+ decimal blackpart c
+ & "}"
+enddef ;
+
+vardef mfun_path_to_lua(expr p) =
+ "{" &
+ mfun_point_to_lua(p,0) for i=1 upto length(p) : & "," & mfun_point_to_lua(p,i) endfor
+ & "}"
+enddef ;
+
+vardef mfun_boolean_to_lua(expr b) =
+ if b : "true" else : "false" fi
+enddef ;
+
+vardef mfun_string_to_lua(expr s) =
+ "[==[" & s & "]==]"
+enddef ;
+
+def mfun_to_lua(expr key)(expr value)(text t) =
+ special "metapost.variables['" & key & "']=" & t(value) ;
+enddef ;
+
+def mfun_array_to_lua(expr key)(suffix value)(expr first, last, stp)(text t) =
+ special
+ "metapost.variables['" & key & "']={"
+ for i=first step stp until last :
+ & "[" & decimal i & "]=" & t(value[i]) & ","
+ endfor
+ & "}" ;
+enddef ;
+
+def passvariable(expr key, value) =
+ if numeric value : mfun_to_lua(key,value,mfun_numeric_to_lua)
+ elseif pair value : mfun_to_lua(key,value,mfun_pair_to_lua)
+ elseif string value : mfun_to_lua(key,value,mfun_string_to_lua)
+ elseif boolean value : mfun_to_lua(key,value,mfun_boolean_to_lua)
+ elseif path value : mfun_to_lua(key,value,mfun_path_to_lua)
+ elseif rgbcolor value : mfun_to_lua(key,value,mfun_rgbcolor_to_lua)
+ elseif cmykcolor value : mfun_to_lua(key,value,mfun_cmykcolor_to_lua)
+ elseif transform value : mfun_to_lua(key,value,mfun_transform_to_lua)
+ fi ;
+enddef ;
+
+def passarrayvariable(expr key)(suffix values)(expr first, last, stp) =
+ if numeric values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_numeric_to_lua)
+ elseif pair values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_pair_to_lua)
+ elseif string values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_string_to_lua)
+ elseif boolean values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_boolean_to_lua)
+ elseif path values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_path_to_lua)
+ elseif rgbcolor values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_rgbcolor_to_lua)
+ elseif cmykcolor values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_cmykcolor_to_lua)
+ elseif transform values[first] : mfun_array_to_lua(key,values,first,last,stp,mfun_transform_to_lua)
+ fi ;
+enddef ;
+
+def startpassingvariable(expr k) =
+ begingroup ;
+ save stoppassingvariable, startarray, stoparray, starthash, stophash, index, key, value, slot, entry ;
+ let stoppassingvariable = mfun_stop_lua_variable ;
+ let startarray = mfun_start_lua_array ;
+ let stoparray = mfun_stop_lua_array ;
+ let starthash = mfun_start_lua_hash ;
+ let stophash = mfun_stop_lua_hash ;
+ let index = mfun_lua_index ;
+ let key = mfun_lua_key ;
+ let value = mfun_lua_value ;
+ let slot = mfun_lua_slot ;
+ let entry = mfun_lua_entry ;
+ save s ; string s ;
+ s := "metapost.variables['" & k & "']="
+enddef ;
+
+def mfun_stop_lua_variable =
+ ;
+ special substring(0,length(s)-1) of s ;
+ endgroup ;
+enddef ;
+
+% currently there is no difference between array and hash
+
+def mfun_start_lua_array =
+ & "{"
+enddef ;
+
+def mfun_stop_lua_array =
+ & "},"
+enddef ;
+
+def mfun_start_lua_hash =
+ & "{"
+enddef ;
+
+def mfun_stop_lua_hash =
+ & "},"
+enddef ;
+
+def mfun_lua_key(expr k) =
+ & "['" & k & "']="
+enddef ;
+
+def mfun_lua_index(expr k) =
+ & "[" & decimal k & "]="
+enddef ;
+
+def mfun_lua_value(expr v) =
+ if numeric v : & mfun_numeric_to_lua(v) & ","
+ elseif pair v : & mfun_pair_to_lua(v) & ","
+ elseif string v : & mfun_string_to_lua(v) & ","
+ elseif boolean v : & mfun_boolean_to_lua(v) & ","
+ elseif path v : & mfun_path_to_lua(v) & ","
+ elseif rgbcolor v : & mfun_rgbcolor_to_lua(v) & ","
+ elseif cmykcolor v : & mfun_cmykcolor_to_lua(v) & ","
+ elseif transform v : & mfun_transform_to_lua(v) & ","
+ fi
+enddef ;
+
+def mfun_lua_entry(expr k, v) =
+ mfun_lua_key(k)
+ mfun_lua_value(v)
+enddef ;
+
+def mfun_lua_slot(expr k, v) =
+ mfun_lua_index(k)
+ mfun_lua_value(v)
+enddef ;
+
+% moved here from mp-grap.mpiv
+
+% vardef escaped_format(expr s) =
+% "" for n=0 upto length(s) : &
+% if ASCII substring (n,n+1) of s = 37 :
+% "@"
+% else :
+% substring (n,n+1) of s
+% fi
+% endfor
+% enddef ;
+
+numeric mfun_esc_b ; % begin
+numeric mfun_esc_l ; % length
+string mfun_esc_s ; % character
+
+mfun_esc_s := "%" ; % or: char(37)
+
+% this one is the fastest when we have a match
+
+% vardef escaped_format(expr s) =
+% "" for n=0 upto length(s)-1 : &
+% % if ASCII substring (n,n+1) of s = 37 :
+% if substring (n,n+1) of s = mfun_esc_s :
+% "@"
+% else :
+% substring (n,n+1) of s
+% fi
+% endfor
+% enddef ;
+
+% this one wins when we have no match
+
+vardef escaped_format(expr s) =
+ mfun_esc_b := 0 ;
+ mfun_esc_l := length(s) ;
+ for n=0 upto mfun_esc_l-1 :
+ % if ASCII substring (n,n+1) of s = 37 :
+ if substring (n,n+1) of s = mfun_esc_s :
+ if mfun_esc_b = 0 :
+ ""
+ fi
+ if n >= mfun_esc_b :
+ & (substring (mfun_esc_b,n) of s)
+ exitif numeric begingroup mfun_esc_b := n+1 endgroup ; % hide
+ fi
+ & "@"
+ fi
+ endfor
+ if mfun_esc_b = 0 :
+ s
+ % elseif mfun_esc_b > 0 :
+ elseif mfun_esc_b < mfun_esc_l :
+ & (substring (mfun_esc_b,mfun_esc_l) of s)
+ fi
+enddef ;
+
+vardef strfmt(expr f, x) = "\MPgraphformat{" & escaped_format(f) & "}{" & mfun_tagged_string(x) & "}" enddef ;
+vardef varfmt(expr f, x) = "\MPformatted{" & escaped_format(f) & "}{" & mfun_tagged_string(x) & "}" enddef ;
+
+vardef format (expr f, x) = textext(strfmt(f, x)) enddef ;
+vardef formatted(expr f, x) = textext(varfmt(f, x)) enddef ;
+
+% could be this (something to discuss with alan as it involves graph):
+%
+% vardef format (expr f,x) = lua.mp.graphformat(f,mfun_tagged_string(x) enddef ;
+% vardef formatted(expr f,x) = lua.mp.format (f, x) enddef ;
+%
+% def strfmt = format enddef ; % old
+% def varfmt = formatted enddef ; % old
+
+% new
+
+def eofill text t = fill t withpostscript "evenodd" enddef ;
+def nofill text t = fill t withpostscript "collect" enddef ;
+%%% eoclip text t = clip t withpostscript "evenodd" enddef ; % no postscripts yet
+
+% def withrule expr r =
+% if (t = "even-odd") or (t = "evenodd") : withpostscript "evenodd" fi
+% enddef ;
diff --git a/metapost/context/base/mpiv/mp-page.mpiv b/metapost/context/base/mpiv/mp-page.mpiv
new file mode 100644
index 000000000..a6fa3fba3
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-page.mpiv
@@ -0,0 +1,664 @@
+%D \module
+%D [ file=mp-page.mpiv,
+%D version=1999.03.10,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=page enhancements,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module is rather preliminary and subjected to changes.
+
+if known context_page : endinput ; fi ;
+
+boolean context_page ; context_page := true ;
+
+% def LoadPageState =
+% % now always set
+% enddef ;
+%
+% if unknown PageStateAvailable :
+% boolean PageStateAvailable ;
+% PageStateAvailable := false ;
+% fi ;
+%
+% if unknown OnRightPage :
+% boolean OnRightPage ;
+% OnRightPage := true ;
+% fi ;
+%
+% if unknown OnOddPage :
+% boolean OnOddPage ;
+% OnOddPage := true ;
+% fi ;
+%
+% if unknown InPageBody :
+% boolean InPageBody ;
+% InPageBody := false ;
+% fi ;
+%
+% string CurrentLayout ;
+%
+% CurrentLayout := "default" ;
+%
+% PageNumber := 0 ;
+% PaperHeight := 845.04684pt ;
+% PaperWidth := 597.50787pt ;
+% PrintPaperHeight := 845.04684pt ;
+% PrintPaperWidth := 597.50787pt ;
+% TopSpace := 71.12546pt ;
+% BottomSpace := 0.0pt ;
+% BackSpace := 71.13275pt ;
+% CutSpace := 0.0pt ;
+% MakeupHeight := 711.3191pt ;
+% MakeupWidth := 426.78743pt ;
+% TopHeight := 0.0pt ;
+% TopDistance := 0.0pt ;
+% HeaderHeight := 56.90294pt ;
+% HeaderDistance := 0.0pt ;
+% TextHeight := 597.51323pt ;
+% FooterDistance := 0.0pt ;
+% FooterHeight := 56.90294pt ;
+% BottomDistance := 0.0pt ;
+% BottomHeight := 0.0pt ;
+% LeftEdgeWidth := 0.0pt ;
+% LeftEdgeDistance := 0.0pt ;
+% LeftMarginWidth := 75.58197pt ;
+% LeftMarginDistance := 11.99829pt ;
+% TextWidth := 426.78743pt ;
+% RightMarginDistance := 11.99829pt ;
+% RightMarginWidth := 75.58197pt ;
+% RightEdgeDistance := 0.0pt ;
+% RightEdgeWidth := 0.0pt ;
+%
+% PageOffset := 0.0pt ;
+% PageDepth := 0.0pt ;
+%
+% LayoutColumns := 0 ;
+% LayoutColumnDistance:= 0.0pt ;
+% LayoutColumnWidth := 0.0pt ;
+%
+% LeftEdge := -4 ; Top := -40 ;
+% LeftEdgeSeparator := -3 ; TopSeparator := -30 ;
+% LeftMargin := -2 ; Header := -20 ;
+% LeftMarginSeparator := -1 ; HeaderSeparator := -10 ;
+% Text := 0 ; Text := 0 ;
+% RightMarginSeparator := +1 ; FooterSeparator := +10 ;
+% RightMargin := +2 ; Footer := +20 ;
+% RightEdgeSeparator := +3 ; BottomSeparator := +30 ;
+% RightEdge := +4 ; Bottom := +40 ;
+%
+% Margin := LeftMargin ; % obsolete
+% Edge := LeftEdge ; % obsolete
+% InnerMargin := RightMargin ; % obsolete
+% InnerEdge := RightEdge ; % obsolete
+% OuterMargin := LeftMargin ; % obsolete
+% OuterEdge := LeftEdge ; % obsolete
+%
+% InnerMarginWidth := 0pt ;
+% OuterMarginWidth := 0pt ;
+% InnerMarginDistance := 0pt ;
+% OuterMarginDistance := 0pt ;
+%
+% InnerEdgeWidth := 0pt ;
+% OuterEdgeWidth := 0pt ;
+% InnerEdgeDistance := 0pt ;
+% OuterEdgeDistance := 0pt ;
+%
+% % path Area[][] ;
+% % pair Location[][] ;
+% % path Field[][] ;
+%
+% % numeric Hstep[] ;
+% % numeric Hsize[] ;
+% % numeric Vstep[] ;
+% % numeric Vsize[] ;
+%
+% path Page ;
+%
+% numeric HorPos ;
+% numeric VerPos ;
+%
+% % for VerPos=Top step 10 until Bottom:
+% % for HorPos=LeftEdge step 1 until RightEdge:
+% % Area[HorPos][VerPos] := origin--cycle ;
+% % Area[VerPos][HorPos] := Area[HorPos][VerPos] ;
+% % Location[HorPos][VerPos] := origin ;
+% % Location[VerPos][HorPos] := Location[HorPos][VerPos] ;
+% % Field[HorPos][VerPos] := origin--cycle ;
+% % Field[VerPos][HorPos] := Field[HorPos][VerPos] ;
+% % endfor ;
+% % endfor ;
+%
+% % def LoadPageState =
+% % scantokens "input mp-state.tmp" ;
+% % enddef ;
+%
+% numeric mfun_temp ;
+%
+% def SwapPageState =
+% if not OnRightPage :
+% BackSpace := PaperWidth-MakeupWidth-BackSpace ;
+% CutSpace := PaperWidth-MakeupWidth-CutSpace ;
+% mfun_temp := LeftMarginWidth ;
+% LeftMarginWidth := RightMarginWidth ;
+% RightMarginWidth := mfun_temp ;
+% mfun_temp := LeftMarginDistance ;
+% LeftMarginDistance := RightMarginDistance ;
+% RightMarginDistance := mfun_temp ;
+% mfun_temp := LeftEdgeWidth ;
+% LeftEdgeWidth := RightEdgeWidth ;
+% RightEdgeWidth := mfun_temp ;
+% mfun_temp := LeftEdgeDistance ;
+% LeftEdgeDistance := RightEdgeDistance ;
+% RightEdgeDistance := mfun_temp ;
+%
+% % these are now available as ..Width and ..Distance
+%
+% Margin := LeftMargin ;
+% Edge := LeftEdge ;
+% InnerMargin := RightMargin ;
+% InnerEdge := RightEdge ;
+% OuterMargin := LeftMargin ;
+% OuterEdge := LeftEdge ;
+% else :
+% Margin := RightMargin ;
+% Edge := RightEdge ;
+% InnerMargin := LeftMargin ;
+% InnerEdge := LeftEdge ;
+% OuterMargin := RightMargin ;
+% OuterEdge := RightEdge ;
+% fi ;
+% enddef ;
+
+% the new way:
+
+def LoadPageState =
+ % now always set
+enddef ;
+
+if unknown PageStateAvailable :
+ boolean PageStateAvailable ;
+ PageStateAvailable := false ;
+fi ;
+
+string CurrentLayout ; CurrentLayout := "default" ;
+
+vardef PaperHeight = lua.mp.PaperHeight () enddef ;
+vardef PaperWidth = lua.mp.PaperWidth () enddef ;
+vardef PrintPaperHeight = lua.mp.PrintPaperHeight () enddef ;
+vardef PrintPaperWidth = lua.mp.PrintPaperWidth () enddef ;
+vardef TopSpace = lua.mp.TopSpace () enddef ;
+vardef BottomSpace = lua.mp.BottomSpace () enddef ;
+vardef BackSpace = lua.mp.BackSpace () enddef ;
+vardef CutSpace = lua.mp.CutSpace () enddef ;
+vardef MakeupHeight = lua.mp.MakeupHeight () enddef ;
+vardef MakeupWidth = lua.mp.MakeupWidth () enddef ;
+vardef TopHeight = lua.mp.TopHeight () enddef ;
+vardef TopDistance = lua.mp.TopDistance () enddef ;
+vardef HeaderHeight = lua.mp.HeaderHeight () enddef ;
+vardef HeaderDistance = lua.mp.HeaderDistance () enddef ;
+vardef TextHeight = lua.mp.TextHeight () enddef ;
+vardef FooterDistance = lua.mp.FooterDistance () enddef ;
+vardef FooterHeight = lua.mp.FooterHeight () enddef ;
+vardef BottomDistance = lua.mp.BottomDistance () enddef ;
+vardef BottomHeight = lua.mp.BottomHeight () enddef ;
+vardef LeftEdgeWidth = lua.mp.LeftEdgeWidth () enddef ;
+vardef LeftEdgeDistance = lua.mp.LeftEdgeDistance () enddef ;
+vardef LeftMarginWidth = lua.mp.LeftMarginWidth () enddef ;
+vardef LeftMarginDistance = lua.mp.LeftMarginDistance () enddef ;
+vardef TextWidth = lua.mp.TextWidth () enddef ;
+vardef RightMarginDistance = lua.mp.RightMarginDistance () enddef ;
+vardef RightMarginWidth = lua.mp.RightMarginWidth () enddef ;
+vardef RightEdgeDistance = lua.mp.RightEdgeDistance () enddef ;
+vardef RightEdgeWidth = lua.mp.RightEdgeWidth () enddef ;
+vardef InnerMarginDistance = lua.mp.InnerMarginDistance () enddef ;
+vardef InnerMarginWidth = lua.mp.InnerMarginWidth () enddef ;
+vardef OuterMarginDistance = lua.mp.OuterMarginDistance () enddef ;
+vardef OuterMarginWidth = lua.mp.OuterMarginWidth () enddef ;
+vardef InnerEdgeDistance = lua.mp.InnerEdgeDistance () enddef ;
+vardef InnerEdgeWidth = lua.mp.InnerEdgeWidth () enddef ;
+vardef OuterEdgeDistance = lua.mp.OuterEdgeDistance () enddef ;
+vardef OuterEdgeWidth = lua.mp.OuterEdgeWidth () enddef ;
+vardef PageOffset = lua.mp.PageOffset () enddef ;
+vardef PageDepth = lua.mp.PageDepth () enddef ;
+vardef LayoutColumns = lua.mp.LayoutColumns () enddef ;
+vardef LayoutColumnDistance = lua.mp.LayoutColumnDistance() enddef ;
+vardef LayoutColumnWidth = lua.mp.LayoutColumnWidth () enddef ;
+
+vardef OnRightPage = lua.mp.OnRightPage () enddef ;
+vardef OnOddPage = lua.mp.OnOddPage () enddef ;
+vardef InPageBody = lua.mp.InPageBody () enddef ;
+
+vardef RealPageNumber = lua.mp.RealPageNumber () enddef ;
+vardef PageNumber = lua.mp.PageNumber () enddef ;
+vardef NOfPages = lua.mp.NOfPages () enddef ;
+vardef LastPageNumber = lua.mp.LastPageNumber () enddef ; % duplicates
+
+vardef CurrentColumn = lua.mp.CurrentColumn () enddef ;
+vardef NOfColumns = lua.mp.NOfColumns () enddef ;
+
+vardef BaseLineSkip = lua.mp.BaseLineSkip () enddef ;
+vardef LineHeight = lua.mp.LineHeight () enddef ;
+vardef BodyFontSize = lua.mp.BodyFontSize () enddef ;
+
+vardef TopSkip = lua.mp.TopSkip () enddef ;
+vardef StrutHeight = lua.mp.StrutHeight () enddef ;
+vardef StrutDepth = lua.mp.StrutDepth () enddef ;
+
+vardef CurrentWidth = lua.mp.CurrentWidth () enddef ;
+vardef CurrentHeight = lua.mp.CurrentHeight () enddef ;
+
+vardef HSize = lua.mp.HSize () enddef ; % duplicates
+vardef VSize = lua.mp.VSize () enddef ; % duplicates
+
+vardef EmWidth = lua.mp.EmWidth () enddef ;
+vardef ExHeight = lua.mp.ExHeight () enddef ;
+
+vardef PageFraction = lua.mp.PageFraction () enddef ;
+
+vardef SpineWidth = lua.mp.SpineWidth () enddef ;
+vardef PaperBleed = lua.mp.PaperBleed () enddef ;
+
+boolean mfun_swapped ;
+
+def SwapPageState =
+ mfun_swapped := true ; % eventually this will go !
+enddef ;
+
+extra_beginfig := extra_beginfig & "mfun_swapped := false ;" ;
+
+vardef LeftMarginWidth = if mfun_swapped and not OnRightPage : lua.mp.RightMarginWidth () else : lua.mp.LeftMarginWidth () fi enddef ;
+vardef RightMarginWidth = if mfun_swapped and not OnRightPage : lua.mp.LeftMarginWidth () else : lua.mp.RightMarginWidth () fi enddef ;
+vardef LeftMarginDistance = if mfun_swapped and not OnRightPage : lua.mp.RightMarginDistance() else : lua.mp.LeftMarginDistance () fi enddef ;
+vardef RightMarginDistance = if mfun_swapped and not OnRightPage : lua.mp.LeftMarginDistance () else : lua.mp.RightMarginDistance() fi enddef ;
+
+vardef LeftEdgeWidth = if mfun_swapped and not OnRightPage : lua.mp.RightEdgeWidth () else : lua.mp.LeftEdgeWidth () fi enddef ;
+vardef RightEdgeWidth = if mfun_swapped and not OnRightPage : lua.mp.LeftEdgeWidth () else : lua.mp.RightEdgeWidth () fi enddef ;
+vardef LeftEdgeDistance = if mfun_swapped and not OnRightPage : lua.mp.RightEdgeDistance () else : lua.mp.LeftEdgeDistance () fi enddef ;
+vardef RightEdgeDistance = if mfun_swapped and not OnRightPage : lua.mp.LeftEdgeDistance () else : lua.mp.RightEdgeDistance () fi enddef ;
+
+vardef BackSpace = if mfun_swapped and not OnRightPage : PaperWidth - MakeupWidth - fi lua.mp.BackSpace() enddef ;
+vardef CutSpace = if mfun_swapped and not OnRightPage : PaperWidth - MakeupWidth - fi lua.mp.CutSpace () enddef ;
+
+% better use:
+
+vardef OuterMarginWidth = if not OnRightPage : lua.mp.LeftMarginWidth () else : lua.mp.RightMarginWidth () fi enddef ;
+vardef InnerMarginWidth = if not OnRightPage : lua.mp.RightMarginWidth () else : lua.mp.LeftMarginWidth () fi enddef ;
+vardef OuterMarginDistance = if not OnRightPage : lua.mp.LeftMarginDistance () else : lua.mp.RightMarginDistance() fi enddef ;
+vardef InnerMarginDistance = if not OnRightPage : lua.mp.RightMarginDistance() else : lua.mp.leftMarginDistance () fi enddef ;
+
+vardef OuterEdgeWidth = if not OnRightPage : lua.mp.LeftEdgeWidth () else : lua.mp.RightEdgeWidth () fi enddef ;
+vardef InnerEdgeWidth = if not OnRightPage : lua.mp.RightEdgeWidth () else : lua.mp.LeftEdgeWidth () fi enddef ;
+vardef OuterEdgeDistance = if not OnRightPage : lua.mp.LeftEdgeDistance () else : lua.mp.RightEdgeDistance () fi enddef ;
+vardef InnerEdgeDistance = if not OnRightPage : lua.mp.RightEdgeDistance () else : lua.mp.leftEdgeDistance () fi enddef ;
+
+vardef OuterSpaceWidth = if not OnRightPage : lua.mp.BackSpace () else : lua.mp.CutSpace () fi enddef ;
+vardef InnerSpaceWidth = if not OnRightPage : lua.mp.CutSpace () else : lua.mp.BackSpace () fi enddef ;
+
+% vardef CurrentLayout = lua.mp.CurrentLayout () enddef ;
+
+vardef OverlayWidth = lua.mp.OverlayWidth () enddef ;
+vardef OverlayHeight = lua.mp.OverlayHeight () enddef ;
+vardef OverlayDepth = lua.mp.OverlayDepth () enddef ;
+vardef OverlayLineWidth = lua.mp.OverlayLineWidth() enddef ;
+vardef OverlayOffset = lua.mp.OverlayOffset () enddef ;
+
+vardef defaultcolormodel = lua.mp.defaultcolormodel() enddef ;
+
+% def OverlayLineColor = lua.mp.OverlayLineColor() enddef ;
+% def OverlayColor = lua.mp.OverlayColor () enddef ;
+
+% Next we implement the the page area model. First some constants.
+
+LeftEdge := -4 ; Top := -40 ;
+LeftEdgeSeparator := -3 ; TopSeparator := -30 ;
+LeftMargin := -2 ; Header := -20 ;
+LeftMarginSeparator := -1 ; HeaderSeparator := -10 ;
+Text := 0 ; Text := 0 ;
+RightMarginSeparator := +1 ; FooterSeparator := +10 ;
+RightMargin := +2 ; Footer := +20 ;
+RightEdgeSeparator := +3 ; BottomSeparator := +30 ;
+RightEdge := +4 ; Bottom := +40 ;
+
+% Margin := LeftMargin ; % obsolete
+% Edge := LeftEdge ; % obsolete
+% InnerMargin := RightMargin ; % obsolete
+% InnerEdge := RightEdge ; % obsolete
+% OuterMargin := LeftMargin ; % obsolete
+% OuterEdge := LeftEdge ; % obsolete
+
+numeric HorPos ; HorPos := 0 ;
+numeric VerPos ; VerPos := 0 ;
+
+% We used to initialize these variables each (sub)run but at some point MP
+% became too slow for this. See later.
+
+% path Area[][] ;
+% pair Location[][] ;
+% path Field[][] ;
+%
+% numeric Hstep[] ;
+% numeric Hsize[] ;
+% numeric Vstep[] ;
+% numeric Vsize[] ;
+%
+% for VerPos=Top step 10 until Bottom:
+% for HorPos=LeftEdge step 1 until RightEdge:
+% Area[HorPos][VerPos] := origin--cycle ;
+% Area[VerPos][HorPos] := Area[HorPos][VerPos] ;
+% Location[HorPos][VerPos] := origin ;
+% Location[VerPos][HorPos] := Location[HorPos][VerPos] ;
+% Field[HorPos][VerPos] := origin--cycle ;
+% Field[VerPos][HorPos] := Field[HorPos][VerPos] ;
+% endfor ;
+% endfor ;
+%
+%
+% def SetPageAreas =
+%
+% numeric Vsize[], Hsize[], Vstep[], Hstep[] ;
+%
+% Vsize[Top] = TopHeight ;
+% Vsize[TopSeparator] = TopDistance ;
+% Vsize[Header] = HeaderHeight ;
+% Vsize[HeaderSeparator] = HeaderDistance ;
+% Vsize[Text] = TextHeight ;
+% Vsize[FooterSeparator] = FooterDistance ;
+% Vsize[Footer] = FooterHeight ;
+% Vsize[BottomSeparator] = BottomDistance ;
+% Vsize[Bottom] = BottomHeight ;
+%
+% Vstep[Top] = Vstep[TopSeparator] +Vsize[TopSeparator] ;
+% Vstep[TopSeparator] = PaperHeight-TopSpace ;
+% Vstep[Header] = Vstep[TopSeparator] -Vsize[Header] ;
+% Vstep[HeaderSeparator] = Vstep[Header] -Vsize[HeaderSeparator] ;
+% Vstep[Text] = Vstep[HeaderSeparator]-Vsize[Text] ;
+% Vstep[FooterSeparator] = Vstep[Text] -Vsize[FooterSeparator] ;
+% Vstep[Footer] = Vstep[FooterSeparator]-Vsize[Footer] ;
+% Vstep[BottomSeparator] = Vstep[Footer] -Vsize[BottomSeparator] ;
+% Vstep[Bottom] = Vstep[BottomSeparator]-Vsize[Bottom] ;
+%
+% Hsize[LeftEdge] = LeftEdgeWidth ;
+% Hsize[LeftEdgeSeparator] = LeftEdgeDistance ;
+% Hsize[LeftMargin] = LeftMarginWidth ;
+% Hsize[LeftMarginSeparator] = LeftMarginDistance ;
+% Hsize[Text] = MakeupWidth ;
+% Hsize[RightMarginSeparator] = RightMarginDistance ;
+% Hsize[RightMargin] = RightMarginWidth ;
+% Hsize[RightEdgeSeparator] = RightEdgeDistance ;
+% Hsize[RightEdge] = RightEdgeWidth ;
+%
+% Hstep[LeftEdge] = Hstep[LeftEdgeSeparator] -Hsize[LeftEdge] ;
+% Hstep[LeftEdgeSeparator] = Hstep[LeftMargin] -Hsize[LeftEdgeSeparator] ;
+% Hstep[LeftMargin] = Hstep[LeftMarginSeparator] -Hsize[LeftMargin] ;
+% Hstep[LeftMarginSeparator] = Hstep[Text] -Hsize[LeftMarginSeparator] ;
+% Hstep[Text] = BackSpace ;
+% Hstep[RightMarginSeparator] = Hstep[Text] +Hsize[Text] ;
+% Hstep[RightMargin] = Hstep[RightMarginSeparator]+Hsize[RightMarginSeparator] ;
+% Hstep[RightEdgeSeparator] = Hstep[RightMargin] +Hsize[RightMargin] ;
+% Hstep[RightEdge] = Hstep[RightEdgeSeparator] +Hsize[RightEdgeSeparator] ;
+%
+% for VerPos=Top step 10 until Bottom:
+% for HorPos=LeftEdge step 1 until RightEdge:
+% Area[HorPos][VerPos] := unitsquare xscaled Hsize[HorPos] yscaled Vsize[VerPos] ;
+% Area[VerPos][HorPos] := Area[HorPos][VerPos] ;
+% Location[HorPos][VerPos] := (Hstep[HorPos],Vstep[VerPos]) ;
+% Location[VerPos][HorPos] := Location[HorPos][VerPos] ;
+% Field[HorPos][VerPos] := Area[HorPos][VerPos] shifted Location[HorPos][VerPos] ;
+% Field[VerPos][HorPos] := Field[HorPos][VerPos] ;
+% endfor ;
+% endfor ;
+%
+% Page := unitsquare xscaled PaperWidth yscaled PaperHeight ;
+%
+% enddef ;
+%
+% def BoundPageAreas =
+% % pickup pencircle scaled 0pt ;
+% bboxmargin := 0 ; setbounds currentpicture to Page ;
+% enddef ;
+%
+% def StartPage =
+% begingroup ;
+% if PageStateAvailable :
+% LoadPageState ;
+% SwapPageState ;
+% fi ;
+% SetPageAreas ;
+% BoundPageAreas ;
+% enddef ;
+%
+% def StopPage =
+% BoundPageAreas ;
+% endgroup ;
+% enddef ;
+
+% Because metapost > 1.50 has dynamic memory management and is less
+% efficient than before we now delay calculations ... (on a document
+% with 150 pages the time spent in mp was close to 5 seconds which was
+% only due to initialising the page related areas, something that was
+% hardly noticeable before. At least now we're back to half a second
+% for such a case.
+
+def SetPageVsize =
+ numeric Vsize[] ;
+ Vsize[Top] = TopHeight ;
+ Vsize[TopSeparator] = TopDistance ;
+ Vsize[Header] = HeaderHeight ;
+ Vsize[HeaderSeparator] = HeaderDistance ;
+ Vsize[Text] = TextHeight ;
+ Vsize[FooterSeparator] = FooterDistance ;
+ Vsize[Footer] = FooterHeight ;
+ Vsize[BottomSeparator] = BottomDistance ;
+ Vsize[Bottom] = BottomHeight ;
+enddef ;
+
+def SetPageHsize =
+ numeric Hsize[] ;
+ Hsize[LeftEdge] = LeftEdgeWidth ;
+ Hsize[LeftEdgeSeparator] = LeftEdgeDistance ;
+ Hsize[LeftMargin] = LeftMarginWidth ;
+ Hsize[LeftMarginSeparator] = LeftMarginDistance ;
+ Hsize[Text] = MakeupWidth ;
+ Hsize[RightMarginSeparator] = RightMarginDistance ;
+ Hsize[RightMargin] = RightMarginWidth ;
+ Hsize[RightEdgeSeparator] = RightEdgeDistance ;
+ Hsize[RightEdge] = RightEdgeWidth ;
+enddef ;
+
+def SetPageVstep =
+ numeric Vstep[] ;
+ Vstep[Top] = Vstep[TopSeparator] +Vsize[TopSeparator] ;
+ Vstep[TopSeparator] = PaperHeight-TopSpace ;
+ Vstep[Header] = Vstep[TopSeparator] -Vsize[Header] ;
+ Vstep[HeaderSeparator] = Vstep[Header] -Vsize[HeaderSeparator] ;
+ Vstep[Text] = Vstep[HeaderSeparator]-Vsize[Text] ;
+ Vstep[FooterSeparator] = Vstep[Text] -Vsize[FooterSeparator] ;
+ Vstep[Footer] = Vstep[FooterSeparator]-Vsize[Footer] ;
+ Vstep[BottomSeparator] = Vstep[Footer] -Vsize[BottomSeparator] ;
+ Vstep[Bottom] = Vstep[BottomSeparator]-Vsize[Bottom] ;
+enddef ;
+
+def SetPageHstep =
+ numeric Hstep[] ;
+ Hstep[LeftEdge] = Hstep[LeftEdgeSeparator] -Hsize[LeftEdge] ;
+ Hstep[LeftEdgeSeparator] = Hstep[LeftMargin] -Hsize[LeftEdgeSeparator] ;
+ Hstep[LeftMargin] = Hstep[LeftMarginSeparator] -Hsize[LeftMargin] ;
+ Hstep[LeftMarginSeparator] = Hstep[Text] -Hsize[LeftMarginSeparator] ;
+ Hstep[Text] = BackSpace ;
+ Hstep[RightMarginSeparator] = Hstep[Text] +Hsize[Text] ;
+ Hstep[RightMargin] = Hstep[RightMarginSeparator]+Hsize[RightMarginSeparator] ;
+ Hstep[RightEdgeSeparator] = Hstep[RightMargin] +Hsize[RightMargin] ;
+ Hstep[RightEdge] = Hstep[RightEdgeSeparator] +Hsize[RightEdgeSeparator] ;
+enddef ;
+
+def SetPageArea =
+ path Area[][] ;
+ for VerPos=Top step 10 until Bottom:
+ for HorPos=LeftEdge step 1 until RightEdge:
+ Area[HorPos][VerPos] := unitsquare xscaled Hsize[HorPos] yscaled Vsize[VerPos] ;
+ Area[VerPos][HorPos] := Area[HorPos][VerPos] ;
+ endfor ;
+ endfor ;
+enddef ;
+
+def SetPageLocation =
+ pair Location[][] ;
+ for VerPos=Top step 10 until Bottom:
+ for HorPos=LeftEdge step 1 until RightEdge:
+ Location[HorPos][VerPos] := (Hstep[HorPos],Vstep[VerPos]) ;
+ Location[VerPos][HorPos] := Location[HorPos][VerPos] ;
+ endfor ;
+ endfor ;
+enddef ;
+
+def SetPageField =
+ path Field[][] ;
+ for VerPos=Top step 10 until Bottom:
+ for HorPos=LeftEdge step 1 until RightEdge:
+ Field[HorPos][VerPos] := unitsquare xscaled Hsize[HorPos] yscaled Vsize[VerPos] shifted (Hstep[HorPos],Vstep[VerPos]) ;
+ Field[VerPos][HorPos] := Field[HorPos][VerPos] ;
+ endfor ;
+ endfor ;
+enddef ;
+
+def mfun_page_Area = hide(SetPageArea ;) Area enddef ;
+def mfun_page_Location = hide(SetPageLocation ;) Location enddef ;
+def mfun_page_Field = hide(SetPageField ;) Field enddef ;
+def mfun_page_Vsize = hide(SetPageVsize ;) Vsize enddef ;
+def mfun_page_Hsize = hide(SetPageHsize ;) Hsize enddef ;
+def mfun_page_Vstep = hide(SetPageVstep ;) Vstep enddef ;
+def mfun_page_Hstep = hide(SetPageHstep ;) Hstep enddef ;
+
+def SetAreaVariables =
+ let Area = mfun_page_Area ;
+ let Location = mfun_page_Location ;
+ let Field = mfun_page_Field ;
+ let Vsize = mfun_page_Vsize ;
+ let Hsize = mfun_page_Hsize ;
+ let Vstep = mfun_page_Vstep ;
+ let Hstep = mfun_page_Hstep ;
+enddef ;
+
+% we should make Page no path .. from now on don't assume this .. for a while we keek it
+
+vardef FrontPageWidth = PaperWidth enddef ;
+vardef BackPageWidth = PaperWidth enddef ;
+vardef CoverWidth = 2 * PaperWidth + SpineWidth enddef ;
+vardef CoverHeight = PaperHeight enddef ;
+
+vardef FrontPageHeight = PaperHeight enddef ;
+vardef BackPageHeight = PaperHeight enddef ;
+vardef SpineHeight = PaperHeight enddef ;
+
+def SetPagePage = path Page ; Page := unitsquare xscaled PaperWidth yscaled PaperHeight ; enddef ;
+def SetPageCoverPage = path CoverPage ; CoverPage := unitsquare xscaled CoverWidth yscaled CoverHeight ; enddef ;
+def SetPageSpine = path Spine ; Spine := unitsquare xscaled SpineWidth yscaled CoverHeight shifted (BackPageWidth,0) ; enddef ;
+def SetPageBackPage = path BackPage ; BackPage := unitsquare xscaled BackPageWidth yscaled CoverHeight ; enddef ;
+def SetPageFrontPage = path FrontPage ; FrontPage := unitsquare xscaled FrontPageWidth yscaled CoverHeight shifted (BackPageWidth+SpineWidth,0) ; enddef ;
+
+def mfun_page_Page = hide(SetPagePage ;) Page enddef ;
+def mfun_page_CoverPage = hide(SetPageCoverPage;) CoverPage enddef ;
+def mfun_page_Spine = hide(SetPageSpine ;) Spine enddef ;
+def mfun_page_BackPage = hide(SetPageBackPage ;) BackPage enddef ;
+def mfun_page_FrontPage = hide(SetPageFrontPage;) FrontPage enddef ;
+
+def SetPageVariables =
+ SetAreaVariables ;
+ %
+ let Page = mfun_page_Page ;
+ let CoverPage = mfun_page_CoverPage ;
+ let Spine = mfun_page_Spine ;
+ let BackPage = mfun_page_BackPage ;
+ let FrontPage = mfun_page_FrontPage ;
+enddef ;
+
+SetPageVariables ;
+
+let SetPageAreas = SetPageVariables ; % compatiblity
+
+def BoundPageAreas =
+ % pickup pencircle scaled 0pt ;
+ bboxmargin := 0 ; setbounds currentpicture to Page ;
+enddef ;
+
+def StartPage =
+ begingroup ;
+ if mfun_first_run :
+ if PageStateAvailable :
+ LoadPageState ;
+ SwapPageState ;
+ fi ;
+ SetPageVariables ;
+ fi ;
+ BoundPageAreas ;
+enddef ;
+
+def StopPage =
+ BoundPageAreas ;
+ endgroup ;
+enddef ;
+
+% cover pages
+
+def BoundCoverAreas =
+ % todo: add cropmarks
+ bboxmargin := 0 ; setbounds currentpicture to CoverPage enlarged PaperBleed ;
+enddef ;
+
+let SetCoverAreas = SetPageVariables ; % compatiblity
+
+def StartCover =
+ begingroup ;
+ if mfun_first_run :
+ if PageStateAvailable :
+ LoadPageState ;
+ % SwapPageState ;
+ fi ;
+ SetPageVariables ; % was SetPageAreas ;
+ SetCoverAreas ;
+ fi ;
+ BoundCoverAreas ;
+enddef ;
+
+def StopCover =
+ BoundCoverAreas ;
+ endgroup ;
+enddef ;
+
+% overlays:
+
+def OverlayBox =
+ (unitsquare xyscaled (OverlayWidth,OverlayHeight))
+enddef ;
+
+% handy
+
+def innerenlarged =
+ hide(LoadPageState)
+ if OnRightPage : leftenlarged else : rightenlarged fi
+enddef ;
+
+def outerenlarged =
+ hide(LoadPageState)
+ if OnRightPage : rightenlarged else : leftenlarged fi
+enddef ;
+
+% obsolete
+
+def llEnlarged (expr p,d) = (llcorner p shifted (-d,-d)) enddef ;
+def lrEnlarged (expr p,d) = (lrcorner p shifted (+d,-d)) enddef ;
+def urEnlarged (expr p,d) = (urcorner p shifted (+d,+d)) enddef ;
+def ulEnlarged (expr p,d) = (ulcorner p shifted (-d,+d)) enddef ;
+
+def Enlarged (expr p, d) =
+ (llEnlarged (p,d) --
+ lrEnlarged (p,d) --
+ urEnlarged (p,d) --
+ ulEnlarged (p,d) -- cycle)
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-shap.mpiv b/metapost/context/base/mpiv/mp-shap.mpiv
new file mode 100644
index 000000000..713656510
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-shap.mpiv
@@ -0,0 +1,218 @@
+%D \module
+%D [ file=mp-shap.mpiv,
+%D version=2000.05.31,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=shapes,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+if known context_shap : endinput ; fi ;
+
+boolean context_shap ; context_shap := true ;
+
+path predefined_shapes[] ;
+
+def start_predefined_shape_definition =
+
+ begingroup ;
+
+ save xradius, yradius, xxradius, yyradius ;
+ save ll, lr, ur, ul, llx, lly, lrx, lry, urx, ury, ulx, uly, llxx, llyy, lrxx, lryy, urxx, uryy, ulxx, ulyy, lc, rc, tc, bc ;
+
+ numeric xradius, yradius, xxradius, yyradius ;
+ pair ll, lr, ur, ul, llx, lly, lrx, lry, urx, ury, ulx, uly, llxx, llyy, lrxx, lryy, urxx, uryy, ulxx, ulyy, lc, rc, tc, bc ;
+
+ xradius := .15 ;
+ yradius := .15 ;
+ xxradius := .10 ;
+ yyradius := .10 ;
+
+ ll := llcorner (unitsquare shifted (-.5,-.5)) ;
+ lr := lrcorner (unitsquare shifted (-.5,-.5)) ;
+ ur := urcorner (unitsquare shifted (-.5,-.5)) ;
+ ul := ulcorner (unitsquare shifted (-.5,-.5)) ;
+
+ llx := ll shifted (xradius,0) ;
+ lly := ll shifted (0,yradius) ;
+
+ lrx := lr shifted (-xradius,0) ;
+ lry := lr shifted (0,yradius) ;
+
+ urx := ur shifted (-xradius,0) ;
+ ury := ur shifted (0,-yradius) ;
+
+ ulx := ul shifted (xradius,0) ;
+ uly := ul shifted (0,-yradius) ;
+
+ llxx := ll shifted (xxradius,0) ;
+ llyy := ll shifted (0,yyradius) ;
+
+ lrxx := lr shifted (-xxradius,0) ;
+ lryy := lr shifted (0,yyradius) ;
+
+ urxx := ur shifted (-xxradius,0) ;
+ uryy := ur shifted (0,-yyradius) ;
+
+ ulxx := ul shifted (xxradius,0) ;
+ ulyy := ul shifted (0,-yyradius) ;
+
+ lc := ll shifted (0,.5) ;
+ rc := lr shifted (0,.5) ;
+ tc := ul shifted (.5,0) ;
+ bc := ll shifted (.5,0) ;
+
+enddef ;
+
+def stop_predefined_shape_definition =
+
+ endgroup ;
+
+enddef ;
+
+start_predefined_shape_definition ;
+
+ predefined_shapes[ 0] := (origin--cycle) ;
+ predefined_shapes[ 5] := (llx--lrx{right}...rc...{left}urx--ulx{left}...lc...{right}cycle) ;
+ predefined_shapes[ 6] := (ll--lrx{right}...rc...{left}urx--ul--cycle) ;
+ predefined_shapes[ 7] := (ll--lrx{right}...rc...{left}urx--ul--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[ 8] := (lr--ury{up}...tc...{down}uly--ll--cycle) ;
+ predefined_shapes[ 9] := (lr--ury{up}...tc...{down}uly--ll--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[10] := (ll--lr--ur--ul--ll--ur--ul--ll--cycle) ;
+ predefined_shapes[11] := (ll--lr--ur--ul--ll--lr--ul--ll--cycle) ;
+ predefined_shapes[12] := (ll--lrx--ur--ulx--cycle) ;
+ predefined_shapes[13] := (llx--lr--urx--ul--cycle) ;
+ predefined_shapes[14] := (lly--bc--lry--ury--tc--uly--cycle) ;
+ predefined_shapes[15] := (llx--lrx--rc--urx--ulx--lc--cycle) ;
+ predefined_shapes[16] := (ll--lrx--rc--urx--ul--cycle) ;
+ predefined_shapes[17] := (ll--lrx--rc--urx--ul--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[18] := (lr--ury--tc--uly--ll--cycle) ;
+ predefined_shapes[19] := (lr--ury--tc--uly--ll--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[20] := (ll--lr--ur--ul--ll--llxx--ulxx--ul--ll--lr--ur--urxx--lrxx--cycle) ;
+ predefined_shapes[21] := (ul--ll--lr--ur--ul--ulyy--uryy--ur--ul--ll--lr--lryy--llyy--cycle) ;
+ predefined_shapes[22] := (ll--lrx--lry--ur--ulx--uly--cycle) ;
+ predefined_shapes[23] := (llx--lr--ury--urx--ul--lly--cycle) ;
+ predefined_shapes[24] := (ll--lr--ur--ul--cycle) ;
+ predefined_shapes[25] := (llx--lrx--lry--ury--urx--ulx--uly--lly--cycle) ;
+ predefined_shapes[26] := (ll--lrx--lry--ur--ul--cycle) ;
+ predefined_shapes[27] := (ll--lr--ury--urx--ul--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[28] := (ll--lr--ury--urx--ul--cycle) ;
+ predefined_shapes[29] := (ll--lrx--lry--ur--ul--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[30] := (bc{right}...{up}rc...tc{left}...{down}lc...{right}bc & bc--tc & tc{left}..{down}lc & lc--rc & rc{up}..tc{left}...{down}lc...{right}bc & cycle) rotated 45;
+ predefined_shapes[31] := (bc{right}...{up}rc...tc{left}...{down}lc...{right}bc & bc--tc & tc{left}..{down}lc & lc--rc & rc{up}..tc{left}...{down}lc...{right}bc & cycle) ;
+ predefined_shapes[32] := (ll{right}...{right}lry--ur--ul--ll--cycle) ;
+ predefined_shapes[33] := (ll{right}...{right}lry--ur--ul--ll--cycle--ul--ulx--ulx shifted(0,yyradius)--ur shifted(yyradius,yyradius)--lry shifted(yyradius,yyradius)--lry shifted(0,yyradius)--ur--ul--cycle ) ;
+ predefined_shapes[34] := (uly..tc..ury & ury..tc shifted (0,-2yradius)..uly & uly--lly & lly..bc..lry & lry--ury & ury..tc shifted (0,-2yradius)..uly & cycle ) ;
+ predefined_shapes[35] := (bc{right}...rc{up}...tc{left}...lc{down}...cycle) ;
+ predefined_shapes[36] := (ul--tc{right}..rc{down}..{left}bc--ll & ll..(xpart llx, ypart lc)..ul & cycle) ;
+ predefined_shapes[37] := (ul--tc{right}..rc{down}..{left}bc--ll & ll..(xpart llx, ypart lc)..ul & cycle) rotatedaround(origin,180) ;
+ predefined_shapes[38] := (ll--lc{up}..tc{right}..{down}rc--lr & lr..(xpart bc, ypart lly)..ll & cycle) ;
+ predefined_shapes[39] := (ll--lc{up}..tc{right}..{down}rc--lr & lr..(xpart bc, ypart lly)..ll & cycle) rotatedaround(origin,180) ;
+ predefined_shapes[40] := (ll--lr--ur--ul--ll--ur--ul--ll--lr--ul--ll--cycle) ;
+ predefined_shapes[41] := (ll--lr--ur--ul--ll--lr--rc--lc--ll--bc--tc--ul--ll & cycle) ;
+ predefined_shapes[42] := (ll--lr--origin shifted (+epsilon,0)--ur--ul--origin shifted (-epsilon,0)--cycle) ;
+ predefined_shapes[43] := (ll--ul--origin shifted (0,+epsilon)--ur--lr--origin shifted (0,-epsilon)--cycle) ;
+ predefined_shapes[45] := (bc--rc--tc--lc--cycle) ;
+ predefined_shapes[46] := (ll--ul--rc--cycle) ;
+ predefined_shapes[47] := (ll--ul--rc--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[48] := (ul--ur--bc--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[49] := (ul--ur--bc--cycle) ;
+ predefined_shapes[56] := (ll--lry--ury--ul--cycle) ;
+ predefined_shapes[57] := (ll--lry--ury--ul--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[58] := (ll--ulx--urx--lr--cycle) ;
+ predefined_shapes[59] := (ll--ulx--urx--lr--cycle) rotatedaround(origin,180);
+ predefined_shapes[66] := (rc--origin shifted ( epsilon,0) --cycle & rc--origin--cycle ) ;
+ predefined_shapes[67] := (lc--origin shifted (-epsilon,0) --cycle & lc--origin--cycle ) ;
+ predefined_shapes[68] := (tc--origin shifted (0, epsilon) --cycle & tc--origin--cycle ) ;
+ predefined_shapes[69] := (bc--origin shifted (0,-epsilon) --cycle & bc--origin--cycle ) ;
+ predefined_shapes[75] := (lly--lry--ury--uly--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[76] := (ll--lr--ur--uly--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[77] := (ll--lr--ury--ul--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[78] := (lly--lr--ur--ul--cycle) rotatedaround(origin,180) ;
+ predefined_shapes[79] := (ll--lry--ur--ul--cycle) rotatedaround(origin,180) ;
+
+ numeric predefined_shapes_xradius ; predefined_shapes_xradius := xradius ;
+ numeric predefined_shapes_yradius ; predefined_shapes_yradius := yradius ;
+ numeric predefined_shapes_xxradius ; predefined_shapes_xxradius := xxradius ;
+ numeric predefined_shapes_yyradius ; predefined_shapes_yyradius := yyradius ;
+
+stop_predefined_shape_definition ;
+
+vardef some_shape_path (expr type) =
+ if known predefined_shapes[type] : predefined_shapes[type] else : predefined_shapes[0] fi
+enddef ;
+
+def some_shape (expr shape_type, shape_width, shape_height, shape_linewidth, shape_linecolor, shape_fillcolor) =
+ begingroup ;
+ save p ; path p ;
+ p := some_shape_path (shape_type) xscaled shape_width yscaled shape_height ;
+ pickup pencircle scaled shape_linewidth ;
+ fill p withcolor shape_fillcolor ;
+ draw p withcolor shape_linecolor ;
+ endgroup ;
+enddef ;
+
+vardef drawpredefinedshape (expr t, p, lw, lc, fc) =
+ save pp ;
+ if t>1 : % normal shape
+ path pp ;
+ pp := some_shape_path(t) xyscaled(bbwidth(p), bbheight(p)) shifted center p ;
+ fill pp withcolor fc ;
+ draw pp withpen pencircle scaled lw withcolor lc ;
+ elseif t=1 : % background only
+ path pp ;
+ pp := fullsquare xyscaled(bbwidth(p), bbheight(p)) shifted center p ;
+ fill pp withcolor fc ;
+ else : % dimensions only
+ picture pp ; pp := nullpicture ;
+ setbounds pp to fullsquare xyscaled(bbwidth(p), bbheight(p)) shifted center p ;
+ draw pp ;
+ fi ;
+enddef ;
+
+vardef drawpredefinedline (expr t, p, lw, lc) =
+ if (t>0) and (length(p)>1) :
+ saveoptions ;
+ drawoptions(withpen pencircle scaled lw withcolor lc) ;
+ draw p ;
+ if t = 1 :
+ draw arrowheadonpath(p,1) ;
+ elseif t = 2 :
+ draw arrowheadonpath(reverse p,1) ;
+ elseif t = 3 :
+ for $ = p,reverse p :
+ draw arrowheadonpath($,1) ;
+ endfor ;
+ elseif t = 11 :
+ draw arrowheadonpath(p,1/2) ;
+ elseif t = 12 :
+ draw arrowheadonpath(reverse p,1/2) ;
+ elseif t = 13 :
+ for $=p,reverse p :
+ draw arrowheadonpath($,1) ;
+ endfor ;
+ for $=p,reverse p :
+ draw arrowheadonpath($,3/4) ;
+ endfor ;
+ elseif t = 21 :
+ for $=1/5,1/2,4/5 :
+ draw arrowheadonpath(p,$) ;
+ endfor ;
+ elseif t = 22 :
+ for $=1/5,1/2,4/5 :
+ draw arrowheadonpath(reverse p,$) ;
+ endfor ;
+ elseif t = 23 :
+ for $=p,reverse p :
+ draw arrowheadonpath($,1/4) ;
+ endfor ;
+ fi ;
+ fi ;
+enddef ;
+
+let drawshape = drawpredefinedshape ;
+let drawline = drawpredefinedline ;
diff --git a/metapost/context/base/mpiv/mp-step.mpiv b/metapost/context/base/mpiv/mp-step.mpiv
new file mode 100644
index 000000000..f7a7ba5de
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-step.mpiv
@@ -0,0 +1,376 @@
+%D \module
+%D [ file=mp-cell.mpiv, % mp-step.mpiv,
+%D version=2010.10.07, % 2001.05.22,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=steps,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+% step prefixes .. no save needed
+
+if known context_cell : endinput ; fi ;
+
+boolean context_cell ; context_cell := true ;
+
+def initialize_step_variables =
+ save
+ text_fill_color, text_line_color, text_line_width, text_offset,
+ cell_fill_color, cell_line_color, cell_line_width, cell_offset,
+ line_line_color, line_line_width, line_alternative,
+ line_distance, cell_distance_y, cell_distance_x,
+ nofcells, chart_vertical ;
+
+ color text_line_color ; text_line_color := red ;
+ color cell_line_color ; cell_line_color := blue ;
+ color line_line_color ; line_line_color := green ;
+
+ color text_fill_color ; text_fill_color := white ;
+ color cell_fill_color ; cell_fill_color := white ;
+
+ numeric text_line_width ; text_line_width := 2pt ;
+ numeric cell_line_width ; cell_line_width := 2pt ;
+ numeric line_line_width ; line_line_width := 2pt ;
+
+ numeric text_offset ; text_offset := 4pt ;
+ numeric cell_offset ; cell_offset := 4pt ;
+
+ numeric line_distance ; line_distance := 10pt ; % between line and text
+ numeric line_offset ; line_offset := 4pt ; % between center and start of line
+ numeric line_height ; line_height := 20pt ;
+
+ numeric cell_distance_y ; cell_distance_y := 20pt ;
+ numeric cell_distance_x ; cell_distance_x := 20pt ;
+
+ numeric text_distance_set ; text_distance_set := 4pt ;
+
+ boolean chart_vertical ; chart_vertical := false ;
+
+ numeric nofcells ; nofcells := 0 ;
+
+enddef ;
+
+def step_cells (expr t, b) =
+ nofcells := nofcells + 1 ;
+ cells_t[nofcells] := textext.d(t) ;
+ cells_b[nofcells] := textext.d(b) ;
+ texts_t[nofcells] := nullpicture ;
+ texts_m[nofcells] := nullpicture ;
+ texts_b[nofcells] := nullpicture ;
+enddef ;
+
+def step_texts (expr t, b) =
+ texts_t[nofcells] := textext.d(t) ;
+ texts_m[nofcells] := textext.d(m) ;
+ texts_b[nofcells] := textext.d(b) ;
+enddef ;
+
+def step_begin_cell =
+ nofcells := nofcells + 1 ;
+ cells_t[nofcells] := nullpicture ;
+ cells_b[nofcells] := nullpicture ;
+ texts_t[nofcells] := nullpicture ;
+ texts_m[nofcells] := nullpicture ;
+ texts_b[nofcells] := nullpicture ;
+enddef ;
+
+def step_end_cell =
+enddef ;
+
+def step_cell_top (expr t) = cells_t[nofcells] := textext.d(t) ; enddef ;
+def step_cell_bot (expr b) = cells_b[nofcells] := textext.d(b) ; enddef ;
+def step_text_top (expr t) = texts_t[nofcells] := textext.d(t) ; enddef ;
+def step_text_mid (expr m) = texts_m[nofcells] := textext.d(m) ; enddef ;
+def step_text_bot (expr b) = texts_b[nofcells] := textext.d(b) ; enddef ;
+
+def step_begin_chart =
+ begingroup ;
+ initialize_step_variables ;
+ save nofcells ; numeric nofcells ; nofcells := 0 ;
+ save cells_t, cells_m, cells_b ; picture cells_t[], cells_m[], cells_b[] ;
+ save texts_t, texts_m, texts_b ; picture texts_t[], texts_m[], texts_b[] ;
+enddef ;
+
+def step_end_chart =
+ % we could combine some loops but this is cleaner
+ save dx, delta ; numeric dx, delta ;
+ save p ; path p ;
+ save one_row_only ; boolean one_row_only ;
+ save cell_t, next_t, text_t ; picture cell_t, next_t, text_t ;
+ save cell_m, next_m, text_m ; picture cell_m, next_m, text_m ;
+ save cell_b, next_b, text_b ; picture cell_b, next_b, text_b ;
+ save height_t, width_t, max_height_t, max_width_t ; numeric height_t, width_t, max_height_t, max_width_t ;
+ save height_m, width_m, max_height_m, max_width_m ; numeric height_m, width_m, max_height_m, max_width_m ;
+ save height_b, width_b, max_height_b, max_width_b ; numeric height_b, width_b, max_height_b, max_width_b ;
+ % check rows
+ one_row_only := true ;
+ for i=1 upto nofcells :
+ if bbwidth(cells_b[i]) > 0 :
+ one_row_only := false ;
+ fi ;
+ endfor ;
+ % swap and rotate
+ if chart_vertical :
+ if one_row_only :
+ % deal with mid_texts
+ max_width_t := max_width_m := max_width_b := 0 ;
+ for i=1 upto nofcells :
+ width_t := bbwidth(texts_t[i]) ;
+ width_m := bbwidth(texts_m[i]) ;
+ width_b := bbwidth(texts_b[i]) ;
+ if width_t > max_width_t : max_width_t := width_t fi ;
+ if width_m > max_width_m : max_width_m := width_m fi ;
+ if width_b > max_width_b : max_width_b := width_b fi ;
+ endfor ;
+ if max_width_m > 0 :
+ for i=1 upto nofcells :
+ text_t := texts_t[i] ; width_t := bbwidth(text_t) ;
+ text_m := texts_m[i] ; width_m := bbwidth(text_m) ;
+ text_b := texts_b[i] ; width_b := bbwidth(text_b) ;
+ if width_t < max_width_t :
+ setbounds text_t to boundingbox text_t leftenlarged (max_width_t - width_t) ;
+ fi ;
+ if width_m < max_width_m :
+ setbounds text_m to boundingbox text_m leftenlarged ((max_width_m - width_m)/2) ;
+ setbounds text_m to boundingbox text_m rightenlarged ((max_width_m - width_m)/2) ;
+ fi ;
+ if width_b < max_width_b :
+ setbounds text_b to boundingbox text_b rightenlarged (max_width_b - width_b) ;
+ fi ;
+ text_t := text_t shifted (- xpart llcorner text_t, 0) ;
+ text_m := text_m shifted (- xpart llcorner text_m, 0) ;
+ text_b := text_b shifted (- xpart llcorner text_b, 0) ;
+ texts_t[i] := image (
+ draw text_t ;
+ draw text_m shifted (max_width_t + text_distance_set,0) ;
+ draw text_b shifted (max_width_t + max_width_m + 2*text_distance_set,0) ;
+ ) rotated 90 ;
+ texts_m[i] := texts_b[i] := nullpicture ;
+ cells_t[i] := cells_t[i] rotated 90 ;
+ endfor ;
+ else :
+ for i=1 upto nofcells :
+ cells_t[i] := cells_t[i] rotated 90 ;
+ texts_t[i] := texts_t[i] rotated 90 ;
+ texts_b[i] := texts_b[i] rotated 90 ;
+ endfor ;
+ fi ;
+ else :
+ for i=1 upto nofcells :
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ cells_t[i] := cell_b rotated 90 ;
+ cells_b[i] := cell_t rotated 90 ;
+ text_t := texts_t[i] ;
+ text_b := texts_b[i] ;
+ texts_t[i] := text_b rotated 90 ;
+ texts_b[i] := text_t rotated 90 ;
+ endfor ;
+ fi ;
+ fi ;
+ % align horizontal
+ for i=1 upto nofcells :
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ width_t := bbwidth(cell_t) ;
+ width_b := bbwidth(cell_b) ;
+ if (width_t = 0) and (width_b = 0) :
+ % skip
+ elseif (width_t > 0) and (width_t < width_b) :
+ delta := (width_b-width_t)/2 ;
+ setbounds cell_t to boundingbox cell_t leftenlarged delta rightenlarged delta ;
+ cells_t[i] := cell_t ;
+ elseif (width_b > 0) and (width_t > width_b) :
+ delta := (width_t-width_b)/2 ;
+ setbounds cell_b to boundingbox cell_b leftenlarged delta rightenlarged delta ;
+ cells_b[i] := cell_b ;
+ fi ;
+ endfor ;
+ % analyze vertical
+ max_height_t := 0 ;
+ max_height_b := 0 ;
+ for i=1 upto nofcells :
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ height_t := bbheight(cell_t) ;
+ height_b := bbheight(cell_b) ;
+ if height_t > 0 :
+ setbounds cell_t to boundingbox cell_t enlarged cell_offset ;
+ height_t := height_t + 2 * cell_offset ;
+ cells_t[i] := cell_t ;
+ fi ;
+ if height_b > 0 :
+ setbounds cell_b to boundingbox cell_b enlarged cell_offset ;
+ height_b := height_b + 2 * cell_offset ;
+ cells_b[i] := cell_b ;
+ fi ;
+ if height_t > max_height_t :
+ max_height_t := height_t ;
+ fi
+ if height_b > max_height_b :
+ max_height_b := height_b ;
+ fi ;
+ endfor ;
+ % align vertical
+ for i=1 upto nofcells :
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ height_t := bbheight(cell_t) ;
+ height_b := bbheight(cell_b) ;
+ if height_t > 0 :
+ delta := (max_height_t-height_t)/2 ;
+ setbounds cell_t to boundingbox cell_t topenlarged delta bottomenlarged delta ;
+ fi ;
+ if height_b > 0 :
+ delta := (max_height_b-height_b)/2 ;
+ setbounds cell_b to boundingbox cell_b topenlarged delta bottomenlarged delta ;
+ fi ;
+ cells_t[i] := cell_t ;
+ cells_b[i] := cell_b ;
+ endfor ;
+ % position
+ dx := 0 ;
+ for i=1 upto nofcells :
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ cell_t := cell_t shifted -llcorner cell_t ;
+ cell_b := cell_b shifted -llcorner cell_b ;
+ cell_t := cell_t shifted (dx, 0) ;
+ cell_b := cell_b shifted (dx,-cell_distance_y-max_height_b) ;
+ cells_t[i] := cell_t ;
+ cells_b[i] := cell_b ;
+ width_t := bbwidth(cell_t) ;
+ width_b := bbwidth(cell_b) ;
+ if width_t > 0 :
+ dx := dx + cell_distance_x + width_t ;
+ elseif width_b > 0 :
+ dx := dx + cell_distance_x + width_b ;
+ fi ;
+ endfor ;
+ % flush
+ for i=1 upto nofcells :
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ width_t := bbwidth(cell_t) ;
+ width_b := bbwidth(cell_b) ;
+ if width_t > 0 :
+ fill boundingbox cell_t withcolor cell_fill_color ;
+ draw boundingbox cell_t withpen pencircle scaled cell_line_width withcolor cell_line_color ;
+ draw cell_t ;
+ fi ;
+ if width_b > 0 :
+ fill boundingbox cell_b withcolor cell_fill_color ;
+ draw boundingbox cell_b withpen pencircle scaled cell_line_width withcolor cell_line_color ;
+ draw cell_b ;
+ fi ;
+ endfor ;
+ %
+ def midtopboundary expr p = 0.5[ulcorner boundingbox p, urcorner boundingbox p] enddef ;
+ def midbottomboundary expr p = 0.5[llcorner boundingbox p, lrcorner boundingbox p] enddef ;
+ % draw top and bottom text boxes
+ for i=1 upto nofcells-1 :
+ text_t := texts_t[i] ;
+ text_b := texts_b[i] ;
+ if bbwidth(text_t) > 0 :
+ setbounds text_t to boundingbox text_t enlarged text_offset ;
+ texts_t[i] := text_t ;
+ fi ;
+ if bbwidth(text_b) > 0 :
+ setbounds text_b to boundingbox text_b enlarged text_offset ;
+ texts_b[i] := text_b ;
+ fi ;
+ endfor ;
+ % arrows
+ for i=1 upto nofcells-1 :
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ next_t := cells_t[i+1] ;
+ next_b := cells_b[i+1] ;
+ pair t_a, t_b, t_c, b_a, b_b, b_c ;
+ t_a := midtopboundary cell_t ;
+ t_b := midtopboundary next_t ;
+ t_c := (xpart 0.5[t_a,t_b], ypart t_a+line_height+line_distance) ;
+ if one_row_only :
+ b_a := midbottomboundary cell_t ;
+ b_b := midbottomboundary next_t ;
+ else :
+ b_a := midbottomboundary cell_b ;
+ b_b := midbottomboundary next_b ;
+ fi ;
+ b_c := (xpart 0.5[b_a,b_b], ypart b_a-line_height-line_distance) ;
+ texts_t[i] := thelabel.top(texts_t[i],t_c) ;
+ texts_b[i] := thelabel.bot(texts_b[i],b_c) ;
+ endfor ;
+ %
+ for i=1 upto nofcells-1 : % todo arrows when empty text
+ cell_t := cells_t[i] ;
+ cell_b := cells_b[i] ;
+ next_t := cells_t[i+1] ;
+ next_b := cells_b[i+1] ;
+ text_t := texts_t[i] ;
+ text_b := texts_b[i] ;
+ if bbwidth(text_t) > 0 :
+ if bbwidth(cell_t) > 0 :
+ drawarrow midtopboundary cell_t
+ shifted (if i > 1 : line_offset else : 0 fi, cell_line_width) {up} ..
+ midbottomboundary text_t shifted (0,-line_distance) ..
+ {down} midtopboundary next_t shifted(if i < nofcells - 1 : -line_offset else : 0 fi,cell_line_width)
+ withpen pencircle scaled line_line_width
+ withcolor line_line_color ;
+ else :
+ fi ;
+ fi ;
+ if bbwidth(text_b) > 0 :
+ if one_row_only :
+ cell_b := cell_t ;
+ next_b := next_t ;
+ fi ;
+ if bbwidth(cell_b) > 0 :
+ drawarrow midbottomboundary cell_b
+ shifted (if i > 1 : line_offset else : 0 fi, -cell_line_width) {down} ..
+ midtopboundary text_b shifted (0, line_distance) ..
+ {up} midbottomboundary next_b shifted (if i < nofcells - 1 : -line_offset else : 0 fi,-cell_line_width)
+ withpen pencircle scaled line_line_width
+ withcolor line_line_color ;
+ else :
+ fi ;
+ fi ;
+ endfor ;
+ % draw top and bottom text boxes
+ for i=1 upto nofcells-1 :
+ text_t := texts_t[i] ;
+ text_b := texts_b[i] ;
+ if bbwidth(text_t) > 0 :
+ fill boundingbox text_t withcolor text_fill_color ;
+ draw boundingbox text_t withpen pencircle scaled text_line_width withcolor text_line_color ;
+ draw text_t ;
+ fi ;
+ if bbwidth(text_b) > 0 :
+ fill boundingbox text_b withcolor text_fill_color ;
+ draw boundingbox text_b withpen pencircle scaled text_line_width withcolor text_line_color ;
+ draw text_b ;
+ fi ;
+ endfor ;
+ if chart_vertical :
+ % rotate back
+ currentpicture := currentpicture rotated -90 ;
+ fi ;
+ endgroup ;
+enddef ;
+
+% start_begin_step ;
+% step_cells ("\strut test 0", "\strut test 0") ;
+% step_cells ("\strut test 1", "\vbox{\hsize3cm \strut oeps 1\crlf oeps 1}") ;
+% step_texts ("\strut 1", "\strut 1") ;
+% step_cells ("\strut test 2", "\strut oeps 2 oeps 2") ;
+% step_cells ("\strut test X", "\strut test X") ;
+% step_texts ("\strut 2", "\strut 2") ;
+% step_cells ("\strut test 3", "\strut oeps 3 oeps 3") ;
+% step_texts ("\strut 3", "\strut 3") ;
+% step_cells ("\strut test 4", "\strut oeps 4 oeps 4") ;
+% step_texts ("\strut 4", "\strut 4") ;
+% stop_end_chart ;
diff --git a/metapost/context/base/mpiv/mp-symb.mpiv b/metapost/context/base/mpiv/mp-symb.mpiv
new file mode 100644
index 000000000..a84c84e82
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-symb.mpiv
@@ -0,0 +1,351 @@
+%D \module
+%D [ file=mp-symb.mp,
+%D version=very old,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=navigation symbol macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Instead of these symbols, you can use the \type {contnav}
+%D font by Taco Hoekwater that is derived form this file.
+
+u := 3;
+h := 5u;
+wt := 5u;
+wb := .25wt;
+o := .1u;
+pw := .5u;
+
+drawoptions (withpen pencircle scaled pw);
+
+path lefttriangle, righttriangle, sublefttriangle, subrighttriangle;
+
+pair s ; s = (2wb,0) ;
+
+x1t = x2t = 0;
+x3t = wt;
+y3t = .5h;
+z1t-z2t = (z3t-z2t) rotated 60;
+
+z4t = (z2t--z3t) intersectionpoint ((z1t--z2t) shifted s) ;
+z5t = (z3t--z1t) intersectionpoint ((z1t--z2t) shifted s) ;
+
+righttriangle = z1t--z2t--z3t--cycle;
+lefttriangle = righttriangle rotatedaround((0,.5h), 180) shifted (wt,0);
+
+subrighttriangle = z4t--((z2t--z3t--z1t) shifted s)--z5t ;
+sublefttriangle = subrighttriangle rotatedaround((0,.5h), 180) shifted (wt,0);
+
+path sidebar;
+
+x1b = x4b = 0;
+x2b = x3b = wb;
+y1b = y2b = y1t;
+y3b = y4b = y2t;
+
+sidebar = z1b--z2b--z3b--z4b--cycle;
+
+path midbar, onebar, twobar;
+
+hh = abs(y1t-y2t);
+
+%midbar := unitsquare scaled 2hh/3;
+midbar := unitsquare scaled hh;
+onebar := unitsquare xscaled (hh/3) yscaled hh;
+twobar := onebar;
+
+def prepareglyph =
+ drawoptions (withpen pencircle scaled .5u);
+enddef;
+
+def finishglyph =
+ set_outer_boundingbox currentpicture;
+ bboxmargin := o;
+ setbounds currentpicture to bbox currentpicture;
+% draw boundingbox currentpicture withcolor red withpen pencircle scaled 1;
+enddef;
+
+beginfig (1);
+ prepareglyph;
+ fill lefttriangle;
+ draw lefttriangle; % draw gets the bbox right, filldraw doesn't
+ finishglyph;
+endfig;
+
+beginfig (2);
+ prepareglyph;
+ fill righttriangle;
+ draw righttriangle;
+ finishglyph;
+endfig;
+
+beginfig (3);
+ prepareglyph;
+ fill sidebar;
+ draw sidebar;
+ fill lefttriangle shifted (.5s);
+ draw lefttriangle shifted (.5s);
+ finishglyph;
+endfig;
+
+beginfig (4);
+ prepareglyph;
+ fill righttriangle;
+ draw righttriangle;
+ fill sidebar shifted (wt,0);
+ draw sidebar shifted (wt,0);
+ finishglyph;
+endfig;
+
+beginfig (5);
+ prepareglyph;
+ fill lefttriangle;
+ draw lefttriangle;
+ fill lefttriangle shifted s;
+ draw lefttriangle shifted s;
+ finishglyph;
+endfig;
+
+beginfig (6);
+ prepareglyph;
+ fill righttriangle;
+ draw righttriangle;
+ fill righttriangle shifted s;
+ draw righttriangle shifted s;
+ finishglyph;
+endfig;
+
+beginfig (7);
+ prepareglyph;
+ fill midbar;
+ draw midbar;
+ finishglyph;
+endfig;
+
+beginfig (8);
+ prepareglyph;
+ fill onebar;
+ draw onebar;
+ finishglyph;
+endfig;
+
+beginfig (9);
+ prepareglyph;
+ fill twobar;
+ draw twobar;
+ fill twobar shifted (pw+hh/2,0);
+ draw twobar shifted (pw+hh/2,0);
+ finishglyph;
+endfig;
+
+beginfig(101);
+ prepareglyph;
+ draw lefttriangle;
+ finishglyph;
+endfig;
+
+beginfig(102);
+ prepareglyph;
+ draw righttriangle;
+ finishglyph;
+endfig;
+
+beginfig(103);
+ prepareglyph;
+ draw sidebar;
+ draw lefttriangle shifted (.5s);
+ finishglyph;
+endfig;
+
+beginfig(104);
+ prepareglyph;
+ draw righttriangle;
+ draw sidebar shifted (wt,0);
+ finishglyph;
+endfig;
+
+beginfig(105);
+ prepareglyph;
+ draw lefttriangle;
+ draw lefttriangle shifted s;
+ finishglyph;
+endfig;
+
+beginfig(106);
+ prepareglyph;
+ draw righttriangle;
+ draw righttriangle shifted s;
+ finishglyph;
+endfig;
+
+beginfig(107);
+ prepareglyph;
+ draw midbar;
+ finishglyph;
+endfig;
+
+beginfig(108);
+ prepareglyph;
+ draw onebar;
+ finishglyph;
+endfig;
+
+beginfig(109);
+ prepareglyph;
+ draw twobar;
+ draw twobar shifted (pw+hh/2,0);
+ finishglyph;
+endfig;
+
+beginfig(201);
+ prepareglyph;
+ draw lefttriangle;
+ finishglyph;
+endfig;
+
+beginfig(202);
+ prepareglyph;
+ draw righttriangle;
+ finishglyph;
+endfig;
+
+beginfig(203);
+ prepareglyph;
+ draw sidebar;
+ draw lefttriangle shifted (.5s);
+ finishglyph;
+endfig;
+
+beginfig(204);
+ prepareglyph;
+ draw righttriangle;
+ draw sidebar shifted (wt,0);
+ finishglyph;
+endfig;
+
+beginfig(205);
+ prepareglyph;
+ draw sublefttriangle shifted s;
+ draw lefttriangle shifted s;
+ finishglyph;
+endfig;
+
+beginfig(206);
+ prepareglyph;
+ draw subrighttriangle;
+ draw righttriangle;
+ finishglyph;
+endfig;
+
+beginfig(207);
+ prepareglyph;
+ draw midbar;
+ finishglyph;
+endfig;
+
+beginfig(208);
+ prepareglyph;
+ draw onebar;
+ finishglyph;
+endfig;
+
+beginfig(209);
+ prepareglyph;
+ draw twobar;
+ draw twobar shifted (pw+hh/2,0);
+ finishglyph;
+endfig;
+
+
+beginfig(999);
+
+picture collection [] ;
+
+prepareglyph ;
+draw lefttriangle ;
+finishglyph ;
+collection[201] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw righttriangle ;
+finishglyph ;
+collection[202] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw sidebar ;
+draw lefttriangle shifted (.5s) ;
+finishglyph ;
+collection[203] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw righttriangle ;
+draw sidebar shifted (wt,0) ;
+finishglyph ;
+collection[204] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw sublefttriangle shifted s ;
+draw lefttriangle shifted s ;
+finishglyph ;
+collection[205] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw subrighttriangle ;
+draw righttriangle ;
+finishglyph ;
+collection[206] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw midbar ;
+finishglyph ;
+collection[207] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw onebar ;
+finishglyph ;
+collection[208] := currentpicture ;
+currentpicture := nullpicture ;
+
+prepareglyph ;
+draw twobar ;
+draw twobar shifted (pw+hh/2,0) ;
+finishglyph ;
+collection[209] := currentpicture ;
+currentpicture := nullpicture ;
+
+for i=201 upto 209 :
+ collection[i] := collection[i] shifted - center collection[i] ;
+endfor ;
+
+addto currentpicture also collection[205] shifted ( 0, 0)
+ withcolor (.3,.4,.5) ;
+addto currentpicture also collection[202] shifted ( 0,1.5h)
+ withcolor (.5,.6,.7) ;
+addto currentpicture also collection[201] shifted (1.5h, 0)
+ withcolor (.6,.7,.8) ;
+addto currentpicture also collection[206] shifted (1.5h,1.5h)
+ withcolor (.4,.5,.6) ;
+
+collection[210] := currentpicture ;
+currentpicture := nullpicture ;
+
+bboxmargin := .25u;
+
+fill bbox collection[210] withcolor .95(1,1,0);
+addto currentpicture also collection[210] ;
+
+endfig ;
+
+end
diff --git a/metapost/context/base/mpiv/mp-text.mpiv b/metapost/context/base/mpiv/mp-text.mpiv
new file mode 100644
index 000000000..b68e8412a
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-text.mpiv
@@ -0,0 +1,163 @@
+%D \module
+%D [ file=mp-text.mpiv,
+%D version=2000.07.10,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=text support,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
+%C details.
+
+%D This one is only used in metafun so it will become a module.
+
+if known context_text : endinput ; fi ;
+
+boolean context_text ; context_text := true ;
+
+def build_parshape (expr p, offset_or_path, dx, dy, baselineskip, strutheight, strutdepth, topskip) =
+
+ if unknown trace_parshape :
+ boolean trace_parshape ; trace_parshape := false ;
+ fi ;
+
+ begingroup ;
+
+ save
+ q, l, r, line, tt, bb,
+ n, hsize, vsize, vvsize, voffset, hoffset, width, indent,
+ ll, lll, rr, rrr, cp, cq, t, b ;
+
+ path
+ q, l, r, line, tt, bb ;
+ numeric
+ n, hsize, vsize, vvsize, voffset, hoffset, width[], indent[] ;
+ pair
+ ll, lll, rr, rrr, cp, cq, t, b ;
+
+ n := 0 ;
+ cp := center p ;
+
+ if path offset_or_path :
+ q := offset_or_path ;
+ cq := center q ;
+ voffset := dy ;
+ hoffset := dx ;
+ else :
+ q := p ;
+ cq := center q ;
+ hoffset := offset_or_path + dx ;
+ voffset := offset_or_path + dy ;
+ fi ;
+
+ hsize := xpart lrcorner q - xpart llcorner q ;
+ vsize := ypart urcorner q - ypart lrcorner q ;
+
+ q := p shifted - cp ;
+
+ startsavingdata ;
+
+ savedata "\global\parvoffset " & decimal voffset&"bp " ;
+ savedata "\global\parhoffset " & decimal hoffset&"bp " ;
+ savedata "\global\parwidth " & decimal hsize&"bp " ;
+ savedata "\global\parheight " & decimal vsize&"bp " ;
+
+ if not path offset_or_path :
+ q := q xscaled ((hsize-2hoffset)/hsize) yscaled ((vsize-2voffset)/vsize) ;
+ fi ;
+
+ hsize := xpart lrcorner q - xpart llcorner q ;
+ vsize := ypart urcorner q - ypart lrcorner q ;
+
+ t := (ulcorner q -- urcorner q) intersection_point q ;
+ b := (llcorner q -- lrcorner q) intersection_point q ;
+
+ if xpart directionpoint t of q < 0 :
+ q := reverse q ;
+ fi ;
+
+ l := q cutbefore t ;
+ l := l if xpart point 0 of q < 0 : & q fi cutafter b ;
+
+ r := q cutbefore b ;
+ r := r if xpart point 0 of q > 0 : & q fi cutafter t ;
+
+ % tt := (ulcorner q -- urcorner q) shifted (0,-topskip) ;
+ % bb := (llcorner q -- lrcorner q) shifted (0,strutdepth) ;
+
+ % l := l cutbefore (l intersection_point tt) ;
+ % l := l cutafter (l intersection_point bb) ;
+ % r := r cutbefore (r intersection_point bb) ;
+ % r := r cutafter (r intersection_point tt) ;
+
+ if trace_parshape :
+ drawarrow p withpen pencircle scaled 2pt withcolor red ;
+ drawarrow l shifted cp withpen pencircle scaled 1pt withcolor green ;
+ drawarrow r shifted cp withpen pencircle scaled 1pt withcolor blue ;
+ fi ;
+
+ vardef found_point (expr lin, pat, sig) =
+ pair a, b ;
+ a := pat intersection_point (lin shifted (0,strutheight)) ;
+ if intersection_found :
+ a := a shifted (0,-strutheight) ;
+ else :
+ a := pat intersection_point lin ;
+ fi ;
+ b := pat intersection_point (lin shifted (0,-strutdepth)) ;
+ if intersection_found :
+ if sig :
+ if xpart b > xpart a : a := b shifted (0,strutdepth) fi ;
+ else :
+ if xpart b < xpart a : a := b shifted (0,strutdepth) fi ;
+ fi ;
+ fi ;
+ a
+ enddef ;
+
+ if (strutheight+strutdepth<baselineskip) :
+ vvsize := vsize ;
+ else :
+ vvsize := (vsize div baselineskip) * baselineskip ;
+ fi ;
+
+ for i=topskip step baselineskip until vvsize :
+
+ line := (ulcorner q -- urcorner q) shifted (0,-i-eps) ;
+
+ ll := found_point(line,l,true ) ;
+ rr := found_point(line,r,false) ;
+
+ if trace_parshape :
+ fill (ll--rr--rr shifted (0,strutheight)--ll shifted (0,strutheight)--cycle) shifted cp withcolor .5white ;
+ fill (ll--rr--rr shifted (0,-strutdepth)--ll shifted (0,-strutdepth)--cycle) shifted cp withcolor .7white ;
+ draw ll shifted cp withpen pencircle scaled 2pt ;
+ draw rr shifted cp withpen pencircle scaled 2pt ;
+ draw (ll--rr) shifted cp withpen pencircle scaled .5pt ;
+ fi ;
+
+ n := n + 1 ;
+ indent[n] := abs(xpart ll - xpart llcorner q) ;
+ width[n] := abs(xpart rr - xpart ll) ;
+
+ if (i=strutheight) and (width[n]<baselineskip) :
+ n := n - 1 ;
+ savedata "\global\chardef\parfirst=1 " ;
+ fi ;
+
+ endfor ;
+
+ savedata "\global\parlines " & decimal n ;
+ savedata "\global\partoks{ " ;
+ for i=1 upto n:
+ savedata decimal indent[i]&"bp " & decimal width[i]&"bp " ;
+ endfor ;
+ savedata "}" ;
+
+ stopsavingdata ;
+
+ endgroup ;
+
+enddef ;
diff --git a/metapost/context/base/mpiv/mp-tool.mpiv b/metapost/context/base/mpiv/mp-tool.mpiv
new file mode 100644
index 000000000..13104f17e
--- /dev/null
+++ b/metapost/context/base/mpiv/mp-tool.mpiv
@@ -0,0 +1,2651 @@
+%D \module
+%D [ file=mp-tool.mpiv,
+%D version=1998.02.15,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=auxiliary macros,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% def loadfile(expr name) = scantokens("input " & name & ";") enddef ;
+
+if known context_tool : endinput ; fi ;
+
+boolean context_tool ; context_tool := true ;
+
+let @## = @# ;
+
+%D New, version number testing:
+%D
+%D \starttyping
+%D fill fullcircle scaled 2cm withcolor if mpversiongt("0.6") : red else : green fi ;
+%D fill fullcircle scaled 1cm withcolor if mpversionlt(0.6) : blue else : white fi ;
+%D \stoptyping
+
+if not known mpversion : string mpversion ; mpversion := "0.641" ; fi ;
+
+newinternal metapostversion ; metapostversion := scantokens(mpversion) ;
+
+%D We always want \EPS\ conforming output, so we say:
+
+prologues := 1 ;
+warningcheck := 0 ;
+mpprocset := 1 ;
+
+%D Namespace handling:
+
+% let exclamationmark = ! ;
+% let questionmark = ? ;
+%
+% def unprotect =
+% let ! = relax ;
+% let ? = relax ;
+% enddef ;
+%
+% def protect =
+% let ! = exclamationmark ;
+% let ? = questionmark ;
+% enddef ;
+%
+% unprotect ;
+%
+% mp!some!module = 10 ; show mp!some!module ; show somemodule ;
+%
+% protect ;
+
+string space ; space := char 32 ;
+string percent ; percent := char 37 ;
+string crlf ; crlf := char 10 & char 13 ;
+string dquote ; dquote := char 34 ;
+
+let SPACE = space ;
+let CRLF = crlf ;
+let DQUOTE = dquote ;
+let PERCENT = percent ;
+
+vardef ddecimal primary p =
+ decimal xpart p & " " & decimal ypart p
+enddef ;
+
+%D Plain compatibility:
+
+string plain_compatibility_data ; plain_compatibility_data := "" ;
+
+def startplaincompatibility =
+ begingroup ;
+ scantokens plain_compatibility_data ;
+enddef ;
+
+def stopplaincompatibility =
+ endgroup ;
+enddef ;
+
+%D More neutral:
+
+let triplet = rgbcolor ;
+let quadruplet = cmykcolor ;
+
+%D Colors:
+
+newinternal nocolormodel ; nocolormodel := 1 ;
+newinternal greycolormodel ; greycolormodel := 3 ;
+newinternal graycolormodel ; graycolormodel := 3 ;
+newinternal rgbcolormodel ; rgbcolormodel := 5 ;
+newinternal cmykcolormodel ; cmykcolormodel := 7 ;
+
+let grayscale = graycolor ;
+let greyscale = greycolor ;
+
+vardef colorpart expr c =
+ if not picture c :
+ 0
+ elseif colormodel c = greycolormodel :
+ greypart c
+ elseif colormodel c = rgbcolormodel :
+ (redpart c,greenpart c,bluepart c)
+ elseif colormodel c = cmykcolormodel :
+ (cyanpart c,magentapart c,yellowpart c,blackpart c)
+ else :
+ 0 % black
+ fi
+enddef ;
+
+vardef colorlike(text c) text v = % colorlike(a) b, c, d ;
+ save _p_ ; picture _p_ ;
+ forsuffixes i=v :
+ _p_ := image(draw origin withcolor c ;) ; % intercept pre and postscripts
+ if (colormodel _p_ = cmykcolormodel) :
+ cmykcolor i ;
+ elseif (colormodel _p_ = rgbcolormodel) :
+ rgbcolor i ;
+ else :
+ greycolor i ;
+ fi ;
+ endfor ;
+enddef ;
+
+%D Also handy (when we flush colors):
+
+vardef dddecimal primary c =
+ decimal redpart c & " " & decimal greenpart c & " " & decimal bluepart c
+enddef ;
+
+vardef ddddecimal primary c =
+ decimal cyanpart c & " " & decimal magentapart c & " " & decimal yellowpart c & " " & decimal blackpart c
+enddef ;
+
+vardef colordecimals primary c =
+ if cmykcolor c :
+ decimal cyanpart c & ":" & decimal magentapart c & ":" & decimal yellowpart c & ":" & decimal blackpart c
+ elseif rgbcolor c :
+ decimal redpart c & ":" & decimal greenpart c & ":" & decimal bluepart c
+ else :
+ decimal c
+ fi
+enddef ;
+
+vardef colordecimalslist(text t) =
+ save b ; boolean b ; b := false ;
+ for s=t :
+ if b : & " " & fi
+ colordecimals(s)
+ hide(b := true ;)
+ endfor
+enddef ;
+
+% vardef _ctx_color_spec_ primary c =
+% if cmykcolor c :
+% "c=" & decimal cyanpart c &
+% ",m=" & decimal magentapart c &
+% ",y=" & decimal yellowpart c &
+% ",k=" & decimal blackpart c
+% elseif rgbcolor c :
+% "r=" & decimal redpart c &
+% ",g=" & decimal greenpart c &
+% ",b=" & decimal bluepart c
+% else :
+% "s=" & decimal c
+% fi
+% enddef ;
+%
+% vardef _ctx_color_spec_list_(text t) =
+% save b ; boolean b ; b := false ;
+% for s=t :
+% if b : & " " & fi
+% _ctx_color_spec_(s)
+% hide(b := true ;)
+% endfor
+% enddef ;
+
+%D We have standardized data file names:
+
+def job_name =
+ jobname
+enddef ;
+
+def data_mpd_file =
+ job_name & "-mp.mpd"
+enddef ;
+
+%D Because \METAPOST\ has a hard coded limit of 4~datafiles,
+%D we need some trickery when we have multiple files. This will
+%D be redone (via \LUA).
+
+if unknown collapse_data :
+ boolean collapse_data ;
+ collapse_data := false ;
+fi ;
+
+boolean savingdata ; savingdata := false ;
+boolean savingdatadone ; savingdatadone := false ;
+
+def savedata expr txt =
+ write if collapse_data :
+ txt
+ else :
+ if savingdata : txt else : "\MPdata{" & decimal charcode & "}{" & txt & "}" fi & "%"
+ fi to data_mpd_file ;
+enddef ;
+
+def startsavingdata =
+ savingdata := true ;
+ savingdatadone := true ;
+ if collapse_data :
+ write "\MPdata{" & decimal charcode & "}{%" to data_mpd_file ;
+ fi ;
+enddef ;
+
+def stopsavingdata =
+ if collapse_data :
+ write "}%" to data_mpd_file ;
+ fi ;
+ savingdata := false ;
+enddef ;
+
+def finishsavingdata =
+ if savingdatadone :
+ write EOF to data_mpd_file ;
+ savingdatadone := false ;
+ fi ;
+enddef ;
+
+%D Instead of a keystroke eating save and allocation
+%D sequence, you can use the \citeer {new} alternatives to
+%D save and allocate in one command.
+
+def newcolor text v = forsuffixes i=v : save i ; color i ; endfor ; enddef ;
+def newnumeric text v = forsuffixes i=v : save i ; numeric i ; endfor ; enddef ;
+def newboolean text v = forsuffixes i=v : save i ; boolean i ; endfor ; enddef ;
+def newtransform text v = forsuffixes i=v : save i ; transform i ; endfor ; enddef ;
+def newpath text v = forsuffixes i=v : save i ; path i ; endfor ; enddef ;
+def newpicture text v = forsuffixes i=v : save i ; picture i ; endfor ; enddef ;
+def newstring text v = forsuffixes i=v : save i ; string i ; endfor ; enddef ;
+def newpair text v = forsuffixes i=v : save i ; pair i ; endfor ; enddef ;
+
+%D Sometimes we don't want parts of the graphics add to the
+%D bounding box. One way of doing this is to save the bounding
+%D box, draw the graphics that may not count, and restore the
+%D bounding box.
+%D
+%D \starttyping
+%D push_boundingbox currentpicture;
+%D pop_boundingbox currentpicture;
+%D \stoptyping
+%D
+%D The bounding box can be called with:
+%D
+%D \starttyping
+%D boundingbox currentpicture
+%D inner_boundingbox currentpicture
+%D outer_boundingbox currentpicture
+%D \stoptyping
+%D
+%D Especially the latter one can be of use when we include
+%D the graphic in a document that is clipped to the bounding
+%D box. In such occasions one can use:
+%D
+%D \starttyping
+%D set_outer_boundingbox currentpicture;
+%D \stoptyping
+%D
+%D Its counterpart is:
+%D
+%D \starttyping
+%D set_inner_boundingbox p
+%D \stoptyping
+
+path mfun_boundingbox_stack ;
+numeric mfun_boundingbox_stack_depth ;
+
+mfun_boundingbox_stack_depth := 0 ;
+
+def pushboundingbox text p =
+ mfun_boundingbox_stack_depth := mfun_boundingbox_stack_depth + 1 ;
+ mfun_boundingbox_stack[mfun_boundingbox_stack_depth] := boundingbox p ;
+enddef ;
+
+def popboundingbox text p =
+ setbounds p to mfun_boundingbox_stack[mfun_boundingbox_stack_depth] ;
+ mfun_boundingbox_stack[mfun_boundingbox_stack_depth] := origin ;
+ mfun_boundingbox_stack_depth := mfun_boundingbox_stack_depth - 1 ;
+enddef ;
+
+let push_boundingbox = pushboundingbox ; % downward compatible
+let pop_boundingbox = popboundingbox ; % downward compatible
+
+vardef boundingbox primary p =
+ if (path p) or (picture p) :
+ llcorner p -- lrcorner p -- urcorner p -- ulcorner p
+ else :
+ origin
+ fi -- cycle
+enddef;
+
+vardef innerboundingbox primary p =
+ top rt llcorner p --
+ top lft lrcorner p --
+ bot lft urcorner p --
+ bot rt ulcorner p -- cycle
+enddef;
+
+vardef outerboundingbox primary p =
+ bot lft llcorner p --
+ bot rt lrcorner p --
+ top rt urcorner p --
+ top lft ulcorner p -- cycle
+enddef;
+
+def inner_boundingbox = innerboundingbox enddef ;
+def outer_boundingbox = outerboundingbox enddef ;
+
+vardef set_inner_boundingbox text q = % obsolete
+ setbounds q to innerboundingbox q;
+enddef;
+
+vardef set_outer_boundingbox text q = % obsolete
+ setbounds q to outerboundingbox q;
+enddef;
+
+%D Some missing functions can be implemented rather straightforward (thanks to
+%D Taco and others):
+
+% oldpi := 3.14159265358979323846 ; % from <math.h>
+pi := 3.14159265358979323846264338327950288419716939937510 ; % 50 digits
+radian := 180/pi ; % 2pi*radian = 360 ;
+
+% let +++ = ++ ;
+
+vardef sqr primary x = x*x enddef ;
+vardef log primary x = if x=0: 0 else: mlog(x)/mlog(10) fi enddef ;
+vardef ln primary x = if x=0: 0 else: mlog(x)/256 fi enddef ;
+vardef exp primary x = (mexp 256)**x enddef ;
+vardef inv primary x = if x=0: 0 else: x**-1 fi enddef ;
+
+vardef pow (expr x,p) = x**p enddef ;
+
+vardef tand primary x = sind(x)/cosd(x) enddef ;
+vardef cotd primary x = cosd(x)/sind(x) enddef ;
+
+vardef sin primary x = sind(x*radian) enddef ;
+vardef cos primary x = cosd(x*radian) enddef ;
+vardef tan primary x = sin(x)/cos(x) enddef ;
+vardef cot primary x = cos(x)/sin(x) enddef ;
+
+vardef asin primary x = angle((1+-+x,x)) enddef ;
+vardef acos primary x = angle((x,1+-+x)) enddef ;
+vardef atan primary x = angle(1,x) enddef ;
+
+vardef invsin primary x = (asin(x))/radian enddef ;
+vardef invcos primary x = (acos(x))/radian enddef ;
+vardef invtan primary x = (atan(x))/radian enddef ;
+
+vardef acosh primary x = ln(x+(x+-+1)) enddef ;
+vardef asinh primary x = ln(x+(x++1)) enddef ;
+
+vardef sinh primary x = save xx ; xx = exp x ; (xx-1/xx)/2 enddef ;
+vardef cosh primary x = save xx ; xx = exp x ; (xx+1/xx)/2 enddef ;
+
+%D Like mod, but useful for anglesl it returns (-.5d,+.5d] and is used
+%D in for instance mp-chem.
+
+primarydef a zmod b = (-((b/2 - a) mod b) + b/2) enddef ;
+
+%D Sometimes this is handy:
+
+def undashed =
+ dashed nullpicture
+enddef ;
+
+%D We provide two macros for drawing stripes across a shape.
+%D The first method (with the n suffix) uses another method,
+%D slower in calculation, but more efficient when drawn. The
+%D first macro divides the sides into n equal parts. The
+%D first argument specifies the way the lines are drawn, while
+%D the second argument identifier the way the shape is to be
+%D drawn.
+%D
+%D \starttyping
+%D stripe_path_n
+%D (dashed evenly withcolor blue)
+%D (filldraw)
+%D fullcircle xscaled 100 yscaled 40 shifted (50,50) withpen pencircle scaled 4;
+%D \stoptyping
+%D
+%D The a (or angle) alternative supports arbitrary angles and
+%D is therefore more versatile.
+%D
+%D \starttyping
+%D stripe_path_a
+%D (withpen pencircle scaled 2 withcolor red)
+%D (draw)
+%D fullcircle xscaled 100 yscaled 40 withcolor blue;
+%D \stoptyping
+%D
+%D We have two alternatives, controlled by arguments or defaults (when arguments
+%D are zero).
+%D
+%D The newer and nicer interface is used as follows (triggered by a question by Mari):
+%D
+%D \starttyping
+%D draw image (draw fullcircle scaled 3cm shifted (0cm,0cm) withcolor green) numberstriped (1,10,3) withcolor red ;
+%D draw image (draw fullcircle scaled 3cm shifted (3cm,0cm) withcolor green) numberstriped (2,20,3) withcolor green ;
+%D draw image (draw fullcircle scaled 3cm shifted (3cm,3cm) withcolor green) numberstriped (3,10,5) withcolor blue ;
+%D draw image (draw fullcircle scaled 3cm shifted (0cm,3cm) withcolor green) numberstriped (4,20,5) withcolor yellow ;
+%D
+%D draw image (draw fullcircle scaled 3cm shifted (6cm,0cm) withcolor green) anglestriped (1,20,2) withcolor red ;
+%D draw image (draw fullcircle scaled 3cm shifted (9cm,0cm) withcolor green) anglestriped (2,40,2) withcolor green ;
+%D draw image (draw fullcircle scaled 3cm shifted (9cm,3cm) withcolor green) anglestriped (3,60,2) withcolor blue ;
+%D draw image (draw fullcircle scaled 3cm shifted (6cm,3cm) withcolor green) anglestriped (4,80,2) withcolor yellow ;
+%D
+%D draw image (
+%D draw fullcircle scaled 3cm shifted (0cm,0cm) withcolor green withpen pencircle scaled 2mm ;
+%D draw fullcircle scaled 2cm shifted (0cm,1cm) withcolor blue withpen pencircle scaled 3mm ;
+%D ) shifted (9cm,0cm) numberstriped (1,10,3) withcolor red ;
+%D
+%D draw image (
+%D draw fullcircle scaled 3cm shifted (0cm,0cm) withcolor green withpen pencircle scaled 2mm ;
+%D draw fullcircle scaled 2cm shifted (0cm,1cm) withcolor blue withpen pencircle scaled 3mm ;
+%D ) shifted (12cm,0cm) numberstriped (2,10,3) withcolor red ;
+%D
+%D draw image (
+%D draw fullcircle scaled 3cm shifted (0cm,0cm) withcolor green withpen pencircle scaled 2mm ;
+%D draw fullcircle scaled 2cm shifted (0cm,1cm) withcolor blue withpen pencircle scaled 3mm ;
+%D ) shifted (9cm,5cm) numberstriped (3,10,3) withcolor red ;
+%D
+%D draw image (
+%D draw fullcircle scaled 3cm shifted (0cm,0cm) withcolor green withpen pencircle scaled 2mm ;
+%D draw fullcircle scaled 2cm shifted (0cm,1cm) withcolor blue withpen pencircle scaled 3mm ;
+%D ) shifted (12cm,5cm) numberstriped (4,10,3) withcolor red ;
+%D \stoptyping
+
+stripe_n := 10;
+stripe_slot := 3;
+stripe_gap := 5;
+stripe_angle := 45;
+
+def mfun_tool_striped_number_action text extra =
+ for i = 1/used_n step 1/used_n until 1 :
+ draw point (1+i) of bounds -- point (3-i) of bounds withpen pencircle scaled penwidth extra ;
+ endfor ;
+ for i = 0 step 1/used_n until 1 :
+ draw point (3+i) of bounds -- point (1-i) of bounds withpen pencircle scaled penwidth extra ;
+ endfor ;
+enddef ;
+
+def mfun_tool_striped_set_options(expr option) =
+ save isinner, swapped ;
+ boolean isinner, swapped ;
+ if option = 1 :
+ isinner := false ;
+ swapped := false ;
+ elseif option = 2 :
+ isinner := true ;
+ swapped := false ;
+ elseif option = 3 :
+ isinner := false ;
+ swapped := true ;
+ elseif option = 4 :
+ isinner := true ;
+ swapped := true ;
+ else :
+ isinner := false ;
+ swapped := false ;
+ fi ;
+enddef ;
+
+vardef mfun_tool_striped_number(expr option, p, s_n, s_slot) text extra =
+ image (
+ begingroup ;
+ save pattern, shape, bounds, penwidth, used_n, used_slot ;
+ picture pattern, shape ; path bounds ; numeric used_s, used_slot ;
+ mfun_tool_striped_set_options(option) ;
+ used_slot := if s_slot = 0 : stripe_slot else : s_slot fi ;
+ used_n := if s_n = 0 : stripe_n else : s_n fi ;
+ shape := image(draw p) ;
+ bounds := boundingbox shape ;
+ penwidth := min(ypart urcorner shape - ypart llcorner shape, xpart urcorner shape - xpart llcorner shape) / (used_slot * used_n) ;
+ pattern := image (
+ if isinner :
+ mfun_tool_striped_number_action extra ;
+ for s within shape :
+ if stroked s or filled s :
+ clip currentpicture to pathpart s ;
+ fi
+ endfor ;
+ else :
+ for s within shape :
+ if stroked s or filled s :
+ draw image (
+ mfun_tool_striped_number_action extra ;
+ clip currentpicture to pathpart s ;
+ ) ;
+ fi ;
+ endfor ;
+ fi ;
+ ) ;
+ if swapped :
+ addto currentpicture also shape ;
+ addto currentpicture also pattern ;
+ else :
+ addto currentpicture also pattern ;
+ addto currentpicture also shape ;
+ fi ;
+ endgroup ;
+ )
+enddef ;
+
+def mfun_tool_striped_angle_action text extra =
+ for i = minimum -.5used_gap step used_gap until maximum :
+ draw (minimum,i) -- (maximum,i) extra ;
+ endfor ;
+ currentpicture := currentpicture rotated used_angle ;
+enddef ;
+
+vardef mfun_tool_striped_angle(expr option, p, s_angle, s_gap) text extra =
+ image (
+ begingroup ;
+ save pattern, shape, mask, maximum, minimum, centrum, used_angle, used_gap ;
+ picture pattern, shape, mask ; numeric maximum, minimum ; pair centrum ; numeric used_angle, used_gap ;
+ mfun_tool_striped_set_options(option) ;
+ used_angle := if s_angle = 0 : stripe_angle else : s_angle fi ;
+ used_gap := if s_gap = 0 : stripe_gap else : s_gap fi ;
+ shape := image(draw p) ;
+ centrum := center shape ;
+ shape := shape shifted - centrum ;
+ mask := shape rotated used_angle ;
+ maximum := max (xpart llcorner mask, xpart urcorner mask, ypart llcorner mask, ypart urcorner mask) ;
+ minimum := min (xpart llcorner mask, xpart urcorner mask, ypart llcorner mask, ypart urcorner mask) ;
+ pattern := image (
+ if isinner :
+ mfun_tool_striped_angle_action extra ;
+ for s within shape :
+ if stroked s or filled s :
+ clip currentpicture to pathpart s ;
+ fi
+ endfor ;
+ else :
+ for s within shape :
+ if stroked s or filled s :
+ draw image (
+ mfun_tool_striped_angle_action extra ;
+ clip currentpicture to pathpart s ;
+ ) ;
+ fi ;
+ endfor ;
+ fi ;
+ ) ;
+ if swapped :
+ addto currentpicture also shape ;
+ addto currentpicture also pattern ;
+ else :
+ addto currentpicture also pattern ;
+ addto currentpicture also shape ;
+ fi ;
+ currentpicture := currentpicture shifted - centrum ;
+ endgroup ;
+ )
+enddef;
+
+newinternal striped_normal_inner ; striped_normal_inner := 1 ;
+newinternal striped_reverse_inner ; striped_reverse_inner := 2 ;
+newinternal striped_normal_outer ; striped_normal_outer := 3 ;
+newinternal striped_reverse_outer ; striped_reverse_outer := 4 ;
+
+secondarydef p anglestriped s =
+ mfun_tool_striped_angle(redpart s,p,greenpart s,bluepart s)
+enddef ;
+
+secondarydef p numberstriped s =
+ mfun_tool_striped_number(redpart s,p,greenpart s,bluepart s)
+enddef ;
+
+% for old times sake:
+
+def stripe_path_n (text s_spec) (text s_draw) expr s_path =
+ do_stripe_path_n (s_spec) (s_draw) (s_path)
+enddef;
+
+def do_stripe_path_n (text s_spec) (text s_draw) (expr s_path) text s_text =
+ draw image(s_draw s_path s_text) numberstriped(3,0,0) s_spec ;
+enddef ;
+
+def stripe_path_a (text s_spec) (text s_draw) expr s_path =
+ do_stripe_path_a (s_spec) (s_draw) (s_path)
+enddef;
+
+def do_stripe_path_a (text s_spec) (text s_draw) (expr s_path) text s_text =
+ draw image(s_draw s_path s_text) anglestriped(3,0,0) s_spec ;
+enddef ;
+
+%D A few normalizing macros:
+
+primarydef p xsized w =
+ (p if (bbwidth (p)>0) and (w>0) : scaled (w/bbwidth (p)) fi)
+enddef ;
+
+primarydef p ysized h =
+ (p if (bbheight(p)>0) and (h>0) : scaled (h/bbheight(p)) fi)
+enddef ;
+
+primarydef p xysized s =
+ begingroup
+ save wh, w, h ; pair wh ; numeric w, h ;
+ wh := paired (s) ; w := bbwidth(p) ; h := bbheight(p) ;
+ p
+ if (w>0) and (h>0) :
+ if xpart wh > 0 : xscaled (xpart wh/w) fi
+ if ypart wh > 0 : yscaled (ypart wh/h) fi
+ fi
+ endgroup
+enddef ;
+
+let sized = xysized ;
+
+def xscale_currentpicture(expr w) = % obsolete
+ currentpicture := currentpicture xsized w ;
+enddef;
+
+def yscale_currentpicture(expr h) = % obsolete
+ currentpicture := currentpicture ysized h ;
+enddef;
+
+def xyscale_currentpicture(expr w, h) = % obsolete
+ currentpicture := currentpicture xysized (w,h) ;
+enddef;
+
+def scale_currentpicture(expr w, h) = % obsolete
+ currentpicture := currentpicture xsized w ;
+ currentpicture := currentpicture ysized h ;
+enddef;
+
+%D A full circle is centered at the origin, while a unitsquare
+%D is located in the first quadrant. Now guess what kind of
+%D path fullsquare and unitcircle do return.
+
+path fullsquare, unitcircle ;
+
+fullsquare := unitsquare shifted - center unitsquare ;
+unitcircle := fullcircle shifted urcorner fullcircle ;
+
+%D Some more paths:
+
+path urcircle, ulcircle, llcircle, lrcircle ;
+
+urcircle := origin -- (+.5,0) & (+.5,0){up} .. (0,+.5) & (0,+.5) -- cycle ;
+ulcircle := origin -- (0,+.5) & (0,+.5){left} .. (-.5,0) & (-.5,0) -- cycle ;
+llcircle := origin -- (-.5,0) & (-.5,0){down} .. (0,-.5) & (0,-.5) -- cycle ;
+lrcircle := origin -- (0,-.5) & (0,-.5){right} .. (+.5,0) & (+.5,0) -- cycle ;
+
+path tcircle, bcircle, lcircle, rcircle ;
+
+tcircle = origin -- (+.5,0) & (+.5,0) {up} .. (0,+.5) .. {down} (-.5,0) -- cycle ;
+bcircle = origin -- (-.5,0) & (-.5,0) {down} .. (0,-.5) .. {up} (+.5,0) -- cycle ;
+lcircle = origin -- (0,+.5) & (0,+.5) {left} .. (-.5,0) .. {right} (0,-.5) -- cycle ;
+rcircle = origin -- (0,-.5) & (0,-.5) {right} .. (+.5,0) .. {left} (0,+.5) -- cycle ;
+
+path urtriangle, ultriangle, lltriangle, lrtriangle ; % watch out: it's contrary to what you expect and starts in the origin
+
+urtriangle := origin -- (+.5,0) -- (0,+.5) -- cycle ;
+ultriangle := origin -- (0,+.5) -- (-.5,0) -- cycle ;
+lltriangle := origin -- (-.5,0) -- (0,-.5) -- cycle ;
+lrtriangle := origin -- (0,-.5) -- (+.5,0) -- cycle ;
+
+path triangle, uptriangle, downtriangle, lefttriangle, righttriangle ;
+
+triangle := (1,0) -- (1,0) rotated 120 -- (1,0) rotated -120 -- cycle ;
+
+uptriangle := triangle rotated 90 ;
+downtriangle := triangle rotated -90 ;
+lefttriangle := triangle rotated 180 ;
+righttriangle := triangle ;
+
+path unitdiamond, fulldiamond ;
+
+unitdiamond := (.5,0) -- (1,.5) -- (.5,1) -- (0,.5) -- cycle ;
+fulldiamond := unitdiamond shifted - center unitdiamond ;
+
+%D More robust:
+
+% let normalscaled = scaled ;
+% let normalxscaled = xscaled ;
+% let normalyscaled = yscaled ;
+%
+% def scaled expr s = normalscaled (s) enddef ;
+% def xscaled expr s = normalxscaled (s) enddef ;
+% def yscaled expr s = normalyscaled (s) enddef ;
+
+%D Shorter
+
+primarydef p xyscaled q = % secundarydef does not work out well
+ begingroup
+ save qq ; pair qq ;
+ qq = paired(q) ;
+ p
+ if xpart qq <> 0 : xscaled (xpart qq) fi
+ if ypart qq <> 0 : yscaled (ypart qq) fi
+ endgroup
+enddef ;
+
+%D Some personal code that might move to another module
+
+def set_grid(expr w, h, nx, ny) =
+ boolean grid[][] ; boolean grid_full ;
+ numeric grid_w, grid_h, grid_nx, grid_ny, grid_x, grid_y, grid_left ;
+ grid_w := w ;
+ grid_h := h ;
+ grid_nx := nx ;
+ grid_ny := ny ;
+ grid_x := round(w/grid_nx) ; % +.5) ;
+ grid_y := round(h/grid_ny) ; % +.5) ;
+ grid_left := (1+grid_x)*(1+grid_y) ;
+ grid_full := false ;
+ for i=0 upto grid_x :
+ for j=0 upto grid_y :
+ grid[i][j] := false ;
+ endfor ;
+ endfor ;
+enddef ;
+
+vardef new_on_grid(expr _dx_, _dy_) =
+ dx := _dx_ ;
+ dy := _dy_ ;
+ ddx := min(round(dx/grid_nx),grid_x) ; % +.5),grid_x) ;
+ ddy := min(round(dy/grid_ny),grid_y) ; % +.5),grid_y) ;
+ if not grid_full and not grid[ddx][ddy] :
+ grid[ddx][ddy] := true ;
+ grid_left := grid_left-1 ;
+ grid_full := (grid_left=0) ;
+ true
+ else :
+ false
+ fi
+enddef ;
+
+%D usage: \type{innerpath peepholed outerpath}.
+%D
+%D beginfig(1);
+%D def fullsquare = (unitsquare shifted -center unitsquare) enddef ;
+%D fill (fullsquare scaled 200) withcolor red ;
+%D path p ; p := (fullcircle scaled 100) ; bboxmargin := 0 ;
+%D fill p peepholed bbox p ;
+%D endfig;
+
+secondarydef p peepholed q =
+ begingroup
+ save start ; pair start ;
+ start := point 0 of p ;
+ if xpart start >= xpart center p :
+ if ypart start >= ypart center p :
+ urcorner q -- ulcorner q -- llcorner q -- lrcorner q --
+ reverse p -- lrcorner q -- cycle
+ else :
+ lrcorner q -- urcorner q -- ulcorner q -- llcorner q --
+ reverse p -- llcorner q -- cycle
+ fi
+ else :
+ if ypart start > ypart center p :
+ ulcorner q -- llcorner q -- lrcorner q -- urcorner q --
+ reverse p -- urcorner q -- cycle
+ else :
+ llcorner q -- lrcorner q -- urcorner q -- ulcorner q --
+ reverse p -- ulcorner q -- cycle
+ fi
+ fi
+ endgroup
+enddef ;
+
+boolean intersection_found ;
+
+secondarydef p intersection_point q =
+ begingroup
+ save x_, y_ ;
+ (x_,y_) = p intersectiontimes q ;
+ if x_<0 :
+ intersection_found := false ;
+ center p % origin
+ else :
+ intersection_found := true ;
+ .5[point x_ of p, point y_ of q]
+ fi
+ endgroup
+enddef ;
+
+%D New, undocumented, experimental:
+
+vardef tensecircle (expr width, height, offset) =
+ (-width/2,-height/2) ... (0,-height/2-offset) ...
+ (+width/2,-height/2) ... (+width/2+offset,0) ...
+ (+width/2,+height/2) ... (0,+height/2+offset) ...
+ (-width/2,+height/2) ... (-width/2-offset,0) ... cycle
+enddef ;
+
+vardef roundedsquare (expr width, height, offset) =
+ (offset,0) -- (width-offset,0) {right} ..
+ (width,offset) -- (width,height-offset) {up} ..
+ (width-offset,height) -- (offset,height) {left} ..
+ (0,height-offset) -- (0,offset) {down} .. cycle
+enddef ;
+
+%D Some colors.
+
+def colortype(expr c) =
+ if cmykcolor c : cmykcolor elseif rgbcolor c : rgbcolor else : grayscale fi
+enddef ;
+
+vardef whitecolor(expr c) =
+ if cmykcolor c : (0,0,0,0) elseif rgbcolor c : (1,1,1) else : 1 fi
+enddef ;
+
+vardef blackcolor expr c =
+ if cmykcolor c : (0,0,0,1) elseif rgbcolor c : (0,0,0) else : 0 fi
+enddef ;
+
+%D Well, this is the dangerous and naive version:
+
+def drawfill text t =
+ fill t ;
+ draw t ;
+enddef;
+
+%D This two step approach saves the path first, since it can
+%D be a function. Attributes must not be randomized.
+
+def drawfill expr c =
+ path _c_ ; _c_ := c ;
+ mfun_do_drawfill
+enddef ;
+
+def mfun_do_drawfill text t =
+ draw _c_ t ;
+ fill _c_ t ;
+enddef;
+
+def undrawfill expr c =
+ drawfill c withcolor background % rather useless
+enddef ;
+
+%D Moved from mp-char.mp
+
+vardef paired primary d =
+ if pair d : d else : (d,d) fi
+enddef ;
+
+vardef tripled primary d =
+ if color d : d else : (d,d,d) fi
+enddef ;
+
+% maybe secondaries:
+
+primarydef p enlarged d = ( p llmoved d -- p lrmoved d -- p urmoved d -- p ulmoved d -- cycle ) enddef ;
+primarydef p llenlarged d = ( p llmoved d -- lrcorner p -- urcorner p -- ulcorner p -- cycle ) enddef ;
+primarydef p lrenlarged d = ( llcorner p -- p lrmoved d -- urcorner p -- ulcorner p -- cycle ) enddef ;
+primarydef p urenlarged d = ( llcorner p -- lrcorner p -- p urmoved d -- ulcorner p -- cycle ) enddef ;
+primarydef p ulenlarged d = ( llcorner p -- lrcorner p -- urcorner p -- p ulmoved d -- cycle ) enddef ;
+
+primarydef p llmoved d = ( (llcorner p) shifted (-xpart paired(d),-ypart paired(d)) ) enddef ;
+primarydef p lrmoved d = ( (lrcorner p) shifted (+xpart paired(d),-ypart paired(d)) ) enddef ;
+primarydef p urmoved d = ( (urcorner p) shifted (+xpart paired(d),+ypart paired(d)) ) enddef ;
+primarydef p ulmoved d = ( (ulcorner p) shifted (-xpart paired(d),+ypart paired(d)) ) enddef ;
+
+primarydef p leftenlarged d = ( (llcorner p) shifted (-d,0) -- lrcorner p -- urcorner p -- (ulcorner p) shifted (-d,0) -- cycle ) enddef ;
+primarydef p rightenlarged d = ( llcorner p -- (lrcorner p) shifted (d,0) -- (urcorner p) shifted (d,0) -- ulcorner p -- cycle ) enddef ;
+primarydef p topenlarged d = ( llcorner p -- lrcorner p -- (urcorner p) shifted (0,d) -- (ulcorner p) shifted (0,d) -- cycle ) enddef ;
+primarydef p bottomenlarged d = ( llcorner p shifted (0,-d) -- lrcorner p shifted (0,-d) -- urcorner p -- ulcorner p -- cycle ) enddef ;
+
+%D Handy for testing/debugging:
+
+primarydef p crossed d = (
+ if pair p :
+ p shifted (-d, 0) -- p --
+ p shifted ( 0,-d) -- p --
+ p shifted (+d, 0) -- p --
+ p shifted ( 0,+d) -- p -- cycle
+ else :
+ center p shifted (-d, 0) -- llcorner p --
+ center p shifted ( 0,-d) -- lrcorner p --
+ center p shifted (+d, 0) -- urcorner p --
+ center p shifted ( 0,+d) -- ulcorner p -- cycle
+ fi
+) enddef ;
+
+%D Also handy (math ladders):
+
+vardef laddered primary p = % was expr
+ point 0 of p
+ for i=1 upto length(p) :
+ -- (xpart (point i of p), ypart (point (i-1) of p)) -- (point i of p)
+ endfor
+enddef ;
+
+%D Saves typing:
+
+% vardef bottomboundary primary p = (llcorner p -- lrcorner p) enddef ;
+% vardef rightboundary primary p = (lrcorner p -- urcorner p) enddef ;
+% vardef topboundary primary p = (urcorner p -- ulcorner p) enddef ;
+% vardef leftboundary primary p = (ulcorner p -- llcorner p) enddef ;
+
+vardef bottomboundary primary p = if pair p : p else : (llcorner p -- lrcorner p) fi enddef ;
+vardef rightboundary primary p = if pair p : p else : (lrcorner p -- urcorner p) fi enddef ;
+vardef topboundary primary p = if pair p : p else : (urcorner p -- ulcorner p) fi enddef ;
+vardef leftboundary primary p = if pair p : p else : (ulcorner p -- llcorner p) fi enddef ;
+
+%D Nice too:
+
+primarydef p superellipsed s =
+ superellipse (
+ .5[lrcorner p,urcorner p],
+ .5[urcorner p,ulcorner p],
+ .5[ulcorner p,llcorner p],
+ .5[llcorner p,lrcorner p],
+ s
+ )
+enddef ;
+
+primarydef p squeezed s = (
+ (llcorner p .. .5[llcorner p,lrcorner p] shifted ( 0, ypart paired(s)) .. lrcorner p) &
+ (lrcorner p .. .5[lrcorner p,urcorner p] shifted (-xpart paired(s), 0) .. urcorner p) &
+ (urcorner p .. .5[urcorner p,ulcorner p] shifted ( 0,-ypart paired(s)) .. ulcorner p) &
+ (ulcorner p .. .5[ulcorner p,llcorner p] shifted ( xpart paired(s), 0) .. llcorner p) & cycle
+) enddef ;
+
+primarydef p randomshifted s =
+ begingroup ;
+ save ss ; pair ss ;
+ ss := paired(s) ;
+ p shifted (-.5xpart ss + uniformdeviate xpart ss,-.5ypart ss + uniformdeviate ypart ss)
+ endgroup
+enddef ;
+
+primarydef p randomized s = (
+ if path p :
+ for i=0 upto length(p)-1 :
+ ((point i of p) randomshifted s) .. controls
+ ((postcontrol i of p) randomshifted s) and
+ ((precontrol (i+1) of p) randomshifted s) ..
+ endfor
+ if cycle p :
+ cycle
+ else :
+ ((point length(p) of p) randomshifted s)
+ fi
+ elseif pair p :
+ p randomshifted s
+ elseif cmykcolor p :
+ if color s :
+ ((uniformdeviate cyanpart s) * cyanpart p,
+ (uniformdeviate magentapart s) * magentapart p,
+ (uniformdeviate yellowpart s) * yellowpart p,
+ (uniformdeviate blackpart s) * blackpart p)
+ elseif pair s :
+ ((xpart s + (uniformdeviate (ypart s - xpart s))) * p)
+ else :
+ ((uniformdeviate s) * p)
+ fi
+ elseif rgbcolor p :
+ if color s :
+ ((uniformdeviate redpart s) * redpart p,
+ (uniformdeviate greenpart s) * greenpart p,
+ (uniformdeviate bluepart s) * bluepart p)
+ elseif pair s :
+ ((xpart s + (uniformdeviate (ypart s - xpart s))) * p)
+ else :
+ ((uniformdeviate s) * p)
+ fi
+ elseif color p :
+ if color s :
+ ((uniformdeviate greypart s) * greypart p)
+ elseif pair s :
+ ((xpart s + (uniformdeviate (ypart s - xpart s))) * p)
+ else :
+ ((uniformdeviate s) * p)
+ fi
+ else :
+ p + uniformdeviate s
+ fi
+) enddef ;
+
+%D Not perfect (alternative for interpath)
+
+vardef interpolated(expr s, p, q) =
+ save m ; numeric m ;
+ m := max(length(p),length(q)) ;
+ if path p :
+ for i=0 upto m-1 :
+ s[point (i /m) along p,point (i /m) along q] .. controls
+ s[postcontrol (i /m) along p,postcontrol (i /m) along q] and
+ s[precontrol ((i+1)/m) along p,precontrol ((i+1)/m) along q] ..
+ endfor
+ if cycle p :
+ cycle
+ else :
+ s[point infinity of p,point infinity of q]
+ fi
+ else :
+ a[p,q]
+ fi
+enddef ;
+
+%D Interesting too:
+
+primarydef p paralleled d = (
+ p shifted if d < 0 : - fi ((point abs(d) on (p rotatedaround(point 0 of p,90))) - point 0 of p)
+) enddef ;
+
+vardef punked primary p =
+ point 0 of p for i=1 upto length(p)-1 : -- point i of p endfor
+ if cycle p : -- cycle else : -- point length(p) of p fi
+enddef ;
+
+vardef curved primary p =
+ point 0 of p for i=1 upto length(p)-1 : .. point i of p endfor
+ if cycle p : .. cycle else : .. point length(p) of p fi
+enddef ;
+
+primarydef p blownup s =
+ begingroup
+ save _p_ ; path _p_ ;
+ _p_ := p xysized (bbwidth(p)+2(xpart paired(s)),bbheight(p)+2(ypart paired(s))) ;
+ (_p_ shifted (center p - center _p_))
+ endgroup
+enddef ;
+
+%D Rather fundamental.
+
+% not yet ok
+
+vardef leftrightpath(expr p, l) = % used in s-pre-19
+ save q, r, t, b ; path q, r ; pair t, b ;
+ t := (ulcorner p -- urcorner p) intersection_point p ;
+ b := (llcorner p -- lrcorner p) intersection_point p ;
+ r := if xpart directionpoint t of p < 0 : reverse p else : p fi ; % r is needed, else problems when reverse is fed
+ q := r cutbefore if l: t else: b fi ;
+ q := q if xpart point 0 of r > 0 : & r fi cutafter if l: b else: t fi ;
+ q
+enddef ;
+
+vardef leftpath expr p = leftrightpath(p,true ) enddef ;
+vardef rightpath expr p = leftrightpath(p,false) enddef ;
+
+%D Drawoptions
+
+def saveoptions =
+ save _op_ ; def _op_ = enddef ;
+enddef ;
+
+%D Tracing. (not yet in lexer)
+
+let normaldraw = draw ;
+let normalfill = fill ;
+
+% bugged in mplib so ...
+
+def normalfill expr c = addto currentpicture contour c _op_ enddef ;
+def normaldraw expr p = addto currentpicture if picture p: also p else: doublepath p withpen currentpen fi _op_ enddef ;
+
+def drawlineoptions (text t) = def _lin_opt_ = t enddef ; enddef ;
+def drawpointoptions (text t) = def _pnt_opt_ = t enddef ; enddef ;
+def drawcontroloptions(text t) = def _ctr_opt_ = t enddef ; enddef ;
+def drawlabeloptions (text t) = def _lab_opt_ = t enddef ; enddef ;
+def draworiginoptions (text t) = def _ori_opt_ = t enddef ; enddef ;
+def drawboundoptions (text t) = def _bnd_opt_ = t enddef ; enddef ;
+def drawpathoptions (text t) = def _pth_opt_ = t enddef ; enddef ;
+
+numeric drawoptionsfactor ; drawoptionsfactor := pt ;
+
+def resetdrawoptions =
+ drawlineoptions (withpen pencircle scaled 1.0 drawoptionsfactor withcolor .5white) ;
+ drawpointoptions (withpen pencircle scaled 4.0 drawoptionsfactor withcolor black) ;
+ drawcontroloptions(withpen pencircle scaled 2.5 drawoptionsfactor withcolor black) ;
+ drawlabeloptions () ;
+ draworiginoptions (withpen pencircle scaled 1.0 drawoptionsfactor withcolor .5white) ;
+ drawboundoptions (dashed evenly _ori_opt_) ;
+ drawpathoptions (withpen pencircle scaled 5.0 drawoptionsfactor withcolor .8white) ;
+enddef ;
+
+resetdrawoptions ;
+
+%D Path.
+
+def drawpath expr p =
+ normaldraw p _pth_opt_
+enddef ;
+
+%D Arrow.
+
+vardef drawarrowpath expr p =
+ save autoarrows ; boolean autoarrows ; autoarrows := true ;
+ drawarrow p _pth_opt_
+enddef ;
+
+def midarrowhead expr p =
+ arrowhead p cutafter (point length(p cutafter point .5 along p)+ahlength on p)
+enddef ;
+
+vardef arrowheadonpath (expr p, s) =
+ save autoarrows ; boolean autoarrows ;
+ autoarrows := true ;
+ set_ahlength(scaled ahfactor) ; % added
+ arrowhead p if s<1 : cutafter (point (s*arclength(p)+.5ahlength) on p) fi
+enddef ;
+
+%D Points.
+
+def drawpoint expr c =
+ if string c :
+ string _c_ ;
+ _c_ := "(" & c & ")" ;
+ dotlabel.urt(_c_, scantokens _c_) ;
+ drawdot scantokens _c_
+ else :
+ dotlabel.urt("(" & decimal xpart c & "," & decimal ypart c & ")", c) ;
+ drawdot c
+ fi _pnt_opt_
+enddef ;
+
+%D PathPoints.
+
+def drawpoints expr c = path _c_ ; _c_ := c ; mfun_draw_points enddef ;
+def drawcontrolpoints expr c = path _c_ ; _c_ := c ; mfun_draw_controlpoints enddef ;
+def drawcontrollines expr c = path _c_ ; _c_ := c ; mfun_draw_controllines enddef ;
+def drawpointlabels expr c = path _c_ ; _c_ := c ; mfun_draw_pointlabels enddef ;
+
+def mfun_draw_points text t =
+ for _i_=0 upto length(_c_) :
+ normaldraw point _i_ of _c_ _pnt_opt_ t ;
+ endfor ;
+enddef;
+
+def mfun_draw_controlpoints text t =
+ for _i_=0 upto length(_c_) :
+ normaldraw precontrol _i_ of _c_ _ctr_opt_ t ;
+ normaldraw postcontrol _i_ of _c_ _ctr_opt_ t ;
+ endfor ;
+enddef;
+
+def mfun_draw_controllines text t =
+ for _i_=0 upto length(_c_) :
+ normaldraw point _i_ of _c_ -- precontrol _i_ of _c_ _lin_opt_ t ;
+ normaldraw point _i_ of _c_ -- postcontrol _i_ of _c_ _lin_opt_ t ;
+ endfor ;
+enddef;
+
+boolean swappointlabels ; swappointlabels := false ;
+numeric pointlabelscale ; pointlabelscale := 0 ;
+string pointlabelfont ; pointlabelfont := "" ;
+
+def mfun_draw_pointlabels text t =
+ for _i_=0 upto length(_c_) :
+ pair _u_ ; _u_ := unitvector(direction _i_ of _c_) rotated if swappointlabels : - fi 90 ;
+ pair _p_ ; _p_ := (point _i_ of _c_) ;
+ begingroup ;
+ if pointlabelscale > 0 :
+ save defaultscale ; numeric defaultscale ;
+ defaultscale := pointlabelscale ;
+ fi ;
+ if pointlabelfont <> "" :
+ save defaultfont ; string defaultfont ;
+ defaultfont := pointlabelfont ;
+ fi ;
+ _u_ := 10 * drawoptionsfactor * defaultscale * _u_ ;
+ normaldraw thelabel ( decimal _i_, _p_ shifted if cycle _c_ and (_i_=0) : - fi _u_ ) _lab_opt_ t ;
+ endgroup ;
+ endfor ;
+enddef;
+
+%D Bounding box.
+
+def drawboundingbox expr p =
+ normaldraw boundingbox p _bnd_opt_
+enddef ;
+
+%D Origin.
+
+numeric originlength ; originlength := .5cm ;
+
+def draworigin text t =
+ normaldraw (origin shifted (0, originlength) -- origin shifted (0,-originlength)) _ori_opt_ t ;
+ normaldraw (origin shifted ( originlength,0) -- origin shifted (-originlength,0)) _ori_opt_ t ;
+enddef;
+
+%D Axis.
+
+numeric tickstep ; tickstep := 5mm ;
+numeric ticklength ; ticklength := 2mm ;
+
+def drawxticks expr c = path _c_ ; _c_ := c ; mfun_draw_xticks enddef ;
+def drawyticks expr c = path _c_ ; _c_ := c ; mfun_draw_yticks enddef ;
+def drawticks expr c = path _c_ ; _c_ := c ; mfun_draw_ticks enddef ;
+
+% Adding eps prevents disappearance due to rounding errors.
+
+def mfun_draw_xticks text t =
+ for i=0 step -tickstep until xpart llcorner _c_ - eps :
+ if (i<=xpart lrcorner _c_) :
+ normaldraw (i,-ticklength)--(i,ticklength) _ori_opt_ t ;
+ fi ;
+ endfor ;
+ for i=0 step tickstep until xpart lrcorner _c_ + eps :
+ if (i>=xpart llcorner _c_) :
+ normaldraw (i,-ticklength)--(i,ticklength) _ori_opt_ t ;
+ fi ;
+ endfor ;
+ normaldraw (llcorner _c_ -- ulcorner _c_) shifted (-xpart llcorner _c_,0) _ori_opt_ t ;
+enddef ;
+
+def mfun_draw_yticks text t =
+ for i=0 step -tickstep until ypart llcorner _c_ - eps :
+ if (i<=ypart ulcorner _c_) :
+ normaldraw (-ticklength,i)--(ticklength,i) _ori_opt_ t ;
+ fi ;
+ endfor ;
+ for i=0 step tickstep until ypart ulcorner _c_ + eps :
+ if (i>=ypart llcorner _c_) :
+ normaldraw (-ticklength,i)--(ticklength,i) _ori_opt_ t ;
+ fi ;
+ endfor ;
+ normaldraw (llcorner _c_ -- lrcorner _c_) shifted (0,-ypart llcorner _c_) _ori_opt_ t ;
+enddef ;
+
+def mfun_draw_ticks text t =
+ drawxticks _c_ t ;
+ drawyticks _c_ t ;
+enddef ;
+
+%D All of it except axis.
+
+def drawwholepath expr p =
+ draworigin ;
+ drawpath p ;
+ drawcontrollines p ;
+ drawcontrolpoints p ;
+ drawpoints p ;
+ drawboundingbox p ;
+ drawpointlabels p ;
+enddef ;
+
+def drawpathonly expr p =
+ drawpath p ;
+ drawcontrollines p ;
+ drawcontrolpoints p ;
+ drawpoints p ;
+ drawpointlabels p ;
+enddef ;
+
+%D Tracing.
+
+def visualizeddraw expr c =
+ if picture c : normaldraw c else : path _c_ ; _c_ := c ; do_visualizeddraw fi
+enddef ;
+
+def visualizedfill expr c =
+ if picture c : normalfill c else : path _c_ ; _c_ := c ; do_visualizedfill fi
+enddef ;
+
+def do_visualizeddraw text t =
+ draworigin ;
+ drawpath _c_ t ;
+ drawcontrollines _c_ ;
+ drawcontrolpoints _c_ ;
+ drawpoints _c_ ;
+ drawboundingbox _c_ ;
+ drawpointlabels _c_ ;
+enddef ;
+
+def do_visualizedfill text t =
+ if cycle _c_ : normalfill _c_ t fi ;
+ draworigin ;
+ drawcontrollines _c_ ;
+ drawcontrolpoints _c_ ;
+ drawpoints _c_ ;
+ drawboundingbox _c_ ;
+ drawpointlabels _c_ ;
+enddef ;
+
+def detaileddraw expr c =
+ if picture c : normaldraw c else : path _c_ ; _c_ := c ; do_detaileddraw fi
+enddef ;
+
+def do_detaileddraw text t =
+ drawpath _c_ t ;
+ drawcontrollines _c_ ;
+ drawcontrolpoints _c_ ;
+ drawpoints _c_ ;
+ % % for labels we need an third run (as the second will mark the numbers); i could preroll them
+ % % but then the hash needs to handle that as well (as now we keep numbering)
+ % drawpointlabels _c_ ;
+enddef ;
+
+def visualizepaths =
+ let fill = visualizedfill ;
+ let draw = visualizeddraw ;
+enddef ;
+
+def detailpaths =
+ let draw = detaileddraw ;
+enddef ;
+
+def naturalizepaths =
+ let fill = normalfill ;
+ let draw = normaldraw ;
+enddef ;
+
+extra_endfig := extra_endfig & " naturalizepaths ; " ;
+
+%D Nice tracer:
+
+def drawboundary primary p =
+ draw p dashed evenly withcolor white ;
+ draw p dashed oddly withcolor black ;
+ draw (- llcorner p) withpen pencircle scaled 3 withcolor white ;
+ draw (- llcorner p) withpen pencircle scaled 1.5 withcolor black ;
+enddef ;
+
+%D Also handy:
+
+extra_beginfig := extra_beginfig & " truecorners := 0 ; " ; % restores
+extra_beginfig := extra_beginfig & " miterlimit := 10 ; " ; % restores
+extra_beginfig := extra_beginfig & " linejoin := rounded ; " ; % restores
+extra_beginfig := extra_beginfig & " linecap := rounded ; " ; % restores
+
+%D Normally, arrowheads don't scale well. So we provide a
+%D hack.
+
+boolean autoarrows ; autoarrows := false ;
+numeric ahfactor ; ahfactor := 2.5 ;
+
+def set_ahlength (text t) =
+ % ahlength := (ahfactor*pen_size(_op_ t)) ; % _op_ added
+ % problem: _op_ can contain color so a no-go, we could apply the transform
+ % but i need to figure out the best way (fakepicture and take components).
+ ahlength := (ahfactor*pen_size(t)) ;
+enddef ;
+
+vardef pen_size (text t) =
+ save p ; picture p ; p := nullpicture ;
+ addto p doublepath (top origin -- bot origin) t ;
+ (ypart urcorner p - ypart lrcorner p)
+enddef ;
+
+%D The next two macros are adapted versions of plain
+%D \METAPOST\ definitions.
+
+vardef arrowpath expr p = % patch by Peter Rolf: supports squared pen and shifting (hh: maybe just use center of head as first)
+ (p cutafter makepath(pencircle scaled 2(ahlength*cosd(.5ahangle)) shifted point length p of p))
+enddef;
+
+% def _finarr text t =
+% if autoarrows : set_ahlength (t) fi ;
+% draw arrowpath _apth t ; % arrowpath added
+% filldraw arrowhead _apth t ;
+% enddef;
+
+def _finarr text t =
+ if autoarrows : set_ahlength (t) fi ;
+ draw arrowpath _apth t ; % arrowpath added
+ fill arrowhead _apth t ;
+ draw arrowhead _apth t ;
+enddef;
+
+def _finarr text t =
+ if autoarrows : set_ahlength (t) fi ;
+ draw arrowpath _apth t ; % arrowpath added
+ fill arrowhead _apth t ;
+ draw arrowhead _apth t undashed ;
+enddef;
+
+%D Handy too ......
+
+vardef pointarrow (expr pat, loc, len, off) =
+ save l, r, s, t ; path l, r ; numeric s ; pair t ;
+ t := if pair loc : loc else : point loc along pat fi ;
+ s := len/2 - off ; if s<=0 : s := 0 elseif s>len : s := len fi ;
+ r := pat cutbefore t ;
+ r := (r cutafter point (arctime s of r) of r) ;
+ s := len/2 + off ; if s<=0 : s := 0 elseif s>len : s := len fi ;
+ l := reverse (pat cutafter t) ;
+ l := (reverse (l cutafter point (arctime s of l) of l)) ;
+ (l..r)
+enddef ;
+
+def rightarrow (expr pat,tim,len) = pointarrow(pat,tim,len,-len) enddef ;
+def leftarrow (expr pat,tim,len) = pointarrow(pat,tim,len,+len) enddef ;
+def centerarrow (expr pat,tim,len) = pointarrow(pat,tim,len, 0) enddef ;
+
+%D The \type {along} and \type {on} operators can be used
+%D as follows:
+%D
+%D \starttyping
+%D drawdot point .5 along somepath ;
+%D drawdot point 3cm on somepath ;
+%D \stoptyping
+%D
+%D The number denotes a percentage (fraction).
+
+primarydef pct along pat = % also negative
+ (arctime (pct * (arclength pat)) of pat) of pat
+enddef ;
+
+primarydef len on pat = % no outer ( ) .. somehow fails
+ (arctime if len>=0 : len else : (arclength(pat)+len) fi of pat) of pat
+enddef ;
+
+% this cuts of a piece from both ends
+
+tertiarydef pat cutends len =
+ begingroup
+ save tap ; path tap ;
+ tap := pat cutbefore (point (xpart paired(len)) on pat) ;
+ (tap cutafter (point -(ypart paired(len)) on tap))
+ endgroup
+enddef ;
+
+%D To be documented.
+
+path freesquare ;
+
+freesquare := (
+ (-1,0) -- (-1,-1) -- (0,-1) -- (+1,-1) --
+ (+1,0) -- (+1,+1) -- (0,+1) -- (-1,+1) -- cycle
+) scaled .5 ;
+
+numeric freelabeloffset ; freelabeloffset := 3pt ;
+numeric freedotlabelsize ; freedotlabelsize := 3pt ;
+
+vardef thefreelabel (expr str, loc, ori) =
+ save s, p, q, l ; picture s ; path p, q ; pair l ;
+ interim labeloffset := freelabeloffset ;
+ s := if string str : thelabel(str,loc) else : str shifted -center str shifted loc fi ;
+ setbounds s to boundingbox s enlarged freelabeloffset ;
+ p := fullcircle scaled (2*length(loc-ori)) shifted ori ;
+ q := freesquare xyscaled (urcorner s - llcorner s) ;
+ l := point xpart (p intersectiontimes (ori--loc shifted (loc-ori))) of q ;
+ setbounds s to boundingbox s enlarged -freelabeloffset ; % new
+ % draw boundingbox s shifted -l withpen pencircle scaled .5pt withcolor red ;
+ (s shifted -l)
+enddef ;
+
+vardef freelabel (expr str, loc, ori) =
+ draw thefreelabel(str,loc,ori) ;
+enddef ;
+
+vardef freedotlabel (expr str, loc, ori) =
+ interim linecap := rounded ;
+ draw loc withpen pencircle scaled freedotlabelsize ;
+ draw thefreelabel(str,loc,ori) ;
+enddef ;
+
+%D \starttyping
+%D drawarrow anglebetween(line_a,line_b,somelabel) ;
+%D \stoptyping
+
+newinternal angleoffset ; angleoffset := 0pt ;
+newinternal anglelength ; anglelength := 20pt ;
+newinternal anglemethod ; anglemethod := 1 ;
+
+vardef anglebetween (expr a, b, str) = % path path string
+ save pointa, pointb, common, middle, offset ;
+ pair pointa, pointb, common, middle, offset ;
+ save curve ; path curve ;
+ save where ; numeric where ;
+ if round point 0 of a = round point 0 of b :
+ common := point 0 of a ;
+ else :
+ common := a intersectionpoint b ;
+ fi ;
+ pointa := point anglelength on a ;
+ pointb := point anglelength on b ;
+ where := turningnumber (common--pointa--pointb--cycle) ;
+ middle := (reverse(common--pointa) rotatedaround (pointa,-where*90))
+ intersection_point
+ (reverse(common--pointb) rotatedaround (pointb, where*90)) ;
+ if not intersection_found :
+ middle := point .5 along
+ ((reverse(common--pointa) rotatedaround (pointa,-where*90)) --
+ ( (common--pointb) rotatedaround (pointb, where*90))) ;
+ fi ;
+ if anglemethod = 0 :
+ curve := pointa{unitvector(middle-pointa)}.. pointb;
+ middle := point .5 along curve ;
+ curve := common ;
+ elseif anglemethod = 1 :
+ curve := pointa{unitvector(middle-pointa)}.. pointb;
+ middle := point .5 along curve ;
+ elseif anglemethod = 2 :
+ middle := common rotatedaround(.5[pointa,pointb],180) ;
+ curve := pointa--middle--pointb ;
+ elseif anglemethod = 3 :
+ curve := pointa--middle--pointb ;
+ elseif anglemethod = 4 :
+ curve := pointa..controls middle..pointb ;
+ middle := point .5 along curve ;
+ fi ;
+ draw thefreelabel(str, middle, common) ; % withcolor black ;
+ curve
+enddef ;
+
+% Stack
+
+picture mfun_current_picture_stack[] ;
+numeric mfun_current_picture_depth ;
+
+mfun_current_picture_depth := 0 ;
+
+def pushcurrentpicture =
+ mfun_current_picture_depth := mfun_current_picture_depth + 1 ;
+ mfun_current_picture_stack[mfun_current_picture_depth] := currentpicture ;
+ currentpicture := nullpicture ;
+enddef ;
+
+def popcurrentpicture text t = % optional text
+ if mfun_current_picture_depth > 0 :
+ addto mfun_current_picture_stack[mfun_current_picture_depth] also currentpicture t ;
+ currentpicture := mfun_current_picture_stack[mfun_current_picture_depth] ;
+ mfun_current_picture_stack[mfun_current_picture_depth] := nullpicture ;
+ mfun_current_picture_depth := mfun_current_picture_depth - 1 ;
+ fi ;
+enddef ;
+
+%D colorcircle(size, red, green, blue) ;
+
+vardef colorcircle (expr size, red, green, blue) = % might move
+ save r, g, b, c, m, y, w ; save radius ;
+ path r, g, b, c, m, y, w ; numeric radius ;
+
+ radius := 5cm ; pickup pencircle scaled (radius/25) ;
+
+ transform t ; t := identity rotatedaround(origin,120) ;
+
+ r := fullcircle rotated 90 scaled radius shifted (0,radius/4) rotatedaround(origin,135) ;
+
+ b := r transformed t ; g := b transformed t ;
+
+ c := buildcycle(subpath(1,7) of g,subpath(1,7) of b) ;
+ y := c transformed t ; m := y transformed t ;
+
+ w := buildcycle(subpath(3,5) of r, subpath(3,5) of g,subpath(3,5) of b) ;
+
+ pushcurrentpicture ;
+
+ fill r withcolor red ;
+ fill g withcolor green ;
+ fill b withcolor blue ;
+ fill c withcolor white - red ;
+ fill m withcolor white - green ;
+ fill y withcolor white - blue ;
+ fill w withcolor white ;
+
+ for i = r,g,b,c,m,y : draw i withcolor .5white ; endfor ;
+
+ currentpicture := currentpicture xsized size ;
+
+ popcurrentpicture ;
+enddef ;
+
+% penpoint (i,2) of somepath -> inner / outer point
+
+vardef penpoint expr pnt of p =
+ save n, d ; numeric n, d ;
+ (n,d) = if pair pnt : pnt else : (pnt,1) fi ;
+ (point n of p shifted ((penoffset direction n of p of currentpen) scaled d))
+enddef ;
+
+% nice: currentpicture := inverted currentpicture ;
+
+primarydef p uncolored c =
+ if color p :
+ c - p
+ else :
+ image (
+ for i within p :
+ addto currentpicture
+ if stroked i or filled i :
+ if filled i :
+ contour
+ else :
+ doublepath
+ fi
+ pathpart i
+ dashed dashpart i withpen penpart i
+ else :
+ also i
+ fi
+ withcolor c-(redpart i, greenpart i, bluepart i) ;
+ endfor ;
+ )
+ fi
+enddef ;
+
+vardef inverted primary p =
+ p uncolored white
+enddef ;
+
+primarydef p softened c =
+ begingroup
+ save cc ; color cc ; cc := tripled(c) ;
+ if color p :
+ (redpart cc * redpart p,greenpart cc * greenpart p, bluepart cc * bluepart p)
+ else :
+ image (
+ for i within p :
+ addto currentpicture
+ if stroked i or filled i :
+ if filled i :
+ contour
+ else :
+ doublepath
+ fi
+ pathpart i
+ dashed dashpart i withpen penpart i
+ else :
+ also i
+ fi
+ withcolor (redpart cc * redpart i, greenpart cc * greenpart i, bluepart cc * bluepart i) ;
+ endfor ;
+ )
+ fi
+ endgroup
+enddef ;
+
+vardef grayed primary p =
+ if rgbcolor p :
+ tripled(.30redpart p+.59greenpart p+.11bluepart p)
+ elseif cmykcolor p :
+ tripled(.30*(1-cyanpart i)+.59*(1-magentapart i)+.11*(1-yellowpart i)+blackpart i)
+ elseif greycolor p :
+ p
+ elseif picture p :
+ image (
+ for i within p :
+ addto currentpicture
+ if stroked i or filled i :
+ if filled i :
+ contour
+ else :
+ doublepath
+ fi
+ pathpart i
+ dashed dashpart i
+ withpen penpart i
+ else :
+ also i
+ fi
+ if unknown colorpart i :
+ % nothing
+ elseif rgbcolor colorpart i :
+ withcolor tripled(.30redpart i+.59greenpart i+.11bluepart i) ;
+ elseif cmykcolor colorpart i :
+ withcolor tripled(.30*(1-cyanpart i)+.59*(1-magentapart i)+.11*(1-yellowpart i)+blackpart i) ;
+ else :
+ withcolor colorpart i ;
+ fi
+ endfor ;
+ )
+ else :
+ p
+ fi
+enddef ;
+
+let greyed = grayed ;
+
+% yes or no: "text" infont "cmr12" at 24pt ;
+
+% let normalinfont = infont ;
+%
+% numeric lastfontsize ; lastfontsize = fontsize defaultfont ;
+%
+% def infont primary name = % no vardef, no expr
+% hide(lastfontsize := fontsize name) % no ;
+% normalinfont name
+% enddef ;
+%
+% def scaledat expr size =
+% scaled (size/lastfontsize)
+% enddef ;
+%
+% let at = scaledat ;
+
+% like decimal
+
+def condition primary b = if b : "true" else : "false" fi enddef ;
+
+% undocumented
+
+primarydef p stretched s =
+ begingroup
+ save pp ; path pp ; pp := p xyscaled s ;
+ (pp shifted ((point 0 of p) - (point 0 of pp)))
+ endgroup
+enddef ;
+
+primarydef p enlonged len =
+ begingroup
+ if pair p :
+ save q ; path q ; q := origin -- p ;
+ save al ; al := arclength(q) ;
+ if al > 0 :
+ point 1 of (q stretched ((al+len)/al))
+ else :
+ p
+ fi
+ else :
+ save al ; al := arclength(p) ;
+ if al > 0 :
+ p stretched ((al+len)/al)
+ else :
+ p
+ fi
+ fi
+ endgroup
+enddef ;
+
+% path p ; p := (0,0) -- (10cm,5cm) ;
+% drawarrow p withcolor red ;
+% drawarrow p shortened 1cm withcolor green ;
+
+primarydef p shortened d =
+ reverse ( ( reverse (p enlonged -d) ) enlonged -d )
+enddef ;
+
+% yes or no, untested -)
+
+def xshifted expr dx = shifted(dx,0) enddef ;
+def yshifted expr dy = shifted(0,dy) enddef ;
+
+% also handy
+
+% right: str = readfrom ("abc" & ".def" ) ;
+% wrong: str = readfrom "abc" & ".def" ;
+
+% Every 62th read fails so we need to try again!
+
+% def readfile (expr name) =
+% if (readfrom (name) <> EOF) :
+% scantokens("input " & name & ";") ;
+% elseif (readfrom (name) <> EOF) :
+% scantokens("input " & name & ";") ;
+% fi ;
+% closefrom (name) ;
+% enddef ;
+%
+% this sometimes fails on the elseif, so :
+%
+
+def readfile (expr name) =
+ begingroup ; save ok ; boolean ok ;
+ if (readfrom (name) <> EOF) :
+ ok := false ;
+ elseif (readfrom (name) <> EOF) :
+ ok := false ;
+ else :
+ ok := true ;
+ fi ;
+ if not ok :
+ scantokens("input " & name & " ") ;
+ fi ;
+ closefrom (name) ;
+ endgroup ;
+enddef ;
+
+% permits redefinition of end in macro
+
+inner end ;
+
+% this will be redone (when needed) using scripts and backend handling
+
+let normalwithcolor = withcolor ;
+
+def remapcolors =
+ def withcolor primary c = normalwithcolor remappedcolor(c) enddef ;
+enddef ;
+
+def normalcolors =
+ let withcolor = normalwithcolor ;
+enddef ;
+
+def resetcolormap =
+ color color_map[][][] ;
+ normalcolors ;
+enddef ;
+
+resetcolormap ;
+
+def r_color primary c = redpart c enddef ;
+def g_color primary c = greenpart c enddef ;
+def b_color primary c = bluepart c enddef ;
+
+def remapcolor(expr old, new) =
+ color_map[redpart old][greenpart old][bluepart old] := new ;
+enddef ;
+
+def remappedcolor(expr c) =
+ if known color_map[redpart c][greenpart c][bluepart c] :
+ color_map[redpart c][greenpart c][bluepart c]
+ else :
+ c
+ fi
+enddef ;
+
+% Thanks to Jens-Uwe Morawski for pointing out that we need
+% to treat bounded and clipped components as local pictures.
+
+def recolor suffix p = p := repathed (0,p) enddef ;
+def refill suffix p = p := repathed (1,p) enddef ;
+def redraw suffix p = p := repathed (2,p) enddef ;
+def retext suffix p = p := repathed (3,p) enddef ;
+def untext suffix p = p := repathed (4,p) enddef ;
+
+% primarydef p recolored t = repathed(0,p) t enddef ;
+% primarydef p refilled t = repathed(1,p) t enddef ;
+% primarydef p redrawn t = repathed(2,p) t enddef ;
+% primarydef p retexted t = repathed(3,p) t enddef ;
+% primarydef p untexted t = repathed(4,p) t enddef ;
+
+color refillbackground ; refillbackground := (1,1,1) ;
+
+def restroke suffix p = p := repathed (21,p) enddef ; % keep attributes
+def reprocess suffix p = p := repathed (22,p) enddef ; % no attributes
+
+% also 11 and 12
+
+vardef repathed (expr mode, p) text t =
+ begingroup ;
+ if mode = 0 :
+ save withcolor ;
+ remapcolors ;
+ fi ;
+ save _p_, _pp_, _ppp_, _f_, _b_, _t_ ;
+ picture _p_, _pp_, _ppp_ ; color _f_ ; path _b_ ; transform _t_ ;
+ _b_ := boundingbox p ;
+ _p_ := nullpicture ;
+ for i within p :
+ _f_ := (redpart i, greenpart i, bluepart i) ;
+ if bounded i :
+ _pp_ := repathed(mode,i) t ;
+ setbounds _pp_ to pathpart i ;
+ addto _p_ also _pp_ ;
+ elseif clipped i :
+ _pp_ := repathed(mode,i) t ;
+ clip _pp_ to pathpart i ;
+ addto _p_ also _pp_ ;
+ elseif stroked i :
+ if mode=21 :
+ _ppp_ := i ; % indirectness is needed
+ addto _p_ also image(scantokens(t & " pathpart _ppp_")
+ dashed dashpart i withpen penpart i
+ withcolor _f_ ; ) ;
+ elseif mode=22 :
+ _ppp_ := i ; % indirectness is needed
+ addto _p_ also image(scantokens(t & " pathpart _ppp_")) ;
+ else :
+ addto _p_ doublepath pathpart i
+ dashed dashpart i withpen penpart i
+ withcolor _f_ % (redpart i, greenpart i, bluepart i)
+ if mode = 2 :
+ t
+ fi ;
+ fi ;
+ elseif filled i :
+ if mode=11 :
+ _ppp_ := i ; % indirectness is needed
+ addto _p_ also image(scantokens(t & " pathpart _ppp_")
+ withcolor _f_ ; ) ;
+ elseif mode=12 :
+ _ppp_ := i ; % indirectness is needed
+ addto _p_ also image(scantokens(t & " pathpart _ppp_")) ;
+ else :
+ addto _p_ contour pathpart i
+ withcolor _f_
+ if (mode=1) and (_f_<>refillbackground) :
+ t
+ fi ;
+ fi ;
+ elseif textual i : % textpart i <> "" :
+ if mode <> 4 :
+ % transform _t_ ;
+ % (xpart _t_, xxpart _t_, xypart _t_) = (xpart i, xxpart i, xypart i) ;
+ % (ypart _t_, yypart _t_, yxpart _t_) = (ypart i, yypart i, yxpart i) ;
+ % addto _p_ also
+ % textpart i infont fontpart i % todo : other font
+ % transformed _t_
+ % withpen penpart i
+ % withcolor _f_
+ % if mode=3 : t fi ;
+ addto _p_ also i
+ if mode=3 :
+ t
+ fi ;
+ fi ;
+ else :
+ addto _p_ also i ;
+ fi ;
+ endfor ;
+ setbounds _p_ to _b_ ;
+ _p_
+ endgroup
+enddef ;
+
+% After a question of Denis on how to erase a z variable, Jacko
+% suggested to assign whatever to x and y. So a clearz
+% variable can be defined as:
+%
+% vardef clearz@# =
+% x@# := whatever ;
+% y@# := whatever ;
+% enddef ;
+%
+% but Jacko suggested a redefinition of clearxy:
+%
+% def clearxy text s =
+% clearxy_index_:=0;
+% for $:=s:
+% clearxy_index_:=clearxy_index_+1; endfor;
+% if clearxy_index_=0:
+% save x,y;
+% else:
+% forsuffixes $:=s: x$:=whatever; y$:=whatever; endfor;
+% fi
+% enddef;
+%
+% which i decided to simplify to:
+
+def clearxy text s =
+ if false for $ := s : or true endfor :
+ forsuffixes $ := s : x$ := whatever ; y$ := whatever ; endfor ;
+ else :
+ save x, y ;
+ fi
+enddef ;
+
+% so now we can say: clearxy ; as well as clearxy 1, 2, 3 ;
+
+% show x0 ; z0 = (10,10) ;
+% show x0 ; x0 := whatever ; y0 := whatever ;
+% show x0 ; z0 = (20,20) ;
+% show x0 ; clearxy 0 ;
+% show x0 ; z0 = (30,30) ;
+
+primarydef p smoothed d =
+ (p llmoved (-xpart paired(d),0) -- p lrmoved (-xpart paired(d),0) {right} ..
+ p lrmoved (0,-ypart paired(d)) -- p urmoved (0,-ypart paired(d)) {up} ..
+ p urmoved (-xpart paired(d),0) -- p ulmoved (-xpart paired(d),0) {left} ..
+ p ulmoved (0,-ypart paired(d)) -- p llmoved (0,-ypart paired(d)) {down} .. cycle)
+enddef ;
+
+primarydef p cornered c =
+ ((point 0 of p) shifted (c*(unitvector(point 1 of p - point 0 of p))) --
+ for i=1 upto length(p) :
+ (point i-1 of p) shifted (c*(unitvector(point i of p - point i-1 of p))) --
+ (point i of p) shifted (c*(unitvector(point i-1 of p - point i of p))) ..
+ controls point i of p ..
+ endfor cycle)
+enddef ;
+
+% cmyk color support
+
+% vardef cmyk(expr c,m,y,k) = % elsewhere
+% (1-c-k,1-m-k,1-y-k)
+% enddef ;
+
+% handy
+
+% vardef bbwidth (expr p) = % vardef width_of primary p =
+% if known p :
+% if path p or picture p :
+% xpart (lrcorner p - llcorner p)
+% else :
+% 0
+% fi
+% else :
+% 0
+% fi
+% enddef ;
+
+vardef bbwidth primary p =
+ if unknown p :
+ 0
+ elseif path p or picture p :
+ xpart (lrcorner p - llcorner p)
+ else :
+ 0
+ fi
+enddef ;
+
+% vardef bbheight (expr p) = % vardef heigth_of primary p =
+% if known p :
+% if path p or picture p :
+% ypart (urcorner p - lrcorner p)
+% else :
+% 0
+% fi
+% else :
+% 0
+% fi
+% enddef ;
+
+vardef bbheight primary p =
+ if unknown p :
+ 0
+ elseif path p or picture p :
+ ypart (urcorner p - lrcorner p)
+ else :
+ 0
+ fi
+enddef ;
+
+color nocolor ; numeric noline ; % both unknown signals
+
+def dowithpath (expr p, lw, lc, bc) =
+ if known p :
+ if known bc :
+ fill p withcolor bc ;
+ fi ;
+ if known lw and known lc :
+ draw p withpen pencircle scaled lw withcolor lc ;
+ elseif known lw :
+ draw p withpen pencircle scaled lw ;
+ elseif known lc :
+ draw p withcolor lc ;
+ fi ;
+ fi ;
+enddef ;
+
+% result from metafont discussion list (denisr/boguslawj)
+
+def [[ = [ [ enddef ; def [[[ = [ [ [ enddef ;
+def ]] = ] ] enddef ; def ]]] = ] ] ] enddef ;
+
+let == = = ;
+
+% added
+
+picture oddly ; % evenly already defined
+
+evenly := dashpattern(on 3 off 3) ;
+oddly := dashpattern(off 3 on 3) ;
+
+% not perfect, but useful since it removes redundant points.
+
+vardef mfun_straightened(expr sign, p) =
+ save _p_, _q_ ; path _p_, _q_ ;
+ _p_ := p ;
+ forever :
+ _q_ := mfun_do_straightened(sign, _p_) ;
+ exitif length(_p_) = length(_q_) ;
+ _p_ := _q_ ;
+ endfor ;
+ _q_
+enddef ;
+
+vardef mfun_do_straightened(expr sign, p) =
+ if length(p)>2 : % was 1, but straight lines are ok
+ save pp ; path pp ;
+ pp := point 0 of p ;
+ for i=1 upto length(p)-1 :
+ if round(point i of p) <> round(point length(pp) of pp) :
+ pp := pp -- point i of p ;
+ fi ;
+ endfor ;
+ save n, ok ; numeric n ; boolean ok ;
+ n := length(pp) ; ok := false ;
+ if n>2 :
+ for i=0 upto n : % evt hier ook round
+ if unitvector(round(point i of pp - point if i=0 : n else : i-1 fi of pp)) <>
+ sign * unitvector(round(point if i=n : 0 else : i+1 fi of pp - point i of pp)) :
+ if ok :
+ --
+ else :
+ ok := true ;
+ fi point i of pp
+ fi
+ endfor
+ if ok and (cycle p) :
+ -- cycle
+ fi
+ else :
+ pp
+ fi
+ else :
+ p
+ fi
+enddef ;
+
+vardef simplified expr p = (
+ reverse mfun_straightened(+1,mfun_straightened(+1,reverse p))
+) enddef ;
+
+vardef unspiked expr p = (
+ reverse mfun_straightened(-1,mfun_straightened(-1,reverse p))
+) enddef ;
+
+% path p ;
+% p := (2cm,1cm) -- (2cm,1cm) -- (2cm,1cm) -- (3cm,1cm) --
+% (4cm,1cm) -- (4cm,2cm) -- (4cm,2.5cm) -- (4cm,3cm) --
+% (3cm,3cm) -- (2cm,3cm) -- (1cm,3cm) -- (-1cm,3cm) --
+% .5[(-1cm,3cm),(1cm,1cm)] -- (1cm,1cm) -- cycle ;
+%
+% p := unitcircle scaled 4cm ;
+%
+% drawpath p ; drawpoints p ; drawpointlabels p ;
+% p := p shifted (4cm,0) ; p := straightened p ;
+% drawpath p ; drawpoints p ; drawpointlabels p ;
+% p := p shifted (4cm,0) ; p := straightened p ;
+% drawpath p ; drawpoints p ; drawpointlabels p ;
+
+% new
+
+path originpath ; originpath := origin -- cycle ;
+
+vardef unitvector primary z =
+ if abs z = abs origin : z else : z/abs z fi
+enddef;
+
+% also new
+
+% vardef anchored@#(expr p, z) = % maybe use the textext variant
+% p shifted (z + (labxf@#*lrcorner p + labyf@#*ulcorner p + (1-labxf@#-labyf@#)*llcorner p))
+% enddef ;
+
+% epsed(1.2345)
+
+vardef epsed (expr e) =
+ e if e>0 : + eps elseif e<0 : - eps fi
+enddef ;
+
+% handy
+
+def withgray primary g =
+ withcolor g
+enddef ;
+
+% for metafun
+
+if unknown darkred : color darkred ; darkred := .625(1,0,0) fi ;
+if unknown darkgreen : color darkgreen ; darkgreen := .625(0,1,0) fi ;
+if unknown darkblue : color darkblue ; darkblue := .625(0,0,1) fi ;
+if unknown darkcyan : color darkcyan ; darkcyan := .625(0,1,1) fi ;
+if unknown darkmagenta : color darkmagenta ; darkmagenta := .625(1,0,1) fi ;
+if unknown darkyellow : color darkyellow ; darkyellow := .625(1,1,0) fi ;
+if unknown darkgray : color darkgray ; darkgray := .625(1,1,1) fi ;
+if unknown lightgray : color lightgray ; lightgray := .875(1,1,1) fi ;
+
+% an improved plain mp macro
+
+vardef center primary p =
+ if pair p :
+ p
+ else :
+ .5[llcorner p, urcorner p]
+ fi
+enddef;
+
+% new, yet undocumented
+
+vardef rangepath (expr p, d, a) =
+ if length p>0 :
+ (d*unitvector(direction 0 of p) rotated a) shifted point 0 of p
+ -- p --
+ (d*unitvector(direction length(p) of p) rotated a) shifted point length(p) of p
+ else :
+ p
+ fi
+enddef ;
+
+% under construction
+
+vardef straightpath (expr a, b, method) =
+ if (method<1) or (method>6) :
+ (a--b)
+ elseif method = 1 :
+ (a --
+ if xpart a > xpart b :
+ if ypart a > ypart b :
+ (xpart b,ypart a) --
+ elseif ypart a < ypart b :
+ (xpart a,ypart b) --
+ fi
+ elseif xpart a < xpart b :
+ if ypart a > ypart b :
+ (xpart a,ypart b) --
+ elseif ypart a < ypart b :
+ (xpart b,ypart a) --
+ fi
+ fi
+ b)
+ elseif method = 3 :
+ (a --
+ if xpart a > xpart b :
+ (xpart b,ypart a) --
+ elseif xpart a < xpart b :
+ (xpart a,ypart b) --
+ fi
+ b)
+ elseif method = 5 :
+ (a --
+ if ypart a > ypart b :
+ (xpart b,ypart a) --
+ elseif ypart a < ypart b :
+ (xpart a,ypart b) --
+ fi
+ b)
+ else :
+ (reverse straightpath(b,a,method-1))
+ fi
+enddef ;
+
+% handy for myself
+
+def addbackground text t =
+ begingroup ;
+ save p, b ; picture p ; path b ;
+ b := boundingbox currentpicture ;
+ p := currentpicture ; currentpicture := nullpicture ;
+ fill b t ;
+ setbounds currentpicture to b ;
+ addto currentpicture also p ;
+ endgroup ;
+enddef ;
+
+% makes a (line) into an infinite one (handy for calculating
+% intersection points
+
+vardef infinite expr p =
+ (-infinity*unitvector(direction 0 of p)
+ shifted point 0 of p
+ -- p --
+ +infinity*unitvector(direction length(p) of p)
+ shifted point length(p) of p)
+enddef ;
+
+% obscure macros: create var from string and replace - and :
+% (needed for process color id's) .. will go away
+
+string mfun_clean_ascii[] ;
+
+def register_dirty_chars(expr str) =
+ for i = 0 upto length(str)-1 :
+ mfun_clean_ascii[ASCII substring(i,i+1) of str] := "_" ;
+ endfor ;
+enddef ;
+
+register_dirty_chars("+-*/:;., ") ;
+
+vardef cleanstring (expr s) =
+ save ss ; string ss, si ; ss = "" ; save i ;
+ for i=0 upto length(s) :
+ si := substring(i,i+1) of s ;
+ ss := ss & if known mfun_clean_ascii[ASCII si] : mfun_clean_ascii[ASCII si] else : si fi ;
+ endfor ;
+ ss
+enddef ;
+
+vardef asciistring (expr s) =
+ save ss ; string ss, si ; ss = "" ; save i ;
+ for i=0 upto length(s) :
+ si := substring(i,i+1) of s ;
+ if (ASCII si >= ASCII "0") and (ASCII si <= ASCII "9") :
+ ss := ss & char(scantokens(si) + ASCII "A") ;
+ else :
+ ss := ss & si ;
+ fi ;
+ endfor ;
+ ss
+enddef ;
+
+vardef setunstringed (expr s, v) =
+ scantokens(cleanstring(s)) := v ;
+enddef ;
+
+vardef getunstringed (expr s) =
+ scantokens(cleanstring(s))
+enddef ;
+
+vardef unstringed (expr s) =
+ expandafter known scantokens(cleanstring(s))
+enddef ;
+
+% for david arnold:
+
+% showgrid(-5,10,1cm,-10,10,1cm);
+
+def showgrid (expr MinX, MaxX, DeltaX, MinY, MaxY, DeltaY) = % will move
+ begingroup
+ save size ; numeric size ; size := 2pt ;
+ for x=MinX upto MaxX :
+ for y=MinY upto MaxY :
+ draw (x*DeltaX, y*DeltaY) withpen pencircle scaled
+ if (x mod 5 = 0) and (y mod 5 = 0) :
+ 1.5size withcolor .50white
+ else :
+ size withcolor .75white
+ fi ;
+ endfor ;
+ endfor ;
+ for x=MinX upto MaxX:
+ label.bot(textext("\infofont " & decimal x), (x*DeltaX,-size)) ;
+ endfor ;
+ for y=MinY upto MaxY:
+ label.lft(textext("\infofont " & decimal y), (-size,y*DeltaY)) ;
+ endfor ;
+ endgroup
+enddef;
+
+% new, handy for:
+%
+% \startuseMPgraphic{map}{n}
+% \includeMPgraphic{map:germany} ;
+% c_phantom (\MPvar{n}<1) (
+% fill map_germany withcolor \MPcolor{lightgray} ;
+% draw map_germany withpen pencircle scaled 1pt withcolor \MPcolor{darkgray} ;
+% ) ;
+% \includeMPgraphic{map:austria} ;
+% c_phantom (\MPvar{n}<2) (
+% fill map_austria withcolor \MPcolor{lightgray} ;
+% draw map_austria withpen pencircle scaled 1pt withcolor \MPcolor{darkgray} ;
+% ) ;
+% c_phantom (\MPvar{n}<3) (
+% \includeMPgraphic{map:swiss} ;
+% fill map_swiss withcolor \MPcolor{lightgray} ;
+% draw map_swiss withpen pencircle scaled 1pt withcolor \MPcolor{darkgray} ;
+% ) ;
+% c_phantom (\MPvar{n}<4) (
+% \includeMPgraphic{map:luxembourg} ;
+% fill map_luxembourg withcolor \MPcolor{lightgray} ;
+% draw map_luxembourg withpen pencircle scaled 1pt withcolor \MPcolor{darkgray} ;
+% ) ;
+% \stopuseMPgraphic
+%
+% \useMPgraphic{map}{n=3}
+
+vardef phantom (text t) = % to be checked
+ picture _p_ ;
+ _p_ := image(t) ;
+ addto _p_ also currentpicture ;
+ setbounds currentpicture to boundingbox _p_ ;
+enddef ;
+
+vardef c_phantom (expr b) (text t) =
+ if b :
+ picture _p_ ;
+ _p_ := image(t) ;
+ addto _p_ also currentpicture ;
+ setbounds currentpicture to boundingbox _p_ ;
+ else :
+ t ;
+ fi ;
+enddef ;
+
+%D Handy:
+
+def break =
+ exitif true ; % fi
+enddef ;
+
+%D New too:
+
+primarydef p xstretched w = (
+ p if (bbwidth (p)>0) and (w>0) : xscaled (w/bbwidth (p)) fi
+) enddef ;
+
+primarydef p ystretched h = (
+ p if (bbheight(p)>0) and (h>0) : yscaled (h/bbheight(p)) fi
+) enddef ;
+
+%D Newer:
+
+vardef area expr p =
+ % we could calculate the boundingbox once
+ (xpart llcorner boundingbox p,0) -- p --
+ (xpart lrcorner boundingbox p,0) -- cycle
+enddef ;
+
+vardef basiccolors[] =
+ if @ = 0 :
+ white
+ else :
+ save n ; n := @ mod 7 ;
+ if n = 1 : red
+ elseif n = 2 : green
+ elseif n = 3 : blue
+ elseif n = 4 : cyan
+ elseif n = 5 : magenta
+ elseif n = 6 : yellow
+ else : black
+ fi
+ fi
+enddef ;
+
+
+% vardef somecolor = (1,1,0,0) enddef ;
+
+% fill OverlayBox withcolor (rcomponent somecolor,gcomponent somecolor,bcomponent somecolor) ;
+% fill OverlayBox withcolor (ccomponent somecolor,mcomponent somecolor,ycomponent somecolor,bcomponent somecolor) ;
+
+% This could be standard mplib 2 behaviour:
+
+vardef rcomponent expr p = if rgbcolor p : redpart p elseif cmykcolor p : 1 - cyanpart p else : p fi enddef ;
+vardef gcomponent expr p = if rgbcolor p : greenpart p elseif cmykcolor p : 1 - magentapart p else : p fi enddef ;
+vardef bcomponent expr p = if rgbcolor p : bluepart p elseif cmykcolor p : 1 - yellowpart p else : p fi enddef ;
+vardef ccomponent expr p = if cmykcolor p : cyanpart p elseif rgbcolor p : 1 - redpart p else : p fi enddef ;
+vardef mcomponent expr p = if cmykcolor p : magentapart p elseif rgbcolor p : 1 - greenpart p else : p fi enddef ;
+vardef ycomponent expr p = if cmykcolor p : yellowpart p elseif rgbcolor p : 1 - bluepart p else : p fi enddef ;
+vardef bcomponent expr p = if cmykcolor p : blackpart p elseif rgbcolor p : 0 else : p fi enddef ;
+
+% draw image (...) ... ; % prescripts prepended to first, postscripts appended to last
+% draw decorated (...) ... ; % prescripts prepended to each, postscripts appended to each
+% draw redecorated (...) ... ; % prescripts assigned to each, postscripts assigned to each
+% draw undecorated (...) ... ; % following properties are ignored, existing properties are kept
+%
+% draw decorated (
+% draw fullcircle scaled 20cm withpen pencircle scaled 20mm withcolor red withtransparency (1,.40) ;
+% draw fullcircle scaled 15cm withpen pencircle scaled 15mm withcolor green withtransparency (1,.30) ;
+% draw fullcircle scaled 10cm withpen pencircle scaled 10mm withcolor blue withtransparency (1,.20) ;
+% )
+% withcolor blue
+% withtransparency (1,.125) % selectively applied
+% withpen pencircle scaled 10mm
+% ;
+
+% vardef image (text imagedata) = % already defined
+% save currentpicture ;
+% picture currentpicture ;
+% currentpicture := nullpicture ;
+% imagedata ;
+% currentpicture
+% enddef ;
+
+vardef undecorated (text imagedata) text decoration =
+ save currentpicture ;
+ picture currentpicture ;
+ currentpicture := nullpicture ;
+ imagedata ;
+ currentpicture
+enddef ;
+
+if metapostversion < 1.770 :
+
+ vardef decorated (text imagedata) text decoration =
+ save mfun_decorated_path, currentpicture ;
+ picture mfun_decorated_path, currentpicture ;
+ currentpicture := nullpicture ;
+ imagedata ;
+ mfun_decorated_path := currentpicture ;
+ currentpicture := nullpicture ;
+ for i within mfun_decorated_path :
+ addto currentpicture
+ if stroked i :
+ doublepath pathpart i
+ dashed dashpart i
+ withpen penpart i
+ withcolor colorpart i
+ decoration
+ elseif filled i :
+ contour pathpart i
+ withpen penpart i
+ withcolor colorpart i
+ decoration
+ elseif textual i :
+ also i
+ withcolor colorpart i
+ decoration
+ else :
+ also i
+ fi
+ ;
+ endfor ;
+ currentpicture
+ enddef ;
+
+else:
+
+ vardef decorated (text imagedata) text decoration =
+ save mfun_decorated_path, currentpicture ;
+ picture mfun_decorated_path, currentpicture ;
+ currentpicture := nullpicture ;
+ imagedata ;
+ mfun_decorated_path := currentpicture ;
+ currentpicture := nullpicture ;
+ for i within mfun_decorated_path :
+ addto currentpicture
+ if stroked i :
+ doublepath pathpart i
+ dashed dashpart i
+ withpen penpart i
+ withcolor colorpart i
+ withprescript prescriptpart i
+ withpostscript postscriptpart i
+ decoration
+ elseif filled i :
+ contour pathpart i
+ withpen penpart i
+ withcolor colorpart i
+ withprescript prescriptpart i
+ withpostscript postscriptpart i
+ decoration
+ elseif textual i :
+ also i
+ withcolor colorpart i
+ withprescript prescriptpart i
+ withpostscript postscriptpart i
+ decoration
+ else :
+ also i
+ fi
+ ;
+ endfor ;
+ currentpicture
+ enddef ;
+
+fi ;
+
+vardef redecorated (text imagedata) text decoration =
+ save mfun_decorated_path, currentpicture ;
+ picture mfun_decorated_path, currentpicture ;
+ currentpicture := nullpicture ;
+ imagedata ;
+ mfun_decorated_path := currentpicture ;
+ currentpicture := nullpicture ;
+ for i within mfun_decorated_path :
+ addto currentpicture
+ if stroked i :
+ doublepath pathpart i
+ dashed dashpart i
+ withpen penpart i
+ decoration
+ elseif filled i :
+ contour pathpart i
+ withpen penpart i
+ decoration
+ elseif textual i :
+ also i
+ decoration
+ else :
+ also i
+ fi
+ ;
+ endfor ;
+ currentpicture
+enddef ;
+
+% path mfun_bleed_box ;
+
+% primarydef p bleeded d =
+% image (
+% mfun_bleed_box := boundingbox p ;
+% if pair d :
+% draw p xysized (bbwidth(p)+2*xpart d,bbheight(p)+2*ypart d) shifted -d ;
+% else :
+% draw p xysized (bbwidth(p)+2d,bbheight(p)+2d) shifted (-d,-d) ;
+% fi ;
+% setbounds currentpicture to mfun_bleed_box ;
+% )
+% enddef ;
+
+vardef mfun_snapped(expr p, s) =
+ if p < 0 : - ( - else : ( fi p div s) * s % the less tokens the better
+enddef ;
+
+vardef mfun_applied(expr p, s)(suffix a) =
+ if path p :
+ if pair s :
+ for i=0 upto length(p)-1 :
+ (a(xpart point i of p,xpart s),a(ypart point i of p,ypart s)) --
+ endfor
+ if cycle p :
+ cycle
+ else :
+ (a(xpart point length(p) of p,xpart s),a(ypart point length(p) of p,ypart s))
+ fi
+ else :
+ for i=0 upto length(p)-1 :
+ (a(xpart point i of p,s),a(ypart point i of p,s)) --
+ endfor
+ if cycle p :
+ cycle
+ else :
+ (a(xpart point length(p) of p,s),a(ypart point length(p) of p,s))
+ fi
+ fi
+ elseif pair p :
+ if pair s :
+ (a(xpart p,xpart s),a(ypart p,ypart s))
+ else :
+ (a(xpart p,s),a(ypart p,s))
+ fi
+ elseif cmykcolor p :
+ (a(cyanpart p,s),a(magentapart p,s),a(yellowpart p,s),a(blackpart p,s))
+ elseif rgbcolor p :
+ (a(redpart p,s),a(greenpart p,s),a(bluepart p,s))
+ elseif graycolor p :
+ a(p,s)
+ elseif numeric p :
+ a(p,s)
+ else
+ p
+ fi
+enddef ;
+
+primarydef p snapped s =
+ mfun_applied(p,s)(mfun_snapped) % so we can play with variants
+enddef ;
+
+%D New helpers:
+
+newinternal charscale ; charscale := 1 ; % persistent so one needs to 'reset' it to 0 or 1
+
+def beginglyph(expr unicode, width, height, depth) =
+ beginfig(unicode) ; % the number is irrelevant
+ charcode := unicode ;
+ charwd := width ;
+ charht := height ;
+ chardp := depth ;
+ % charscale := 1 ; % can be set for a whole font, so no reset here
+enddef ;
+
+def endglyph =
+ setbounds currentpicture to (boundingbox unitsquare xscaled charwd yscaled (charht + chardp) shifted (0,-chardp)) ;
+ if known charscale : if (charscale > 0) and (charscale <> 1) :
+ currentpicture := currentpicture scaled charscale ;
+ fi ; fi ;
+ endfig ;
+enddef ;
+
+%D Dimensions have never been an issue as traditional MP can't make that large
+%D pictures, but with double mode we need a catch:
+
+newinternal maxdimensions ; maxdimensions := 14000 ;
+
+def mfun_apply_max_dimensions = % not a generic helper, we want to protect this one
+ if bbwidth currentpicture > maxdimensions :
+ currentpicture := currentpicture if bbheight currentpicture > bbwidth currentpicture : ysized else : xsized fi maxdimensions ;
+ elseif bbheight currentpicture > maxdimensions :
+ currentpicture := currentpicture ysized maxdimensions ;
+ fi ;
+enddef;
+
+extra_endfig := extra_endfig & "mfun_apply_max_dimensions ;" ;
+
+let dump = relax ;