%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 ;