mp-mlib.mpxl /size: 60 Kb    last modification: 2023-12-21 09:43
1%D \module
2%D   [       file=mp-mlib.mpiv,
3%D        version=2008.03.21,
4%D          title=\CONTEXT\ \METAPOST\ graphics,
5%D       subtitle=plugins,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See licen-en.pdf for
12%C details.
13
14if known metafun_loaded_mlib : endinput ; fi ;
15
16newinternal boolean metafun_loaded_mlib ; metafun_loaded_mlib := true ; immutable metafun_loaded_mlib ;
17
18% numeric LUATEXFUNCTIONALITY ; LUATEXFUNCTIONALITY := runscript("mp.print(LUATEXFUNCTIONALITY or (status and status.development_id) or 6346)") ;
19
20%D Color and transparency
21%D
22%D Separable:
23
24newinternal normaltransparent     ; normaltransparent     :=  1 ;
25newinternal multiplytransparent   ; multiplytransparent   :=  2 ;
26newinternal screentransparent     ; screentransparent     :=  3 ;
27newinternal overlaytransparent    ; overlaytransparent    :=  4 ;
28newinternal softlighttransparent  ; softlighttransparent  :=  5 ;
29newinternal hardlighttransparent  ; hardlighttransparent  :=  6 ;
30newinternal colordodgetransparent ; colordodgetransparent :=  7 ;
31newinternal colorburntransparent  ; colorburntransparent  :=  8 ;
32newinternal darkentransparent     ; darkentransparent     :=  9 ;
33newinternal lightentransparent    ; lightentransparent    := 10 ;
34newinternal differencetransparent ; differencetransparent := 11 ;
35newinternal exclusiontransparent  ; exclusiontransparent  := 12 ;
36
37%D Nonseparable:
38
39newinternal huetransparent        ; huetransparent        := 13 ;
40newinternal saturationtransparent ; saturationtransparent := 14 ;
41newinternal colortransparent      ; colortransparent      := 15 ;
42newinternal luminositytransparent ; luminositytransparent := 16 ;
43
44permanent normaltransparent, multiplytransparent, screentransparent, overlaytransparent,
45    softlighttransparent, hardlighttransparent, colordodgetransparent, colorburntransparent,
46    darkentransparent, lightentransparent, differencetransparent, exclusiontransparent,
47    huetransparent, saturationtransparent, colortransparent, luminositytransparent ;
48
49vardef transparency_alternative_to_number(expr name) =
50    if string name :
51        if expandafter known scantokens(name & "transparent") :
52            scantokens(name & "transparent")
53        else :
54            0
55        fi
56    elseif name < 17 :
57        name
58    else :
59        0
60    fi
61enddef ;
62
63def namedcolor expr n =
64    (1)
65    withprescript "sp_type=named"
66    withprescript "sp_name=" & n
67enddef ;
68
69% def mfun_spotcolor(expr n, v) =
70%     1
71%     withprescript "sp_type=xspot"
72%     withprescript "sp_name="  & n
73%     withprescript "sp_value=" & (if numeric v : decimal v else : v fi)
74% enddef ;
75
76% def mfun_multispotcolor(expr name, fractions, components, value) =
77%     1
78%     withprescript "sp_type=multispot"
79%     withprescript "sp_name="       & name
80%     withprescript "sp_fractions="  & decimal fractions
81%     withprescript "sp_components=" & components
82%     withprescript "sp_value="      & value
83% enddef ;
84
85def spotcolor(expr name, v) =
86    (1)
87    withprescript "sp_type=spot"
88    withprescript "sp_name=" & name
89    withprescript "sp_value=" & colordecimals v
90enddef ;
91
92% In this case a mixed color will be calculated:
93
94def multitonecolor(expr name)(text t) =
95    (1)
96    withprescript "sp_type=multitone"
97    withprescript "sp_name=" & name
98    withprescript "sp_value=" & colordecimalslist(t)
99enddef ;
100
101def transparent(expr a, t)(text c) = % use withtransparency instead
102    (1) % this permits withcolor x intoshade y
103    withprescript "tr_alternative=" & decimal transparency_alternative_to_number(a)
104    withprescript "tr_transparency=" & decimal t
105    withcolor c
106enddef ;
107
108def withtransparency(expr a, t) =
109    withprescript "tr_alternative="  & decimal transparency_alternative_to_number(a)
110    withprescript "tr_transparency=" & decimal t
111enddef ;
112
113% for svg:
114
115def withopacity expr o =
116    if o <> 1 :
117        withprescript "tr_alternative="  & decimal normaltransparent
118        withprescript "tr_transparency=" & decimal o
119    fi
120enddef ;
121
122% Provided for downward compability:
123
124def cmyk(expr c, m, y, k) =
125    (c,m,y,k)
126enddef ;
127
128permanent spotcolor, multitonecolor, transparent, withtransparency, namedcolor, withopacity, cmyk ;
129
130% Texts (todo: better strut ratio, now .7 hardcoded, should be passed)
131
132newinternal textextoffset ; textextoffset := 0 ;
133
134permanent textextoffset ;
135
136rgbcolor mfun_tt_r ;
137numeric  mfun_tt_n ; mfun_tt_n := 0 ;
138picture  mfun_tt_p ; mfun_tt_p := nullpicture ;
139picture  mfun_tt_o ; mfun_tt_o := nullpicture ;
140picture  mfun_tt_c ; mfun_tt_c := nullpicture ;
141
142if unknown mfun_trial_run :
143    boolean mfun_trial_run ;
144    mfun_trial_run := false ;
145else :
146    % already defined before the format is loaded
147fi ;
148
149def mfun_reset_tex_texts =
150    mfun_tt_n := 0 ;
151    mfun_tt_p := nullpicture ;
152    mfun_tt_o := nullpicture ; % redundant
153    mfun_tt_c := nullpicture ; % redundant
154enddef ;
155
156def mfun_flush_tex_texts =
157    addto currentpicture also mfun_tt_p
158enddef ;
159
160extra_endfig   := "mfun_flush_tex_texts ;" & extra_endfig ;
161extra_beginfig := extra_beginfig & "mfun_reset_tex_texts ;" ;
162
163% We collect and flush them all, as we can also have temporary textexts
164% that gets never really flushed but are used for calculations. So, we
165% flush twice: once in location in order to pick up e.g. color properties,
166% and once at the end because we need to flush missing ones.
167
168boolean mfun_onetime_textext ; mfun_onetime_textext := false ;
169numeric mfun_global_textext ; mfun_global_textext := 0 ;
170
171def keepcached =
172    hide(mfun_global_textext := mfun_global_textext + 1;)
173    withprescript ("tx_cache=" & decimal mfun_global_textext)
174enddef ;
175
176def notcached =
177    withprescript "tx_cache=no"
178enddef ;
179
180permanent keepcached, notcached ;
181
182% todo: onetime
183
184rgbcolor mfun_tt_r ;
185
186newinternal inicatcoderegime ; inicatcoderegime := runscript("return catcodes.numbers.ctxcatcodes") ;
187newinternal texcatcoderegime ; texcatcoderegime := runscript("return catcodes.numbers.texcatcodes") ;
188newinternal luacatcoderegime ; luacatcoderegime := runscript("return catcodes.numbers.luacatcodes") ;
189newinternal notcatcoderegime ; notcatcoderegime := runscript("return catcodes.numbers.notcatcodes") ;
190newinternal vrbcatcoderegime ; vrbcatcoderegime := runscript("return catcodes.numbers.vrbcatcodes") ;
191newinternal prtcatcoderegime ; prtcatcoderegime := runscript("return catcodes.numbers.prtcatcodes") ;
192newinternal ctxcatcoderegime ; ctxcatcoderegime := runscript("return catcodes.numbers.ctxcatcodes") ;
193newinternal txtcatcoderegime ; txtcatcoderegime := runscript("return catcodes.numbers.txtcatcodes") ;
194
195newinternal catcoderegime    ; catcoderegime    := ctxcatcoderegime ;
196
197immutable inicatcoderegime, texcatcoderegime, luacatcoderegime, notcatcoderegime,
198    vrbcatcoderegime, prtcatcoderegime, ctxcatcoderegime, txtcatcoderegime ;
199
200permanent catcoderegime ;
201
202newscriptindex mfid_sometextext   ; mfid_sometextext   := scriptindex "sometextext" ;
203newscriptindex mfid_madetextext   ; mfid_madetextext   := scriptindex "madetextext" ;
204newscriptindex mfid_boxdimensions ; mfid_boxdimensions := scriptindex "boxdimensions" ;
205
206vardef rawtextext(expr s) =
207    if s = "" :
208        nullpicture
209    else :
210        mfun_tt_n := mfun_tt_n + 1 ;
211        mfun_tt_c := nullpicture ;
212        mfun_tt_o := nullpicture ;
213        addto mfun_tt_o doublepath origin base_draw_options ;
214        mfun_tt_r := runscript mfid_sometextext mfun_tt_n s catcoderegime ;
215        addto mfun_tt_c doublepath unitsquare
216            xscaled wdpart mfun_tt_r
217            yscaled (htpart mfun_tt_r + dppart mfun_tt_r)
218            shifted (0,-dppart mfun_tt_r)
219            withprescript "mf_object=text"
220            withprescript "tx_index=" & decimal mfun_tt_n
221            withprescript "tx_color=" & colordecimals colorpart mfun_tt_o
222        ;
223        mfun_tt_c
224    fi
225enddef ;
226
227vardef rawmadetext =
228    mfun_tt_n := mfun_tt_n + 1 ;
229    mfun_tt_c := nullpicture ;
230    mfun_tt_o := nullpicture ;
231    addto mfun_tt_o doublepath origin base_draw_options ;
232    mfun_tt_r := runscript mfid_madetextext mfun_tt_n ;
233    addto mfun_tt_c doublepath unitsquare
234        xscaled wdpart mfun_tt_r
235        yscaled (htpart mfun_tt_r + dppart mfun_tt_r)
236        shifted (0,-dppart mfun_tt_r)
237        withprescript "mf_object=text"
238        withprescript "tx_index=" & decimal mfun_tt_n
239        withprescript "tx_color=" & colordecimals colorpart mfun_tt_o
240    ;
241    mfun_tt_c
242enddef ;
243
244% \setbox\scratchbox\hbox{!!!!!!!!!!!!!}
245% \putboxincache{one}{a}\scratchbox
246% \startMPcode draw rawtexbox("one","a") ; \stopMPcode
247
248vardef validtexbox(expr category, name) =
249    if category == "" :
250        false
251    elseif string name :
252        name <> ""
253    elseif numeric name :
254        name > 0
255    else :
256        true
257    fi
258enddef ;
259
260vardef rawtexbox(expr category, name) =
261    mfun_tt_c := nullpicture ;
262    if validtexbox(category,name) :
263      % mfun_tt_r := lua.mp.mf_tb_dimensions(category, name) ;
264        mfun_tt_r := runscript mfid_boxdimensions category name ;
265        addto mfun_tt_c doublepath unitsquare
266            xscaled wdpart mfun_tt_r
267            yscaled (htpart mfun_tt_r + dppart mfun_tt_r)
268            shifted (0,- dppart mfun_tt_r)
269            withprescript "mf_object=box"
270            withprescript "bx_category=" & if numeric category : decimal fi category
271            withprescript "bx_name=" & if numeric name : decimal fi name ;
272    fi
273    mfun_tt_c
274enddef ;
275
276% More text
277
278defaultfont  := "Mono" ;
279defaultscale := 1 ;
280
281extra_beginfig := extra_beginfig & "defaultscale:=1;" ;
282
283vardef fontsize expr name =
284    save size ; numeric size ;
285    size := bbwidth(textext("\MPfontsizehskip{" & name & "}")) ;
286    if size = 0 :
287        12pt
288    else :
289        size
290    fi
291enddef ;
292
293permanent fontsize ;
294
295pair mfun_laboff        ; mfun_laboff        := origin   ;
296pair mfun_laboff.lft    ; mfun_laboff.lft    := (-1,0)   ;
297pair mfun_laboff.rt     ; mfun_laboff.rt     := (1,0)    ;
298pair mfun_laboff.bot    ; mfun_laboff.bot    := (0,-1)   ;
299pair mfun_laboff.top    ; mfun_laboff.top    := (0,1)    ;
300pair mfun_laboff.ulft   ; mfun_laboff.ulft   := (-.7,.7) ;
301pair mfun_laboff.urt    ; mfun_laboff.urt    := (.7,.7)  ;
302pair mfun_laboff.llft   ; mfun_laboff.llft   := -(.7,.7) ;
303pair mfun_laboff.lrt    ; mfun_laboff.lrt    := (.7,-.7) ;
304
305pair mfun_laboff.d      ; mfun_laboff.d      := mfun_laboff     ;
306pair mfun_laboff.dlft   ; mfun_laboff.dlft   := mfun_laboff.lft ;
307pair mfun_laboff.drt    ; mfun_laboff.drt    := mfun_laboff.rt  ;
308pair mfun_laboff.origin ; mfun_laboff.origin := mfun_laboff     ;
309pair mfun_laboff.raw    ; mfun_laboff.raw    := mfun_laboff     ;
310
311pair mfun_laboff.l      ; mfun_laboff.l      := mfun_laboff.lft  ;
312pair mfun_laboff.r      ; mfun_laboff.r      := mfun_laboff.rt   ;
313pair mfun_laboff.b      ; mfun_laboff.b      := mfun_laboff.bot  ;
314pair mfun_laboff.t      ; mfun_laboff.t      := mfun_laboff.top  ;
315pair mfun_laboff.l_t    ; mfun_laboff.l_t    := mfun_laboff.ulft ;
316pair mfun_laboff.r_t    ; mfun_laboff.r_t    := mfun_laboff.urt  ;
317pair mfun_laboff.l_b    ; mfun_laboff.l_b    := mfun_laboff.llft ;
318pair mfun_laboff.r_b    ; mfun_laboff.r_b    := mfun_laboff.lrt  ;
319pair mfun_laboff.t_l    ; mfun_laboff.t_l    := mfun_laboff.ulft ;
320pair mfun_laboff.t_r    ; mfun_laboff.t_r    := mfun_laboff.urt  ;
321pair mfun_laboff.b_l    ; mfun_laboff.b_l    := mfun_laboff.llft ;
322pair mfun_laboff.b_r    ; mfun_laboff.b_r    := mfun_laboff.lrt  ;
323
324mfun_labxf                                              := 0.5 ;
325mfun_labxf.lft      := mfun_labxf.l                     := 1   ;
326mfun_labxf.rt       := mfun_labxf.r                     := 0   ;
327mfun_labxf.bot      := mfun_labxf.b                     := 0.5 ;
328mfun_labxf.top      := mfun_labxf.t                     := 0.5 ;
329mfun_labxf.ulft     := mfun_labxf.l_t := mfun_labxf.t_l := 1   ;
330mfun_labxf.urt      := mfun_labxf.r_t := mfun_labxf.t_r := 0   ;
331mfun_labxf.llft     := mfun_labxf.l_b := mfun_labxf.b_l := 1   ;
332mfun_labxf.lrt      := mfun_labxf.r_b := mfun_labxf.b_r := 0   ;
333
334mfun_labxf.d        := mfun_labxf     ;
335mfun_labxf.dlft     := mfun_labxf.lft ;
336mfun_labxf.drt      := mfun_labxf.rt  ;
337mfun_labxf.origin   := 0              ;
338mfun_labxf.raw      := 0              ;
339
340mfun_labyf                                              := 0.5 ;
341mfun_labyf.lft      := mfun_labyf.l                     := 0.5 ;
342mfun_labyf.rt       := mfun_labyf.r                     := 0.5 ;
343mfun_labyf.bot      := mfun_labyf.b                     := 1   ;
344mfun_labyf.top      := mfun_labyf.t                     := 0   ;
345mfun_labyf.ulft     := mfun_labyf.l_t := mfun_labyf.t_l := 0   ;
346mfun_labyf.urt      := mfun_labyf.r_t := mfun_labyf.t_r := 0   ;
347mfun_labyf.llft     := mfun_labyf.l_b := mfun_labyf.b_l := 1   ;
348mfun_labyf.lrt      := mfun_labyf.r_b := mfun_labyf.b_r := 1   ;
349
350mfun_labyf.d        := mfun_labyf     ;
351mfun_labyf.dlft     := mfun_labyf.lft ;
352mfun_labyf.drt      := mfun_labyf.rt  ;
353mfun_labyf.origin   := 0              ;
354mfun_labyf.raw      := 0              ;
355
356mfun_labtype                                                 :=  0 ;
357mfun_labtype.lft    := mfun_labtype.l                        :=  1 ;
358mfun_labtype.rt     := mfun_labtype.r                        :=  2 ;
359mfun_labtype.bot    := mfun_labtype.b                        :=  3 ;
360mfun_labtype.top    := mfun_labtype.t                        :=  4 ;
361mfun_labtype.ulft   := mfun_labtype.l_t :=  mfun_labtype.t_l :=  5 ;
362mfun_labtype.urt    := mfun_labtype.r_t :=  mfun_labtype.t_r :=  6 ;
363mfun_labtype.llft   := mfun_labtype.l_b :=  mfun_labtype.b_l :=  7 ;
364mfun_labtype.lrt    := mfun_labtype.r_b :=  mfun_labtype.b_r :=  8 ;
365mfun_labtype.d                                               := 10 ;
366mfun_labtype.dlft                                            := 11 ;
367mfun_labtype.drt                                             := 12 ;
368mfun_labtype.origin                                          :=  0 ;
369mfun_labtype.raw                                             :=  0 ;
370
371vardef installlabel@# (expr type, x, y, offset) =
372    numeric mfun_labtype@# ; mfun_labtype@# := type ;
373    pair    mfun_laboff @# ; mfun_laboff @# := offset ;
374    numeric mfun_labxf  @# ; mfun_labxf  @# := x ;
375    numeric mfun_labyf  @# ; mfun_labyf  @# := y ;
376enddef ;
377
378permanent installlabel ;
379
380installlabel.center (0, 0.5, 0.5, (0,0)) ;
381installlabel.c      (0, 0.5, 0.5, (0,0)) ;
382
383installlabel.hcenter(0, 0.5, 0.5, (1,0)) ;
384installlabel.h      (0, 0.5, 0.5, (1,0)) ;
385
386installlabel.vcenter(0, 0.5, 0.5, (0,1)) ;
387installlabel.v      (0, 0.5, 0.5, (0,1)) ;
388
389vardef mfun_labshift@#(expr p) =
390    (mfun_labxf@#*lrcorner p +
391     mfun_labyf@#*ulcorner p +
392     (1-mfun_labxf@#-mfun_labyf@#)*llcorner p)
393enddef ;
394
395vardef mfun_picshift@#(expr p) =
396    (mfun_labxf@#*ulcorner p +
397     mfun_labyf@#*lrcorner p +
398     (1-mfun_labxf@#-mfun_labyf@#)*urcorner p)
399enddef ;
400
401% we save the plain variant
402
403% vardef plain_thelabel@#(expr p,z) =
404%     if string p :
405%         plain_thelabel@#(rawtextext("\definedfont[" & defaultfont & "]" & p) scaled defaultscale,z)
406%     else :
407%         p shifted (z + labeloffset*laboff@# - mfun_labshift@#(p))
408%     fi
409% enddef;
410%
411% def plain_label = % takes two arguments, contrary to textext that takes one
412%     normaldraw plain_thelabel
413% enddef ;
414%
415% let mfun_label    = label ;
416% let mfun_thelabel = thelabel ;
417%
418% def useplainlabels = % somehow let doesn't work for all code
419%     def label    = plain_label    enddef ;
420%     def thelabel = plain_thelabel enddef ;
421% enddef ;
422%
423% def usemetafunlabels =
424%     let label    = mfun_label ;
425%     let thelabel = mfun_thelabel ;
426% enddef ;
427%
428% plain_compatibility_data := plain_compatibility_data & "save label, thelabel ;" & "useplainlabels ;" ;
429
430newinternal anchortextexts ; anchortextexts := 0 ; % disabled by default
431
432vardef thetextext@#(expr p,z) =
433  % interim labeloffset := textextoffset ;
434    if string p :
435        thetextext@#(rawtextext(p),z)
436    elseif numeric p :
437        thetextext@#(rawtextext(decimal p),z)
438    elseif pair p :
439        thetextext@#(rawtextext(ddecimal p),z)
440    else :
441        if anchortextexts > 0 :
442            image(draw p withprescript "tx_anchor=" & ddecimal z)
443        else :
444            p
445        fi
446        if (mfun_labtype@# >= 10) :
447            shifted (0,ypart center p)
448        fi
449        shifted (z + textextoffset*mfun_laboff@# - mfun_labshift@#(p))
450    fi
451enddef ;
452
453vardef textext@#(expr p) = % no draw here
454    thetextext@#(p,origin)
455enddef ;
456
457vardef onetimetextext@#(expr p) = % no draw here
458    mfun_onetime_textext := true ;
459    thetextext@#(p,origin)
460enddef ;
461
462permanent rawtextext, rawmadetext, validtexbox, rawtexbox, thetextext, textext, onetimetextext ;
463
464% formatted text
465
466pair mfun_tt_z ;
467
468vardef rawfmttext(text t) =
469    mfun_tt_n := mfun_tt_n + 1 ;
470    mfun_tt_c := nullpicture ;
471    mfun_tt_o := nullpicture ;
472    addto mfun_tt_o doublepath origin base_draw_options ;
473    mfun_tt_r := lua.mp.mf_formatted_text(mfun_tt_n,t) ;
474    addto mfun_tt_c doublepath unitsquare
475        xscaled wdpart mfun_tt_r
476        yscaled (htpart mfun_tt_r + dppart mfun_tt_r)
477        shifted (0,-dppart mfun_tt_r)
478        withprescript "mf_object=text"
479        withprescript "tx_index=" & decimal mfun_tt_n
480        withprescript "tx_color=" & colordecimals colorpart mfun_tt_o
481    ;
482    for s = t :
483        if pair s : mfun_tt_z := s ; fi
484    endfor ;
485    mfun_tt_c
486enddef ;
487
488vardef thefmttext@#(text t) =
489    mfun_tt_z := origin ; % initialization
490    save p ; picture p ; p := rawfmttext(t) ;
491    if anchortextexts > 0 :
492        image(draw p withprescript "tx_anchor=" & ddecimal mfun_tt_z)
493    else :
494        p
495    fi
496        if (mfun_labtype@# >= 10) :
497            shifted (0,ypart center p)
498        fi
499        shifted (mfun_tt_z + textextoffset*mfun_laboff@# - mfun_labshift@#(p))
500enddef ;
501
502vardef fmttext@#(text t) = % no draw here
503    thefmttext@#(t,origin)
504enddef ;
505
506% or just: def fmttext = thefmttext enddef ;
507
508vardef onetimefmttext@#(text t) = % no draw here
509    mfun_onetime_textext := true ;
510    thefmttext@#(t,origin)
511enddef ;
512
513% so much for formatted text
514
515vardef thetexbox@#(expr category, name, z) =
516    save p ; picture p ; p := rawtexbox(category,name) ;
517    p
518        if (mfun_labtype@# >= 10) :
519            shifted (0,ypart center p)
520        fi
521        shifted (z + textextoffset*mfun_laboff@# - mfun_labshift@#(p))
522enddef ;
523
524vardef texbox@#(expr category, name) = % no draw here
525    thetexbox@#(category,name,origin)
526enddef ;
527
528permanent rawfmttext, thefmttext, fmttext, onetimefmttext, thetexbox, texbox ;
529
530% vardef thelabel@#(expr p,z) =
531%     if string p :
532%         thelabel@#(rawtextext("\definedfont[" & defaultfont & "]" & p) scaled defaultscale,z)
533%     else :
534%         p shifted (z + labeloffset*mfun_laboff@# - (mfun_labxf@#*lrcorner p + mfun_labyf@#*ulcorner p + (1-mfun_labxf@#-mfun_labyf@#)*llcorner p))
535%     fi
536% enddef;
537
538vardef theoffset@#(expr z) =
539    if pair z :
540        z
541    elseif path z :
542        if mfun_laboff@# = origin :
543            center z
544        else :
545            ((center z)-- mfun_picshift@#(z)) intersectionpoint (z if not cycle z: --cycle fi)
546        fi
547    else : % picture
548        mfun_picshift@#(z)
549    fi
550enddef;
551
552vardef thelabel@#(expr p,z) =
553    if string p :
554        thelabel@#(rawtextext("\definedfont[" & defaultfont & "]" & p) scaled defaultscale,z)
555    elseif numeric p :
556        thelabel@#(decimal p,z)
557    elseif pair p :
558        thelabel@#("(" & decimal(xpart p) & "," & decimal(ypart p) & ")",z)
559    else :
560        p shifted (theoffset@#(z) + labeloffset*mfun_laboff@# - mfun_labshift@#(p))
561    fi
562enddef;
563
564def label = % takes two arguments, contrary to textext that takes one
565    normaldraw thelabel
566enddef ;
567
568vardef anchored@#(expr p, z) = % beware: no "+ mfun_laboff@#" here (never!)
569    p
570        if (mfun_labtype@# >= 10) :
571            shifted (0,ypart center p)
572        fi
573        shifted (z + mfun_labshift@#(p))
574enddef ;
575
576let normalinfont = infont ;
577
578primarydef s infont name = % nasty hack
579    if name = "" :
580        textext(s)
581    else :
582        textext("\definedfont[" & name & "]" & s)
583    fi
584enddef ;
585
586permanent theoffset, thelabel, anchored ;
587primitive infont ; % fake primitive
588
589% Helper
590
591string mfun_prescript_separator ; mfun_prescript_separator := char(13) ;
592
593% Shades
594
595% for while we had this:
596
597newinternal shadefactor  ; shadefactor  := 1 ;      % currently obsolete
598pair        shadeoffset  ; shadeoffset  := origin ; % currently obsolete
599boolean     trace_shades ; trace_shades := false ;  % still there
600
601permanent shadefactor, shadeoffset ;
602
603% def withlinearshading (expr a, b) =
604%     withprescript "sh_type=linear"
605%     withprescript "sh_domain=0 1"
606%     withprescript "sh_factor="   & decimal shadefactor
607%     withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
608%     withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
609% enddef ;
610%
611% def withcircularshading (expr a, b, ra, rb) =
612%     withprescript "sh_type=circular"
613%     withprescript "sh_domain=0 1"
614%     withprescript "sh_factor="   & decimal shadefactor
615%     withprescript "sh_center_a=" & ddecimal (a shifted shadeoffset)
616%     withprescript "sh_center_b=" & ddecimal (b shifted shadeoffset)
617%     withprescript "sh_radius_a=" & decimal ra
618%     withprescript "sh_radius_b=" & decimal rb
619% enddef ;
620%
621% def withshading (expr how)(text rest) =
622%     if how = "linear" :
623%         withlinearshading(rest)
624%     elseif how = "circular" :
625%         withcircularshading(rest)
626%     else :
627%         % nothing
628%     fi
629% enddef ;
630%
631% def withfromshadecolor expr t =
632%     withprescript "sh_color=into"
633%     withprescript "sh_color_a=" & colordecimals t
634% enddef ;
635
636% def withtoshadecolor expr t =
637%     withprescript "sh_color=into"
638%     withprescript "sh_color_b=" & colordecimals t
639% enddef ;
640
641% but this is nicer
642
643% fill fullcircle scaled 10cm
644%     withshademethod "circular"
645%     withshadevector (5cm,1cm)
646%     withshadecenter (.1,.5)
647%     withshadedomain (.2,.6)
648%     withshadefactor 1.2
649%     withshadecolors (red,green)
650% ;
651
652path    mfun_shade_path ;
653numeric mfun_shade_step ; mfun_shade_step := 0 ;
654
655def withshadestep =
656    hide(mfun_shade_step := mfun_shade_step + 1 ;)
657    mfun_withshadestep
658enddef ;
659
660def mfun_withshadestep (text t) =
661    withprescript "sh_step=" & decimal mfun_shade_step
662    t
663enddef ;
664
665numeric mfun_shade_fx, mfun_shade_fy ;
666numeric mfun_shade_lx, mfun_shade_ly ;
667numeric mfun_shade_nx, mfun_shade_ny ;
668numeric mfun_shade_dx, mfun_shade_dy ;
669numeric mfun_shade_tx, mfun_shade_ty ;
670pair    mfun_shade_center ;
671path    mfun_shade_bbox ;
672
673numeric mfun_shade_height, mfun_shade_width;
674% first
675
676def mfun_with_shade_method_analyze(expr p) =
677    mfun_shade_path   := p ;
678    mfun_shade_center := center p;
679    mfun_shade_bbox   := boundingbox p;
680    mfun_shade_width  := bbwidth p;
681    mfun_shade_height := bbheight p;
682    mfun_shade_step   := 1 ;
683    mfun_shade_fx     := xpart point 0 of p ;
684    mfun_shade_fy     := ypart point 0 of p ;
685    mfun_shade_lx     := mfun_shade_fx ;
686    mfun_shade_ly     := mfun_shade_fy ;
687    mfun_shade_nx     := 0 ;
688    mfun_shade_ny     := 0 ;
689    mfun_shade_dx     := abs(mfun_shade_fx - mfun_shade_lx) ;
690    mfun_shade_dy     := abs(mfun_shade_fy - mfun_shade_ly) ;
691    for i=1 upto length(p) :
692        mfun_shade_tx := abs(mfun_shade_fx - xpart point i of p) ;
693        mfun_shade_ty := abs(mfun_shade_fy - ypart point i of p) ;
694        if mfun_shade_tx > mfun_shade_dx :
695            mfun_shade_nx := i + 1 ;
696            mfun_shade_lx := xpart point i of p ;
697            mfun_shade_dx := mfun_shade_tx ;
698        fi ;
699        if mfun_shade_ty > mfun_shade_dy :
700            mfun_shade_ny := i + 1 ;
701            mfun_shade_ly := ypart point i of p ;
702            mfun_shade_dy := mfun_shade_ty ;
703        fi ;
704    endfor ;
705enddef ;
706
707% todo: native bbox
708
709vardef mfun_shade_center_fraction_do expr a =
710    ddecimal (
711        (xpart llcorner mfun_shade_bbox) + (xpart a) * mfun_shade_width,
712        (ypart llcorner mfun_shade_bbox) + (ypart a) * mfun_shade_height
713    )
714enddef ;
715
716def withshadecenterfraction expr a =
717    withprescript "sh_center_a=" & mfun_shade_center_fraction_do a
718    withprescript "sh_center_b=" & mfun_shade_center_fraction_do a
719enddef ;
720
721def withshadecenteronefraction expr a =
722    withprescript "sh_center_a=" & mfun_shade_center_fraction_do a
723enddef ;
724
725def withshadecentertwofraction expr a =
726    withprescript "sh_center_b=" & mfun_shade_center_fraction_do a
727enddef ;
728
729def withshaderadiusfraction expr a =
730    withprescript "sh_radius_a=0"
731    withprescript "sh_radius_b=" & decimal (a * sqrt(mfun_shade_width*mfun_shade_width+mfun_shade_height*mfun_shade_height)/2)
732enddef ;
733
734vardef mfun_max_radius(expr p) =
735    max (
736        (xpart center   p - xpart llcorner p) ++ (ypart center   p - ypart llcorner p),
737        (xpart center   p - xpart ulcorner p) ++ (ypart ulcorner p - ypart center   p),
738        (xpart lrcorner p - xpart center   p) ++ (ypart center   p - ypart lrcorner p),
739        (xpart urcorner p - xpart center   p) ++ (ypart urcorner p - ypart center   p)
740    )
741enddef ;
742
743vardef mfun_min_radius(expr p) =
744    min (
745        (xpart center   p - xpart llcorner p) ++ (ypart center   p - ypart llcorner p),
746        (xpart center   p - xpart ulcorner p) ++ (ypart ulcorner p - ypart center   p),
747        (xpart lrcorner p - xpart center   p) ++ (ypart center   p - ypart lrcorner p),
748        (xpart urcorner p - xpart center   p) ++ (ypart urcorner p - ypart center   p)
749    )
750enddef ;
751
752primarydef p withshademethod m =
753    hide(mfun_with_shade_method_analyze(p))
754    p
755    withprescript "sh_domain=0 1"
756    withprescript "sh_transform=yes"
757    withprescript "sh_color=into"
758    withprescript "sh_color_a=" & colordecimals white
759    withprescript "sh_color_b=" & colordecimals black
760    withprescript "sh_first=" & ddecimal point 0 of p % used for support scaling
761    withprescript "sh_set_x=" & ddecimal (mfun_shade_nx,mfun_shade_lx) %
762    withprescript "sh_set_y=" & ddecimal (mfun_shade_ny,mfun_shade_ly) %
763    if m = "linear" :
764        withprescript "sh_type=linear"
765        withprescript "sh_factor=1"
766        withprescript "sh_center_a=" & ddecimal llcorner p
767        withprescript "sh_center_b=" & ddecimal urcorner p
768    else :
769        withprescript "sh_type=circular"
770        withprescript "sh_factor=1.2"
771        withprescript "sh_center_a=" & ddecimal center p
772        withprescript "sh_center_b=" & ddecimal center p
773        withprescript "sh_radius_a=" & decimal 0
774        withprescript "sh_radius_b=" & decimal mfun_max_radius(p)
775    fi
776enddef ;
777
778def withshaderadius expr a =
779    withprescript "sh_radius_a=" & decimal (xpart a)
780    withprescript "sh_radius_b=" & decimal (ypart a)
781enddef ;
782
783def withshadeorigin expr a =
784    withprescript "sh_center_a=" & ddecimal a
785    withprescript "sh_center_b=" & ddecimal a
786enddef ;
787
788def withshadecenterone expr a =
789    withprescript "sh_center_a=" & ddecimal a
790enddef ;
791
792def withshadecentertwo expr a =
793    withprescript "sh_center_b=" & ddecimal a
794enddef ;
795
796def withshadevector expr a =
797    withprescript "sh_center_a=" & ddecimal (point xpart a of mfun_shade_path)
798    withprescript "sh_center_b=" & ddecimal (point ypart a of mfun_shade_path)
799enddef ;
800
801def withshadedirection expr a =
802    withprescript "sh_center_a=" & ddecimal (point xpart a of boundingbox(mfun_shade_path))
803    withprescript "sh_center_b=" & ddecimal (point ypart a of boundingbox(mfun_shade_path))
804enddef ;
805
806def withshadetransform expr a = % yes | no
807    withprescript "sh_transform=" & a
808enddef ;
809
810pair shadedup    ; shadedup    := (0.5,2.5) ;
811pair shadeddown  ; shadeddown  := (2.5,0.5) ;
812pair shadedleft  ; shadedleft  := (1.5,3.5) ;
813pair shadedright ; shadedright := (3.5,1.5) ;
814
815def withshadecenter expr a =
816    withprescript "sh_center_a=" & ddecimal (
817        center mfun_shade_path shifted (
818            xpart a * bbwidth (mfun_shade_path)/2,
819            ypart a * bbheight(mfun_shade_path)/2
820        )
821    )
822enddef ;
823
824def withshadedomain expr d =
825    withprescript "sh_domain=" & ddecimal d
826enddef ;
827
828def withshadefactor expr f =
829    withprescript "sh_factor=" & decimal f
830enddef ;
831
832% def withshadebound (expr a) =
833%     if mfun_shade_step > 0 :
834%         withprescript "sh_bound_" & decimal mfun_shade_step & "=" & decimal a
835%     fi
836% enddef ;
837
838def withshadefraction expr a =
839    if mfun_shade_step > 0 :
840        withprescript "sh_fraction_" & decimal mfun_shade_step & "=" & decimal a
841    fi
842enddef ;
843
844% def withshadeopacity expr a =
845%     if mfun_shade_step > 0 :
846%         withprescript "sh_opacity_" & decimal mfun_shade_step & "=" & decimal a
847%     fi
848% enddef ;
849
850def withshadecolors (expr a, b) =
851    if mfun_shade_step > 0 :
852        withprescript "sh_color=into"
853        withprescript "sh_color_a_" & decimal mfun_shade_step & "=" & colordecimals a
854        withprescript "sh_color_b_" & decimal mfun_shade_step & "=" & colordecimals b
855    else :
856        withprescript "sh_color=into"
857        withprescript "sh_color_a=" & colordecimals a
858        withprescript "sh_color_b=" & colordecimals b
859    fi
860enddef ;
861
862primarydef a shadedinto b = % withcolor red shadedinto green
863    1 % does not work with transparency
864    withprescript "sh_color=into"
865    withprescript "sh_color_a=" & colordecimals a
866    withprescript "sh_color_b=" & colordecimals b
867enddef ;
868
869primarydef p withshade sc =
870    p withprescript mfun_defined_cs_pre[sc]
871enddef ;
872
873def defineshade suffix s =
874    mfun_defineshade(str s)
875enddef ;
876
877def mfun_defineshade (expr s) text t =
878    expandafter def scantokens s = t enddef ;
879enddef ;
880
881def shaded text s =
882    s
883enddef ;
884
885
886% For me.
887
888primarydef p shownshadevector v =
889    image (
890        drawarrow (point xpart v of p) -- (point ypart v of p) ;
891        fill fullcircle scaled 2 shifted point xpart v of p ;
892        setbounds currentpicture to center currentpicture -- cycle ;
893    )
894enddef ;
895
896primarydef p shownshadedirection v =
897    image (
898        drawarrow (point xpart v of boundingbox p) -- (point ypart v of boundingbox p) ;
899        fill fullcircle scaled 2 shifted (point xpart v of boundingbox p) ;
900        setbounds currentpicture to center currentpicture -- cycle ;
901    )
902enddef ;
903
904primarydef p shownshadecenter v =
905    image (
906        fill fullcircle scaled 2
907            shifted center p shifted (
908            xpart v * bbwidth (p)/2,
909            ypart v * bbheight(p)/2
910        ) ;
911        setbounds currentpicture to center currentpicture -- cycle ;
912    )
913enddef ;
914
915primarydef p shownshadeorigin v =
916    image (
917        fill fullcircle scaled 2 shifted v ;
918        setbounds currentpicture to center currentpicture -- cycle ;
919    )
920enddef ;
921
922permanent withshademethod, withshaderadius, withshadeorigin, withshadevector, withshadedirection,
923    withshadetransform, withshadedomain, withshadefactor, withshadecenter, withshadefraction, withshadestep,
924    withshadecolors, shadedinto, withshade, shaded, shadedup, shadeddown, shadedleft, shadedright,
925    shownshadevector, shownshadedirection, shownshadecenter, shownshadeorigin ;
926
927% Old macros:
928
929def withcircularshade (expr a, b, ra, rb, ca, cb) =
930    withprescript "sh_type=circular"
931    withprescript "sh_transform=yes"
932    withprescript "sh_domain=0 1"
933    withprescript "sh_factor=1"
934    withprescript "sh_color_a="  & colordecimals ca
935    withprescript "sh_color_b="  & colordecimals cb
936    withprescript "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
937    withprescript "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
938    withprescript "sh_radius_a=" & decimal ra
939    withprescript "sh_radius_b=" & decimal rb
940enddef ;
941
942def withlinearshade (expr a, b, ca, cb) =
943    withprescript "sh_type=linear"
944    withprescript "sh_transform=yes"
945    withprescript "sh_domain=0 1"
946    withprescript "sh_factor=1"
947    withprescript "sh_color_a="  & colordecimals ca
948    withprescript "sh_color_b="  & colordecimals cb
949    withprescript "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
950    withprescript "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
951enddef ;
952
953permanent withcircularshade, withlinearshade ;
954
955% replaced (obsolete):
956
957def set_linear_vector (suffix a,b)(expr p,n) =
958    if     (n=1) : a := llcorner p ; b := urcorner p ;
959    elseif (n=2) : a := lrcorner p ; b := ulcorner p ;
960    elseif (n=3) : a := urcorner p ; b := llcorner p ;
961    elseif (n=4) : a := ulcorner p ; b := lrcorner p ;
962    elseif (n=5) : a := .5[ulcorner p,llcorner p] ; b := .5[urcorner p,lrcorner p] ;
963    elseif (n=6) : a := .5[llcorner p,lrcorner p] ; b := .5[ulcorner p,urcorner p] ;
964    elseif (n=7) : a := .5[lrcorner p,urcorner p] ; b := .5[llcorner p,ulcorner p] ;
965    elseif (n=8) : a := .5[urcorner p,ulcorner p] ; b := .5[lrcorner p,llcorner p] ;
966    else         : a := .5[ulcorner p,llcorner p] ; b := .5[urcorner p,lrcorner p] ;
967    fi ;
968enddef ;
969
970def set_circular_vector (suffix ab,r)(expr p,n) =
971    if     (n=1) : ab := llcorner p ;
972    elseif (n=2) : ab := lrcorner p ;
973    elseif (n=3) : ab := urcorner p ;
974    elseif (n=4) : ab := ulcorner p ;
975    else         : ab := center   p ; r := .5r ;
976    fi ;
977enddef ;
978
979def circular_shade (expr p, n, ca, cb) =
980    begingroup ;
981        save ab, r ; pair ab ; numeric r ;
982        r := (xpart lrcorner p - xpart llcorner p) ++ (ypart urcorner p - ypart lrcorner p) ;
983        set_circular_vector(ab,r)(p,n) ;
984        fill p withcircularshade(ab,ab,0,r,ca,cb) ;
985        if trace_shades :
986            drawarrow ab -- ab shifted (0,r) withpen pencircle scaled 1pt withcolor .5white ;
987        fi ;
988    endgroup ;
989enddef ;
990
991def linear_shade (expr p, n, ca, cb) =
992    begingroup ;
993        save a, b ; pair a, b ;
994        set_linear_vector(a,b)(p,n) ;
995        fill p withlinearshade(a,b,ca,cb) ;
996        if trace_shades :
997            drawarrow a -- b withpen pencircle scaled 1pt withcolor .5white ;
998        fi ;
999    endgroup ;
1000enddef ;
1001
1002string mfun_defined_cs_pre[] ; numeric mfun_defined_cs ; mfun_defined_cs := 0 ;
1003
1004vardef define_circular_shade (expr a, b, ra, rb, ca, cb) =
1005    mfun_defined_cs := mfun_defined_cs + 1 ;
1006    mfun_defined_cs_pre[mfun_defined_cs] := "sh_type=circular"
1007    & mfun_prescript_separator & "sh_domain=0 1"
1008    & mfun_prescript_separator & "sh_factor=1"
1009    & mfun_prescript_separator & "sh_color_a="  & colordecimals ca
1010    & mfun_prescript_separator & "sh_color_b="  & colordecimals cb
1011    & mfun_prescript_separator & "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
1012    & mfun_prescript_separator & "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
1013    & mfun_prescript_separator & "sh_radius_a=" & decimal ra
1014    & mfun_prescript_separator & "sh_radius_b=" & decimal rb
1015    ;
1016    mfun_defined_cs
1017enddef ;
1018
1019vardef define_linear_shade (expr a, b, ca, cb) =
1020    mfun_defined_cs := mfun_defined_cs + 1 ;
1021    mfun_defined_cs_pre[mfun_defined_cs] := "sh_type=linear"
1022    & mfun_prescript_separator & "sh_domain=0 1"
1023    & mfun_prescript_separator & "sh_factor=1"
1024    & mfun_prescript_separator & "sh_color_a=" & colordecimals ca
1025    & mfun_prescript_separator & "sh_color_b=" & colordecimals cb
1026    & mfun_prescript_separator & "sh_center_a=" & ddecimal a % (a shifted shadeoffset)
1027    & mfun_prescript_separator & "sh_center_b=" & ddecimal b % (b shifted shadeoffset)
1028    ;
1029    mfun_defined_cs
1030enddef ;
1031
1032% I lost the example code that uses this:
1033%
1034% vardef define_sampled_linear_shade(expr a,b,n)(text t) =
1035%     mfun_defined_cs := mfun_defined_cs + 1 ;
1036%     mfun_defined_cs_pre[mfun_defined_cs] := "ssh_type=linear"
1037%     & mfun_prescript_separator & "ssh_center_a=" & ddecimal (a shifted shadeoffset)
1038%     & mfun_prescript_separator & "ssh_center_b=" & ddecimal (b shifted shadeoffset)
1039%     & mfun_prescript_separator & "ssh_nofcolors=" & decimal n
1040%     & mfun_prescript_separator & "ssh_domain=" & domstr
1041%     & mfun_prescript_separator & "ssh_extend=" & extstr
1042%     & mfun_prescript_separator & "ssh_colors=" & colstr
1043%     & mfun_prescript_separator & "ssh_bounds=" & bndstr
1044%     & mfun_prescript_separator & "ssh_ranges=" & ranstr
1045%     ;
1046%     mfun_defined_cs
1047% enddef ;
1048%
1049% vardef define_sampled_circular_shade(expr a,b,ra,rb,n)(text t) =
1050%     mfun_defined_cs := mfun_defined_cs + 1 ;
1051%     mfun_defined_cs_pre[mfun_defined_cs] := "ssh_type=circular"
1052%     & mfun_prescript_separator & "ssh_center_a=" & ddecimal (a shifted shadeoffset)
1053%     & mfun_prescript_separator & "ssh_radius_a=" & decimal ra
1054%     & mfun_prescript_separator & "ssh_center_b=" & ddecimal (b shifted shadeoffset)
1055%     & mfun_prescript_separator & "ssh_radius_b=" & decimal rb
1056%     & mfun_prescript_separator & "ssh_nofcolors=" & decimal n
1057%     & mfun_prescript_separator & "ssh_domain=" & domstr
1058%     & mfun_prescript_separator & "ssh_extend=" & extstr
1059%     & mfun_prescript_separator & "ssh_colors=" & colstr
1060%     & mfun_prescript_separator & "ssh_bounds=" & bndstr
1061%     & mfun_prescript_separator & "ssh_ranges=" & ranstr
1062%     ;
1063%     mfun_defined_cs
1064% enddef ;
1065
1066% vardef predefined_linear_shade (expr p, n, ca, cb) =
1067%     save a, b, sh ; pair a, b ;
1068%     set_linear_vector(a,b)(p,n) ;
1069%     define_linear_shade (a,b,ca,cb)
1070% enddef ;
1071%
1072% vardef predefined_circular_shade (expr p, n, ca, cb) =
1073%     save ab, r ; pair ab ; numeric r ;
1074%     r := (xpart lrcorner p - xpart llcorner p) ++ (ypart urcorner p - ypart lrcorner p) ;
1075%     set_circular_vector(ab,r)(p,n) ;
1076%     define_circular_shade(ab,ab,0,r,ca,cb)
1077% enddef ;
1078
1079% Layers
1080
1081def onlayer primary name =
1082    withprescript "la_name=" & name
1083enddef ;
1084
1085permanent onlayer ;
1086
1087% Figures
1088
1089% def externalfigure primary filename =
1090%     doexternalfigure (filename)
1091% enddef ;
1092%
1093% def doexternalfigure (expr filename) text transformation =
1094%     if true : % a bit incompatible esp scaled 1cm now scaled the natural size
1095%         draw rawtextext("\externalfigure[" & filename & "]") transformation ;
1096%     else :
1097%         draw unitsquare transformation withprescript "fg_name=" & filename ;
1098%     fi ;
1099% enddef ;
1100
1101def withmask primary filename =
1102    withprescript "fg_mask=" & filename
1103enddef ;
1104
1105vardef externalfigure primary filename =
1106    mfun_tt_c := nullpicture ;
1107    mfun_tt_r := lua.mp.mf_external_figure(filename) ;
1108    addto mfun_tt_c doublepath unitsquare
1109        xscaled wdpart mfun_tt_r
1110        yscaled htpart mfun_tt_r
1111        withprescript "mf_object=figure"
1112        withprescript "fg_name=" & filename ;
1113    ;
1114    mfun_tt_c
1115enddef ;
1116
1117def figure primary filename =
1118    rawtextext("\externalfigure[" & filename & "]")
1119enddef ;
1120
1121vardef svgembeddedfigure primary index =
1122%     mfun_onetime_textext := true ;
1123    rawtextext("\svgembeddedfigure{" & decimal index & "}")
1124enddef ;
1125
1126permanent withmask, externalfigure, figure ;
1127
1128% Positions
1129
1130def register (expr tag, width, height, offset) =
1131%     draw image (
1132        addto currentpicture doublepath unitsquare xscaled width yscaled height shifted offset
1133            withprescript "ps_label=" & tag ;
1134%     ) ; % no transformations
1135enddef ;
1136
1137permanent register ;
1138
1139% outlines (todo: pass around less arguments)
1140
1141numeric currentoutlinetext ; currentoutlinetext := 0 ;
1142
1143vardef mfun_do_outline_text_flush (expr kind, n, x, y, c) (text t) =
1144    if kind = "f" :
1145        mfun_do_outline_text_f (n, x, y, c) (t)
1146    elseif kind = "d" :
1147        mfun_do_outline_text_d (n, x, y, c) (t)
1148    elseif kind = "b" :
1149        mfun_do_outline_text_b (n, x, y, c) (t)
1150    elseif kind = "r" :
1151        mfun_do_outline_text_r (n, x, y, c) (t)
1152    elseif kind = "p" :
1153        mfun_do_outline_text_p (n, x, y, c) (t)
1154    elseif kind = "u" :
1155        mfun_do_outline_text_u (n, x, y, c) (t)
1156    else :
1157        mfun_do_outline_text_n (n, x, y, c) (t)
1158    fi ;
1159enddef ;
1160
1161vardef mfun_do_outline_rule_flush (expr kind, x, y, w, h) =
1162  % mfun_do_outline_text_flush (kind, 1, x, y, "") (fullsquare xyscaled(w,h))
1163    mfun_do_outline_text_flush (kind, 1, x, y, "") (unitsquare xyscaled(w,h))
1164enddef ;
1165
1166numeric mfun_do_outline_n ; mfun_do_outline_n := 0 ;
1167
1168vardef mfun_do_outline_text_f (expr n, x, y, c) (text t) =
1169    mfun_do_outline_n := 0 ;
1170    for i=t :
1171        mfun_do_outline_n := mfun_do_outline_n + 1 ;
1172        if mfun_do_outline_n = n : fill else : nofill fi (i shifted(x,y)) mfun_do_outline_options_f withpen pencircle scaled 0 withprescript c ;
1173    endfor ;
1174enddef ;
1175
1176vardef mfun_do_outline_text_u (expr n, x, y, c) (text t) =
1177    mfun_do_outline_n := 0 ;
1178    for i=t :
1179        mfun_do_outline_n := mfun_do_outline_n + 1 ;
1180        if mfun_do_outline_n = n : fillup else : nofill fi (i shifted(x,y)) mfun_do_outline_options_f withprescript c ;
1181    endfor ;
1182enddef ;
1183
1184vardef mfun_do_outline_text_d (expr n, x, y, c) (text t) =
1185    for i=t :
1186        draw i shifted(x,y) mfun_do_outline_options_d ;
1187    endfor ;
1188enddef ;
1189
1190vardef mfun_do_outline_text_p (expr n, x, y, c) (text t) =
1191    for i=t :
1192        draw i shifted(x,y) withprescript c ;
1193    endfor ;
1194enddef ;
1195
1196vardef mfun_do_outline_text_b (expr n, x, y, c) (text t) =
1197    mfun_do_outline_n := 0 ;
1198    for i=t :
1199        mfun_do_outline_n := mfun_do_outline_n + 1 ;
1200        if mfun_do_outline_n = n : fill else : nofill fi (i shifted(x,y)) mfun_do_outline_options_f ;
1201    endfor ;
1202    for i=t :
1203        draw i shifted(x,y) mfun_do_outline_options_d ;
1204    endfor ;
1205enddef ;
1206
1207vardef mfun_do_outline_text_r (expr n, x, y, c) (text t) =
1208    mfun_do_outline_n := 0 ;
1209    for i=t :
1210        draw i shifted(x,y) mfun_do_outline_options_d ;
1211    endfor ;
1212    for i=t :
1213        mfun_do_outline_n := mfun_do_outline_n + 1 ;
1214        if mfun_do_outline_n = n : fill else : nofill fi (i shifted(x,y)) mfun_do_outline_options_f;
1215    endfor ;
1216enddef ;
1217
1218vardef mfun_do_outline_text_n (expr n, x, y, c) (text t) =
1219    mfun_do_outline_n := 0 ;
1220    for i=t :
1221        mfun_do_outline_n := mfun_do_outline_n + 1 ;
1222        if mfun_do_outline_n = n : fill else : nofill fi (i shifted(x,y)) ;
1223    endfor ;
1224enddef ;
1225
1226vardef mfun_do_outline_text_set_f (text f) text r =
1227    def mfun_do_outline_options_f = f enddef ;
1228    def mfun_do_outline_options_r = r enddef ;
1229enddef ;
1230
1231vardef mfun_do_outline_text_set_u (text f) text r =
1232    def mfun_do_outline_options_f = f enddef ;
1233enddef ;
1234
1235vardef mfun_do_outline_text_set_d (text d) text r =
1236    def mfun_do_outline_options_d = d enddef ;
1237    def mfun_do_outline_options_r = r enddef ;
1238enddef ;
1239
1240vardef mfun_do_outline_text_set_b (text f) (text d) text r =
1241    def mfun_do_outline_options_f = f enddef ;
1242    def mfun_do_outline_options_d = d enddef ;
1243    def mfun_do_outline_options_r = r enddef ;
1244enddef ;
1245
1246vardef mfun_do_outline_text_set_r (text d) (text f) text r =
1247    def mfun_do_outline_options_d = d enddef ;
1248    def mfun_do_outline_options_f = f enddef ;
1249    def mfun_do_outline_options_r = r enddef ;
1250enddef ;
1251
1252vardef mfun_do_outline_text_set_n text r =
1253    def mfun_do_outline_options_r = r enddef ;
1254enddef ;
1255
1256vardef mfun_do_outline_text_set_p =
1257enddef ;
1258
1259def mfun_do_outline_options_d = enddef ;
1260def mfun_do_outline_options_f = enddef ;
1261def mfun_do_outline_options_r = enddef ;
1262
1263def outlinetexttopath (text o, p, n) =
1264    scantokens("numeric " & str n &   ";") ;
1265    scantokens("path "    & str p & "[];") ;
1266    n := 0 ;
1267    for i within o : p[incr(n)] := pathpart i ; endfor ;
1268enddef ;
1269
1270def filloutlinetext (expr o) =
1271    draw image (
1272        save n, m ; numeric n, m ; n := m := 0 ;
1273        for i within o :
1274            n := n + 1 ;
1275        endfor ;
1276        for i within o :
1277            m := m + 1 ;
1278            if n = m :
1279                eofill
1280            else :
1281                nofill
1282            fi pathpart i ;
1283        endfor ;
1284    )
1285enddef ;
1286
1287def drawoutlinetext (expr o) =
1288    draw image (
1289        % nicer for properties
1290        for i within o :
1291            draw pathpart i ;
1292        endfor ;
1293    )
1294enddef ;
1295
1296vardef outlinetext@# (expr t) text rest =
1297    save kind ; string kind ; kind := str @# ;
1298    currentoutlinetext := currentoutlinetext + 1 ;
1299    def mfun_do_outline_options_d = enddef ;
1300    def mfun_do_outline_options_f = enddef ;
1301    def mfun_do_outline_options_r = enddef ;
1302    image ( normaldraw image (
1303      % lua.mp.report("set outline text",currentoutlinetext);
1304        lua.mp.mf_outline_text(currentoutlinetext,t,kind) ;
1305      % lua.mp.report("get outline text",currentoutlinetext);
1306        if kind = "f" :
1307            mfun_do_outline_text_set_f rest ;
1308        elseif kind = "d" :
1309            mfun_do_outline_text_set_d rest ;
1310        elseif kind = "b" :
1311            mfun_do_outline_text_set_b rest ;
1312        elseif kind = "u" :
1313            mfun_do_outline_text_set_f rest ;
1314        elseif kind = "r" :
1315            mfun_do_outline_text_set_r rest ;
1316        elseif kind = "p" :
1317            mfun_do_outline_text_set_p ;
1318        else :
1319            mfun_do_outline_text_set_n rest ;
1320        fi ;
1321        lua.mp.mf_get_outline_text(currentoutlinetext) ;
1322    ) mfun_do_outline_options_r ; )
1323enddef ;
1324
1325
1326permanent outlinetexttopath, filloutlinetext, drawoutlinetext, outlinetext ;
1327
1328% A few helpers:
1329
1330numeric mfun_c_b_llx, mfun_c_b_h, mfun_c_b_w, mfun_c_b_l ;
1331
1332vardef checkedbounds(expr llx,lly,urx,ury) =
1333    mfun_c_b_llx := min(xpart llcorner currentpicture,llx) ;
1334    mfun_c_b_urx := max(xpart urcorner currentpicture,urx) ;
1335    mfun_c_b_lly := min(ypart llcorner currentpicture,lly) ;
1336    mfun_c_b_ury := max(ypart urcorner currentpicture,ury) ;
1337    (mfun_c_b_llx,mfun_c_b_lly) --
1338    (mfun_c_b_urx,mfun_c_b_lly) --
1339    (mfun_c_b_urx,mfun_c_b_ury) --
1340    (mfun_c_b_llx,mfun_c_b_ury) -- cycle
1341enddef ;
1342
1343vardef checkbounds(expr llx,lly,urx,ury) =
1344    setbounds currentpicture to checkedbounds(llx,lly,urx,ury) ;
1345enddef ;
1346
1347vardef strut(expr ht,dp) =
1348    setbounds currentpicture to checkedbounds(0,0,ht,dp) ;
1349enddef ;
1350
1351vardef rule(expr wd,ht,dp) =
1352    image (fill (0,-dp)--(wd,-dp)--(wd,ht)--(0,ht)--cycle)
1353enddef ;
1354
1355permanent checkedbounds, checkbounds, strut, rule ;
1356
1357% Housekeeping
1358
1359extra_beginfig := extra_beginfig & "currentgraphictext := 0 ; " ;
1360extra_beginfig := extra_beginfig & "currentoutlinetext := 0 ; " ;
1361extra_endfig   := extra_endfig   & "finishsavingdata ; " ;
1362extra_endfig   := extra_endfig   & "mfun_reset_tex_texts ; " ;
1363
1364% Bonus
1365
1366vardef verbatim(expr s) =
1367    ditto & "\detokenize{" & s & "}" & ditto
1368enddef ;
1369
1370permanent verbatim ;
1371
1372% New
1373
1374% def bitmapimage(expr xresolution, yresolution, data) =
1375%     image (
1376%         addto currentpicture doublepath unitsquare
1377%             withprescript  "bm_xresolution=" & decimal xresolution
1378%             withprescript  "bm_yresolution=" & decimal yresolution
1379%             withpostscript data ;
1380%     )
1381% enddef ;
1382
1383vardef bitmapimage(expr xresolution, yresolution, data) =
1384    save p ; picture p ; p := nullpicture ;
1385    addto p doublepath unitsquare
1386%         xscaled xresolution
1387%         yscaled yresolution
1388        withprescript  "bm_xresolution=" & decimal xresolution
1389        withprescript  "bm_yresolution=" & decimal yresolution
1390        withpostscript data
1391    ;
1392    p
1393enddef ;
1394
1395permanent bitmapimage ;
1396
1397% Experimental:
1398%
1399% property p ; p = properties(withcolor (1,1,0,0)) ;
1400% fill fullcircle scaled 20cm withproperties p ;
1401
1402let property = picture ; permanent property ;
1403
1404vardef properties(text t) =
1405    image(draw unitcircle t)
1406enddef ;
1407
1408def withproperties expr p =
1409    if colormodel p = graycolormodel :
1410        withcolor greypart p
1411    elseif colormodel p = rgbcolormodel :
1412        withcolor (redpart p,greenpart p,bluepart p)
1413    elseif colormodel p = cmykcolormodel :
1414        withcolor (cyanpart p,magentapart p,yellowpart p,blackpart p)
1415    fi
1416    withpen penpart p
1417    if length (dashpart p) > 0 :
1418        dashed dashpart p
1419    fi
1420    if stackingpart p <> 0 :
1421        withstacking stackingpart p
1422    fi
1423    withprescript prescriptpart p
1424    withpostscript postscriptpart p
1425enddef ;
1426
1427permanent properties, withproperties ;
1428
1429% Experimental:
1430
1431primarydef t asgroup s = % s = isolated|knockout
1432    begingroup
1433    save temp_p, temp_q, temp_r ;
1434    picture temp_p, temp_q ; path temp_r ;
1435    temp_p := if picture t : t else : image(draw t) fi ;
1436    temp_r := boundingbox temp_p ;
1437    temp_q:= nullpicture ;
1438    addto temp_q contour temp_r
1439        withprescript "gr_state=start"
1440        withprescript "gr_type=" & s
1441    ;
1442    addto temp_q also temp_p ;
1443    addto temp_q contour temp_r
1444        withprescript "gr_state=stop"
1445    ;
1446    temp_q
1447    endgroup
1448enddef ;
1449
1450permanent asgroup ;
1451
1452% Even more experimental:
1453
1454pair    mfun_pattern_s ; mfun_pattern_s := origin ; % auto scale to fraction of shape (svg)
1455boolean mfun_pattern_f ; mfun_pattern_f := false  ; % anchor or not (normally we do that)
1456
1457def withpatternscale primary s = hide (mfun_pattern_s := paired s ;) enddef ;
1458def withpatternfloat primary s = hide (mfun_pattern_f := s ;) enddef ;
1459
1460primarydef t withpattern p =
1461    begingroup
1462    %
1463    save temp_q, temp_r ;
1464    picture temp_q ; path temp_r ;
1465    % the combination
1466    temp_q:= nullpicture ;
1467    % the pattern
1468    temp_r := boundingbox p ;
1469    if mfun_pattern_s <> origin :
1470        sx := (xpart mfun_pattern_s) * bbwidth (t) ;
1471        sy := (ypart mfun_pattern_s) * bbheight(t) ;
1472        temp_r := temp_r xysized (sx,sy) ;
1473        addto temp_q contour temp_r
1474            withprescript "pt_state=start"
1475            withprescript "pt_action=set"
1476            withprescript "pt_float=" & tostring(mfun_pattern_f)
1477        ;
1478        addto temp_q also (p xysized (sx,sy));
1479    else :
1480        addto temp_q contour temp_r
1481            withprescript "pt_state=start"
1482            withprescript "pt_action=set"
1483            withprescript "pt_float=" & tostring(mfun_pattern_f)
1484        ;
1485        addto temp_q also p ;
1486    fi ;
1487    addto temp_q contour temp_r
1488        withprescript "pt_state=stop"
1489        withprescript "pt_action=set" ;
1490    % the path
1491    temp_r := boundingbox t ;
1492    addto temp_q contour temp_r
1493        withprescript "pt_state=start"
1494        withprescript "pt_action=get"
1495    ;
1496    addto temp_q contour temp_r
1497        withprescript "pt_state=stop"
1498        withprescript "pt_action=get" ;
1499    % make sure we fill only t
1500    clip temp_q to t ;
1501    % reset
1502    mfun_pattern_s := origin ;
1503    mfun_pattern_f := false ;
1504    % the path
1505    temp_q
1506    endgroup
1507enddef ;
1508
1509% Also experimental ... needs to be made better ... so it can change!
1510
1511string mfun_auto_align[] ;
1512
1513mfun_auto_align[0] := "rt" ;
1514mfun_auto_align[1] := "urt" ;
1515mfun_auto_align[2] := "top" ;
1516mfun_auto_align[3] := "ulft" ;
1517mfun_auto_align[4] := "lft" ;
1518mfun_auto_align[5] := "llft" ;
1519mfun_auto_align[6] := "bot" ;
1520mfun_auto_align[7] := "lrt" ;
1521mfun_auto_align[8] := "rt" ;
1522
1523def autoalign(expr n) =
1524    scantokens mfun_auto_align[round((n mod 360)/45)]
1525enddef ;
1526
1527% draw textext.autoalign(60) ("\strut oeps 1") ;
1528% draw textext.autoalign(160)("\strut oeps 2") ;
1529% draw textext.autoalign(260)("\strut oeps 3") ;
1530% draw textext.autoalign(360)("\strut oeps 4") ;
1531
1532% new
1533%
1534% passvariable("version","1.0") ;
1535% passvariable("number",123) ;
1536% passvariable("string","whatever") ;
1537% passvariable("point",(1,2)) ;
1538% passvariable("triplet",(1,2,3)) ;
1539% passvariable("quad",(1,2,3,4)) ;
1540% passvariable("boolean",false) ;
1541% passvariable("path",fullcircle scaled 1cm) ;
1542
1543% we could use the new lua interface but there is not that much gain i.e.
1544% we still need to serialize
1545
1546vardef mfun_point_to_string(expr p,i) =
1547    decimal xpart (point       i of p) & " " &
1548    decimal ypart (point       i of p) & " " &
1549    decimal xpart (precontrol  i of p) & " " &
1550    decimal ypart (precontrol  i of p) & " " &
1551    decimal xpart (postcontrol i of p) & " " &
1552    decimal ypart (postcontrol i of p)
1553enddef ;
1554
1555vardef mfun_transform_to_string(expr t) =
1556    decimal xxpart t & " " &   % rx
1557    decimal xypart t & " " &   % sx
1558    decimal yxpart t & " " &   % sy
1559    decimal yypart t & " " &   % ry
1560    decimal xpart  t & " " &   % tx
1561    decimal ypart  t           % ty
1562enddef ;
1563
1564vardef mfun_numeric_to_string(expr n) =
1565    decimal n
1566enddef ;
1567
1568vardef mfun_pair_to_string(expr p) =
1569    decimal xpart p & " " &
1570    decimal ypart p
1571enddef ;
1572
1573vardef mfun_rgbcolor_to_string(expr c) =
1574    decimal redpart   c & " " &
1575    decimal greenpart c & " " &
1576    decimal bluepart  c
1577enddef ;
1578
1579vardef mfun_cmykcolor_to_string(expr c) =
1580    decimal cyanpart    c & " " &
1581    decimal magentapart c & " " &
1582    decimal yellowpart  c & " " &
1583    decimal blackpart   c
1584enddef ;
1585
1586vardef mfun_pair_to_table(expr p) =
1587    "{" & decimal xpart p &
1588    "," & decimal ypart p &
1589    "}"
1590enddef ;
1591
1592vardef mfun_point_to_table(expr p,i) =
1593    "{" & decimal xpart (point       i of p) &
1594    "," & decimal ypart (point       i of p) &
1595    "," & decimal xpart (precontrol  i of p) &
1596    "," & decimal ypart (precontrol  i of p) &
1597    "," & decimal xpart (postcontrol i of p) &
1598    "," & decimal ypart (postcontrol i of p) &
1599    "}"
1600enddef ;
1601
1602vardef mfun_path_to_table(expr p) =
1603    "{" & mfun_point_to_table(p,0) for i=1 upto length(p) : & "," & mfun_point_to_table(p,i) endfor & "}"
1604enddef ;
1605
1606vardef mfun_rgb_to_table(expr c) =
1607    "{" & decimal redpart   c &
1608    "," & decimal greenpart c &
1609    "," & decimal bluepart  c &
1610    "}"
1611enddef ;
1612
1613vardef mfun_cmyk_to_table(expr c) =
1614    "{" & decimal cyanpart    c &
1615    "," & decimal magentapart c &
1616    "," & decimal yellowpart  c &
1617    "," & decimal blackpart   c &
1618    "}"
1619enddef ;
1620
1621vardef mfun_grey_to_string(expr n) =
1622    decimal n
1623enddef ;
1624
1625vardef mfun_path_to_string(expr p) =
1626    mfun_point_to_string(p,0) for i=1 upto length(p) : & " " & mfun_point_to_string(p,i) endfor
1627enddef ;
1628
1629vardef mfun_boolean_to_string(expr b) =
1630    if b : "true" else : "false" fi
1631enddef ;
1632
1633vardef tostring primary v =
1634    if     numeric   v : mfun_numeric_to_string(v)
1635    elseif pair      v : mfun_pair_to_string(v)
1636    elseif rgbcolor  v : mfun_rgbcolor_to_string(v)
1637    elseif cmykcolor v : mfun_cmykcolor_to_string(v)
1638    elseif greycolor v : mfun_greycolor_to_string(v)
1639    elseif boolean   v : mfun_boolean_to_string(v)
1640    elseif path      v : mfun_path_to_string(v)
1641    elseif transform v : mfun_transform_to_string(v)
1642    else               : v
1643    fi
1644enddef ;
1645
1646vardef topair primary p =
1647    if     pair    p : "(" & decimal xpart p & "," & decimal ypart p & ")"
1648    elseif numeric p : "(" & decimal       p & "," & decimal       p & ")"
1649    else             : "" fi
1650enddef ;
1651
1652string dq ; dq := char 92 & char 34 ;
1653string sq ; sq := char 92 & char 39 ;
1654
1655permanent dq, sq ;
1656
1657vardef quote     primary s = sq & tostring(s) & sq enddef;
1658vardef quotation primary s = dq & tostring(s) & dq enddef;
1659
1660vardef mfun_tagged_string(expr value) =
1661    if     numeric   value : "1:" & mfun_numeric_to_string(value)
1662    elseif pair      value : "4:" & mfun_pair_to_string(value)
1663    elseif rgbcolor  value : "5:" & mfun_rgbcolor_to_string(value)
1664    elseif cmykcolor value : "6:" & mfun_cmykcolor_to_string(value)
1665    elseif boolean   value : "3:" & mfun_boolean_to_string(value)
1666    elseif path      value : "7:" & mfun_path_to_string(value)
1667    elseif transform value : "8:" & mfun_transform_to_string(value)
1668    else                   : "2:" & value
1669    fi
1670enddef ;
1671
1672permanent tostring, topair, quote, quotation ;
1673
1674% A more flexible variant for passing data to context. We used to construct strings
1675% but running lua is fast enough so we can gain on string construction in metapost
1676% which is also not that efficient.
1677
1678newscriptindex mfid_passvariable ; mfid_passvariable := scriptindex("passvariable") ;
1679newscriptindex mfid_pushvariable ; mfid_pushvariable := scriptindex("pushvariable") ;
1680newscriptindex mfid_popvariable  ; mfid_popvariable  := scriptindex("popvariable") ;
1681
1682def passvariable        (expr key, value) = runscript mfid_passvariable key value ; enddef ;
1683def startpassingvariable(expr key)        = runscript mfid_pushvariable key ; enddef ;
1684def stoppassingvariable                   = runscript mfid_popvariable ; enddef ;
1685
1686def passarrayvariable(expr key)(suffix values)(expr first, last, stp) =
1687    startpassingvariable(key) ;
1688    for i=first step stp until last :
1689        passvariable(i, values[i]) ;
1690    endfor
1691    stoppassingvariable ;
1692enddef ;
1693
1694permanent passvariable, passarrayvariable, startpassingvariable, stoppassingvariable ;
1695
1696% moved here from mp-grap.mpiv
1697
1698% vardef escaped_format(expr s) =
1699%     "" for n=0 upto length(s) : &
1700%         if ASCII substring (n,n+1) of s = 37 :
1701%             "@"
1702%         else :
1703%             substring (n,n+1) of s
1704%         fi
1705%     endfor
1706% enddef ;
1707
1708numeric mfun_esc_b ; % begin
1709numeric mfun_esc_l ; % length
1710string  mfun_esc_s ; % character
1711
1712mfun_esc_s := "%" ; % or: char(37)
1713
1714% this one is the fastest when we have a match
1715
1716% vardef escaped_format(expr s) =
1717%     "" for n=0 upto length(s)-1 : &
1718%       % if ASCII substring (n,n+1) of s = 37 :
1719%         if substring (n,n+1) of s = mfun_esc_s :
1720%             "@"
1721%         else :
1722%             substring (n,n+1) of s
1723%         fi
1724%     endfor
1725% enddef ;
1726
1727% this one wins when we have no match
1728
1729vardef escaped_format(expr s) =
1730    mfun_esc_b := 0 ;
1731    mfun_esc_l := length(s) ;
1732    for n=0 upto mfun_esc_l-1 :
1733      % if ASCII substring (n,n+1) of s = 37 :
1734        if substring (n,n+1) of s = mfun_esc_s :
1735            if mfun_esc_b = 0 :
1736                ""
1737            fi
1738            if n >= mfun_esc_b :
1739                & (substring (mfun_esc_b,n) of s)
1740                exitif numeric begingroup mfun_esc_b := n+1 endgroup ; % hide
1741            fi
1742            & "@"
1743        fi
1744    endfor
1745    if mfun_esc_b = 0 :
1746        s
1747  % elseif mfun_esc_b > 0 :
1748    elseif mfun_esc_b < mfun_esc_l :
1749        & (substring (mfun_esc_b,mfun_esc_l) of s)
1750    fi
1751enddef ;
1752
1753vardef strfmt(expr f, x) = "\MPgraphformat{" & escaped_format(f) & "}{" & mfun_tagged_string(x) & "}" enddef ;
1754vardef varfmt(expr f, x) = "\MPformatted{"   & escaped_format(f) & "}{" & mfun_tagged_string(x) & "}" enddef ;
1755
1756vardef format@#   (expr f, x) = textext@#(strfmt(f, x)) enddef ;
1757vardef formatted@#(expr f, x) = textext@#(varfmt(f, x)) enddef ;
1758
1759permanent format, formatted ;
1760
1761% could be this (something to discuss with alan as it involves graph):
1762%
1763% vardef format   (expr f,x) = lua.mp.graphformat(f,mfun_tagged_string(x) enddef ;
1764% vardef formatted(expr f,x) = lua.mp.format     (f,                   x) enddef ;
1765%
1766% def strfmt = format    enddef ; % old
1767% def varfmt = formatted enddef ; % old
1768
1769% def fmttext = lua.mp.formatted enddef ;
1770
1771% new
1772
1773def fillup   text t = draw t withpostscript "both"     enddef ; % we use draw because we need the proper boundingbox
1774def eofillup text t = draw t withpostscript "eoboth"   enddef ; % we use draw because we need the proper boundingbox
1775def eofill   text t = fill t withpostscript "evenodd"  enddef ;
1776def nofill   text t = fill t withpostscript "collect"  enddef ;
1777def nodraw   text t = draw t withpostscript "collect"  enddef ;
1778def dodraw   text t = draw t withpostscript "flush"    enddef ;
1779%   eodraw   text t = draw t withpostscript "evenodd"  enddef ;
1780def dofill   text t = fill t withpostscript "flush"    enddef ;
1781def eoclip   text t = clip t withpostscript "evenodd"  enddef ;
1782def enfill   text t = fill t withpostscript "envelope" enddef ;
1783
1784permanent fillup, eofillup, eofill, nofill, nodraw, dodraw, dofill, eoclip ;
1785
1786% maybe (saves a bogus path but the problem is that it can influence the dimensions):
1787
1788% def dodraw text t = draw center currentpicture         withpostscript "flush" enddef ;
1789% def dofill text t = fill center currentpicture --cycle withpostscript "flush" enddef ;
1790
1791% def withrule expr r =
1792%     if (t = "even-odd") or (t = "evenodd") : withpostscript "evenodd" fi
1793% enddef ;
1794
1795% A comment will end up on top of the graphic in the output. This can be handy for
1796% locating a graphic: comment("test graphic").
1797
1798% This can be a prescript to currentpicture ... we can actually make
1799%
1800% setprescript  str to picture/path ;
1801% setpostscript str to picture/path ;
1802
1803def special text t = enddef ;
1804
1805def comment expr str =
1806    special "metapost.comment[[" & str & "]]" ;
1807enddef ;
1808
1809vardef report(text t) =
1810    lua.mp.report(t)
1811enddef ;
1812
1813permanent comment, report ;
1814
1815% This nechanism is not really promoted and more an experiment. It scales better than
1816% \METAPOST\ own hash.
1817
1818% todo: use mfid_* cum suis
1819
1820newscriptindex mfid_hash_new     ; mfid_hash_new     := scriptindex("lmt_hash_new") ;
1821newscriptindex mfid_hash_dispose ; mfid_hash_dispose := scriptindex("lmt_hash_dispose") ;
1822newscriptindex mfid_hash_in      ; mfid_hash_in      := scriptindex("lmt_hash_in") ;
1823newscriptindex mfid_hash_from    ; mfid_hash_from    := scriptindex("lmt_hash_from") ;
1824newscriptindex mfid_hash_to      ; mfid_hash_to      := scriptindex("lmt_hash_to") ;
1825
1826def newhash                          = runscript mfid_hash_new                 enddef ; % optional, returns index
1827def disposehash (expr n)             = runscript mfid_hash_dispose n           enddef ;
1828def inhash      (expr n, key)        = runscript mfid_hash_in      n key       enddef ;
1829def fromhash    (expr n, key)        = runscript mfid_hash_from    n key       enddef ;
1830def tohash      (expr n, key, value) = runscript mfid_hash_to      n key value enddef ;
1831
1832string mfun_u_l_h ; mfun_u_l_h := "mfun_u_l_h" ;
1833
1834vardef uniquelist(suffix list) =
1835    % this can be optimized by passing all values at once and returning
1836    % a result but for now this is ok .. we need an undef foo
1837    save i, j ;
1838    if known lis[0] :
1839        i := 0 ;
1840        j := -1 ;
1841    else :
1842        i := 1 ;
1843        j := 0 ;
1844    fi ;
1845  % mfun_u_l_h := runscript mfid_hash_new ; % here mfun_u_l_h has to be a numeric
1846    forever :
1847        exitif unknown list[i] ;
1848        if not (runscript mfid_hash_in (mfun_u_l_h) list[i]) :
1849            j := j + 1 ;
1850            list[j] := list[i] ;
1851            runscript mfid_hash_to (mfun_u_l_h) (j) list[i] ;
1852        fi ;
1853        i := i + 1 ;
1854    endfor ;
1855    for n = j + 1 step 1 until i - 1 :
1856        dispose(list[n])
1857    endfor ;
1858    runscript mfid_hash_dispose mfun_u_l_h ;
1859enddef ;
1860
1861permanent uniquelist ;
1862
1863% This influences the decision for a curve or path segment; 1/4096 is the default but
1864% 10/2048 works quite well.
1865
1866def withtolerance expr n =
1867    withprescript ("tolerance=" & decimal n)
1868enddef ;
1869
1870% fun stuff: randomseed := repeatablerandom("default") ;
1871
1872newscriptindex mfid_repeatablerandom ; mfid_repeatablerandom := scriptindex("repeatablerandom") ;
1873
1874def repeatablerandom = runscript mfid_repeatablerandom enddef ;
1875
1876