summaryrefslogtreecommitdiff
path: root/metapost/context/base/mpiv/mp-tool.mpiv
diff options
context:
space:
mode:
Diffstat (limited to 'metapost/context/base/mpiv/mp-tool.mpiv')
-rw-r--r--metapost/context/base/mpiv/mp-tool.mpiv932
1 files changed, 836 insertions, 96 deletions
diff --git a/metapost/context/base/mpiv/mp-tool.mpiv b/metapost/context/base/mpiv/mp-tool.mpiv
index 76459d25c..cd04b8dcb 100644
--- a/metapost/context/base/mpiv/mp-tool.mpiv
+++ b/metapost/context/base/mpiv/mp-tool.mpiv
@@ -11,8 +11,6 @@
%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 ;
@@ -28,7 +26,9 @@ let @## = @# ;
if not known mpversion : string mpversion ; mpversion := "0.641" ; fi ;
-newinternal metapostversion ; metapostversion := scantokens(mpversion) ;
+% newinternal metapostversion ; metapostversion := scantokens(mpversion) ;
+
+newinternal metapostversion ; metapostversion := 2.0 ;
%D We always want \EPS\ conforming output, so we say:
@@ -36,6 +36,10 @@ prologues := 1 ;
warningcheck := 0 ;
mpprocset := 1 ;
+%D Handy:
+
+def nothing = enddef ;
+
%D Namespace handling:
% let exclamationmark = ! ;
@@ -89,6 +93,47 @@ enddef ;
let triplet = rgbcolor ;
let quadruplet = cmykcolor ;
+%D Image redefined, for Alan:
+
+vardef image@#(text t) =
+ save currentpicture ;
+ picture currentpicture ;
+ currentpicture := nullpicture ;
+ t ;
+ currentpicture
+ if str @# <> "" :
+ shifted (
+ mfun_labxf@# * lrcorner p
+ + mfun_labyf@# * ulcorner p
+ + (1-mfun_labxf@#-mfun_labyf@#) * llcorner p
+ )
+ fi
+enddef ;
+
+%D Variables
+
+def dispose suffix s =
+ if known s :
+ begingroup ;
+ save ss ;
+ if numeric s : numeric ss
+ elseif boolean s : boolean ss
+ elseif pair s : pair ss
+ elseif path s : path ss
+ elseif picture s : picture ss
+ elseif string s : string ss
+ elseif transform s : transform ss
+ elseif color s : color ss
+ elseif rgbcolor s : rgbcolor ss
+ elseif cmykcolor s : cmykcolor ss
+ elseif pen s : pen ss
+ else s : numeric ss
+ fi ;
+ s := ss ;
+ endgroup ;
+ fi ;
+enddef ;
+
%D Colors:
newinternal nocolormodel ; nocolormodel := 1 ;
@@ -143,6 +188,8 @@ vardef colordecimals primary 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
+ elseif string c:
+ colordecimals resolvedcolor(c)
else :
decimal c
fi
@@ -335,6 +382,42 @@ enddef;
% mfun_a_b
% enddef ;
+%D Here are some special ones, cooked up in the process of Alan's mp-node
+%D module:
+
+vardef boundingradius primary p =
+ if picture p :
+ max(
+ abs((llcorner p) shifted -center p),
+ abs((lrcorner p) shifted -center p),
+ abs((urcorner p) shifted -center p),
+ abs((ulcorner p) shifted -center p)
+ )
+ elseif pen p :
+ boundingradius image(draw makepath p ;)
+ elseif path p :
+ boundingradius image(draw p ;)
+ fi
+enddef ;
+
+vardef boundingcircle primary p =
+ fullcircle scaled 2boundingradius p shifted center p
+enddef ;
+
+vardef boundingpoint@#(expr p) =
+ if picture p : % pen?
+ ( mfun_labxf@# *ulcorner p
+ + mfun_labyf@# *lrcorner p
+ +(1-mfun_labxf@#-mfun_labyf@#)*urcorner p)
+ elseif path p :
+ boundingpoint@#(image(draw p ;))
+ %elseif pair p :
+ % p
+ %else :
+ % origin
+ fi
+enddef ;
+
%D Some missing functions can be implemented rather straightforward (thanks to
%D Taco and others):
@@ -373,6 +456,7 @@ 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 ;
+vardef tanh primary x = save xx ; xx = exp x ; (xx-1/xx)/(xx+1/xx) enddef ;
%D Like mod, but useful for anglesl it returns (-.5d,+.5d] and is used
%D in for instance mp-chem.
@@ -715,7 +799,7 @@ primarydef p xyscaled q = % secundarydef does not work out well
endgroup
enddef ;
-%D Some personal code that might move to another module
+%D Some personal code that might move to another module (todo: save).
def set_grid(expr w, h, nx, ny) =
boolean grid[][] ; boolean grid_full ;
@@ -789,7 +873,7 @@ secondarydef p intersection_point q =
begingroup
save x_, y_ ;
(x_,y_) = p intersectiontimes q ;
- if x_<0 :
+ if x_< 0 :
intersection_found := false ;
center p % origin
else :
@@ -817,36 +901,59 @@ enddef ;
%D Some colors.
-def colortype(expr c) =
- if cmykcolor c : cmykcolor elseif rgbcolor c : rgbcolor else : grayscale fi
+def resolvedcolor(expr s) =
+ .5white
+enddef ;
+
+let normalwithcolor = withcolor ;
+
+def withcolor expr c =
+ normalwithcolor if string c : resolvedcolor(c) else : c fi
enddef ;
-vardef whitecolor(expr c) =
- if cmykcolor c : (0,0,0,0) elseif rgbcolor c : (1,1,1) else : 1 fi
+vardef colortype expr c =
+ if cmykcolor c : cmykcolor
+ elseif rgbcolor c : rgbcolor
+ elseif numeric c : grayscale
+ fi
+enddef ;
+
+vardef whitecolor expr c =
+ if cmykcolor c : (0,0,0,0)
+ elseif rgbcolor c : (1,1,1)
+ elseif numeric c : 1
+ elseif string c : whitecolor resolvedcolor(c)
+ fi
enddef ;
vardef blackcolor expr c =
- if cmykcolor c : (0,0,0,1) elseif rgbcolor c : (0,0,0) else : 0 fi
+ if cmykcolor c : (0,0,0,1)
+ elseif rgbcolor c : (0,0,0)
+ elseif numeric c : 0
+ elseif string c : blackcolor resolvedcolor(c)
+ fi
enddef ;
-vardef complementary expr c = (
- if cmykcolor c : (1,1,1,1) -
- elseif rgbcolor c : (1,1,1) -
- elseif pair c : (1,1) -
- elseif numeric c : 1 -
- fi c
-) enddef ;
+vardef complementary expr c =
+ if cmykcolor c : (1,1,1,1) - c
+ elseif rgbcolor c : (1,1,1) - c
+ elseif pair c : (1,1) - c
+ elseif numeric c : 1 - c
+ elseif string c : complementary resolvedcolor(c)
+ fi
+enddef ;
vardef complemented expr c =
save m ;
if cmykcolor c : m := max(cyanpart c, magentapart c, yellowpart c, blackpart c) ;
- ( (m,m,m,m) -
+ (m,m,m,m) - c
elseif rgbcolor c : m := max(redpart c, greenpart c, bluepart c) ;
- ( (m,m,m) -
+ (m,m,m) - c
elseif pair c : m := max(xpart c, ypart c) ;
- ( (m,m) -
- elseif numeric c : ( m -
- fi c )
+ (m,m) - c
+ elseif numeric c : m - c
+ elseif string c : complemented resolvedcolor(c)
+ fi
enddef ;
%D Well, this is the dangerous and naive version:
@@ -971,6 +1078,56 @@ primarydef p randomshifted s =
endgroup
enddef ;
+vardef mfun_randomized_path(expr p,s) =
+ for i=0 upto length(p)-1 :
+ (point i of p) .. 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)
+ fi
+enddef;
+
+vardef mfun_randomized_picture(expr p,s)(text rnd) =
+ save currentpicture ;
+ picture currentpicture ;
+ currentpicture := nullpicture ;
+ for i within p :
+ addto currentpicture
+ if stroked i :
+ doublepath pathpart i rnd s
+ dashed dashpart i
+ withpen penpart i
+ withcolor colorpart i
+ withprescript prescriptpart i
+ withpostscript postscriptpart i
+ elseif filled i :
+ contour pathpart i rnd s
+ withpen penpart i
+ withcolor colorpart i
+ withprescript prescriptpart i
+ withpostscript postscriptpart i
+ else :
+ also i
+ fi
+ ;
+ endfor ;
+ currentpicture
+enddef ;
+
+primarydef p randomizedcontrols s = (
+ if path p :
+ mfun_randomized_path(p,s)
+ elseif picture p :
+ mfun_randomized_picture(p,s)(randomizedcontrols)
+ else :
+ p randomized s
+ fi
+) enddef ;
+
primarydef p randomized s = (
if path p :
for i=0 upto length(p)-1 :
@@ -1014,7 +1171,12 @@ primarydef p randomized s = (
else :
((uniformdeviate s) * p)
fi
+ elseif string p :
+ (resolvedcolor(p)) randomized s
+ elseif picture p :
+ mfun_randomized_picture(p,s)(randomized)
else :
+ % p - s/2 + uniformdeviate s % would have been better but we want to be positive
p + uniformdeviate s
fi
) enddef ;
@@ -1165,6 +1327,15 @@ vardef arrowheadonpath (expr p, s) =
arrowhead p if s < 1 : cutafter (point (s*arclength(p) + (ahlength/2)) on p) fi
enddef ;
+def resetarrows =
+ hide (
+ ahlength := 4 ;
+ ahangle := 45 ;
+ ahvariant := 0 ;
+ ahdimple := 1/5 ;
+ )
+enddef ;
+
%D Points.
def drawpoint expr c =
@@ -1384,13 +1555,12 @@ 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.
+%D Normally, arrowheads don't scale well. So we provide a hack.
boolean autoarrows ; autoarrows := false ;
numeric ahfactor ; ahfactor := 2.5 ;
-def set_ahlength (text t) =
+def set_ahlength (text t) = % called to often
% 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).
@@ -1413,31 +1583,158 @@ vardef arrowpath expr p = % patch by Peter Rolf: supports squared pen and shifti
))
enddef;
-% def _finarr text t =
-% if autoarrows : set_ahlength (t) fi ;
-% draw arrowpath _apth t ; % arrowpath added
-% filldraw arrowhead _apth t ;
-% enddef;
+% New experimental extension: also handling pictures:
+%
+% drawarrow fullsquare scaled 2cm withcolor green ;
+% drawarrow fullcircle scaled 3cm withcolor green ;
+% drawarrow image (
+% draw fullsquare scaled 4cm withcolor red ;
+% draw fullcircle scaled 5cm withcolor blue ;
+% ) ;
+% currentpicture := currentpicture shifted (-bbwidth(currentpicture)-1cm,0) ;
+% drawdblarrow fullsquare scaled 2cm withcolor green ;
+% drawdblarrow fullcircle scaled 3cm withcolor green ;
+% drawdblarrow image (
+% draw fullsquare scaled 4cm withcolor red ;
+% draw fullcircle scaled 5cm withcolor blue ;
+% ) ;
+
+vardef stroked_paths(expr p) =
+ save n ; numeric n ; n := 0 ;
+ for i within p :
+ if stroked i :
+ n := n + 1 ;
+ fi
+ endfor ;
+ n
+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 mfun_decoration_i expr i =
+ withpen penpart i
+ withcolor colorpart i
+ withprescript prescriptpart i
+ withpostscript postscriptpart i
+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;
+% We could collapse all in one helper but in context we nowaways don't want
+% the added obscurity. Tokens come cheap.
-def _finarr text t =
- if autoarrows : set_ahlength (t) fi ;
- draw arrowpath _apth t ; % arrowpath added
- fillup arrowhead _apth t ;
-enddef;
+numeric mfun_arrow_snippets ;
+numeric mfun_arrow_count ;
+
+def drawarrow expr p =
+ begingroup ;
+ save mfun_arrow_path ;
+ path mfun_arrow_path ;
+ if path p :
+ mfun_arrow_path := p ;
+ expandafter mfun_draw_arrow_path
+ elseif picture p :
+ save mfun_arrow_picture ;
+ picture mfun_arrow_picture ;
+ mfun_arrow_picture := p ;
+ expandafter mfun_draw_arrow_picture
+ else :
+ expandafter mfun_draw_arrow_nothing
+ fi
+enddef ;
+
+def drawdblarrow expr p =
+ begingroup ;
+ save mfun_arrow_path ;
+ path mfun_arrow_path ;
+ if path p :
+ mfun_arrow_path := p ;
+ expandafter mfun_draw_arrow_path_double
+ elseif picture p :
+ save mfun_arrow_picture ;
+ picture mfun_arrow_picture ;
+ mfun_arrow_picture := p ;
+ expandafter mfun_draw_arrow_picture_double
+ else :
+ expandafter mfun_draw_arrow_nothing
+ fi
+enddef ;
+
+def mfun_draw_arrow_nothing text t =
+enddef ;
+
+% The path is shortened so that the arrow head extends it to the original
+% length. In case of a double arrow the path gets shortened twice.
+
+def mfun_draw_arrow_path text t =
+ if autoarrows :
+ set_ahlength(t) ;
+ fi
+ draw arrowpath mfun_arrow_path t ;
+ fillup arrowhead mfun_arrow_path t ;
+ endgroup ;
+enddef ;
+
+def mfun_draw_arrow_path_double text t =
+ if autoarrows :
+ set_ahlength(t) ;
+ fi
+ draw arrowpath (reverse arrowpath mfun_arrow_path) t ;
+ fillup arrowhead mfun_arrow_path t ;
+ fillup arrowhead reverse mfun_arrow_path t ;
+ endgroup ;
+enddef ;
+
+% The picture variant is not treating each path but only the first and
+% last path. This can be somewhat counterintuitive but is needed for Alan's
+% macros. So here the last and in case of a double path first paths in a
+% picture get the shortening.
+
+def mfun_with_arrow_picture (text t) =
+ mfun_arrow_count := 0 ;
+ mfun_arrow_snippets := stroked_paths(mfun_arrow_picture) ;
+ for i within mfun_arrow_picture :
+ if stroked i :
+ mfun_arrow_count := mfun_arrow_count + 1 ;
+ mfun_arrow_path := pathpart i ;
+ t
+ fi ;
+ endfor ;
+enddef ;
+
+def mfun_draw_arrow_picture text t =
+ if autoarrows :
+ set_ahlength(t) ;
+ fi
+ mfun_with_arrow_picture (
+ if mfun_arrow_count = mfun_arrow_snippets :
+ draw arrowpath mfun_arrow_path mfun_decoration_i i t ;
+ fillup arrowhead mfun_arrow_path mfun_decoration_i i t ;
+ else :
+ draw mfun_arrow_path mfun_decoration_i i t ;
+ fi ;
+ )
+ endgroup ;
+enddef ;
+
+def mfun_draw_arrow_picture_double text t =
+ if autoarrows :
+ set_ahlength(t) ;
+ fi
+ mfun_with_arrow_picture (
+ draw
+ if mfun_arrow_count = 1 :
+ arrowpath reverse
+ fi
+ if mfun_arrow_count = mfun_arrow_snippets :
+ arrowpath
+ fi
+ mfun_arrow_path mfun_decoration_i i t ;
+ if mfun_arrow_count = 1 :
+ fillup arrowhead reverse mfun_arrow_path mfun_decoration_i i t ;
+ fi
+ if mfun_arrow_count = mfun_arrow_snippets :
+ fillup arrowhead mfun_arrow_path mfun_decoration_i i t ;
+ fi
+ )
+ endgroup ;
+enddef ;
%D Handy too ......
@@ -1487,9 +1784,7 @@ enddef ;
%D To be documented.
-path freesquare ;
-
-freesquare := (
+path freesquare ; freesquare := (
(-1,0) -- (-1,-1) -- (0,-1) -- (+1,-1) --
(+1,0) -- (+1,+1) -- (0,+1) -- (-1,+1) -- cycle
) scaled .5 ;
@@ -1637,7 +1932,7 @@ enddef ;
% nice: currentpicture := inverted currentpicture ;
-primarydef p uncolored c =
+primarydef p uncolored c = % not complete ... needs text and scripts and ...
if color p :
c - p
else :
@@ -1699,6 +1994,8 @@ vardef grayed primary p =
tripled(.30*(1-cyanpart i)+.59*(1-magentapart i)+.11*(1-yellowpart i)+blackpart i)
elseif greycolor p :
p
+ elseif string p :
+ grayed resolvedcolor(p)
elseif picture p :
image (
for i within p :
@@ -1854,14 +2151,16 @@ inner end ;
% this will be redone (when needed) using scripts and backend handling
-let normalwithcolor = withcolor ;
+let mfun_remap_colors_normalwithcolor = normalwithcolor ;
def remapcolors =
- def withcolor primary c = normalwithcolor remappedcolor(c) enddef ;
+ def normalwithcolor primary c =
+ mfun_remap_colors_normalwithcolor remappedcolor(c)
+ enddef ;
enddef ;
def normalcolors =
- let withcolor = normalwithcolor ;
+ let normalwithcolor = mfun_remap_colors_normalwithcolor ;
enddef ;
def resetcolormap =
@@ -1912,7 +2211,7 @@ def reprocess suffix p = p := repathed (22,p) enddef ; % no attributes
vardef repathed (expr mode, p) text t =
begingroup ;
if mode = 0 :
- save withcolor ;
+ save normalwithcolor ;
remapcolors ;
fi ;
save _p_, _pp_, _ppp_, _f_, _b_, _t_ ;
@@ -2138,8 +2437,22 @@ vardef mfun_straightened(expr sign, p) =
_q_
enddef ;
+% vardef mfun_straightened(expr sign, p) =
+% save lp, lq, q ; path q ; q := p ;
+% lp := length(p) ;
+% forever :
+% q := mfun_do_straightened(sign,q) ;
+% lq := length(q) ;
+% exitif lp = lq ;
+% lp := lq ;
+% endfor ;
+% q
+% enddef ;
+
+% can be optimized:
+
vardef mfun_do_straightened(expr sign, p) =
- if length(p)>2 : % was 1, but straight lines are ok
+ 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 :
@@ -2149,10 +2462,10 @@ vardef mfun_do_straightened(expr sign, p) =
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 n > 2 :
+ for i=0 upto n :
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)) :
+ sign * unitvector(round(point if i=n : 0 else : i+1 fi of pp - point i of pp)) :
if ok :
--
else :
@@ -2198,7 +2511,7 @@ vardef unspiked expr p = (
path originpath ; originpath := origin -- cycle ;
vardef unitvector primary z =
- if abs z = abs origin : z else : z/abs z fi
+ if abs z = abs origin : z else : z/abs z fi % hm, abs origin is just origin
enddef;
% also new
@@ -2523,41 +2836,41 @@ vardef undecorated (text imagedata) text decoration =
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:
+% 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 ;
@@ -2597,7 +2910,7 @@ else:
currentpicture
enddef ;
-fi ;
+% fi ;
vardef redecorated (text imagedata) text decoration =
save mfun_decorated_path, currentpicture ;
@@ -2726,4 +3039,431 @@ enddef;
extra_endfig := extra_endfig & "mfun_apply_max_dimensions ;" ;
+%D Bonus shapes (need along):
+
+path unittriangle, fulltriangle ; % not really units but circle based
+
+unittriangle := point 0 along unitcircle
+ -- point 1/3 along unitcircle
+ -- point 2/3 along unitcircle
+ -- cycle ;
+fulltriangle := point 0 along fullcircle
+ -- point 1/3 along fullcircle
+ -- point 2/3 along fullcircle
+ -- cycle ;
+
+%D Kind of special and undocumented. On Wikipedia one can find examples
+%D of quick sort routines. Here we have a variant that permits a
+%D method.
+
+% vardef listsize(suffix list) =
+% numeric len ; len := 0 ;
+% forever :
+% exitif unknown list[len+1] ;
+% len := len + 1 ;
+% endfor ;
+% len
+% enddef ;
+
+vardef listsize(suffix list) =
+ numeric len ; len := 1 ;
+ forever :
+ exitif unknown list[len] ;
+ len := len + 1 ;
+ endfor ;
+ len if unknown list[0] : - 1 fi
+enddef ;
+
+vardef listlast(suffix list) =
+ numeric len ; len := if known list[0] : 0 else : 1 fi ;
+ forever :
+ len := len + 1 ;
+ exitif unknown list[len] ;
+ endfor ;
+ len - 1
+enddef ;
+
+vardef mfun_quick_sort(suffix list)(expr _min_, _max_)(text what) =
+ save l, r, m ;
+ numeric l ; l := _min_ ;
+ numeric r ; r := _max_ ;
+ numeric m ; m := floor(.5[_min_,_max_]) ;
+ _mid_ := what list[m] ;
+ forever :
+ exitif l >= r ;
+ forever :
+ exitif l > _max_ ;
+ % exitif (what list[l]) >= (what list[m]) ;
+ exitif (what list[l]) >= _mid_ ;
+ l := l + 1 ;
+ endfor ;
+ forever :
+ exitif r < _min_ ;
+ % exitif (what list[m]) >= (what list[r]) ;
+ exitif _mid_ >= (what list[r]) ;
+ r := r - 1 ;
+ endfor ;
+ if l <= r :
+ temp := list[l] ;
+ list[l] := list[r] ;
+ list[r] := temp ;
+ l := l + 1 ;
+ r := r - 1 ;
+ fi ;
+ endfor ;
+ if _min_ < r :
+ mfun_quick_sort(list)(_min_,r)(what) ;
+ fi ;
+ if l < _max_ :
+ mfun_quick_sort(list)(l,_max_)(what) ;
+ fi ;
+enddef ;
+
+vardef sortlist(suffix list)(text what) =
+ save _max_ ; numeric _max_ ;
+ save _mid_ ; numeric _mid_ ;
+ save temp ;
+ % _max_ := listsize(list) ;
+ _max_ := listlast(list) ;
+ if pair list[_max_] :
+ pair temp ;
+ else :
+ numeric temp ;
+ fi ;
+ if pair what list[_max_] :
+ pair _mid_ ;
+ else :
+ numeric _mid_ ;
+ fi ;
+ if _max_ > 1 :
+ % mfun_quick_sort(list)(1,_max_)(what) ;
+ mfun_quick_sort(list)(if known list[0] : 0 else : 1 fi,_max_)(what) ;
+ fi ;
+enddef ;
+
+vardef uniquelist(suffix list) =
+ % this one will be defined later
+enddef ;
+
+vardef copylist(suffix list, target) =
+ save i ; i := 1 ;
+ forever :
+ exitif unknown list[i] ;
+ target[i] := list[i] ;
+ i := i + 1 ;
+ endfor ;
+enddef ;
+
+vardef listtolines(suffix list) =
+ list[1] for i=2 upto listsize(list) : -- list[i] endfor
+enddef ;
+
+vardef listtocurves(suffix list) =
+ list[1] for i=2 upto listsize(list) : .. list[i] endfor
+enddef ;
+
+%D The sorter is used in:
+
+% not yet ok
+
+vardef shapedlist(suffix p) = % takes a list of paths
+ save l ; pair l[] ;
+ save r ; pair r[] ;
+ save i ; i := 1 ;
+ save n ; n := 0 ;
+ forever :
+ exitif unknown p[i] ;
+ n := n + 1 ;
+ l[n] := ulcorner p[i] ;
+ r[n] := urcorner p[i] ;
+ n := n + 1 ;
+ l[n] := llcorner p[i] ;
+ r[n] := lrcorner p[i] ;
+ i := i + 1 ;
+ endfor ;
+ for i = 3 upto n :
+ if xpart r[i] < xpart r[i-1] :
+ r[i] := (xpart r[i],ypart r[i-1]) ;
+ elseif xpart r[i] > xpart r[i-1] :
+ r[i-1] := (xpart r[i-1],ypart r[i]) ;
+ fi ;
+ if xpart l[i] < xpart l[i-1] :
+ l[i-1] := (xpart l[i-1],ypart l[i]) ;
+ elseif xpart l[i] > xpart l[i-1] :
+ l[i] := (xpart l[i],ypart l[i-1]) ;
+ fi ;
+ endfor ;
+ if n > 0 :
+ simplified (
+ for i = 1 upto n : r[i] -- endfor
+ for i = n downto 1 : l[i] -- endfor
+ cycle
+ )
+ else :
+ origin -- cycle
+ fi
+enddef ;
+
+%D Dumping is fake anyway but let's keep this:
+
let dump = relax ;
+
+%D Loading modules can be done with:
+
+def loadmodule expr name = % no vardef
+ % input can't be used directly in a macro
+ if unknown scantokens("context_" & name) :
+ save s ; string s ;
+ % s := "mp-" & name & ".mpiv" ;
+ % message("loading module",s) ;
+ % s := "input " & s ;
+ s := "input " & "mp-" & name & ".mpiv" ;
+ expandafter scantokens expandafter s
+ fi ;
+enddef ;
+
+%D Handy for backgrounds:
+
+def drawpathwithpoints expr p =
+ do_drawpathwithpoints(p)
+enddef ;
+
+def do_drawpathwithpoints(expr p) text t =
+ draw p t ;
+ if length(p) > 2 :
+ begingroup ;
+ save _c_ ; path _c_ ;
+ save _p_; picture _p_ ;
+ _p_ := image (
+ _c_ := if cycle p : fullsquare else : fullcircle fi scaled 6pt ;
+ 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 withcolor white/2 withpen pencircle scaled .5pt ;
+ if (i = 0) and cycle p :
+ _c_ := fullcircle scaled 6pt ;
+ fi ;
+ endfor ;
+ for i=0 upto length(p) if cycle p : -1 fi :
+ draw textext("\infofont " & decimal i) ysized 2pt shifted point i of p ;
+ endfor ;
+ ) ;
+ setbounds _p_ to boundingbox p ;
+ draw _p_ ;
+ fi ;
+enddef ;
+
+%D These new helpers are by Alan and are used in for instance the mp-node
+%D module.
+
+newinternal crossingdebug ; crossingdebug := 0 ;
+newinternal crossingscale ; crossingscale := 10 ;
+newinternal crossingnumbermax ; crossingnumbermax := 1000 ;
+
+% primary, secondary or tertiary? always hard to decide but primary makes sense
+
+vardef infotext@#(expr txt, ysize) =
+ textext@#("\infofont " & if numeric txt : decimal fi txt) ysized ysize
+enddef ;
+
+primarydef p crossingunder q =
+ begingroup
+ save pic ; picture pic ; pic := nullpicture ;
+ if picture p :
+ for i within p :
+ if stroked i :
+ addto pic also image(draw pathpart i crossingunder q) ;
+ fi
+ endfor
+ elseif path p :
+ save n, t, a, b, c, r, bcuttings, hold ;
+ numeric n, t[], hold ;
+ path a, b, c, r, bcuttings, hold[] ;
+ c := makepath(currentpen scaled crossingscale) ;
+ r := if picture q : boundingbox fi q ;
+ t[0] := n := hold := 0 ;
+ a := p ;
+ % The cutbefore/cutafter using c below prevents endless loops!
+ %forever : % find all intersections
+ for i=1 upto crossingnumbermax : % safeguard
+ clearxy ; z = a intersectiontimes r ;
+ if x < 0 :
+ exitif hold < 1 ;
+ a := hold[hold] ; hold := hold - 1 ;
+ clearxy ; z = a intersectiontimes r ;
+ fi
+ (t[incr n], whatever) = p intersectiontimes point x of a ;
+ if x = 0 :
+ a := a cutbefore c shifted point x of a ;
+ elseif x = length a :
+ a := a cutafter c shifted point x of a ;
+ else : % before or after?
+ b := subpath (0,x) of a cutafter c shifted point x of a ;
+ bcuttings := cuttings ;
+ a := subpath (x,length a) of a cutbefore c shifted point x of a ;
+ clearxy ; z = a intersectiontimes r ;
+ if x < 0 :
+ a := b ;
+ cuttings := bcuttings ;
+ else :
+ if length bcuttings > 0 :
+ clearxy ; z = b intersectiontimes r ;
+ if x >= 0 :
+ hold[incr hold] := b ;
+ fi
+ fi
+ fi
+ fi
+ if length cuttings = 0 : % a single point: nothing cut
+ exitif hold < 1 ;
+ a := hold[hold] ; hold := hold - 1 ;
+ fi
+ if i = crossingnumbermax :
+ message("crossingunder reached maximum " & decimal i &
+ " intersections.");
+ fi
+ endfor
+
+ if n = 0 : % No crossings, we return the PATH
+ save pic ; path pic ; pic := p ;
+ else : % n>0
+ sortlist(t,) ;
+ % we add too much, maybe a test is needed
+ t[incr n] = length p if cycle p : + t[1] fi ;
+% save tt[] ; numeric tt[] ; uniquelist(t,tt) ; t := tt ;
+ % Now, n>1 !
+ % t[0] is the first point of the path and t[n] is the last point
+ % (or the first intersection beyond the length if cyclic)
+ save m ; m := 0 ;
+ for i=if cycle p: 2 else: 1 fi upto n :
+ % skip the first segment if cyclic
+ % as it gets repeated (fully) at the end.
+ if crossingdebug > 0 :
+ if crossingdebug = 1 :
+ addto pic doublepath c shifted point t[i] of p
+ withpen currentpen withtransparency(1,.5) ;
+ elseif crossingdebug = 2 :
+ addto pic also
+ infotext (incr m,crossingscale/5)
+ shifted point t[i] of p ;
+ fi
+ fi
+ a := subpath (t[i-1],t[i]) of p
+ if i > 1 :
+ cutbefore (c shifted point t[i-1] of p)
+ fi
+ if (i < n) or (cycle p) :
+ cutafter (c shifted point t[i] of p)
+ fi ;
+ if (not picture q) or (a outsideof q) :
+ addto pic doublepath a withpen currentpen ;
+ fi
+ endfor
+ fi
+ fi
+ pic
+ endgroup
+enddef ;
+
+primarydef p insideof q =
+ begingroup
+ save pth, pic, t ;
+ path pth ; picture pic ;
+ pic := if path q : image(draw q;) else : q fi ;
+ pth := p -- center pic ;
+ (t, whatever) = pth intersectiontimes boundingbox pic ;
+ t < 0
+ endgroup
+enddef ;
+
+% primarydef p insideof q =
+% if (path q or picture q) :
+% if (path p or picture p) :
+% (xpart llcorner p > xpart llcorner q) and
+% (xpart urcorner p < xpart urcorner q) and
+% (ypart llcorner p > ypart llcorner q) and
+% (ypart urcorner p < ypart urcorner q)
+% elseif pair p :
+% (xpart p > xpart llcorner q) and
+% (xpart p < xpart urcorner q) and
+% (ypart p > ypart llcorner q) and
+% (ypart p < ypart urcorner q)
+% fi
+% elseif (numeric p and pair q) :
+% % range check
+% (p >= xpart q) and (p <= ypart q)
+% else : % maybe triplets and such
+% false
+% fi
+% enddef ;
+
+primarydef p outsideof q =
+ not (p insideof q)
+enddef ;
+
+%D Also handy:
+
+vardef circularpath primary n =
+ reverse (for i=0 step 2/n until 8-2/n+2eps: point i of fullcircle .. endfor cycle) rotated 90
+enddef ;
+
+vardef squarepath primary n =
+ for i=0 step 1/n until 4-1/n + 2eps: point i of fullsquare -- endfor cycle
+enddef ;
+
+vardef linearpath primary n =
+ origin for i=1/n step 1/n until 1-1/n + 2eps: -- point i of (origin--(1,0)) endfor
+enddef ;
+
+%D A nice tracing helper:
+
+color pensilcolor ; pensilcolor := .5red ;
+newinternal pensilstep ; pensilstep := 1/25 ;
+
+vardef pensilled(expr p, q) =
+ image (
+ draw p withcolor pensilcolor withpen q ;
+ for i = 0 step pensilstep until length(p) + eps:
+ draw point i of p withcolor white withtransparency (1,.5) withpen q ;
+ endfor ;
+ )
+enddef ;
+
+%D Easy to forget but handy for manuals:
+
+vardef tolist(suffix l)(text t) =
+ save n ; n := 1 ;
+ for p = t :
+ if numeric p :
+ n := p ;
+ dispose(l[n])
+ elseif pair p :
+ l[n] := p ;
+ n := n + 1 ;
+ elseif path p :
+ for i=0 step 1 until length(p) :
+ l[n] := point i of p ;
+ n := n + 1 ;
+ endfor ;
+ else :
+ % ignore
+ fi ;
+ endfor ;
+ forever :
+ exitif unknown l[n] ;
+ dispose(l[n])
+ n := n + 1 ;
+ endfor ;
+enddef ;
+
+vardef topath(suffix p)(text t) =
+ save i ; i := if known p[1] : 2 ; p[1] elseif known p[0] : 1 ; p[0] else : 0 ; origin fi
+ forever :
+ exitif unknown p[i] ;
+ t p[i]
+ hide(i := i + 1)
+ endfor
+enddef ;
+
+vardef tocycle(suffix p)(text t) =
+ topath(p,t) t cycle
+enddef ;