summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua')
-rw-r--r--Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua938
1 files changed, 938 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua
new file mode 100644
index 00000000000..586efa12067
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua
@@ -0,0 +1,938 @@
+-- Copyright 2012 by Till Tantau
+--
+-- This file may be distributed an/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 information
+
+-- @release $Header: /cvsroot/pgf/pgf/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToAlgorithms.lua,v 1.17 2013/12/20 14:44:46 tantau Exp $
+
+
+
+---
+-- This class provides the interface between the graph drawing system
+-- and algorithms. Another class, |InterfaceToDisplay|, binds the
+-- display layers (like \tikzname\ or a graph drawing editor) to the
+-- graph drawing system ``from the other side''.
+--
+-- The functions declared here can be used by algorithms to
+-- communicate with the graph drawing system, which will usually
+-- forward the ``requests'' of the algorithms to the display layers in
+-- some way. For instance, when you declare a new parameter, this
+-- parameter will become available on the display layer.
+
+local InterfaceToAlgorithms = {}
+
+-- Namespace
+require("pgf.gd.interface").InterfaceToAlgorithms = InterfaceToAlgorithms
+
+
+-- Imports
+local InterfaceCore = require "pgf.gd.interface.InterfaceCore"
+local InterfaceToDisplay = require "pgf.gd.interface.InterfaceToDisplay"
+local InterfaceToC = require "pgf.gd.interface.InterfaceToC"
+
+local LookupTable = require "pgf.gd.lib.LookupTable"
+local LayoutPipeline = require "pgf.gd.control.LayoutPipeline"
+
+local Edge = require "pgf.gd.model.Edge"
+
+local lib = require "pgf.gd.lib"
+
+local doc = require "pgf.gd.doc"
+
+-- Forwards
+
+local declare_handlers
+
+
+
+
+---
+-- Adds a handler for the |declare| function. The |declare|
+-- command is just a ``dispatcher'' to one of many possible
+-- declaration functions. Which function is used, depends on which
+-- fields are present in the table passed to |declare|. For each
+-- registered handler, we call the |test| function. If it returns
+-- neither |nil| nor |false|, the |handler| field of this handler is
+-- called. If it returns |true|, the handler immediately
+-- finishes. Otherwise, the next handler is tried.
+
+function InterfaceToAlgorithms.addHandler(test, handler)
+ table.insert(declare_handlers, 1, { test = test, handler = handler })
+end
+
+
+
+-- Local stuff
+
+local key_metatable = {}
+
+---
+-- This function is the ``work-horse'' for declaring things. It allows
+-- you to specify on the algorithmic layer that a key ``is available''
+-- for use on the display layer. There is just one function for
+-- handling all declarations in order to make the declarations
+-- easy-to-use since you just need to import a single function:
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+--local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare
+--\end{codeexample}
+--
+-- You can now use |declare| it as follows: You pass it a table
+-- containing information about the to-be-declared key. The table
+-- \emph{must} have a field |key| whose value is unique and must be a
+-- string. If the value of |key| is, say, |"foo"|, the
+-- parameter can be set on the display layer such as, say, the
+-- \tikzname\ layer, using |/graph drawing/foo|. Here is a typical
+-- example of how a declaration is done:
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- ---
+-- declare {
+-- key = "electrical charge",
+-- type = "number",
+-- initial = "1.0",
+--
+-- summary = "The ``electrical charge'' is a property...",
+-- documentation = [[...]],
+-- examples = [[...]]
+-- }
+--\end{codeexample}
+--
+-- \medskip\noindent\textbf{Inlining Documentation.}
+-- The three keys |summary|, |documentation| and |examples| are
+-- intended for the display layer to give the users information about
+-- what the key does. The |summary| should be a string that succinctly
+-- describes the option. This text will typically be displayed for
+-- instance as a ``tool tip'' or in an option overview. The
+-- |documentation| optionally provides more information and should be
+-- typeset using \TeX. The |examples| can either be a single string or
+-- an array of strings. Each should be a \tikzname\ example
+-- demonstrating how the key is used.
+--
+-- Note that you can take advantage of the Lua syntax of enclosing
+-- very long multi-line strings in |[[| and |]]|. As a bonus, if the
+-- summary, documentation, or an example starts and ends with a quote,
+-- these two quotes will be stripped. This allows you to enclose the
+-- whole multi-line string (additionally) in quotes, leading to better
+-- syntax highlighting in editors.
+--
+-- \medskip\noindent\textbf{External Documentation.}
+-- It is sometimes more desirable to put the documentation of a key
+-- into an external file. First, this makes the code leaner and, thus,
+-- faster to read (both for humans and for computers). Second, for C
+-- code, it is quite inconvenient to have long strings inside a C
+-- file. In such cases, you can use the |documentation_in| field:
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- ---
+-- declare {
+-- key = "electrical charge",
+-- type = "number",
+-- initial = "1.0",
+-- documentation_in = "some_filename"
+-- }
+--\end{codeexample}
+--
+-- The |some_filename| must be the name of a Lua file that will be
+-- read ``on demand,'' that is, whenever someone tries to access the
+-- documentation, summary, or examples field of the key, this file
+-- will be loaded using |require|. The file should then use
+-- |pgf.gd.doc| to install the missing information in the keys.
+--
+-- \medskip\noindent\textbf{The Use Field.}
+-- When you declare a key, you can provide a |use| field. If present,
+-- you must set it to an array of small tables which have two fields:
+-- \begin{itemize}
+-- \item |key| This is the name of another key or a function.
+-- \item |value| This is either a value (like a string or a number) or
+-- a function or |nil|.
+-- \end{itemize}
+--
+-- Here is an example:
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- ---
+-- declare {
+-- key = "binary tree layout",
+-- use = {
+-- { key = "minimum number of children", value = 2 },
+-- { key = "significant sep", value = 12 },
+-- { key = "tree layout" }
+-- },
+-- summary = "The |binary tree layout| places node...",
+-- documentation = ...,
+-- examples = ...,
+-- }
+--\end{codeexample}
+--
+-- The effect of a |use| field is the following: Whenever the key is
+-- encountered on the option stack, the key is first handled
+-- normally. Then, we iterate over all elements of the |use|
+-- array. For each element, we perform the action as if the |key| of
+-- the array had been set explicitly to the value given by the |value|
+-- field. If the |value| is a function, we pass a different value to
+-- the key, namely the result of applying the function to the value
+-- originally passed to the original key. Here is a typical example:
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- ---
+-- declare {
+-- key = "level sep",
+-- type = "length",
+-- use = {
+-- { key = "level pre sep", value = function (v) return v/2 end },
+-- { key = "level post sep", value = function (v) return v/2 end }
+-- },
+-- summary = "..."
+-- }
+--\end{codeexample}
+--
+-- Just like the value, the key itself can also be a function. In this
+-- case, the to-be-used key is also computed by applying the function
+-- to the value passed to the original key.
+--
+-- As mentioned at the beginning, |declare| is a work-horse that will call
+-- different internal functions depending on whether you declare a
+-- parameter key or a new algorithm or a collection kind. Which kind
+-- of declaration is being done is detected by the presence of certain
+-- fields in the table passed to |t|. The different kind of
+-- possible declarations are documented in the |declare_...|
+-- functions. Note that these functions are internal and cannot be
+-- called from outside; you must use the |declare| function.
+--
+-- @param t A table contain the field |key| and other fields as
+-- described.
+
+function InterfaceToAlgorithms.declare (t)
+ local keys = InterfaceCore.keys
+
+ -- Sanity check:
+ assert (type(t.key) == "string" and t.key ~= "", "parameter key may not be the empty string")
+ if keys[t.key] or t.keys == "algorithm_phases" then
+ error("parameter '" .. t.key .. "' already declared")
+ end
+
+ for _,h in ipairs (declare_handlers) do
+ if h.test(t) then
+ if h.handler(t) then
+ break
+ end
+ end
+ end
+
+ -- Attach metatable:
+ setmetatable (t, key_metatable)
+
+ -- Set!
+ keys[t.key] = t
+ keys[#keys + 1] = t
+end
+
+
+function key_metatable.__index (key_table, what)
+ if what == "documentation" or what == "summary" or what == "examples" then
+ local doc = rawget(key_table,"documentation_in")
+ if doc then
+ require (doc)
+ return rawget(key_table, what)
+ end
+ end
+end
+
+
+
+---
+-- This function is called by |declare| for ``normal parameter keys,''
+-- which are all keys for which no special field like |algorithm| or
+-- |layer| is declared. You write
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- ---
+-- declare {
+-- key = "electrical charge",
+-- type = "number",
+-- initial = "1.0",
+--
+-- summary = "The ``electrical charge'' is a property...",
+-- documentation = [[...]],
+-- examples = [[...]]
+-- }
+--\end{codeexample}
+--
+-- When an author writes |my node[electrical charge=5-3]| in the
+-- description of her graph, the object |vertex| corresponding to the
+-- node |my node| will have a field |options| attached to it with
+--\begin{codeexample}[code only, tikz syntax=false]
+--vertex.options["electrical charge"] == 2
+--\end{codeexample}
+--
+-- The |type| field does not refer to Lua types. Rather, these types are
+-- sensible types for graph drawing and they are mapped by the higher
+-- layers to Lua types. In detail, the following types are available:
+--
+-- \begin{itemize}
+-- \item |number| A dimensionless number. Will be mapped to a normal
+-- Lua |number|. So, when the author writes |foo=5*2|, the |foo| key
+-- of the |options| field of the corresponding object will be set to
+-- |10.0|.
+-- \item |length| A ``dimension'' in the sense of \TeX\ (a number with
+-- a dimension like |cm| attached to it). It is the job of the display
+-- layer to map this to a number in ``\TeX\ points,'' that is, to a
+-- multiple of $1/72.27$th of an inch.
+-- \item |string| Some text. Will be mapped to a Lua |string|.
+-- \item |canvas coordinate| A position on the canvas. Will be mapped
+-- to a |model.Coordinate|.
+-- \item |boolean| A Boolean value.
+-- \item |raw| Some to-be-executed Lua text.
+-- \item |direction| Normally, an angle; however,
+-- the special values of |down|, |up|, |left|, |right| as well as the
+-- directions |north|, |north west|, and so on are also legal on the
+-- display layer. All of them will be mapped to a number. Furthermore,
+-- a vertical bar (\verb!|!) will be mapped to |-90| and a minus sign
+-- (|-|) will be mapped to |0|.
+-- \item |hidden| A key of this type ``cannot be set,'' that is,
+-- users cannot set this key at all. However algorithms can still read
+-- this key and, through the use of |alias|, can use the key as a
+-- handle to another key.
+-- \item |user value| The key stores a Lua user value (userdata). Such
+-- keys can only be set from C since user values cannot be created in
+-- Lua (let alone in \tikzname).
+-- \end{itemize}
+--
+-- If the |type| field is missing, it is automatically set to
+-- |"string"|.
+--
+-- A parameter can have an |initial| value. This value will be used
+-- whenever the parameter has not been set explicitly for an object.
+--
+-- A parameter can have a |default| value. This value will be used as
+-- the parameter value whenever the parameter is explicitly set, but
+-- no value is provided. For a key of type |"boolean"|, if no
+-- |default| is provided, |"true"| will be used automatically.
+--
+-- A parameter can habe an |alias| field. This field must be set to
+-- the name of another key or to a function. Whenever you access the
+-- current key and this key is not set, the |alias| key is tried
+-- instead. If it is set, its value will be returned (if the |alias|
+-- key has itself an alias set, this is tried recursively). If the
+-- alias is not set either and neither does it have an initial value,
+-- the |initial| value is used. Note that in case the alias has its
+-- |initial| field set, the |initial| value of the current key will
+-- never be used.
+--
+-- The main purpose of the current key is to allow algorithms to
+-- introduce their own terminology for keys while still having access
+-- to the standard keys. For instance, the |OptimalHierarchyLayout|
+-- class uses the name |layerDistance| for what would be called
+-- |level distance| in the rest of the graph drawing system. In this
+-- case, we can declare the |layerDistance| key as follows:
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- declare {
+-- key = "layerDistance",
+-- type = "length",
+-- alias = "level distance"
+-- }
+--\end{codeexample}
+--
+-- Inside the algorithm, we can write |...options.layerDistance| and
+-- will get the current value of the |level distance| unless the
+-- |layerDistance| has been set explicitly. Indeed, we might set the
+-- |type| to |hidden| to ensure that \emph{only} the |level distance|
+-- can and must set to set the layerDistance.
+--
+-- Note that there is a difference between |alias| and the |use|
+-- field: Suppose we write
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- declare {
+-- key = "layerDistance",
+-- type = "length",
+-- use = {
+-- { key = "level distance", value = lib.id }
+-- }
+-- }
+--\end{codeexample}
+--
+-- Here, when you say |layerDistance=1cm|, the |level distance| itself
+-- will be modified. When the |level distance| is set, however, the
+-- |layerDistance| will not be modified.
+--
+-- If the alias is a function, it will be called with the option table
+-- as its parameter. You can thus say things like
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- declare {
+-- key = "layerDistance",
+-- type = "length",
+-- alias = function (option)
+-- return option["layer pre dist"] + option["layer post dist"]
+-- end
+-- }
+--\end{codeexample}
+--
+-- As a special curtesy to C code, you can also set the key
+-- |alias_function_string|, which allows you to put the function into
+-- a string that is read using |loadstring|.
+--
+-- (You cannot call this function directly, it is included for
+-- documentation purposes only.)
+--
+-- @param t The table originally passed to |declare|.
+
+local function declare_parameter (t)
+
+ t.type = t.type or "string"
+
+ if t.type == "boolean" and t.default == nil then
+ t.default = true
+ end
+
+ -- Normal key
+ assert (type(t.type) == "string", "key type must be a string")
+
+ -- Declare via the hub:
+ if t.type ~= "hidden" then
+ InterfaceCore.binding:declareCallback(t)
+
+ -- Handle initials:
+ if t.initial then
+ InterfaceCore.option_initial[t.key] = InterfaceCore.convert(t.initial, t.type)
+ end
+ end
+
+ if t.alias_function_string and not t.alias then
+ local count = 0
+ t.alias = load (
+ function ()
+ count = count + 1
+ if count == 1 then
+ return "return "
+ elseif count == 2 then
+ return t.alias_function_string
+ else
+ return nil
+ end
+ end)()
+ end
+
+ if t.alias then
+ assert (type(t.alias) == "string" or type(t.alias == "function"), "alias must be a string or a function")
+ InterfaceCore.option_aliases[t.key] = t.alias
+ end
+
+ return true
+end
+
+
+
+
+---
+-- This function is called by |declare| for ``algorithm
+-- keys.'' They are detected by the presence of the field |algorithm|
+-- in the table |t| passed to |declare|. Here is an example of how it
+-- is used:
+--\begin{codeexample}[code only, tikz syntax=false]
+-- local ReingoldTilford1981 = {}
+--
+-- ---
+-- declare {
+-- key = "tree layout",
+-- algorithm = ReingoldTilford1981,
+--
+-- preconditions = {
+-- connected = true,
+-- tree = true
+-- },
+--
+-- postconditions = {
+-- upward_oriented = true
+-- },
+--
+-- summary = "The Reingold--Tilford method is...",
+-- documentation = ...,
+-- examples = ...,
+-- }
+--
+-- function ReingoldTilford1981:run()
+-- ...
+-- end
+--\end{codeexample}
+--
+-- The |algorithm| field expects either a table or a string as
+-- value. If you provide a string, then |require| will be applied to
+-- this string to obtain the table; however, this will happen only
+-- when the key is actually used for the first time. This means that
+-- you can declare (numerous) algorithms in a library without these
+-- algorithms actually being loaded until they are needed.
+--
+-- Independently of how the table is obtained, it will be ``upgraded''
+-- to a class by setting its |__index| field and installing a static
+-- |new| function (which takes a table of initial values as
+-- argument). Both these settings will only be done if they have not
+-- yet been performed.
+--
+-- Next, you can specify the fields |preconditions| and
+-- |postconditions|. The preconditions are a table that tell the graph
+-- drawing engine what kind of graphs your algorithm expects. If the
+-- input graph is not of this kind, it will be automatically
+-- transformed to meet this condition. Similarly, the postconditions
+-- tell the engine about properties of your graph after the algorithm
+-- has run. Again, additional transformations may be performed.
+--
+-- You can also specify the field |phase|. This tells the graph
+-- drawing engine which ``phase'' of the graph drawing process your
+-- option applies to. Each time you select an algorithm later on
+-- through use of the algorithm's key, the algorithm for this phase
+-- will be set; algorithms of other phases will not be changed. So,
+-- for instance, when an algorithm is part of the spanning tree
+-- computation, its phase will be |"spanning tree computation"| and
+-- using its key does not change the main algorithm, but only the
+-- algorithm used during the computation of a spanning tree for the
+-- current graph (in case this is needed by the main algorithm). In
+-- case the |phase| field is missing, the phase |main| is used. Thus,
+-- when no phase field is given, the key will change the main
+-- algorithm used to draw the graph.
+--
+-- Later on, the algorithm set for the current phase can be accessed
+-- through the special |algorithm_phases| field of |options|
+-- tables. The |algorithm_phases| table will contain a field for each
+-- phase for which some algorithm has been set.
+--
+-- The following example shows the declaration of an algorithm that is
+-- the default for the phase |spanning tree computation|:
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- ---
+-- declare {
+-- key = "breadth first spanning tree",
+-- algorithm = {
+-- run =
+-- function (self)
+-- return SpanningTreeComputation.computeSpanningTree(self.ugraph, false, self.events)
+-- end
+-- },
+-- phase = "spanning tree computation",
+-- phase_default = true,
+-- summary = ...
+-- }
+--\end{codeexample}
+--
+-- The algorithm is called as follows during a run of the main
+-- algorithms:
+--
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+-- local graph = ... -- the graph object
+-- local spanning_algorithm_class = graph.options.algorithm_phases["spanning tree computation"]
+-- local spanning_algorithm =
+-- spanning_algorithm_class.new{
+-- ugraph = ugraph,
+-- events = scope.events
+-- }
+-- local spanning_tree = spanning_algorithm:run()
+--\end{codeexample}
+--
+-- If you set the |phase_default| field of |t| to |true|, the algorithm will
+-- be installed as the default algorithm for the phase. This can be
+-- done only once per phase. Furthermore, for such a default algorithm
+-- the |algorithm| key must be table, it may not be a string (in other
+-- words, all default algorithms are loaded immediately).
+--
+-- (You cannot call this function directly, it is included for
+-- documentation purposes only.)
+--
+-- @param t The table originally passed to |declare|.
+
+local function declare_algorithm (t)
+ -- Algorithm declaration!
+ assert(type(t.algorithm) == "table" or type(t.algorithm) == "string")
+
+ t.phase = t.phase or "main"
+
+ local function make_class ()
+ local class
+
+ if type(t.algorithm) == "table" then
+ class = lib.class(t.algorithm)
+ else
+ class = lib.class(require(t.algorithm))
+ end
+
+ -- Now, save pre- and postconditions
+ class.preconditions = t.preconditions or {}
+ class.postconditions = t.postconditions or {}
+
+ -- Save phase
+ class.phase = t.phase
+
+ -- Compatibility
+ class.old_graph_model = t.old_graph_model
+
+ return class
+ end
+
+ -- Store this:
+ local store_me
+ if type(t.algorithm) == "table" then
+ store_me = make_class()
+ else
+ store_me = make_class
+ end
+
+ -- Save in the algorithm_classes table:
+ InterfaceCore.algorithm_classes[t.key] = store_me
+
+ -- Install!
+ InterfaceCore.binding:declareCallback(t)
+
+ if t.phase_default then
+ assert (not InterfaceCore.option_initial.algorithm_phases[t.phase],
+ "default algorithm for phase already set")
+ assert (type(store_me) == "table",
+ "default algorithms must be loaded immediately")
+ InterfaceCore.option_initial.algorithm_phases[t.phase] = store_me
+ end
+
+ return true
+end
+
+
+
+
+---
+-- This function is called by |declare| for ``collection kinds.'' They
+-- are detected by the presence of the field |layer|
+-- in the table |t| passed to |declare|. See the class |Collection|
+-- for details on what a collection and a collection kind is.
+--
+-- The |key| field of the table |t| passed to this function is both
+-- the name of the to-be-declared collection kind as well as the key
+-- that is used on the display layer to indicate that a node or edge
+-- belongs to a collection.
+--
+-- \medskip
+-- \noindent\textbf{The Display Layer.}
+-- Let us first have a look at what happens on the display layer:
+-- A key |t.key| is setup on the display layer that, when used inside
+-- a graph drawing scope, starts a new collection of the specified
+-- kind. ``Starts'' means that all nodes and edges mentioned in the
+-- rest of the current option scope will belong to a new collection
+-- of kind |t.key|.
+--
+--\begin{codeexample}[code only, tikz syntax=false]
+--declare { key = "hyper", layer = 1 }
+--\end{codeexample}
+-- you can say on the \tikzname\ layer
+--\begin{codeexample}[code only]
+-- \graph {
+-- a, b, c, d;
+-- { [hyper] a, b, c }
+-- { [hyper] b, c, d }
+-- };
+--\end{codeexample}
+--
+-- In this case, the nodes |a|, |b|, |c| will belong to a collection of
+-- kind |hyper|. The nodes |b|, |c|, and |d| will (also) belong to
+-- another collection of the same kind |hyper|. You can nest
+-- collections; in this case, nodes will belong to several
+-- collections.
+--
+-- The effect of declaring a collection kind on the algorithm layer
+-- it, first of all, that |scope.collections| will have a field named
+-- by the collection kind. This field will store an array that
+-- contains all collections that were declared as part of the
+-- graph. For instance, |collections.hyper| will contain all
+-- hyperedges, each of which is a table with the following fields: The
+-- |vertices| and |edges| fields each contain arrays of all objects
+-- being part of the collection. The |sub| field is an array of
+-- ``subcollections,'' that is, all collections that were started
+-- inside another collection. (For the collection kinds |hyper| and
+-- |same layer| this makes no sense, but subgraphs could, for instance,
+-- be nested.)
+--
+-- \medskip
+-- \noindent\textbf{Rendering of Collections.}
+-- For some kinds of collections, it makes sense to \emph{render} them,
+-- but only after the graph drawing algorithm has run. For this
+-- purpose, the binding layer will use a callback for each collection
+-- kind and each collection, see the |Binding| class for details.
+-- Suppose, for instance, you would
+-- like hyperedges to be rendered. In this case, a graph drawing
+-- algorithm should iterate over all collections of type |hyper| and
+-- compute some hints on how to render the hyperedge and store this
+-- information in the |generated_options| table of the hyperedge. Then,
+-- the binding layer will ask the dislay layer to run some some code
+-- that is able to read key--value pairs passed to
+-- it (which are the key--value pairs of the |generated_options| table)
+-- and use this information to nicely draw the hyperedge.
+--
+-- The number |t.layer| determines in which order the different
+-- collection kinds are rendered.
+--
+-- The last parameter, the layer number, is used to specify the order
+-- in which the different collection kinds are rendered. The higher the
+-- number, the later the collection will be rendered. Thus, if there is
+-- a collection kind with layer number 10 and another with layer number
+-- 20, all collections of the first kind will be rendered first,
+-- followed by all collections of the second kind.
+--
+-- Collections whose layer kinds are non-negative get rendered
+-- \emph{after} the nodes and edges have already been rendered. In
+-- contrast, collections with a negative layer number get shown
+-- ``below'' the nodes and edges.
+--
+-- (You cannot call this function directly, it is included for
+-- documentation purposes only.)
+--
+-- @param t The table originally passed to |declare|.
+
+local function declare_collection_kind (t)
+ assert (type(t.layer) == "number", "layer must be a number")
+
+ local layer = t.layer
+ local kind = t.key
+ local kinds = InterfaceCore.collection_kinds
+ local new_entry = { kind = kind, layer = layer }
+
+ -- Insert into table part:
+ kinds[kind] = new_entry
+
+ -- Insert into array part:
+ local found
+ for i=1,#kinds do
+ if kinds[i].layer > layer or (kinds[i].layer == layer and kinds[i].kind > kind) then
+ table.insert(kinds, i, new_entry)
+ return
+ end
+ end
+
+ kinds[#kinds+1] = new_entry
+
+ -- Bind
+ InterfaceCore.binding:declareCallback(t)
+
+ return true
+end
+
+
+
+-- Build in handlers:
+
+declare_handlers = {
+ { test = function (t) return t.algorithm_written_in_c end, handler = InterfaceToC.declare_algorithm_written_in_c },
+ { test = function (t) return t.algorithm end, handler = declare_algorithm },
+ { test = function (t) return t.layer end, handler = declare_collection_kind },
+ { test = function (t) return true end, handler = declare_parameter }
+}
+
+
+
+
+
+
+
+
+---
+-- Finds a node by its name. This method should be used by algorithms
+-- for which a node name is specified in some option and, thus, needs
+-- to be converted to a vertex object during a run of the algorithm.
+--
+-- @param name A node name
+--
+-- @return The vertex of the given name in the syntactic digraph or
+-- |nil|.
+
+function InterfaceToAlgorithms.findVertexByName(name)
+ return InterfaceCore.topScope().node_names[name]
+end
+
+
+
+
+
+-- Helper function
+local function add_to_collections(collection,where,what)
+ if collection then
+ LookupTable.addOne(collection[where],what)
+ add_to_collections(collection.parent,where,what)
+ end
+end
+
+local unique_count = 1
+
+---
+-- Generate a new vertex in the syntactic digraph. Calling this method
+-- allows algorithms to create vertices that are not present in the
+-- original input graph. Using the graph drawing coroutine, this
+-- function will pass back control to the display layer in order to
+-- render the vertex and, thereby, create precise size information
+-- about it.
+--
+-- Note that creating new vertices in the syntactic digraph while the
+-- algorithm is already running is a bit at odds with the notion of
+-- treating graph drawing as a series of graph transformations: For
+-- instance, when a new vertex is created, the graph will (at least
+-- temporarily) no longer be connected; even though an algorithm may
+-- have requested that it should only be fed connected
+-- graphs. Likewise, more complicated requirements like insisting on
+-- the graph being a tree also cannot be met.
+--
+-- For these reasons, the following happens, when a new vertex is
+-- created using the function:
+--
+-- \begin{enumerate}
+-- \item The vertex is added to the syntactic digraph.
+-- \item It is added to all layouts on the current layout stack. When
+-- a graph drawing algorithm is run, it is not necessarily run on the
+-- original syntactic digraph. Rather, a sequence / stack of nested
+-- layouts may currently
+-- be processed and the vertex is added to all of them.
+-- \item The vertex is added to both the |digraph| and the |ugraph| of
+-- the current algorithm.
+-- \end{enumerate}
+--
+-- @param algorithm An algorithm for whose syntactic digraph the node
+-- should be added
+-- @param init A table of initial values for the node that is passed
+-- to |Binding:createVertex|, see that function for details.
+--
+-- @return The newly created node
+--
+function InterfaceToAlgorithms.createVertex(algorithm, init)
+
+ -- Setup
+ local scope = InterfaceCore.topScope()
+ local binding = InterfaceCore.binding
+
+ -- Setup node
+ if not init.name then
+ init.name = "internal@gd@node@" .. unique_count
+ unique_count = unique_count + 1
+ end
+
+ -- Does vertex already exist?
+ assert (not scope.node_names[name], "node already created")
+
+ if not init.shape or init.shape == "none" then
+ init.shape = "rectangle"
+ end
+
+ -- Call binding
+ binding:createVertex(init)
+
+ local v = assert(scope.node_names[init.name], "internal node creation failed")
+
+ -- Add vertex to the algorithm's digraph and ugraph
+ algorithm.syntactic_component:add {v}
+ algorithm.digraph:add {v}
+ algorithm.ugraph:add {v}
+
+ -- Compute bounding boxes:
+ LayoutPipeline.prepareBoundingBoxes(algorithm.rotation_info, algorithm.adjusted_bb, algorithm.digraph, {v})
+
+ -- Add the node to the layout stack:
+ add_to_collections(algorithm.layout, "vertices", v)
+
+ algorithm.layout_graph:add { v }
+
+ return v
+end
+
+
+
+---
+-- Generate a new edge in the syntactic digraph. This method is quite
+-- similar to |createVertex| and has the same effects with respect to
+-- the edge: The edge is added to the syntactic digraph and also to
+-- all layouts on the layout stack. Forthermore, appropriate edges are
+-- added to the |digraph| and the |ugraph| of the algorithm currently
+-- running.
+--
+-- @param algorithm An algorithm for whose syntactic digraph the node should be added
+-- @param tail A syntactic tail vertex
+-- @param head A syntactic head vertex
+-- @param init A table of initial values for the edge.
+--
+-- The following fields are useful for |init|:
+-- \begin{itemize}
+-- \item |init.direction| If present, a direction for the edge. Defaults to "--".
+-- \item |init.options| If present, some options for the edge.
+-- \item |init.generated_options| A table that is passed back to the
+-- display layer as a list of key-value pairs in the syntax of
+-- |declare_parameter|.
+-- \end{itemize}
+
+function InterfaceToAlgorithms.createEdge(algorithm, tail, head, init)
+
+ init = init or {}
+
+ -- Setup
+ local scope = InterfaceCore.topScope()
+ local binding = InterfaceCore.binding
+ local syntactic_digraph = algorithm.layout_graph
+ local syntactic_component = algorithm.syntactic_component
+
+ assert (syntactic_digraph:contains(tail) and
+ syntactic_digraph:contains(head),
+ "attempting to create edge between nodes that are not in the syntactic digraph")
+
+ local arc = syntactic_digraph:connect(tail, head)
+
+ local edge = Edge.new {
+ head = head,
+ tail = tail,
+ direction = init.direction or "--",
+ options = init.options or algorithm.layout.options,
+ path = init.path,
+ generated_options = init.generated_options
+ }
+
+ -- Add to arc
+ arc.syntactic_edges[#arc.syntactic_edges+1] = edge
+
+ local s_arc = syntactic_component:connect(tail, head)
+ s_arc.syntactic_edges = arc.syntactic_edges
+
+ -- Create Event
+ local e = InterfaceToDisplay.createEvent ("edge", { arc, #arc.syntactic_edges })
+ edge.event = e
+
+ -- Make part of collections
+ for _,c in ipairs(edge.options.collections) do
+ LookupTable.addOne(c.edges, edge)
+ end
+
+ -- Call binding
+ binding.storage[edge] = {}
+ binding:everyEdgeCreation(edge)
+
+ -- Add edge to digraph and ugraph
+ local direction = edge.direction
+ if direction == "->" then
+ algorithm.digraph:connect(tail, head)
+ elseif direction == "<-" then
+ algorithm.digraph:connect(head, tail)
+ elseif direction == "--" or direction == "<->" then
+ algorithm.digraph:connect(tail, head)
+ algorithm.digraph:connect(head, tail)
+ end
+ algorithm.ugraph:connect(tail, head)
+ algorithm.ugraph:connect(head, tail)
+
+ -- Add edge to layouts
+ add_to_collections(algorithm.layout, "edges", edge)
+
+end
+
+
+
+
+
+-- Done
+
+return InterfaceToAlgorithms \ No newline at end of file