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

% returns a pair suffix if the path is unknown

vardef makenode@#(suffix p)(text t) =
    save i, b ; numeric i ; string b ;
    for a = t :
        if unknown i : % first argument is the index
            i = a ;
            if isarray p :
                %
                % note that one needs to declare "path p[] ; picture p[]pic[] ;"
                % before calling node() if one is to use a pseudo-array for p
                % because "picture p1.pic[] ;" is not a valid syntax!
                %
                % The following works, but is a bit awkward...
                %
                b := prefix p ;
                if not picture p.pic[i] : scantokens("picture " & b & "[]pic[] ;") ; fi
                if not pair    p.pos[i] : scantokens("pair    " & b & "[]pos[] ;") ; fi
            else :
                if not picture p.pic[i] : picture p.pic[] ; fi
                if not pair    p.pos[i] : pair    p.pos[] ; fi
            fi
        else :
            if known p.pic[i] :
                addto p.pic[i] also
            else :
                p.pic[i] :=
            fi
            if     picture a           : a
            elseif string  a           : textext@#(a)
            elseif numeric a           : textext@#(decimal a)
            elseif ((boolean a) and a) : image(draw origin)
            else                       : nullpicture
            fi ;
        fi
    endfor
    p.pos[i] if known p : := point i of p ; fi
enddef ;

% returns a picture

vardef node@#(suffix p)(text t) =
    if pair makenode@#(p)(t) :
        % nop: gobble the function return.
    fi
    for a = t :
        if (unknown p) and (known p.pos[a]) :
            makenodepath(p) ;
        fi
        if known p.pic[a] :
            p.pic[a] if known p : shifted point a of p fi
        else :
            nullpicture
        fi
        exitif true ;
    endfor
enddef ;

% returns a path

vardef fromto@#(expr d)(suffix p)(expr f)(suffix q)(text s) =
    save r, t, l ;
    path r[] ; numeric t ; 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 ; numeric deviation ;
            deviation := if numeric d: d else: 0 fi ;
            r1 = if 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            : textext@#(a)
                 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 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 ; numeric t ;
    for a = s :
        if unknown t :
            t = a ;
            nodeboundingpoint@#(q,t) + nodeboundingpoint@#(p,f)
        else :
            + relative@#(a)
        fi
    endfor
enddef ;

% build a path from the node positions.
% Must be continuous in index starting at 0.

vardef makenodepath(suffix p) =
    if unknown p :
        save i ; i = -1 ;
        p = forever : exitif unknown p.pos[incr i] ;
                 p.pos[i] --
             endfor cycle ;
    fi
enddef ;

