%D \module %D [ file=mp-node.mpiv, %D version=1998.02.15, %D title=\CONTEXT\ \METAPOST\ graphics, %D subtitle=Node Based Graphics, %D author=Alan Braslau, %D date=\currentdate, %D copyright={Alan Braslau & \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. %D The crossing macros were written as part of this module but as they %D can be of use elsewhere they are defined in mp-tool. if known context_node : endinput ; fi ; boolean context_node ; context_node := true ; % Build a path from the node positions. % Must be integer and continuous in index starting at 0. vardef makenodepath(suffix p) = if unknown p : if not path p : d := dimension p ; if d>0 : scantokens("path " & prefix p & for i=1 upto d : "[]" & endfor " ;") ; else : path p ; fi fi save i ; i = -1 ; p = forever : exitif unknown p.pos[incr i] ; p.pos[i] -- endfor cycle ; fi enddef ; % can take a list: def clearpath text t = save t ; path t ; enddef ; def clearnodepath = clearpath nodepath enddef ; clearnodepath ; % the trailing "," below handles when number of t<3 vardef makenode@#(text t) = for a = t : if (path a) or (unknown a) : mfun_makenode@#(t,) elseif (string a) and (length(a) = 0) : mfun_makenode@#(t,) else : mfun_makenode@#(nodepath, t,) fi exitif true ; endfor enddef ; vardef node@#(text t) = for a = t : if (path a) or (unknown a) : mfun_node@#(t,) elseif (string a) and (length(a) = 0) : mfun_node@#(t,) else : mfun_node@#(nodepath, t,) fi exitif true ; endfor enddef ; vardef nodeboundingpoint@#(text t) = for a = t : if (path a) or (unknown a) : mfun_nodeboundingpoint@#(t) elseif (string a) and (length(a) = 0) : mfun_nodeboundingpoint@#(t) else : mfun_nodeboundingpoint@#(nodepath,a) fi exitif true ; endfor enddef ; vardef fromto@#(expr d, f)(text t) = fromtopaths@#(d,nodepath,f,nodepath,t) enddef ; % returns a pair suffix if the path is unknown vardef mfun_makenode@#(suffix p)(expr i)(text t) = save d, b ; string b ; d = dimension p ; if d > 0 : b := prefix p ; if not picture p.pic[i] : scantokens("picture " & b & for j=1 upto d : "[]" & endfor "pic[] ;") ; fi if not pair p.pos[i] : scantokens("pair " & b & for j=1 upto d : "[]" & endfor "pos[] ;") ; fi else : if not picture p.pic[i] : picture p.pic[] ; fi if not pair p.pos[i] : pair p.pos[] ; fi fi for a = t : if known p.pic[i] : addto p.pic[i] also else : p.pic[i] = fi if picture a : a elseif string a : if (length(a) > 0) : textext@#(a) else : nullpicture fi elseif numeric a : textext@#(decimal a) elseif ((boolean a) and a) : image(draw origin withpen currentpen scaled 4) else : nullpicture fi ; endfor p.pos[i] if known p : := point i of p ; fi enddef ; % returns a picture vardef mfun_node@#(suffix p)(expr i)(text t) = if pair mfun_makenode@#(p,i,t) : % nop: enclose in "if ... fi" to gobble the function return. fi if (unknown p) and (known p.pos[i]) : makenodepath(p) ; fi if known p.pic[i] : p.pic[i] if known p : shifted point i of p fi else : nullpicture fi enddef ; newinternal node_loopback_yscale ; node_loopback_yscale := 1 ; % returns a path vardef fromtopaths@#(expr d)(suffix p)(expr f)(suffix q)(text s) = save r, t, l ; path r[] ; picture l ; for a = s : if unknown t : t = a ; if (unknown p) and (known p.pos[f]) : makenodepath(p) ; fi if (unknown q) and (known q.pos[t]) : makenodepath(q) ; fi r0 = if ((not numeric d) and (point f of p = point f of q) and (point t of p = point t of q)) : subpath (f,t) of p else : point f of p -- point t of q fi ; save deviation ; deviation := if numeric d: d else: 0 fi ; r1 = if (point 0 of r0) = (point length r0 of r0) : (fullcircle yscaled node_loopback_yscale rotated 180 if mfun_laboff@# <> origin : rotated angle mfun_laboff@# shifted .5mfun_laboff@# fi) scaled deviation shifted point 0 of r0 elseif deviation=0 : r0 else : point 0 of r0 .. unitvector direction .5length r0 of r0 rotated 90 scaled deviation * arclength r0 shifted point .5length r0 of r0 .. point length r0 of r0 fi ; else : if known l : addto l also else : l := fi if picture a : a elseif string a : if (length(a) > 0) : textext@#(a) else : nullpicture fi elseif numeric a : textext@#(decimal a) elseif ((boolean a) and a) : image(draw origin withpen currentpen scaled 4) else : nullpicture fi ; fi endfor r2 = r1 if known p.pic[f if cycle p: mod length p fi] : cutbefore boundingbox (p.pic[f if cycle p: mod length p fi] shifted point f of p) fi if known q.pic[t if cycle q: mod length q fi] : cutafter boundingbox (q.pic[t if cycle q: mod length q fi] shifted point t of q) fi ; if known l : l := l shifted point .5length r2 of r2 ; draw l ; (r2 if str @# = "" : crossingunder l fi) else : r2 fi enddef ; % returns pair: bounding point of the node picture vardef mfun_nodeboundingpoint@#(suffix p)(expr i) = if known p.pic[i] : boundingpoint@#(p.pic[i]) else : origin fi enddef ; % returns pair: scaled laboff direction vardef relative@#(expr s) = (mfun_laboff@# scaled s) enddef ; % returns pair: vector between nodes (+ optional scale) vardef betweennodes@#(suffix p)(expr f)(suffix q)(text s) = save t ; for a = s : if unknown t : t = a ; mfun_nodeboundingpoint@#(q,t) + mfun_nodeboundingpoint@#(p,f) else : + relative@#(a) fi endfor enddef ; % helpers that save passing tokens def mfun_node_init(expr dx, dy, da) = save nodelattice ; pair nodelattice[] ; nodelattice0 = (dx,0) ; nodelattice1 = dy * dir(da) ; clearnodepath ; save nodecount ; nodecount = -1; enddef ; def mfun_node_make(expr x, y, s) = nodecount := nodecount + 1 ; makenode(nodecount,s) = x * nodelattice0 + y * nodelattice1 ; enddef ; def mfun_node_flush = for i=0 upto nodecount: draw node(i) ; endfor enddef ; vardef mfun_nodes_fromto@#(expr d, f)(text t) = fromtopaths@#(d,nodepath,f,nodepath,t) enddef ;