diff options
Diffstat (limited to 'graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex')
-rw-r--r-- | graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex | 1165 |
1 files changed, 1165 insertions, 0 deletions
diff --git a/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex new file mode 100644 index 0000000000..63efd352f1 --- /dev/null +++ b/graphics/pgf/base/tex/generic/graphdrawing/tex/pgflibrarygraphdrawing.code.tex @@ -0,0 +1,1165 @@ +% Copyright 2018 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster +% Copyright 2018 by Till Tantau +% +% This file may be distributed and/or modified +% +% 1. under the LaTeX Project Public License and/or +% 2. under the GNU Public License. +% +% See the file doc/generic/pgf/licenses/LICENSE for more details. + +\ProvidesFileRCS{pgflibrarygraphdrawing.code.tex} + + + +% check if luatex is running + +\ifx\directlua\relax% + \pgferror{You need to run LuaTeX to use the graph drawing library} + \expandafter\endinput +\fi +\ifx\directlua\undefined% + \pgferror{You need to run LuaTeX to use the graph drawing library} + \expandafter\endinput +\fi + + + + +% +% All graph drawing keys normally live in the following namespace: +% /graph drawing. +% + +\def\pgfgdset{\pgfqkeys{/graph drawing}}% + + +% Setup a key +% +% #1 = key +% +% Description: +% +% An internal macro that sets up #1 as a graph drawing key. + +\def\pgfgd@callbackkey#1{% + \pgf@gd@setup@forwards{#1}% + \pgfutil@g@addto@macro\pgf@gd@forwards@list{\pgf@gd@setup@forwards{#1}}% +}% +\def\pgf@gd@setup@forwards#1{% + \let\pgf@temp\pgfutil@empty + \foreach \pgf@gd@path in \pgf@gd@forwarding@list {% + \ifx\pgf@gd@path\pgfutil@empty\else% + \expandafter\pgfutil@g@addto@macro% + \expandafter\pgf@temp\expandafter{% + \expandafter\pgfkeys\expandafter{\pgf@gd@path#1/.forward to=/graph drawing/#1}}% + \fi% + }% + \pgf@temp +}% + +\let\pgf@gd@forwards@list\pgfutil@empty + + +% Append to the forwarding list: +% +% #1 = paths to append to the forwarding list +% +% Description: +% +% Append the paths in #1 (with trailing slashes) to the forwarding +% list. +% +% If algorithms have already been declared, forwarding will also be +% setup for them (using a bit of magic...). + +\def\pgfgdappendtoforwardinglist#1{% + \let\pgf@gd@forwarding@list@orig\pgf@gd@forwarding@list + \def\pgf@gd@forwarding@list{#1}% + \pgf@gd@forwards@list% + \expandafter\def\expandafter\pgf@gd@forwarding@list\expandafter{\pgf@gd@forwarding@list@orig,#1}% +}% +\let\pgf@gd@forwarding@list\pgfutil@empty + + + +% +% +% Callbacks +% +% The following macros are called *from* the binding layer. You do not +% call them from the pgf layer. +% +% + + +% Callback for declaring a graph parameter key +% +% #1 = Parameter key +% #2 = Parameter type +% +% Description: +% +% When a graph drawing algorithm starts working, a set of options, +% called "graph drawing parameters" in the following, can influence the +% way the algorithm works. For instance, an graph drawing parameter +% might be the average distance between vertices which the algorithm +% should take into account. Another example might be the fact the +% certain nodes are special nodes and that a certain edge should have +% a large label. +% +% These graph drawing parameters are different from "usual" pgf +% options: An algorithmic parameter influenced the way the algorithm +% works, while usual options normally only influence how the result +% looks like. For instance, the fact that a node is red is not an +% graph drawing parameter (usually, at least), while the shape of a node +% might be an graph drawing parameter. +% +% Graph drawing parameters are declared by the algorithmic layer +% (since only this layer "knows" which parameters there are). The +% binding to TeX will call the \pgfgddeclareparameter function +% internally. +% +% Specifying the set of graph drawing parameters for a given graph or +% node or edge works as follows: When the graph drawing engine is +% started for a graph (using \pgfgdbeginscope), a snapshot is taken of +% all graph drawing parameters currently setup at this +% point. Similarly, when a node is created inside such a scope, a +% snapshot is taken of the set of all graph drawing parameters in +% force at this point is taken and stored together with the +% node. Finally, when an edge is created, a snapshot of the setting of +% the graph drawing parameters is taken. + +\def\pgfgdcallbackdeclareparameter#1#2{% + \pgfkeysdef{/graph drawing/#1}{\pgf@gd@handle@parameter{#1}{#2}{##1}}% + \pgfgd@callbackkey{#1}% +}% +\def\pgf@gd@handle@parameter#1#2#3{% + \def\pgf@temp{#3}% + \ifx\pgf@temp\pgfkeysnovalue@text% + \let\pgfgdresult\pgfgd@niltext% + \else% + \pgfkeys{/graph drawing/conversions/#2={#3}}% + \fi% + \advance\pgf@gd@parameter@stack@height by1\relax% + \pgf@gd@parameter@stack@height\directlua{% + local new, main = pgf.gd.interface.InterfaceToDisplay.pushOption('\pgfutil@luaescapestring{#1}',\pgfgdresult,\the\pgf@gd@parameter@stack@height) + tex.print(new..'\pgfutil@luaescapestring{\relax}') + if main then + tex.print('\pgfutil@luaescapestring{\noexpand\pgfgdtriggerrequest}') + end}% +}% +\newcount\pgf@gd@parameter@stack@height + +\def\pgfgdtriggerrequest{\pgfgdset{@request scope and layout}}% + + +% Conversions are used to adapt the syntactic description of a +% parameter on the TikZ layer to the one expected by Lua. The set of +% permissible conversions is described in +% InterfaceToAlgorithms.declareParameter. + +\pgfgdset{ + conversions/string/.code=\def\pgfgdresult{'\pgfutil@luaescapestring{\detokenize{#1}}'}, + conversions/raw/.code=\def\pgfgdresult{#1}, + conversions/nil/.code=\let\pgfgdresult\pgfgd@niltext, + conversions/boolean/.code=\def\pgf@test{#1}\ifx\pgf@test\pgf@truetext\def\pgfgdresult{true}\else\ifx\pgf@test\pgfkeysnovalue@text\def\pgfgdresult{true}\else\def\pgfgdresult{false}\fi\fi, + conversions/number/.code=\pgfmathparse{#1}\let\pgfgdresult\pgfmathresult, + conversions/length/.code=\pgfmathparse{#1}\let\pgfgdresult\pgfmathresult, + conversions/time/.code=\pgfparsetime{#1}\let\pgfgdresult\pgftimeresult, + conversions/direction/.code=\pgf@lib@gd@grow@dir{#1}\let\pgfgdresult\pgfmathresult, + conversions/canvas coordinate/.code args={(#1pt,#2pt)}{\edef\pgfgdresult{pgf.gd.model.Coordinate.new(#1,#2)}}, + % deprecated, will be removed: + conversions/coordinate/.code args={(#1pt,#2pt)}{\edef\pgfgdresult{{#1,#2}}} +}% +\def\pgf@truetext{true}% +\def\pgfgd@niltext{nil}% + +\def\pgf@lib@gd@grow@dir#1{% + \def\pgf@temp{#1}% + \ifx\pgf@temp\pgf@gd@lib@active@bar% + \def\pgfmathresult{-90} + \else% + \ifcsname pgf@orient@direction@#1\endcsname% + \expandafter\let\expandafter\pgfmathresult\csname pgf@orient@direction@#1\endcsname% + \else + \pgfmathparse{#1}% + \fi + \fi +}% + +\def\pgf@orient@direction@down{-90}% +\def\pgf@orient@direction@up{90}% +\def\pgf@orient@direction@left{180}% +\def\pgf@orient@direction@right{0}% + +\def\pgf@orient@direction@south{-90}% +\def\pgf@orient@direction@north{90}% +\def\pgf@orient@direction@west{180}% +\def\pgf@orient@direction@east{0}% + +\expandafter\def\csname pgf@orient@direction@north east\endcsname{45}% +\expandafter\def\csname pgf@orient@direction@north west\endcsname{135}% +\expandafter\def\csname pgf@orient@direction@south east\endcsname{-45}% +\expandafter\def\csname pgf@orient@direction@south west\endcsname{-135}% + +\expandafter\def\csname pgf@orient@direction@-\endcsname{0}% +\expandafter\def\csname pgf@orient@direction@|\endcsname{-90}% + +{% + \catcode`\|=13 + \gdef\pgf@gd@lib@active@bar{|}% +}% + + + + + +% Callback for starting the rendering of a collection kind +% +% #1 = Kind +% #2 = Layer +% +% Description: +% +% Executes /graph drawing/#1/begin rendering/.try +% + +\def\pgfgdcallbackrendercollectionkindstart#1#2{% + \ifnum#2<0\relax + \setbox\pgf@gd@prekind@box=\hbox\bgroup% + \unhbox\pgf@gd@prekind@box% + \else% + \setbox\pgf@gd@postkind@box=\hbox\bgroup% + \unhbox\pgf@gd@postkind@box% + \fi% + \pgfgdset{/graph drawing/#1/begin rendering/.try}% +}% + +% Callback for ending the rendering of a collection kind +% +% #1 = Kind +% #2 = Layer +% +% Description: +% +% Executes /graph drawing/#1/end rendering/.try +% + +\def\pgfgdcallbackrendercollectionkindstop#1#2{% + \pgfgdset{/graph drawing/#1/end rendering/.try}% + \egroup % close box +}% + + + +% Callback for rendering a collection +% +% #1 = Kind +% #2 = Options +% +% Description: +% +% Executes /graph drawing/#1/render/.try={#2} +% + +\def\pgfgdcallbackrendercollection#1#2{ + \pgfgdset{/graph drawing/#1/render/.try={#2}} +}% + + + + + +% Graph events +% +% Although a graph consists of nodes and edges, during the +% construction of the graph a lot of information concerning the +% structure of the graph is often available. For instance, as we +% specify a graph using the child-syntax, we do not only which edges +% are present, but we can implicitly specify an ordering on the +% nodes. Even more, there is even information available concerning +% nodes that are not present at all: A child[missing] is not present +% as a node or an edge, but a tree drawing algorithm will want to know +% about this child nevertheless. +% +% In order to communicate such information to the graph drawing +% engine, "events" are used. As a graph is created, in addition to +% nodes and edges, "events" may happen. The events come in a +% sequential order and they are stored together with the graph. For +% each node and each edge, its index in the event sequence is +% stored, that is, it is stored how many events happened before the +% node or edge was created. +% +% Internally, an event consists of a name and, possibly, some +% parameters. When the parameter is created on the tikz level, it will +% be a string that is passed down to Lua. Internally created events +% will also have parameters that are objects. +% +% Two events are a bit special since they get special internal +% support: The begin and end events. The first signals that some kind +% of group has started; which is closed by the corresponding end +% event. The "kind" of group is indicated by the parameter of the +% begin event. +% +% +% +% Standard events are: +% +% For each node entered into a graph, a "node" event is automatically +% created internally with the parameter being the node. However, you +% can also create this event yourself. In this case, the parameter +% will be a string and will mean that the node is "virtual" or +% "missing", but space should be reserved for it, if possible (this is +% use, for instance, by certain tree layouts). +% +% For each edge entered into a graph, an "edge" event is automatically +% created, with the edge as the parameter. Again, an event with a +% string parameter corresponds to a "non-existing" node. +% +% +% Standard event groups are: +% +% +% The "descendants" event group include a set of nodes that, at least +% inside the specification, are descendants of the last node +% +% begin descendants +% ... +% end +% +% +% The "array" event group collects together some nodes in an array of +% nodes. This can be used, for instance, to specify matrices. +% +% begin array +% ... +% end + + + +% Create a new event +% +% #1 = event name (should be a valid lua identifier name) +% #2 = parameter (some text) +% +% Description: +% +% Adds a new event to the event sequence of the graph + +\def\pgfgdevent#1#2{% + \directlua{pgf.gd.interface.InterfaceToDisplay.createEvent('\pgfutil@luaescapestring{#1}', '\pgfutil@luaescapestring{#2}')}% +}% + + +% Start an event group +% +% #1 = kind of event group +% +% Description: +% +% Creates a begin event with #1 as the parameter of the begin +% event. + +\def\pgfgdbegineventgroup#1{% + \pgfgdevent{begin}{#1}% +}% + +% End an event group +% +% Description: +% +% Creates an end event. + +\def\pgfgdendeventgroup{% + \pgfgdevent{end}{}% +}% + + +% Creates an event group for the current TeX group +% +% #1 = event group name +% +% Description: +% +% Issues a begin event for #1 and, using \aftergroup, adds an end +% event at the end of the current tex group. + +\def\pgfgdeventgroup#1{% + \pgfgdbegineventgroup{#1}% + \aftergroup\pgfgdendeventgroup% +}% + + + + + +% +% Nodes +% + + + +% +% Callback method for \pgfpositionnodelater +% +% This function is called by \pgfnode whenever a node has been newly +% created inside a graph drawing scope. It will create a new vertex on +% the Lua layer. +% +\def\pgf@gd@positionnode@callback{% + {% + % evaluate coordinates + \pgfmathsetmacro{\pgf@gd@node@minx}{\pgfpositionnodelaterminx}% + \pgfmathsetmacro{\pgf@gd@node@miny}{\pgfpositionnodelaterminy}% + \pgfmathsetmacro{\pgf@gd@node@maxx}{\pgfpositionnodelatermaxx}% + \pgfmathsetmacro{\pgf@gd@node@maxy}{\pgfpositionnodelatermaxy}% + % Assemble the Path object: + \directlua{pgf.temp = require 'pgf.gd.model.Path'.new ()}% + \let\pgfsyssoftpath@movetotoken\pgf@gd@movetotoken% + \let\pgfsyssoftpath@linetotoken\pgf@gd@linetotoken% + \let\pgfsyssoftpath@rectcornertoken\pgf@gd@rectcornertoken% + \let\pgfsyssoftpath@curvetosupportatoken\pgf@gd@curvetosupportatoken% + \let\pgfsyssoftpath@closepathtoken\pgf@gd@closepathtoken% + \pgfpositionnodelaterpath% + % + \pgfmathsetlength\pgf@xa{\pgfkeysvalueof{/pgf/outer xsep}}% + \pgfmathsetlength\pgf@ya{\pgfkeysvalueof{/pgf/outer ysep}}% + % + {% + \pgf@process{\pgfpointanchor{\pgfpositionnodelatername}{center}} + \pgfsettransform{\csname pgf@sh@nt@\pgfpositionnodelatername\endcsname}% + \pgf@pos@transform{\pgf@x}{\pgf@y}% + \global\pgf@x=\pgf@x% + \global\pgf@y=\pgf@y% + }% + % call lua system library to create a lua node object + \directlua{ + pgf.gd.interface.InterfaceToDisplay.createVertex( + string.sub('\pgfutil@luaescapestring{\pgfpositionnodelatername}',30), % strip "not yet positionedPGFINTERNAL" + '\pgfutil@luaescapestring{\csname pgf@sh@ns@\pgfpositionnodelatername\endcsname}', + pgf.temp:pad((\pgf@sys@tonumber\pgf@xa+\pgf@sys@tonumber\pgf@ya)/2), % Padded path + \the\pgf@gd@parameter@stack@height, % Stack height + {% Binding info + x_min = \pgf@gd@node@minx, + y_min = \pgf@gd@node@miny, + x_max = \pgf@gd@node@maxx, + y_max = \pgf@gd@node@maxy, + tex_box_number = \pgfpositionnodelaterbox + }, + {% Anchors + center = require 'pgf.gd.model.Coordinate'.new(\pgf@sys@tonumber\pgf@x,\pgf@sys@tonumber\pgf@y) + } + ) + pgf.temp = nil + } + }% +}% + + +\def\pgf@gd@movetotoken#1#2{\directlua{pgf.temp:appendMoveto(\Pgf@geT#1,\Pgf@geT#2)}}% +\def\pgf@gd@linetotoken#1#2{\directlua{pgf.temp:appendLineto(\Pgf@geT#1,\Pgf@geT#2)}}% +\def\pgf@gd@rectcornertoken#1#2#3#4#5{% + \directlua{% + local x,y,dx,dy=\Pgf@geT#1,\Pgf@geT#2,\Pgf@geT#4,\Pgf@geT#5 + pgf.temp:appendMoveto(x,y) + pgf.temp:appendLineto(x,y+dy) + pgf.temp:appendLineto(x+dx,y+dy) + pgf.temp:appendLineto(x+dx,y) + pgf.temp:appendClosepath()% + }% +}% +\def\pgf@gd@curvetosupportatoken#1#2#3#4#5#6#7#8{\directlua{pgf.temp:appendCurveto(\Pgf@geT#1,\Pgf@geT#2,\Pgf@geT#4,\Pgf@geT#5,\Pgf@geT#7,\Pgf@geT#8)}}% +\def\pgf@gd@closepathtoken#1#2{\directlua{pgf.temp:appendClosepath()}}% + + +% Set options for an already existing node +% +% #1 = node name +% +% These node parameters of #1 will be updated with the current values +% of the node parameters. The node #1 must previously have been passed +% to the gd engine. If some of the options have already been set for +% the node, these settings will be overruled. + +\def\pgfgdsetlatenodeoption#1{% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.addToVertexOptions('\pgfutil@luaescapestring{#1}',\the\pgf@gd@parameter@stack@height) + } +}% + + + +% +% A callback for rendering (finally positioning) a node +% +% #1 = name of the node +% #2 = x min of the bounding box +% #3 = x max of the bounding box +% #4 = y min of the bounding box +% #5 = y max of the bounding box +% #6 = desired x pos of the node +% #7 = desired y pos of the node +% #8 = box register number of the TeX node +% #9 = animation code +% +% This callback will be called by the engine for every original node +% when it finally needs to placed at a final position. + +\def\pgfgdcallbackrendernode#1#2#3#4#5#6#7#8#9{% + {% + \def\pgfpositionnodelatername{#1} + \def\pgfpositionnodelaterminx{#2} + \def\pgfpositionnodelatermaxx{#3} + \def\pgfpositionnodelaterminy{#4} + \def\pgfpositionnodelatermaxy{#5} + \directlua{pgf.gd.interface.InterfaceCore.binding:retrieveBox(#8,\pgfpositionnodelaterbox)} + \def\pgf@temp{#9}% + \ifx\pgf@temp\pgfutil@empty% + \pgfpositionnodenow{\pgfqpoint{#6}{#7}}% + \else% + \pgfset{every graphdrawing animation/.try}% + \pgfset{every graphdrawing node animation/.try}% + #9% + \pgfuseid{pgf@gd}% + \pgfidscope% + \pgfpositionnodenow{\pgfqpoint{#6}{#7}}% + \endpgfidscope% + \fi% + }% +}% + +\ifx\pgfanimateattribute\pgfutil@undefined + \def\pgfanimateattribute#1#2{\tikzerror{You need to say \string\usetikzlibrary{animations} for animated graphs}}% +\fi + + +% Adds an edge to the graph +% +% #1 = first node +% #2 = second node +% #3 = edge direction +% #4 = edge options (will be executed in a protected environment) +% #5 = aux stuff (curtesy for TikZ -- edge nodes) +% +% Description: +% +% Creating an edge means that you tell the graph drawing algorithm +% that #1 and #2 are connected. The "kind" of connection is indicated +% by #3, which may be one of the following: +% +% -> = a directed edge (also known as an arc) from #1 to #2 +% -- = an undirected edge between #1 and #2 +% <- = a directed edge from #2 to #1, but with the "additional hint" +% that this is a "backward" edge. A graph drawing algorithm may +% or may not take this hint into account +% <-> = a bi-directed edge between #1 and #2. +% +% +% The parameters #4 and #5 are a bit more tricky. When an edge between +% two vertices of a graph is created via \pgfgdedge, nothing is +% actually done immediately. After all, without knowing the final +% positions of the nodes #1 and #2, there is no way of +% creating the actual drawing commands for the edge. Thus, the actual +% drawing of the edge is done only when the graph drawing algorithm is +% done (namely in the macro \pgfgdcallbackedge, see later). +% +% Because of this "delayed" drawing of edges, options that influence +% the edge must be retained until the moment when the edge is actually +% drawn. Parameters #4 and #5 store such options. +% +% Let us start with #4. This parameter should be set to a list of +% key-value pairs like +% +% /tikz/.cd, color=red, very thick, this edge must be vertical +% +% Some of these options may be of interest to the graph drawing +% algorithm (like the last option) while others will +% only be important during the drawing of edge (like the first +% option). The options that are important for the graph drawing +% algorithm must be passed to the algorithm via setting keys that have +% been declared using the handler .edge parameter (see +% above). +% +% The tricky part is that options that are of interest to the graph +% drawing algorithm must be executed *before* the algorithm starts, +% but the options as a whole are usually only executed during the +% drawing of the edges, which is *after* the algorithm has finished. +% +% To overcome this problem, the following happens: +% +% The options in #4 are executed "tentatively" inside +% \pgfgdedge. However, this execution is done in a "heavily guarded +% sandbox" where all effects of the options (like changing the +% color or the line width) do not propagate beyond the sandbox. Only +% the changes of the graph drawing edge parameters leave the +% sandbox. These parameters are then passed down to the graph drawing +% engine. +% +% Later, when the edge is drawn using \pgfgdcallbackedge, the options #4 +% are available once more and then they are executed normally. +% +% Note that when the options in #4 are executed, no path is +% preset. Thus, you typically need to start it with, say, /tikz/.cd. +% +% +% The text in #5 is some "auxiliary" text that is simply stored away +% and later directly to \pgfgdcallbackedge. This is a curtesy to TikZ, +% which can use it to store its node labels. +% +% Example: +% +% \pgfgdedge{A}{B}{->}{red}{} +% +\def\pgfgdedge#1#2#3#4#5{% + % Ok, setup sandbox + \begingroup% + \setbox0=\hbox{{% + \pgfinterruptpath% + \pgfgdprepareedge% + \pgfkeys{#4}% + % create edge in Lua + \toks0={#4}% + \toks1={#5}% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.createEdge( + '\pgfutil@luaescapestring{#1}','\pgfutil@luaescapestring{#2}','\pgfutil@luaescapestring{#3}', + \the\pgf@gd@parameter@stack@height, + { pgf_options = '\pgfutil@luaescapestring{\the\toks0}', + pgf_edge_nodes = '\pgfutil@luaescapestring{\the\toks1}', + }) + }% + \endpgfinterruptpath% + }}% + \endgroup% +}% + +\let\pgfgdprepareedge=\pgfutil@empty +\def\pgfgdaddprepareedgehook#1{\expandafter\def\expandafter\pgfgdprepareedge\expandafter{\pgfgdprepareedge#1}}% + + +\newif\ifpgf@gd@nodes@behind@edges + + + +% Define a callback for rendering edges +% +% #1 = macro name +% +% Descriptions: +% +% This is a callback from the graph drawing engine. At the end of the +% creation of a graph, when the nodes have been positioned, this macro +% is called once for each edge. The macro should take the following +% parameters: +% +% #1 = from node, optionally followed by "." and the tail anchor +% #2 = to node, optionally followed by "." and the head anchor +% #3 = direction (<-, --, ->, or <->) +% #4 = original options +% #5 = aux text (typically edge nodes) +% #6 = algorithm-generated options +% #7 = bend information +% #8 = animations +% +% The first five parameters are the original values that were passed +% down to the \pgfgdedge command. +% +% #6 contains options that have been "computed by the algorithm". For +% instance, an algorithm might have determined, say, flow capacities +% for edges and it might now wish to communicate this information back +% to the upper layers. These options should be executed with the path +% /graph drawing. +% +% #7 contains algorithmically-computed information concerning how the +% edge should bend. This will be a text like +% "--(10pt,20pt)--(30pt,40pt)" in tikz-syntax, using the path +% operations "--", "..controls" and "--cycle". +% +% By default, a simple line is drawn between the nodes. Usually, you +% will wish to install a more "fancy" callback, here. + +\def\pgfgdsetedgecallback#1{\let\pgfgdcallbackedge=#1}% + +\def\pgfgddefaultedgecallback#1#2#3#4#5#6#7#8{% + {% + \def\pgf@temp{#8}% + \ifx\pgf@temp\pgfutil@empty% + \else% + \pgfset{every graphdrawing animation/.try}% + \pgfset{every graphdrawing edge animation/.try}% + #8% + \pgfuseid{pgf@gd}% + \pgfidscope% + \fi% + \pgfscope + \pgfpathmoveto{ + \pgfutil@in@.{#1}% + \ifpgfutil@in@ + \pgf@gd@unravel#1\relax% + \else + \pgfpointshapeborder{#1}{\pgfpointanchor{#2}{center}} + \fi + } + \pgfpathlineto{ + \pgfutil@in@.{#2}% + \ifpgfutil@in@ + \pgf@gd@unravel#2\relax% + \else + \pgfpointshapeborder{#2}{\pgfpointanchor{#1}{center}} + \fi + } + \pgfusepath{stroke} + \endpgfscope + \ifx\pgf@temp\pgfutil@empty% + \else% + \endpgfidscope% + \fi% + } +}% + +\pgfgdsetedgecallback{\pgfgddefaultedgecallback}% + +\def\pgf@gd@unravel#1.#2\relax{% + \pgfpointanchor{#1}{#2}% +}% + + + + +% Callbacks: Called before the shipout of nodes and edges starts +% +% First, the general begin shipout is called. Then, the node shipout +% starts, the nodes are created, and then the end of the node shipout +% is signaled. Next, the edge shipout starts and ends. Finally, the +% end shipout is called. + +\def\pgfgdcallbackbeginshipout{% + \pgfscope% + \catcode`\@=11\relax% + \setbox\pgf@gd@prekind@box=\box\pgfutil@voidb@x% + \setbox\pgf@gd@postkind@box=\box\pgfutil@voidb@x% +}% +\def\pgfgdcallbackendshipout{% + \box\pgf@gd@prekind@box% + \ifpgf@gd@nodes@behind@edges% + \box\pgf@gd@node@box% + \box\pgf@gd@edge@box% + \else% + \box\pgf@gd@edge@box% + \box\pgf@gd@node@box% + \fi% + \box\pgf@gd@postkind@box% + \endpgfscope +}% + +\newbox\pgf@gd@node@box +\newbox\pgf@gd@edge@box +\newbox\pgf@gd@prekind@box +\newbox\pgf@gd@postkind@box + +\def\pgfgdcallbackbeginnodeshipout{% + \setbox\pgf@gd@node@box=\hbox\bgroup% +}% +\def\pgfgdcallbackendnodeshipout{% + \egroup% +}% + +\def\pgfgdcallbackbeginedgeshipout{% + \setbox\pgf@gd@edge@box=\hbox\bgroup% +}% + +\def\pgfgdcallbackendedgeshipout{% + \egroup +}% + + + + +% Generate a node +% +% This callback is called from the engine whenever an algorithm +% generates a new node internally. +% +% #1 = name of the node +% #2 = shape of the node +% #3 = options generated by the algorithm in key-value syntax. The set +% of generated options is algorithm-dependent. +% #4 = text +% +% This is an internal function and will be called by the binding layer + +\def\pgfgdcallbackcreatevertex#1#2#3#4{% + { + \pgfkeys{#3} + \pgfnode{#2}{\pgfkeysvalueof{/graph drawing/generated + node/anchor}}{#4}{#1}{\pgfkeysvalueof{/graph drawing/generated + node/use path}} + } +}% + +\pgfkeys{ + /graph drawing/generated node/anchor/.initial=center, + /graph drawing/generated node/use path/.initial=\pgfusepath{} +}% + + + +% +% Sublayouts +% +% Description: For a general introduction to (sub)layouts, see +% Section~\ref{section-gd-sublayouts} in the manual. +% + +\def\pgfgdbeginlayout{ + \begingroup + \pgfgdlayoutscopeactivetrue + \advance\pgf@gd@parameter@stack@height by1\relax% + \directlua{pgf.gd.interface.InterfaceToDisplay.pushLayout(\the\pgf@gd@parameter@stack@height)} +}% + +\def\pgfgdendlayout{ + \endgroup% +}% + + + + +% Creates a subgraph node +% +% #1 = name +% #2 = node options +% #3 = node text +% +% Description: +% +% A subgraph node is a node that "surrounds" the nodes of a +% subgraph. The special property of a subgraph node opposed to a +% normal node is that it is created only after the subgraph has been +% laid out. However, the difference to a collection like "hyper" is +% that the node is available immediately as a normal node in the sense +% that you can connect edges to it. +% +% What happens internally is that subgraph nodes get "registered" +% immediately both on the pgf level and on the lua level, but the +% actual node is only created inside the layout pipeline using a +% callback. The actual node creation happens when the innermost layout +% in which the subgraph node is declared has finished. +% +% When you create a subgraph node using this macro, you also start a +% collection (of an internal kind) that stores the subgraph. All +% following nodes in the current TeX scope will become part of this +% collection. +% +% See |InterfaceToDisplay.pushSubgraphVertex| for details. + +\def\pgfgdsubgraphnode#1#2#3{% + \advance\pgf@gd@parameter@stack@height by1\relax% + {% + % create edge in Lua + \toks0={#2}% + \toks1={#3}% + \directlua{pgf.gd.interface.InterfaceToDisplay.pushSubgraphVertex% + ('\pgfutil@luaescapestring{#1}',\the\pgf@gd@parameter@stack@height, + { + shape = 'rectangle', % typically overwritten by the pgf_options: + pgf_options = '\pgfutil@luaescapestring{\the\toks0}', + text = '\pgfutil@luaescapestring{\the\toks1}', + }) + }% + } +}% + +\def\pgfgdsubgraphnodecontents#1{% helper function + \hbox to \pgfkeysvalueof{/graph drawing/subgraph bounding box width}{% + \vrule width0pt height\pgfkeysvalueof{/graph drawing/subgraph bounding box height}\hfil}% +}% + +\pgfgdset{ + subgraph point cloud/.initial=, + subgraph bounding box width/.initial=, + subgraph bounding box height/.initial=, +}% + + +% +% Requests +% +% Description: +% +% This key is used to ``request'' a graph drawing scope and a +% layout. The objective of this key is to make it easier for users and +% algorithm designers to control the slightly involved +% back-and-forth-calling between the different layers. +% +% This key does the following: When called inside a pgfpicture +% (otherwise, the call is "illegal"), it will call a call-back with +% two parameters. This callback will get passed some code that should +% be executed at the beginning of ``the next scope'' and some code +% that should be executed at the end of that scope. +% +% The code passed to the callbacks will have a different effect, +% depending on whether we are currently inside a layout scope or not +% (if no graph drawing scope is open, we are +% not inside a layout). If we are not inside a layout scope (or if the +% layout scope has been interrupted), the code will issue a +% \pgfgdbeginscope command in the opening code and a corresponding +% scope ending command in the closing code. Next, the two code pieces +% always contain \pgfgdbeginlayout and \pgfgdendlayout. +% +% Note that the "@request scope and layout" key will not immediately +% trigger a layout scope to be created; rather, the TikZ callback will +% call it only at the beginning of the scope, which will be after +% other options in the current list of options have been parsed. So, +% when you write \graph [binary tree layout, significant sep=2em] ..., +% the "significant sep" option has an effect despite being given +% *after* the "@request scope and layout" key since the actual opening +% of the scope happens only before the "..." part is parsed. + +\pgfgdset{@request scope and layout/.code=\pgfgd@requestcallback{\pgfgdbeginrequest}{\pgfgdendrequest}}% + +\def\pgfgd@requestcallback#1#2{% + #1\def\pgf@gd@after@request{#2\egroup}\bgroup\aftergroup\pgf@gd@after@request% +}% Default for basic layer + +\def\pgfgdbeginrequest{% + \ifpgfgdlayoutscopeactive% + \else% + \expandafter\pgfgdbeginscope% + \fi% + \pgfgdbeginlayout% +}% +\def\pgfgdendrequest{% + \pgfgdendlayout% + \ifpgfgdlayoutscopeactive% + \else% + \expandafter\pgfgdendscope% + \fi% +}% +\newif\ifpgfgdlayoutscopeactive + + +% Set the request callback +% +% #1 = A macro +% +% Description: +% +% Sets the request callback as described in the "@request scope and +% layout" key. + +\def\pgfgdsetrequestcallback#1{\let\pgfgd@requestcallback#1}% + + + + +% +% An if that is true exactly if we are inside a graph drawing scope +% + +\newif\ifpgfgdgraphdrawingscopeactive + + +% Begins a new graph drawing scope +% +% Description: +% +% Inside a graph drawing scope, all pgf nodes that are newly created +% are automatically passed to the graph drawing engine. In contrast, +% edges have to be indicated explicitly using the macro \pgfgdedge +% (this is because it is somewhat unclear what, exactly, should count +% as an edge). Naturally, users typically will not call \pgfgdedge +% explicitly, but have styles and keys invoke it internally. +% +% Usage: +% +% \pgfgdset{algorithm=somealgorithm} +% \pgfgdbeginscope +% \pgfnode{rectangle}{center}{A}{A}{} +% \pgfnode{rectangle}{center}{B}{B}{} +% \pgfnode{rectangle}{center}{C}{C}{} +% \pgfgdedge{A}{B}{->}{}{} +% \pgfgdedge{B}{C}{->}{}{} +% \pgfgdedge{C}{A}{->}{}{} +% \pgfgdendscope +% +% Naturally, users will typically use TikZ's somewhat simpler syntax: ' +% +% \tikz \graph [some algorithm] { A -> B -> C -> A }; + +\def\pgfgdbeginscope{% + \begingroup % Protecting scope + % get options + \directlua{ + pgf.gd.interface.InterfaceToDisplay.beginGraphDrawingScope(\the\pgf@gd@parameter@stack@height) + }% + \begingroup % Inner scope, the actual nodes will be inserted after + % this scope has been closed + % Indicate that we are now inside a graph drawing scope + \pgfgdgraphdrawingscopeactivetrue + % Switch on late positioning + \pgfpositionnodelater{\pgf@gd@positionnode@callback} + % Switch on late edges + \pgfgd@latecallback% + % Kill transformations (will be added by the position now + % macros) + \pgftransformreset +}% + + + +% The following is used to ensure that if we need to resume the graph +% drawing (through co-routines), we pass control back to TeX +% first. Otherwise, new text input levels are created and there may be +% only 15 of these... +\newif\ifpgfgdresumecoroutine + + +% Ends a graph drawing scope +% +% Description: +% +% This macro invokes the selected graph drawing algorithm and +% ships out all nodes within this scope +% +% See \pgfgdbeginscope + +\def\pgfgdendscope{% + \pgfgdresumecoroutinefalse% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.runGraphDrawingAlgorithm() + }% + \pgfutil@loop% + \ifpgfgdresumecoroutine% + \pgfgdresumecoroutinefalse% + \directlua{ + pgf.gd.interface.InterfaceToDisplay.resumeGraphDrawingCoroutine() + }% + \pgfutil@repeat% + \endgroup% + % Late positioning has ended + \directlua{pgf.gd.interface.InterfaceToDisplay.renderGraph()}% + \directlua{pgf.gd.interface.InterfaceToDisplay.endGraphDrawingScope()}% + \endgroup% +}% + + + + + + +% Hook into graph specification +% +% #1 = code +% +% Description: +% +% Allows you to specify code that should be active while the graph +% drawing engine collects the information concerning the graph, but +% which should no longer be active when the graph is rendered. + +\def\pgfgdaddspecificationhook#1{ + \expandafter\def\expandafter\pgfgd@latecallback\expandafter{\pgfgd@latecallback#1} +}% +\let\pgfgd@latecallback\pgfutil@empty + + + + + + + + +% Loading further libraries + +% Include a graph drawing library file. +% +% #1 = List of names of library file. +% +% Description: +% +% This command includes a list of graph drawing library files. For +% each file X in the list, the file pgf.gd.X.lua is included using +% |require|. +% +% For the convenience of Context users, both round and square brackets +% are possible for the argument. +% +% +% Example: +% +% \usegdlibrary{trees} +% \usegdlibrary[force,circular] + +\def\usegdlibrary{\pgfutil@ifnextchar[{\use@gdlibrary}{\use@@gdlibrary}}%}% +\def\use@gdlibrary[#1]{\use@@gdlibrary{#1}}% +\def\use@@gdlibrary#1{% + \edef\pgf@list{#1}% + \pgfutil@for\pgf@temp:=\pgf@list\do{% + \expandafter\pgfkeys@spdef\expandafter\pgf@temp\expandafter{\pgf@temp}% + \ifx\pgf@temp\pgfutil@empty + \else + \directlua{if not pgf_lookup_and_require('\pgf@temp') then + tex.print('\pgfutil@luaescapestring{\noexpand\pgferror{Graph drawing library '\pgf@temp' not found}}') + end} + \fi + } +}% + +% LaTeX uses kpathsea for file lookup while ConTeXt uses its +% resolvers. Luckily, kpathsea is still accessible in ConTeXt in a +% subtable kpse.original which we use if kpse.find_file is nil. +{% +\catcode`\%=11 +\directlua{ + function pgf_lookup_and_require(name) + local sep = package.config:sub(1,1) + local function lookup(name) + local sub = name:gsub('%.',sep) + local find_file = context and + resolvers.findfile or + kpse.find_file + if find_file(sub, 'lua') then + require(name) + elseif find_file(sub, 'clua') then + collectgarbage('stop') + require(name) + collectgarbage('restart') + else + return false + end + return true + end + return + lookup('pgf.gd.' .. name .. '.library') or + lookup('pgf.gd.' .. name) or + lookup(name .. '.library') or + lookup(name) + end +} +}% + + +% +% Ok, fire up the system by creating the binding! +% +\directlua{ + require 'pgf.gd.interface.InterfaceToDisplay' + pgf.gd.interface.InterfaceToDisplay.bind(require 'pgf.gd.bindings.BindingToPGF') +}% + + + +% +% Special setup for keys that are declared by the above libraries, but +% that have a special meaning on the display layer. +% + +\pgfkeys{/graph drawing/nodes behind edges/.append code=\csname pgf@gd@nodes@behind@edges#1\endcsname}% +\pgfkeys{/graph drawing/nodes behind edges/.default=true}% + + + + +\endinput |