diff options
author | Karl Berry <karl@freefriends.org> | 2019-04-04 20:55:44 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-04-04 20:55:44 +0000 |
commit | acab24042d34dd439e1d074820d1da2fa1d591cd (patch) | |
tree | 32881f869e20a69711c5fe86134aa48143d9b1e8 /Master/texmf-dist/tex/generic/pgf/graphdrawing | |
parent | 93f5c4643a3d0a596d220ff14756ce68d99afe33 (diff) |
pgf (4apr19)
git-svn-id: svn://tug.org/texlive/trunk@50758 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgf/graphdrawing')
183 files changed, 8869 insertions, 8631 deletions
diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf.lua index da0aba39121..b0a32476167 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf.lua @@ -19,7 +19,7 @@ pgf = {} --- Forward +-- Forward local tostring_table --- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd.lua index cf94454a494..20d8acafa59 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd.lua @@ -38,7 +38,7 @@ require("pgf").gd = gd -- this table is present, it will be used as the default table. Second, -- it can have a graph_parameters table. This table will be used in the -- constructor to preload graph parameters from the pgf layer. For --- this, each entry of the table should be of the form +-- this, each entry of the table should be of the form -- -- key = 'string' -- @@ -50,13 +50,13 @@ require("pgf").gd = gd function gd.new_algorithm_class (class) class.__index = class - class.new = - function (initial) + class.new = + function (initial) -- Create new object local obj = {} for k,v in pairs(initial) do - obj[k] = v + obj[k] = v end setmetatable(obj, class) @@ -69,4 +69,4 @@ function gd.new_algorithm_class (class) end -return gd
\ No newline at end of file +return gd diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/Binding.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/Binding.lua index 5b60d90ccd6..6ffb4168f52 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/Binding.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/Binding.lua @@ -38,7 +38,7 @@ local Storage = require "pgf.gd.lib.Storage" -- -- @field storage A |Storage| storing the information passed from the -- display layer. The interpretation of this left to the actual --- binding. +-- binding. local Binding = { storage = Storage.newTableStorage () @@ -71,7 +71,7 @@ end -- of the display layer to make the parameter |t.key| available to the -- parsing process. Furthermore, if |t.initial| is not |nil|, the -- display layer must convert it into a value that is stored as the --- initial value and call |InterfaceToDisplay.setOptionInitial|. +-- initial value and call |InterfaceToDisplay.setOptionInitial|. -- -- @param t See |InterfaceToAlgorithms.declare| for details. @@ -105,7 +105,7 @@ end --- --- This function and the correspoding |...Stop...| functions are +-- This function and the corresponding |...Stop...| functions are -- called whenever a collection kind should be rendered. See -- |InterfaceToDisplay.render_collections| for details. -- @@ -141,7 +141,7 @@ end --- --- This function and the correspoding |...Stop...| functions are +-- This function and the corresponding |...Stop...| functions are -- called whenever a vertex should be rendered. See -- |InterfaceToDisplay.render_vertices| for details. -- @@ -191,7 +191,7 @@ end --- --- This function and the correspoding |...Stop...| functions are +-- This function and the corresponding |...Stop...| functions are -- called whenever an edge should be rendered. See -- |InterfaceToDisplay.render_edges| for details. -- @@ -237,21 +237,22 @@ end -- vertex. This call will be made while an algorithm is running. It is -- now the job of the binding to cause the display layer to create the -- node. This is done by calling the |yield| method of the scope's --- coroutine. +-- coroutine. -- -- @param init A table of initial values for the node. The following -- fields will be used: +-- % -- \begin{itemize} --- \item |name| If present, this name will be given to the --- node. If not present, an iternal name is generated. Note that, --- unless the node is a subgraph node, this name may not be the name --- of an already present node of the graph; in this case an error --- results. --- \item |shape| If present, a shape of the node. --- \item |generated_options| A table that is passed back to the --- display layer as a list of key-value pairs. --- \item |text| The text of the node, to be passed back to the --- higher layer. This is what should be displayed as the node's text. +-- \item |name| If present, this name will be given to the +-- node. If not present, an internal name is generated. Note that, +-- unless the node is a subgraph node, this name may not be the name +-- of an already present node of the graph; in this case an error +-- results. +-- \item |shape| If present, a shape of the node. +-- \item |generated_options| A table that is passed back to the +-- display layer as a list of key--value pairs. +-- \item |text| The text of the node, to be passed back to the +-- higher layer. This is what should be displayed as the node's text. -- \end{itemize} function Binding:createVertex(init) diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua index 90519e23d55..5324a1652e6 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/bindings/BindingToPGF.lua @@ -20,7 +20,7 @@ local Storage = require "pgf.gd.lib.Storage" -- drawing system to the \pgfname\ display system by overriding (that -- is, implementing) the methods of the |Binding| class. As a typical -- example, consider the implementation of the function |renderVertex|: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] --function BindingToPGF:renderVertex(v) -- local info = assert(self.infos[v], "thou shalt not modify the syntactic digraph") @@ -44,7 +44,7 @@ local Storage = require "pgf.gd.lib.Storage" -- (new) position for the node. For almost all methods of the -- |Binding| class there is a corresponding ``callback'' macro on the -- \TeX\ layer, all of which are implemented in the \pgfname\ library --- |graphdrawing|. For details on these callbacks, +-- |graphdrawing|. For details on these callbacks, -- please consult the code of that file and of the class -- |BindingToPGF| (they are not documented here since they are local -- to the binding and should not be called by anyone other than the @@ -81,7 +81,7 @@ local coordinate_in_pgf_syntax function BindingToPGF:resumeGraphDrawingCoroutine(text) tex.print(text) - tex.print("\\pgfgdresumecoroutinetrue") + tex.print("\\pgfgdresumecoroutinetrue") end @@ -108,7 +108,7 @@ end function BindingToPGF:renderCollection(collection) tex.print("\\pgfgdcallbackrendercollection{".. collection.kind .. "}{" - .. table_in_pgf_syntax(collection.generated_options) .. "}") + .. table_in_pgf_syntax(collection.generated_options) .. "}") end function BindingToPGF:renderCollectionStartKind(kind, layer) @@ -133,11 +133,11 @@ local box_count = 0 function BindingToPGF:everyVertexCreation(v) local info = self.storage[v] - + -- Save the box! box_count = box_count + 1 boxes[box_count] = node.copy_list(tex.box[info.tex_box_number]) - + -- Special tex stuff, should not be considered by gd algorithm info.box_count = box_count end @@ -180,12 +180,12 @@ local function rigid(x) end end - + -- Managing edges function BindingToPGF:renderEdge(e) local info = assert(self.storage[e], "thou shalt not modify the syntactic digraph") - + local function get_anchor(e, anchor) local a = e.options[anchor] if a and a ~= "" then @@ -194,7 +194,7 @@ function BindingToPGF:renderEdge(e) return "" end end - + local callback = { '\\pgfgdcallbackedge', '{', e.tail.name .. get_anchor(e, "tail anchor"), '}', @@ -205,12 +205,12 @@ function BindingToPGF:renderEdge(e) '{', table_in_pgf_syntax(e.generated_options), '}', '{' } - + local i = 1 while i <= #e.path do local c = e.path[i] assert (type(c) == "string", "illegal path operand") - + if c == "lineto" then i = i + 1 local d = rigid(e.path[i]) @@ -231,19 +231,19 @@ function BindingToPGF:renderEdge(e) .. to_pt(d2.x) .. ',' .. to_pt(d2.y) .. ')..' callback [#callback + 1] = '(' .. to_pt(d3.x) .. ',' .. to_pt(d3.y) .. ')' i = i + 1 - else + else error("illegal operation in edge path") end end callback [#callback + 1] = '}' callback [#callback + 1] = '{' .. animations_in_pgf_syntax(e.animations) .. '}' - + -- hand TikZ code over to TeX tex.print(table.concat(callback)) end - - + + function BindingToPGF:renderEdgesStart() tex.print("\\pgfgdcallbackbeginedgeshipout") end @@ -275,12 +275,12 @@ function table_in_pgf_syntax (t) local prefix = "/graph drawing/" local suffix = "/.try" return table.concat( lib.imap( t, function(table) - if table.value then - return prefix .. table.key .. suffix .. "={" .. tostring(table.value) .. "}" - else - return prefix .. table.key .. suffix - end - end), ",") + if table.value then + return prefix .. table.key .. suffix .. "={" .. tostring(table.value) .. "}" + else + return prefix .. table.key .. suffix + end + end), ",") end @@ -288,29 +288,29 @@ function animations_in_pgf_syntax (a) return table.concat( lib.imap( - a, - function(animation) - return "\\pgfanimateattribute{" .. animation.attribute .. "}{whom=pgf@gd," .. - table.concat( - lib.imap ( - animation.entries, - function (entry) - return "entry={" .. entry.t .. "s}{" .. to_pgf(entry.value) .. "}" - end - ), ",") .. - "," .. - table.concat( - lib.imap( - animation.options or {}, - function(table) - if table.value then - return table.key .. "={" .. to_pgf(table.value) .. "}" - else - return table.key - end - end), ",") - .. "}" - end) + a, + function(animation) + return "\\pgfanimateattribute{" .. animation.attribute .. "}{whom=pgf@gd," .. + table.concat( + lib.imap ( + animation.entries, + function (entry) + return "entry={" .. entry.t .. "s}{" .. to_pgf(entry.value) .. "}" + end + ), ",") .. + "," .. + table.concat( + lib.imap( + animation.options or {}, + function(table) + if table.value then + return table.key .. "={" .. to_pgf(table.value) .. "}" + else + return table.key + end + end), ",") + .. "}" + end) ) end @@ -332,12 +332,12 @@ end function path_in_pgf_syntax (p) local s = {} - + local i = 1 while i <= #p do local c = p[i] assert (type(c) == "string", "illegal path operand") - + if c == "lineto" then i = i + 1 local d = rigid(p[i]) @@ -355,10 +355,10 @@ function path_in_pgf_syntax (p) local d1, d2, d3 = rigid(p[i+1]), rigid(p[i+2]), rigid(p[i+3]) i = i + 3 s [#s + 1] = '\\pgfpathcurveto{\\pgfqpoint{' .. to_pt(d1.x) .. '}{' .. to_pt(d1.y) .. '}}{\\pgfqpoint{' - .. to_pt(d2.x) .. '}{' .. to_pt(d2.y) .. '}}{\\pgfqpoint{' - .. to_pt(d3.x) .. '}{' .. to_pt(d3.y) .. '}}' + .. to_pt(d2.x) .. '}{' .. to_pt(d2.y) .. '}}{\\pgfqpoint{' + .. to_pt(d3.x) .. '}{' .. to_pt(d3.y) .. '}}' i = i + 1 - else + else error("illegal operation in edge path") end end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua index 8e0d7d5bc66..bebb87ab3e1 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/Tantau2012.lua @@ -22,7 +22,7 @@ local Tantau2012 = {} declare { key = "simple necklace layout", algorithm = Tantau2012, - + postconditions = { upward_oriented = true }, @@ -48,15 +48,15 @@ function Tantau2012:run() local g = self.ugraph local vertices = g.vertices local n = #vertices - + local sib_dists = self:computeNodeDistances () local radii = self:computeNodeRadii() local diam, adjusted_radii = self:adjustNodeRadii(sib_dists, radii) - -- Compute total necessary length. For this, iterate over all - -- consecutive pairs and keep track of the necessary space for - -- this node. We imagine the nodes to be aligned from left to - -- right in a line. + -- Compute total necessary length. For this, iterate over all + -- consecutive pairs and keep track of the necessary space for + -- this node. We imagine the nodes to be aligned from left to + -- right in a line. local carry = 0 local positions = {} local function wrap(i) return (i-1)%n + 1 end @@ -67,11 +67,11 @@ function Tantau2012:run() local node_sep = lib.lookup_option('node post sep', vertices[i], g) + lib.lookup_option('node pre sep', vertices[wrap(i+1)], g) - local arc = node_sep + adjusted_radii[i] + adjusted_radii[wrap(i+1)] + local arc = node_sep + adjusted_radii[i] + adjusted_radii[wrap(i+1)] local needed = carry + arc local dist = math.sin( arc/diam ) * diam needed = needed + math.max ((radii[i] + radii[wrap(i+1)]+node_sep)-dist, 0) - carry = math.max(needed-sib_dists[i],0) + carry = math.max(needed-sib_dists[i],0) end local length = ideal_pos + carry @@ -98,15 +98,15 @@ function Tantau2012:computeNodeDistances() local missing_length = self.digraph.options['radius'] * 2 * math.pi - sum_length if missing_length > 0 then - -- Ok, the sib_dists to not add up to the desired minimum value. - -- What should we do? Hmm... We increase all by the missing amount: - for i=1,#vertices do - sib_dists[i] = sib_dists[i] + missing_length/#vertices - end + -- Ok, the sib_dists to not add up to the desired minimum value. + -- What should we do? Hmm... We increase all by the missing amount: + for i=1,#vertices do + sib_dists[i] = sib_dists[i] + missing_length/#vertices + end end sib_dists.total = math.max(self.digraph.options['radius'] * 2 * math.pi, sum_length) - + return sib_dists end @@ -130,24 +130,24 @@ function Tantau2012:adjustNodeRadii(sib_dists,radii) local total = 0 local max_rad = 0 for i=1,#radii do - total = total + 2*radii[i] + total = total + 2*radii[i] + lib.lookup_option('node post sep', self.digraph.vertices[i], self.digraph) + lib.lookup_option('node pre sep', self.digraph.vertices[i], self.digraph) - max_rad = math.max(max_rad, radii[i]) + max_rad = math.max(max_rad, radii[i]) end total = math.max(total, sib_dists.total, max_rad*math.pi) local diam = total/(math.pi) - + -- Now, adjust the radii: local adjusted_radii = {} for i=1,#radii do adjusted_radii[i] = (math.pi - 2*math.acos(radii[i]/diam))*diam/2 end - + return diam, adjusted_radii end -- done -return Tantau2012
\ No newline at end of file +return Tantau2012 diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/doc.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/doc.lua index e532e783e11..0bd9090a1c1 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/doc.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/circular/doc.lua @@ -19,20 +19,23 @@ local example = require 'pgf.gd.doc'.example key "simple necklace layout" summary -[[ This simple layout arranges the nodes in a circle, which is -especially useful for drawing, well, circles of nodes. ]] +[[ +This simple layout arranges the nodes in a circle, which is +especially useful for drawing, well, circles of nodes. +]] documentation [[ The name |simple necklace layout| is reminiscent of the more general -``necklace layout,'' a term coined by Speckmann and Verbeek in +``necklace layout'', a term coined by Speckmann and Verbeek in their paper +% \begin{itemize} -\item - Bettina Speckmann and Kevin Verbeek, - \newblock Necklace Maps, - \newblock \emph{IEEE Transactions on Visualization and Computer - Graphics,} 16(6):881--889, 2010. + \item + Bettina Speckmann and Kevin Verbeek, + \newblock Necklace Maps, + \newblock \emph{IEEE Transactions on Visualization and Computer + Graphics,} 16(6):881--889, 2010. \end{itemize} For a |simple necklace layout|, the centers of the nodes @@ -41,7 +44,7 @@ node at the |grow| direction (for |grow'|, the circle is clockwise). The order of the nodes is the order in which they appear in the graph, the edges are not taken into consideration, unless the |componentwise| option is given. - +% \begin{codeexample}[] \tikz[>=spaced stealth'] \graph [simple necklace layout, grow'=down, node sep=1em, @@ -49,35 +52,38 @@ in the graph, the edges are not taken into consideration, unless the { x_1 -> x_2 -> x_3 -> x_4 -> x_5 -> "\dots"[draw=none] -> "x_{n-1}" -> x_n -> x_1 - }; + }; \end{codeexample} - + When you give the |componentwise| option, the graph will be decomposed into connected components, which are then laid out individually and packed using the usual component packing mechanisms: - +% \begin{codeexample}[] \tikz \graph [simple necklace layout] { a -- b -- c -- d -- a, 1 -- 2 -- 3 -- 1 -}; +}; \end{codeexample} +% \begin{codeexample}[] \tikz \graph [simple necklace layout, componentwise] { a -- b -- c -- d -- a, 1 -- 2 -- 3 -- 1 -}; +}; \end{codeexample} - + The nodes are placed in such a way that +% \begin{enumerate} -\item The (angular) distance between the centers of consecutive - nodes is at least |node distance|, -\item the distance between the borders of consecutive nodes is at - least |node sep|, and -\item the radius is at least |radius|. + \item The (angular) distance between the centers of consecutive + nodes is at least |node distance|, + \item the distance between the borders of consecutive nodes is at + least |node sep|, and + \item the radius is at least |radius|. \end{enumerate} +% The radius of the circle is chosen near-minimal such that the above properties are satisfied. To be more precise, if all nodes are circles, the radius is chosen optimally while for, say, rectangular @@ -101,8 +107,8 @@ example node sep=0pt, node distance=0pt, nodes={draw,circle}] { 1 -- 2 [minimum size=30pt] -- 3 -- - 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; - + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; + \draw [red] (0,-1.25) circle []; \end{tikzpicture} ]] @@ -113,7 +119,7 @@ example node sep=0pt, node distance=1cm, nodes={draw,circle}] { 1 -- 2 [minimum size=30pt] -- 3 -- - 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; ]] example @@ -122,7 +128,7 @@ example node sep=2pt, node distance=0pt, nodes={draw,circle}] { 1 -- 2 [minimum size=30pt] -- 3 -- - 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; ]] example @@ -131,6 +137,6 @@ example node sep=0pt, node distance=0pt, nodes={rectangle,draw}] { 1 -- 2 [minimum size=30pt] -- 3 -- - 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; + 4 [minimum size=50pt] -- 5 [minimum size=40pt] -- 6 -- 7 }; ]] -------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Anchoring.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Anchoring.lua index ccbb097583c..03a05ee627d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Anchoring.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Anchoring.lua @@ -23,29 +23,29 @@ -- \emph{absolutely} once all relative positions have been computed. In -- case that the graph consists of several unconnected components, the -- situation is even more complicated. --- +-- -- The order in which the algorithm layer determines the node at which -- the graph should be anchored: --- +-- % -- \begin{enumerate} --- \item If the |anchor node=|\meta{node name} option given to the graph --- as a whole, the graph is anchored at \meta{node name}, provided --- there is a node of this name in the graph. (If there is no node of --- this name or if it is misspelled, the effect is the same as if this --- option had not been given at all.) --- \item Otherwise, if there is a node where the |anchor here| option is --- specified, the first node with this option set is used. --- \item Otherwise, if there is a node where the |desired at| option is --- set (perhaps implicitly through keys like |x|), the first such node --- is used. --- \item Finally, in all other cases, the first node is used. +-- \item If the |anchor node=|\meta{node name} option given to the graph +-- as a whole, the graph is anchored at \meta{node name}, provided +-- there is a node of this name in the graph. (If there is no node of +-- this name or if it is misspelled, the effect is the same as if this +-- option had not been given at all.) +-- \item Otherwise, if there is a node where the |anchor here| option is +-- specified, the first node with this option set is used. +-- \item Otherwise, if there is a node where the |desired at| option is +-- set (perhaps implicitly through keys like |x|), the first such node +-- is used. +-- \item Finally, in all other cases, the first node is used. -- \end{enumerate} -- -- In the above description, the ``first'' node refers to the node first -- encountered in the specification of the graph. -- -- Once the node has been determined, the graph is shifted so that --- this node lies at the poistion specified by |anchor at|. +-- this node lies at the position specified by |anchor at|. -- -- @end @@ -70,7 +70,7 @@ declare { type = "coordinate", documentation_in = "pgf.gd.control.doc" } - + --- declare { key = "anchor node", diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua index dec07caaccd..5e5b0635bf4 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentAlign.lua @@ -47,22 +47,22 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare -- -- @end - + --- - + declare { key = "align here", type = "boolean", - summary = [[" - When this option is given to a node, this alignment line will go - through the origin of this node. If this option is passed to more - than one node of a component, the node encountered first in the - component is used. + summary = [[" + When this option is given to a node, this alignment line will go + through the origin of this node. If this option is passed to more + than one node of a component, the node encountered first in the + component is used. "]], - examples = [[" - \tikz \graph [binary tree layout, nodes={draw}] - { a, b -- c[align here], d -- e[second, align here] -- f }; + examples = [[" + \tikz \graph [binary tree layout, nodes={draw}] + { a, b -- c[align here], d -- e[second, align here] -- f }; "]] } @@ -72,81 +72,94 @@ declare { key = "component align", type = "string", initial = "first node", - + summary = [[" Specifies a ``strategy'' for the alignment of components. "]], - documentation = [[" - The following values are permissible: - \begin{itemize} - \item \declare{|first node|} - In each component, the alignment line goes through the center of - the first node of the component encountered during specification - of the component. + documentation = [[" + The following values are permissible: + % + \begin{itemize} + \item \declare{|first node|} + + In each component, the alignment line goes through the center of + the first node of the component encountered during specification + of the component. + % \begin{codeexample}[] \tikz \graph [binary tree layout, nodes={draw}, component align=first node] { a, b -- c, d -- e[second] -- f }; \end{codeexample} - \item \declare{|center|} - - The nodes of the component are projected onto the shift line. The - alignment line is now chosen so that it is exactly in the middle - between the maximum and minimum value that the projected nodes - have on the shift line. + % + \item \declare{|center|} + + The nodes of the component are projected onto the shift line. The + alignment line is now chosen so that it is exactly in the middle + between the maximum and minimum value that the projected nodes + have on the shift line. + % \begin{codeexample}[] \tikz \graph [binary tree layout, nodes={draw}, component align=center] { a, b -- c, d -- e[second] -- f }; \end{codeexample} + % \begin{codeexample}[] \tikz \graph [binary tree layout, nodes={draw}, component direction=90, component align=center] { a, b -- c, d -- e[second] -- f }; \end{codeexample} - \item \declare{|counterclockwise|} - - As for |center|, we project the nodes of the component onto the - shift line. The alignment line is now chosen so that it goes - through the center of the node whose center has the highest - projected value. + % + \item \declare{|counterclockwise|} + + As for |center|, we project the nodes of the component onto the + shift line. The alignment line is now chosen so that it goes + through the center of the node whose center has the highest + projected value. + % \begin{codeexample}[] \tikz \graph [binary tree layout, nodes={draw}, component align=counterclockwise] { a, b -- c, d -- e[second] -- f }; \end{codeexample} + % \begin{codeexample}[] \tikz \graph [binary tree layout, nodes={draw}, component direction=90, component align=counterclockwise] { a, b -- c, d -- e[second] -- f }; \end{codeexample} - The name |counterclockwise| is intended to indicate that the align - line goes through the node that comes last if we go from the - alignment direction in a counter-clockwise direction. - \item \declare{|clockwise|} - - Works like |counterclockwise|, only in the other direction: + The name |counterclockwise| is intended to indicate that the align + line goes through the node that comes last if we go from the + alignment direction in a counter-clockwise direction. + \item \declare{|clockwise|} + + Works like |counterclockwise|, only in the other direction: + % \begin{codeexample}[] \tikz \graph [binary tree layout, nodes={draw}, component align=clockwise] { a, b -- c, d -- e[second] -- f }; \end{codeexample} + % \begin{codeexample}[] \tikz \graph [binary tree layout, nodes={draw}, component direction=90, component align=clockwise] { a, b -- c, d -- e[second] -- f }; \end{codeexample} - \item \declare{|counterclockwise bounding box|} - - This method is quite similar to |counterclockwise|, only the - alignment line does not go through the center of the node with a - maximum projected value on the shift line, but through the maximum - value of the projected bounding boxes. For a left-to-right - packing, this means that the components are aligned so that the - bounding boxes of the components are aligned at the top. + % + \item \declare{|counterclockwise bounding box|} + + This method is quite similar to |counterclockwise|, only the + alignment line does not go through the center of the node with a + maximum projected value on the shift line, but through the maximum + value of the projected bounding boxes. For a left-to-right + packing, this means that the components are aligned so that the + bounding boxes of the components are aligned at the top. + % \begin{codeexample}[] \tikz \graph [tree layout, nodes={draw, align=center}, component sep=0pt, @@ -157,10 +170,11 @@ declare { component align=counterclockwise bounding box] { a, "high\\node" -- b}; \end{codeexample} - \item \declare{|clockwise bounding box|} - - Works like |counterclockwise bounding box|. - \end{itemize} + % + \item \declare{|clockwise bounding box|} + + Works like |counterclockwise bounding box|. + \end{itemize} "]] } @@ -173,16 +187,16 @@ declare { { key = "component align", value = "counterclockwise"}, }, - summary = [[" - Shorthand for |component direction=right| and - |component align=counterclockwise|. This means that, as the name - suggest, the components will be placed left-to-right and they are - aligned such that their top nodes are in a line. + summary = [[" + Shorthand for |component direction=right| and + |component align=counterclockwise|. This means that, as the name + suggest, the components will be placed left-to-right and they are + aligned such that their top nodes are in a line. "]], - examples = [[" - \tikz \graph [tree layout, nodes={draw, align=center}, - components go right top aligned] - { a, "high\\node" -- b}; + examples = [[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go right top aligned] + { a, "high\\node" -- b}; "]] } @@ -194,17 +208,17 @@ declare { { key = "component direction", value=0}, { key = "component align", value = "counterclockwise bounding box"}, }, - - summary = [[" - Like |components go right top aligned|, but with - |component align| set to |counterclockwise| |bounding box|. This means that the - components will be aligned with their bounding boxed being - top-aligned. + + summary = [[" + Like |components go right top aligned|, but with + |component align| set to |counterclockwise| |bounding box|. + This means that the components will be aligned with their bounding + boxed being top-aligned. "]], examples = [[" - \tikz \graph [tree layout, nodes={draw, align=center}, - components go right absolute top aligned] - { a, "high\\node" -- b}; + \tikz \graph [tree layout, nodes={draw, align=center}, + components go right absolute top aligned] + { a, "high\\node" -- b}; "]] } @@ -216,7 +230,7 @@ declare { { key = "component direction", value=0}, { key = "component align", value = "clockwise"}, }, - + summary = "See the other |components go ...| keys." } @@ -229,7 +243,7 @@ declare { { key = "component direction", value=0}, { key = "component align", value = "clockwise bounding box"}, }, - + summary = "See the other |components go ...| keys." } @@ -242,7 +256,7 @@ declare { { key = "component direction", value=0}, { key = "component align", value = "center"}, }, - + summary = "See the other |components go ...| keys." } @@ -255,11 +269,11 @@ declare { { key = "component direction", value=0}, { key = "component align", value = "first node"}, }, - - summary = [[" - Shorthand for |component direction=right| and - |component align=first node|. - "]] + + summary = [[" + Shorthand for |component direction=right| and + |component align=first node|. + "]] } @@ -271,13 +285,13 @@ declare { { key = "component direction", value=180}, { key = "component align", value = "clockwise"}, }, - + summary = "See the other |components go ...| keys.", - examples = [[" - \tikz \graph [tree layout, nodes={draw, align=center}, - components go left top aligned] - { a, "high\\node" -- b}; + examples = [[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go left top aligned] + { a, "high\\node" -- b}; "]] } @@ -290,7 +304,7 @@ declare { { key = "component direction", value=180}, { key = "component align", value = "clockwise bounding box"}, }, - + summary = "See the other |components go ...| keys." } @@ -304,7 +318,7 @@ declare { { key = "component direction", value=180}, { key = "component align", value = "counterclockwise"}, }, - + summary = "See the other |components go ...| keys." } @@ -318,7 +332,7 @@ declare { { key = "component direction", value=180}, { key = "component align", value = "counterclockwise bounding box"}, }, - + summary = "See the other |components go ...| keys." } @@ -360,17 +374,15 @@ declare { }, summary = "See the other |components go ...| keys.", - examples = { - [[" - \tikz \graph [tree layout, nodes={draw, align=center}, - components go down left aligned] - { a, hello -- {world,s} }; - "]], - [[" - \tikz \graph [tree layout, nodes={draw, align=center}, - components go up absolute left aligned] - { a, hello -- {world,s}}; - "]] + examples = {[[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go down left aligned] + { a, hello -- {world,s} }; + "]],[[" + \tikz \graph [tree layout, nodes={draw, align=center}, + components go up absolute left aligned] + { a, hello -- {world,s}}; + "]] } } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua index a84800d94cf..f941ff226ec 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDirection.lua @@ -25,35 +25,32 @@ declare { type = "direction", initial = "0", - summary = [[" - The \meta{angle} is used to determine the relative position of each - component relative to the previous one. The direction need not be a - multiple of |90|. As usual, you can use texts like |up| or - |right| instead of a number. + summary = [[" + The \meta{angle} is used to determine the relative position of each + component relative to the previous one. The direction need not be a + multiple of |90|. As usual, you can use texts like |up| or + |right| instead of a number. "]], - documentation = [[" - As the examples show, the direction only has an influence on the - relative positions of the components, not on the direction of growth - inside the components. In particular, the components are not rotated - by this option in any way. You can use the |grow| option or |orient| - options to orient individual components. + documentation = [[" + As the examples show, the direction only has an influence on the + relative positions of the components, not on the direction of growth + inside the components. In particular, the components are not rotated + by this option in any way. You can use the |grow| option or |orient| + options to orient individual components. "]], - examples = { - [[" - \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, - component direction=left] - { a, b, c -- d -- e, f -- g }; - "]], - [[" - \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, - component direction=10] - { a, b, c -- d -- e, f -- g }; - "]], - [[" - \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, - component direction=up] - { a, b, c [grow=right] -- d -- e, f[grow=45] -- g }; - "]] + examples = {[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component direction=left] + { a, b, c -- d -- e, f -- g }; + "]],[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component direction=10] + { a, b, c -- d -- e, f -- g }; + "]],[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component direction=up] + { a, b, c [grow=right] -- d -- e, f[grow=45] -- g }; + "]] } } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua index 5bf473e9c6a..7ba4d000a7a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentDistance.lua @@ -23,7 +23,7 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare -- -- @end - + --- declare { @@ -31,70 +31,74 @@ declare { type = "string", initial = "skyline", - documentation = [[" - Given two components, their distance is computed as follows in - depencende of \meta{method}: - \begin{itemize} - \item \declare{|rectangular|} - - Imagine a bounding box to be drawn around both components. They - are then shifted such that the padding (separating distance) - between the two boxes is the current value of |component sep|. - \begin{codeexample}[] - \tikz \graph [tree layout, nodes={draw}, component sep=0pt, - component packing=rectangular] - { a -- long text, longer text -- b}; - \end{codeexample} - \item \declare{|skyline|} - - The ``skyline method'' is used to compute the distance. It works - as follows: For simplicity, assume that the component direction is - right (other case work similary, only everything is - rotated). Imaging the second component to be placed far right - beyond the first component. Now start moving the second component - back to the left until one of the nodes of the second component - touches a node of the first component, and stop. Again, the - padding |component sep| can be used to avoid the nodes actually - touching each other. - - \begin{codeexample}[] - \tikz \graph [tree layout, nodes={draw}, component sep=0pt, - level distance=1.5cm, - component packing=skyline] - { a -- long text, longer text -- b}; - \end{codeexample} - - In order to avoid nodes of the second component ``passing through - a hole in the first component,'' the actual algorithm is a bit - more complicated: For both components, a ``skyline'' is - computed. For the first component, consider an arbitrary - horizontal line. If there are one or more nodes on this line, the - rightmost point on any of the bounding boxes of these nodes will - be the point on the skyline of the first component for this - line. Similarly, for the second component, for each horizontal - level the skyline is given by the leftmost point on any of the - bounding boxes intersecting the line. - - Now, the interesting case are horizontal lines that do not - intersect any of the nodes of the first and/or second - component. Such lines represent ``holes'' in the skyline. For - them, the following rule is used: Move the horizontal line upward - and downward as little as possible until a height is reached where - there is a skyline defined. Then the skyline position on the - original horizontal line is the skyline position at the reached - line, minus (or, for the second component, plus) the distance by - which the line was moved. This means that the holes are ``filled - up by slanted roofs.'' - \begin{codeexample}[] - \begin{tikzpicture} - \graph [tree layout, nodes={draw}, component sep=0pt, - component packing=skyline] - { a -- long text, longer text -- b}; - \draw[red] (long text.north east) -- ++(north west:1cm); - \end{tikzpicture} - \end{codeexample} - - \end{itemize} + documentation = [[" + Given two components, their distance is computed as follows in + dependence of \meta{method}: + % + \begin{itemize} + \item \declare{|rectangular|} + + Imagine a bounding box to be drawn around both components. They + are then shifted such that the padding (separating distance) + between the two boxes is the current value of |component sep|. + % + \begin{codeexample}[] + \tikz \graph [tree layout, nodes={draw}, component sep=0pt, + component packing=rectangular] + { a -- long text, longer text -- b}; + \end{codeexample} + % + \item \declare{|skyline|} + + The ``skyline method'' is used to compute the distance. It works + as follows: For simplicity, assume that the component direction is + right (other case work similarly, only everything is + rotated). Imaging the second component to be placed far right + beyond the first component. Now start moving the second component + back to the left until one of the nodes of the second component + touches a node of the first component, and stop. Again, the + padding |component sep| can be used to avoid the nodes actually + touching each other. + % + \begin{codeexample}[] + \tikz \graph [tree layout, nodes={draw}, component sep=0pt, + level distance=1.5cm, + component packing=skyline] + { a -- long text, longer text -- b}; + \end{codeexample} + + In order to avoid nodes of the second component ``passing through + a hole in the first component'', the actual algorithm is a bit + more complicated: For both components, a ``skyline'' is + computed. For the first component, consider an arbitrary + horizontal line. If there are one or more nodes on this line, the + rightmost point on any of the bounding boxes of these nodes will + be the point on the skyline of the first component for this + line. Similarly, for the second component, for each horizontal + level the skyline is given by the leftmost point on any of the + bounding boxes intersecting the line. + + Now, the interesting case are horizontal lines that do not + intersect any of the nodes of the first and/or second + component. Such lines represent ``holes'' in the skyline. For + them, the following rule is used: Move the horizontal line upward + and downward as little as possible until a height is reached where + there is a skyline defined. Then the skyline position on the + original horizontal line is the skyline position at the reached + line, minus (or, for the second component, plus) the distance by + which the line was moved. This means that the holes are ``filled + up by slanted roofs''. + % + \begin{codeexample}[] + \begin{tikzpicture} + \graph [tree layout, nodes={draw}, component sep=0pt, + component packing=skyline] + { a -- long text, longer text -- b}; + \draw[red] (long text.north east) -- ++(north west:1cm); + \end{tikzpicture} + \end{codeexample} + + \end{itemize} "]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua index 0cad5d7d9b5..78537b614cd 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/ComponentOrder.lua @@ -13,7 +13,7 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare - + --- -- @section subsubsection {Ordering the Components} @@ -33,46 +33,44 @@ declare { initial = "by first specified node", summary = [[" - Selects a ``strategy'' for ordering the components. By default, - they are ordered in the way they appear in the input. + Selects a ``strategy'' for ordering the components. By default, + they are ordered in the way they appear in the input. "]], - documentation = [[" - The following values are permissible for \meta{strategy} - \begin{itemize} - \item \declare{|by first specified node|} - - The components are ordered ``in the way they appear in the input - specification of the graph''. More precisely, for each component - consider the node that is first encountered in the description - of the graph. Order the components in the same way as these nodes - appear in the graph description. - - \item \declare{|increasing node number|} - - The components are ordered by increasing number of nodes. For - components with the same number of nodes, the first node in each - component is considered and they are ordered according to the - sequence in which these nodes appear in the input. - - \item \declare{|decreasing node number|} - As above, but in decreasing order. - \end{itemize} + documentation = [[" + The following values are permissible for \meta{strategy} + % + \begin{itemize} + \item \declare{|by first specified node|} + + The components are ordered ``in the way they appear in the input + specification of the graph''. More precisely, for each component + consider the node that is first encountered in the description + of the graph. Order the components in the same way as these nodes + appear in the graph description. + \item \declare{|increasing node number|} + + The components are ordered by increasing number of nodes. For + components with the same number of nodes, the first node in each + component is considered and they are ordered according to the + sequence in which these nodes appear in the input. + + \item \declare{|decreasing node number|} + As above, but in decreasing order. + \end{itemize} "]], - examples = { - [[" - \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, - component order=by first specified node] - { a, b, c, f -- g, c -- d -- e }; - "]], - [[" - \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, - component order=increasing node number] - { a, b, c -- d -- e, f -- g }; - "]] + examples = {[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component order=by first specified node] + { a, b, c, f -- g, c -- d -- e }; + "]],[[" + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + component order=increasing node number] + { a, b, c -- d -- e, f -- g }; + "]] } -} - - +} + + --- declare { @@ -81,11 +79,11 @@ declare { { key = "component order", value = "increasing node number" } }, - summary = [[" - A shorthand for |component order=increasing node number|. - "]] + summary = [[" + A shorthand for |component order=increasing node number|. + "]] } - + --- declare { @@ -93,15 +91,15 @@ declare { use = { { key = "component order", value = "decreasing node number" }, }, - summary = [[" - A shorthand for |component order=decreasing node number|. + summary = [[" + A shorthand for |component order=decreasing node number|. "]], examples = [[" - \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, - large components first] - { a, b, c -- d -- e, f -- g }; + \tikz \graph [tree layout, nodes={inner sep=1pt,draw,circle}, + large components first] + { a, b, c -- d -- e, f -- g }; "]] -} +} return Components
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Components.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Components.lua index 9d9621e6da4..c5019a56e23 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Components.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Components.lua @@ -35,57 +35,57 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare -- -- The default method for placing the different components works as -- follows: --- +-- % -- \begin{enumerate} --- \item For each component, a layout is determined and the component is --- oriented as described --- Section~\ref{subsection-library-graphdrawing-standard-orientation} --- on the orientation of graphs. --- \item The components are sorted as prescribed by the --- |component order| key. --- \item The first component is now placed (conceptually) at the --- origin. (The final position of this and all other components will be --- determined later, namely in the anchoring phase, but let us imagine --- that the first component lies at the origin at this point.) --- \item The second component is now positioned relative to the first --- component. The ``direction'' in which the next component is placed --- relative to the first one is determined by the |component direction| --- key, so components can be placed from left to right or up to down or --- in any other direction (even something like $30^\circ$). However, --- both internally and in the following description, we assume that the --- components are placed from left to right; other directions are --- achieved by doing some (clever) rotating of the arrangement achieved --- in this way. +-- \item For each component, a layout is determined and the component is +-- oriented as described +-- Section~\ref{subsection-library-graphdrawing-standard-orientation} +-- on the orientation of graphs. +-- \item The components are sorted as prescribed by the +-- |component order| key. +-- \item The first component is now placed (conceptually) at the +-- origin. (The final position of this and all other components will be +-- determined later, namely in the anchoring phase, but let us imagine +-- that the first component lies at the origin at this point.) +-- \item The second component is now positioned relative to the first +-- component. The ``direction'' in which the next component is placed +-- relative to the first one is determined by the |component direction| +-- key, so components can be placed from left to right or up to down or +-- in any other direction (even something like $30^\circ$). However, +-- both internally and in the following description, we assume that the +-- components are placed from left to right; other directions are +-- achieved by doing some (clever) rotating of the arrangement achieved +-- in this way. -- --- So, we now wish to place the second component to the right of the --- first component. The component is first shifted vertically according --- to some alignment strategy. For instance, it can be shifted so that --- the topmost node of the first component and the topmost node of the --- second component have the same vertical position. Alternatively, we --- might require that certain ``alignment nodes'' in both components --- have the same vertical position. There are several other strategies, --- which can be configured using the |component align| key. +-- So, we now wish to place the second component to the right of the +-- first component. The component is first shifted vertically according +-- to some alignment strategy. For instance, it can be shifted so that +-- the topmost node of the first component and the topmost node of the +-- second component have the same vertical position. Alternatively, we +-- might require that certain ``alignment nodes'' in both components +-- have the same vertical position. There are several other strategies, +-- which can be configured using the |component align| key. -- --- One the vertical position has been fixed, the horizontal position is --- computed. Here, two different strategies are available: First, image --- rectangular bounding boxed to be drawn around both components. Then --- we shift the second component such that the right border of the --- bounding box of the first component touches the left border of the --- bounding box of the second component. Instead of having the bounding --- boxes ``touch,'' we can also have a padding of |component sep| --- between them. The second strategy is more involved and also known as --- a ``skyline'' strategy, where (roughly) the components are --- ``moved together as near as possible so that nodes do not touch''. --- \item --- After the second component has been placed, the third component is --- considered and positioned relative to the second one, and so on. --- \item --- At the end, as hinted at earlier, the whole arrangement is rotate so --- that instead of ``going right'' the component go in the direction of --- |component direction|. Note, however, that this rotation applies only --- to the ``shift'' of the components; the components themselves are --- not rotated. Fortunately, this whole rotation process happens in the --- background and the result is normally exactly what you would expect. +-- One the vertical position has been fixed, the horizontal position is +-- computed. Here, two different strategies are available: First, image +-- rectangular bounding boxed to be drawn around both components. Then +-- we shift the second component such that the right border of the +-- bounding box of the first component touches the left border of the +-- bounding box of the second component. Instead of having the bounding +-- boxes ``touch'', we can also have a padding of |component sep| +-- between them. The second strategy is more involved and also known as +-- a ``skyline'' strategy, where (roughly) the components are +-- ``moved together as near as possible so that nodes do not touch''. +-- \item +-- After the second component has been placed, the third component is +-- considered and positioned relative to the second one, and so on. +-- \item +-- At the end, as hinted at earlier, the whole arrangement is rotate so +-- that instead of ``going right'' the component go in the direction of +-- |component direction|. Note, however, that this rotation applies only +-- to the ``shift'' of the components; the components themselves are +-- not rotated. Fortunately, this whole rotation process happens in the +-- background and the result is normally exactly what you would expect. -- \end{enumerate} -- -- In the following, we go over the different keys that can be used to @@ -95,35 +95,33 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare --- - + declare { key = "componentwise", type = "boolean", - summary = [[" - For algorithms that also support drawing unconnected graphs, use - this key to enforce that the components of the graph are, - nevertheless, laid out individually. For algorithms that do not - support laying out unconnected graphs, this option has no effect; - rather it works as if this option were always set. + summary = [[" + For algorithms that also support drawing unconnected graphs, use + this key to enforce that the components of the graph are, + nevertheless, laid out individually. For algorithms that do not + support laying out unconnected graphs, this option has no effect; + rather it works as if this option were always set. "]], - examples = { - [[" - \tikz \graph [simple necklace layout] - { - a -- b -- c -- d -- a, - 1 -- 2 -- 3 -- 1 - }; - "]], - [[", - \tikz \graph [simple necklace layout, componentwise] - { - a -- b -- c -- d -- a, - 1 -- 2 -- 3 -- 1 - }; - "]] + examples = {[[" + \tikz \graph [simple necklace layout] + { + a -- b -- c -- d -- a, + 1 -- 2 -- 3 -- 1 + }; + "]],[[", + \tikz \graph [simple necklace layout, componentwise] + { + a -- b -- c -- d -- a, + 1 -- 2 -- 3 -- 1 + }; + "]] } -} - +} + diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Distances.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Distances.lua index c1b64729fab..6dc5a13018d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Distances.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Distances.lua @@ -24,24 +24,24 @@ local lib = require "pgf.gd.lib" -- general keys that will be used by many algorithms. -- -- There are different kinds of objects for which you can specify --- distances and paddings: --- +-- distances and paddings: +-- % -- \begin{itemize} --- \item You specify the ``natural'' distance between nodes --- connected by an edge using |node distance|, which is also available in --- normal \tikzname\ albeit for a slightly different purpose. However, --- not every algorithm will (or can) honour the key; see the description --- of each algorithm what it will ``make of this option''. --- \item A number of graph drawing algorithms arrange nodes in layers --- (or levels); we refer --- to the nodes on the same layer as siblings (although, in a tree, --- siblings are only nodes with the same parent; nevertheless we use --- ``sibling'' loosely also for nodes that are more like ``cousins''). --- \item When a graph consists of several connected component, many graph --- drawing algorithms will layout these components individually. The --- different components will then be arranged next to each other, see --- Section~\ref{section-gd-packing} for the details, such that between --- the nodes of any two components a padding is avaiable. +-- \item You specify the ``natural'' distance between nodes +-- connected by an edge using |node distance|, which is also available in +-- normal \tikzname\ albeit for a slightly different purpose. However, +-- not every algorithm will (or can) honor the key; see the description +-- of each algorithm what it will ``make of this option''. +-- \item A number of graph drawing algorithms arrange nodes in layers +-- (or levels); we refer +-- to the nodes on the same layer as siblings (although, in a tree, +-- siblings are only nodes with the same parent; nevertheless we use +-- ``sibling'' loosely also for nodes that are more like ``cousins''). +-- \item When a graph consists of several connected component, many graph +-- drawing algorithms will layout these components individually. The +-- different components will then be arranged next to each other, see +-- Section~\ref{section-gd-packing} for the details, such that between +-- the nodes of any two components a padding is available. -- \end{itemize} -- -- @end @@ -56,23 +56,23 @@ declare { type = "length", initial = "1cm", - summary = [[" - This is minimum distance that the centers of nodes connected by an - edge should have. It will not always be possible to satisfy this - desired distance, for instance in case the nodes are too big. In - this case, the \meta{length} is just considered as a lower bound. + summary = [[" + This is minimum distance that the centers of nodes connected by an + edge should have. It will not always be possible to satisfy this + desired distance, for instance in case the nodes are too big. In + this case, the \meta{length} is just considered as a lower bound. "]], examples = [[" - \begin{tikzpicture} - \graph [simple necklace layout, node distance=1cm, node sep=0pt, - nodes={draw,circle,as=.}] - { - 1 -- 2 [minimum size=2cm] -- 3 -- - 4 -- 5 -- 6 -- 7 --[orient=up] 8 - }; - \draw [red,|-|] (1.center) -- ++(0:1cm); - \draw [red,|-|] (5.center) -- ++(180:1cm); - \end{tikzpicture} + \begin{tikzpicture} + \graph [simple necklace layout, node distance=1cm, node sep=0pt, + nodes={draw,circle,as=.}] + { + 1 -- 2 [minimum size=2cm] -- 3 -- + 4 -- 5 -- 6 -- 7 --[orient=up] 8 + }; + \draw [red,|-|] (1.center) -- ++(0:1cm); + \draw [red,|-|] (5.center) -- ++(180:1cm); + \end{tikzpicture} "]] } @@ -84,26 +84,24 @@ declare { type = "length", initial = ".333em", - summary = [[" - This is a minimum ``padding'' or ``separation'' between the border - of nodes connected by an edge. Thus, if nodes are so big that nodes - with a distance of |node distance| would overlap (or - just come with \meta{dimension} distance of one another), their - distance is enlarged so that this distance is still satisfied. - The |pre| means that the padding is added to the node ``at the - front.'' This make sense only for some algorithms, like for a - simple necklace layout. + summary = [[" + This is a minimum ``padding'' or ``separation'' between the border + of nodes connected by an edge. Thus, if nodes are so big that nodes + with a distance of |node distance| would overlap (or + just come with \meta{dimension} distance of one another), their + distance is enlarged so that this distance is still satisfied. + The |pre| means that the padding is added to the node ``at the + front''. This make sense only for some algorithms, like for a + simple necklace layout. "]], - examples = { - [[" - \tikz \graph [simple necklace layout, node distance=0cm, nodes={circle,draw}] - { 1--2--3--4--5--1 }; - "]], - [[" - \tikz \graph [simple necklace layout, node distance=0cm, node sep=0mm, - nodes={circle,draw}] - { 1--2--3[node pre sep=5mm]--4--5[node pre sep=1mm]--1 }; - "]] + examples = {[[" + \tikz \graph [simple necklace layout, node distance=0cm, nodes={circle,draw}] + { 1--2--3--4--5--1 }; + "]],[[" + \tikz \graph [simple necklace layout, node distance=0cm, node sep=0mm, + nodes={circle,draw}] + { 1--2--3[node pre sep=5mm]--4--5[node pre sep=1mm]--1 }; + "]] } } @@ -114,13 +112,13 @@ declare { type = "length", initial = ".333em", - summary = [[" - Works like |node pre sep|. - "]] + summary = [[" + Works like |node pre sep|. + "]] } - - + + --- -- @param length A length. @@ -131,9 +129,9 @@ declare { { key = "node pre sep", value = function(v) return v/2 end }, { key = "node post sep", value = function(v) return v/2 end }, }, - summary = [[" - A shorthand for setting both |node pre sep| and |node post sep| to - $\meta{length}/2$. + summary = [[" + A shorthand for setting both |node pre sep| and |node post sep| to + $\meta{length}/2$. "]] } @@ -145,26 +143,26 @@ declare { type = "length", initial = "1cm", - summary = [[" - This is minimum distance that the centers of nodes on one - level should have from the centers of nodes on the next level. It - will not always be possible to satisfy this desired distance, for - instance in case the nodes are too big. In this case, the - \meta{length} is just considered as a lower bound. + summary = [[" + This is minimum distance that the centers of nodes on one + level should have from the centers of nodes on the next level. It + will not always be possible to satisfy this desired distance, for + instance in case the nodes are too big. In this case, the + \meta{length} is just considered as a lower bound. "]], examples = [[" - \begin{tikzpicture}[inner sep=2pt] - \draw [help lines] (0,0) grid (3.5,2); - \graph [layered layout, level distance=1cm, level sep=0] - { 1 [x=1,y=2] -- 2 -- 3 -- 1 }; - \graph [layered layout, level distance=5mm, level sep=0] - { 1 [x=3,y=2] -- 2 -- 3 -- 1, 3 -- {4,5} -- 6 -- 3 }; - \end{tikzpicture} + \begin{tikzpicture}[inner sep=2pt] + \draw [help lines] (0,0) grid (3.5,2); + \graph [layered layout, level distance=1cm, level sep=0] + { 1 [x=1,y=2] -- 2 -- 3 -- 1 }; + \graph [layered layout, level distance=5mm, level sep=0] + { 1 [x=3,y=2] -- 2 -- 3 -- 1, 3 -- {4,5} -- 6 -- 3 }; + \end{tikzpicture} "]] } - + --- -declare { +declare { key = "layer distance", type = "length", use = { @@ -179,25 +177,25 @@ declare { type = "length", initial = ".333em", - summary = [[" - This is a minimum ``padding'' or ``separation'' between the border - of the nodes on a level to any nodes on the previous level. Thus, if - nodes are so big that nodes on consecutive levels would overlap (or - just come with \meta{lrngth} distance of one another), their - distance is enlarged so that this distance is still satisfied. - If a node on the previous level also has a |level post sep|, this - post padding and the \meta{dimension} add up. Thus, these keys - behave like the ``padding'' keys rather - than the ``margin'' key of cascading style sheets. + summary = [[" + This is a minimum ``padding'' or ``separation'' between the border + of the nodes on a level to any nodes on the previous level. Thus, if + nodes are so big that nodes on consecutive levels would overlap (or + just come with \meta{length} distance of one another), their + distance is enlarged so that this distance is still satisfied. + If a node on the previous level also has a |level post sep|, this + post padding and the \meta{dimension} add up. Thus, these keys + behave like the ``padding'' keys rather + than the ``margin'' key of cascading style sheets. "]], examples = [[" - \begin{tikzpicture}[inner sep=2pt, level sep=0pt, sibling distance=0pt] - \draw [help lines] (0,0) grid (3.5,2); - \graph [layered layout, level distance=0cm, nodes=draw] - { 1 [x=1,y=2] -- {2,3[level pre sep=1mm],4[level pre sep=5mm]} -- 5 }; - \graph [layered layout, level distance=0cm, nodes=draw] - { 1 [x=3,y=2] -- {2,3,4} -- 5[level pre sep=5mm] }; - \end{tikzpicture} + \begin{tikzpicture}[inner sep=2pt, level sep=0pt, sibling distance=0pt] + \draw [help lines] (0,0) grid (3.5,2); + \graph [layered layout, level distance=0cm, nodes=draw] + { 1 [x=1,y=2] -- {2,3[level pre sep=1mm],4[level pre sep=5mm]} -- 5 }; + \graph [layered layout, level distance=0cm, nodes=draw] + { 1 [x=3,y=2] -- {2,3,4} -- 5[level pre sep=5mm] }; + \end{tikzpicture} "]] } @@ -208,13 +206,13 @@ declare { type = "length", initial = ".333em", - summary = [[" - Works like |level pre sep|. - "]] + summary = [[" + Works like |level pre sep|. + "]] } - + --- -declare { +declare { key = "layer pre sep", type = "length", use = { @@ -224,7 +222,7 @@ declare { } --- -declare { +declare { key = "layer post sep", type = "length", use = { @@ -247,17 +245,17 @@ declare { { key = "level post sep", value = function (v) return v/2 end }, }, - summary = [[" - A shorthand for setting both |level pre sep| and |level post sep| to - $\meta{length}/2$. Note that if you set |level distance=0| and - |level sep=1em|, you get a layout where any two consecutive layers - are ``spaced apart'' by |1em|. + summary = [[" + A shorthand for setting both |level pre sep| and |level post sep| to + $\meta{length}/2$. Note that if you set |level distance=0| and + |level sep=1em|, you get a layout where any two consecutive layers + are ``spaced apart'' by |1em|. "]] } --- -declare { +declare { key = "layer sep", type = "number", use = { @@ -273,28 +271,25 @@ declare { type = "length", initial = "1cm", - summary = [[" - This is minimum distance that the centers of node should have to the - center of the next node on the same level. As for levels, this is - just a lower bound. - For some layouts, like a simple necklace layout, the \meta{length} is - measured as the distance on the circle. + summary = [[" + This is minimum distance that the centers of node should have to the + center of the next node on the same level. As for levels, this is + just a lower bound. + For some layouts, like a simple necklace layout, the \meta{length} is + measured as the distance on the circle. "]], - examples = { - [[" - \tikz \graph [tree layout, sibling distance=1cm, nodes={circle,draw}] - { 1--{2,3,4,5} }; - "]], - [[" - \tikz \graph [tree layout, sibling distance=0cm, sibling sep=0pt, - nodes={circle,draw}] - { 1--{2,3,4,5} }; - "]], - [[" - \tikz \graph [tree layout, sibling distance=0cm, sibling sep=0pt, - nodes={circle,draw}] - { 1--{2,3[sibling distance=1cm],4,5} }; - "]] + examples = {[[" + \tikz \graph [tree layout, sibling distance=1cm, nodes={circle,draw}] + { 1--{2,3,4,5} }; + "]],[[" + \tikz \graph [tree layout, sibling distance=0cm, sibling sep=0pt, + nodes={circle,draw}] + { 1--{2,3,4,5} }; + "]],[[" + \tikz \graph [tree layout, sibling distance=0cm, sibling sep=0pt, + nodes={circle,draw}] + { 1--{2,3[sibling distance=1cm],4,5} }; + "]] } } @@ -306,13 +301,13 @@ declare { type = "length", initial = ".333em", - summary = [[" - Works like |level pre sep|, only for siblings. + summary = [[" + Works like |level pre sep|, only for siblings. "]], examples = [[" - \tikz \graph [tree layout, sibling distance=0cm, nodes={circle,draw}, - sibling sep=0pt] - { 1--{2,3[sibling pre sep=1cm],4,5} }; + \tikz \graph [tree layout, sibling distance=0cm, nodes={circle,draw}, + sibling sep=0pt] + { 1--{2,3[sibling pre sep=1cm],4,5} }; "]] } @@ -323,11 +318,11 @@ declare { type = "length", initial = ".333em", - summary = [[" - Works like |sibling pre sep|. + summary = [[" + Works like |sibling pre sep|. "]] } - + --- @@ -341,26 +336,26 @@ declare { { key = "sibling post sep", value = function(v) return v/2 end }, }, - summary = [[" - A shorthand for setting both |sibling pre sep| and |sibling post sep| to - $\meta{length}/2$. + summary = [[" + A shorthand for setting both |sibling pre sep| and |sibling post sep| to + $\meta{length}/2$. "]] } - - - + + + --- declare { key = "part distance", type = "length", initial = "1.5cm", - summary = [[" - This is minimum distance between the centers of ``parts'' of a - graph. What a ``part'' is depends on the algorithm. + summary = [[" + This is minimum distance between the centers of ``parts'' of a + graph. What a ``part'' is depends on the algorithm. "]] } @@ -382,7 +377,7 @@ declare { initial = "1em", summary = "A post-padding for pars." } - + --- @@ -396,9 +391,9 @@ declare { { key = "part post sep", value = function(v) return v/2 end }, }, - summary = [[" - A shorthand for setting both |part pre sep| and |part post sep| to - $\meta{length}/2$. + summary = [[" + A shorthand for setting both |part pre sep| and |part post sep| to + $\meta{length}/2$. "]] } @@ -412,33 +407,31 @@ declare { type = "length", initial = "1.5em", - summary = [[" - This is pading between the bounding boxes that nodes of different - connected components will have when they are placed next to each - other. + summary = [[" + This is padding between the bounding boxes that nodes of different + connected components will have when they are placed next to each + other. "]], - examples = { - [[" - \tikz \graph [binary tree layout, sibling distance=4mm, level distance=8mm, - components go right top aligned, - component sep=1pt, nodes=draw] - { - 1 -> 2 -> {3->4[second]->5,6,7}; - a -> b[second] -> c[second] -> d -> e; - x -> y[second] -> z -> u[second] -> v; - }; - "]], - [[" - \tikz \graph [binary tree layout, sibling distance=4mm, level distance=8mm, - components go right top aligned, - component sep=1em, nodes=draw] - { - 1 -> 2 -> {3->4[second]->5,6,7}; - a -> b[second] -> c[second] -> d -> e; - x -> y[second] -> z -> u[second] -> v; - }; - "]] - } + examples = {[[" + \tikz \graph [binary tree layout, sibling distance=4mm, level distance=8mm, + components go right top aligned, + component sep=1pt, nodes=draw] + { + 1 -> 2 -> {3->4[second]->5,6,7}; + a -> b[second] -> c[second] -> d -> e; + x -> y[second] -> z -> u[second] -> v; + }; + "]],[[" + \tikz \graph [binary tree layout, sibling distance=4mm, level distance=8mm, + components go right top aligned, + component sep=1em, nodes=draw] + { + 1 -> 2 -> {3->4[second]->5,6,7}; + a -> b[second] -> c[second] -> d -> e; + x -> y[second] -> z -> u[second] -> v; + }; + "]] + } } @@ -451,11 +444,11 @@ declare { initial = "2cm", summary = [[" - This is the minimum distance between the centers of bounding - boxes of connected components when they are placed next to each - other. (Not used, currently.) + This is the minimum distance between the centers of bounding + boxes of connected components when they are placed next to each + other. (Not used, currently.) "]] } -return Distances
\ No newline at end of file +return Distances diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/FineTune.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/FineTune.lua index be1666b255b..87d67b5b56f 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/FineTune.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/FineTune.lua @@ -28,20 +28,20 @@ declare { type = "canvas coordinate", summary = [[" - This option allows you to slightly ``nudge'' (move) nodes after - they have been positioned by the given offset. The idea is that - this nudging is done after the position of the node has been - computed, so nudging has no influence on the actual graph - drawing algorithms. This, in turn, means that you can use - nudging to ``correct'' or ``optimize'' the positioning of nodes - after the algorithm has computed something. + This option allows you to slightly ``nudge'' (move) nodes after + they have been positioned by the given offset. The idea is that + this nudging is done after the position of the node has been + computed, so nudging has no influence on the actual graph + drawing algorithms. This, in turn, means that you can use + nudging to ``correct'' or ``optimize'' the positioning of nodes + after the algorithm has computed something. "]], examples = [[" - \tikz \graph [edges=rounded corners, nodes=draw, - layered layout, sibling distance=0] { - a -- {b, c, d[nudge=(up:2mm)]} -- e -- a; - }; + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b, c, d[nudge=(up:2mm)]} -- e -- a; + }; "]] } @@ -58,10 +58,10 @@ declare { summary = "A shorthand for nudging a node upwards.", examples = [[" - \tikz \graph [edges=rounded corners, nodes=draw, - layered layout, sibling distance=0] { - a -- {b, c, d[nudge up=2mm]} -- e -- a; - }; + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b, c, d[nudge up=2mm]} -- e -- a; + }; "]] } @@ -91,10 +91,10 @@ declare { summary = "Like |nudge up|, but left.", examples = [[" - \tikz \graph [edges=rounded corners, nodes=draw, - layered layout, sibling distance=0] { - a -- {b, c, d[nudge left=2mm]} -- e -- a; - }; + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b, c, d[nudge left=2mm]} -- e -- a; + }; "]] } @@ -118,18 +118,18 @@ declare { type = "canvas coordinate", summary = [[" - Using this option you can provide a position for a node to wish - it will be forced after the graph algorithms have run. So, the node - is positioned normally and the graph drawing algorithm does not know - about the position specified using |regardless at|. However, - afterwards, the node is placed there, regardless of what the - algorithm has computed (all other nodes are unaffected). + Using this option you can provide a position for a node to wish + it will be forced after the graph algorithms have run. So, the node + is positioned normally and the graph drawing algorithm does not know + about the position specified using |regardless at|. However, + afterwards, the node is placed there, regardless of what the + algorithm has computed (all other nodes are unaffected). "]], examples = [[" - \tikz \graph [edges=rounded corners, nodes=draw, - layered layout, sibling distance=0] { - a -- {b,c,d[regardless at={(1,0)}]} -- e -- a; - }; + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b,c,d[regardless at={(1,0)}]} -- e -- a; + }; "]] } @@ -148,17 +148,17 @@ declare { }, summary = [[" - This option combines |desired at| and |regardless at|. Thus, the - algorithm is ``told'' about the desired position. If it fails to place - the node at the desired position, it will be put there - regardless. The name of the key is intended to remind one of a node - being ``nailed'' to the canvas. + This option combines |desired at| and |regardless at|. Thus, the + algorithm is ``told'' about the desired position. If it fails to place + the node at the desired position, it will be put there + regardless. The name of the key is intended to remind one of a node + being ``nailed'' to the canvas. "]], examples = [[" - \tikz \graph [edges=rounded corners, nodes=draw, - layered layout, sibling distance=0] { - a -- {b,c,d[nail at={(1,0)}]} -- e[nail at={(1.5,-1)}] -- a; - }; + \tikz \graph [edges=rounded corners, nodes=draw, + layered layout, sibling distance=0] { + a -- {b,c,d[nail at={(1,0)}]} -- e[nail at={(1.5,-1)}] -- a; + }; "]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua index c998ca490aa..1c5e48b4c7e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/LayoutPipeline.lua @@ -21,48 +21,48 @@ -- Before an algorithm is applied, a number of transformations will -- have been applied, depending on the algorithm's |preconditions| -- field: --- +-- % -- \begin{itemize} --- \item |connected| +-- \item |connected| -- --- If this property is set for an algorithm (that is, in the --- |declare| statement for the algorithm the |predconditions| field --- has the entry |connected=true| set), then the graph will be --- decomposed into connected components. The algorithm is run on each --- component individually. --- \item |tree| +-- If this property is set for an algorithm (that is, in the +-- |declare| statement for the algorithm the |predconditions| field +-- has the entry |connected=true| set), then the graph will be +-- decomposed into connected components. The algorithm is run on each +-- component individually. +-- \item |tree| -- --- When set, the field |spanning_tree| of the algorithm will be set --- to a spanning tree of the graph. This option implies |connected|. --- \item |loop_free| +-- When set, the field |spanning_tree| of the algorithm will be set +-- to a spanning tree of the graph. This option implies |connected|. +-- \item |loop_free| -- --- When set, all loops (arcs from a vertex to itself) will have been --- removed when the algorithm runs. +-- When set, all loops (arcs from a vertex to itself) will have been +-- removed when the algorithm runs. -- --- \item |at_least_two_nodes| +-- \item |at_least_two_nodes| -- --- When explicitly set to |false| (this precondition is |true| by --- default), the algorithm will even be run if there is only a --- single vertex in the graph. +-- When explicitly set to |false| (this precondition is |true| by +-- default), the algorithm will even be run if there is only a +-- single vertex in the graph. -- \end{itemize} -- -- Once the algorithm has run, the algorithm's |postconditions| will -- be processed: --- +-- % -- \begin{itemize} --- \item |upward_oriented| +-- \item |upward_oriented| -- --- When set, the algorithm tells the layout pipeline that the graph --- has been laid out in a layered manner with each layer going from --- left to right and layers at a whole going upwards (positive --- $y$-coordinates). The graph will then be rotated and possibly --- swapped in accordance with the |grow| key set by the user. --- \item |fixed| +-- When set, the algorithm tells the layout pipeline that the graph +-- has been laid out in a layered manner with each layer going from +-- left to right and layers at a whole going upwards (positive +-- $y$-coordinates). The graph will then be rotated and possibly +-- swapped in accordance with the |grow| key set by the user. +-- \item |fixed| -- --- When set, no rotational postprocessing will be done after the --- algorithm has run. Usually, a graph is rotated to meet a user's --- |orient| settings. However, when the algorithm has already --- ``ideally'' rotated the graph, set this postcondition. +-- When set, no rotational postprocessing will be done after the +-- algorithm has run. Usually, a graph is rotated to meet a user's +-- |orient| settings. However, when the algorithm has already +-- ``ideally'' rotated the graph, set this postcondition. -- \end{itemize} -- -- @@ -71,23 +71,22 @@ -- posttransformations. This happens when users install additional -- algorithms in appropriate phases. In detail, the following happens -- in order: --- +-- % -- \begin{enumerate} --- \item If specified, the graph is decomposed into connected --- components and the following steps are applied to each component --- individually. --- \item All algorithms in the phase stack for the phase --- |preprocessing| are applied to the component. These algorithms are --- run one after the other in the order they appear in the phase --- stack. --- \item If necessary, the spanning tree is now computed and --- rotational information is gathered. --- \item The single algorithm in phase |main| is called. --- \item All algorithms in the phase stack for the phase --- |edge routing| are run. --- \item All algorithms in the phase stack for phase |postprocessing| --- are run. --- \item Edge syncing, orientation, and anchoring are applied. +-- \item If specified, the graph is decomposed into connected +-- components and the following steps are applied to each component +-- individually. +-- \item All algorithms in the phase stack for the phase +-- |preprocessing| are applied to the component. These algorithms are +-- run one after the other in the order they appear in the phase stack. +-- \item If necessary, the spanning tree is now computed and +-- rotational information is gathered. +-- \item The single algorithm in phase |main| is called. +-- \item All algorithms in the phase stack for the phase +-- |edge routing| are run. +-- \item All algorithms in the phase stack for phase |postprocessing| +-- are run. +-- \item Edge syncing, orientation, and anchoring are applied. -- \end{enumerate} -- -- If sublayouts are used, all of the above (except for anchoring) @@ -128,39 +127,39 @@ local prepare_events --- The main ``graph drawing pipeline'' that handles the pre- and --- postprocessing for a graph. This method is called by the diplay --- interface. +-- The main ``graph drawing pipeline'' that handles the pre- and +-- postprocessing for a graph. This method is called by the display +-- interface. -- -- @param scope A graph drawing scope. function LayoutPipeline.run(scope) -- The pipeline... - + -- Step 1: Preparations - + -- Prepare events prepare_events(scope.events) - + -- Step 2: Recursively layout the graph, starting with the root layout local root_layout = assert(scope.collections[InterfaceCore.sublayout_kind][1], "no layout in scope") - + scope.syntactic_digraph = Sublayouts.layoutRecursively (scope, - root_layout, - LayoutPipeline.runOnLayout, - { root_layout }) - + root_layout, + LayoutPipeline.runOnLayout, + { root_layout }) + -- Step 3: Anchor the graph LayoutPipeline.anchor(scope.syntactic_digraph, scope) - + -- Step 4: Apply regardless transforms Sublayouts.regardless(scope.syntactic_digraph) - + -- Step 5: Cut edges LayoutPipeline.cutEdges(scope.syntactic_digraph) - + end @@ -174,7 +173,7 @@ end -- @param algorithm_class The to-be-applied algorithm class. -- @param layout_graph A subgraph of the syntactic digraph which is -- restricted to the current layout and in which sublayouts have --- been contracted to single nodes. +-- been contracted to single nodes. -- @param layout The layout to which the graph belongs. -- function LayoutPipeline.runOnLayout(scope, algorithm_class, layout_graph, layout) @@ -189,12 +188,12 @@ function LayoutPipeline.runOnLayout(scope, algorithm_class, layout_graph, layout local new_a = layout_copy:connect(a.tail,a.head) new_a.syntactic_edges = a.syntactic_edges end - + -- Step 1: Decompose the graph into connected components, if necessary: local syntactic_components if algorithm_class.preconditions.tree or algorithm_class.preconditions.connected or layout_graph.options.componentwise then - syntactic_components = LayoutPipeline.decompose(layout_copy) - LayoutPipeline.sortComponents(layout_graph.options['component order'], syntactic_components) + syntactic_components = LayoutPipeline.decompose(layout_copy) + LayoutPipeline.sortComponents(layout_graph.options['component order'], syntactic_components) else -- Only one component: The graph itself... syntactic_components = { layout_copy } @@ -202,17 +201,17 @@ function LayoutPipeline.runOnLayout(scope, algorithm_class, layout_graph, layout -- Step 2: For all components do: for i,syntactic_component in ipairs(syntactic_components) do - + -- Step 2.1: Reset random number generator to make sure that the -- same graph is always typeset in the same way. - math.randomseed(layout_graph.options['random seed']) - + lib.randomseed(layout_graph.options['random seed']) + local digraph = Direct.digraphFromSyntacticDigraph(syntactic_component) -- Step 2.3: If requested, remove loops if algorithm_class.preconditions.loop_free then for _,v in ipairs(digraph.vertices) do - digraph:disconnect(v,v) + digraph:disconnect(v,v) end end @@ -222,15 +221,15 @@ function LayoutPipeline.runOnLayout(scope, algorithm_class, layout_graph, layout -- Step 2.4a: Run preprocessor for _,class in ipairs(layout_graph.options.algorithm_phases["preprocessing stack"]) do class.new{ - digraph = digraph, - ugraph = ugraph, - scope = scope, - layout = layout, - layout_graph = layout_graph, - syntactic_component = syntactic_component, - }:run() + digraph = digraph, + ugraph = ugraph, + scope = scope, + layout = layout, + layout_graph = layout_graph, + syntactic_component = syntactic_component, + }:run() end - + -- Step 2.5: Create an algorithm object local algorithm = algorithm_class.new{ digraph = digraph, @@ -240,14 +239,14 @@ function LayoutPipeline.runOnLayout(scope, algorithm_class, layout_graph, layout layout_graph = layout_graph, syntactic_component = syntactic_component, } - + -- Step 2.7: Compute a spanning tree, if necessary if algorithm_class.preconditions.tree then local spanning_algorithm_class = syntactic_component.options.algorithm_phases["spanning tree computation"] algorithm.spanning_tree = - spanning_algorithm_class.new{ - ugraph = ugraph, - events = scope.events + spanning_algorithm_class.new{ + ugraph = ugraph, + events = scope.events }:run() end @@ -261,43 +260,43 @@ function LayoutPipeline.runOnLayout(scope, algorithm_class, layout_graph, layout or algorithm_class.preconditions.at_least_two_nodes == false then -- Main run of the algorithm: if algorithm_class.old_graph_model then - LayoutPipeline.runOldGraphModel(scope, digraph, algorithm_class, algorithm) + LayoutPipeline.runOldGraphModel(scope, digraph, algorithm_class, algorithm) else - algorithm:run () + algorithm:run () end end -- Step 2.9a: Run edge routers for _,class in ipairs(layout_graph.options.algorithm_phases["edge routing stack"]) do class.new{ - digraph = digraph, - ugraph = ugraph, - scope = scope, - layout = layout, - layout_graph = layout_graph, - syntactic_component = syntactic_component, - }:run() + digraph = digraph, + ugraph = ugraph, + scope = scope, + layout = layout, + layout_graph = layout_graph, + syntactic_component = syntactic_component, + }:run() end - + -- Step 2.9b: Run postprocessor for _,class in ipairs(layout_graph.options.algorithm_phases["postprocessing stack"]) do class.new{ - digraph = digraph, - ugraph = ugraph, - scope = scope, - layout = layout, - layout_graph = layout_graph, - syntactic_component = syntactic_component, - }:run() + digraph = digraph, + ugraph = ugraph, + scope = scope, + layout = layout, + layout_graph = layout_graph, + syntactic_component = syntactic_component, + }:run() end - + -- Step 2.10: Sync the graphs digraph:sync() ugraph:sync() if algorithm.spanning_tree then algorithm.spanning_tree:sync() end - + -- Step 2.11: Orient the graph LayoutPipeline.orient(algorithm.rotation_info, algorithm.postconditions, syntactic_component, scope) end @@ -317,7 +316,7 @@ end -- procedure described in -- Section~\ref{subsection-library-graphdrawing-anchoring}. These -- transformations are always performed. --- +-- -- @param graph A graph -- @param scope The scope @@ -325,7 +324,7 @@ function LayoutPipeline.anchor(graph, scope) -- Step 1: Find anchor node: local anchor_node - + local anchor_node_name = graph.options['anchor node'] if anchor_node_name then anchor_node = scope.node_names[anchor_node_name] @@ -337,10 +336,10 @@ function LayoutPipeline.anchor(graph, scope) lib.find (graph.vertices, function (v) return v.options['desired at'] end) or graph.vertices[1] end - + -- Sanity check assert(graph:contains(anchor_node), "anchor node is not in graph!") - + local desired = anchor_node.options['desired at'] or graph.options['anchor at'] local delta = desired - anchor_node.pos @@ -361,7 +360,7 @@ end --- -- This method tries to determine in which direction the graph is supposed to -- grow and in which direction the algorithm will grow the graph. These two --- pieces of information togehter produce a necessary rotation around some node. +-- pieces of information together produce a necessary rotation around some node. -- This rotation is returned in a table. -- -- Note that this method does not actually cause a rotation to happen; this is @@ -372,12 +371,12 @@ end -- @return A table containing the computed information. function LayoutPipeline.prepareRotateAround(postconditions, graph) - + -- Find the vertex from which we orient local swap = true local v,_,grow = lib.find (graph.vertices, function (v) return v.options["grow"] end) - + if not v and graph.options["grow"] then v,grow,swap = graph.vertices[1], graph.options["grow"], true end @@ -386,7 +385,7 @@ function LayoutPipeline.prepareRotateAround(postconditions, graph) v,_,grow = lib.find (graph.vertices, function (v) return v.options["grow'"] end) swap = false end - + if not v and graph.options["grow'"] then v,grow,swap = graph.vertices[1], graph.options["grow'"], false end @@ -394,15 +393,15 @@ function LayoutPipeline.prepareRotateAround(postconditions, graph) if not v then v, grow, swap = graph.vertices[1], -90, true end - + -- Now compute the rotation local info = {} local growth_direction = (postconditions.upward_oriented and 90) or (postconditions.upward_oriented_swapped and 90) - + if postconditions.upward_oriented_swapped then swap = not swap end - + if growth_direction == "fixed" then info.angle = 0 -- no rotation elseif growth_direction then @@ -416,9 +415,9 @@ function LayoutPipeline.prepareRotateAround(postconditions, graph) local other = lib.find_min( graph:outgoing(v), function (a) - if a.head ~= v and a:eventIndex() then - return a, a:eventIndex() - end + if a.head ~= v and a:eventIndex() then + return a, a:eventIndex() + end end) info.to_node = (other and other.head) or (graph.vertices[1] == v and graph.vertices[2] or graph.vertices[1]) @@ -440,55 +439,57 @@ end -- orientation for what the algorithm assumes. -- -- The ``bounding box'' actually consists of the fields +-- % -- \begin{itemize} --- \item |sibling_pre|, --- \item |sibling_post|, --- \item |layer_pre|, and --- \item |layer_post|, +-- \item |sibling_pre|, +-- \item |sibling_post|, +-- \item |layer_pre|, and +-- \item |layer_post|, -- \end{itemize} +-- % -- which correspond to ``min x'', ``min y'', ``min y'', and ``max y'' --- for a tree growing up. +-- for a tree growing up. -- -- The computation of the ``bounding box'' treats a centered circle in -- a special way, all other shapes are currently treated like a -- rectangle. -- -- @param rotation_info The table computed by the function prepareRotateAround --- @param packing_storage A storage in which the computed distances are stored. --- @param graph An graph +-- @param packing_storage A storage in which the computed distances are stored. +-- @param graph An graph -- @param vertices An array of to-be-prepared vertices inside graph function LayoutPipeline.prepareBoundingBoxes(rotation_info, adjusted_bb, graph, vertices) - + local angle = assert(rotation_info.angle, "angle field missing") local swap = rotation_info.swap - + for _,v in ipairs(vertices) do local bb = adjusted_bb[v] local a = angle - + if v.shape == "circle" then a = 0 -- no rotation for circles. end - + -- Fill the bounding box field, bb.sibling_pre = math.huge bb.sibling_post = -math.huge bb.layer_pre = math.huge bb.layer_post = -math.huge - + local c = math.cos(angle) local s = math.sin(angle) for _,p in ipairs(v.path:coordinates()) do local x = p.x*c + p.y*s local y = -p.x*s + p.y*c - + bb.sibling_pre = math.min (bb.sibling_pre, x) bb.sibling_post = math.max (bb.sibling_post, x) bb.layer_pre = math.min (bb.layer_pre, y) bb.layer_post = math.max (bb.layer_post, y) end - + -- Flip sibling per and post if flag: if swap then bb.sibling_pre, bb.sibling_post = -bb.sibling_post, -bb.sibling_pre @@ -501,7 +502,7 @@ end -- --- Rotate the whole graph around a point +-- Rotate the whole graph around a point -- -- Causes the graph to be rotated around \meta{around} so that what -- used to be the |from_angle| becomes the |to_angle|. If the flag |swap| @@ -516,21 +517,21 @@ end -- swapped (flipped) along the new angle function LayoutPipeline.rotateGraphAround(graph, around_x, around_y, from, to, swap) - + -- Translate to origin local t = Transform.new_shift(-around_x, -around_y) - + -- Rotate to zero degrees: t = Transform.concat(Transform.new_rotation(-from), t) - + -- Swap if swap then t = Transform.concat(Transform.new_scaling(1,-1), t) end - + -- Rotate to from degrees: t = Transform.concat(Transform.new_rotation(to), t) - + -- Translate back t = Transform.concat(Transform.new_shift(around_x, around_y), t) @@ -546,7 +547,7 @@ end --- +-- -- Orient the whole graph using two nodes -- -- The whole graph is rotated so that the line from the first node to @@ -557,17 +558,17 @@ end -- @param first_node -- @param seond_node -- @param target_angle --- @param swap +-- @param swap function LayoutPipeline.orientTwoNodes(graph, first_node, second_node, target_angle, swap) if first_node and second_node then -- Compute angle between first_node and second_node: local x = second_node.pos.x - first_node.pos.x local y = second_node.pos.y - first_node.pos.y - + local angle = math.atan2(y,x) LayoutPipeline.rotateGraphAround(graph, first_node.pos.x, - first_node.pos.y, angle, target_angle, swap) + first_node.pos.y, angle, target_angle, swap) end end @@ -576,25 +577,25 @@ end --- -- Performs a post-layout orientation of the graph by performing the -- steps documented in Section~\ref{subsection-library-graphdrawing-standard-orientation}. --- +-- -- @param rotation_info The info record computed by the function |prepareRotateAround|. -- @param postconditions The algorithm's postconditions. -- @param graph A to-be-oriented graph. -- @param scope The graph drawing scope. function LayoutPipeline.orient(rotation_info, postconditions, graph, scope) - + -- Sanity check if #graph.vertices < 2 then return end - + -- Step 1: Search for global graph orient options: local function f (orient, tail, head, flag) if orient and head and tail then local n1 = scope.node_names[tail] local n2 = scope.node_names[head] if graph:contains(n1) and graph:contains(n2) then - LayoutPipeline.orientTwoNodes(graph, n1, n2, orient/360*2*math.pi, flag) - return true + LayoutPipeline.orientTwoNodes(graph, n1, n2, orient/360*2*math.pi, flag) + return true end end end @@ -608,32 +609,32 @@ function LayoutPipeline.orient(rotation_info, postconditions, graph, scope) if f(-90, tail, head, false) then return end local tail, head = string.match(graph.options["vertical'"] or "", "^(.*) to (.*)$") if f(-90, tail, head, true) then return end - + -- Step 2: Search for a node with the orient option: for _, v in ipairs(graph.vertices) do local function f (key, flag) local orient = v.options[key] - local head = v.options["orient head"] + local head = v.options["orient head"] local tail = v.options["orient tail"] - + if orient and head then - local n2 = scope.node_names[head] - if graph:contains(n2) then - LayoutPipeline.orientTwoNodes(graph, v, n2, orient/360*2*math.pi, flag) - return true - end - elseif orient and tail then - local n1 = scope.node_names[tail] - if graph:contains(n1) then - LayoutPipeline.orientTwoNodes(graph, n1, v, orient/360*2*math.pi, flag) - return true - end + local n2 = scope.node_names[head] + if graph:contains(n2) then + LayoutPipeline.orientTwoNodes(graph, v, n2, orient/360*2*math.pi, flag) + return true + end + elseif orient and tail then + local n1 = scope.node_names[tail] + if graph:contains(n1) then + LayoutPipeline.orientTwoNodes(graph, n1, v, orient/360*2*math.pi, flag) + return true + end end end if f("orient", false) then return end if f("orient'", true) then return end end - + -- Step 3: Search for an edge with the orient option: for _, a in ipairs(graph.arcs) do if a:options("orient",true) then @@ -643,21 +644,21 @@ function LayoutPipeline.orient(rotation_info, postconditions, graph, scope) return LayoutPipeline.orientTwoNodes(graph, a.tail, a.head, a:options("orient'")/360*2*math.pi, true) end end - + -- Step 4: Search two nodes with a desired at option: local first, second, third - + for _, v in ipairs(graph.vertices) do if v.options['desired at'] then if first then - if second then - third = v - break - else - second = v - end - else - first = v + if second then + third = v + break + else + second = v + end + else + first = v end end end @@ -667,13 +668,13 @@ function LayoutPipeline.orient(rotation_info, postconditions, graph, scope) local b = second.options['desired at'] return LayoutPipeline.orientTwoNodes(graph, first, second, math.atan2(b.y-a.y,b.x-a.x), false) end - + -- Computed during preprocessing: if rotation_info.from_node and postconditions.fixed ~= true then local x = rotation_info.from_node.pos.x local y = rotation_info.from_node.pos.y local from_angle = rotation_info.from_angle or math.atan2(rotation_info.to_node.pos.y - y, rotation_info.to_node.pos.x - x) - + LayoutPipeline.rotateGraphAround(graph, x, y, from_angle, rotation_info.to_angle, rotation_info.swap) end end @@ -689,74 +690,74 @@ end -- -- @param graph A to-be-decomposed graph -- --- @return An array of graph objects that represent the connected components of the graph. +-- @return An array of graph objects that represent the connected components of the graph. function LayoutPipeline.decompose (digraph) -- The list of connected components (node sets) local components = {} - + -- Remember, which graphs have already been visited local visited = {} - + for _,v in ipairs(digraph.vertices) do if not visited[v] then -- Start a depth-first-search of the graph, starting at node n: local stack = { v } local component = Digraph.new { - syntactic_digraph = digraph.syntactic_digraph, - options = digraph.options + syntactic_digraph = digraph.syntactic_digraph, + options = digraph.options } - + while #stack >= 1 do - local tos = stack[#stack] - stack[#stack] = nil -- pop - - if not visited[tos] then - - -- Visit pos: - component:add { tos } - visited[tos] = true - - -- Push all unvisited neighbors: - for _,a in ipairs(digraph:incoming(tos)) do - local neighbor = a.tail - if not visited[neighbor] then - stack[#stack+1] = neighbor -- push - end - end - for _,a in ipairs(digraph:outgoing(tos)) do - local neighbor = a.head - if not visited[neighbor] then - stack[#stack+1] = neighbor -- push - end - end - end + local tos = stack[#stack] + stack[#stack] = nil -- pop + + if not visited[tos] then + + -- Visit pos: + component:add { tos } + visited[tos] = true + + -- Push all unvisited neighbors: + for _,a in ipairs(digraph:incoming(tos)) do + local neighbor = a.tail + if not visited[neighbor] then + stack[#stack+1] = neighbor -- push + end + end + for _,a in ipairs(digraph:outgoing(tos)) do + local neighbor = a.head + if not visited[neighbor] then + stack[#stack+1] = neighbor -- push + end + end + end end - + -- Ok, vertices will now contain all vertices reachable from n. components[#components+1] = component end end - + if #components < 2 then return { digraph } end - + for _,c in ipairs(components) do table.sort (c.vertices, function (u,v) return u.event.index < v.event.index end) for _,v in ipairs(c.vertices) do for _,a in ipairs(digraph:outgoing(v)) do - local new_a = c:connect(a.tail, a.head) - new_a.syntactic_edges = a.syntactic_edges + local new_a = c:connect(a.tail, a.head) + new_a.syntactic_edges = a.syntactic_edges end for _,a in ipairs(digraph:incoming(v)) do - local new_a = c:connect(a.tail, a.head) - new_a.syntactic_edges = a.syntactic_edges + local new_a = c:connect(a.tail, a.head) + new_a.syntactic_edges = a.syntactic_edges end end end - + return components end @@ -784,23 +785,23 @@ end -- Right now, we hardcode the functions here. Perhaps make this -- dynamic in the future. Could easily be done on the tikzlayer, --- acutally. +-- actually. LayoutPipeline.component_ordering_functions = { - ["increasing node number"] = - function (g,h) + ["increasing node number"] = + function (g,h) if #g.vertices == #h.vertices then - return g.vertices[1].event.index < h.vertices[1].event.index + return g.vertices[1].event.index < h.vertices[1].event.index else - return #g.vertices < #h.vertices + return #g.vertices < #h.vertices end end, - ["decreasing node number"] = - function (g,h) + ["decreasing node number"] = + function (g,h) if #g.vertices == #h.vertices then - return g.vertices[1].event.index < h.vertices[1].event.index + return g.vertices[1].event.index < h.vertices[1].event.index else - return #g.vertices > #h.vertices + return #g.vertices > #h.vertices end end, ["by first specified node"] = nil, @@ -810,27 +811,27 @@ LayoutPipeline.component_ordering_functions = { local function compute_rotated_bb(vertices, angle, sep, bb) - + local r = Transform.new_rotation(-angle) - + for _,v in ipairs(vertices) do -- Find the rotated bounding box field, local t = Transform.concat(r,Transform.new_shift(v.pos.x, v.pos.y)) - + local min_x = math.huge local max_x = -math.huge local min_y = math.huge local max_y = -math.huge - + for _,e in ipairs(v.path) do if type(e) == "table" then - local c = e:clone() - c:apply(t) - - min_x = math.min (min_x, c.x) - max_x = math.max (max_x, c.x) - min_y = math.min (min_y, c.y) - max_y = math.max (max_y, c.y) + local c = e:clone() + c:apply(t) + + min_x = math.min (min_x, c.x) + max_x = math.max (max_x, c.x) + min_y = math.min (min_y, c.y) + max_y = math.max (max_y, c.y) end end @@ -839,12 +840,12 @@ local function compute_rotated_bb(vertices, angle, sep, bb) max_x = max_x + sep min_y = min_y - sep max_y = max_y + sep - + local _,_,_,_,c_x,c_y = v:boundingBox() local center = Coordinate.new(c_x,c_y) - + center:apply(t) - + bb[v].min_x = min_x bb[v].max_x = max_x bb[v].min_y = min_y @@ -855,9 +856,9 @@ end ---- +--- -- This internal function packs the components of a graph. See --- Section~\ref{subsection-gd-component-packing} for details. +-- Section~\ref{subsection-gd-component-packing} for details. -- -- @param graph The graph -- @param components A list of components @@ -866,14 +867,14 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) local vertices = Storage.newTableStorage() local bb = Storage.newTableStorage() - + -- Step 1: Preparation, rotation to target direction local sep = syntactic_digraph.options['component sep'] local angle = syntactic_digraph.options['component direction']/180*math.pi - + local mark = {} for _,c in ipairs(components) do - + -- Setup the lists of to-be-considered nodes local vs = {} for _,v in ipairs(c.vertices) do @@ -882,24 +883,24 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) for _,a in ipairs(c.arcs) do for _,p in ipairs(a:pointCloud()) do - vs [#vs + 1] = Vertex.new { pos = p } + vs [#vs + 1] = Vertex.new { pos = p } end end vertices[c] = vs compute_rotated_bb(vs, angle, sep/2, bb) end - + local x_shifts = { 0 } local y_shifts = {} - + -- Step 2: Vertical alignment for i,c in ipairs(components) do local max_max_y = -math.huge local max_center_y = -math.huge local min_min_y = math.huge local min_center_y = math.huge - + for _,v in ipairs(c.vertices) do local info = bb[v] max_max_y = math.max(info.max_y, max_max_y) @@ -907,7 +908,7 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) min_min_y = math.min(info.min_y, min_min_y) min_center_y = math.min(info.c_y, min_center_y) end - + -- Compute alignment line local valign = syntactic_digraph.options['component align'] local line @@ -921,15 +922,15 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) line = min_center_y elseif valign == "first node" then line = bb[c.vertices[1]].c_y - else + else line = min_min_y end - + -- Overruled? for _,v in ipairs(c.vertices) do if v.options['align here'] then - line = bb[v].c_y - break + line = bb[v].c_y + break end end @@ -956,9 +957,9 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) y_values[#y_values+1] = info.c_y end end - + table.sort(y_values) - + local y_ranks = {} local right_face = {} for i=1,#y_values do @@ -966,41 +967,41 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) right_face[i] = -math.huge end - - + + for i=1,#components-1 do -- First, update right_face: local touched = {} - + for _,v in ipairs(vertices[components[i]]) do local info = bb[v] local border = info.max_x - + for i=y_ranks[info.min_y],y_ranks[info.max_y] do - touched[i] = true - right_face[i] = math.max(right_face[i], border) + touched[i] = true + right_face[i] = math.max(right_face[i], border) end end - + -- Fill up the untouched entries: local right_max = -math.huge for i=1,#y_values do if not touched[i] then - -- Search for next and previous touched - local interpolate = -math.huge - for j=i+1,#y_values do - if touched[j] then - interpolate = math.max(interpolate,right_face[j] - (y_values[j] - y_values[i])) - break - end - end - for j=i-1,1,-1 do - if touched[j] then - interpolate = math.max(interpolate,right_face[j] - (y_values[i] - y_values[j])) - break - end - end - right_face[i] = math.max(interpolate,right_face[i]) + -- Search for next and previous touched + local interpolate = -math.huge + for j=i+1,#y_values do + if touched[j] then + interpolate = math.max(interpolate,right_face[j] - (y_values[j] - y_values[i])) + break + end + end + for j=i-1,1,-1 do + if touched[j] then + interpolate = math.max(interpolate,right_face[j] - (y_values[i] - y_values[j])) + break + end + end + right_face[i] = math.max(interpolate,right_face[i]) end right_max = math.max(right_max, right_face[i]) end @@ -1016,30 +1017,30 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) local border = info.min_x for i=y_ranks[info.min_y],y_ranks[info.max_y] do - touched[i] = true - left_face[i] = math.min(left_face[i], border) + touched[i] = true + left_face[i] = math.min(left_face[i], border) end end - + -- Fill up the untouched entries: local left_min = math.huge for i=1,#y_values do if not touched[i] then - -- Search for next and previous touched - local interpolate = math.huge - for j=i+1,#y_values do - if touched[j] then - interpolate = math.min(interpolate,left_face[j] + (y_values[j] - y_values[i])) - break - end - end - for j=i-1,1,-1 do - if touched[j] then - interpolate = math.min(interpolate,left_face[j] + (y_values[i] - y_values[j])) - break - end - end - left_face[i] = interpolate + -- Search for next and previous touched + local interpolate = math.huge + for j=i+1,#y_values do + if touched[j] then + interpolate = math.min(interpolate,left_face[j] + (y_values[j] - y_values[i])) + break + end + end + for j=i-1,1,-1 do + if touched[j] then + interpolate = math.min(interpolate,left_face[j] + (y_values[i] - y_values[j])) + break + end + end + left_face[i] = interpolate end left_min = math.min(left_min, left_face[i]) end @@ -1051,10 +1052,10 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) shift = right_max - left_min else for i=1,#y_values do - shift = math.max(shift, right_face[i] - left_face[i]) + shift = math.max(shift, right_face[i] - left_face[i]) end end - + -- Adjust nodes: x_shifts[i+1] = shift for _,v in ipairs(vertices[components[i+1]]) do @@ -1063,12 +1064,12 @@ function LayoutPipeline.packComponents(syntactic_digraph, components) info.max_x = info.max_x + shift end end - + -- Now, rotate shifts for i,c in ipairs(components) do local x = x_shifts[i]*math.cos(angle) - y_shifts[i]*math.sin(angle) local y = x_shifts[i]*math.sin(angle) + y_shifts[i]*math.cos(angle) - + for _,v in ipairs(vertices[c]) do v.pos.x = v.pos.x + x v.pos.y = v.pos.y + y @@ -1094,13 +1095,13 @@ prepare_events = for i=1,#events do if events[i].kind == "begin" then - stack[#stack + 1] = i + stack[#stack + 1] = i elseif events[i].kind == "end" then - local tos = stack[#stack] - stack[#stack] = nil -- pop - - events[tos].end_index = i - events[i].begin_index = tos + local tos = stack[#stack] + stack[#stack] = nil -- pop + + events[tos].end_index = i + events[i].begin_index = tos end end end @@ -1124,48 +1125,48 @@ function LayoutPipeline.cutEdges(graph) local p = e.path p:makeRigid() local orig = p:clone() - - if e.options['tail cut'] and e.tail.options['cut policy'] == "as edge requests" - or e.tail.options['cut policy'] == "all" then - - local vpath = e.tail.path:clone() - vpath:shiftByCoordinate(e.tail.pos) - - local x = p:intersectionsWith (vpath) - - if #x > 0 then - p:cutAtBeginning(x[1].index, x[1].time) - end + + if e.options['tail cut'] and e.tail.options['cut policy'] == "as edge requests" + or e.tail.options['cut policy'] == "all" then + + local vpath = e.tail.path:clone() + vpath:shiftByCoordinate(e.tail.pos) + + local x = p:intersectionsWith (vpath) + + if #x > 0 then + p:cutAtBeginning(x[1].index, x[1].time) + end end - - if e.options['head cut'] and e.head.options['cut policy'] == "as edge requests" - or e.head.options['cut policy'] == "all" then - - local vpath = e.head.path:clone() - vpath:shiftByCoordinate(e.head.pos) - x = p:intersectionsWith (vpath) - if #x > 0 then - p:cutAtEnd(x[#x].index, x[#x].time) - else - -- Check whether there was an intersection with the original - --path: - local x2 = orig:intersectionsWith (vpath) - if #x2 > 0 then - -- Ok, after cutting the tail vertex, there is no longer - -- an intersection with the head vertex, but there used to - -- be one. This means that the vertices overlap and the - -- path should be ``inside'' them. Hmm... - if e.options['allow inside edges'] and #p > 1 then - local from = p[2] - local to = x2[1].point - p:clear() - p:appendMoveto(from) - p:appendLineto(to) - else - p:clear() - end - end - end + + if e.options['head cut'] and e.head.options['cut policy'] == "as edge requests" + or e.head.options['cut policy'] == "all" then + + local vpath = e.head.path:clone() + vpath:shiftByCoordinate(e.head.pos) + x = p:intersectionsWith (vpath) + if #x > 0 then + p:cutAtEnd(x[#x].index, x[#x].time) + else + -- Check whether there was an intersection with the original + --path: + local x2 = orig:intersectionsWith (vpath) + if #x2 > 0 then + -- Ok, after cutting the tail vertex, there is no longer + -- an intersection with the head vertex, but there used to + -- be one. This means that the vertices overlap and the + -- path should be ``inside'' them. Hmm... + if e.options['allow inside edges'] and #p > 1 then + local from = p[2] + local to = x2[1].point + p:clear() + p:appendMoveto(from) + p:appendLineto(to) + else + p:clear() + end + end + end end end end @@ -1200,7 +1201,7 @@ local function compatibility_digraph_to_graph(scope, g) for i,e in ipairs(scope.events) do graph.events[i] = e end - + -- Nodes for _,v in ipairs(g.vertices) do if not v.name then @@ -1212,13 +1213,13 @@ local function compatibility_digraph_to_graph(scope, g) local node = Node.new{ name = v.name, tex = { - tex_node = v.tex and v.tex.stored_tex_box_number, - shape = v.shape, - minX = minX, - maxX = maxX, - minY = minY, - maxY = maxY, - }, + tex_node = v.tex and v.tex.stored_tex_box_number, + shape = v.shape, + minX = minX, + maxX = maxX, + minY = minY, + maxY = maxY, + }, options = v.options, event_index = v.event.index, index = v.event.index, @@ -1234,38 +1235,38 @@ local function compatibility_digraph_to_graph(scope, g) local da = g.syntactic_digraph:arc(a.tail, a.head) if da then for _,m in ipairs(da.syntactic_edges) do - if not mark[m] then - mark[m] = true - local from_node = graph:findNode(da.tail.name) - local to_node = graph:findNode(da.head.name) - local edge = graph:createEdge(from_node, to_node, m.direction, nil, m.options, nil) - edge.event_index = m.event.index - edge.orig_m = m - graph.events[m.event.index] = { kind = 'edge', parameters = edge } - end + if not mark[m] then + mark[m] = true + local from_node = graph:findNode(da.tail.name) + local to_node = graph:findNode(da.head.name) + local edge = graph:createEdge(from_node, to_node, m.direction, nil, m.options, nil) + edge.event_index = m.event.index + edge.orig_m = m + graph.events[m.event.index] = { kind = 'edge', parameters = edge } + end end end local da = g.syntactic_digraph:arc(a.head, a.tail) - if da then + if da then for _,m in ipairs(da.syntactic_edges) do - if not mark[m] then - mark[m] = true - local from_node = graph:findNode(da.tail.name) - local to_node = graph:findNode(da.head.name) - local edge = graph:createEdge(from_node, to_node, m.direction, nil, m.options, nil) - edge.event_index = m.event.index - edge.orig_m = m - graph.events[m.event.index] = { kind = 'edge', parameters = edge } - end + if not mark[m] then + mark[m] = true + local from_node = graph:findNode(da.tail.name) + local to_node = graph:findNode(da.head.name) + local edge = graph:createEdge(from_node, to_node, m.direction, nil, m.options, nil) + edge.event_index = m.event.index + edge.orig_m = m + graph.events[m.event.index] = { kind = 'edge', parameters = edge } + end end end end - + table.sort(graph.edges, function(e1,e2) return e1.event_index < e2.event_index end) for _,n in ipairs (graph.nodes) do table.sort(n.edges, function(e1,e2) return e1.event_index < e2.event_index end) end - + -- Clusters for _, c in ipairs(scope.collections['same layer'] or {}) do @@ -1274,7 +1275,7 @@ local function compatibility_digraph_to_graph(scope, g) graph:addCluster(cluster) for _,v in ipairs(c.vertices) do if g:contains(v) then - cluster:addNode(graph:findNode(v.name)) + cluster:addNode(graph:findNode(v.name)) end end end @@ -1292,7 +1293,7 @@ local function compatibility_graph_to_digraph(graph) if #e.bend_points > 0 then local c = {} for _,x in ipairs(e.bend_points) do - c[#c+1] = Coordinate.new (x.x, x.y) + c[#c+1] = Coordinate.new (x.x, x.y) end e.orig_m:setPolylinePath(c) end @@ -1309,12 +1310,12 @@ function LayoutPipeline.runOldGraphModel(scope, digraph, algorithm_class, algori algorithm.graph = graph graph:registerAlgorithm(algorithm) - + -- If requested, remove loops if algorithm_class.preconditions.loop_free then Simplifiers:removeLoopsOldModel(algorithm) end - + -- If requested, collapse multiedges if algorithm_class.preconditions.simple then Simplifiers:collapseMultiedgesOldModel(algorithm) @@ -1324,12 +1325,12 @@ function LayoutPipeline.runOldGraphModel(scope, digraph, algorithm_class, algori -- Main run of the algorithm: algorithm:run () end - + -- If requested, expand multiedges if algorithm_class.preconditions.simple then Simplifiers:expandMultiedgesOldModel(algorithm) end - + -- If requested, restore loops if algorithm_class.preconditions.loop_free then Simplifiers:restoreLoopsOldModel(algorithm) @@ -1343,4 +1344,4 @@ end -- Done -return LayoutPipeline
\ No newline at end of file +return LayoutPipeline diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua index e7d44d7d10e..80aa7ef420a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/NodeAnchors.lua @@ -18,9 +18,9 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare -- -- \label{section-gd-anchors} -- --- When a graph has been layed out completely, the edges between the +-- When a graph has been laid out completely, the edges between the -- nodes must be drawn. Conceptually, an edge is ``between two --- nodes,'' but when we actually draw the node, we do not really want +-- nodes'', but when we actually draw the node, we do not really want -- the edge's path to start ``in the middle'' of the node; rather, we -- want it to start ``on the border'' and also end there. -- @@ -37,7 +37,7 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare -- inside the tail and head nodes, respectively. The edge path will -- then start and end at these points, however, they will usually be -- shortened so that they actually start and end on the intersection --- of the edge's path with the nodes' paths. +-- of the edge's path with the nodes' paths. --- @@ -47,41 +47,41 @@ declare { type = "string", initial = "", - summary = [[" - Specifies where in the tail vertex the edge should start. + summary = [[" + Specifies where in the tail vertex the edge should start. "]], documentation = [[" - This is either a string or a number, interpreted as an angle - (with 90 meaning ``up''). If it is a string, when the start of - the edge is computed, we try to look up the anchor in the tail - vertex's table of anchors (some anchors get installed in this - table by the display system). If it is not found, we test - whether it is one of the special ``direction anchors'' like - |north| or |south east|. If so, we convert them into points on - the border of the node that lie in the direction of a line - starting at the center to a point on the bounding box of the - node in the designated direction. Finally, if the anchor is a - number, we use a point on the border of the node that is on a - line from the center in the specified direction. - - If the anchor is set to the empty string (which is the default), - the anchor is interpreted as the |center| anchor inside the - graph drawing system. However, a display system may choose to - make a difference between the |center| anchor and an empty - anchor (\tikzname\ does: for options like |bend left| if the - anchor is empty, the bend line starts at the border of the node, - while for the anchor set explicitly to |center| it starts at the - center). - - Note that graph drawing algorithms need not take the - setting of this option into consideration. However, the final - rendering of the edge will always take it into consideration - (only, the setting may not be very sensible if the algorithm - ignored it). + This is either a string or a number, interpreted as an angle + (with 90 meaning ``up''). If it is a string, when the start of + the edge is computed, we try to look up the anchor in the tail + vertex's table of anchors (some anchors get installed in this + table by the display system). If it is not found, we test + whether it is one of the special ``direction anchors'' like + |north| or |south east|. If so, we convert them into points on + the border of the node that lie in the direction of a line + starting at the center to a point on the bounding box of the + node in the designated direction. Finally, if the anchor is a + number, we use a point on the border of the node that is on a + line from the center in the specified direction. + + If the anchor is set to the empty string (which is the default), + the anchor is interpreted as the |center| anchor inside the + graph drawing system. However, a display system may choose to + make a difference between the |center| anchor and an empty + anchor (\tikzname\ does: for options like |bend left| if the + anchor is empty, the bend line starts at the border of the node, + while for the anchor set explicitly to |center| it starts at the + center). + + Note that graph drawing algorithms need not take the + setting of this option into consideration. However, the final + rendering of the edge will always take it into consideration + (only, the setting may not be very sensible if the algorithm + ignored it). "]] } - + --- declare { @@ -101,10 +101,10 @@ declare { initial = true, summary = [[" - Decides whether the tail of an edge is ``cut'', meaning - that the edge's path will be shortened at the beginning so that - it starts only of the node's border rather than at the exact - position of the |tail anchor|, which may be inside the node. + Decides whether the tail of an edge is ``cut'', meaning + that the edge's path will be shortened at the beginning so that + it starts only of the node's border rather than at the exact + position of the |tail anchor|, which may be inside the node. "]] } @@ -130,23 +130,24 @@ declare { summary = "The policy for cutting edges entering or leaving a node.", documentation = [[" - This option is important for nodes only. It can have three - possible values: - \begin{itemize} + This option is important for nodes only. It can have three + possible values: + % + \begin{itemize} \item |as edge requests| Whether or not an edge entering or - leaving the node is cut depends on the setting of the edge's - |tail cut| and |head cut| options. This is the default. + leaving the node is cut depends on the setting of the edge's + |tail cut| and |head cut| options. This is the default. \item |all| All edges entering or leaving the node are cut, - regardless of the edges' cut values. + regardless of the edges' cut values. \item |none| No edge entering or leaving the node is cut, - regardless of the edges' cut values. - \end{itemize} + regardless of the edges' cut values. + \end{itemize} "]] } - + --- -declare { +declare { key = "allow inside edges", type = "boolean", initial = "true", @@ -154,21 +155,21 @@ declare { summary = "Decides whether an edge between overlapping nodes should be drawn.", documentation = [[" - If two vertices overlap, it may happen that when you draw an - edge between them, this edges would be completely inside the two - vertices. In this case, one could either not draw them or one - could draw a sort of ``inside edge''. + If two vertices overlap, it may happen that when you draw an + edge between them, this edges would be completely inside the two + vertices. In this case, one could either not draw them or one + could draw a sort of ``inside edge''. "]], - + examples = { [[" - \tikz \graph [no layout, nodes={draw, minimum size=20pt}] { - a [x=0, y=0] -- b [x=15pt, y=10pt] -- c[x=40pt] - }; - "]], [[" - \tikz \graph [no layout, nodes={draw, minimum size=20pt}, - allow inside edges=false] { - a [x=0, y=0] -- b [x=15pt, y=10pt] -- c[x=40pt] - }; - "]] + \tikz \graph [no layout, nodes={draw, minimum size=20pt}] { + a [x=0, y=0] -- b [x=15pt, y=10pt] -- c[x=40pt] + }; + "]],[[" + \tikz \graph [no layout, nodes={draw, minimum size=20pt}, + allow inside edges=false] { + a [x=0, y=0] -- b [x=15pt, y=10pt] -- c[x=40pt] + }; + "]] } }
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Orientation.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Orientation.lua index 10f5ecdf471..1890fa4f39d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Orientation.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Orientation.lua @@ -27,7 +27,7 @@ -- you can specify that the line from a certain vertex to another -- vertex should have a certain slope. How these vertices and slopes -- are specified in explained momentarily. Second, you can specify a --- so-called ``growth direction'' for trees. +-- so-called ``growth direction'' for trees. -- -- @end @@ -48,42 +48,40 @@ declare { type = "direction", default = 0, - summary = [[" - This key specifies that the straight line from the |orient tail| to - the |orient head| should be at an angle of \meta{direction} relative to - the right-going $x$-axis. Which vertices are used as tail an head - depends on where the |orient| option is encountered: When used with - an edge, the tail is the edge's tail und the head is the edge's - head. When used with a node, the tail or the head must be specified - explicitly and the node is used as the node missing in the - specification. When used with a graph as a whole, both the head and - tail nodes must be specified explicitly. + summary = [[" + This key specifies that the straight line from the |orient tail| to + the |orient head| should be at an angle of \meta{direction} relative to + the right-going $x$-axis. Which vertices are used as tail an head + depends on where the |orient| option is encountered: When used with + an edge, the tail is the edge's tail and the head is the edge's + head. When used with a node, the tail or the head must be specified + explicitly and the node is used as the node missing in the + specification. When used with a graph as a whole, both the head and + tail nodes must be specified explicitly. "]], documentation = [[" - Note that the \meta{direction} is independent of the actual to-path - of an edge, which might define a bend or more complicated shapes. For - instance, a \meta{angle} of |45| requests that the end node is ``up - and right'' relative to the start node. - - You can also specify the standard direction texts |north| or |south east| - and so forth as \meta{direction} and also |up|, |down|, |left|, and |right|. Also, you - can specify |-| for ``right'' and \verb!|! for ``down.'' - "]], - examples = { - [[" - \tikz \graph [spring layout] - { - a -- { b, c, d, e -- {f, g, h} }; - h -- [orient=30] a; - }; - "]], - [[" - \tikz \graph [spring layout] - { - a -- { b, c, d[> orient=right], e -- {f, g, h} }; - h -- a; - }; - "]] + Note that the \meta{direction} is independent of the actual to-path + of an edge, which might define a bend or more complicated shapes. For + instance, a \meta{angle} of |45| requests that the end node is ``up + and right'' relative to the start node. + + You can also specify the standard direction texts |north| or |south east| + and so forth as \meta{direction} and also |up|, |down|, |left|, and + |right|. Also, you can specify |-| for ``right'' and \verb!|! for ``down''. + "]], + examples = {[[" + \tikz \graph [spring layout] + { + a -- { b, c, d, e -- {f, g, h} }; + h -- [orient=30] a; + }; + "]],[[" + \tikz \graph [spring layout] + { + a -- { b, c, d[> orient=right], e -- {f, g, h} }; + h -- a; + }; + "]] } } @@ -95,16 +93,16 @@ declare { type = "direction", default = 0, - summary = [[" - Same as |orient|, only the rest of the graph should be - flipped relative to the connection line. + summary = [[" + Same as |orient|, only the rest of the graph should be + flipped relative to the connection line. "]], examples = [[" - \tikz \graph [spring layout] - { - a -- { b, c, d[> orient'=right], e -- {f, g, h} }; - h -- a; - }; + \tikz \graph [spring layout] + { + a -- { b, c, d[> orient'=right], e -- {f, g, h} }; + h -- a; + }; "]] } @@ -114,26 +112,24 @@ declare { key = "orient tail", type = "string", - summary = [[" - Specifies the tail vertex for the orientation of a graph. See - |orient| for details. + summary = [[" + Specifies the tail vertex for the orientation of a graph. See + |orient| for details. "]], - examples = { - [[" - \tikz \graph [spring layout] { - a [orient=|, orient tail=f] -- { b, c, d, e -- {f, g, h} }; - { h, g } -- a; - }; - "]], - [[" - \tikz \graph [spring layout] { - a [orient=down, orient tail=h] -- { b, c, d, e -- {f, g, h} }; - { h, g } -- a; - }; - "]] + examples = {[[" + \tikz \graph [spring layout] { + a [orient=|, orient tail=f] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz \graph [spring layout] { + a [orient=down, orient tail=h] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]] } } - + @@ -144,23 +140,21 @@ declare { key = "orient head", type = "string", - summary = [[" - Specifies the head vertex for the orientation of a graph. See - |orient| for details. + summary = [[" + Specifies the head vertex for the orientation of a graph. See + |orient| for details. "]], - examples = { - [[" - \tikz \graph [spring layout] - { - a [orient=|, orient head=f] -- { b, c, d, e -- {f, g, h} }; - { h, g } -- a; - }; - "]], - [[" - \tikz \graph [spring layout] { a -- b -- c -- a }; - \tikz \graph [spring layout, orient=10, - orient tail=a, orient head=b] { a -- b -- c -- a }; - "]] + examples = {[[" + \tikz \graph [spring layout] + { + a [orient=|, orient head=f] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz \graph [spring layout] { a -- b -- c -- a }; + \tikz \graph [spring layout, orient=10, + orient tail=a, orient head=b] { a -- b -- c -- a }; + "]] } } @@ -170,17 +164,17 @@ declare { key = "horizontal", type = "string", - summary = [[" - A shorthand for specifying |orient tail|, |orient head| and - |orient=0|. The tail will be everything before the part ``| to |'' - and the head will be everything following it. + summary = [[" + A shorthand for specifying |orient tail|, |orient head| and + |orient=0|. The tail will be everything before the part ``| to |'' + and the head will be everything following it. "]], - examples = [[" - \tikz \graph [spring layout] { a -- b -- c -- a }; - \tikz \graph [spring layout, horizontal=a to b] { a -- b -- c -- a }; + examples = [[" + \tikz \graph [spring layout] { a -- b -- c -- a }; + \tikz \graph [spring layout, horizontal=a to b] { a -- b -- c -- a }; "]] } - + @@ -190,11 +184,11 @@ declare { key = "horizontal'", type = "string", - summary = [[" - Like |horizontal|, but with a flip. + summary = [[" + Like |horizontal|, but with a flip. "]] } - + @@ -207,16 +201,15 @@ declare { key = "vertical", type = "string", - summary = [[" - A shorthand for specifying |orient tail|, |orient head| and - |orient=-90|. + summary = [[" + A shorthand for specifying |orient tail|, |orient head| and |orient=-90|. "]], examples = [[" - \tikz \graph [spring layout] { a -- b -- c -- a }; - \tikz \graph [spring layout, vertical=a to b] { a -- b -- c -- a }; + \tikz \graph [spring layout] { a -- b -- c -- a }; + \tikz \graph [spring layout, vertical=a to b] { a -- b -- c -- a }; "]] } - + @@ -227,8 +220,8 @@ declare { key = "vertical'", type = "string", - summary = [[" - Like |vertical|, but with a flip. + summary = [[" + Like |vertical|, but with a flip. "]] } @@ -240,54 +233,50 @@ declare { key = "grow", type = "direction", - summary = [[" - This key specifies in which direction the neighbors of a node - ``should grow.'' For some graph drawing algorithms, especially for - those that layout trees, but also for those that produce layered - layouts, there is a natural direction in which the ``children'' of - a node should be placed. For instance, saying |grow=down| will cause - the children of a node in a tree to be placed in a left-to-right - line below the node (as always, you can replace the \meta{angle} - by direction texts). The children are requested to be placed in a - counter-clockwise fashion, the |grow'| key will place them in a - clockwise fashion. + summary = [[" + This key specifies in which direction the neighbors of a node + ``should grow''. For some graph drawing algorithms, especially for + those that layout trees, but also for those that produce layered + layouts, there is a natural direction in which the ``children'' of + a node should be placed. For instance, saying |grow=down| will cause + the children of a node in a tree to be placed in a left-to-right + line below the node (as always, you can replace the \meta{angle} + by direction texts). The children are requested to be placed in a + counter-clockwise fashion, the |grow'| key will place them in a + clockwise fashion. "]], - documentation = [[" - Note that when you say |grow=down|, it is not necessarily the case - that any particular node is actually directly below the current - node; the key just requests that the direction of growth is - downward. - - In principle, you can specify the direction of growth for each node - individually, but do not count on graph drawing algorithms to - honour these wishes. - - When you give the |grow=right| key to the graph as a whole, it will - be applied to all nodes. This happens to be exactly what you want: + documentation = [[" + Note that when you say |grow=down|, it is not necessarily the case + that any particular node is actually directly below the current + node; the key just requests that the direction of growth is downward. + + In principle, you can specify the direction of growth for each node + individually, but do not count on graph drawing algorithms to + honor these wishes. + + When you give the |grow=right| key to the graph as a whole, it will + be applied to all nodes. This happens to be exactly what you want: "]], - examples = { - [[" - \tikz \graph [layered layout, sibling distance=5mm] - { - a [grow=right] -- { b, c, d, e -- {f, g, h} }; - { h, g } -- a; - }; - "]], - [[" - \tikz \graph [layered layout, grow=right, sibling distance=5mm] - { - a -- { b, c, d, e -- {f, g, h} }; - { h, g } -- a; - }; - "]], - [[" - \tikz - \graph [layered layout, grow=-80] - { - {a,b,c} --[complete bipartite] {e,d,f} - --[complete bipartite] {g,h,i}; - }; - "]] + examples = {[[" + \tikz \graph [layered layout, sibling distance=5mm] + { + a [grow=right] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz \graph [layered layout, grow=right, sibling distance=5mm] + { + a -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; + "]],[[" + \tikz + \graph [layered layout, grow=-80] + { + {a,b,c} --[complete bipartite] {e,d,f} + --[complete bipartite] {g,h,i}; + }; + "]] } } @@ -300,11 +289,11 @@ declare { summary = "Same as |grow|, only with the children in clockwise order.", examples = [[" - \tikz \graph [layered layout, sibling distance=5mm] - { - a [grow'=right] -- { b, c, d, e -- {f, g, h} }; - { h, g } -- a; - }; + \tikz \graph [layered layout, sibling distance=5mm] + { + a [grow'=right] -- { b, c, d, e -- {f, g, h} }; + { h, g } -- a; + }; "]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Sublayouts.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Sublayouts.lua index c28d12db563..970483193f0 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Sublayouts.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/Sublayouts.lua @@ -15,7 +15,7 @@ local function full_print(g, pref) for _,v in ipairs(g.vertices) do s = s .. tostring(v) .. "[" .. tostring(v.pos) .. "]\n " end - + s = s .. "\n" for _,a in ipairs(g.arcs) do @@ -23,16 +23,16 @@ local function full_print(g, pref) s = s .. tostring(e) .. "(" .. tostring(e.path) .. ")\n" end end - + pgf.debug((pref or "") .. s) end --- --- The |Sublayouts| module handles graphs for which multiple layouts are defined. +-- The |Sublayouts| module handles graphs for which multiple layouts are defined. -- -- Please see Section~\ref{section-gd-sublayouts} for an overview of --- sublayouts. +-- sublayouts. -- local Sublayouts = {} @@ -80,7 +80,7 @@ end -- Nudge positioning. You can call this function several times on the --- same graph; nudging will be done only once. +-- same graph; nudging will be done only once. -- -- @param graph A graph -- @@ -100,28 +100,28 @@ end -- -- @param scope A scope -- @param syntactic_digraph The syntactic digraph. --- @param test Only for vertices whose subgraph collection passes this test will we create subgraph nodes +-- @param test Only for vertices whose subgraph collection passes this test will we create subgraph nodes local function create_subgraph_node(scope, syntactic_digraph, vertex) - + local subgraph_collection = vertex.subgraph_collection local binding = InterfaceCore.binding - + local cloud = {} -- Add all points of n's collection, except for v itself, to the cloud: for _,v in ipairs(subgraph_collection.vertices) do if vertex ~= v then assert(syntactic_digraph:contains(v), "the layout must contain all nodes of the subgraph") for _,p in ipairs(v.path) do - if type(p) == "table" then - cloud[#cloud+1] = p + v.pos - end + if type(p) == "table" then + cloud[#cloud+1] = p + v.pos + end end end end for _,e in ipairs(subgraph_collection.edges) do for _,p in ipairs(e.path) do if type(p) == "table" then - cloud[#cloud+1] = p:clone() + cloud[#cloud+1] = p:clone() end end end @@ -137,13 +137,13 @@ local function create_subgraph_node(scope, syntactic_digraph, vertex) o[#o+1] = { key = "subgraph point cloud", value = table.concat(lib.imap(cloud, tostring)) } o[#o+1] = { key = "subgraph bounding box height", value = tostring(y_max-y_min) .. "pt" } o[#o+1] = { key = "subgraph bounding box width", value = tostring(x_max-x_min) .. "pt" } - + -- And now, the "grand call": binding:createVertex(vertex.subgraph_info) - + -- Shift it were it belongs vertex.pos:shift(c_x,c_y) - + -- Remember all the subnodes for nudging and regardless -- positioning local s = {} @@ -191,22 +191,22 @@ end -- @return A laid out graph. function Sublayouts.layoutRecursively(scope, layout, fun) - + -- Step 1: Iterate over all sublayouts of the current layout: local resulting_graphs = {} local loc = Storage.new() - + -- Now, iterate over all sublayouts for i,child in ipairs(layout:childrenOfKind(InterfaceCore.sublayout_kind)) do resulting_graphs[i] = Sublayouts.layoutRecursively(scope, child, fun) loc[resulting_graphs[i]] = child end - + -- Step 2: Run the merge process: local merged_graphs = {} - + while #resulting_graphs > 0 do - + local n = #resulting_graphs -- Setup marked array: @@ -214,57 +214,57 @@ function Sublayouts.layoutRecursively(scope, layout, fun) for i=1,n do marked[i] = false end - + -- Mark first graph and copy everything from there marked[1] = true local touched = Storage.new() for _,v in ipairs(resulting_graphs[1].vertices) do v.pos = positions[v][resulting_graphs[1]] touched[v] = true - end + end -- Repeatedly find a node that is connected to a marked node: local i = 1 while i <= n do if not marked[i] then - for j=1,n do - if marked[j] then - local v = intersection(resulting_graphs[i], resulting_graphs[j]) - if v then - -- Aha, they intersect at vertex v - - -- Mark the i-th graph: - marked[i] = true - connected_some_graph = true - - -- Shift the i-th graph: - local x_offset = v.pos.x - positions[v][resulting_graphs[i]].x - local y_offset = v.pos.y - positions[v][resulting_graphs[i]].y - - for _,u in ipairs(resulting_graphs[i].vertices) do - if not touched[u] then - touched[u] = true - u.pos = positions[u][resulting_graphs[i]]:clone() - u.pos:shift(x_offset, y_offset) - - for _,a in ipairs(resulting_graphs[i]:outgoing(u)) do - for _,e in ipairs(a.syntactic_edges) do - for _,p in ipairs(e.path) do - if type(p) == "table" then - p:shift(x_offset, y_offset) - end - end - end - end - end - end - - -- Restart - i = 0 - break - end - end - end + for j=1,n do + if marked[j] then + local v = intersection(resulting_graphs[i], resulting_graphs[j]) + if v then + -- Aha, they intersect at vertex v + + -- Mark the i-th graph: + marked[i] = true + connected_some_graph = true + + -- Shift the i-th graph: + local x_offset = v.pos.x - positions[v][resulting_graphs[i]].x + local y_offset = v.pos.y - positions[v][resulting_graphs[i]].y + + for _,u in ipairs(resulting_graphs[i].vertices) do + if not touched[u] then + touched[u] = true + u.pos = positions[u][resulting_graphs[i]]:clone() + u.pos:shift(x_offset, y_offset) + + for _,a in ipairs(resulting_graphs[i]:outgoing(u)) do + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:shift(x_offset, y_offset) + end + end + end + end + end + end + + -- Restart + i = 0 + break + end + end + end end i = i + 1 end @@ -273,19 +273,19 @@ function Sublayouts.layoutRecursively(scope, layout, fun) local merge = Digraph.new {} merge.syntactic_digraph = merge local remaining = {} - + -- Add all vertices and edges: for i=1,n do if marked[i] then - merge:add (resulting_graphs[i].vertices) - for _,a in ipairs(resulting_graphs[i].arcs) do - local ma = merge:connect(a.tail,a.head) - for _,e in ipairs(a.syntactic_edges) do - ma.syntactic_edges[#ma.syntactic_edges+1] = e - end - end - else - remaining[#remaining + 1] = resulting_graphs[i] + merge:add (resulting_graphs[i].vertices) + for _,a in ipairs(resulting_graphs[i].arcs) do + local ma = merge:connect(a.tail,a.head) + for _,e in ipairs(a.syntactic_edges) do + ma.syntactic_edges[#ma.syntactic_edges+1] = e + end + end + else + remaining[#remaining + 1] = resulting_graphs[i] end end @@ -294,37 +294,37 @@ function Sublayouts.layoutRecursively(scope, layout, fun) -- Restart with rest: merged_graphs[#merged_graphs+1] = merge - + resulting_graphs = remaining end - + -- Step 3: Run the algorithm on the layout: - - local class = layout.options.algorithm_phases.main + + local class = layout.options.algorithm_phases.main assert (type(class) == "table", "algorithm selection failed") - + local algorithm = class local uncollapsed_subgraph_nodes = lib.imap( scope.collections[InterfaceCore.subgraph_node_kind] or {}, function (c) if c.parent_layout == layout then - return c.subgraph_node + return c.subgraph_node end end) - + -- Create a new syntactic digraph: local syntactic_digraph = Digraph.new { options = layout.options } syntactic_digraph.syntactic_digraph = syntactic_digraph - + -- Copy all vertices and edges from the collection... syntactic_digraph:add (layout.vertices) for _,e in ipairs(layout.edges) do syntactic_digraph:add {e.head, e.tail} - local arc = syntactic_digraph:connect(e.tail, e.head) + local arc = syntactic_digraph:connect(e.tail, e.head) arc.syntactic_edges[#arc.syntactic_edges+1] = e end @@ -335,13 +335,13 @@ function Sublayouts.layoutRecursively(scope, layout, fun) -- Test, if all vertices of the subgraph are in one of the merged graphs. for _,g in ipairs(merged_graphs) do if special_vertex_subset(vertices, g) then - -- Ok, we can create a subgraph now - create_subgraph_node(scope, syntactic_digraph, v) - -- Make it part of the collapse! - g:add{v} - -- Do not consider again - uncollapsed_subgraph_nodes[i] = false - break + -- Ok, we can create a subgraph now + create_subgraph_node(scope, syntactic_digraph, v) + -- Make it part of the collapse! + g:add{v} + -- Do not consider again + uncollapsed_subgraph_nodes[i] = false + break end end end @@ -353,7 +353,7 @@ function Sublayouts.layoutRecursively(scope, layout, fun) local intersection = {} for _,v in ipairs(g.vertices) do if syntactic_digraph:contains(v) then - intersection[#intersection+1] = v + intersection[#intersection+1] = v end end if #intersection > 0 then @@ -361,33 +361,33 @@ function Sublayouts.layoutRecursively(scope, layout, fun) -- hull) Hmm...: local array = {} for _,v in ipairs(g.vertices) do - local min_x, min_y, max_x, max_y = v:boundingBox() - array[#array+1] = Coordinate.new(min_x + v.pos.x, min_y + v.pos.y) - array[#array+1] = Coordinate.new(max_x + v.pos.x, max_y + v.pos.y) + local min_x, min_y, max_x, max_y = v:boundingBox() + array[#array+1] = Coordinate.new(min_x + v.pos.x, min_y + v.pos.y) + array[#array+1] = Coordinate.new(max_x + v.pos.x, max_y + v.pos.y) end for _,a in ipairs(g.arcs) do - for _,e in ipairs(a.syntactic_edges) do - for _,p in ipairs(e.path) do - if type(p) == "table" then - array[#array+1] = p - end - end - end + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + array[#array+1] = p + end + end + end end local x_min, y_min, x_max, y_max, c_x, c_y = Coordinate.boundingBox(array) -- Shift the graph so that it is centered on the origin: for _,v in ipairs(g.vertices) do - v.pos:unshift(c_x,c_y) + v.pos:unshift(c_x,c_y) end for _,a in ipairs(g.arcs) do - for _,e in ipairs(a.syntactic_edges) do - for _,p in ipairs(e.path) do - if type(p) == "table" then - p:unshift(c_x,c_y) - end - end - end + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:unshift(c_x,c_y) + end + end + end end x_min = x_min - c_x @@ -398,33 +398,33 @@ function Sublayouts.layoutRecursively(scope, layout, fun) local index = loc[g].event.index local v = Vertex.new { - -- Standard stuff - shape = "none", - kind = "node", - path = Path.new { - "moveto", - x_min, y_min, - x_min, y_max, - x_max, y_max, - x_max, y_min, - "closepath" - }, - options = {}, - event = scope.events[index] + -- Standard stuff + shape = "none", + kind = "node", + path = Path.new { + "moveto", + x_min, y_min, + x_min, y_max, + x_max, y_max, + x_max, y_min, + "closepath" + }, + options = {}, + event = scope.events[index] } - + -- Update node_event scope.events[index].parameters = v - + local collapse_vertex = syntactic_digraph:collapse( - intersection, - v, - nil, - function (new_arc, arc) - for _,e in ipairs(arc.syntactic_edges) do - new_arc.syntactic_edges[#new_arc.syntactic_edges+1] = e - end - end) + intersection, + v, + nil, + function (new_arc, arc) + for _,e in ipairs(arc.syntactic_edges) do + new_arc.syntactic_edges[#new_arc.syntactic_edges+1] = e + end + end) syntactic_digraph:remove(intersection) collapsed_vertices[#collapsed_vertices+1] = collapse_vertex @@ -432,14 +432,14 @@ function Sublayouts.layoutRecursively(scope, layout, fun) end -- Sort the vertices - table.sort(syntactic_digraph.vertices, function(u,v) return u.event.index < v.event.index end) - + table.sort(syntactic_digraph.vertices, function(u,v) return u.event.index < v.event.index end) + -- Should we "hide" the subgraph nodes? local hidden_node if not algorithm.include_subgraph_nodes then local subgraph_nodes = lib.imap (syntactic_digraph.vertices, - function (v) if v.kind == "subgraph node" then return v end end) - + function (v) if v.kind == "subgraph node" then return v end end) + if #subgraph_nodes > 0 then hidden_node = Vertex.new {} syntactic_digraph:collapse(subgraph_nodes, hidden_node) @@ -457,36 +457,36 @@ function Sublayouts.layoutRecursively(scope, layout, fun) -- Ok, everything setup! Run the algorithm... fun(scope, algorithm, syntactic_digraph, layout) - + if hidden_node then syntactic_digraph:expand(hidden_node) end - + -- Now, we need to expand the collapsed vertices once more: for i=#collapsed_vertices,1,-1 do syntactic_digraph:expand( collapsed_vertices[i], function (c, v) - v.pos:shiftByCoordinate(c.pos) + v.pos:shiftByCoordinate(c.pos) end, function (a, v) - for _,e in ipairs(a.syntactic_edges) do - for _,p in ipairs(e.path) do - if type(p) == "table" then - p:shiftByCoordinate(v.pos) - end - end - end + for _,e in ipairs(a.syntactic_edges) do + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:shiftByCoordinate(v.pos) + end + end + end end ) for _,a in ipairs(syntactic_digraph:outgoing(collapsed_vertices[i])) do for _,e in ipairs(a.syntactic_edges) do - for _,p in ipairs(e.path) do - if type(p) == "table" then - p:shiftByCoordinate(a.tail.pos) - p:unshiftByCoordinate(e.tail.pos) - end - end + for _,p in ipairs(e.path) do + if type(p) == "table" then + p:shiftByCoordinate(a.tail.pos) + p:unshiftByCoordinate(e.tail.pos) + end + end end end end @@ -498,16 +498,16 @@ function Sublayouts.layoutRecursively(scope, layout, fun) create_subgraph_node(scope, syntactic_digraph, uncollapsed_subgraph_nodes[i]) end end - + -- Now seems like a good time to nudge and do regardless positioning nudge(syntactic_digraph) - -- Step 5: Cleanup + -- Step 5: Cleanup -- Push the computed position into the storage: for _,v in ipairs(syntactic_digraph.vertices) do positions[v][syntactic_digraph] = v.pos:clone() end - + return syntactic_digraph end @@ -531,6 +531,6 @@ end --- Done +-- Done -return Sublayouts
\ No newline at end of file +return Sublayouts diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/doc.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/doc.lua index 2d8317bd72d..c7adfab830e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/doc.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/doc.lua @@ -30,6 +30,7 @@ documentation Now, when you set this key for a single node of a graph, then, by shifting the graph around, this ``wish'' can obviously always be fulfill: +% \begin{codeexample}[] \begin{tikzpicture} \draw [help lines] (0,0) grid (3,2); @@ -39,6 +40,7 @@ always be fulfill: }; \end{tikzpicture} \end{codeexample} +% \begin{codeexample}[] \begin{tikzpicture} \draw [help lines] (0,0) grid (3,2); @@ -48,6 +50,7 @@ always be fulfill: }; \end{tikzpicture} \end{codeexample} +% Since the key's name is a bit long and since the many braces and parentheses are a bit cumbersome, there is a special support for this key inside a |graph|: The standard |/tikz/at| key is redefined @@ -57,6 +60,7 @@ specify an |at| position for a node whose position it to be computed by a graph drawing algorithm.) A nice side effect of this is that you can use the |x| and |y| keys (see Section~\ref{section-graphs-xy}) to specify desired positions: +% \begin{codeexample}[] \begin{tikzpicture} \draw [help lines] (0,0) grid (3,2); @@ -66,6 +70,7 @@ Section~\ref{section-graphs-xy}) to specify desired positions: }; \end{tikzpicture} \end{codeexample} +% \begin{codeexample}[] \begin{tikzpicture} \draw [help lines] (0,0) grid (3,2); @@ -75,7 +80,7 @@ Section~\ref{section-graphs-xy}) to specify desired positions: }; \end{tikzpicture} \end{codeexample} - + A problem arises when two or more nodes have this key set, because then your ``desires'' for placement and the positions computed by the graph drawing algorithm may clash. Graph drawing algorithms are @@ -83,10 +88,10 @@ the graph drawing algorithm may clash. Graph drawing algorithms are ignore these desired positions since they will be taken care of in the so-called post-anchoring phase, see below. However, for some algorithms it makes a lot of sense to fix the positions of some -nodes and only compute the positions -of the other nodes relative to these nodes. For instance, for a -|spring layout| it makes perfect sense that some nodes are -``nailed to the canvas'' while other nodes can ``move freely''. +nodes and only compute the positions of the other nodes relative +to these nodes. For instance, for a |spring layout| it makes perfect +sense that some nodes are ``nailed to the canvas'' while other +nodes can ``move freely''. ]] example @@ -134,19 +139,21 @@ key "anchor node" summary [[ This option can be used with a graph to specify a node that -should be used for anchoring the whole graph. +should be used for anchoring the whole graph. ]] documentation [[ When this option is specified, after the layout has been computed, the whole graph will be shifted in such a way that the \meta{node name} is -either +either +% \begin{itemize} -\item at the current value of |anchor at| or -\item at the position that is specified in the form of a - |desired at| for the \meta{node name}. + \item at the current value of |anchor at| or + \item at the position that is specified in the form of a + |desired at| for the \meta{node name}. \end{itemize} +% Note how in the last example |c| is placed at |(1,1)| rather than |b| as would happen by default. ]] @@ -163,7 +170,7 @@ example [[ \begin{tikzpicture} \draw [help lines] (0,0) grid (3,2); - + \graph [layered layout, anchor node=c, edges=rounded corners] { a -- {b [x=1,y=1], c [x=1,y=1] } -- d -- a}; \end{tikzpicture} @@ -178,15 +185,15 @@ key "anchor at" summary [[ -The coordinate at which the graph should be anchored when no -explicit anchor is given for any node. The initial value is the origin. +The coordinate at which the graph should be anchored when no +explicit anchor is given for any node. The initial value is the origin. ]] example [[ \begin{tikzpicture} \draw [help lines] (0,0) grid (2,2); - + \graph [layered layout, edges=rounded corners, anchor at={(1,2)}] { a -- {b, c [anchor here] } -- d -- a}; \end{tikzpicture} @@ -216,7 +223,7 @@ example [[ \begin{tikzpicture} \draw [help lines] (0,0) grid (2,2); - + \graph [layered layout, edges=rounded corners] { a -- {b, c [anchor here] } -- d -- a}; \end{tikzpicture} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/library.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/library.lua index e25e0cd628e..df7ce68dd94 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/library.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/control/library.lua @@ -38,29 +38,29 @@ declare { type = "boolean", summary = "Specifies, that nodes should be drawn behind the edges", - documentation = [[" - Once a graph drawing algorithm has determined positions for the nodes, - they are drawn \emph{before} the edges are drawn; after - all, it is hard to draw an edge between nodes when their positions - are not yet known. However, we typically want the nodes to be - rendered \emph{after} or rather \emph{on top} of the edges. For - this reason, the default behaviour is that the nodes at their - final positions are collected in a box that is inserted into the - output stream only after the edges have been drawn -- which has - the effect that the nodes will be placed ``on top'' of the - edges. - - This behaviour can be changed using this option. When the key is - invoked, nodes are placed \emph{behind} the edges. + documentation = [[" + Once a graph drawing algorithm has determined positions for the nodes, + they are drawn \emph{before} the edges are drawn; after + all, it is hard to draw an edge between nodes when their positions + are not yet known. However, we typically want the nodes to be + rendered \emph{after} or rather \emph{on top} of the edges. For + this reason, the default behavior is that the nodes at their + final positions are collected in a box that is inserted into the + output stream only after the edges have been drawn -- which has + the effect that the nodes will be placed ``on top'' of the + edges. + + This behavior can be changed using this option. When the key is + invoked, nodes are placed \emph{behind} the edges. "]], examples = [[" - \tikz \graph [simple necklace layout, nodes={draw,fill=white}, - nodes behind edges] - { subgraph K_n [n=7], 1 [regardless at={(0,-1)}] }; + \tikz \graph [simple necklace layout, nodes={draw,fill=white}, + nodes behind edges] + { subgraph K_n [n=7], 1 [regardless at={(0,-1)}] }; "]] -} +} + - --- declare { @@ -69,13 +69,13 @@ declare { { key = "nodes behind edges", value = "false" }, }, - summary = [[" - This is the default placemenet of edges: Behind the nodes. + summary = [[" + This is the default placement of edges: Behind the nodes. "]], examples = [[" - \tikz \graph [simple necklace layout, nodes={draw,fill=white}, - edges behind nodes] - { subgraph K_n [n=7], 1 [regardless at={(0,-1)}] }; + \tikz \graph [simple necklace layout, nodes={draw,fill=white}, + edges behind nodes] + { subgraph K_n [n=7], 1 [regardless at={(0,-1)}] }; "]] } @@ -85,14 +85,14 @@ declare { type = "number", initial = "42", - summary = [[" - To ensure that the same is always shown in the same way when the - same algorithm is applied, the random is seed is reset on each call - of the graph drawing engine. To (possibly) get different results on - different runs, change this value. + summary = [[" + To ensure that the same is always shown in the same way when the + same algorithm is applied, the random is seed is reset on each call + of the graph drawing engine. To (possibly) get different results on + different runs, change this value. "]] } - + --- declare { @@ -111,45 +111,42 @@ declare { type = "number", initial = 1, - summary = [[" - Sets the ``weight'' of an edge or a node. For many algorithms, this - number tells the algorithm how ``important'' the edge or node is. - For instance, in a |layered layout|, an edge with a large |weight| - will be as short as possible. + summary = [[" + Sets the ``weight'' of an edge or a node. For many algorithms, this + number tells the algorithm how ``important'' the edge or node is. + For instance, in a |layered layout|, an edge with a large |weight| + will be as short as possible. "]], - examples = { - [[" - \tikz \graph [layered layout] { - a -- {b,c,d} -- e -- a; - }; - "]], - [[" - \tikz \graph [layered layout] { - a -- {b,c,d} -- e --[weight=3] a; - }; - "]] + examples = {[[" + \tikz \graph [layered layout] { + a -- {b,c,d} -- e -- a; + }; + "]],[[" + \tikz \graph [layered layout] { + a -- {b,c,d} -- e --[weight=3] a; + }; + "]] } } - - + + --- declare { key = "length", type = "length", initial = 1, - summary = [[" - Sets the ``length'' of an edge. Algorithms may take this value - into account when drawing a graph. + summary = [[" + Sets the ``length'' of an edge. Algorithms may take this value + into account when drawing a graph. + "]], + examples = {[[" + \tikz \graph [phylogenetic tree layout] { + a --[length=2] b --[length=1] {c,d}; + a --[length=3] e + }; "]], - examples = { - [[" - \tikz \graph [phylogenetic tree layout] { - a --[length=2] b --[length=1] {c,d}; - a --[length=3] e - }; - "]], } } @@ -161,24 +158,24 @@ declare { type = "number", initial = "0", - summary = [[" - The radius of a circular object used in graph drawing. + summary = [[" + The radius of a circular object used in graph drawing. "]] } - + --- - + declare { key = "no layout", algorithm = { run = function (self) - for _,v in ipairs(self.digraph.vertices) do - if v.options['desired at'] then - v.pos.x = v.options['desired at'].x - v.pos.y = v.options['desired at'].y - end - end + for _,v in ipairs(self.digraph.vertices) do + if v.options['desired at'] then + v.pos.x = v.options['desired at'].x + v.pos.y = v.options['desired at'].y + end + end end }, summary = "This layout does nothing.", } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua index 0b8d9e324fb..d7baed45daa 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Cluster.lua @@ -12,7 +12,7 @@ ---- The Cluser class defines a model of a cluster inside a graph. +--- The Cluster class defines a model of a cluster inside a graph. -- -- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Edge.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Edge.lua index 7d6369d2bc9..7355597955e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Edge.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Edge.lua @@ -43,7 +43,7 @@ Edge.NONE = "-!-" -- |nodes|: TODO \par -- |edge_nodes|: TODO \par -- |options|: TODO \par --- |tikz_options|: TODO \par +-- |tikz_options|: TODO \par -- |direction|: TODO \par -- |bend_points|: TODO \par -- |bend_nodes|: TODO \par @@ -90,14 +90,14 @@ end --- Returns the value of the edge option \meta{name}. -- -- @param name Name of the option. --- @param graph If this optional argument is given, --- in case the option is not set as a node parameter, +-- @param graph If this optional argument is given, +-- in case the option is not set as a node parameter, -- we try to look it up as a graph parameter. -- -- @return The value of the edge option \meta{name} or |nil|. -- function Edge:getOption(name, graph) - return lib.lookup_option(name, self, graph) + return lib.lookup_option(name, self, graph) end @@ -134,7 +134,7 @@ end --- Returns all nodes of the edge. -- --- Instead of calling |edge:getNodes()| the nodes can alternatively be +-- Instead of calling |edge:getNodes()| the nodes can alternatively be -- accessed directly with |edge.nodes|. -- -- @return All edges of the node. @@ -168,11 +168,11 @@ end ---- Gets first neighbour of the node (disregarding hyperedges). +--- Gets first neighbor of the node (disregarding hyperedges). -- --- @param node The node which first neighbour should be returned. +-- @param node The node which first neighbor should be returned. -- --- @return The first neighbour of the node. +-- @return The first neighbor of the node. -- function Edge:getNeighbour(node) if node == self.nodes[1] then @@ -199,7 +199,7 @@ function Edge:getHead() -- of <- edges is the first node local head_index = (self.direction == Edge.LEFT) and 1 or #self.nodes - -- if the edge should be assumed reversed, we simply switch head and + -- if the edge should be assumed reversed, we simply switch head and -- tail positions if self.reversed then head_index = (head_index == 1) and #self.nodes or 1 @@ -230,9 +230,9 @@ end -- -- This method only works for edges with two adjacent nodes. -- --- Edges may be reversed internally, so their head and tail might be switched. --- Whether or not this internal reversal is handled by this method --- can be specified with the optional second \meta{ignore\_reversed} parameter +-- Edges may be reversed internally, so their head and tail might be switched. +-- Whether or not this internal reversal is handled by this method +-- can be specified with the optional second \meta{ignore\_reversed} parameter -- which is |false| by default. -- -- @param node The node to check. @@ -246,7 +246,7 @@ function Edge:isHead(node) -- of <- edges is the first node local head_index = (self.direction == Edge.LEFT) and 1 or #self.nodes - -- if the edge should be assumed reversed, we simply switch head and + -- if the edge should be assumed reversed, we simply switch head and -- tail positions if self.reversed then head_index = (head_index == 1) and #self.nodes or 1 @@ -267,8 +267,8 @@ end -- This method only works for edges with two adjacent nodes. -- -- Edges may be reversed internally, so their head and tail might be switched. --- Whether or not this internal reversal is handled by this method --- can be specified with the optional second \meta{ignore\_reversed} parameter +-- Whether or not this internal reversal is handled by this method +-- can be specified with the optional second \meta{ignore\_reversed} parameter -- which is |false| by default. -- -- @param node The node to check. @@ -279,7 +279,7 @@ end -- function Edge:isTail(node, ignore_reversed) local result = false - + -- by default, the tail of -> edges is the first node and the tail -- of <- edges is the last node local tail_index = (self.direction == Edge.LEFT) and #self.nodes or 1 @@ -338,7 +338,7 @@ function Edge:__tostring() result = result .. table.concat(node_strings, ', ') end --return result .. ")" - + -- Note: the following lines generate a shorter string representation -- of the edge that is more readable and can be used for debugging. -- So please don't remove this: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Graph.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Graph.lua index 23712278990..161b89fd15d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Graph.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Graph.lua @@ -127,9 +127,9 @@ function Graph:addNode(node) if not self:findNode(node.name) then -- Does the node have an index, yet? if not node.index then - node.index = #self.nodes + 1 + node.index = #self.nodes + 1 end - + table.insert(self.nodes, node) end end @@ -143,8 +143,8 @@ end -- @return The removed node or |nil| if it was not found in the graph. -- function Graph:removeNode(node) - local _, index = lib.find(self.nodes, function (other) - return other.name == node.name + local _, index = lib.find(self.nodes, function (other) + return other.name == node.name end) if index then table.remove(self.nodes, index) @@ -170,7 +170,7 @@ end --- Looks up the first node for which the function \meta{test} returns |true|. -- --- @param test A function that takes one parameter (a |Node|) and returns +-- @param test A function that takes one parameter (a |Node|) and returns -- |true| or |false|. -- -- @return The first node for which \meta{test} returns |true|. @@ -183,7 +183,7 @@ end --- Like removeNode, but also deletes all adjacent edges of the removed node. -- --- This function also removes the deleted adjacent edges from all neighbours +-- This function also removes the deleted adjacent edges from all neighbors -- of the removed node. -- -- @param node The node to be deleted together with its adjacent edges. @@ -293,7 +293,7 @@ end ---- Creates and adds a new edge to the graph. +--- Creates and adds a new edge to the graph. -- -- @param first_node The first node of the new edge. -- @param second_node The second node of the new edge. @@ -305,7 +305,7 @@ end -- \item |Edge.BOTH| and -- \item |Edge.NONE| (for invisible edges). -- \end{itemize} --- @param edge_nodes A string of \tikzname\ edge nodes that needs to be passed +-- @param edge_nodes A string of \tikzname\ edge nodes that needs to be passed -- back to the \TeX layer unmodified. -- @param options The options of the new edge. -- @param tikz_options A table of \tikzname\ options to be used by graph drawing @@ -315,9 +315,9 @@ end -- function Graph:createEdge(first_node, second_node, direction, edge_nodes, options, tikz_options) local edge = Edge.new{ - direction = direction, + direction = direction, edge_nodes = edge_nodes, - options = options, + options = options, tikz_options = tikz_options } edge:addNode(first_node) @@ -393,4 +393,4 @@ end -- Done -return Graph
\ No newline at end of file +return Graph diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua index 9e41e1124ee..903291a892d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Iterators.lua @@ -39,40 +39,40 @@ local lib = require("pgf.gd.lib") -- @return An iterator for traversing \meta{graph} in a topological order. -- function Iterators.topologicallySorted(dag) - -- track visited edges + -- track visited edges local deleted_edges = {} -- collect all sources (nodes with no incoming edges) of the dag local sources = lib.imap(dag.nodes, function (node) if node:getInDegree() == 0 then return node end end) -- return the iterator function - return function () + return function () while #sources > 0 do -- fetch the next sink from the queue local source = table.remove(sources, 1) -- get its outgoing edges local out_edges = source:getOutgoingEdges() - + -- iterate over all outgoing edges we haven't visited yet for _,edge in ipairs(out_edges) do - if not deleted_edges[edge] then - -- mark the edge as visited - deleted_edges[edge] = true - - -- get the node at the other end of the edge - local neighbour = edge:getNeighbour(source) - - -- get a list of all incoming edges of the neighbour that have - -- not been visited yet - local in_edges = lib.imap(neighbour:getIncomingEdges(), - function (edge) if not deleted_edges[edge] then return edge end end) - - -- if there are no such edges then we have a new source - if #in_edges == 0 then - sources[#sources+1] = neighbour - end - end + if not deleted_edges[edge] then + -- mark the edge as visited + deleted_edges[edge] = true + + -- get the node at the other end of the edge + local neighbour = edge:getNeighbour(source) + + -- get a list of all incoming edges of the neighbor that have + -- not been visited yet + local in_edges = lib.imap(neighbour:getIncomingEdges(), + function (edge) if not deleted_edges[edge] then return edge end end) + + -- if there are no such edges then we have a new source + if #in_edges == 0 then + sources[#sources+1] = neighbour + end + end end -- return the current source @@ -88,4 +88,4 @@ end -- Done -return Iterators
\ No newline at end of file +return Iterators diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Node.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Node.lua index 84d3d3ee11f..379a65fafd8 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Node.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Node.lua @@ -48,12 +48,12 @@ function Node.new(values) local new = { class = Node, name = nil, - tex = { + tex = { -- texNode = nil, -- maxX = nil, -- minX = nil, -- maxY = nil, - -- minY = nil + -- minY = nil }, edges = {}, -- pos = nil, @@ -69,8 +69,8 @@ function Node.new(values) new [k] = v end end - if not new.pos then - new.pos = Vector.new(2) + if not new.pos then + new.pos = Vector.new(2) end return new end @@ -91,8 +91,8 @@ end --- Returns the value of the node option \meta{name}. -- -- @param name Name of the node option. --- @param graph If this optional argument is given, --- in case the option is not set as a node parameter, +-- @param graph If this optional argument is given, +-- in case the option is not set as a node parameter, -- we try to look it up as a graph parameter. -- -- @return The value of the node option \meta{name} or |nil|. @@ -113,7 +113,7 @@ end ---- Computes the heigth of the node. +--- Computes the height of the node. -- -- @return Height of the node. -- @@ -155,7 +155,7 @@ end --- Returns all edges of the node. -- --- Instead of calling |node:getEdges()| the edges can alternatively be +-- Instead of calling |node:getEdges()| the edges can alternatively be -- accessed directly with |node.edges|. -- -- @return All edges of the node. @@ -168,7 +168,7 @@ end --- Returns the incoming edges of the node. Undefined result for hyperedges. -- --- @param ignore_reversed Optional parameter to consider reversed edges not +-- @param ignore_reversed Optional parameter to consider reversed edges not -- reversed for this method call. Defaults to |false|. -- -- @return Incoming edges of the node. This includes undirected edges @@ -176,16 +176,16 @@ end -- function Node:getIncomingEdges(ignore_reversed) return lib.imap(self.edges, - function (edge) - if edge:isHead(self, ignore_reversed) then return edge end - end) + function (edge) + if edge:isHead(self, ignore_reversed) then return edge end + end) end --- Returns the outgoing edges of the node. Undefined result for hyperedges. -- --- @param ignore_reversed Optional parameter to consider reversed edges not +-- @param ignore_reversed Optional parameter to consider reversed edges not -- reversed for this method call. Defaults to |false|. -- -- @return Outgoing edges of the node. This includes undirected edges @@ -193,9 +193,9 @@ end -- function Node:getOutgoingEdges(ignore_reversed) return lib.imap(self.edges, - function (edge) - if edge:isTail(self, ignore_reversed) then return edge end - end) + function (edge) + if edge:isTail(self, ignore_reversed) then return edge end + end) end @@ -204,7 +204,7 @@ end -- -- @see Node:getIncomingEdges(reversed) -- --- @param ignore_reversed Optional parameter to consider reversed edges not +-- @param ignore_reversed Optional parameter to consider reversed edges not -- reversed for this method call. Defaults to |false|. -- -- @return The number of incoming edges of the node. @@ -219,7 +219,7 @@ end -- -- @see Node:getOutgoingEdges() -- --- @param ignore_reversed Optional parameter to consider reversed edges not +-- @param ignore_reversed Optional parameter to consider reversed edges not -- reversed for this method call. Defaults to |false|. -- -- @return The number of outgoing edges of the node. @@ -230,7 +230,7 @@ end ---- Creates a shallow copy of the node. +--- Creates a shallow copy of the node. -- -- Most notably, the edges adjacent are not preserved in the copy. -- @@ -262,7 +262,7 @@ end -- -- @ignore This should not appear in the documentation. -- --- @return String represenation of the node. +-- @return String representation of the node. -- function Node:__tostring() local tmp = Node.__tostring @@ -277,4 +277,4 @@ end -- Done -return Node
\ No newline at end of file +return Node diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Vector.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Vector.lua index ef8500b5aeb..8af7378154e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Vector.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Vector.lua @@ -28,7 +28,7 @@ lib.Vector = Vector -- Class setup Vector.__index = function (t, k) - if k == "x" then + if k == "x" then return rawget(t,1) elseif k == "y" then return rawget(t,2) @@ -37,8 +37,8 @@ Vector.__index = end end Vector.__newindex = - function (t, k, v) - if k == "x" then + function (t, k, v) + if k == "x" then rawset(t,1,v) elseif k == "y" then rawset(t,2,v) @@ -52,9 +52,9 @@ Vector.__newindex = --- Creates a new vector with \meta{n} values using an optional \meta{fill\_function}. -- -- @param n The number of elements of the vector. (If omitted, then 2.) --- @param fill_function Optional function that takes a number between 1 and \meta{n} +-- @param fill_function Optional function that takes a number between 1 and \meta{n} -- and is expected to return a value for the corresponding element --- of the vector. If omitted, all elements of the vector will +-- of the vector. If omitted, all elements of the vector will -- be initialized with 0. -- -- @return A newly-allocated vector with \meta{n} elements. @@ -65,7 +65,7 @@ function Vector.new(n, fill_function) setmetatable(vector, Vector) local n = n or 2 - + if type(n) == 'table' then for k,v in pairs(n) do vector[k] = v @@ -74,7 +74,7 @@ function Vector.new(n, fill_function) -- fill vector elements with values if not fill_function then for i = 1,n do - rawset(vector,i,0) + rawset(vector,i,0) end else for i = 1,n do @@ -91,7 +91,7 @@ end --- Creates a copy of the vector that holds the same elements as the original. -- -- @return A newly-allocated copy of the vector holding exactly the same elements. --- +-- function Vector:copy() return Vector.new(#self, function (n) return self[n] end) end @@ -100,7 +100,7 @@ end --- Performs a vector addition and returns the result in a new vector. -- --- @param other The vector to add. +-- @param other The vector to add. -- -- @return A new vector with the result of the addition. -- @@ -114,7 +114,7 @@ end --- Subtracts two vectors and returns the result in a new vector. -- --- @param other Vector to subtract. +-- @param other Vector to subtract. -- -- @return A new vector with the result of the subtraction. -- @@ -196,7 +196,7 @@ end --- Updates the values of the vector in-place. -- -- @param update_function A function that is called for each element of the --- vector. The elements are replaced by the values +-- vector. The elements are replaced by the values -- returned from this function. -- function Vector:update(update_function) @@ -253,4 +253,4 @@ end -- Done -return Vector
\ No newline at end of file +return Vector diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc.lua index 428091a9ae4..78b68bbcb17 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc.lua @@ -17,16 +17,17 @@ -- when the documentation is kept in a separate file. -- -- Using the doc facility is easy: --- +-- % -- \begin{enumerate} --- \item In the |declare| statement of the key, you do not provide --- fields like |documentation| or |summary|. Rather, you provide the --- field |documentation_in|, which gets the name of a Lua file the --- will be read whenever one of the fields |documentation|, |summary|, --- or |examples| is requested for the key. --- \item When the key is requested, |require| will be applied to the --- filename given in the |documentation_in| field. --- \item In this file, you start with the following code: +-- \item In the |declare| statement of the key, you do not provide +-- fields like |documentation| or |summary|. Rather, you provide the +-- field |documentation_in|, which gets the name of a Lua file the +-- will be read whenever one of the fields |documentation|, |summary|, +-- or |examples| is requested for the key. +-- \item When the key is requested, |require| will be applied to the +-- filename given in the |documentation_in| field. +-- \item In this file, you start with the following code: +-- % --\begin{codeexample}[code only] --local doc = require 'pgf.gd.doc' --local key = doc.key @@ -34,10 +35,12 @@ --local summary = doc.summary --local example = doc.example --\end{codeexample} --- This will setup nice shortcuts for the commands you are going to --- use in your file. --- \item Next, for each to-be-lazily-documented key, add a block to --- the file like the following: +-- % +-- This will setup nice shortcuts for the commands you are going to +-- use in your file. +-- \item Next, for each to-be-lazily-documented key, add a block to +-- the file like the following: +-- % --\begin{codeexample}[code only] -- --- -- key "my radius" @@ -50,19 +53,18 @@ -- example "\tikz \graph [foo layout, my radius=3] { c--d };" --\end{codeexample} -- --- Note that |[[| and |]]| are used in Lua for raw multi-line --- strings. +-- Note that |[[| and |]]| are used in Lua for raw multi-line strings. -- --- The effect of the above code will be that for the key |my radius| --- the different field like |summary| or |documentation| get --- updated. The |key| function simple ``selects'' a key and subsequent --- commands like |summary| will update this key until a different key --- is selected through another use of |key|. +-- The effect of the above code will be that for the key |my radius| +-- the different field like |summary| or |documentation| get +-- updated. The |key| function simple ``selects'' a key and subsequent +-- commands like |summary| will update this key until a different key +-- is selected through another use of |key|. -- \end{enumerate} local doc = {} -local current_key +local current_key -- Namespace @@ -107,7 +109,7 @@ end --- --- Adds an example to the |examples| field of the last key selected +-- Adds an example to the |examples| field of the last key selected -- through the |key| command. -- -- @param string An additional example string. diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua index 37878cd20f4..552dd00dc8b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased.lua @@ -14,6 +14,6 @@ --- -- @section subsection {Force-Based Algorithms} -- --- +-- local _
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua index 0d987f7c5b6..b7bab378191 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FMMMLayout.lua @@ -20,7 +20,7 @@ local example = require 'pgf.gd.doc'.example key "FMMMLayout" summary "The fast multipole multilevel layout algorithm." -documentation +documentation [[ |FMMMLayout| implements a force-directed graph drawing method suited also for very large graphs. It is based on a @@ -29,12 +29,12 @@ approximating the repulsive forces in the system by rapidly evaluating potential fields. The implementation is based on the following publication: - +% \begin{itemize} -\item Stefan Hachul, Michael J\"unger: Drawing Large Graphs with - a Potential-Field-Based Multilevel Algorithm. \emph{12th - International Symposium on Graph Drawing 1998 (GD '04)}, New York, LNCS 3383, - pp. 285--295, 2004. + \item Stefan Hachul, Michael J\"unger: Drawing Large Graphs with + a Potential-Field-Based Multilevel Algorithm. \emph{12th + International Symposium on Graph Drawing 1998 (GD '04)}, + New York, LNCS 3383, pp. 285--295, 2004. \end{itemize} ]] @@ -44,7 +44,7 @@ example ]] -example +example [[ \tikz [nodes={text height=.7em, text depth=.2em, draw=black!20, thick, fill=white, font=\footnotesize}, @@ -65,7 +65,7 @@ example { "USG 2.0" -> "USG 3.0", "PWB 2.0", "Unix/TS 1.0" } -> "Unix/TS 3.0"; { "Unix/TS++", "CB Unix 3", "Unix/TS 3.0" } -> "TS 4.0" -> "System V.0" -> "System V.2" -> "System V.3"; - }; + }; ]] -------------------------------------------------------------------------------- @@ -74,7 +74,7 @@ example -------------------------------------------------------------------------------- key "FMMMLayout.randSeed" summary "Sets the random seed for the |FMMMLayout|." -documentation +documentation [[ By changing this number, you can vary the appearance of the generated graph drawing. This key is an alias for |random seed|, which in turn @@ -117,7 +117,7 @@ example [[ \tikz { \graph [FMMMLayout, node sep=5mm] { subgraph C_n[n=6]; }; - + \draw [red, ultra thick, |-|] (1.south) -- ++(down:5mm); } ]] diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua index 4b676aff121..453078b1306 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/FastMultipoleEmbedder.lua @@ -18,27 +18,27 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "FastMultipoleEmbedder" -summary "Implementation of a fast multipole embedder by Martin Gronemann." +summary "Implementation of a fast multipole embedder by Martin Gronemann." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "FastMultipoleEmbedder.numIterations" summary "sets the maximum number of iterations" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "FastMultipoleEmbedder.multipolePrec" summary "sets the number of coefficients for the expansions. default = 4" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "FastMultipoleEmbedder.defaultEdgeLength" summary "" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "FastMultipoleEmbedder.defaultNodeSize" @@ -48,4 +48,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua index 674bc996f14..d0b94c2bb7a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/GEMLayout.lua @@ -18,79 +18,79 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "GEMLayout" -summary "The energy-based GEM layout algorithm." - +summary "The energy-based GEM layout algorithm." + documentation [[ -The implementation used in |GEMLayout| is based on the following publication: -\begin{itemize} -\item Arne Frick, Andreas Ludwig, Heiko Mehldau: \emph{A Fast Adaptive Layout - Algorithm for Undirected Graphs.} Proc. Graph Drawing 1994, - LNCS 894, pp. 388-403, 1995. -\end{itemize} - + The implementation used in |GEMLayout| is based on the following publication: + % + \begin{itemize} + \item Arne Frick, Andreas Ludwig, Heiko Mehldau: \emph{A Fast Adaptive Layout + Algorithm for Undirected Graphs.} Proc. Graph Drawing 1994, + LNCS 894, pp. 388-403, 1995. + \end{itemize} ]] -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.numberOfRounds" summary "Sets the maximal number of round per node." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.minimalTemperature" summary "Sets the minimal temperature." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.initialTemperature" summary "Sets the initial temperature; must be $\\ge$ |minimalTemperature|." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.gravitationalConstant" summary "Sets the gravitational constant; must be $\\ge 0$." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.desiredLength" summary "Sets the desired edge length; must be $\\ge 0$." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.maximalDisturbance" summary "Sets the maximal disturbance; must be $\\ge 0$." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.rotationAngle" summary "Sets the opening angle for rotations ($0 \\le x \\le \\pi / 2$)." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.oscillationAngle" summary "Sets the opening angle for oscillations ($0 \\le x \\le \\pi / 2$)." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.rotationSensitivity" summary "Sets the rotation sensitivity ($0 \\le x \\le 1$)." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.oscillationSensitivity" summary "Sets the oscillation sensitivity ($0 \\le x \\le 1$)." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "GEMLayout.attractionFormula" @@ -100,4 +100,4 @@ summary "sets the formula for attraction (1 = Fruchterman / Reingold, 2 = -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua index 4dc8d3b3fc7..6210c939412 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/MultilevelLayout.lua @@ -18,7 +18,7 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "MultilevelLayout" -summary "A wrapper for the multilevel layout computation using the modular multi-level mixer." +summary "A wrapper for the multilevel layout computation using the modular multi-level mixer." example [[ \tikz \graph [MultilevelLayout] { @@ -30,4 +30,4 @@ example [[ -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua index b71d6629c13..ae3cf9c8ef8 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFR.lua @@ -18,30 +18,29 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "SpringEmbedderFR" -summary "The spring-embedder layout algorithm by Fruchterman and Reingold." - -documentation [[ -The implementation used in SpringEmbedderFR is based on the following -publication: +summary "The spring-embedder layout algorithm by Fruchterman and Reingold." -Thomas M. J. Fruchterman, Edward M. Reingold: \emph{Graph Drawing by Force-directed -Placement}. Software - Practice and Experience 21(11), pp. 1129-1164, 1991. +documentation [[ + The implementation used in SpringEmbedderFR is based on the following + publication: + Thomas M. J. Fruchterman, Edward M. Reingold: \emph{Graph Drawing by Force-directed + Placement}. Software - Practice and Experience 21(11), pp. 1129--1164, 1991. ]] -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFR.iterations" summary "Sets the number of iterations." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFR.noise" summary "Sets the parameter noise." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFR.scaleFunctionFactor" @@ -51,4 +50,4 @@ summary "Sets the scale function factor." -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua index a79d94f7e2a..6286e9f3954 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderFRExact.lua @@ -18,33 +18,33 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "SpringEmbedderFRExact" -summary "Declaration of Spring-Embedder (Fruchterman,Reingold) algorithm with exact force computations." +summary "Declaration of Spring-Embedder (Fruchterman,Reingold) algorithm with exact force computations." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFRExact.iterations" summary "Sets the number of iterations." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFRExact.noise" summary "Sets the parameter noise." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFRExact.coolingFunction" summary "Sets the parameter coolingFunction to |factor| or to |logarithmic|." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFRExact.idealEdgeLength" summary "Sets the ideal edge length to a length." -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderFRExact.convTolerance" @@ -54,4 +54,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua index 0d130b19235..a4fd46aa775 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/SpringEmbedderKK.lua @@ -18,40 +18,38 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "SpringEmbedderKK" -summary "The spring embedder of Kamada and Kawai" - +summary "The spring embedder of Kamada and Kawai" + documentation [[ - The implementation used in |SpringEmbedderKK| is based on - the following publication: - - Tomihisa Kamada, Satoru Kawai: \emph{An Algorithm for Drawing - General Undirected Graphs.} Information Processing Letters 31, pp. 7--15, 1989. - - There are some parameters that can be tuned to optimize the - algorithm's behavior regarding runtime and layout quality. - First of all note that the algorithm uses all pairs shortest path - to compute the graph theoretic distance. This can be done either - with BFS (ignoring node sizes) in quadratic time or by using - e.g. Floyd's algorithm in cubic time with given edge lengths - that may reflect the node sizes. Also |m_computeMaxIt| decides - if the computation is stopped after a fixed maximum number of - iterations. The desirable edge length can either be set or computed - from the graph and the given layout. - + The implementation used in |SpringEmbedderKK| is based on + the following publication: + + Tomihisa Kamada, Satoru Kawai: \emph{An Algorithm for Drawing + General Undirected Graphs.} Information Processing Letters 31, pp. 7--15, 1989. + + There are some parameters that can be tuned to optimize the + algorithm's behavior regarding runtime and layout quality. + First of all note that the algorithm uses all pairs shortest path + to compute the graph theoretic distance. This can be done either + with BFS (ignoring node sizes) in quadratic time or by using + e.g. Floyd's algorithm in cubic time with given edge lengths + that may reflect the node sizes. Also |m_computeMaxIt| decides + if the computation is stopped after a fixed maximum number of + iterations. The desirable edge length can either be set or computed + from the graph and the given layout. ]] -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderKK.stopTolerance" summary "Sets the value for the stop tolerance." -documentation -[[ -Below this value, the system is regarded stable (balanced) and the -optimization stopped. +documentation [[ + Below this value, the system is regarded stable (balanced) and the + optimization stopped. ]] -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SpringEmbedderKK.desLength" @@ -61,4 +59,4 @@ summary "Sets desirable edge length directly" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua index 55ac157e302..e658a896bdc 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/BarycenterPlacer.lua @@ -18,9 +18,9 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "BarycenterPlacer" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "BarycenterPlacer.weightedPositionPriority" @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua index 1ef3e4914cb..e6f06add57d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/CirclePlacer.lua @@ -18,21 +18,21 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "CirclePlacer" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "CirclePlacer.circleSize" summary "" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "CirclePlacer.radiusFixed" summary "" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "CirclePlacer.nodeSelection" @@ -42,4 +42,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua index 82af7b56366..e8723272ee2 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/EdgeCoverMerger.lua @@ -18,9 +18,9 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "EdgeCoverMerger" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "EdgeCoverMerger.factor" @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua index e65a9f41fe6..81e2f37db0e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/IndependentSetMerger.lua @@ -18,9 +18,9 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "IndependentSetMerger" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "IndependentSetMerger.searchDepthBase" @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua index 7e5e261f55f..7fbca25e816 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/LocalBiconnectedMerger.lua @@ -18,9 +18,9 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "LocalBiconnectedMerger" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "LocalBiconnectedMerger.factor" @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua index e7f8144e3bb..e966b490563 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MatchingMerger.lua @@ -18,9 +18,9 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "MatchingMerger" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "MatchingMerger.selectByNodeMass" @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua index 10a8ba58994..0b9d967db9c 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/MedianPlacer.lua @@ -18,10 +18,10 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "MedianPlacer" -summary "?" +summary "?" -------------------------------------------------------------------------------- -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua index aafb8afd2ad..71bdbc7340d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomMerger.lua @@ -18,9 +18,9 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "RandomMerger" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "RandomMerger.factor" @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua index a0c9738fa17..c26946d4e11 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/RandomPlacer.lua @@ -18,9 +18,9 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "RandomPlacer" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "RandomPlacer.circleSize" @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua index 99ff4c621d3..76b084fa67e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarMerger.lua @@ -18,15 +18,15 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "SolarMerger" -summary "?" +summary "?" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SolarMerger.simple" summary "" -------------------------------------------------------------------------------- - + -------------------------------------------------------------------------------- key "SolarMerger.massAsNodeRadius" @@ -36,4 +36,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua index eb186a56157..530ddbc0d89 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/SolarPlacer.lua @@ -18,10 +18,10 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "SolarPlacer" -summary "?" +summary "?" -------------------------------------------------------------------------------- -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua index e7722fd669a..6f579d0a453 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/energybased/multilevelmixer/ZeroPlacer.lua @@ -18,7 +18,7 @@ local example = require 'pgf.gd.doc'.example -------------------------------------------------------------------------------- key "ZeroPlacer" -summary "?" +summary "?" -------------------------------------------------------------------------------- @@ -30,4 +30,4 @@ summary "" -- Local Variables: -- mode:latex --- End: +-- End: diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua index 77a679d2be2..ffd3ea844dd 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered.lua @@ -14,6 +14,6 @@ --- -- @section subsection {Algorithms for Drawing Layered Graphs} -- --- +-- local _
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua index e2c09f21242..fd13e9bd4b3 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/CoffmanGrahamRanking.lua @@ -21,10 +21,10 @@ key "CoffmanGrahamRanking" summary "The ranking algorithm due to Coffman and Graham." documentation [[ -|CoffmanGrahamRanking| implements a node ranking algorithmn based on +|CoffmanGrahamRanking| implements a node ranking algorithm based on the Coffman--Graham scheduling algorithm, which can be used as first phase in |SugiyamaLayout|. The aim of the algorithm is to ensure that -the height of the ranking (the number of layers) is kept small. +the height of the ranking (the number of layers) is kept small. ]] -------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua index 4d45270a01f..a7baad7e109 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastHierarchyLayout.lua @@ -23,21 +23,21 @@ documentation [[ This class implements a hierarchy layout algorithm, that is, it layouts hierarchies with a given order of nodes on each -layer. It is used as a third phase of the Sugiyama algorithm. +layer. It is used as a third phase of the Sugiyama algorithm. All edges of the layout will have at most two bends. Additionally, for each edge having exactly two bends, the segment between them is drawn vertically. This applies in particular to the long edges arising in the first phase of the -Sugiyama algorithm. +Sugiyama algorithm. The implementation is based on: - +% \begin{itemize} -\item - Christoph Buchheim, Michael Jünger, Sebastian Leipert: A Fast - Layout Algorithm for k-Level Graphs. \emph{Proc. Graph - Drawing 2000}, volumne 1984 of LNCS, pages 229--240, 2001. + \item + Christoph Buchheim, Michael Jünger, Sebastian Leipert: A Fast + Layout Algorithm for k-Level Graphs. \emph{Proc. Graph + Drawing 2000}, volume 1984 of LNCS, pages 229--240, 2001. \end{itemize} ]] diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua index 719e6035699..4af6daa6207 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/FastSimpleHierarchyLayout.lua @@ -24,29 +24,31 @@ documentation [[ This class implements a hierarchy layout algorithm, that is, it layouts hierarchies with a given order of nodes on each -layer. It is used as a third phase of the Sugiyama algorithm. +layer. It is used as a third phase of the Sugiyama algorithm. The algorithm runs in three phases: +% \begin{enumerate} -\item Alignment (4x) -\item Horizontal Compactation (4x) -\item Balancing + \item Alignment (4x) + \item Horizontal Compactation (4x) + \item Balancing \end{enumerate} +% The alignment and horizontal compactification phases are calculated downward, upward, left-to-right and right-to-left. The four -resulting layouts are combined in a balancing step. +resulting layouts are combined in a balancing step. Warning: The implementation is known to not always produce a correct layout. Therefore this Algorithm is for testing purpose -only. +only. The implementation is based on: - +% \begin{itemize} -\item - Ulrik Brandes, Boris Köpf: Fast and Simple Horizontal - Coordinate Assignment. \emph{LNCS} 2002, Volume 2265/2002, - pp. 33--36 + \item + Ulrik Brandes, Boris Köpf: Fast and Simple Horizontal + Coordinate Assignment. \emph{LNCS} 2002, Volume 2265/2002, + pp. 33--36 \end{itemize} ]] @@ -62,7 +64,7 @@ example -------------------------------------------------------------------- key "FastSimpleHierarchyLayout.layerDistance" -summary "Distance between the cetners of nodes of two consecutive layers." +summary "Distance between the centers of nodes of two consecutive layers." documentation [[ @@ -80,7 +82,7 @@ example -------------------------------------------------------------------- key "FastSimpleHierarchyLayout.siblingDistance" -summary "Distance between the cetners of nodes of sibling nodes." +summary "Distance between the centers of nodes of sibling nodes." documentation [[ diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua index 788baece4ff..d2f1d8eeeaf 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/GreedyCycleRemoval.lua @@ -21,7 +21,7 @@ key "GreedyCycleRemoval" summary "Greedy algorithm for computing a maximal acyclic subgraph." documentation [[ -The algorithm applies a greedy heuristic to compute a maximal -acyclic subgraph and works in linear-time. + The algorithm applies a greedy heuristic to compute a maximal + acyclic subgraph and works in linear-time. ]] -------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua index e81bb2e1c30..3d98fbe9c6a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/LongestPathRanking.lua @@ -21,11 +21,11 @@ key "LongestPathRanking" summary "The longest-path ranking algorithm." documentation [[ -|LongestPathRanking| implements the well-known longest-path ranking -algorithm, which can be used as first phase in |SugiyamaLayout|. The -implementation contains a special optimization for reducing edge -lengths, as well as special treatment of mixed-upward graphs (for -instance, \textsc{uml} class diagrams). + |LongestPathRanking| implements the well-known longest-path ranking + algorithm, which can be used as first phase in |SugiyamaLayout|. The + implementation contains a special optimization for reducing edge + lengths, as well as special treatment of mixed-upward graphs (for + instance, \textsc{uml} class diagrams). ]] -------------------------------------------------------------------- @@ -47,10 +47,10 @@ summary "If set to true, multi-edges will span at least two layers." key "LongestPathRanking.optimizeEdgeLength" summary [[ -If set to true the ranking algorithm tries to reduce edge -length even if this might increase the height of the layout. Choose -false, if the longest-path ranking known from the literature should be -used. + If set to true the ranking algorithm tries to reduce edge + length even if this might increase the height of the layout. Choose + false, if the longest-path ranking known from the literature should be + used. ]] -------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua index 64eb7eadd80..25a8dd5262b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/OptimalRanking.lua @@ -21,9 +21,9 @@ key "OptimalRanking" summary "The optimal ranking algorithm." documentation [[ -The |OptimalRanking| implements the LP-based algorithm for -computing a node ranking with minimal edge lengths, which can -be used as first phase in |SugiyamaLayout|. + The |OptimalRanking| implements the LP-based algorithm for + computing a node ranking with minimal edge lengths, which can + be used as first phase in |SugiyamaLayout|. ]] -------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua index f54f0c33462..d0815a5b761 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SiftingHeuristic.lua @@ -25,10 +25,10 @@ summary "The sifting heuristic for 2-layer crossing minimization." -------------------------------------------------------------------- key "SiftingHeuristic.strategy" -summary "Sets a so-called ``sifting strategy.''" +summary "Sets a so-called ``sifting strategy''." documentation [[ -The following values are permissible: |left_to_right|, |desc_degree|, -and |random|. + The following values are permissible: |left_to_right|, |desc_degree|, + and |random|. ]] -------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua index ef68a1db0db..ab9d9ee77f7 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/layered/SugiyamaLayout.lua @@ -20,19 +20,18 @@ local example = require 'pgf.gd.doc'.example key "SugiyamaLayout" summary "The OGDF implementation of the Sugiyama algorithm." -documentation -[[ -This layout represents a customizable implementation of Sugiyama's -layout algorithm. The implementation used in |SugiyamaLayout| is based -on the following publications: - -\begin{itemize} -\item Emden R. Gansner, Eleftherios Koutsofios, Stephen - C. North, Kiem-Phong Vo: A technique for drawing directed - graphs. \emph{IEEE Trans. Software Eng.} 19(3):214--230, 1993. -\item Georg Sander: \emph{Layout of compound directed graphs.} - Technical Report, Universität des Saarlandes, 1996. -\end{itemize} +documentation [[ + This layout represents a customizable implementation of Sugiyama's + layout algorithm. The implementation used in |SugiyamaLayout| is based + on the following publications: + + \begin{itemize} + \item Emden R. Gansner, Eleftherios Koutsofios, Stephen + C. North, Kiem-Phong Vo: A technique for drawing directed + graphs. \emph{IEEE Trans. Software Eng.} 19(3):214--230, 1993. + \item Georg Sander: \emph{Layout of compound directed graphs.} + Technical Report, Universität des Saarlandes, 1996. + \end{itemize} ]] example @@ -40,14 +39,14 @@ example \tikz \graph [SugiyamaLayout] { a -- {b,c,d} -- e -- a }; ]] -example +example [[ \tikz \graph [SugiyamaLayout, grow=right] { a -- {b,c,d} -- e -- a }; ]] -example +example [[ \tikz [nodes={text height=.7em, text depth=.2em, draw=black!20, thick, fill=white, font=\footnotesize}, @@ -68,7 +67,7 @@ example { "USG 2.0" -> "USG 3.0", "PWB 2.0", "Unix/TS 1.0" } -> "Unix/TS 3.0"; { "Unix/TS++", "CB Unix 3", "Unix/TS 3.0" } -> "TS 4.0" -> "System V.0" -> "System V.2" -> "System V.3"; - }; + }; ]] -------------------------------------------------------------------------------- @@ -77,10 +76,10 @@ example -------------------------------------------------------------------------------- key "SugiyamaLayout.runs" summary "Determines, how many times the crossing minimization is repeated." -documentation +documentation [[ Each repetition (except for the first) starts with -randomly permuted nodes on each layer. Deterministic behaviour can +randomly permuted nodes on each layer. Deterministic behavior can be achieved by setting |SugiyamaLayout.runs| to 1. ]] -------------------------------------------------------------------------------- @@ -89,12 +88,11 @@ be achieved by setting |SugiyamaLayout.runs| to 1. -------------------------------------------------------------------------------- key "SugiyamaLayout.transpose" -documentation -[[ -Determines whether the transpose step is performed -after each 2-layer crossing minimization; this step tries to -reduce the number of crossings by switching neighbored nodes on -a layer. +documentation [[ + Determines whether the transpose step is performed + after each 2-layer crossing minimization; this step tries to + reduce the number of crossings by switching neighbored nodes on + a layer. ]] -------------------------------------------------------------------------------- @@ -102,11 +100,10 @@ a layer. -------------------------------------------------------------------------------- key "SugiyamaLayout.fails" -documentation -[[ -The number of times that the number of crossings may -not decrease after a complete top-down bottom-up traversal, -before a run is terminated. +documentation [[ + The number of times that the number of crossings may + not decrease after a complete top-down bottom-up traversal, + before a run is terminated. ]] -------------------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua index bdf85e9905e..9f5f291461a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout.lua @@ -14,6 +14,6 @@ --- -- @section subsection {Miscellaneous Algorithms for Graph Drawing} -- --- +-- local _
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua index bca8edd9ebc..2a250ecece6 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/BalloonLayout.lua @@ -20,7 +20,7 @@ local example = require 'pgf.gd.doc'.example key "BalloonLayout" summary "A ``balloon layout''." -documentation +documentation [[ This algorithm computes a radial (balloon) layout based on a spanning tree. The algorithm is partially based on the paper diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua index 5c8a926384e..c5e2cf7a6c8 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/misclayout/CircularLayout.lua @@ -20,14 +20,14 @@ local example = require 'pgf.gd.doc'.example key "CircularLayout" summary "The circular layout algorithm." -documentation +documentation [[ -The implementation used in CircularLayout is based on the following publication: - +The implementation used in CircularLayout is based on the following publication: +% \begin{itemize} -\item Ugur Dogrus\"oz, Brendan Madden, Patrick Madden: Circular - Layout in the Graph Layout Toolkit. \emph{Proc. Graph Drawing 1996,} - LNCS 1190, pp. 92--100, 1997. + \item Ugur Dogrus\"oz, Brendan Madden, Patrick Madden: Circular + Layout in the Graph Layout Toolkit. \emph{Proc. Graph Drawing 1996,} + LNCS 1190, pp. 92--100, 1997. \end{itemize} ]] diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua index c653bdc6b60..fb1abb5ccd6 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity.lua @@ -14,6 +14,6 @@ --- -- @section subsection {Algorithms for Drawing Planar Graphs} -- --- +-- local _
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua index 516d119f553..e61f9281b97 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/doc/ogdf/planarity/PlanarizationLayout.lua @@ -20,17 +20,17 @@ local example = require 'pgf.gd.doc'.example key "PlanarizationLayout" summary "The planarization layout algorithm." -documentation +documentation [[ -A |PlanarizationLayout| represents a customizable implementation -of the planarization approach for drawing graphs. The implementation -used in PlanarizationLayout is based on the following publication: - -\begin{itemize} -\item C. Gutwenger, P. Mutzel: \emph{An Experimental Study of Crossing - Minimization Heuristics.} 11th International Symposium on Graph - Drawing 2003, Perugia (GD '03), LNCS 2912, pp. 13-24, 2004. -\end{itemize} + A |PlanarizationLayout| represents a customizable implementation + of the planarization approach for drawing graphs. The implementation + used in PlanarizationLayout is based on the following publication: + % + \begin{itemize} + \item C. Gutwenger, P. Mutzel: \emph{An Experimental Study of Crossing + Minimization Heuristics.} 11th International Symposium on Graph + Drawing 2003, Perugia (GD '03), LNCS 2912, pp. 13--24, 2004. + \end{itemize} ]] example @@ -44,12 +44,12 @@ example -------------------------------------------------------------------------------- key "PlanarizationLayout.preprocessCliques" summary "Configures, whether cliques are collapsed in a preprocessing step." -documentation +documentation [[ -If set to true, a preprocessing for cliques (complete subgraphs) -is performed and cliques will be laid out in a special form (straight-line, -not orthogonal). The preprocessing may reduce running time and improve -layout quality if the input graphs contains dense subgraphs. + If set to true, a preprocessing for cliques (complete subgraphs) + is performed and cliques will be laid out in a special form (straight-line, + not orthogonal). The preprocessing may reduce running time and improve + layout quality if the input graphs contains dense subgraphs. ]] -------------------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua index ccaa91f9992..5acc28396b2 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/ASCIIDisplayer.lua @@ -5,7 +5,7 @@ require "pgf.gd.layered.library" require "pgf.gd.force.library" local algorithm = io.read():match("%s*graph%s*%[(.-)%]") - + InterfaceToDisplay.pushPhase(algorithm, "main", 1) InterfaceToDisplay.pushOption("level distance", 6, 2) InterfaceToDisplay.pushOption("sibling distance", 8, 3) @@ -27,6 +27,6 @@ end InterfaceToDisplay.runGraphDrawingAlgorithm() InterfaceToDisplay.renderGraph() InterfaceToDisplay.endGraphDrawingScope() - + diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua index 9752254907a..2b5c9cc0b6a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/BindingToASCII.lua @@ -22,10 +22,10 @@ function BindingToASCII:renderStop() for x=-30,30 do local s = canvas[x][y] for i=1,#s do - pos = x+30+i-math.floor(#s/2) - if not t[pos] or t[pos] == " " or t[pos] == "." then - t[pos] = string.sub(s,i,i) - end + pos = x+30+i-math.floor(#s/2) + if not t[pos] or t[pos] == " " or t[pos] == "." then + t[pos] = string.sub(s,i,i) + end end end print(table.concat(t)) @@ -41,46 +41,46 @@ function BindingToASCII:renderEdge(e) local function connect (p,q) local x1, y1, x2, y2 = math.floor(p.x+0.5), math.floor(p.y+0.5), math.floor(q.x+0.5), math.floor(q.y+0.5) - + -- Go upward with respect to x if x2 < x1 then x1, y1, x2, y2 = x2, y2, x1, y1 end - + local delta_x = x2-x1 local delta_y = y2-y1 if math.abs(delta_x) > math.abs(delta_y) then local slope = delta_y/delta_x for i=x1,x2 do - local x,y = i, math.floor(y1 + (i-x1)*slope + 0.5) + local x,y = i, math.floor(y1 + (i-x1)*slope + 0.5) - if canvas[x][y] == " " then - canvas[x][y] = '.' - end + if canvas[x][y] == " " then + canvas[x][y] = '.' + end end elseif math.abs(delta_y) > 0 then local slope = delta_x/delta_y for i=y1,y2,(y1<y2 and 1) or -1 do - local x,y = math.floor(x1 + (i-y1)*slope + 0.5), i + local x,y = math.floor(x1 + (i-y1)*slope + 0.5), i - if canvas[x][y] == " " then - canvas[x][y] = '.' - end + if canvas[x][y] == " " then + canvas[x][y] = '.' + end end end end - - + + local p = e.tail.pos - + for i=1,#e.path do if type(e.path[i]) == "table" then connect(p, e.path[i]) p = e.path[i] end end - + connect(p, e.head.pos) end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleDemo.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleDemo.lua index da850ff0dea..46eb4eff385 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleDemo.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleDemo.lua @@ -29,7 +29,7 @@ declare { function (self) local g = self.digraph local alpha = (2 * math.pi) / #g.vertices - + for i,vertex in ipairs(g.vertices) do local radius = vertex.options['radius'] or g.options['radius'] vertex.pos.x = radius * math.cos(i * alpha) @@ -39,19 +39,19 @@ declare { }, summary = [[" - This algorithm is the ``Hello World'' of graph drawing. + This algorithm is the ``Hello World'' of graph drawing. "]], - documentation = [=[" - The algorithm - arranges nodes in a circle (without paying heed to the sizes of the - nodes or to the edges). In order to ``really'' layout nodes in a - circle, use |simple necklace layout|; the present layout is only intended - to demonstrate how much (or little) is needed to implement a graph - drawing algorithm. + documentation = [=[" + The algorithm arranges nodes in a circle (without paying heed to the + sizes of the nodes or to the edges). In order to ``really'' layout + nodes in a circle, use |simple necklace layout|; the present layout + is only intended to demonstrate how much (or little) is needed to + implement a graph drawing algorithm. + % \begin{codeexample}[code only, tikz syntax=false] -- File pgf.gd.examples.SimpleDemo local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare - + declare { key = "simple demo layout", algorithm = { @@ -59,7 +59,7 @@ declare { function (self) local g = self.digraph local alpha = (2 * math.pi) / #g.vertices - + for i,vertex in ipairs(g.vertices) do local radius = vertex.options['radius'] or g.options['radius'] vertex.pos.x = radius * math.cos(i * alpha) @@ -73,10 +73,10 @@ declare { "]] } \end{codeexample} - - On the display layer (\tikzname, that is) the algorithm can now - immediately be employed; you just need to say - |\usegdlibrary{examples.SimpleDemo}| at the beginning - somewhere. + + On the display layer (\tikzname, that is) the algorithm can now + immediately be employed; you just need to say + |\usegdlibrary{examples.SimpleDemo}| at the beginning + somewhere. "]=] }
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleEdgeDemo.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleEdgeDemo.lua index 8eb9d7d7019..c22c4decf22 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleEdgeDemo.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleEdgeDemo.lua @@ -31,33 +31,34 @@ declare { algorithm = SimpleEdgeDemo, summary = "This algorithm shows how edges can be created by an algorithm.", - documentation = [[" - For its job, the algorithm uses the function |createEdge|, which can be - called during the run of the algorithm to create edges in the - syntactic graph. The algorithm first does exactly the same as the - simple demo layout, then it creates an edge for every node where the - |new edge to| option is set. You will see in the code how this - option is declared and how we use it to look up a vertex in the - graph by its name. - + documentation = [[" + For its job, the algorithm uses the function |createEdge|, which can be + called during the run of the algorithm to create edges in the + syntactic graph. The algorithm first does exactly the same as the + simple demo layout, then it creates an edge for every node where the + |new edge to| option is set. You will see in the code how this + option is declared and how we use it to look up a vertex in the + graph by its name. + % \begin{codeexample}[] \tikz [simple edge demo layout] \graph [radius=2cm] { a, b, c, d, e, f; - + e -> [red] f; % normal edge - + % Edges generated by the algorithm: - a[new edge to=b]; + a[new edge to=b]; b[new edge to=d]; c[new edge to=f]; }; \end{codeexample} - - And the algorithm: + + And the algorithm: + % \begin{codeexample}[code only, tikz syntax=false] -- File pgf.gd.examples.SimpleEdgeDemo - + -- Imports local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" local declare = InterfaceToAlgorithms.declare @@ -71,9 +72,9 @@ declare { summary = "This algorithm shows...", } \end{codeexample} - - Next comes the declaration of the new option |new edge to|: - + + Next comes the declaration of the new option |new edge to|: + % \begin{codeexample}[code only, tikz syntax=false] declare { key = "new edge to", @@ -81,9 +82,9 @@ declare { summary = "This option takes the name of a vertex..." } \end{codeexample} - - Finally, the algorithm's code: - + + Finally, the algorithm's code: + % \begin{codeexample}[code only, tikz syntax=false] function SimpleEdgeDemo:run() -- As in a SimpleDemo: @@ -108,15 +109,15 @@ declare { key = "new edge to", type = "string", - summary = [[" - This option takes the name of a vertex. An edge leading to this - vertex is added to the syntactic digraph. - "]] + summary = [[" + This option takes the name of a vertex. An edge leading to this + vertex is added to the syntactic digraph. + "]] } function SimpleEdgeDemo:run() - + -- As in a SimpleDemo: local g = self.digraph local alpha = (2 * math.pi) / #g.vertices diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua index 270ecce2c90..f81abf11058 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/SimpleHuffman.lua @@ -31,27 +31,26 @@ local SimpleHuffman = {} declare { key = "simple Huffman layout", algorithm = SimpleHuffman, - + postconditions = { upward_oriented = true }, summary = [[" - This algorithm demonstrates how an algorithm can generate new - nodes. + This algorithm demonstrates how an algorithm can generate new nodes. "]], - documentation = [[" - The input graph should just consist of some nodes (without - edges) and each node should have a |probability| key set. The nodes - will then be arranged in a line (as siblings) and a Huffman tree - will be constructed ``above'' these nodes. For the construction of - the Huffman tree, new nodes are created and connected. - - \pgfgdset{ - HuffmanLabel/.style={/tikz/edge node={node[fill=white,font=\footnotesize,inner sep=1pt]{#1}}}, - HuffmanNode/.style={/tikz/.cd,circle,inner sep=0pt,outer sep=0pt,draw,minimum size=3pt} - } - + documentation = [[" + The input graph should just consist of some nodes (without + edges) and each node should have a |probability| key set. The nodes + will then be arranged in a line (as siblings) and a Huffman tree + will be constructed ``above'' these nodes. For the construction of + the Huffman tree, new nodes are created and connected. + + \pgfgdset{ + HuffmanLabel/.style={/tikz/edge node={node[fill=white,font=\footnotesize,inner sep=1pt]{#1}}}, + HuffmanNode/.style={/tikz/.cd,circle,inner sep=0pt,outer sep=0pt,draw,minimum size=3pt} + } + \begin{codeexample}[] \tikz \graph [simple Huffman layout, level distance=7mm, sibling distance=8mm, grow'=up] @@ -61,14 +60,16 @@ declare { c ["0.2", probability=0.2], d ["0.1", probability=0.1], e ["0.11", probability=0.11] -}; +}; \end{codeexample} - The file starts with some setups and declarations: + % + The file starts with some setups and declarations: + % \begin{codeexample}[code only, tikz syntax=false] -- File pgf.gd.examples.SimpleHuffman - + local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare - + -- The class local SimpleHuffman = {} @@ -85,7 +86,7 @@ declare { initial = "1", summary = "..." } - + -- Import local layered = require "pgf.gd.layered" local InterfaceToAlgorithms = require "pgf.gd.interface.InterfaceToAlgorithms" @@ -97,29 +98,31 @@ local layer = Storage.new() function SimpleHuffman:run() -- Construct a Huffman tree on top of the vertices... \end{codeexample} - - Next comes a setup, where we create the working list of vertices - that changes as the Huffman coding method proceeds: + + Next comes a setup, where we create the working list of vertices + that changes as the Huffman coding method proceeds: + % \begin{codeexample}[code only, tikz syntax=false] -- Shorthand local function prop (v) return probability[v] or v.options['probability'] end - + -- Copy the vertex table, since we are going to modify it: local vertices = {} for i,v in ipairs(self.ugraph.vertices) do vertices[i] = v end \end{codeexample} - - The initial vertices are arranged in a line on the last layer. The - function |ideal_sibling_distance| takes care of the rather - complicated handling of the (possibly rotated) bounding boxes and - separations. The |props| and |layer| are tables used by - algorithms to ``store stuff'' at a vertex or at an arc. The - table will be accessed by |arrange_layers_by_baselines| to - determine the ideal vertical placements. + + The initial vertices are arranged in a line on the last layer. The + function |ideal_sibling_distance| takes care of the rather + complicated handling of the (possibly rotated) bounding boxes and + separations. The |props| and |layer| are tables used by + algorithms to ``store stuff'' at a vertex or at an arc. The + table will be accessed by |arrange_layers_by_baselines| to + determine the ideal vertical placements. + % \begin{codeexample}[code only, tikz syntax=false] -- Now, arrange the nodes in a line: vertices [1].pos.x = 0 @@ -129,16 +132,17 @@ function SimpleHuffman:run() vertices [i].pos.x = vertices[i-1].pos.x + d layer[ vertices [i] ] = #vertices end -\end{codeexample} - - Now comes the actual Huffman algorithm: Always find the vertices - with a minimal probability\dots +\end{codeexample} + + Now comes the actual Huffman algorithm: Always find the vertices + with a minimal probability\dots + % \begin{codeexample}[code only, tikz syntax=false] -- Now, do the Huffman thing... while #vertices > 1 do -- Find two minimum probabilities local min1, min2 - + for i=1,#vertices do if not min1 or prop(vertices[i]) < prop(vertices[min1]) then min2 = min1 @@ -148,9 +152,11 @@ function SimpleHuffman:run() end end \end{codeexample} - \dots and connect them with a new node. This new node gets the - option |HuffmanNode|. It is now the job of the higher layers to map - this option to something ``nice''. + % + \dots and connect them with a new node. This new node gets the + option |HuffmanNode|. It is now the job of the higher layers to map + this option to something ``nice''. + % \begin{codeexample}[code only, tikz syntax=false] -- Create new node: local p = prop(vertices[min1]) + prop(vertices[min2]) @@ -159,27 +165,29 @@ function SimpleHuffman:run() layer[v] = #vertices-1 v.pos.x = (vertices[min1].pos.x + vertices[min2].pos.x)/2 vertices[#vertices + 1] = v - + InterfaceToAlgorithms.createEdge (self, v, vertices[min1], {generated_options = {{key="HuffmanLabel", value = "0"}}}) InterfaceToAlgorithms.createEdge (self, v, vertices[min2], {generated_options = {{key="HuffmanLabel", value = "1"}}}) - + table.remove(vertices, math.max(min1, min2)) table.remove(vertices, math.min(min1, min2)) end \end{codeexample} - Ok, we are mainly done now. Finish by computing vertical placements - and do formal cleanup. + % + Ok, we are mainly done now. Finish by computing vertical placements + and do formal cleanup. \begin{codeexample}[code only, tikz syntax=false] layered.arrange_layers_by_baselines(layers, self.adjusted_bb, self.ugraph) end \end{codeexample} - - In order to use the class, we have to make sure that, on the - display layer, the options |HuffmanLabel| and |HuffmanNode| are - defined. This is done by adding, for instance, the following to - \tikzname: + + In order to use the class, we have to make sure that, on the + display layer, the options |HuffmanLabel| and |HuffmanNode| are + defined. This is done by adding, for instance, the following to + \tikzname: + % \begin{codeexample}[code only] \pgfkeys{ /graph drawing/HuffmanLabel/.style={ @@ -191,8 +199,8 @@ end } \end{codeexample} "]] -} - +} + --- @@ -201,18 +209,18 @@ declare { type = "number", initial = "1", - summary = [[" - The probability parameter. It is used by the Huffman algorithm to - group nodes. - "]] + summary = [[" + The probability parameter. It is used by the Huffman algorithm to + group nodes. + "]] } - + -- Imports - + local Storage = require 'pgf.gd.lib.Storage' - + -- Storages - + local probability = Storage.new() local layer = Storage.new() @@ -224,13 +232,13 @@ function SimpleHuffman:run() local function prop (v) return probability[v] or v.options['probability'] end - + -- Copy the vertex table, since we are going to modify it: local vertices = {} for i,v in ipairs(self.ugraph.vertices) do vertices[i] = v end - + -- Now, arrange the nodes in a line: vertices [1].pos.x = 0 layer[vertices [1]] = #vertices @@ -239,7 +247,7 @@ function SimpleHuffman:run() vertices [i].pos.x = vertices[i-1].pos.x + d layer[vertices [i]] = #vertices end - + -- Now, do the Huffman thing... while #vertices > 1 do -- Find two minimum probabilities @@ -261,7 +269,7 @@ function SimpleHuffman:run() layer[v] = #vertices-1 v.pos.x = (vertices[min1].pos.x + vertices[min2].pos.x)/2 vertices[#vertices + 1] = v - + InterfaceToAlgorithms.createEdge (self, v, vertices[min1], {generated_options = {{key="HuffmanLabel", value = "0"}}}) InterfaceToAlgorithms.createEdge (self, v, vertices[min2], @@ -270,7 +278,7 @@ function SimpleHuffman:run() table.remove(vertices, math.max(min1, min2)) table.remove(vertices, math.min(min1, min2)) end - + layered.arrange_layers_by_baselines(layer, self.adjusted_bb, self.ugraph) end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/library.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/library.lua index 85e74970095..0c977600a7e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/library.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/examples/library.lua @@ -16,7 +16,7 @@ -- graph drawing engine can be used. In particular, the algorithms of -- this package are not really meant to be used to layout graphs -- (although they can be used, in principle); rather you are invited --- to have a look at their implementation and to adapt them to your needs. +-- to have a look at their implementation and to adapt them to your needs. -- -- @library diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua index 2dd23937fe1..31f8f27431b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GraphAnimationCoordination.lua @@ -49,11 +49,11 @@ declare { type = "boolean", Initial = false, documentation = [[" - This key specifies, if a supernode changed its - visual properties since the last snapshot. - The default value is |false| and prevent the algorithm - to produce a lot of unnecessary animations. - "]] + This key specifies, if a supernode changed its + visual properties since the last snapshot. + The default value is |false| and prevent the algorithm + to produce a lot of unnecessary animations. + "]] } declare { @@ -70,12 +70,12 @@ declare { type = "number", initial = 0.5, documentation = [[" - This key specifies a minimum time in which a single node - has to be prohibited to be animated. - For a node with minimum rest time of 1s that exists in a snapshot - at time $t$ this means that all animations including movements and fadings - are only allowed before $t$-0.5s and after $t$+0.5s. - "]], + This key specifies a minimum time in which a single node + has to be prohibited to be animated. + For a node with minimum rest time of 1s that exists in a snapshot + at time $t$ this means that all animations including movements and fadings + are only allowed before $t$-0.5s and after $t$+0.5s. + "]], } declare { @@ -83,9 +83,9 @@ declare { type = "number", initial = math.huge, documentation = [[" - Use this key if you want to limit the time during nodes are allowed to move - when they changing their positions. - "]], + Use this key if you want to limit the time during nodes are allowed to move + when they changing their positions. + "]], } declare { @@ -93,7 +93,10 @@ declare { type = "boolean", initial = true, documentation = [[" - Use this key if you want to allow that the fade animations for or dissappearing nodes may occurs while the mid time between two snapshots. If false then the appearing ends on the midtime and the disappering starts in this moment. + Use this key if you want to allow that the fade animations for or + disappearing nodes may occurs while the mid time between two snapshots. + If false then the appearing ends on the midtime and the disappearing + starts in this moment. "]] } @@ -103,40 +106,39 @@ declare { algorithm = GraphAnimationCoordination, phase = "evolving graph animation", phase_default = true, - summary = [[" - This phase animates all vertices including movements and - fade in or fade out animations given an evolving graph as sequence - of single snapshot graphs. + summary = [[" + This phase animates all vertices including movements and + fade in or fade out animations given an evolving graph as sequence + of single snapshot graphs. "]], - documentation = [[" - This phase animates all vertices including movements and - fade in or fade out animations given an evolving graph as sequence - of single snapshot graphs. - - Your algorithm needs to work on evolving graphs and has to use - the |evolving graph animation| phase. You do not need to use - this key by yourself then because this key starts the default - algorithm algorithm of the phase. - - \begin{codeexample}[] - local ga_class = self.digraph.options.algorithm_phases['evolving graph animation'] - -- animate graph - ga_class.new { - main_algorithm = self, - supergraph = supergraph, - digraph = self.digraph, - ugraph = self.ugraph - }:run() - \end{codeexample} - - This algorithm and phase require a supergraph instance and the original digraph and ugraph. - Note that you have to set the layout of the snapshot nodes before running algorithms of this - is useful. - + documentation = [[" + This phase animates all vertices including movements and + fade in or fade out animations given an evolving graph as sequence + of single snapshot graphs. + + Your algorithm needs to work on evolving graphs and has to use + the |evolving graph animation| phase. You do not need to use + this key by yourself then because this key starts the default + algorithm algorithm of the phase. + % + \begin{codeexample}[] + local ga_class = self.digraph.options.algorithm_phases['evolving graph animation'] + -- animate graph + ga_class.new { + main_algorithm = self, + supergraph = supergraph, + digraph = self.digraph, + ugraph = self.ugraph + }:run() + \end{codeexample} + + This algorithm and phase require a supergraph instance and the original + digraph and ugraph. Note that you have to set the layout of the snapshot + nodes before running algorithms of this is useful. "]], } --- Helpfunctions +-- Help functions -- -- Appends a move animation to a given snapshot object such that the @@ -146,7 +148,7 @@ declare { -- -- This means if we want to move a node 1cm to the right the value of -- |c_from| has to be (0,0) while |c_to| must be (1,0). The argument --- |c_from| is usefull for a node which has a position but its +-- |c_from| is useful for a node which has a position but its -- previous node related to the same supervertex is at a different -- position. Then we can use this argument to move the new node to -- its origin position for smooth transitions. @@ -170,16 +172,16 @@ local function append_move_animation(object, c_from, c_to, t_start, t_end) local t1 = (7*t_start + 5*t_end)/12 local t2 = (5*t_start + 7*t_end)/12 table.insert(animations, { - attribute = "translate", - entries = { - { t = t_start, value = c_from}, --- { t = t1, value = c1 }, --- { t = t2, value = c2 }, - { t = t_end, value = c_to } - }, - options = { { key = "freeze at end", }, --- {key = "entry control", value="0}{1",} - } + attribute = "translate", + entries = { + { t = t_start, value = c_from}, +-- { t = t1, value = c1 }, +-- { t = t2, value = c2 }, + { t = t_end, value = c_to } + }, + options = { { key = "freeze at end", }, +-- {key = "entry control", value="0}{1",} + } }) object.animations = animations end @@ -187,26 +189,26 @@ end local function append_fade_animation(object, v_start, v_end, t_start, t_end) local animations = object.animations or {} - + if v_start == 0 then table.insert(animations, { - attribute = "stage", - entries = { { t = t_start, value = "true"}, }, - options = { { key = "freeze at end" } } + attribute = "stage", + entries = { { t = t_start, value = "true"}, }, + options = { { key = "freeze at end" } } }) elseif v_end == 0 and nil then table.insert(animations, { - attribute = "stage", - entries = { { t = t_end, value = "false"}, }, - options = { --{ key = "freeze at end" } - } - }) + attribute = "stage", + entries = { { t = t_end, value = "false"}, }, + options = { --{ key = "freeze at end" } + } + }) end table.insert(animations, { attribute = "opacity", entries = { - { t = t_start, value = v_start }, + { t = t_start, value = v_start }, { t = t_end, value = v_end } }, options = { { key = "freeze at end" } } }) @@ -221,13 +223,13 @@ local function eq_offset(a1, a2, b1, b2) local dy = ((a1.y-a2.y) - (b1.y-b2.y)) if dx<0 then dx = -dx end if dy<0 then dy = -dy end - return dx<0.001 and dy<0.001 + return dx<0.001 and dy<0.001 end -- -- Check if two arcs connect a pair of nodes at the same position. -- This can be used as an indicator that two consecutive arcs --- can be representet by the same arc object. +-- can be represented by the same arc object. -- local function eq_arc(arc1, arc2) if not arc1 or not arc2 then @@ -251,7 +253,7 @@ function GraphAnimationCoordination:run() self.next_node = Storage.new() self.visible_objects = Storage.new() - + self:precomputeNodes() self:precomputeEdges() self:animateNodeAppearing() @@ -263,7 +265,7 @@ end function GraphAnimationCoordination:generateNodeMotions(node_types) local supergraph = self.supergraph local graph = self.digraph - + for _, supervertex in ipairs(self.supergraph.vertices) do local lj = -1 local last_v = nil @@ -272,25 +274,25 @@ function GraphAnimationCoordination:generateNodeMotions(node_types) local vertex = supergraph:getSnapshotVertex(supervertex, s) if lj == j-1 and vertex and last_v then - local mrt1 = last_v.options["minimum rest time"]/2 - local mrt2 = vertex.options["minimum rest time"]/2 - + local mrt1 = last_v.options["minimum rest time"]/2 + local mrt2 = vertex.options["minimum rest time"]/2 + local s1 = Coordinate.new(0,0) - local e1 = Coordinate.new(vertex.pos.x-last_v.pos.x,-vertex.pos.y+last_v.pos.y) - - local s2 = Coordinate.new(-vertex.pos.x+last_v.pos.x,vertex.pos.y-last_v.pos.y) - local e2 = Coordinate.new(0,0) - - local t_end = s.timestamp - math.max(0, mrt2) - local t_start = last_time + math.max(0,mrt1) - - local representative = self.visible_objects[supervertex][s] - if representative == vertex then - append_move_animation(vertex, s2, e2, t_start, t_end) - append_move_animation(last_v, s1, e1, t_start, t_end) - else - append_move_animation(representative,s1,e1,t_start,t_end) - end + local e1 = Coordinate.new(vertex.pos.x-last_v.pos.x,-vertex.pos.y+last_v.pos.y) + + local s2 = Coordinate.new(-vertex.pos.x+last_v.pos.x,vertex.pos.y-last_v.pos.y) + local e2 = Coordinate.new(0,0) + + local t_end = s.timestamp - math.max(0, mrt2) + local t_start = last_time + math.max(0,mrt1) + + local representative = self.visible_objects[supervertex][s] + if representative == vertex then + append_move_animation(vertex, s2, e2, t_start, t_end) + append_move_animation(last_v, s1, e1, t_start, t_end) + else + append_move_animation(representative,s1,e1,t_start,t_end) + end end last_time = s.timestamp lj = j @@ -300,59 +302,59 @@ function GraphAnimationCoordination:generateNodeMotions(node_types) end - + function GraphAnimationCoordination:generateEdgeMotions() local supergraph = self.supergraph local graph = self.digraph - + for i, arc in ipairs(supergraph.arcs) do local head = arc.head local tail = arc.tail - + local last_arc = nil local last_time = nil local last_v = nil local last_w = nil - + for j, s in ipairs(supergraph.snapshots) do local v = supergraph:getSnapshotVertex(tail,s) local w = supergraph:getSnapshotVertex(head,s) if v and w then - local this_arc = graph:arc(v,w) --or graph:arc(w,v) + local this_arc = graph:arc(v,w) --or graph:arc(w,v) if this_arc then - if this_arc and last_arc then - local mrt1 = last_v.options["minimum rest time"]/2 - local mrt2 = v.options["minimum rest time"]/2 - - local s1 = Coordinate.new(0,0)--lv.pos - local e1 = Coordinate.new(v.pos.x-last_v.pos.x,-v.pos.y+last_v.pos.y) - - local s2 = Coordinate.new(-v.pos.x+last_v.pos.x,v.pos.y-last_v.pos.y) - local e2 = Coordinate.new(0,0) - - local t_end = s.timestamp - math.max(0,mrt2) - local t_start = last_time + math.max(0,mrt1) - - local representative = self.visible_objects[arc][s] - if representative == this_arc then - append_move_animation(last_arc, s1, e1, t_start,t_end) - append_move_animation(this_arc, s2, e2, t_start,t_end) - else - append_move_animation(representative,s1,e1,t_start,t_end) - end - this_arc = representative - end - last_arc = this_arc - last_v = v - last_time = s.timestamp - else - last_arc = nil - end + if this_arc and last_arc then + local mrt1 = last_v.options["minimum rest time"]/2 + local mrt2 = v.options["minimum rest time"]/2 + + local s1 = Coordinate.new(0,0)--lv.pos + local e1 = Coordinate.new(v.pos.x-last_v.pos.x,-v.pos.y+last_v.pos.y) + + local s2 = Coordinate.new(-v.pos.x+last_v.pos.x,v.pos.y-last_v.pos.y) + local e2 = Coordinate.new(0,0) + + local t_end = s.timestamp - math.max(0,mrt2) + local t_start = last_time + math.max(0,mrt1) + + local representative = self.visible_objects[arc][s] + if representative == this_arc then + append_move_animation(last_arc, s1, e1, t_start,t_end) + append_move_animation(this_arc, s2, e2, t_start,t_end) + else + append_move_animation(representative,s1,e1,t_start,t_end) + end + this_arc = representative + end + last_arc = this_arc + last_v = v + last_time = s.timestamp + else + last_arc = nil + end else - last_arc = nil + last_arc = nil end end end @@ -363,9 +365,9 @@ end -- @field t_transition The mid time between two snapshot times. -- @field fade_duration The duration of the fade animation -- @field overlapping A boolean defining if the animation occurs --- beofre and after the mid time (true) or if it +-- before and after the mid time (true) or if it -- starts/end only in one interval (false) --- @field closing A boolean specifieng if this is a outfading time +-- @field closing A boolean specifying if this is an outfading time local function compute_fade_times(t_transition, fade_duration, overlapping, closing) if overlapping then @@ -394,9 +396,9 @@ function GraphAnimationCoordination:animateNodeAppearing() local overlapping_out= true local minimum_rest_time = math.max(0,vertex.options["minimum rest time"]) local allow_overlapping = vertex.options["overlapping transition"] - local fadein_duration = 0.01 - local fadeout_duration = 0.01 - + local fadein_duration = 0.01 + local fadeout_duration = 0.01 + if self.is_first[vertex] then fadein_duration = self.ugraph.options["fadein time"] overlapping_in = false or allow_overlapping @@ -414,7 +416,7 @@ function GraphAnimationCoordination:animateNodeAppearing() fadeout_duration = (interval.to-interval.from-minimum_rest_time)/2 if overlapping then fadeout_duration = fadeout_duration*2 end end - + local fin = compute_fade_times(interval.from, fadein_duration, overlapping_in, false) local fout = compute_fade_times(interval.to, fadeout_duration, overlapping_out, true) @@ -422,23 +424,23 @@ function GraphAnimationCoordination:animateNodeAppearing() if representative~= vertex then table.insert(vertex.animations,{ - attribute = "stage", - entries = { { t = 0, value = "false"}, }, - options = {} + attribute = "stage", + entries = { { t = 0, value = "false"}, }, + options = {} }) end - + if interval.from > -math.huge and (vertex == representative or self.is_first[vertex]) then -- only appears if the snapshot node is its own repr. or if in the prev snapshot is -- no representative. - append_fade_animation(representative, 0, 1, fin.t_start, fin.t_end) + append_fade_animation(representative, 0, 1, fin.t_start, fin.t_end) end if interval.to < math.huge and (self.is_last[vertex] or self.last_rep[vertex]) then -- The snapshot node only disappears when the node is not visible - -- in the next or (this=)last snapshot: + -- in the next or (this=)last snapshot: append_fade_animation(representative, 1, 0, fout.t_start, fout.t_end) end - end + end end @@ -447,121 +449,119 @@ function GraphAnimationCoordination:animateEdgeAppearing() local supergraph = self.supergraph local graph = self.digraph for _,edge in ipairs(graph.arcs) do - local snapshot = supergraph:getSnapshot(edge.head) - local int = snapshot.interval - local superarc = supergraph:getSuperarc(edge) - local representative = self.visible_objects[superarc][snapshot] or edge - - local minimum_rest_time = math.max(0,edge.head.options["minimum rest time"]/2, - edge.tail.options["minimum rest time"]/2) - - local appears = math.max(int.from, int.from) - local disappears = math.min(int.to, int.to) - - local overlapping_in = true -- init true for crossfading - local overlapping_out= true - local fadein_duration = 0.01 - local fadeout_duration = 0.01 - local allow_overlapping = (edge.tail.options["overlapping transition"] and edge.head.options["overlapping transition"]) - - if self.is_first[edge] and not self.move_on_enter[edge] and not self.move_on_enter[edge.head] then - fadein_duration = self.ugraph.options["fadein time"] - overlapping_in = false or allow_overlapping - end - - if self.is_last[edge] and not self.move_on_leave[edge] then - fadeout_duration = self.ugraph.options["fadeout time"] - overlapping_out = false or allow_overlapping - end - + local snapshot = supergraph:getSnapshot(edge.head) + local int = snapshot.interval + local superarc = supergraph:getSuperarc(edge) + local representative = self.visible_objects[superarc][snapshot] or edge - if self.is_first[edge] - and (self.move_on_enter[edge.head] - or self.move_on_enter[edge.tail] ) - then - appears = snapshot.timestamp - minimum_rest_time - end - if self.is_last[edge] and - (self.move_on_leave[edge.head] - or self.move_on_leave[edge.tail] - ) then - disappears = snapshot.timestamp + minimum_rest_time - end - - local fin = compute_fade_times(appears, fadein_duration, overlapping_in,false) - local fout = compute_fade_times(disappears,fadeout_duration,overlapping_out,true) - - edge.animations = edge.animations or {} - - if representative~=edge then - table.insert(edge.animations,{ - attribute = "stage", - entries = { { t = 0, value = "false"}, }, - options = {}}) - end - - -- Fade in: - if appears > -math.huge and (edge == representative or self.is_first[edge]) then - append_fade_animation(representative, 0, 1, fin.t_start, fin.t_end ) - end - - -- Fade out: - if disappears < math.huge and (self.is_last[edge] or self.last_rep[edge])then - append_fade_animation(representative, 1, 0, fout.t_start,fout.t_end ) - end - + local minimum_rest_time = math.max(0,edge.head.options["minimum rest time"]/2, + edge.tail.options["minimum rest time"]/2) + + local appears = math.max(int.from, int.from) + local disappears = math.min(int.to, int.to) + + local overlapping_in = true -- init true for crossfading + local overlapping_out= true + local fadein_duration = 0.01 + local fadeout_duration = 0.01 + local allow_overlapping = (edge.tail.options["overlapping transition"] and edge.head.options["overlapping transition"]) + + if self.is_first[edge] and not self.move_on_enter[edge] and not self.move_on_enter[edge.head] then + fadein_duration = self.ugraph.options["fadein time"] + overlapping_in = false or allow_overlapping + end + + if self.is_last[edge] and not self.move_on_leave[edge] then + fadeout_duration = self.ugraph.options["fadeout time"] + overlapping_out = false or allow_overlapping + end + + + if self.is_first[edge] + and (self.move_on_enter[edge.head] + or self.move_on_enter[edge.tail] ) + then + appears = snapshot.timestamp - minimum_rest_time + end + if self.is_last[edge] and + (self.move_on_leave[edge.head] + or self.move_on_leave[edge.tail] + ) then + disappears = snapshot.timestamp + minimum_rest_time + end + + local fin = compute_fade_times(appears, fadein_duration, overlapping_in,false) + local fout = compute_fade_times(disappears,fadeout_duration,overlapping_out,true) + + edge.animations = edge.animations or {} + + if representative~=edge then + table.insert(edge.animations,{ + attribute = "stage", + entries = { { t = 0, value = "false"}, }, + options = {}}) + end + + -- Fade in: + if appears > -math.huge and (edge == representative or self.is_first[edge]) then + append_fade_animation(representative, 0, 1, fin.t_start, fin.t_end ) + end + + -- Fade out: + if disappears < math.huge and (self.is_last[edge] or self.last_rep[edge])then + append_fade_animation(representative, 1, 0, fout.t_start,fout.t_end ) end - + end end function GraphAnimationCoordination:precomputeNodes() local supergraph = self.supergraph - + for _, supernode in ipairs(supergraph.vertices) do - + local vis_nodes = {} self.visible_objects[supernode] = vis_nodes - + local any_previous_node = nil local previous_representant = nil local node_before = nil for i, s in ipairs(supergraph.snapshots) do - local node = supergraph:getSnapshotVertex(supernode, s) + local node = supergraph:getSnapshotVertex(supernode, s) if node then - -- assume the node is the last node - self.is_last[node] = true - - if node.options["modified"] then - -- modified - vis_nodes[s] = node - previous_representant = node - if any_previous_node then - self.last_rep[any_previous_node] = true - end - else - -- unmodified - previous_representant = previous_representant or node - vis_nodes[s] = previous_representant - end - any_previous_node = node - - if node_before then - self.is_last[node_before] = false - self.previous_node[node] = node_before - self.next_node[node_before] = node - - local do_move = (( node.pos.x ~= node_before.pos.x ) - or (node.pos.y ~= node_before.pos.y)) - self.move_on_enter[node] = do_move - self.move_on_leave[node_before] = do_move - else - self.is_first[node] = true - end - node_before = node + -- assume the node is the last node + self.is_last[node] = true + + if node.options["modified"] then + -- modified + vis_nodes[s] = node + previous_representant = node + if any_previous_node then + self.last_rep[any_previous_node] = true + end + else + -- unmodified + previous_representant = previous_representant or node + vis_nodes[s] = previous_representant + end + any_previous_node = node + + if node_before then + self.is_last[node_before] = false + self.previous_node[node] = node_before + self.next_node[node_before] = node + + local do_move = (( node.pos.x ~= node_before.pos.x ) + or (node.pos.y ~= node_before.pos.y)) + self.move_on_enter[node] = do_move + self.move_on_leave[node_before] = do_move + else + self.is_first[node] = true + end + node_before = node else - node_before = nil + node_before = nil end end end @@ -574,8 +574,8 @@ function GraphAnimationCoordination:precomputeEdges() local tail = arc.tail if not ( self.is_first[head] or self.is_first[tail]) then if not self.digraph:arc(self.previous_node[tail], self.previous_node[head]) then - -- new arc connects existing nodes - self.is_first[arc] = true + -- new arc connects existing nodes + self.is_first[arc] = true end else -- arc and at least one node is new. @@ -583,8 +583,8 @@ function GraphAnimationCoordination:precomputeEdges() end if not ( self.is_last[head] or self.is_last[tail]) then if not self.digraph:arc(self.next_node[tail],self.next_node[head]) then - -- arc disappears while nodes are still in the next snapshot - self.is_last[arc] = true + -- arc disappears while nodes are still in the next snapshot + self.is_last[arc] = true end else -- arc and at least one node disappears in the next snapshot @@ -603,34 +603,34 @@ function GraphAnimationCoordination:precomputeEdges() local previous_arc local previous_representant - + for _, s in ipairs(supergraph.arc_snapshots[superarc]) do - local head = supergraph:getSnapshotVertex(superarc.head, s) - local tail = supergraph:getSnapshotVertex(superarc.tail, s) - -- use the digraph because the snapshot arc is not syncted - local arc = self.digraph:arc(tail, head) - - local modified = false - local opt_array = arc:optionsArray('modified') - for i = 1,#opt_array.aligned do - modified = modified or opt_array[i] - end - - if modified or - not eq_arc(arc, previous_arc) or self.is_first[arc] then - --modified - previous_representant = arc - vis_objects[s] = arc - if previous_arc then - self.last_rep[previous_arc] = true - end + local head = supergraph:getSnapshotVertex(superarc.head, s) + local tail = supergraph:getSnapshotVertex(superarc.tail, s) + -- use the digraph because the snapshot arc is not synced + local arc = self.digraph:arc(tail, head) + + local modified = false + local opt_array = arc:optionsArray('modified') + for i = 1,#opt_array.aligned do + modified = modified or opt_array[i] + end + + if modified or + not eq_arc(arc, previous_arc) or self.is_first[arc] then + --modified + previous_representant = arc + vis_objects[s] = arc + if previous_arc then + self.last_rep[previous_arc] = true + end else - -- unmodified - previous_representant = previous_representant or arc - vis_objects[s] = previous_representant - end - previous_arc = arc - end + -- unmodified + previous_representant = previous_representant or arc + vis_objects[s] = previous_representant + end + previous_arc = arc + end end end -- Done diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua index 17c46aa352c..0c348bcc8fd 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/GreedyTemporalCycleRemoval.lua @@ -47,19 +47,19 @@ declare { algorithm = GreedyTemporalCycleRemoval, phase = "temporal cycle removal", phase_default = true, - summary = [[" - A temporal dependency cycle is a cyclic path in the supergraph of - an evolving graph. Use this key if you want remove all temporal - dependency cycles by a greedy strategy which incrementally inserts - edge checks if this edge creates a cycle and splits at least one node - into two supernode at a given time. + summary = [[" + A temporal dependency cycle is a cyclic path in the supergraph of + an evolving graph. Use this key if you want remove all temporal + dependency cycles by a greedy strategy which incrementally inserts + edge checks if this edge creates a cycle and splits at least one node + into two supernode at a given time. "]], - documentation = [[" - See ToDo + documentation = [[" + See ToDo "]] } --- Helpfunctions +-- Help functions local function reachable(graph, v, w) local visited = {} local queue = PriorityQueue.new() @@ -73,12 +73,12 @@ local function reachable(graph, v, w) for _, e in ipairs(outgoings) do local head = e.head if not visited[head] then - visited[head] = true - if head == w then - return true - else - queue:enqueue(head,1) - end + visited[head] = true + if head == w then + return true + else + queue:enqueue(head,1) + end end end end @@ -101,13 +101,13 @@ end -- Resolves all dependencies by splitting supernodes into multiple supernodes. -- To resolve a cycle each edge will be inserted into a dependency graph -- successively. Each time such edge closes a cycle the head and tail will --- be splitet at the related snapshot. +-- be split at the related snapshot. -- -- @param supergraph -- function GreedyTemporalCycleRemoval:iterativeCycleRemoval(supergraph, split_tail, split_head) -- Build up the global dependency graph - -- A supernode v directly depends on another supernode w iff + -- A supernode v directly depends on another supernode w if -- there is a snapshot in which w is a child of w local dependency_graph = Digraph.new(supergraph) local stable_arcs = {} @@ -115,57 +115,57 @@ function GreedyTemporalCycleRemoval:iterativeCycleRemoval(supergraph, split_tail --local tree = snapshot.spanning_tree for _,tree in ipairs(snapshot.spanning_trees) do local new_arcs = {} - + for _, e in ipairs(tree.arcs) do if e.head.kind ~= "dummy" and e.tail.kind~="dummy" then - table.insert(new_arcs, e) - - local sv = supergraph:getSupervertex(e.tail) - local sw = supergraph:getSupervertex(e.head) - local dep_arc = dependency_graph:arc(sv, sw) - - - if (not dep_arc) then - -- check if the edge v->w closes a cycle in the dependencygraph - --pgf.debug{dependency_graph} - local cycle_arc = reachable(dependency_graph, sw, sv) - dep_arc = dependency_graph:connect(sv,sw) --- texio.write("\ncheck ".. sv.name.."->" .. sw.name) - if cycle_arc then - if split_tail then - supergraph:splitSupervertex(sv, { [1]=snapshot }) - end - if split_head then - supergraph:splitSupervertex(sw, { [1]=snapshot }) - end - - -- rebuild dependency graph - dependency_graph = Digraph.new(supergraph) - - for _, arc in ipairs(stable_arcs) do - dependency_graph:connect(arc.tail, arc.head) - end - - for _, arc in ipairs(new_arcs) do - local sv = supergraph:getSupervertex(arc.tail) - local sw = supergraph:getSupervertex(arc.head) - dependency_graph:connect(sv, sw) - end - end -- end of resovle cycle_arc - end + table.insert(new_arcs, e) + + local sv = supergraph:getSupervertex(e.tail) + local sw = supergraph:getSupervertex(e.head) + local dep_arc = dependency_graph:arc(sv, sw) + + + if (not dep_arc) then + -- check if the edge v->w closes a cycle in the dependency graph + --pgf.debug{dependency_graph} + local cycle_arc = reachable(dependency_graph, sw, sv) + dep_arc = dependency_graph:connect(sv,sw) +-- texio.write("\ncheck ".. sv.name.."->" .. sw.name) + if cycle_arc then + if split_tail then + supergraph:splitSupervertex(sv, { [1]=snapshot }) + end + if split_head then + supergraph:splitSupervertex(sw, { [1]=snapshot }) + end + + -- rebuild dependency graph + dependency_graph = Digraph.new(supergraph) + + for _, arc in ipairs(stable_arcs) do + dependency_graph:connect(arc.tail, arc.head) + end + + for _, arc in ipairs(new_arcs) do + local sv = supergraph:getSupervertex(arc.tail) + local sw = supergraph:getSupervertex(arc.head) + dependency_graph:connect(sv, sw) + end + end -- end of resolve cycle_arc + end end end -- Stable Arcs: for _, arc in ipairs(new_arcs) do - + local sv = supergraph:getSupervertex(arc.tail) local sw = supergraph:getSupervertex(arc.head) local deparc = dependency_graph:arc(sv, sw) -- if not deparc or not stable_arcs[deparc] then --- stable_arcs[deparc] = true - table.insert(stable_arcs, deparc) +-- stable_arcs[deparc] = true + table.insert(stable_arcs, deparc) -- end - + end end -- end for spanning_tree end -- end for snapshot diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua index 23bbdf36a8c..2beec1e216e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Skambath2016.lua @@ -6,7 +6,7 @@ -- 2. under the GNU Public License -- -- See the file doc/generic/pgf/licenses/LICENSE for more information --- +-- -- Imports require "pgf.gd.trees.ChildSpec" @@ -17,7 +17,7 @@ local Vertex = require "pgf.gd.model.Vertex" local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare local layered = require "pgf.gd.layered" local tlayered = require "pgf.gd.experimental.evolving.layered" -local SpanningTreeComputation = require "pgf.gd.trees.SpanningTreeComputation" +local SpanningTreeComputation = require "pgf.gd.trees.SpanningTreeComputation" local lib = require "pgf.gd.lib" local Storage = require "pgf.gd.lib.Storage" @@ -71,19 +71,19 @@ declare { --- Helpfunctions +-- Help functions --- -- Borders models the borderlines / the line of border vertices -- of a tree or subtree structure which can change over time. -- Each ordered and rooted tree or subtree has vertices per layer for which they --- are on the outer places. On the left or respectivly on the right. +-- are on the outer places. On the left or respectively on the right. -- The field |left| and |right| stores the both borderlines. -- A \emph{borderline} is an array. This array contains for each layer of the tree -- a table mapping a given snapshot to the related border-vertex of the layer -- in the snapshot. --- --- @field left +-- +-- @field left -- @field right -- local Borders = {} @@ -136,7 +136,7 @@ function Borders.copyBordersAtSnapshot(source, target, snapshot) level_border_left = target.left[i] or {} level_border_right = target.right[i] or {} assert(not level_border_left[snapshot] and not level_border_right[snapshot], - "border for a given snapshat already defined") + "border for a given snapshot already defined") level_border_left[snapshot] = source.left[i][snapshot] level_border_right[snapshot] = source.right[i][snapshot] target.left[i] = level_border_left @@ -149,7 +149,7 @@ end -- placed on the right next to the existing borders. For each level -- and time in which the group has a border the borders on the right -- will be replaced with this border. If it is not existing in the old --- borders then also the left border will be adapted +-- borders then also the left border will be adapted -- -- @param borders The existing borders. These will be modified with -- the borders of @@ -164,27 +164,27 @@ local function adapt_borders(borders, group_borders, snapshots, ignore_dummies) local r = borders.right[level] or {} for _, s in pairs(snapshots) do if ignore_dummies then - local gls,grs = group_borders.left[level][s], group_borders.right[level][s] - if gls~=nil then - if gls.kind~="dummy" then - l[s] = l[s] or gls - end - end - if grs~=nil then - if grs.kind~="dummy" then - r[s] = grs or r[s] - end - end + local gls,grs = group_borders.left[level][s], group_borders.right[level][s] + if gls~=nil then + if gls.kind~="dummy" then + l[s] = l[s] or gls + end + end + if grs~=nil then + if grs.kind~="dummy" then + r[s] = grs or r[s] + end + end else - l[s] = l[s] or group_borders.left[level][s] - r[s] = group_borders.right[level][s] or r[s] + l[s] = l[s] or group_borders.left[level][s] + r[s] = group_borders.right[level][s] or r[s] end - + end borders.left[level] = l borders.right[level] = r end - + end -- @@ -211,16 +211,16 @@ end local function shift_group(shift, group, snapshots, descendants) assert(group,"no group passed") assert(shift~=math.huge and shift ~=-math.huge, - "shift must be a valid finit length") + "shift must be a valid finite length") local shifted = {} -- remember which vertex was shifted during this run local anchor = -math.huge for _, s in ipairs(snapshots) do - local v = group[s] - if not shifted[v] and v then + local v = group[s] + if not shifted[v] and v then v.pos.x = v.pos.x + shift shifted[v] = true - -- also shift all descendants of the group vertex + -- also shift all descendants of the group vertex for _, d in ipairs(descendants[v]) do if not shifted[d] then d.pos.x = d.pos.x + shift @@ -228,28 +228,28 @@ local function shift_group(shift, group, snapshots, descendants) end end anchor = math.max(anchor, v.pos.x ) - end + end end return anchor end -- --- Traverse through the spanneng tree |tree| of a snapshot and sort --- the child nodes into groups. A group summarises for a given parent +-- Traverse through the spanning tree |tree| of a snapshot and sort +-- the child nodes into groups. A group summarizes for a given parent -- node all children node over time that are at the same child -- position. The k-th child group groups[i] maps each snapshot to the -- k-th node in the related snapshot. -- -- -- @field supergraph the supergraph --- +-- -- @field tree the tree or spanning tree to decide the indices of the -- child nodes -- -- @field childgroups a Storage which contains the list of childgroups -- for each supernode -- --- @field snapshot +-- @field snapshot -- local function precompute_childgroups(supergraph, tree, node, childgroups, snapshot) local outgoings = tree:outgoing(node) @@ -257,7 +257,7 @@ local function precompute_childgroups(supergraph, tree, node, childgroups, snaps local supervertex = supergraph:getSupervertex(node) local groups = childgroups[supervertex] or {} for i, e in ipairs(outgoings) do - + group = groups[i] or {} assert(e.head, "no edge") group[snapshot] = e.head @@ -274,7 +274,7 @@ end -- vertices in a tree by accumulation of the relative shifts on the -- path from the root to the vertex recursively. -- --- @param tree the tree in which the vertice's position should be +-- @param tree the tree in which the vertex's position should be -- computed. -- -- @param vertex the next vertex that gets its absolute coordinate. @@ -302,7 +302,7 @@ local function get_next(border_pair, next) local nr = next.right[border_pair.right] assert ((nl and nr) or (not nl and not nr)) return {left = nl, right = nr, - } + } end local function add_shift(abs_shift, border_pair, next) @@ -325,25 +325,25 @@ function Skambath2016:computeRequiredDistance(tree, vertex, i, shifts, next) if clumb.right.kind=="dummy" then shifts[clumb.right] = 0 end local v0 = outgoings[i].head local v1 = outgoings[i+1].head - local shift = layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, v0, v1) + shifts[clumb.right] + local shift = layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, v0, v1) + shifts[clumb.right] local last0 = {left = clumb.left, right = clumb.right} - local last1 = {left = v1, right = v1} + local last1 = {left = v1, right = v1} local next0 = get_next(last0, next) local next1 = get_next(last1, next) local abs_shift0 = {left = shifts[clumb.left], right = shifts[clumb.right]} - local abs_shift1 = {left = 0, right = 0} + local abs_shift1 = {left = 0, right = 0} while (next0.left and next1.left) do add_shift(abs_shift0, last0, next) add_shift(abs_shift1, last1, next) shift = math.max(shift, - layered.ideal_sibling_distance(self.adjusted_bb, - self.ugraph, - next0.right, - next1.left) - + abs_shift0.right - abs_shift1.left) --- texio.write("\n | "..(next0.right.name or "dummy").."<->"..(next1.left.name or "dummy").." :\t"..shift) + layered.ideal_sibling_distance(self.adjusted_bb, + self.ugraph, + next0.right, + next1.left) + + abs_shift0.right - abs_shift1.left) +-- texio.write("\n | "..(next0.right.name or "dummy").."<->"..(next1.left.name or "dummy").." :\t"..shift) last0, last1 = next0, next1 next0 = get_next(next0, next) next1 = get_next(next1, next) @@ -383,7 +383,7 @@ local function apply_shift(tree, vertex, i, shifts, next, border_ptr, shift) next.left[last0.left] = next1.left -- pgf.debug{last0,abs0,abs1,last1} next.left_shift[last0.left] = shift - abs0.left + (abs1.left + next.left_shift[last1.left] ) - + else -- both trees have the same height end @@ -398,11 +398,11 @@ function Skambath2016:run() local childgroups = Storage.new() local phases = self.digraph.options.algorithm_phases - + local so_class = phases['supergraph optimization'] local ga_class = phases['evolving graph animation'] local cr_class = phases['temporal cycle removal'] - + self.extended_version = self.digraph.options['missing nodes get space'] self.supergraph = Supergraph.generateSupergraph(self.digraph) local supergraph_original = Supergraph.generateSupergraph(self.digraph) @@ -414,8 +414,8 @@ function Skambath2016:run() digraph = self.digraph, ugraph = self.ugraph }:run() - - + + self:precomputeSpanningTrees() -- Resolve cyclic dependencies if exists. @@ -432,13 +432,13 @@ function Skambath2016:run() self:computeHorizontalLayout(childgroups, descendants) -- self:computeHorizontalLayoutFast() - - -- vertical positions + + -- vertical positions tlayered.arrange_layers_by_baselines(layers, - self.adjusted_bb, - self.ugraph, - self.supergraph.snapshots, - self.supergraph.vertex_snapshots) + self.adjusted_bb, + self.ugraph, + self.supergraph.snapshots, + self.supergraph.vertex_snapshots) -- animate graph ga_class.new { @@ -446,11 +446,11 @@ function Skambath2016:run() supergraph = supergraph_original, digraph = self.digraph, ugraph = self.ugraph - }:run() + }:run() end -- --- Compute the required shift value for a second tree to garuantee +-- Compute the required shift value for a second tree to guarantee -- a required node distance. -- @field right_borders The Border data structure for the right border of -- the left tree @@ -465,11 +465,11 @@ function Skambath2016:computeMinShift(right_borders, left_borders, selected_snap local max_level = math.min(#right_borders, #left_borders) local first_shift = 0 local snapshots = selected_snapshots or self.supergraph.snapshots - + for layer = 1, max_level do local rb, lb = right_borders[layer], left_borders[layer] for _,s in ipairs(snapshots) do - + local v1,v2 = rb[s],lb[s] if v1 and v2 then local local_shift = layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, v1, v2) + v1.pos.x - v2.pos.x @@ -497,7 +497,7 @@ function Skambath2016:computeMinShift(right_borders, left_borders, selected_snap if is_significant then shift = shift + self.ugraph.options['significant sep'] end - + return shift end @@ -521,20 +521,20 @@ function Skambath2016:computeHorizontalLayout(groups, descendants) end -- 1. Initialize Dependencies - + for _, snapshot in ipairs(self.supergraph.snapshots) do for _, spanning_tree in ipairs(snapshot.spanning_trees) do for _, arc in ipairs(spanning_tree.arcs) do - - local head = self.supergraph:getSupervertex(arc.head) - local tail = self.supergraph:getSupervertex(arc.tail) - - if(head and tail) then - if not dependency_graph:arc(tail, head) then - dependency_graph:connect(tail, head) - dep_counter[tail] = dep_counter[tail] + 1 - end - end + + local head = self.supergraph:getSupervertex(arc.head) + local tail = self.supergraph:getSupervertex(arc.tail) + + if(head and tail) then + if not dependency_graph:arc(tail, head) then + dependency_graph:connect(tail, head) + dep_counter[tail] = dep_counter[tail] + 1 + end + end end end end @@ -546,19 +546,19 @@ function Skambath2016:computeHorizontalLayout(groups, descendants) queue:enqueue(vertex, 1) end end - - -- 2. + + -- 2. while not queue:isEmpty() do - local vertex = queue:dequeue() + local vertex = queue:dequeue() local vertex_snapshots = self.supergraph:getSnapshots(vertex) - + -- a. Resolve dependencies on this vertex: local incomings = dependency_graph:incoming(vertex) - for _, e in ipairs(incomings) do + for _, e in ipairs(incomings) do dep_counter[e.tail] = dep_counter[e.tail] - 1 if dep_counter[e.tail] == 0 then - queue:enqueue(e.tail, 1) - end + queue:enqueue(e.tail, 1) + end end -- b. Compute borders of this supervertex: @@ -569,63 +569,63 @@ function Skambath2016:computeHorizontalLayout(groups, descendants) snapshot_vertex.pos.x = 0 snapshot_vertex.pos.y = 0 end - + local vertex_groups = groups[vertex] local last_pos_x = 0 if vertex_groups then -- c. Compute borders of groups: local all_group_borders = {} for i, group in ipairs(vertex_groups) do - local group_boders = Borders.new() - for _,s in ipairs(vertex_snapshots) do - local child = group[s] - if child then - local child_borders - if not (child.kind == "dummy") then - local superchild = self.supergraph:getSupervertex(child) - child_borders = subtree_borders[superchild] or Borders.new() - else - child_borders = Borders.new() - child_borders:addBoth(1, s, child) - end - assert(child.pos~=math.huge, "invalid child pos") - shift_group(-child.pos.x,{[s]=child},{[1]=s}, descendants) - Borders.copyBordersAtSnapshot(child_borders, group_boders, s) - end - end - all_group_borders[i] = group_boders + local group_boders = Borders.new() + for _,s in ipairs(vertex_snapshots) do + local child = group[s] + if child then + local child_borders + if not (child.kind == "dummy") then + local superchild = self.supergraph:getSupervertex(child) + child_borders = subtree_borders[superchild] or Borders.new() + else + child_borders = Borders.new() + child_borders:addBoth(1, s, child) + end + assert(child.pos~=math.huge, "invalid child pos") + shift_group(-child.pos.x,{[s]=child},{[1]=s}, descendants) + Borders.copyBordersAtSnapshot(child_borders, group_boders, s) + end + end + all_group_borders[i] = group_boders end - + -- d. Place groups and merge borders of groups: local last_group = nil last_pos_x = 0 local merged_borders = Borders.new() local final_borders = Borders.new() for i, group in ipairs(vertex_groups) do - local group_borders = all_group_borders[i] - if last_group_borders then - -- i. compute minimal shift - - local shift - shift = self:computeMinShift(merged_borders.right, group_borders.left) - - - assert(shift ~= math.huge and shift~=-math.huge, "invalid shift") - - -- ii. shift group - local anchor = shift_group(shift, group,vertex_snapshots, descendants) - last_pos_x = anchor - end - last_group_borders = group_borders - - -- iii. adapt borders - adapt_borders(merged_borders, - group_borders, - self.supergraph.snapshots) - adapt_borders(final_borders, - group_borders, - self.supergraph.snapshots, - not self.extended_version) + local group_borders = all_group_borders[i] + if last_group_borders then + -- i. compute minimal shift + + local shift + shift = self:computeMinShift(merged_borders.right, group_borders.left) + + + assert(shift ~= math.huge and shift~=-math.huge, "invalid shift") + + -- ii. shift group + local anchor = shift_group(shift, group,vertex_snapshots, descendants) + last_pos_x = anchor + end + last_group_borders = group_borders + + -- iii. adapt borders + adapt_borders(merged_borders, + group_borders, + self.supergraph.snapshots) + adapt_borders(final_borders, + group_borders, + self.supergraph.snapshots, + not self.extended_version) end -- for (group) vertex_borders:appendBelow(1, final_borders) end @@ -637,24 +637,24 @@ function Skambath2016:computeHorizontalLayout(groups, descendants) local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) snapshot_vertex.pos.x = x end - - subtree_borders[vertex] = vertex_borders + + subtree_borders[vertex] = vertex_borders end - -- align roots + -- align roots for _, s in ipairs(self.supergraph.snapshots) do local lastroot - local rborder + local rborder for i, spanning_tree in ipairs(s.spanning_trees) do local root = spanning_tree.root local rootborders = subtree_borders[self.supergraph:getSupervertex(root)] shift_group(-root.pos.x,{[s]=root},{[1]=s}, descendants) if i>1 then - local l = subtree_borders[self.supergraph:getSupervertex(lastroot)] - local r = rootborders - shift = math.max(self:computeMinShift(l.right, r.left, {[1]=s}), - self:computeMinShift(rborder.right,r.left, {[1]=s})) - shift_group(shift,{[s]=root},{[1]=s}, descendants) + local l = subtree_borders[self.supergraph:getSupervertex(lastroot)] + local r = rootborders + shift = math.max(self:computeMinShift(l.right, r.left, {[1]=s}), + self:computeMinShift(rborder.right,r.left, {[1]=s})) + shift_group(shift,{[s]=root},{[1]=s}, descendants) else rborder = Borders.new() end @@ -684,28 +684,28 @@ function Skambath2016:computeHorizontalLayoutFast() dependency_graph:add {vertex} end - + -- I. Initialize Dependencies (Build Dependency Graph) for _, snapshot in ipairs(self.supergraph.snapshots) do for _, spanning_tree in ipairs(snapshot.spanning_trees) do table.insert(all_trees, spanning_tree) shifts[spanning_tree] = Storage.new() next[spanning_tree] = {left= Storage.new(), - right= Storage.new(), - left_shift = Storage.new(), - right_shift = Storage.new() + right= Storage.new(), + left_shift = Storage.new(), + right_shift = Storage.new() } - + for _, arc in ipairs(spanning_tree.arcs) do - local head = self.supergraph:getSupervertex(arc.head) - local tail = self.supergraph:getSupervertex(arc.tail) - - if(head and tail) then - if not dependency_graph:arc(tail, head) then - dependency_graph:connect(tail, head) - dep_counter[tail] = dep_counter[tail] + 1 - end - end + local head = self.supergraph:getSupervertex(arc.head) + local tail = self.supergraph:getSupervertex(arc.tail) + + if(head and tail) then + if not dependency_graph:arc(tail, head) then + dependency_graph:connect(tail, head) + dep_counter[tail] = dep_counter[tail] + 1 + end + end end end end @@ -718,21 +718,21 @@ function Skambath2016:computeHorizontalLayoutFast() queue:enqueue(vertex, 1) end end - + while not queue:isEmpty() do -- Next node in topological order local vertex = queue:dequeue() -- texio.write("\n\n --- "..vertex.name .. " ---") --pgf.debug{next} local vertex_snapshots = self.supergraph:getSnapshots(vertex) - + -- a. Resolve dependencies on this vertex: local incomings = dependency_graph:incoming(vertex) - for _, e in ipairs(incomings) do + for _, e in ipairs(incomings) do dep_counter[e.tail] = dep_counter[e.tail] - 1 if dep_counter[e.tail] == 0 then - queue:enqueue(e.tail, 1) - end + queue:enqueue(e.tail, 1) + end end -- b. Compute maximum number of children over time: @@ -743,7 +743,7 @@ function Skambath2016:computeHorizontalLayoutFast() num_children = math.max(num_children, #(tree:outgoing(v))) shifts[tree][v] = 0 end - + -- c. Shift all subtrees in all snapshots: local hlp_ptr = Storage.new() local max_shift = 0 @@ -751,27 +751,27 @@ function Skambath2016:computeHorizontalLayoutFast() -- i) Compute the necessary shift between the i-th and (i+1)-th subtrees (per snapshot): local min_shift = 0 for t, s in ipairs(vertex_snapshots) do - local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) - local tree = s.spanning_trees[1] - local req_shift, hptr - req_shift, hptr = self:computeRequiredDistance(tree, - snapshot_vertex, - i, - shifts[tree], - next[tree] - ) - hlp_ptr[t] = hptr --- texio.write(" -> \t"..req_shift) - min_shift = math.max(min_shift, req_shift) + local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) + local tree = s.spanning_trees[1] + local req_shift, hptr + req_shift, hptr = self:computeRequiredDistance(tree, + snapshot_vertex, + i, + shifts[tree], + next[tree] + ) + hlp_ptr[t] = hptr +-- texio.write(" -> \t"..req_shift) + min_shift = math.max(min_shift, req_shift) end -- texio.write("\n \t\t".. min_shift ) - - -- ii) Synchronize distance between neigbored subtrees and apply shifts + + -- ii) Synchronize distance between neighbored subtrees and apply shifts for t, s in ipairs(vertex_snapshots) do - local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) - local tree = s.spanning_trees[1] - apply_shift(tree, snapshot_vertex, i, shifts[tree], next[tree], hlp_ptr[t], min_shift) + local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) + local tree = s.spanning_trees[1] + apply_shift(tree, snapshot_vertex, i, shifts[tree], next[tree], hlp_ptr[t], min_shift) end max_shift = min_shift @@ -781,22 +781,22 @@ function Skambath2016:computeHorizontalLayoutFast() local snapshot_vertex = self.supergraph:getSnapshotVertex(vertex, s) local tree = s.spanning_trees[1] local outgoings = tree:outgoing(snapshot_vertex) - + -- next[tree].left[snapshot_vertex] = outgoings[1].head for i = 1,#outgoings do - if i==1 then - next[tree].left_shift[snapshot_vertex] = - max_shift / 2 - next[tree].left[snapshot_vertex]= outgoings[i].head - end - shifts[tree][outgoings[i].head] = shifts[tree][outgoings[i].head] - max_shift / 2 - next[tree].right[snapshot_vertex] = outgoings[i].head - next[tree].right_shift[snapshot_vertex] = shifts[tree][outgoings[i].head] + if i==1 then + next[tree].left_shift[snapshot_vertex] = - max_shift / 2 + next[tree].left[snapshot_vertex]= outgoings[i].head + end + shifts[tree][outgoings[i].head] = shifts[tree][outgoings[i].head] - max_shift / 2 + next[tree].right[snapshot_vertex] = outgoings[i].head + next[tree].right_shift[snapshot_vertex] = shifts[tree][outgoings[i].head] end - + end - + end -- end while (all vertices have been processed) -- III. Accumulate absolute horizontal coordinates @@ -832,7 +832,7 @@ end -- --- +-- -- function Skambath2016:precomputeChildgroups(childgroups) for _,s in ipairs(self.supergraph.snapshots) do @@ -849,8 +849,8 @@ end -- function Skambath2016:precomputeSpanningTrees() local events = assert(self.scope.events, - "no events found for the spanning tree computation") - + "no events found for the spanning tree computation") + for i, s in ipairs(self.supergraph.snapshots) do -- The involved snapshot graph: local s_copy = Digraph.new(s) diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua index 490b8b3191d..99e79919b54 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/Supergraph.lua @@ -27,12 +27,12 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- and if there is a single snapshot in which two vertices are -- connected by an edge they are connected in the supergraph. -- --- Note that in TikZ a \emph{node} is more than a single dot. A node +-- Note that in \tikzname\ a \emph{node} is more than a single dot. A node -- has a content and different properties like background-color or a --- shape. Formally this can be modelled by function mapping vertices +-- shape. Formally this can be modeled by function mapping vertices -- to their properties. For evolving graphs this could be done in the --- same way. As this is difficult to be realised in PGF because there --- is no basic support for time dependend properties on nodes, each +-- same way. As this is difficult to be realized in PGF because there +-- is no basic support for time dependent properties on nodes, each -- vertex will be displayed over time by different single -- (snapshot-)nodes which can have different visual properties. This -- means for a vertex which we call |supervertex| in the following we @@ -53,7 +53,7 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- @field supervertices_by_id This storage maps a node identifier to the -- related supervertex such that PGF-nodes which belonging to -- the same superverticex can be identified --- +-- -- @field snapshots An array of all snapshots. Sorted in ascending order -- over the timestamps of the snapshots. -- @@ -64,6 +64,7 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- Assume we want to iterate over all snapshots -- for a certain pair of supernodes in which they are connected -- by an arc. The arc_snapshots storage helps in this case: +-- % -- \begin{codeexample}[code only, tikz syntax=false] -- local supergraph = Supergraph.generateSupergraph(self.digraph) -- local u = supergraph.vertices[1] @@ -110,24 +111,24 @@ local get_snapshot -- -- @param snapshots An array of all existing snapshots -- @param timestamps A table which maps known timestamps to their --- related snapshots +-- related snapshots -- @param ugraph The ugraph of the underlying graph structure -- @param snapshot_time -- -- @return The snapshot instance found in the snapshots array for the --- wanted timestamp snapshot_time if it does'nt exists a new snapshot --- will be generated and added to the arrays +-- wanted timestamp snapshot_time if it doesn't exists a new snapshot +-- will be generated and added to the arrays -- function get_snapshot(snapshots, timestamps, ugraph, snapshot_time) local snapshot local snapshot_idx = timestamps[snapshot_time] - + if not snapshot_idx then -- store snapshot if it doesn't exists - snapshot_idx = timestamps.n + 1 + snapshot_idx = timestamps.n + 1 timestamps[snapshot_time] = snapshot_idx timestamps.n = timestamps.n + 1 - snapshot = Digraph.new { + snapshot = Digraph.new { syntactic_digraph = ugraph.syntactic_digraph, options = ugraph.options } @@ -136,7 +137,7 @@ function get_snapshot(snapshots, timestamps, ugraph, snapshot_time) else snapshot = snapshots[snapshot_idx] end - assert(snapshot~=nil, "an unexpected error occured") + assert(snapshot~=nil, "an unexpected error occurred") return snapshot end @@ -152,7 +153,7 @@ end -- -- @return The supergraph which is a |Digraph| that has a supervertex -- for each set of snapshot-vertices with the same |supernode| --- attribute. +-- attribute. -- function Supergraph.generateSupergraph(digraph) local new_supergraph @@ -161,35 +162,35 @@ function Supergraph.generateSupergraph(digraph) options = digraph.options, digraph = digraph, } - - -- array to store the supervertices for a given vertex name + + -- array to store the supervertices for a given vertex name local local_snapshots = {} -- array to store each snapshot graphs - + local timestamps = { n = 0 } -- set of snapshot times - -- separate and assign vertices to their snapshots and supervertives + -- separate and assign vertices to their snapshots and supervertices for i,vertex in ipairs(digraph.vertices) do local snapshot_time = assert(vertex.options["snapshot"], "Missing option 'snapshot' for vertex ".. vertex.name ..". ") local supernode_name = assert(vertex.options["supernode"], "Missing option 'supernode' for vertex"..vertex.name..". ") - + local snapshot = get_snapshot(local_snapshots, timestamps, digraph, snapshot_time) local supervertex = new_supergraph.supervertices_by_id[supernode_name] - + if not supervertex then - -- first appeareance of the supernode id - supervertex = Vertex.new { - kind = "super", - name = supernode_name + -- first appearance of the supernode id + supervertex = Vertex.new { + kind = "super", + name = supernode_name } supervertex.snapshots = {} supervertex.subvertex = {} - new_supergraph.supervertices_by_id[supernode_name] = supervertex + new_supergraph.supervertices_by_id[supernode_name] = supervertex new_supergraph:add{supervertex} supervertex.options = {} supervertex.options = vertex.options - end - + end + snapshot:add{vertex} new_supergraph.supervertices[vertex] = supervertex @@ -198,11 +199,11 @@ function Supergraph.generateSupergraph(digraph) end -- Create edges - for i, e in ipairs(digraph.arcs) do + for i, e in ipairs(digraph.arcs) do local u,v = e.tail, e.head local snapshot_tail = new_supergraph.vertex_snapshots[e.tail] local snapshot_head = new_supergraph.vertex_snapshots[e.head] - + assert(snapshot_head == snapshot_tail, "Arcs must connect nodes that exist at the same time.") -- connect in the snapshot graph @@ -211,18 +212,18 @@ function Supergraph.generateSupergraph(digraph) -- connect in the supergraph: local super_tail = new_supergraph.supervertices[u] local super_head = new_supergraph.supervertices[v] - + new_supergraph:assignToSuperarc(super_tail, super_head, snapshot_tail) end - + -- snapshots in temporal order - table.sort(local_snapshots, + table.sort(local_snapshots, function(s1,s2) return s1.timestamp < s2.timestamp end ) - - local previous_snapshot - + + local previous_snapshot + for i,s in ipairs(local_snapshots) do local start = -math.huge if previous_snapshot then @@ -235,18 +236,18 @@ function Supergraph.generateSupergraph(digraph) new_supergraph.snapshots = local_snapshots new_supergraph.snapshots_indices = Storage.new() - + for i, s in ipairs(new_supergraph.snapshots) do new_supergraph.snapshots_indices[s] = i end - + return new_supergraph end function Supergraph:getSnapshotStaticDuration(snapshot) assert(snapshot, "a snapshot as parameter expected, but got nil") - local idur = snapshot.interval.to - snapshot.interval.from + local idur = snapshot.interval.to - snapshot.interval.from assert(idur, "unexpected nil-value") local d1 = snapshot.interval.to - snapshot.timestamp local d2 = snapshot.timestamp - snapshot.interval.from @@ -272,9 +273,9 @@ function Supergraph:getDuration() end --- --- +-- -- @return The ratio of the time of a snapshot related to the global duration of the whole --- evlolving trees. (The time between the last and first snapshot) +-- evolving trees. (The time between the last and first snapshot) function Supergraph:getSnapshotRelativeDuration(snapshot) if self:getDuration() == 0 then return 1 @@ -294,7 +295,7 @@ end function Supergraph:getSupervertex(vertex) assert(vertex, "vertex required") assert(self.supervertices, "supervertex table is not defined") - return self.supervertices[vertex] + return self.supervertices[vertex] end function Supergraph:getSuperarc(arc) @@ -322,7 +323,7 @@ end --- -- For a given supervertex get the related vertex for a snapshot -- --- @param supervertex +-- @param supervertex -- -- @param snapshot -- @@ -340,7 +341,7 @@ function Supergraph:consecutiveSnapshots(snapshot1, snapshot2, n) local idx1 = self.snapshots_indices[snapshot1] --or -1 local idx2 = self.snapshots_indices[snapshot2] --or -1 local d = n or 1 - + return (idx2-idx1 <= d) or (idx1-idx2 <= d) end @@ -358,21 +359,21 @@ end -- their positions from the supergraph. -- function Supergraph:sharePositions(ugraph, ignore) - + for _,vertex in ipairs(ugraph.vertices) do if not ignore then vertex.pos.x = self.supervertices[vertex].pos.x vertex.pos.y = self.supervertices[vertex].pos.y else if not ignore.x then - vertex.pos.x = self.supervertices[vertex].pos.x + vertex.pos.x = self.supervertices[vertex].pos.x end if not ignore.y then - vertex.pos.y = self.supervertices[vertex].pos.y + vertex.pos.y = self.supervertices[vertex].pos.y end end - - + + end end @@ -380,7 +381,7 @@ function Supergraph:onAllSnapshotvertices(f, ugraph) for _,vertex in ipairs(ugraph.vertices) do local snapshot_vertex = self.supertvertices[vertex] if snapshot_vertex then - f(vertex, snapshot_vertex) + f(vertex, snapshot_vertex) end end end @@ -394,23 +395,23 @@ end -- the original vertex. -- If a supervertex has no subvertices then it will not be added to the graph. -- --- @param supervertex The supervertex which should be splitted. +-- @param supervertex The supervertex which should be split. -- -- @param snapshots An array of snapshots at which the supervertex --- should be splitted into a new one with the corresponding pgf-vertices. +-- should be split into a new one with the corresponding pgf-vertices. -- If there are more than one snapshots passed to the function -- for each snapshot there will be a new pseudo-vertex -- function Supergraph:splitSupervertex(supervertex, snapshots) assert(supervertex, "no supervertex defined") -- snapshots in temporal order - table.sort(snapshots, + table.sort(snapshots, function(s1,s2) return s1.timestamp < s2.timestamp end ) assert(#snapshots~=0) - + local edit_snapshots = supervertex.snapshots local first_removed = math.huge local rem_arcs = {} @@ -437,42 +438,42 @@ function Supergraph:splitSupervertex(supervertex, snapshots) local s = self.snapshots[j] local vertex = self:getSnapshotVertex(supervertex, s) if vertex then - self.supervertices[vertex] = pseudovertex - self:addSnapshotVertex(pseudovertex, s, vertex) - self:removeSnapshotVertex(supervertex, s) - - if not has_subvertices then - has_subvertices = true - self:add{pseudovertex} - end - - -- update edges: - local incoming = self.digraph:incoming(vertex) - local outgoing = self.digraph:outgoing(vertex) - - for _, arc in ipairs(incoming) do - local tail = self.supervertices[arc.tail] - local head = self.supervertices[arc.head] - self:assignToSuperarc(tail, pseudovertex, s) - - local super_arc = self:arc(tail, supervertex) - if not rem_arcs[super_arc] then - table.insert(rem_arcs, {arc = super_arc, snapshot = s}) - rem_arcs[super_arc] = true - end - end - - for _, arc in ipairs(outgoing) do - local tail = self.supervertices[arc.tail] - local head = self.supervertices[arc.head] - self:assignToSuperarc(pseudovertex, head, s) - - local super_arc = self:arc(supervertex, head) - if not rem_arcs[super_arc] then - table.insert(rem_arcs, {arc = super_arc, snapshot = s}) - rem_arcs[super_arc] = true - end - end + self.supervertices[vertex] = pseudovertex + self:addSnapshotVertex(pseudovertex, s, vertex) + self:removeSnapshotVertex(supervertex, s) + + if not has_subvertices then + has_subvertices = true + self:add{pseudovertex} + end + + -- update edges: + local incoming = self.digraph:incoming(vertex) + local outgoing = self.digraph:outgoing(vertex) + + for _, arc in ipairs(incoming) do + local tail = self.supervertices[arc.tail] + local head = self.supervertices[arc.head] + self:assignToSuperarc(tail, pseudovertex, s) + + local super_arc = self:arc(tail, supervertex) + if not rem_arcs[super_arc] then + table.insert(rem_arcs, {arc = super_arc, snapshot = s}) + rem_arcs[super_arc] = true + end + end + + for _, arc in ipairs(outgoing) do + local tail = self.supervertices[arc.tail] + local head = self.supervertices[arc.head] + self:assignToSuperarc(pseudovertex, head, s) + + local super_arc = self:arc(supervertex, head) + if not rem_arcs[super_arc] then + table.insert(rem_arcs, {arc = super_arc, snapshot = s}) + rem_arcs[super_arc] = true + end + end end end end @@ -481,14 +482,14 @@ function Supergraph:splitSupervertex(supervertex, snapshots) for _, removed_arc in ipairs(rem_arcs) do local snapshots = self.arc_snapshots[removed_arc.arc] for i=#snapshots,1,-1 do - local s = snapshots[i] - if s.timestamp >= removed_arc.snapshot.timestamp then - table.remove(snapshots, i) - end + local s = snapshots[i] + if s.timestamp >= removed_arc.snapshot.timestamp then + table.remove(snapshots, i) + end end if #snapshots==0 then - self:disconnect(removed_arc.arc.tail, removed_arc.arc.head) + self:disconnect(removed_arc.arc.tail, removed_arc.arc.head) end end end @@ -553,16 +554,16 @@ end -- function Supergraph:assignToSuperarc(super_tail, super_head, snapshot) assert(self:contains(super_tail) and self:contains(super_head), - "tried to connect supernodes not in the supergraph") - + "tried to connect supernodes not in the supergraph") + local super_arc = self:arc(super_tail, super_head) if not super_arc then - super_arc = self:connect(super_tail, super_head) + super_arc = self:connect(super_tail, super_head) end - + table.insert(self.arc_snapshots[super_arc], snapshot) self.arc_snapshots[super_arc][snapshot] = true - + return super_arc end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua index 2295e60513b..b5a4ea22c94 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/SupergraphVertexSplitOptimization.lua @@ -59,19 +59,19 @@ declare { algorithm = SupergraphVertexSplitOptimization, phase = "supergraph optimization", phase_default = true, - summary = [[" - Use this key if you want to disable animations. - Instead of producing animations the evolving graph animation phasephase animates all vertices including movements and - fade in or fade out animations. + summary = [[" + Use this key if you want to disable animations. + Instead of producing animations the evolving graph animation phasephase animates all vertices including movements and + fade in or fade out animations. "]], - documentation = [[" - See ToDo + documentation = [[" + See ToDo "]] } --- Helpfunctions +-- Help functions -- Implementation @@ -84,102 +84,102 @@ function SupergraphVertexSplitOptimization:run() local split_on_no_common_child = self.digraph.options["split on disjoint children"] local split_on_no_common_parent = self.digraph.options["split on disjoint parents"] local split_all = self.digraph.options["split all supervertices"] - + for _, supernode in ipairs(supergraph.vertices) do -- follow trace of the supernode local snapshots = supergraph:getSnapshots(supernode) local splitsnapshots = {} - + for i=2, #snapshots do local s = snapshots[i] local s_prev = snapshots[i - 1] local can_split = false if supergraph:consecutiveSnapshots(s_prev, s) then - local v1 = supergraph:getSnapshotVertex(supernode, s_prev) - local v2 = supergraph:getSnapshotVertex(supernode, s) - local is_child1 = {} - local is_parent1 = {} - local is_neighbor1 = {} - - local incoming1 = s_prev:incoming(v1) - local outgoing1 = s_prev:outgoing(v1) - - for _,e in ipairs(incoming1) do - local p = supergraph:getSupervertex(e.tail) - if p then - is_parent1[p] = true - is_neighbor1[p] = true - end - end - - for _,e in ipairs(outgoing1) do - local p = supergraph:getSupervertex(e.head) - if p then - is_child1[p] = true - is_neighbor1[p] = true - end - end - - local incoming2 = s:incoming(v2) - local outgoing2 = s:outgoing(v2) - - no_common_parent = true - no_common_child = true - no_common_neighbor = true - for _,e in ipairs(incoming2) do - local p = supergraph:getSupervertex(e.tail) - if p then - if is_neighbor1[p] then - no_common_neighbor = false - end - if is_parent1[p] then - no_common_parent = false - end - if (not no_common_neighbor) and (not no_common_parent) then - break - end - end - end - - for _,e in ipairs(outgoing2) do - local p = supergraph:getSupervertex(e.head) - if p then - if is_neighbor1[p] then - no_common_neighbor = false - end - if is_child1[p] then - no_common_child = false - end - if (not no_common_neighbor) and (not no_common_child) then - break - end - end - end - - - - if no_common_neighbor and split_on_no_common_neighbor then - can_split = true - --texio.write("[N@".. s.timestamp .."]") - end - if no_common_parent and split_on_no_common_parent then - can_split = true - --texio.write("[P@".. s.timestamp .."]") - end - if no_common_child and split_on_no_common_child then - can_split = true - --texio.write("[N@".. s.timestamp .."]") - end - if v2.options["split me"] then - can_split = true - end - else - can_split = true - --texio.write("[R@".. s.timestamp .."]") - end - if can_split or split_all then - table.insert(splitsnapshots, s) + local v1 = supergraph:getSnapshotVertex(supernode, s_prev) + local v2 = supergraph:getSnapshotVertex(supernode, s) + local is_child1 = {} + local is_parent1 = {} + local is_neighbor1 = {} + + local incoming1 = s_prev:incoming(v1) + local outgoing1 = s_prev:outgoing(v1) + + for _,e in ipairs(incoming1) do + local p = supergraph:getSupervertex(e.tail) + if p then + is_parent1[p] = true + is_neighbor1[p] = true + end + end + + for _,e in ipairs(outgoing1) do + local p = supergraph:getSupervertex(e.head) + if p then + is_child1[p] = true + is_neighbor1[p] = true + end + end + + local incoming2 = s:incoming(v2) + local outgoing2 = s:outgoing(v2) + + no_common_parent = true + no_common_child = true + no_common_neighbor = true + for _,e in ipairs(incoming2) do + local p = supergraph:getSupervertex(e.tail) + if p then + if is_neighbor1[p] then + no_common_neighbor = false + end + if is_parent1[p] then + no_common_parent = false + end + if (not no_common_neighbor) and (not no_common_parent) then + break + end + end + end + + for _,e in ipairs(outgoing2) do + local p = supergraph:getSupervertex(e.head) + if p then + if is_neighbor1[p] then + no_common_neighbor = false + end + if is_child1[p] then + no_common_child = false + end + if (not no_common_neighbor) and (not no_common_child) then + break + end + end + end + + + + if no_common_neighbor and split_on_no_common_neighbor then + can_split = true + --texio.write("[N@".. s.timestamp .."]") + end + if no_common_parent and split_on_no_common_parent then + can_split = true + --texio.write("[P@".. s.timestamp .."]") + end + if no_common_child and split_on_no_common_child then + can_split = true + --texio.write("[N@".. s.timestamp .."]") + end + if v2.options["split me"] then + can_split = true + end + else + can_split = true + --texio.write("[R@".. s.timestamp .."]") + end + if can_split or split_all then + table.insert(splitsnapshots, s) end end if #splitsnapshots>0 then diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua index 13d453f1fd6..2b2168da1aa 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/TimeSpec.lua @@ -14,47 +14,49 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare --- declare { - key = "snapshot", - type = "time", - initial = "0s", - summary = "The time of the snapshot in which a PGF node should be visible.", - documentation = [[" - This option defines the time in seconds when respectively in which - state or snapshot of the graph the PGF represents a graph node. -"]] + key = "snapshot", + type = "time", + initial = "0s", + summary = "The time of the snapshot in which a PGF node should be visible.", + documentation = [[" + This option defines the time in seconds when respectively in which + state or snapshot of the graph the PGF represents a graph node. + "]], } --- declare { - key = "supernode", - type = "string", - initial = "null", - summary = "A unique name for a node a given PGF node should be assigned to.", - documentation = [[" - Because it should be possible that nodes can change their - appearance, they are represented by separate PGF nodes in each - snapshot. To identify PGF nodes of the same supernode we have to - specify this key. -"]] + key = "supernode", + type = "string", + initial = "null", + summary = "A unique name for a node a given PGF node should be assigned to.", + documentation = [[" + Because it should be possible that nodes can change their + appearance, they are represented by separate PGF nodes in each + snapshot. To identify PGF nodes of the same supernode we have to + specify this key. + "]], } --- declare { - key = "fadein time", - type = "time", - initial = "0.5s", - summary = [["The time in seconds it should take that a nodes will be fade in - when it disappears in the graph"]], + key = "fadein time", + type = "time", + initial = "0.5s", + summary = [[" + The time in seconds it should take that a nodes will be fade in + when it disappears in the graph. + "]], } --- declare { - key = "fadeout time", - type = "time", - initial = "0.5s", - summary = "", - documentation = "The same as |fadein time| but for disappearing nodes." + key = "fadeout time", + type = "time", + initial = "0.5s", + summary = "", + documentation = "The same as |fadein time| but for disappearing nodes.", } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua index 801e3808bb4..dbd81462758 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/doc.lua @@ -26,26 +26,27 @@ documentation A method to create layouts for evolving graphs as an SVG animation.The Reingold--Tilford method is a standard method for drawing trees. It is described in: -The algorithm, which is based on the Reingold--Tilford algorithm and +The algorithm, which is based on the Reingold--Tilford algorithm and its implementation in |graphdrawing.trees|, is introduced in my Masthesis: +% \begin{itemize} -\item - M.\ Skambath, - \newblock Algorithmic Drawing of Evolving Trees, Masterthesis, 2016 + \item + M.\ Skambath, + \newblock Algorithmic Drawing of Evolving Trees, Masterthesis, 2016 \end{itemize} -You can use the same known graph macros as for other graph drawing -algorithms in Ti\emph{k}Z. In addition all keys and features that +You can use the same known graph macros as for other graph drawing +algorithms in Ti\emph{k}Z. In addition all keys and features that are available for the static tree algorithm can be used: - +% \begin{codeexample}[animation list={1,1.5,2,2.5,3,3.5,4}] \tikz \graph[animated binary tree layout, nodes={draw,circle}, auto supernode, - ] { - {[when=1] 15 -> {10 -> { ,11}, 20 }}, - {[when=2] 15 -> {10 -> {3,11}, 20 }}, - {[when=3] 15 -> {10 -> {3, }, 20 }}, - {[when=4] 15 -> {10 -> {3, }, 20 -> 18 }}, + ] { + {[when=1] 15 -> {10 -> { ,11}, 20 }}, + {[when=2] 15 -> {10 -> {3,11}, 20 }}, + {[when=3] 15 -> {10 -> {3, }, 20 }}, + {[when=4] 15 -> {10 -> {3, }, 20 -> 18 }}, }; \end{codeexample} ]] @@ -54,11 +55,11 @@ are available for the static tree algorithm can be used: example [[ \tikz[animated binary tree layout] - \graph[nodes={draw,circle}, auto supernode] { - {[when=1] 15 -> {10 -> { ,11}, 20 }}, - {[when=2] 15 -> {10 -> {3,11}, 20 }}, - {[when=3] 15 -> {10 -> {3, }, 20 }}, - {[when=4] 15 -> {10 -> {3, }, 20 -> 18 }}, + \graph[nodes={draw,circle}, auto supernode] { + {[when=1] 15 -> {10 -> { ,11}, 20 }}, + {[when=2] 15 -> {10 -> {3,11}, 20 }}, + {[when=3] 15 -> {10 -> {3, }, 20 }}, + {[when=4] 15 -> {10 -> {3, }, 20 -> 18 }}, }; ]] -------------------------------------------------------------------- @@ -76,15 +77,17 @@ key "animated binary tree layout" summary [[ A layout based on the Reingold--Tilford method for drawing -binary trees. ]] +binary trees. +]] documentation [[ This key executes: +% \begin{enumerate} -\item |animated tree layout|, thereby selecting the Reingold--Tilford method, -\item |minimum number of children=2|, thereby ensuring the all nodes - have (at least) two children or none at all, and + \item |animated tree layout|, thereby selecting the Reingold--Tilford method, + \item |minimum number of children=2|, thereby ensuring the all nodes + have (at least) two children or none at all, and \end{enumerate} ]] @@ -99,14 +102,15 @@ example -------------------------------------------------------------------- - + -------------------------------------------------------------------- key "extended animated binary tree layout" summary [[ This algorithm is similar to |animated binary tree layout|, only the option \texttt{missing nodes get space} is executed and the -\texttt{significant sep} is zero. ]] +\texttt{significant sep} is zero. +]] example [[ diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua index dc1e8ab571c..15df9990f8e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/experimental/evolving/layered.lua @@ -23,7 +23,7 @@ local lib = require "pgf.gd.lib" local Storage = require "pgf.gd.lib.Storage" local layered = require "pgf.gd.layered" --- +-- -- This file defines some basic functions to compute and/or set the -- ideal distances between nodes of any kind of layered drawing of a -- graph. @@ -35,7 +35,7 @@ local layered = require "pgf.gd.layered" -- -- @param layers A |Storage| object assigning layers to vertices. -- @param paddings A |Storage| object storing the computed distances --- (paddings). +-- (paddings). -- @param graph The graph in which the nodes reside -- @param snapshots The list of snapshots over which the overlaying evolving -- graph exists @@ -56,47 +56,47 @@ function temporallayered.arrange_layers_by_baselines (layers, paddings, graph, s end if count_layers > 0 then - - + + -- Now compute ideal distances and store local height = 0 - + for _, s in ipairs(snapshots) do local layer_vertices = snapshots_layers[s] if #layer_vertices > 0 then -- sanity check - for _,v in ipairs(layer_vertices[1]) do - v.pos.y = 0 - end + for _,v in ipairs(layer_vertices[1]) do + v.pos.y = 0 + end end end - + for i=2, count_layers do local distance = 0 for _, s in ipairs(snapshots) do - local layer_vertices = snapshots_layers[s] - if #layer_vertices >= i then - distance = math.max( - distance, - layered.baseline_distance( - paddings, - s, - layer_vertices[i-1], - layer_vertices[i])) - end + local layer_vertices = snapshots_layers[s] + if #layer_vertices >= i then + distance = math.max( + distance, + layered.baseline_distance( + paddings, + s, + layer_vertices[i-1], + layer_vertices[i])) + end end - + height = height + distance - + for _, s in ipairs(snapshots) do - local layer_vertices = snapshots_layers[s] - if #layer_vertices >= i then - for _,v in ipairs(layer_vertices[i]) do - v.pos.y = height - end - end + local layer_vertices = snapshots_layers[s] + if #layer_vertices >= i then + for _,v in ipairs(layer_vertices[i]) do + v.pos.y = height + end + end end end - end + end end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua index 6cd46c60eb2..a4e51dfeff9 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/CoarseGraph.lua @@ -12,7 +12,7 @@ --- A class for handling "coarse" versions of a graph. Such versions contain --- less nodes and edges than the original graph while retaining the overall +-- less nodes and edges than the original graph while retaining the overall -- structure. local Graph = require "pgf.gd.deprecated.Graph" -- we subclass from here @@ -43,12 +43,12 @@ CoarseGraph.COARSEN_HYBRID = 2 --- Creates a new coarse graph derived from an existing graph. -- --- Generates a coarse graph for the input |Graph|. +-- Generates a coarse graph for the input |Graph|. -- --- Coarsening describes the process of reducing the amount of nodes in a graph --- by merging nodes into supernodes. There are different strategies, called --- schemes, that can be applied, like merging nodes that belong to edges in a --- maximal independent edge set or by creating supernodes based on a maximal +-- Coarsening describes the process of reducing the amount of nodes in a graph +-- by merging nodes into supernodes. There are different strategies, called +-- schemes, that can be applied, like merging nodes that belong to edges in a +-- maximal independent edge set or by creating supernodes based on a maximal -- independent node set. -- -- Coarsening is not performed automatically. The functions |CoarseGraph:coarsen| @@ -57,28 +57,28 @@ CoarseGraph.COARSEN_HYBRID = 2 -- the coarser version of the graph). -- -- Note, however, that the input \meta{graph} is always modified in-place, so --- if the original version of \meta{graph} is needed in parallel to its --- coarse representations, a deep copy of \meta{grpah} needs to be passed over +-- if the original version of \meta{graph} is needed in parallel to its +-- coarse representations, a deep copy of \meta{graph} needs to be passed over -- to |CoarseGraph.new|. -- -- @param graph An existing graph that needs to be coarsened. -- @param scheme Coarsening scheme to use. Possible values are:\par --- |CoarseGraph.COARSEN_INDEPENDENT_EDGES|: +-- |CoarseGraph.COARSEN_INDEPENDENT_EDGES|: -- Coarsen the input graph by computing a maximal independent edge set -- and collapsing edges from this set. The resulting coarse graph has -- at least 50% of the nodes of the input graph. This coarsening scheme --- gives slightly better results than +-- gives slightly better results than -- |CoarseGraph.COARSEN_INDEPENDENT_NODES| because it is less aggressive. -- However, this comes at higher computational cost.\par -- |CoarseGraph.COARSEN_INDEPENDENT_NODES|: -- Coarsen the input graph by computing a maximal independent node set, -- making nodes from this set supernodes in the coarse graph, merging --- adjacent nodes into the supernodes and connecting the supernodes --- if their grpah distance is no greater than three. This scheme gives +-- adjacent nodes into the supernodes and connecting the supernodes +-- if their graph distance is no greater than three. This scheme gives -- slightly worse results than |CoarseGraph.COARSEN_INDEPENDENT_EDGES| -- but is computationally more efficient.\par -- |CoarseGraph.COARSEN_HYBRID|: Combines the other schemes by starting --- with |CoarseGraph.COARSEN_INDEPENDENT_EDGES| and switching to +-- with |CoarseGraph.COARSEN_INDEPENDENT_EDGES| and switching to -- |CoarseGraph.COARSEN_INDEPENDENT_NODES| as soon as the first scheme -- does not reduce the amount of nodes by a factor of 25%. -- @@ -114,14 +114,14 @@ end local function pairs_by_sorted_keys (t, f) - local a = {} - for n in pairs(t) do a[#a + 1] = n end - table.sort (a, f) - local i = 0 - return function () - i = i + 1 - return a[i], t[a[i]] - end + local a = {} + for n in pairs(t) do a[#a + 1] = n end + table.sort (a, f) + local i = 0 + return function () + i = i + 1 + return a[i], t[a[i]] + end end @@ -153,33 +153,33 @@ function CoarseGraph:coarsen() -- add the supernode to the graph self.graph:addNode(supernode) - -- collact all neighbours of the nodes to merge, create a node -> edge mapping + -- collect all neighbors of the nodes to merge, create a node -> edge mapping local u_neighbours = lib.map(u.edges, function(edge) return edge, edge:getNeighbour(u) end) local v_neighbours = lib.map(v.edges, function(edge) return edge, edge:getNeighbour(v) end) - -- remove the two nodes themselves from the neighbour lists + -- remove the two nodes themselves from the neighbor lists u_neighbours = lib.map(u_neighbours, function (edge,node) if node ~= v then return edge,node end end) v_neighbours = lib.map(v_neighbours, function (edge,node) if node ~= u then return edge,node end end) - -- compute a list of neighbours u and v have in common + -- compute a list of neighbors u and v have in common local common_neighbours = lib.map(u_neighbours, - function (edge,node) - if v_neighbours[node] ~= nil then return edge,node end - end) + function (edge,node) + if v_neighbours[node] ~= nil then return edge,node end + end) - -- create a node -> edges mapping for common neighbours + -- create a node -> edges mapping for common neighbors common_neighbours = lib.map(common_neighbours, function (edge, node) return { edge, v_neighbours[node] }, node end) - -- drop common edges from the neighbour mappings + -- drop common edges from the neighbor mappings u_neighbours = lib.map(u_neighbours, function (val,node) if not common_neighbours[node] then return val,node end end) v_neighbours = lib.map(v_neighbours, function (val,node) if not common_neighbours[node] then return val,node end end) - -- merge neighbour lists + -- merge neighbor lists local disjoint_neighbours = custom_merge(u_neighbours, v_neighbours) - -- create edges between the supernode and the neighbours of the merged nodes + -- create edges between the supernode and the neighbors of the merged nodes for neighbour, edge in pairs_by_sorted_keys(disjoint_neighbours, function (n,m) return n.index < m.index end) do -- create a superedge to replace the existing one @@ -190,11 +190,11 @@ function CoarseGraph:coarsen() level = self.level, } - -- add the supernode and the neighbour to the edge + -- add the supernode and the neighbor to the edge if u_neighbours[neighbour] then superedge:addNode(neighbour) superedge:addNode(supernode) - + else superedge:addNode(supernode) superedge:addNode(neighbour) @@ -206,14 +206,14 @@ function CoarseGraph:coarsen() self.graph:deleteEdge(edge) end - -- do the same for all neighbours that the merged nodes have + -- do the same for all neighbors that the merged nodes have -- in common, except that the weights of the new edges are the - -- sums of the of the weights of the edges to the common neighbours + -- sums of the of the weights of the edges to the common neighbors for neighbour, edges in pairs_by_sorted_keys(common_neighbours, function (n,m) return n.index < m.index end) do local weights = 0 - for _,e in ipairs(edges) do - weights = weights + edge.weight - end + for _,e in ipairs(edges) do + weights = weights + edge.weight + end local superedge = Edge.new{ direction = Edge.UNDIRECTED, @@ -222,7 +222,7 @@ function CoarseGraph:coarsen() level = self.level, } - -- add the supernode and the neighbour to the edge + -- add the supernode and the neighbor to the edge superedge:addNode(supernode) superedge:addNode(neighbour) @@ -253,7 +253,7 @@ function CoarseGraph:revertSuperedge(superedge) -- TODO we can probably skip adding edges that have one or more -- subedges with the same level. But that needs more testing. - -- TODO we might have to pass the corresponding supernode to + -- TODO we might have to pass the corresponding supernode to -- this method so that we can move subnodes to the same -- position, right? Interpolating seems to work fine without -- though... @@ -345,14 +345,14 @@ function CoarseGraph:interpolate() self.graph:deleteNode(supernode) end end - + -- Make sure that the nodes and edges are in the correct order: table.sort (self.graph.nodes, function (a, b) return a.index < b.index end) table.sort (self.graph.edges, function (a, b) return a.index < b.index end) for _, n in pairs(self.graph.nodes) do table.sort (n.edges, function (a, b) return a.index < b.index end) end - + -- update the level self.level = self.level - 1 end @@ -396,22 +396,22 @@ function CoarseGraph:findMaximalMatching() -- mark the node as matched matched_nodes[node] = true - -- filter out edges adjacent to neighbours already matched + -- filter out edges adjacent to neighbors already matched local edges = lib.imap(node.edges, - function (edge) - if not matched_nodes[edge:getNeighbour(node)] then return edge end - end) + function (edge) + if not matched_nodes[edge:getNeighbour(node)] then return edge end + end) -- FIXME TODO We use a light-vertex matching here. This is -- different from the algorithm proposed by Hu which collapses -- edges based on a heavy-edge matching... if #edges > 0 then - -- sort edges by the weights of the node's neighbours + -- sort edges by the weights of the node's neighbors table.sort(edges, function (a, b) return a:getNeighbour(node).weight < b:getNeighbour(node).weight end) - -- match the node against the neighbour with minimum weight + -- match the node against the neighbor with minimum weight matched_nodes[edges[1]:getNeighbour(node)] = true table.insert(matching, edges[1]) end @@ -432,4 +432,4 @@ end -- done -return CoarseGraph
\ No newline at end of file +return CoarseGraph diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua index 17cd121b85e..d69d5fc6c9c 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlCoarsening.lua @@ -28,48 +28,48 @@ declare { type = "boolean", initial = "true", - summary = [[" - Defines whether or not a multilevel approach is used that - iteratively coarsens the input graph into graphs $G_1,\dots,G_l$ - with a smaller and smaller number of nodes. The coarsening stops as - soon as a minimum number of nodes is reached, as set via the - |minimum coarsening size| option, or if, in the last iteration, the - number of nodes was not reduced by at least the ratio specified via - |downsize ratio|. + summary = [[" + Defines whether or not a multilevel approach is used that + iteratively coarsens the input graph into graphs $G_1,\dots,G_l$ + with a smaller and smaller number of nodes. The coarsening stops as + soon as a minimum number of nodes is reached, as set via the + |minimum coarsening size| option, or if, in the last iteration, the + number of nodes was not reduced by at least the ratio specified via + |downsize ratio|. "]], documentation = [[" - A random initial layout is computed for the coarsest graph $G_l$ first. - Afterwards, it is laid out by computing the attractive and repulsive - forces between its nodes. - - In the subsequent steps, the previous coarse graph $G_{l-1}$ is - restored and its node positions are interpolated from the nodes - in~$G_l$. The graph $G_{l-1}$ is again laid out by computing the forces - between its nodes. These steps are repeated with $G_{l-2},\dots,G_1$ until - the original input graph $G_0$ has been restored, interpolated - and laid out. - - The idea behind this approach is that, by arranging recursively - formed supernodes first and then interpolating and arranging their - subnodes step by step, the algorithm is less likely to settle in a - local energy minimum (of which there can be many, particularly for - large graphs). The quality of the drawings with coarsening enabled is - expected to be higher than graphics where this feature is not applied. - - The following example demonstrates how coarsening can improve the - quality of graph drawings generated with Walshaw's algorihtm - |spring electrical layout'|. - "]], + A random initial layout is computed for the coarsest graph $G_l$ first. + Afterwards, it is laid out by computing the attractive and repulsive + forces between its nodes. + + In the subsequent steps, the previous coarse graph $G_{l-1}$ is + restored and its node positions are interpolated from the nodes + in~$G_l$. The graph $G_{l-1}$ is again laid out by computing the forces + between its nodes. These steps are repeated with $G_{l-2},\dots,G_1$ until + the original input graph $G_0$ has been restored, interpolated + and laid out. + + The idea behind this approach is that, by arranging recursively + formed supernodes first and then interpolating and arranging their + subnodes step by step, the algorithm is less likely to settle in a + local energy minimum (of which there can be many, particularly for + large graphs). The quality of the drawings with coarsening enabled is + expected to be higher than graphics where this feature is not applied. + + The following example demonstrates how coarsening can improve the + quality of graph drawings generated with Walshaw's algorihtm + |spring electrical layout'|. + "]], examples = [[" - \tikz \graph [spring electrical layout', coarsen=false, vertical=3 to 4] - { - { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } - }; - - \tikz \graph [spring electrical layout', coarsen, vertical=3 to 4] - { - { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } - }; + \tikz \graph [spring electrical layout', coarsen=false, vertical=3 to 4] + { + { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } + }; + + \tikz \graph [spring electrical layout', coarsen, vertical=3 to 4] + { + { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } + }; "]] } @@ -80,29 +80,29 @@ declare { type = "number", initial = 2, - summary = [[" - Defines the minimum number of nodes down to which the graph is - coarsened iteratively. The first graph that has a smaller or equal - number of nodes becomes the coarsest graph $G_l$, where $l$ is the - number of coarsening steps. The algorithm proceeds with the steps - described in the documentation of the |coarsen| option. - "]], - documentation = [[" - In the following example the same graph is coarsened down to two - and four nodes, respectively. The layout of the original graph is - interpolated from the random initial layout and is not improved - further because the forces are not computed (0 iterations). Thus, - in the two graphs, the nodes are placed at exactly two and four - coordinates in the final drawing. - "]], + summary = [[" + Defines the minimum number of nodes down to which the graph is + coarsened iteratively. The first graph that has a smaller or equal + number of nodes becomes the coarsest graph $G_l$, where $l$ is the + number of coarsening steps. The algorithm proceeds with the steps + described in the documentation of the |coarsen| option. + "]], + documentation = [[" + In the following example the same graph is coarsened down to two + and four nodes, respectively. The layout of the original graph is + interpolated from the random initial layout and is not improved + further because the forces are not computed (0 iterations). Thus, + in the two graphs, the nodes are placed at exactly two and four + coordinates in the final drawing. + "]], examples = [[" - \tikz \graph [spring layout, iterations=0, - minimum coarsening size=2] - { subgraph C_n [n=8] }; - - \tikz \graph [spring layout, iterations=0, - minimum coarsening size=4] - { subgraph C_n [n=8] }; + \tikz \graph [spring layout, iterations=0, + minimum coarsening size=2] + { subgraph C_n [n=8] }; + + \tikz \graph [spring layout, iterations=0, + minimum coarsening size=4] + { subgraph C_n [n=8] }; "]] } @@ -113,36 +113,36 @@ declare { type = "number", initial = "0.25", - summary = [[" - Minimum ratio between 0 and 1 by which the number of nodes between - two coarse graphs $G_i$ and $G_{i+1}$ need to be reduced in order for - the coarsening to stop and for the algorithm to use $G_{i+1}$ as the - coarsest graph $G_l$. Aside from the input graph, the optimal value - of |downsize ratio| mostly depends on the coarsening scheme being - used. Possible schemes are |collapse independent edges| and - |connect independent nodes|. - "]], - documentation = [[" - Increasing this option possibly reduces the number of coarse - graphs computed during the coarsening phase as coarsening will stop as - soon as a coarse graph does not reduce the number of nodes - substantially. This may speed up the algorithm but if the size of the - coarsest graph $G_l$ is much larger than |minimum coarsening size|, the - multilevel approach may not produce drawings as good as with a lower - |downsize ratio|. - "]], + summary = [[" + Minimum ratio between 0 and 1 by which the number of nodes between + two coarse graphs $G_i$ and $G_{i+1}$ need to be reduced in order for + the coarsening to stop and for the algorithm to use $G_{i+1}$ as the + coarsest graph $G_l$. Aside from the input graph, the optimal value + of |downsize ratio| mostly depends on the coarsening scheme being + used. Possible schemes are |collapse independent edges| and + |connect independent nodes|. + "]], + documentation = [[" + Increasing this option possibly reduces the number of coarse + graphs computed during the coarsening phase as coarsening will stop as + soon as a coarse graph does not reduce the number of nodes + substantially. This may speed up the algorithm but if the size of the + coarsest graph $G_l$ is much larger than |minimum coarsening size|, the + multilevel approach may not produce drawings as good as with a lower + |downsize ratio|. + "]], examples = [[" - % 1. ratio too high, coarsening stops early, benefits are lost - \tikz \graph [spring electrical layout', - downsize ratio=1.0, - node distance=7mm, vertical=3 to 4] - { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; - - % 2. ratio set to default, coarsening benefits are visible - \tikz \graph [spring electrical layout', - downsize ratio=0.2, - node distance=7mm, vertical=3 to 4] - { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + % 1. ratio too high, coarsening stops early, benefits are lost + \tikz \graph [spring electrical layout', + downsize ratio=1.0, + node distance=7mm, vertical=3 to 4] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + + % 2. ratio set to default, coarsening benefits are visible + \tikz \graph [spring electrical layout', + downsize ratio=0.2, + node distance=7mm, vertical=3 to 4] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; "]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua index 6d80fff6aa6..af209d2c78b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlDeclare.lua @@ -19,7 +19,7 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- -- All force-based algorithms are based on -- a general pattern which we detail in the following. Numerous options --- can be used to influence the behaviour of this general pattern; more +-- can be used to influence the behavior of this general pattern; more -- specific options that apply only to individual algorithms are -- explained along with these algorithms. -- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlElectric.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlElectric.lua index 7bd118d7b85..47e3cee45da 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlElectric.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlElectric.lua @@ -29,29 +29,26 @@ declare { type = "number", initial = 1, - summary = [[" - Defines the electric charge of the node. The stronger the - |electric charge| of a node the stronger the repulsion between the - node and others in the graph. A negative |electric charge| means that - other nodes are further attracted to the node rather than repulsed, - although in theory this effect strongly depends on how the - |spring electrical layout| algorithm works. - Two typcal effects of increasing the |electric charge| are distortion - of symmetries and an upscaling of the drawings. + summary = [[" + Defines the electric charge of the node. The stronger the + |electric charge| of a node the stronger the repulsion between the + node and others in the graph. A negative |electric charge| means that + other nodes are further attracted to the node rather than repulsed, + although in theory this effect strongly depends on how the + |spring electrical layout| algorithm works. + Two typical effects of increasing the |electric charge| are distortion + of symmetries and an upscaling of the drawings. "]], - examples = { - [[" - \tikz \graph [spring electrical layout, horizontal=0 to 1] - { 0 [electric charge=1] -- subgraph C_n [n=10] }; - "]], - [[" - \tikz \graph [spring electrical layout, horizontal=0 to 1] - { 0 [electric charge=5] -- subgraph C_n [n=10] }; - "]], - [[" - \tikz \graph [spring electrical layout, horizontal=0 to 1] - { [clique] 1 [electric charge=5], 2, 3, 4 }; - "]] + examples = {[[" + \tikz \graph [spring electrical layout, horizontal=0 to 1] + { 0 [electric charge=1] -- subgraph C_n [n=10] }; + "]],[[" + \tikz \graph [spring electrical layout, horizontal=0 to 1] + { 0 [electric charge=5] -- subgraph C_n [n=10] }; + "]],[[" + \tikz \graph [spring electrical layout, horizontal=0 to 1] + { [clique] 1 [electric charge=5], 2, 3, 4 }; + "]] } } @@ -63,16 +60,16 @@ declare { type = "number", initial = "1", - summary = [[" - Sometimes, when drawing symmetric and mesh-like graphs, the - peripheral distortion caused by long-range electric forces may be - undesired. Some electric force models allow to reduce long-range - forces and distortion effects by increasing - the order (epxonent) of electric forces. Values between 0 and 1 - increase long-range electric forces and the scaling of the - generated layouts. Value greater than 1 decrease long-range - electric forces and results in shrinking drawings. - "]] + summary = [[" + Sometimes, when drawing symmetric and mesh-like graphs, the + peripheral distortion caused by long-range electric forces may be + undesired. Some electric force models allow to reduce long-range + forces and distortion effects by increasing + the order (exponent) of electric forces. Values between 0 and 1 + increase long-range electric forces and the scaling of the + generated layouts. Value greater than 1 decrease long-range + electric forces and results in shrinking drawings. + "]] } @@ -82,19 +79,19 @@ declare { key = "approximate remote forces", type = "boolean", - summary = [[" - Force based algorithms often need to compute a force for each pair - of vertices, which, for larger numbers of vertices, can lead to a - significant time overhead. This problem can be addressed by - approximating these forces: For a vertex far removed from a cluster - of vertices, instead of computing the force contribution of each - vertex of the cluster indiviually, we form a sort of - ``supervertex'' at the ``gravitational center'' of the cluster and - then compute only the force between this supervertex and the single - vertex. - - \emph{Remark:} Currently, the implementation seems to be broken, at - least the results are somewhat strange when this key is used. - "]] + summary = [[" + Force based algorithms often need to compute a force for each pair + of vertices, which, for larger numbers of vertices, can lead to a + significant time overhead. This problem can be addressed by + approximating these forces: For a vertex far removed from a cluster + of vertices, instead of computing the force contribution of each + vertex of the cluster individually, we form a sort of + ``supervertex'' at the ``gravitational center'' of the cluster and + then compute only the force between this supervertex and the single + vertex. + + \emph{Remark:} Currently, the implementation seems to be broken, at + least the results are somewhat strange when this key is used. + "]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlIteration.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlIteration.lua index b845d9d1f89..b8d96630cdf 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlIteration.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlIteration.lua @@ -30,38 +30,34 @@ declare { type = "number", initial = "500", - summary = [[" - Limits the number of iterations of algorithms for force-based - layouts to \meta{number}. - "]], - documentation = [[" - Depending on the characteristics of the input graph and the parameters - chosen for the algorithm, minimizing the system energy may require - many iterations. - - In these situations it may come in handy to limit the number of - iterations. This feature can also be useful to draw the same graph - after different iterations and thereby demonstrate how the spring or - spring-electrical algorithm improves the drawing step by step. - - The examples shows two drawings generated using two - different |iteration| limits. + summary = [[" + Limits the number of iterations of algorithms for force-based + layouts to \meta{number}. "]], - examples = { - [[" - \tikz \graph [spring layout, iterations=10] { subgraph K_n [n=4] }; - "]], - [[" - \tikz \graph [spring layout, iterations=500] { subgraph K_n [n=4] }; - "]], - [[" - \tikz \graph [spring electrical layout, iterations=10] - { subgraph K_n [n=4] }; - "]], - [[" - \tikz \graph [spring electrical layout, iterations=500] - { subgraph K_n [n=4] }; - "]] + documentation = [[" + Depending on the characteristics of the input graph and the parameters + chosen for the algorithm, minimizing the system energy may require + many iterations. + + In these situations it may come in handy to limit the number of + iterations. This feature can also be useful to draw the same graph + after different iterations and thereby demonstrate how the spring or + spring-electrical algorithm improves the drawing step by step. + + The examples shows two drawings generated using two + different |iteration| limits. + "]], + examples = {[[" + \tikz \graph [spring layout, iterations=10] { subgraph K_n [n=4] }; + "]],[[" + \tikz \graph [spring layout, iterations=500] { subgraph K_n [n=4] }; + "]],[[" + \tikz \graph [spring electrical layout, iterations=10] + { subgraph K_n [n=4] }; + "]],[[" + \tikz \graph [spring electrical layout, iterations=500] + { subgraph K_n [n=4] }; + "]] } } @@ -72,11 +68,11 @@ declare { type = "length", initial = "0", - summary = [[" - This parameter specifies the amount by which nodes will be - displaced in each iteration, initially. If set to |0| (which is the - default), an appropriate value is computed automatically. - "]] + summary = [[" + This parameter specifies the amount by which nodes will be + displaced in each iteration, initially. If set to |0| (which is the + default), an appropriate value is computed automatically. + "]] } --- @@ -86,30 +82,28 @@ declare { type = "number", initial = "0.95", - summary = [[" - This parameter helps in controlling how layouts evolve over - time. It is used to gradually reduce the step size - between one iteration to the next. + summary = [[" + This parameter helps in controlling how layouts evolve over + time. It is used to gradually reduce the step size + between one iteration to the next. "]], documentation = [[" - A small positive cooling factor - $\ge 0$ means that the movement of nodes is quickly or abruptly - reduced, while a large cooling factor $\le 1$ allows for a smoother - step by step layout refinement at the cost of more iterations. The - following example demonstrates how a smaller cooling factor may - result in a less balanced drawing. By default, Hu2006 spring, - Hu2006 spring electrical, and Walshaw2000 spring electrical use a - cooling factor of |0.95|. + A small positive cooling factor + $\ge 0$ means that the movement of nodes is quickly or abruptly + reduced, while a large cooling factor $\le 1$ allows for a smoother + step by step layout refinement at the cost of more iterations. The + following example demonstrates how a smaller cooling factor may + result in a less balanced drawing. By default, Hu2006 spring, + Hu2006 spring electrical, and Walshaw2000 spring electrical use a + cooling factor of |0.95|. "]], - examples = { - [[" - \tikz \graph [spring layout, cooling factor=0.1] - { a -> b -> c -> a }; - "]], - [[" - \tikz \graph [spring layout, cooling factor=0.5] - { a -> b -> c -> a }; - "]] + examples = {[[" + \tikz \graph [spring layout, cooling factor=0.1] + { a -> b -> c -> a }; + "]],[[" + \tikz \graph [spring layout, cooling factor=0.5] + { a -> b -> c -> a }; + "]] } } @@ -120,21 +114,19 @@ declare { type = "number", initial = "0.01", - summary = [[" - All spring and spring-electrical algorithms implemented in the - thesis terminate as soon as the maximum movement of any node drops - below $k \cdot \meta{tolerance}$. This tolerance factor can be changed - with the convergence tolerance option: + summary = [[" + All spring and spring-electrical algorithms implemented in the + thesis terminate as soon as the maximum movement of any node drops + below $k \cdot \meta{tolerance}$. This tolerance factor can be changed + with the convergence tolerance option: "]], - examples = { - [[" - \tikz \graph [spring layout, convergence tolerance=0.001] - { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; - "]], - [[" - \tikz \graph [spring layout, convergence tolerance=1.0] - { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; - "]] + examples = {[[" + \tikz \graph [spring layout, convergence tolerance=0.001] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + "]],[[" + \tikz \graph [spring layout, convergence tolerance=1.0] + { { [clique] 1, 2 } -- 3 -- 4 -- { 5, 6, 7 } }; + "]] } } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlSprings.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlSprings.lua index 9252f7b1cb8..45b9c9ef55e 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlSprings.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlSprings.lua @@ -21,15 +21,17 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- length'', which can be configured using the general-purpose -- |node distance| parameter. It is the ``equilibrium length'' of a -- spring between two nodes in the graph. When an edge has this --- lenght, no forces will ``push'' or ``pull'' along the edge. +-- length, no forces will ``push'' or ``pull'' along the edge. -- -- The following examples shows how a simple graph can be scaled by -- changing the |node distance|: +-- % -- \begin{codeexample}[] -- \tikz \graph [spring layout, node distance=7mm] { subgraph C_n[n=3] }; -- \tikz \graph [spring layout] { subgraph C_n[n=3] }; -- \tikz \graph [spring layout, node distance=15mm]{ subgraph C_n[n=3] }; -- \end{codeexample} +-- % -- \begin{codeexample}[] -- \tikz \graph [spring electrical layout, node distance=0.7cm] { subgraph C_n[n=3] }; -- \tikz \graph [spring electrical layout] { subgraph C_n[n=3] }; @@ -47,12 +49,12 @@ declare { type = "number", initial = "0.01", - summary = [[" - The ``spring constant'' is a factor from Hooke's law describing the - ``stiffness'' of a spring. This factor is used inside spring-based - algorithms to determine how strongly edges ``pull'' and ``push'' at - the nodes they connect. - "]] - } + summary = [[" + The ``spring constant'' is a factor from Hooke's law describing the + ``stiffness'' of a spring. This factor is used inside spring-based + algorithms to determine how strongly edges ``pull'' and ``push'' at + the nodes they connect. + "]] +} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlStart.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlStart.lua index b62be10c0a5..269b81a3d7c 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlStart.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/ControlStart.lua @@ -22,12 +22,13 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- Currently, the start configuration for force-based algorithms is a -- random distribution of the vertices. You can influence it by -- changing the |random seed|: --- +-- % --\begin{codeexample}[] --\tikz \graph [random seed=10, spring layout] { -- a -- {b, c, d} -- e -- f -- {g,h} -- {a,b,e}; --}; --\end{codeexample} +-- % --\begin{codeexample}[] --\tikz \graph [random seed=11, spring layout] { -- a -- {b, c, d} -- e -- f -- {g,h} -- {a,b,e}; @@ -35,6 +36,6 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare --\end{codeexample} -- -- Other methods, like a planar preembedding, are not implemented --- currently. +-- currently. -- -- @end
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/QuadTree.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/QuadTree.lua index 4e511746bb2..3e1620dc21f 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/QuadTree.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/QuadTree.lua @@ -14,12 +14,12 @@ --- An implementation of a quad trees. -- -- The class QuadTree provides methods form handling quadtrees. --- +-- local QuadTree = { - -- Subclases + -- Subclasses Particle = {}, - Cell = {} + Cell = {} } QuadTree.__index = QuadTree @@ -45,7 +45,7 @@ end ---- Inserts a particle +--- Inserts a particle -- -- @param param A particle of type QuadTree.Particle -- @@ -76,7 +76,7 @@ end ---- Partical subclass +--- Particle subclass QuadTree.Particle.__index = QuadTree.Particle @@ -176,7 +176,7 @@ function QuadTree.Cell:insert(particle) if #self.subcells == 0 then self:createSubcells() end - + -- move particles to the new subcells for _,existing in ipairs(self.particles) do local cell = self:findSubcell(existing) @@ -210,7 +210,7 @@ function QuadTree.Cell:updateMass() for _,particle in ipairs(self.particles) do self.mass = self.mass + particle.mass for _,subparticle in ipairs(particle.subparticles) do - self.mass = self.mass + subparticle.mass + self.mass = self.mass + subparticle.mass end end else @@ -226,27 +226,27 @@ end function QuadTree.Cell:updateCenterOfMass() -- reset center of mass, assuming the cell is empty self.center_of_mass = nil - + if #self.subcells == 0 then -- the center of mass is the average position of the particles -- weighted by their masses self.center_of_mass = Vector.new (2) for _,p in ipairs(self.particles) do for _,sp in ipairs(p.subparticles) do - self.center_of_mass = self.center_of_mass:plus(sp.pos:timesScalar(sp.mass)) + self.center_of_mass = self.center_of_mass:plus(sp.pos:timesScalar(sp.mass)) end self.center_of_mass = self.center_of_mass:plus(p.pos:timesScalar(p.mass)) end self.center_of_mass = self.center_of_mass:dividedByScalar(self.mass) else - -- the center of mass is the average of the weighted centers of mass + -- the center of mass is the average of the weighted centers of mass -- of the subcells self.center_of_mass = Vector.new(2) for _,sc in ipairs(self.subcells) do if sc.center_of_mass then - self.center_of_mass = self.center_of_mass:plus(sc.center_of_mass:timesScalar(sc.mass)) + self.center_of_mass = self.center_of_mass:plus(sc.center_of_mass:timesScalar(sc.mass)) else - assert(sc.mass == 0) + assert(sc.mass == 0) end end self.center_of_mass = self.center_of_mass:dividedByScalar(self.mass) @@ -268,7 +268,7 @@ end function QuadTree.Cell:__tostring() return '((' .. self.x .. ', ' .. self.y .. ') ' - .. 'to (' .. self.x + self.width .. ', ' .. self.y + self.height .. '))' + .. 'to (' .. self.x + self.width .. ', ' .. self.y + self.height .. '))' .. (self.particle and ' => ' .. self.particle.name or '') .. (self.center_of_mass and ' mass ' .. self.mass .. ' at ' .. tostring(self.center_of_mass) or '') end @@ -277,4 +277,4 @@ end -- done -return QuadTree
\ No newline at end of file +return QuadTree diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua index 9fa709a8053..a7230eb1f6d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalHu2006.lua @@ -23,7 +23,7 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare declare { key = "spring electrical Hu 2006 layout", algorithm = SpringElectricalHu2006, - + preconditions = { connected = true, loop_free = true, @@ -32,20 +32,20 @@ declare { old_graph_model = true, - summary = [[" - Implementation of a spring electrical graph drawing algorithm based on - a paper by Hu. - "]], - documentation = [[" - \begin{itemize} - \item - Y. Hu. - \newblock Efficient, high-quality force-directed graph drawing. - \newblock \emph{The Mathematica Journal}, 2006. - \end{itemize} - - There are some modifications compared to the original algorithm, - see the Diploma thesis of Pohlmann for details. + summary = [[" + Implementation of a spring electrical graph drawing algorithm based on + a paper by Hu. + "]], + documentation = [[" + \begin{itemize} + \item + Y. Hu. + \newblock Efficient, high-quality force-directed graph drawing. + \newblock \emph{The Mathematica Journal}, 2006. + \end{itemize} + + There are some modifications compared to the original algorithm, + see the Diploma thesis of Pohlmann for details. "]] } @@ -64,7 +64,7 @@ function SpringElectricalHu2006:run() -- Setup properties local options = self.digraph.options - + self.iterations = options['iterations'] self.cooling_factor = options['cooling factor'] self.initial_step_length = options['initial step length'] @@ -75,11 +75,11 @@ function SpringElectricalHu2006:run() self.approximate_repulsive_forces = options['approximate remote forces'] self.repulsive_force_order = options['electric force order'] - + self.coarsen = options['coarsen'] self.downsize_ratio = options['downsize ratio'] self.minimum_graph_size = options['minimum coarsening size'] - + -- Adjust types self.downsize_ratio = math.max(0, math.min(1, self.downsize_ratio)) self.graph_size = #self.graph.nodes @@ -103,24 +103,24 @@ function SpringElectricalHu2006:run() node.weight = 1 end end - + -- initialize edge weights for _,edge in ipairs(self.graph.edges) do edge.weight = 1 end -- initialize the coarse graph data structure. note that the algorithm - -- is the same regardless whether coarsening is used, except that the + -- is the same regardless whether coarsening is used, except that the -- number of coarsening steps without coarsening is 0 local coarse_graph = CoarseGraph.new(self.graph) -- check if the multilevel approach should be used if self.coarsen then - -- coarsen the graph repeatedly until only minimum_graph_size nodes - -- are left or until the size of the coarse graph was not reduced by + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by -- at least the downsize ratio configured by the user - while coarse_graph:getSize() > self.minimum_graph_size - and coarse_graph:getRatio() <= (1 - self.downsize_ratio) + while coarse_graph:getSize() > self.minimum_graph_size + and coarse_graph:getRatio() <= (1 - self.downsize_ratio) do coarse_graph:coarsen() end @@ -188,8 +188,8 @@ end function SpringElectricalHu2006:computeInitialLayout(graph, spring_length) - -- TODO how can supernodes and fixed nodes go hand in hand? - -- maybe fix the supernode if at least one of its subnodes is + -- TODO how can supernodes and fixed nodes go hand in hand? + -- maybe fix the supernode if at least one of its subnodes is -- fixated? -- fixate all nodes that have a 'desired at' option. this will set the @@ -204,7 +204,7 @@ function SpringElectricalHu2006:computeInitialLayout(graph, spring_length) if not graph.nodes[1].fixed and not graph.nodes[2].fixed then -- both nodes can be moved, so we assume node 1 is fixed at (0,0) graph.nodes[1].pos.x = 0 - graph.nodes[1].pos.y = 0 + graph.nodes[1].pos.y = 0 end -- position the loose node relative to the fixed node, with @@ -220,7 +220,7 @@ function SpringElectricalHu2006:computeInitialLayout(graph, spring_length) else -- use a random positioning technique - local function positioning_func(n) + local function positioning_func(n) local radius = 3 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 return lib.random(-radius, radius) end @@ -228,8 +228,8 @@ function SpringElectricalHu2006:computeInitialLayout(graph, spring_length) -- compute initial layout based on the random positioning technique for _,node in ipairs(graph.nodes) do if not node.fixed then - node.pos.x = positioning_func(1) - node.pos.y = positioning_func(2) + node.pos.x = positioning_func(1) + node.pos.y = positioning_func(2) end end end @@ -268,7 +268,7 @@ function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_up -- adjust the initial step length automatically if desired by the user local step_length = self.initial_step_length == 0 and spring_length or self.initial_step_length - + -- convergence criteria etc. local converged = false local energy = math.huge @@ -293,6 +293,114 @@ function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_up for _,v in ipairs(graph.nodes) do if not v.fixed then + -- vector for the displacement of v + local d = Vector.new(2) + + -- compute repulsive forces + if self.approximate_repulsive_forces then + -- determine the cells that have a repulsive influence on v + local cells = quadtree:findInteractionCells(v, barnes_hut_criterion) + + -- compute the repulsive force between these cells and v + for _,cell in ipairs(cells) do + -- check if the cell is a leaf + if #cell.subcells == 0 then + -- compute the forces between the node and all particles in the cell + for _,particle in ipairs(cell.particles) do + local real_particles = lib.copy(particle.subparticles) + table.insert(real_particles, particle) + + for _,real_particle in ipairs(real_particles) do + local delta = real_particle.pos:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), real_particle.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + -- compute the distance between the node and the cell's center of mass + local delta = cell.center_of_mass:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), cell.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + for _,u in ipairs(graph.nodes) do + if v ~= u then + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = accurate_repulsive_force(delta:norm(), u.weight) + local force = delta:normalized():timesScalar(repulsive_force) + + -- move the node v accordingly + d = d:plus(force) + end + end + end + + -- compute attractive forces between v and its neighbors + for _,edge in ipairs(v.edges) do + local u = edge:getNeighbour(v) + + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the spring force vector between u and v + local attr_force = attractive_force(delta:norm()) + local force = delta:normalized():timesScalar(attr_force) + + -- move the node v accordingly + d = d:plus(force) + end + + -- really move the node now + -- TODO note how all nodes are moved by the same amount (step_length) + -- while Walshaw multiplies the normalized force with min(step_length, + -- d:norm()). could that improve this algorithm even further? + v.pos = v.pos:plus(d:normalized():timesScalar(step_length)) + + -- TODO Hu doesn't mention this but the energy of a particle is + -- typically considered as the product of its mass and the square of + -- its forces. This means we should probably take the weight of + -- the node v into the equation, doesn't it? + -- + -- update the energy function + energy = energy + math.pow(d:norm(), 2) -- vector for the displacement of v local d = Vector.new(2) @@ -316,7 +424,7 @@ function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_up -- enforce a small virtual distance if the node and the cell's -- center of mass are located at (almost) the same position if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) end -- compute the repulsive force vector @@ -334,7 +442,7 @@ function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_up -- enforce a small virtual distance if the node and the cell's -- center of mass are located at (almost) the same position if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) end -- compute the repulsive force vector @@ -354,7 +462,7 @@ function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_up -- enforce a small virtual distance if the nodes are -- located at (almost) the same position if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) end -- compute the repulsive force vector @@ -377,7 +485,7 @@ function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_up -- enforce a small virtual distance if the nodes are -- located at (almost) the same position if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) end -- compute the spring force vector between u and v @@ -413,9 +521,9 @@ function SpringElectricalHu2006:computeForceLayout(graph, spring_length, step_up local delta = x.pos:minus(old_positions[x]) max_movement = math.max(delta:norm(), max_movement) end - - -- the algorithm will converge if the maximum movement is below a - -- threshold depending on the spring length and the convergence + + -- the algorithm will converge if the maximum movement is below a + -- threshold depending on the spring length and the convergence -- tolerance if max_movement < spring_length * self.convergence_tolerance then converged = true @@ -472,7 +580,7 @@ function SpringElectricalHu2006:buildQuadtree(graph) -- larger than the minimum position if min_pos:equals(max_pos) then max_pos = max_pos:plus(Vector.new(2, function (n) - return 0.1 + math.random() * 0.1 + return 0.1 + lib.random() * 0.1 end)) end @@ -484,8 +592,8 @@ function SpringElectricalHu2006:buildQuadtree(graph) -- create the quadtree quadtree = QuadTree.new(min_pos.x, min_pos.y, - max_pos.x - min_pos.x, - max_pos.y - min_pos.y) + max_pos.x - min_pos.x, + max_pos.y - min_pos.y) -- insert nodes into the quadtree for _,node in ipairs(graph.nodes) do diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua index df7dc70a745..6ab74fc3676 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalLayouts.lua @@ -30,11 +30,11 @@ declare { { key = "spring constant", value = "0.2" } }, - summary = [[" - This key selects Hu's 2006 spring electrical layout with - appropriate settings for some parameters. - "]] - } + summary = [[" + This key selects Hu's 2006 spring electrical layout with + appropriate settings for some parameters. + "]] +} --- @@ -47,8 +47,8 @@ declare { { key = "convergence tolerance", value = "0.001" }, }, - summary = [[" - This key selects Walshaw's 2000 spring electrical layout with - appropriate settings for some parameters. - "]] - } + summary = [[" + This key selects Walshaw's 2000 spring electrical layout with + appropriate settings for some parameters. + "]] +} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua index 02fd09a72d9..5f7978da4eb 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringElectricalWalshaw2000.lua @@ -26,7 +26,7 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare declare { key = "spring electrical Walshaw 2000 layout", algorithm = SpringElectricalWalshaw2000, - + preconditions = { connected = true, loop_free = true, @@ -35,42 +35,42 @@ declare { old_graph_model = true, - summary = [[" - Implementation of a spring electrical graph drawing algorithm based on - a paper by Walshaw. - "]], - documentation = [[" - \begin{itemize} - \item - C. Walshaw. - \newblock A multilevel algorithm for force-directed graph - drawing. - \newblock In J. Marks, editor, \emph{Graph Drawing}, Lecture Notes in - Computer Science, 1984:31--55, 2001. - \end{itemize} - - The following modifications compared to the original algorithm were applied: - \begin{itemize} - \item An iteration limit was added. - \item The natural spring length for all coarse graphs is computed based - on the formula presented by Walshaw, so that the natural spring - length of the original graph (coarse graph 0) is the same as - the value requested by the user. - \item Users can define custom node and edge weights. - \item Coarsening stops when $|V(G_i+1)|/|V(G_i)| < p$ where $p = 0.75$. - \item Coarsening stops when the maximal matching is empty. - \item Theruntime of the algorithm is improved by use of a quadtree - data structure like Hu does in his algorithm. - \item A limiting the number of levels of the quadtree is not implemented. - \end{itemize} + summary = [[" + Implementation of a spring electrical graph drawing algorithm based on + a paper by Walshaw. + "]], + documentation = [[" + \begin{itemize} + \item + C. Walshaw. + \newblock A multilevel algorithm for force-directed graph drawing. + \newblock In J. Marks, editor, \emph{Graph Drawing}, Lecture Notes in + Computer Science, 1984:31--55, 2001. + \end{itemize} + + The following modifications compared to the original algorithm were applied: + % + \begin{itemize} + \item An iteration limit was added. + \item The natural spring length for all coarse graphs is computed based + on the formula presented by Walshaw, so that the natural spring + length of the original graph (coarse graph 0) is the same as + the value requested by the user. + \item Users can define custom node and edge weights. + \item Coarsening stops when $|V(G_i+1)|/|V(G_i)| < p$ where $p = 0.75$. + \item Coarsening stops when the maximal matching is empty. + \item The runtime of the algorithm is improved by use of a quadtree + data structure like Hu does in his algorithm. + \item A limiting the number of levels of the quadtree is not implemented. + \end{itemize} "]] } - + -- TODO Implement the following keys (or whatever seems appropriate -- and doable for this algorithm): -- - /tikz/desired at -- - /tikz/influence cutoff distance --- - /tikz/spring stiffness (could this be the equivalent to the electric +-- - /tikz/spring stiffness (could this be the equivalent to the electric -- charge of nodes? -- - /tikz/natural spring dimension per edge -- @@ -91,10 +91,10 @@ local lib = require "pgf.gd.lib" function SpringElectricalWalshaw2000:run() - + -- Setup parameters local options = self.digraph.options - + self.iterations = options['iterations'] self.cooling_factor = options['cooling factor'] self.initial_step_length = options['initial step length'] @@ -105,7 +105,7 @@ function SpringElectricalWalshaw2000:run() self.approximate_repulsive_forces = options['approximate remote forces'] self.repulsive_force_order = options['electric force order'] - + self.coarsen = options['coarsen'] self.downsize_ratio = options['downsize ratio'] self.minimum_graph_size = options['minimum coarsening size'] @@ -133,7 +133,7 @@ function SpringElectricalWalshaw2000:run() node.weight = 1 end - -- a node is charged if its weight derives from the default setting + -- a node is charged if its weight derives from the default setting -- of 1 (where it has no influence on the forces) node.charged = node.weight ~= 1 end @@ -142,17 +142,17 @@ function SpringElectricalWalshaw2000:run() for _,edge in ipairs(self.graph.edges) do edge.weight = 1 end - - + + -- initialize the coarse graph data structure. note that the algorithm - -- is the same regardless whether coarsening is used, except that the + -- is the same regardless whether coarsening is used, except that the -- number of coarsening steps without coarsening is 0 local coarse_graph = CoarseGraph.new(self.graph) -- check if the multilevel approach should be used if self.coarsen then - -- coarsen the graph repeatedly until only minimum_graph_size nodes - -- are left or until the size of the coarse graph was not reduced by + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by -- at least the downsize ratio configured by the user while coarse_graph:getSize() > self.minimum_graph_size and coarse_graph:getRatio() < (1 - self.downsize_ratio) @@ -162,7 +162,7 @@ function SpringElectricalWalshaw2000:run() end -- compute the natural spring length for the coarsest graph in a way - -- that will result in the desired natural spring length in the + -- that will result in the desired natural spring length in the -- original graph local spring_length = self.natural_spring_length / math.pow(math.sqrt(4/7), coarse_graph:getLevel()) @@ -186,17 +186,17 @@ function SpringElectricalWalshaw2000:run() else -- generate a random initial layout for the coarsest graph self:computeInitialLayout(coarse_graph.graph, spring_length) - + -- apply the force-based algorithm to improve the layout self:computeForceLayout(coarse_graph.graph, spring_length) - end + end end function SpringElectricalWalshaw2000:computeInitialLayout(graph, spring_length) - -- TODO how can supernodes and fixed nodes go hand in hand? - -- maybe fix the supernode if at least one of its subnodes is + -- TODO how can supernodes and fixed nodes go hand in hand? + -- maybe fix the supernode if at least one of its subnodes is -- fixated? -- fixate all nodes that have a 'desired at' option. this will set the @@ -237,8 +237,8 @@ function SpringElectricalWalshaw2000:computeInitialLayout(graph, spring_length) -- compute initial layout based on the random positioning technique for _,node in ipairs(graph.nodes) do if not node.fixed then - node.pos.x = positioning_func(1) - node.pos.y = positioning_func(2) + node.pos.x = positioning_func(1) + node.pos.y = positioning_func(2) end end end @@ -248,9 +248,9 @@ end function SpringElectricalWalshaw2000:computeForceLayout(graph, spring_length) -- global (=repulsive) force function - local function accurate_repulsive_force(distance, weight) + local function accurate_repulsive_force(distance, weight) return - self.spring_constant * weight * math.pow(spring_length, self.repulsive_force_order + 1) / math.pow(distance, self.repulsive_force_order) - end + end -- global (=repulsive, approximated) force function local function approximated_repulsive_force(distance, mass) @@ -258,8 +258,8 @@ function SpringElectricalWalshaw2000:computeForceLayout(graph, spring_length) end -- local (spring) force function - local function attractive_force(distance, d, weight, charged, repulsive_force) - -- for charged nodes, never subtract the repulsive force; we want ALL other + local function attractive_force(distance, d, weight, charged, repulsive_force) + -- for charged nodes, never subtract the repulsive force; we want ALL other -- nodes to be attracted more / repulsed less (not just non-adjacent ones), -- depending on the charge of course if charged then @@ -285,9 +285,9 @@ function SpringElectricalWalshaw2000:computeForceLayout(graph, spring_length) -- convergence criteria local converged = false local i = 0 - + while not converged and i < self.iterations do - + -- assume that we are converging converged = true i = i + 1 @@ -303,137 +303,137 @@ function SpringElectricalWalshaw2000:computeForceLayout(graph, spring_length) -- iterate over all nodes for _,v in ipairs(graph.nodes) do if not v.fixed then - -- vector for the displacement of v - local d = Vector.new(2) - - -- repulsive force induced by other nodes - local repulsive_forces = {} - - -- compute repulsive forces - if self.approximate_repulsive_forces then - -- determine the cells that have an repulsive influence on v - local cells = quadtree:findInteractionCells(v, barnes_hut_criterion) - - -- compute the repulsive force between these cells and v - for _,cell in ipairs(cells) do - -- check if the cell is a leaf - if #cell.subcells == 0 then - -- compute the forces between the node and all particles in the cell - for _,particle in ipairs(cell.particles) do - -- build a table that contains the particle plus all its subparticles - -- (particles at the same position) - local real_particles = lib.copy(particle.subparticles) - table.insert(real_particles, particle) - - for _,real_particle in ipairs(real_particles) do - local delta = real_particle.pos:minus(v.pos) - - -- enforce a small virtual distance if the node and the cell's - -- center of mass are located at (almost) the same position - if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) - end - - -- compute the repulsive force vector - local repulsive_force = approximated_repulsive_force(delta:norm(), real_particle.mass) - local force = delta:normalized():timesScalar(repulsive_force) - - -- remember the repulsive force for the particle so that we can - -- subtract it later when computing the attractive forces with - -- adjacent nodes - repulsive_forces[real_particle.node] = repulsive_force - - -- move the node v accordingly - d = d:plus(force) - end - end - else - -- compute the distance between the node and the cell's center of mass - local delta = cell.center_of_mass:minus(v.pos) - - -- enforce a small virtual distance if the node and the cell's - -- center of mass are located at (almost) the same position - if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) - end - - -- compute the repulsive force vector - local repulsive_force = approximated_repulsive_force(delta:norm(), cell.mass) - local force = delta:normalized():timesScalar(repulsive_force) - - -- TODO for each neighbour of v, check if it is in this cell. - -- if this is the case, compute the quadtree force for the mass - -- 'node.weight / cell.mass' and remember this as the repulsive - -- force of the neighbour; (it is not necessarily at - -- the center of mass of the cell, so the result is only an - -- approximation of the real repulsive force generated by the - -- neighbour) - - -- move te node v accordingly - d = d:plus(force) - end - end - else - for _,u in ipairs(graph.nodes) do - if u.name ~= v.name then - -- compute the distance between u and v - local delta = u.pos:minus(v.pos) - - -- enforce a small virtual distance if the nodes are - -- located at (almost) the same position - if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) - end - - -- compute the repulsive force vector - local repulsive_force = accurate_repulsive_force(delta:norm(), u.weight) - local force = delta:normalized():timesScalar(repulsive_force) - - -- remember the repulsive force so we can later subtract them - -- when computing the attractive forces - repulsive_forces[u] = repulsive_force - - -- move the node v accordingly - d = d:plus(force) - end - end - end - - -- compute attractive forces between v and its neighbours - for _,edge in ipairs(v.edges) do - local u = edge:getNeighbour(v) - - -- compute the distance between u and v - local delta = u.pos:minus(v.pos) - - -- enforce a small virtual distance if the nodes are - -- located at (almost) the same position - if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) - end - - -- compute the spring force between them - local attr_force = attractive_force(delta:norm(), #v.edges, u.weight, u.charged, repulsive_forces[u]) - local force = delta:normalized():timesScalar(attr_force) - - -- move the node v accordingly - d = d:plus(force) - end - - -- remember the previous position of v - old_position = v.pos:copy() - - if d:norm() > 0 then - -- reposition v according to the force vector and the current temperature - v.pos = v.pos:plus(d:normalized():timesScalar(math.min(step_length, d:norm()))) - end - - -- we need to improve the system energy as long as any of - -- the node movements is large enough to assume we're far - -- away from the minimum system energy - if v.pos:minus(old_position):norm() > spring_length * self.convergence_tolerance then - converged = false - end + -- vector for the displacement of v + local d = Vector.new(2) + + -- repulsive force induced by other nodes + local repulsive_forces = {} + + -- compute repulsive forces + if self.approximate_repulsive_forces then + -- determine the cells that have an repulsive influence on v + local cells = quadtree:findInteractionCells(v, barnes_hut_criterion) + + -- compute the repulsive force between these cells and v + for _,cell in ipairs(cells) do + -- check if the cell is a leaf + if #cell.subcells == 0 then + -- compute the forces between the node and all particles in the cell + for _,particle in ipairs(cell.particles) do + -- build a table that contains the particle plus all its subparticles + -- (particles at the same position) + local real_particles = lib.copy(particle.subparticles) + table.insert(real_particles, particle) + + for _,real_particle in ipairs(real_particles) do + local delta = real_particle.pos:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), real_particle.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- remember the repulsive force for the particle so that we can + -- subtract it later when computing the attractive forces with + -- adjacent nodes + repulsive_forces[real_particle.node] = repulsive_force + + -- move the node v accordingly + d = d:plus(force) + end + end + else + -- compute the distance between the node and the cell's center of mass + local delta = cell.center_of_mass:minus(v.pos) + + -- enforce a small virtual distance if the node and the cell's + -- center of mass are located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = approximated_repulsive_force(delta:norm(), cell.mass) + local force = delta:normalized():timesScalar(repulsive_force) + + -- TODO for each neighbor of v, check if it is in this cell. + -- if this is the case, compute the quadtree force for the mass + -- 'node.weight / cell.mass' and remember this as the repulsive + -- force of the neighbor; (it is not necessarily at + -- the center of mass of the cell, so the result is only an + -- approximation of the real repulsive force generated by the + -- neighbor) + + -- move the node v accordingly + d = d:plus(force) + end + end + else + for _,u in ipairs(graph.nodes) do + if u.name ~= v.name then + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the repulsive force vector + local repulsive_force = accurate_repulsive_force(delta:norm(), u.weight) + local force = delta:normalized():timesScalar(repulsive_force) + + -- remember the repulsive force so we can later subtract them + -- when computing the attractive forces + repulsive_forces[u] = repulsive_force + + -- move the node v accordingly + d = d:plus(force) + end + end + end + + -- compute attractive forces between v and its neighbors + for _,edge in ipairs(v.edges) do + local u = edge:getNeighbour(v) + + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + -- compute the spring force between them + local attr_force = attractive_force(delta:norm(), #v.edges, u.weight, u.charged, repulsive_forces[u]) + local force = delta:normalized():timesScalar(attr_force) + + -- move the node v accordingly + d = d:plus(force) + end + + -- remember the previous position of v + old_position = v.pos:copy() + + if d:norm() > 0 then + -- reposition v according to the force vector and the current temperature + v.pos = v.pos:plus(d:normalized():timesScalar(math.min(step_length, d:norm()))) + end + + -- we need to improve the system energy as long as any of + -- the node movements is large enough to assume we're far + -- away from the minimum system energy + if v.pos:minus(old_position):norm() > spring_length * self.convergence_tolerance then + converged = false + end end end @@ -488,7 +488,7 @@ function SpringElectricalWalshaw2000:buildQuadtree(graph) -- larger than the minimum position if min_pos:equals(max_pos) then max_pos = max_pos:plus(Vector.new(2, function (n) - return 0.1 + math.random() * 0.1 + return 0.1 + lib.random() * 0.1 end)) end @@ -500,8 +500,8 @@ function SpringElectricalWalshaw2000:buildQuadtree(graph) -- create the quadtree quadtree = QuadTree.new(min_pos.x, min_pos.y, - max_pos.x - min_pos.x, - max_pos.y - min_pos.y) + max_pos.x - min_pos.x, + max_pos.y - min_pos.y) -- insert nodes into the quadtree for _,node in ipairs(graph.nodes) do diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua index b53bc9bff98..51e278b904c 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringHu2006.lua @@ -25,7 +25,7 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare declare { key = "spring Hu 2006 layout", algorithm = SpringHu2006, - + preconditions = { connected = true, loop_free = true, @@ -34,20 +34,20 @@ declare { old_graph_model = true, - summary = [[" - Implementation of a spring graph drawing algorithm based on - a paper by Hu. - "]], - documentation = [[" - \begin{itemize} - \item - Y. Hu. - \newblock Efficient, high-quality force-directed graph drawing. - \newblock \emph{The Mathematica Journal}, 2006. - \end{itemize} - - There are some modifications compared to the original algorithm, - see the Diploma thesis of Pohlmann for details. + summary = [[" + Implementation of a spring graph drawing algorithm based on + a paper by Hu. + "]], + documentation = [[" + \begin{itemize} + \item + Y. Hu. + \newblock Efficient, high-quality force-directed graph drawing. + \newblock \emph{The Mathematica Journal}, 2006. + \end{itemize} + + There are some modifications compared to the original algorithm, + see the Diploma thesis of Pohlmann for details. "]] } @@ -65,26 +65,26 @@ local lib = require("pgf.gd.lib") function SpringHu2006:run() - + -- Setup some parameters local options = self.digraph.options - + self.iterations = options['iterations'] self.cooling_factor = options['cooling factor'] self.initial_step_length = options['initial step length'] self.convergence_tolerance = options['convergence tolerance'] self.natural_spring_length = options['node distance'] - + self.coarsen = options['coarsen'] self.downsize_ratio = options['downsize ratio'] self.minimum_graph_size = options['minimum coarsening size'] -- Setup - + self.downsize_ratio = math.max(0, math.min(1, tonumber(self.downsize_ratio))) - + self.graph_size = #self.graph.nodes self.graph_density = (2 * #self.graph.edges) / (#self.graph.nodes * (#self.graph.nodes - 1)) @@ -96,7 +96,7 @@ function SpringHu2006:run() assert(self.natural_spring_length >= 0, 'the natural spring dimension (value: ' .. self.natural_spring_length .. ') needs to be greater than or equal to 0') assert(self.downsize_ratio >= 0 and self.downsize_ratio <= 1, 'the downsize ratio (value: ' .. self.downsize_ratio .. ') needs to be between 0 and 1') assert(self.minimum_graph_size >= 2, 'the minimum coarsening size of coarse graphs (value: ' .. self.minimum_graph_size .. ') needs to be greater than or equal to 2') - + -- initialize node weights for _,node in ipairs(self.graph.nodes) do node.weight = 1 @@ -106,20 +106,20 @@ function SpringHu2006:run() for _,edge in ipairs(self.graph.edges) do edge.weight = 1 end - - + + -- initialize the coarse graph data structure. note that the algorithm - -- is the same regardless whether coarsening is used, except that the + -- is the same regardless whether coarsening is used, except that the -- number of coarsening steps without coarsening is 0 local coarse_graph = CoarseGraph.new(self.graph) -- check if the multilevel approach should be used if self.coarsen then - -- coarsen the graph repeatedly until only minimum_graph_size nodes - -- are left or until the size of the coarse graph was not reduced by + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by -- at least the downsize ratio configured by the user - while coarse_graph:getSize() > self.minimum_graph_size - and coarse_graph:getRatio() <= (1 - self.downsize_ratio) + while coarse_graph:getSize() > self.minimum_graph_size + and coarse_graph:getRatio() <= (1 - self.downsize_ratio) do coarse_graph:coarsen() end @@ -192,8 +192,8 @@ end function SpringHu2006:computeInitialLayout(graph, spring_length) - -- TODO how can supernodes and fixed nodes go hand in hand? - -- maybe fix the supernode if at least one of its subnodes is + -- TODO how can supernodes and fixed nodes go hand in hand? + -- maybe fix the supernode if at least one of its subnodes is -- fixated? -- fixate all nodes that have a 'desired at' option. this will set the @@ -208,7 +208,7 @@ function SpringHu2006:computeInitialLayout(graph, spring_length) if not graph.nodes[1].fixed and not graph.nodes[2].fixed then -- both nodes can be moved, so we assume node 1 is fixed at (0,0) graph.nodes[1].pos.x = 0 - graph.nodes[1].pos.y = 0 + graph.nodes[1].pos.y = 0 end -- position the loose node relative to the fixed node, with @@ -223,16 +223,16 @@ function SpringHu2006:computeInitialLayout(graph, spring_length) end else -- use a random positioning technique - local function positioning_func(n) + local function positioning_func(n) local radius = 2 * spring_length * self.graph_density * math.sqrt(self.graph_size) / 2 return lib.random(-radius, radius) end -- compute initial layout based on the random positioning technique for _,node in ipairs(graph.nodes) do - if not node.fixed then - node.pos.x = positioning_func(1) - node.pos.y = positioning_func(2) + if not node.fixed then + node.pos.x = positioning_func(1) + node.pos.y = positioning_func(2) end end end @@ -253,7 +253,7 @@ function SpringHu2006:computeForceLayout(graph, spring_length, step_update_func) -- adjust the initial step length automatically if desired by the user local step_length = self.initial_step_length == 0 and spring_length or self.initial_step_length - + -- convergence criteria etc. local converged = false local energy = math.huge @@ -273,6 +273,39 @@ function SpringHu2006:computeForceLayout(graph, spring_length, step_update_func) for _,v in ipairs(graph.nodes) do if not v.fixed then + -- vector for the displacement of v + local d = Vector.new(2) + + for _,u in ipairs(graph.nodes) do + if v ~= u then + -- compute the distance between u and v + local delta = u.pos:minus(v.pos) + + -- enforce a small virtual distance if the nodes are + -- located at (almost) the same position + if delta:norm() < 0.1 then + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) + end + + local graph_distance = (distances[u] and distances[u][v]) and distances[u][v] or #graph.nodes + 1 + + -- compute the repulsive force vector + local force = repulsive_force(delta:norm(), graph_distance, v.weight) + local force = delta:normalized():timesScalar(force) + + -- move the node v accordingly + d = d:plus(force) + end + end + + -- really move the node now + -- TODO note how all nodes are moved by the same amount (step_length) + -- while Walshaw multiplies the normalized force with min(step_length, + -- d:norm()). could that improve this algorithm even further? + v.pos = v.pos:plus(d:normalized():timesScalar(step_length)) + + -- update the energy function + energy = energy + math.pow(d:norm(), 2) -- vector for the displacement of v local d = Vector.new(2) @@ -284,7 +317,7 @@ function SpringHu2006:computeForceLayout(graph, spring_length, step_update_func) -- enforce a small virtual distance if the nodes are -- located at (almost) the same position if delta:norm() < 0.1 then - delta:update(function (n, value) return 0.1 + math.random() * 0.1 end) + delta:update(function (n, value) return 0.1 + lib.random() * 0.1 end) end local graph_distance = (distances[u] and distances[u][v]) and distances[u][v] or #graph.nodes + 1 @@ -318,9 +351,9 @@ function SpringHu2006:computeForceLayout(graph, spring_length, step_update_func) local delta = x.pos:minus(old_positions[x]) max_movement = math.max(delta:norm(), max_movement) end - - -- the algorithm will converge if the maximum movement is below a - -- threshold depending on the spring length and the convergence + + -- the algorithm will converge if the maximum movement is below a + -- threshold depending on the spring length and the convergence -- tolerance if max_movement < spring_length * self.convergence_tolerance then converged = true diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua index 5554410816e..e3ac58d5718 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/SpringLayouts.lua @@ -29,8 +29,8 @@ declare { { key = "spring Hu 2006 layout" }, }, - summary = [[" - This key selects Hu's 2006 spring layout with appropriate settings - for some parameters. - "]] - } + summary = [[" + This key selects Hu's 2006 spring layout with appropriate settings + for some parameters. + "]] +} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua index 6c9677aeabb..2450bba2a20 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/FruchtermanReingold.lua @@ -20,33 +20,39 @@ local Storage = require "pgf.gd.lib.Storage" declare { key = "spring electric no coarsen layout", algorithm = SpringElectricNoCoarsenClass, - preconditions = { connected = true }, + preconditions = { connected = true }, postconditions = {fixed = true}, - summary = [[This layout uses the algorithm proposed by Fruchterman and Reingold to draw graphs."]], - - documentation = - [[The Fruchterman-Reingold algorithm is one if the oldest methods - for force-based graph drawing. It is described in: - \begin{itemize} - \item - Thomas M.~J.~ Fruchterman and Edward M.~ Reingold, - \newblock Graph Drawing by Force-directed Placement, - \newblock \emph{Software -- practice and experience,} - 21(1 1), 1129-1164, 1991. - \end{itemize} - Fruchterman and Reingold had to principles in graph drawing: - \begin{enumerate} - \item Vertices connected by an edge should be drawn close toa another and - \item in general, vertices should not be drawn too close to each other. - \end{itemize} - The spring electric no coarsen layout uses spring forces as attractive - forces influecing vertex pairs connected by an edge and electric forces - as repulsive forces between all vertex pairs. The original algorithm - also contained a frame that stopped the vertices from drifting too far - apart, but this concept was not implemented. This algorithm will not be affected - by coarsening. This layout was implemented - by using the Jedi framework. + summary = [[ + This layout uses the algorithm proposed by Fruchterman and Reingold to draw graphs." + ]], + + documentation = [[ + The Fruchterman-Reingold algorithm is one if the oldest methods + for force-based graph drawing. It is described in: + % + \begin{itemize} + \item + Thomas M.~J.~ Fruchterman and Edward M.~ Reingold, + \newblock Graph Drawing by Force-directed Placement, + \newblock \emph{Software -- practice and experience,} + 21(1 1), 1129-1164, 1991. + \end{itemize} + % + Fruchterman and Reingold had to principles in graph drawing: + % + \begin{enumerate} + \item Vertices connected by an edge should be drawn close to another and + \item in general, vertices should not be drawn too close to each other. + \end{itemize} + % + The spring electric no coarsen layout uses spring forces as attractive + forces influencing vertex pairs connected by an edge and electric forces + as repulsive forces between all vertex pairs. The original algorithm + also contained a frame that stopped the vertices from drifting too far + apart, but this concept was not implemented. This algorithm will not be + affected by coarsening. This layout was implemented by using the Jedi + framework. ]], example = @@ -62,14 +68,14 @@ declare { g -- {h, i, j}, h -- {i, j}, i -- j - }; + }; ]], example = [[ \graph[spring electric no coarsen layout, speed = 0.25, node distance = 0.25cm, horizontal = c to l, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, coarsen = false, maximum step = 1]{ a -> b -> c -> {d1 -> e -> f -> g -> h -> i -> {j1 -> e, j2 -> l}, d2 -> l -> m}, m -> a - }; + }; ]] } @@ -80,7 +86,7 @@ declare { --define a local time function local time_fun_1 -function time_fun_1 (t_total, t_now) +function time_fun_1 (t_total, t_now) if t_now/t_total <= 0.5 then return 0.5 else @@ -112,7 +118,7 @@ function SpringElectricNoCoarsenClass:run() } -- run algorithm - spring_electric_no_coarsen:run() + spring_electric_no_coarsen:run() end return SpringElectricNoCoarsenClass
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua index 08ccad1308f..57cd1547b6c 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/HuSpringElectricalFW.lua @@ -20,29 +20,31 @@ declare { key = "jedi spring electric layout", algorithm = HuClass, documentation_in = "documentation_hu_layout", - preconditions = { connected = true }, + preconditions = { connected = true }, postconditions = {fixed = true}, - summary = "This layout uses the spring electric algorithm proposed by Hu to draw graphs.", + summary = "This layout uses the spring electric algorithm proposed by Hu to draw graphs.", - documentation = - [[The spring electric algorithm by Hu uses two kinds of forces and coarsening. - It is described in: - \begin{itemize} - \item - Yifan Hu, - \newblock Efficient, high quality force-directed graph drawing, - \newblock \emph{The Mathematica Journal,} - 10(1), 37-71, 2006. - \end{itemize} - This algorithm uses spring forces as attractive forces between vertices - connected by an edge and electric forces as repulsive forces between - all vertex pairs. Hu introduces coarsening, a procedure which repeatedly - merges vertices in order to obtain a smaller version of the graph, to - overcome local minima. He also uses the Barnes-Hut algorithm to enhance - the runtime of his algorithms. This algorithm is not used in this - implementation. This layout was implemented by using the Jedi framework. - ]], + documentation = [[ + The spring electric algorithm by Hu uses two kinds of forces and coarsening. + It is described in: + % + \begin{itemize} + \item + Yifan Hu, + \newblock Efficient, high quality force-directed graph drawing, + \newblock \emph{The Mathematica Journal,} + 10(1), 37--71, 2006. + \end{itemize} + % + This algorithm uses spring forces as attractive forces between vertices + connected by an edge and electric forces as repulsive forces between + all vertex pairs. Hu introduces coarsening, a procedure which repeatedly + merges vertices in order to obtain a smaller version of the graph, to + overcome local minima. He also uses the Barnes-Hut algorithm to enhance + the runtime of his algorithms. This algorithm is not used in this + implementation. This layout was implemented by using the Jedi framework. + ]], example = [[ @@ -52,15 +54,15 @@ declare { b -- {c, d, e}, c -- {d, e}, d --e - }; - ]], + }; + ]], example = [[ \tikz \graph[spring electric fw layout, speed = 0.35, node distance = 1cm, horizontal = c to l, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, maximum displacement per step = 10]{ a -> b -> c -> {d1 -> e -> f -> g -> h -> i -> {j1 -> e, j2 -> l}, d2 -> l -> m}, m -> a - }; + }; ]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua index 20a1be5de0e..4dbae2b1f4c 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SimpleSpring.lua @@ -19,35 +19,34 @@ declare { key = "trivial spring layout", algorithm = SimpleSpringClass, documentation_in = "pgf.gd.doc.jedi.algorithms.SimpleSpringLayout", - preconditions = { connected = true }, + preconditions = { connected = true }, postconditions = {fixed = true}, - summary = "This layout uses only spring forces to draw graphs.", + summary = "This layout uses only spring forces to draw graphs.", - documentation = - [[The simple spring algorithm only uses one force kind: A spring force - that serves as both attracitve and repuslive force. The edges are modeled as - springs and act according to Hoke's law: They have an ideal length and will - expand if they are contracted below this length, pushing the adjacent - vertices away from each other, and contract if it is stretched, pulling the - adjacent vertices towards each other. This ideal length is given by the - parameter |node distance|. There is no force repelling vertices that are not - connected to each other, which can lead to vertices being placed at the same - point. It is not a very powerfull layout and will probably fail with large - graphs, especially if they have few edges. It can however be used to - demonstrate the effect of spring forces. This layout was implemented by using - the Jedi framework. - ]], + documentation = [[ + The simple spring algorithm only uses one force kind: A spring force + that serves as both attractive and repulsive force. The edges are modeled as + springs and act according to Hoke's law: They have an ideal length and will + expand if they are contracted below this length, pushing the adjacent + vertices away from each other, and contract if it is stretched, pulling the + adjacent vertices towards each other. This ideal length is given by the + parameter |node distance|. There is no force repelling vertices that are not + connected to each other, which can lead to vertices being placed at the same + point. It is not a very powerful layout and will probably fail with large + graphs, especially if they have few edges. It can however be used to + demonstrate the effect of spring forces. This layout was implemented by using + the Jedi framework. + ]], - example = - [[ - \tikz - \graph[simple spring layout, node distance = 3cm, speed = 2, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, coarsen = true, maximum step = 1]{ - a -- {b, c, d, e}, - b -- {c, d, e}, - c -- {d, e}, - d --e - }; + example = [[ + \tikz + \graph[simple spring layout, node distance = 3cm, speed = 2, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, coarsen = true, maximum step = 1]{ + a -- {b, c, d, e}, + b -- {c, d, e}, + c -- {d, e}, + d --e + }; ]] } @@ -69,7 +68,7 @@ function SimpleSpringClass:run() } -- run algorithm - simple_spring:run() + simple_spring:run() end return SimpleSpringClass
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua index 12e6c02e4bf..1c8a1bb8d91 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityCloseness.lua @@ -24,63 +24,64 @@ declare { algorithm = SocialClass, postconditions = {fixed = true}, - summary = [[This layout uses the social gravity algorithm proposed by Bannister - with closeness mass to draw graphs.]], + summary = [[ + This layout uses the social gravity algorithm proposed by Bannister + with closeness mass to draw graphs. + ]], - documentation = - [[Bannister et all described a social gravity algorithm that can be - implemented with different kinds of gravity. - It is described in: - \begin{itemize} - \item - Michael J.~ Bannister and David Eppstein and Michael T~. Goodrich and - Lowell Trott, - \newblock Force-Directed Graph Drawing Using Social Gravity and Scaling, - \newblock \emph{CoRR,} - abs/1209.0748, 2012. - \end{itemize} - This implementation uses the closeness mass to determine the gravity of each - vertex. There are three forces in this algorithm: A spring force as - attractive force between vertices connected by an edge, an electric force as - repulsive force between all vertex pairs, and a gravitational force pulling - all vertices closer to their midpoint. The gravitational force depends on - the social mass of a vertex, which can be determined in different ways. This - algorithm uses the closeness mass. The closeness of a vertex $u$ is the - reciprocal of the sum of the shortest path from $u$ to every other vertex - $v$. The gravitational force leads to more "important" vertices ending up - closer to the middle of the drawing, since the social mass of a vertex is - proportinal to its importance. The social layouts work especially well on - unconnected graphs like forests. This layout was implemented by using the - Jedi framework. - ]], + documentation = [[ + Bannister et all described a social gravity algorithm that can be + implemented with different kinds of gravity. + It is described in: + % + \begin{itemize} + \item Michael J.~ Bannister and David Eppstein and Michael T~. Goodrich + and Lowell Trott, + \newblock Force-Directed Graph Drawing Using Social Gravity and Scaling, + \newblock \emph{CoRR,} + abs/1209.0748, 2012. + \end{itemize} + % + This implementation uses the closeness mass to determine the gravity of each + vertex. There are three forces in this algorithm: A spring force as + attractive force between vertices connected by an edge, an electric force as + repulsive force between all vertex pairs, and a gravitational force pulling + all vertices closer to their midpoint. The gravitational force depends on + the social mass of a vertex, which can be determined in different ways. This + algorithm uses the closeness mass. The closeness of a vertex $u$ is the + reciprocal of the sum of the shortest path from $u$ to every other vertex + $v$. The gravitational force leads to more "important" vertices ending up + closer to the middle of the drawing, since the social mass of a vertex is + proportional to its importance. The social layouts work especially well on + unconnected graphs like forests. This layout was implemented by using the + Jedi framework. + ]], - example = - [[ - \tikz - \graph[social closeness layout, speed = 0.9, gravity = 0.2, node distance = 0.65cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, find equilibrium = true, maximum step = 5]{ - a -- a1 -- a2 -- a, - b -- b1 -- b2 -- b, - c -- c1 -- c2 -- c, - d -- d1 -- d2 -- d, - e -- e1 -- e2 -- e, - f -- f1 -- f2 -- f, - g -- g1 -- g2 -- g, - h -- h1 -- h2 -- h, - i -- i1 -- i2 -- i, - j -- j1 -- j2 -- j, - a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- a - }; - ]], + example = [[ + \tikz + \graph[social closeness layout, speed = 0.9, gravity = 0.2, node distance = 0.65cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, find equilibrium = true, maximum step = 5]{ + a -- a1 -- a2 -- a, + b -- b1 -- b2 -- b, + c -- c1 -- c2 -- c, + d -- d1 -- d2 -- d, + e -- e1 -- e2 -- e, + f -- f1 -- f2 -- f, + g -- g1 -- g2 -- g, + h -- h1 -- h2 -- h, + i -- i1 -- i2 -- i, + j -- j1 -- j2 -- j, + a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- a + }; + ]], - example = - [[ - \tikz - \graph[social closeness layout, speed = 0.35, node distance = 0.7cm, maximum step = 5, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, radius = 1cm, gravity = 2]{ - a -- {a1 -- a2, a3}, - b -- {b1, b2 -- b3 -- b4 --{b5, b6}}, - c -- {c1--c2}, - d -- {d1, d2, d3 -- {d4, d5}, d6 --{d7, d8}} - }; + example = [[ + \tikz + \graph[social closeness layout, speed = 0.35, node distance = 0.7cm, maximum step = 5, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, radius = 1cm, gravity = 2]{ + a -- {a1 -- a2, a3}, + b -- {b1, b2 -- b3 -- b4 --{b5, b6}}, + c -- {c1--c2}, + d -- {d1, d2, d3 -- {d4, d5}, d6 --{d7, d8}} + }; ]] } @@ -93,7 +94,7 @@ function SocialClass:run() tmp = fw_attributes[vertex] local sum = 0 for i, w in pairs(n) do - sum = sum + w + sum = sum + w end sum = sum / # self.ugraph.vertices tmp.mass = 1/sum @@ -108,21 +109,21 @@ function SocialClass:run() social_gravity:addForce{ force_type = ForceCanvasDistance, fun_u = function (data) return data.k/(data.d*data.d) end, - epoch = {"after expand", "during expand"} + epoch = {"after expand", "during expand"} } social_gravity:addForce{ force_type = ForceCanvasPosition, fun_u = function (data) return data.attributes[data.u].mass*data.attributes.options.gravity end, - epoch = {"after expand", "during expand"} + epoch = {"after expand", "during expand"} } social_gravity:addForce{ force_type = ForceGraphDistance, fun_u = function (data) return -data.d/(data.k*data.k) end, n = 1, - epoch = {"after expand", "during expand"} + epoch = {"after expand", "during expand"} } social_gravity:run() end -return SocialClass
\ No newline at end of file +return SocialClass diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua index 8e94a561871..6408349107b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/algorithms/SocialGravityDegree.lua @@ -23,60 +23,63 @@ declare { algorithm = SocialClass, postconditions = {fixed = true}, - summary = [[This layout uses the social gravity algorithm proposed by Bannister - with closeness mass to draw graphs.]], - - documentation = - [[Bannister et all described a social gravity algorithm that can be - implemented with different kinds of gravity. - It is described in: - \begin{itemize} - \item - Michael J.~ Bannister and David Eppstein and Michael T~. Goodrich and - Lowell Trott, - \newblock Force-Directed Graph Drawing Using Social Gravity and Scaling, - \newblock \emph{CoRR,} - abs/1209.0748, 2012. - \end{itemize} - This implementation uses the degree mass to determine the gravity of each - vertex. There are three forces in this algorithm: A spring force as - attractive force between vertices connected by an edge, an electric force as - repulsive force between all vertex pairs, and a gravitational force pulling - all vertices closer to their midpoint. The gravitational force depends on - the social mass of a vertex, which can be determined in different ways. This - algorithm uses the degree of each vertex as its mass. The gravitational - force leads to more "important" vertices ending up closer to the middle of - the drawing, since the social mass of a vertex is proportinal to its - importance. The social layouts work especially well on unconnected graphs - like forests. This layout was implemented by using the Jedi framework. - ]], + summary = [[ + This layout uses the social gravity algorithm proposed by Bannister + with closeness mass to draw graphs.]], + + documentation = [[ + Bannister et all described a social gravity algorithm that can be + implemented with different kinds of gravity. + It is described in: + % + \begin{itemize} + \item + Michael J.~ Bannister and David Eppstein and Michael T~. Goodrich and + Lowell Trott, + \newblock Force-Directed Graph Drawing Using Social Gravity and Scaling, + \newblock \emph{CoRR,} abs/1209.0748, 2012. + \end{itemize} + % + This implementation uses the degree mass to determine the gravity of each + vertex. There are three forces in this algorithm: A spring force as + attractive force between vertices connected by an edge, an electric force as + repulsive force between all vertex pairs, and a gravitational force pulling + all vertices closer to their midpoint. The gravitational force depends on + the social mass of a vertex, which can be determined in different ways. This + algorithm uses the degree of each vertex as its mass. The gravitational + force leads to more "important" vertices ending up closer to the middle of + the drawing, since the social mass of a vertex is proportional to its + importance. The social layouts work especially well on unconnected graphs + like forests. This layout was implemented by using the Jedi framework. + ]], example = [[ - \graph[social degree layout, speed = 0.9, gravity = 0.2, node distance = 0.65cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, find equilibrium = true, maximum step = 5]{ - a -- a1 -- a2 -- a, - b -- b1 -- b2 -- b, - c -- c1 -- c2 -- c, - d -- d1 -- d2 -- d, - e -- e1 -- e2 -- e, - f -- f1 -- f2 -- f, - g -- g1 -- g2 -- g, - h -- h1 -- h2 -- h, - i -- i1 -- i2 -- i, - j -- j1 -- j2 -- j, - a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- a - }; - ]], + \tikz + \graph[social degree layout, speed = 0.9, gravity = 0.2, node distance = 0.65cm, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, find equilibrium = true, maximum step = 5]{ + a -- a1 -- a2 -- a, + b -- b1 -- b2 -- b, + c -- c1 -- c2 -- c, + d -- d1 -- d2 -- d, + e -- e1 -- e2 -- e, + f -- f1 -- f2 -- f, + g -- g1 -- g2 -- g, + h -- h1 -- h2 -- h, + i -- i1 -- i2 -- i, + j -- j1 -- j2 -- j, + a -- b -- c -- d -- e -- f -- g -- h -- i -- j -- a + }; + ]], example = [[ - \tikz - \graph[social degree layout, speed = 0.35, node distance = 0.7cm, maximum step = 15, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, radius = 1cm, gravity = 0.2]{ - a -- {a1 -- a2, a3}, - b -- {b1, b2 -- b3 -- b4 --{b5, b6}}, - c -- {c1--c2}, - d -- {d1, d2, d3 -- {d4, d5}, d6 --{d7, d8}} - }; + \tikz + \graph[social degree layout, speed = 0.35, node distance = 0.7cm, maximum step = 15, nodes={as=,circle, draw, inner sep=3pt,outer sep=0pt}, radius = 1cm, gravity = 0.2]{ + a -- {a1 -- a2, a3}, + b -- {b1, b2 -- b3 -- b4 --{b5, b6}}, + c -- {c1--c2}, + d -- {d1, d2, d3 -- {d4, d5}, d6 --{d7, d8}} + }; ]] } @@ -85,30 +88,30 @@ declare { key = "gravity", type = "number", initial = 0.2, - + summary = "The gravity key describes the magnitude of the gravitational force.", - documentation = - [[ - This parameter currently only affects the \lstinline{social degree layout} - and the \lstinline{social closeness layout}. The gravity key determines the - strength used to pull the vertices to the center of the canvas. - ]], + documentation = [[ + This parameter currently only affects the \lstinline{social degree layout} + and the \lstinline{social closeness layout}. The gravity key determines the + strength used to pull the vertices to the center of the canvas. + ]], example = [[ - \graph[social degree layout, iterations = 100, maximum time = 100, maximum step = 10]{ - a1[weight = 2] -- {a2, a3, a4, a5}, - b1 -- {b2 -- {b3, b4}, b5} - }; - ]], - - example = - [[ - \graph[social degree layout, iterations = 100, maximum time = 100, gravity = 0.5, maximum step = 10]{ - a1 -- {a2 [mass = 2], a3, a4, a5}, - b1 -- {b2 -- {b3, b4}, b5} - }; + \tikz + \graph[social degree layout, iterations = 100, maximum time = 100, maximum step = 10]{ + a1[weight = 2] -- {a2, a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; + ]], + + example = [[ + \tikz + \graph[social degree layout, iterations = 100, maximum time = 100, gravity = 0.5, maximum step = 10]{ + a1 -- {a2 [mass = 2], a3, a4, a5}, + b1 -- {b2 -- {b3, b4}, b5} + }; ]] } @@ -135,7 +138,7 @@ function time_fun_3 (t_total, t_now) end end --- define table to store variables if needed +-- define table to store variables if needed local fw_attributes = Storage.newTableStorage() function SocialClass:run() @@ -148,7 +151,7 @@ function SocialClass:run() -- add options to storage table fw_attributes.options = self.ugraph.options - + -- generate new force class local social_gravity = ForceController.new(self.ugraph, fw_attributes) @@ -174,7 +177,7 @@ function SocialClass:run() } -- run algorithm - social_gravity:run() + social_gravity:run() end return SocialClass
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua index f33d44e6ae1..04872146547 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/CoarseGraphFW.lua @@ -9,12 +9,12 @@ --- A class for creating and handling "coarse" versions of a graph. Such versions contain --- less nodes and edges than the original graph while retaining the overall --- structure. This class offers functions to create coarse graphs and to expand them --- to regain their original size. +-- less nodes and edges than the original graph while retaining the overall +-- structure. This class offers functions to create coarse graphs and to expand them +-- to regain their original size. -- Imports -local Digraph = require "pgf.gd.model.Digraph" +local Digraph = require "pgf.gd.model.Digraph" local Vertex = require "pgf.gd.model.Vertex" local Arc = require "pgf.gd.model.Arc" @@ -25,26 +25,26 @@ CoarseGraph.__index = CoarseGraph --- Creates a new coarse graph derived from an existing graph. -- --- Generates a coarse graph for the input |Digraph|. +-- Generates a coarse graph for the input |Digraph|. -- --- Coarsening describes the process of reducing the amount of vertices in a graph --- by merging vertices into pseudo-vertices. There are different strategies, --- to decide which vertices should be merged, like merging vertices that belong to edges in a --- maximal independent edge set or by creating pseudo-verties based on a maximal --- independent node set. Those strategies are called --- schemes. +-- Coarsening describes the process of reducing the amount of vertices in a graph +-- by merging vertices into pseudo-vertices. There are different strategies, +-- to decide which vertices should be merged, like merging vertices that belong to edges in a +-- maximal independent edge set or by creating pseudo-vertices based on a maximal +-- independent node set. Those strategies are called +-- schemes. -- -- Coarsening is not performed automatically. The function |CoarseGraph:coarsen| -- can be used to further coarsen the graph, or the function |CoarseGraph:uncoarsen| -- can be used to restore the previous state. -- -- Note, however, that the input \meta{graph} is always modified in-place, so --- if the original version of \meta{graph} is needed in parallel to its --- coarse representations, a deep copy of \meta{grpah} needs to be passed over +-- if the original version of \meta{graph} is needed in parallel to its +-- coarse representations, a deep copy of \meta{graph} needs to be passed over -- to |CoarseGraph.new|. -- -- @param graph An existing graph that needs to be coarsened. --- @param fw_attributes The user defined attributes, possibly attached to vertices. +-- @param fw_attributes The user defined attributes, possibly attached to vertices. function CoarseGraph.new(ugraph, fw_attributes) local coarse_graph = { @@ -62,10 +62,10 @@ end -- locals for performance local find_maximal_matching, arc_function --- This function performs one coarsening step: It finds all independent vertex --- set according to |scheme|, coarsens them and adds the newly created --- vertices to the collapsed_vertices table, associating them with the current --- level. +-- This function performs one coarsening step: It finds all independent vertex +-- set according to |scheme|, coarsens them and adds the newly created +-- vertices to the collapsed_vertices table, associating them with the current +-- level. function CoarseGraph:coarsen() -- update the level self.level = self.level + 1 @@ -87,32 +87,32 @@ function CoarseGraph:coarsen() local collapse_vertices = {a_h, a_t} collapse_vertex = Vertex.new {weight = 0, mass = 0} - ugraph:collapse(collapse_vertices, - collapse_vertex, - function (a,b) - a.weight = a.weight + b.weight - a.mass = a.mass + b.mass - if fw_attributes then - for key,value in pairs(fw_attributes[b]) do - if fw_attributes.functions[key] then - fw_attributes.functions[key](a,b) - elseif type(value) == "number" then - local tmp = fw_attributes[a] - if not tmp[key] then - tmp[key] = 0 - end - tmp[key] = tmp[key] + value - end - end - end - end, - function (a,b) - if a.weight == nil then - a.weight = b.weight - else - a.weight = a.weight + b.weight + ugraph:collapse(collapse_vertices, + collapse_vertex, + function (a,b) + a.weight = a.weight + b.weight + a.mass = a.mass + b.mass + if fw_attributes then + for key,value in pairs(fw_attributes[b]) do + if fw_attributes.functions[key] then + fw_attributes.functions[key](a,b) + elseif type(value) == "number" then + local tmp = fw_attributes[a] + if not tmp[key] then + tmp[key] = 0 end - end) + tmp[key] = tmp[key] + value + end + end + end + end, + function (a,b) + if a.weight == nil then + a.weight = b.weight + else + a.weight = a.weight + b.weight + end + end) local c_v_p = collapse_vertex.pos local a_h_p = a_h.pos @@ -133,19 +133,19 @@ function CoarseGraph:coarsen() self.ratio = #vertices / old_graph_size end --- This function expands all vertices assoicated with the current level, then +-- This function expands all vertices associated with the current level, then -- updates the level. function CoarseGraph:uncoarsen() local a = self.collapsed_vertices[self.level] local ugraph = self.ugraph - local random = math.random - local randomseed = math.randomseed + local random = lib.random + local randomseed = lib.randomseed for j=#a,1,-1 do randomseed(42) local to_expand = a[j] - ugraph:expand(to_expand, function(a,b) + ugraph:expand(to_expand, function(a,b) b.pos.x = a.pos.x + random()*10 b.pos.y = a.pos.y + random()*10 end) @@ -176,13 +176,13 @@ function CoarseGraph:getGraph() return self.ugraph end --- Private helper function to determine whether the second vertex in the +-- Private helper function to determine whether the second vertex in the -- current arc has been matched already -- -- @param arc The arc in question -- @param vertex One of the arc's endpoints, either head or tail -- @param matched_vertices The table holding all matched vertices --- +-- -- @return The arc if the other endpoint has not been matched yet function arc_function (arc, vertex, matched_vertices) local x @@ -191,22 +191,22 @@ function arc_function (arc, vertex, matched_vertices) else x = arc.tail end - if not matched_vertices[x] then - return arc + if not matched_vertices[x] then + return arc end end --- The function finding a maximum matching of independent arcs. +-- The function finding a maximum matching of independent arcs. -- -- @param ugraph The current graph -- --- @return A table of arcs wich are in the matching +-- @return A table of arcs which are in the matching function find_matching(ugraph) local matching = {} local matched_vertices = {} local unmatched_vertices = {} local vertices = ugraph.vertices - + -- iterate over nodes in random order for _,j in ipairs(lib.random_permutation(#vertices)) do local vertex = vertices[j] @@ -240,7 +240,7 @@ function find_matching(ugraph) return x.weight < y.weight end) - -- match the node against the neighbour with minimum weight + -- match the node against the neighbor with minimum weight matched_vertices[arcs[1].head] = true matched_vertices[arcs[1].tail] = true table.insert(matching, arcs[1]) @@ -261,4 +261,4 @@ end -- done -return CoarseGraph
\ No newline at end of file +return CoarseGraph diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua index 1762fcf07eb..ab30ada5b32 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceController.lua @@ -8,26 +8,27 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This class is the most basic class for the Jedi framework. It manages the --- forces, epochs, options and streamlines the graph drawing process. +--- This class is the most basic class for the Jedi framework. It manages the +-- forces, epochs, options and streamlines the graph drawing process. -- In detail, the force template will do the following: +-- % -- \begin{itemize} --- \item Hold the table with all epochs currently defined, and provide --- a function to add new ones --- \item Hold the table associating forces with the epochs, and provide a --- function to add new ones --- \item Define all the non-algorithm-specific options provided by Jedi --- \item Assert user options to catch exceptions --- \item Save user options and library functions to local variables to enchance --- runtime. --- \item Add any forces that are indicated by set options --- \item Find and call the initial positioning algorithm requested --- \item Determine if coarsening is enabled, and manage coarsening process if so --- \item Call the proprocesing function of each force to obtain a vertex list the --- force will be applied to --- \item Calculate the forces affecting each vertex. --- \item Move the vertices, check for equilibria/used up iterations, update --- virtual time +-- \item Hold the table with all epochs currently defined, and provide +-- a function to add new ones +-- \item Hold the table associating forces with the epochs, and provide a +-- function to add new ones +-- \item Define all the non-algorithm-specific options provided by Jedi +-- \item Assert user options to catch exceptions +-- \item Save user options and library functions to local variables to enhance +-- runtime. +-- \item Add any forces that are indicated by set options +-- \item Find and call the initial positioning algorithm requested +-- \item Determine if coarsening is enabled, and manage coarsening process if so +-- \item Call the preprocessing function of each force to obtain a vertex list the +-- force will be applied to +-- \item Calculate the forces affecting each vertex. +-- \item Move the vertices, check for equilibria/used up iterations, update +-- virtual time -- \end{itemize} local ForceController = {} @@ -42,7 +43,7 @@ local ForcePullToPoint = require "pgf.gd.force.jedi.forcetypes.ForcePullToPoint" local ForcePullToGrid = require "pgf.gd.force.jedi.forcetypes.ForcePullToGrid" local epochs = { - [1] = "preprocessing", + [1] = "preprocessing", [2] = "initial layout", [3] = "start coarsening process", [4] = "before coarsen", @@ -59,14 +60,14 @@ local epochs = { } -- Automatic parameter generation for epoch-variables -for _,e in ipairs(epochs) do - --- +for _,e in ipairs(epochs) do + --- declare { key = "iterations " .. e, type = "number" } - --- + --- declare { key = "maximum displacement per step " .. e, type = "number" @@ -115,9 +116,9 @@ end -- @return An integer value matching the epch's index, or $-1$ if epoch was not found function ForceController:findEpoch(epoch) - for j, e in ipairs(epochs) do + for j, e in ipairs(epochs) do if e == epoch then - return j + return j end end return -1 @@ -132,17 +133,17 @@ local sum_up, options, move_vertices, get_net_force, preprocessing, epoch_forces --- Creating a new force algorithm -- @params ugraph The ugraph object the graph drawing algorithm will run on --- @params fw_attributes The storage object holding the additional attributes defined by +-- @params fw_attributes The storage object holding the additional attributes defined by -- the engineer -- -- @returns A new instance of force template function ForceController.new(ugraph, fw_attributes) - return setmetatable( + return setmetatable( {epoch_forces = {}, ugraph = ugraph, fw_attributes = fw_attributes, pull_to_point = false, - }, ForceController) + }, ForceController) end --- Running the force algorithm @@ -178,16 +179,16 @@ function ForceController:run() end -- Initialize epoch_forces table entries as empty tables - for _, e in ipairs(epochs) do + for _, e in ipairs(epochs) do if not self.epoch_forces[e] then self.epoch_forces[e] = {} end end - -- Find inital positioning algorithm + -- Find initial positioning algorithm local initial_positioning_class = options.algorithm_phases['initial positioning force framework'] -- initial_types[self.initial_layout] - -- If snap to grid option is set and no force was added yet, add an extra + -- If snap to grid option is set and no force was added yet, add an extra -- force to post-processing if snap_to_grid then self:addForce{ @@ -211,15 +212,15 @@ function ForceController:run() local end_coarsen = self:findEpoch("end coarsen") local start_expand = self:findEpoch("start expand") local end_expand = self:findEpoch("end expand") - + -- iterate over epoch table local i = 1 - while i <= #epochs do + while i <= #epochs do local e = epochs[i] local iterations = options["iterations "..e] or options["iterations"] - -- assert input + -- assert input assert(iterations >= 0, 'iterations (value: ' .. iterations .. ') needs to be greater than 0') -- Check for desired vertices and collect them in a table if any are found @@ -227,7 +228,7 @@ function ForceController:run() local desired_vertices = {} -- initialize node weights for _,vertex in ipairs(vertices) do - if vertex.options then + if vertex.options then if vertex.options["desired at"] then desired = true desired_vertices[vertex] = vertex.options["desired at"] @@ -235,7 +236,7 @@ function ForceController:run() end end - -- Add pull to point force if desired vertices were found and engineer did not add + -- Add pull to point force if desired vertices were found and engineer did not add -- this force if desired and not self.pull_to_point then self:addForce{ @@ -249,9 +250,9 @@ function ForceController:run() -- vertices = coarse_graph.ugraph.vertices -- arcs = coarse_graph.ugraph.arcs if i >= start_coarsening and i < end_coarsening then - -- coarsen the graph repeatedly until only minimum_graph_size nodes - -- are left or until the size of the coarse graph was not reduced by - -- at least the downsize ratio configured by the user + -- coarsen the graph repeatedly until only minimum_graph_size nodes + -- are left or until the size of the coarse graph was not reduced by + -- at least the downsize ratio configured by the user if i >= start_coarsen and i < start_expand then if coarse_graph:getSize() > minimum_graph_size and coarse_graph:getRatio() <= (1 - downsize_ratio) then if i == start_coarsen then @@ -259,9 +260,9 @@ function ForceController:run() elseif i < end_coarsen then preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) move_vertices(coarse_graph.ugraph.vertices, e) - else + else i = start_coarsen - 1 - end + end end end @@ -271,13 +272,13 @@ function ForceController:run() local spring_length = natural_spring_length if not vertices_initalized then - initial_positioning_class.new { vertices = coarse_graph.ugraph.vertices, - options = options, - desired_vertices = desired_vertices + initial_positioning_class.new { vertices = coarse_graph.ugraph.vertices, + options = options, + desired_vertices = desired_vertices }:run() vertices_initalized = true end - + preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) -- set the spring length to the average arc length of the initial layout @@ -305,9 +306,9 @@ function ForceController:run() elseif i < end_expand then preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) move_vertices(coarse_graph.ugraph.vertices, e) - else + else i = start_expand - 1 - end + end else preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) move_vertices(coarse_graph.ugraph.vertices, e) @@ -317,9 +318,9 @@ function ForceController:run() elseif i < start_coarsening or i > end_coarsening then if not vertices_initalized then initial_positioning_class.new { - vertices = coarse_graph.ugraph.vertices, - options = options, - desired_vertices = desired_vertices }:run() + vertices = coarse_graph.ugraph.vertices, + options = options, + desired_vertices = desired_vertices }:run() vertices_initalized = true end preprocessing(coarse_graph.ugraph.vertices, coarse_graph.ugraph.arcs, e, coarse_graph.ugraph) @@ -330,9 +331,9 @@ function ForceController:run() if i < start_coarsening or i > end_coarsening then if not vertices_initalized then initial_positioning_class.new { - vertices = vertices, - options = options, - desired_vertices = desired_vertices }:run() + vertices = vertices, + options = options, + desired_vertices = desired_vertices }:run() vertices_initalized = true end preprocessing(vertices, arcs, e, ugraph) @@ -348,7 +349,7 @@ end -- -- @params v The vertices of the current graph -- @params a The arcs of the current graph --- @params epoch The preprocessing algorithm will only be applied to the forces +-- @params epoch The preprocessing algorithm will only be applied to the forces -- associated with this epoch. -- @params ugraph The current graph object @@ -359,8 +360,8 @@ function preprocessing(v, a, epoch, ugraph) end ---- Adding forces to the algorithm. --- +--- Adding forces to the algorithm. +-- -- @params force_data A table containing force type, time function, force function, -- capping thresholds and the epochs in which this force will be active @@ -374,7 +375,7 @@ function ForceController:addForce(force_data) if force_data.epoch == nil then force_data.epoch = {} end - for _,e in ipairs(force_data.epoch) do + for _,e in ipairs(force_data.epoch) do local tab = self.epoch_forces[e] if not tab then tab = {} @@ -382,10 +383,10 @@ function ForceController:addForce(force_data) tab[#tab +1] = f self.epoch_forces[e] = tab end -end +end ---- Moving vertices according to force functions until the maximum number of +--- Moving vertices according to force functions until the maximum number of -- iterations is reached -- -- @params vertices The vertices in the current graph @@ -408,16 +409,16 @@ function move_vertices(vertices, epoch, g) local max_time = options["maximum time ".. epoch] or options["maximum time"] local d_t = max_time/iterations local t_now = 0 - local random = math.random - local randomseed = math.randomseed - + local random = lib.random + local randomseed = lib.randomseed + for j = 1 , iterations do t_now = t_now + d_t net_forces = get_net_force(vertices, j, t_now, epoch) - + -- normalize the force vector if necessary for v, c in pairs(net_forces) do - local n = sqrt(c.x*c.x+c.y*c.y) + local n = sqrt(c.x*c.x+c.y*c.y) if n > max_step then local factor = max_step/n c.x = c.x*factor @@ -429,7 +430,7 @@ function move_vertices(vertices, epoch, g) if not find_equilibrium or sum_up(net_forces)*d_t > epsilon then local cool_down_dt = d_t if cool_down_dt > 1 then - cool_down_dt = 1 + 1/d_t + cool_down_dt = 1 + 1/d_t end for _, v in ipairs(vertices) do local factor = 1/(v.mass or 1) @@ -454,9 +455,9 @@ end -- @params t_now The current virtual time -- @params epoch The current epoch -- --- @return A table of coordinate-objects associated with vertices. The --- coordinate object hold the calculated net displacement for --- the $x$ and $y$ coordinate. +-- @return A table of coordinate-objects associated with vertices. The +-- coordinate object hold the calculated net displacement for +-- the $x$ and $y$ coordinate. function get_net_force(vertices, j, t_now, epoch) local net_forces = {} local natural_spring_length = options["node distance"] @@ -464,11 +465,11 @@ function get_net_force(vertices, j, t_now, epoch) for _,v in ipairs(vertices) do net_forces[v] = Coordinate.new(0,0) end - + for _,force_class in ipairs(epoch_forces[epoch]) do force_class:applyTo{net_forces = net_forces, options = options, j = j, t_now = t_now, k = natural_spring_length} end - + return net_forces end @@ -485,4 +486,4 @@ function sum_up(tab) return sum end -return ForceController
\ No newline at end of file +return ForceController diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua index 06b61870ff4..29370fc0297 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/ForceTemplate.lua @@ -8,8 +8,8 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is the parent class for forces. It provides a constructor and methods --- stubs to be overwritten in the subclasses. +--- This is the parent class for forces. It provides a constructor and methods +-- stubs to be overwritten in the subclasses. -- Imports local lib = require "pgf.gd.lib" @@ -33,11 +33,11 @@ function ForceTemplate:preprocess(v) end -- Method stub for applying the forces --- --- @param data A table holding data like the table the forces are collected +-- +-- @param data A table holding data like the table the forces are collected -- in, the current iteration, the current time stamp, some options -- or the natural spring length - + function ForceTemplate:applyTo(data) end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua index ad315e7a660..762717f64a1 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/InitialTemplate.lua @@ -8,11 +8,11 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is the parent class for initial layout algorithms. It provides a --- constructor and methods stubs to be overwritten in the subclasses as well +--- This is the parent class for initial layout algorithms. It provides a +-- constructor and methods stubs to be overwritten in the subclasses as well -- as placing vertices which are |desired at| a certain point. --- Imports +-- Imports local lib = require "pgf.gd.lib" local InitialTemplate = lib.class {} @@ -21,14 +21,14 @@ local InitialTemplate = lib.class {} function InitialTemplate:constructor() self.vertices = self.vertices self.options = self.options - self.desired_vertices = self.desired_vertices + self.desired_vertices = self.desired_vertices end -- Method placing |desired at| vertices at the point they are desired -- --- @params desired_vertices A table containing all the vertices where the +-- @params desired_vertices A table containing all the vertices where the -- |desired at| option is set. --- +-- -- @return |placed| A boolean array stating if vertices have been placed yet -- @return |centroid_x| The x-coordinate of the midpoint of all placed vertices -- @return |centroid_y| The y-coordinate of the midpoint of all placed vertices @@ -37,7 +37,7 @@ function InitialTemplate:desired(desired_vertices) local placed = {} local centroid_x, centroid_y = 0, 0 - + local size = 0 for v, da in pairs(desired_vertices) do local p = v.pos @@ -53,7 +53,7 @@ function InitialTemplate:desired(desired_vertices) centroid_x = centroid_x / size centroid_y = centroid_y / size end - + return placed, centroid_x, centroid_y end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua index cf7cbddc20f..2d50677fa5f 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/PathLengthsFW.lua @@ -7,9 +7,9 @@ -- -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is a helper class providing different functions that deal with graph --- distances. This class can be used by engineers and implementers if they --- need to calculate anything regarding graph distances. +--- This is a helper class providing different functions that deal with graph +-- distances. This class can be used by engineers and implementers if they +-- need to calculate anything regarding graph distances. local PathLengths = {} @@ -17,12 +17,12 @@ local PathLengths = {} local PriorityQueue = require "pgf.gd.lib.PriorityQueue" local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing" --- This algorithm conducts a breadth first search on the graph it is given. --- +-- This algorithm conducts a breadth first search on the graph it is given. +-- -- @param ugraph The graph on which the search should be conducted -- --- @return A table holding every vertex $v$ as key and a table as value. The --- value table holds all other vertices $u$ as keys and their shortest +-- @return A table holding every vertex $v$ as key and a table as value. The +-- value table holds all other vertices $u$ as keys and their shortest -- distance to $v$ as value function PathLengths:breadthFirstSearch(ugraph) @@ -57,12 +57,12 @@ end -- @param ugraph The graph where the paths should be found -- @param source The source vertex -- --- @return |distance| A table holding every vertex $v$ as key and a table as --- value. The value table holds all other vertices $u$ as +-- @return |distance| A table holding every vertex $v$ as key and a table as +-- value. The value table holds all other vertices $u$ as -- keys and their shortest distance to $v$ as value --- @return |levels| A table holding the levels of the graph as keys and a +-- @return |levels| A table holding the levels of the graph as keys and a -- table holding the vertices found on that level as values --- @return |parent| A tbale holding each vertex as key and it's parent vertex +-- @return |parent| A table holding each vertex as key and it's parent vertex -- as value function PathLengths:dijkstra(ugraph, source) @@ -113,13 +113,13 @@ function PathLengths:dijkstra(ugraph, source) return distance, levels, parent end --- This function finds the pseudo diameter of the graph, which is the longest --- shortest path in the graph +-- This function finds the pseudo diameter of the graph, which is the longest +-- shortest path in the graph -- -- @param ugraph The graph who's pseudo diameter is wanted -- -- @ return |diameter| The pseudo diameter of the graph --- @ return |start_node| The start node of the longest shortest path in the +-- @ return |start_node| The start node of the longest shortest path in the -- graph -- @ return |end_node| The end node of the longest shortest path in the graph diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua index 182a1e4fa79..de59e0cb5cc 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/base/Preprocessing.lua @@ -8,10 +8,10 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This file holds functions to create lists of vertex pairs. All --- functions return a Graph object containing the vertices of the --- original graph and an edge between the vertices forming a pair --- under the specified conditions. The lists can be precomouted to +--- This file holds functions to create lists of vertex pairs. All +-- functions return a Graph object containing the vertices of the +-- original graph and an edge between the vertices forming a pair +-- under the specified conditions. The lists can be precomputed to -- enhance performance. local PreprocessClass = {} @@ -21,7 +21,7 @@ local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare local Digraph = require "pgf.gd.model.Digraph" --- Creates a graph object with an arc between all pairwise disjoint vertex +-- Creates a graph object with an arc between all pairwise disjoint vertex -- pairs and returns the arc table -- -- @param vertices The vertices of the original graph @@ -29,94 +29,94 @@ local Digraph = require "pgf.gd.model.Digraph" -- @return An arc table function PreprocessClass.allPairs(vertices) - local aP = Digraph.new{} - for _, vertex in ipairs(vertices) do - for _, vertex2 in ipairs(vertices) do - if vertex ~= vertex2 then - if not aP:contains(vertex) then - aP:add {vertex} - end - if not aP:contains(vertex2) then - aP:add {vertex2} - end - if not aP:arc(vertex, vertex2) and not aP:arc(vertex2, vertex) then - aP:connect(vertex, vertex2) - end - end - end - end - return aP.arcs + local aP = Digraph.new{} + for _, vertex in ipairs(vertices) do + for _, vertex2 in ipairs(vertices) do + if vertex ~= vertex2 then + if not aP:contains(vertex) then + aP:add {vertex} + end + if not aP:contains(vertex2) then + aP:add {vertex2} + end + if not aP:arc(vertex, vertex2) and not aP:arc(vertex2, vertex) then + aP:connect(vertex, vertex2) + end + end + end + end + return aP.arcs end --- Creates a graph object with an arc between all pairwise disjoint vertex --- pairs that are connected by a shortest path of length n in the original +-- Creates a graph object with an arc between all pairwise disjoint vertex +-- pairs that are connected by a shortest path of length n in the original -- graph and returns the arc table -- -- @param vertices The vertices of the original graph -- @param arcs The arcs of the original graph --- @param n The length of the shortest path we are looking for +-- @param n The length of the shortest path we are looking for -- -- @return An arc table function PreprocessClass.overExactlyNPairs(vertices, arcs, n) - local waste, p_full = PreprocessClass.overMaxNPairs(vertices, arcs, n) - local waste, p_small = PreprocessClass.overMaxNPairs(vertices, arcs, n-1) - for _, paar in ipairs(p_full.arcs) do - if p_small:arc(paar.head, paar.tail) ~= nil or p_small:arc(paar.tail, paar.head) ~= nil then - p_full:disconnect(paar.head, paar.tail) - p_full:disconnect(paar.tail, paar.head) - end - end - return p_full.arcs + local waste, p_full = PreprocessClass.overMaxNPairs(vertices, arcs, n) + local waste, p_small = PreprocessClass.overMaxNPairs(vertices, arcs, n-1) + for _, paar in ipairs(p_full.arcs) do + if p_small:arc(paar.head, paar.tail) ~= nil or p_small:arc(paar.tail, paar.head) ~= nil then + p_full:disconnect(paar.head, paar.tail) + p_full:disconnect(paar.tail, paar.head) + end + end + return p_full.arcs end --- Creates a graph object with an arc between all pairwise disjoint vertex --- pairs that are connected by a shortest path of length n or shorter in the +-- Creates a graph object with an arc between all pairwise disjoint vertex +-- pairs that are connected by a shortest path of length n or shorter in the -- original graph and returns the arc table --- +-- -- @param vertices The vertices of the original graph -- @param arcs The arcs of the original graph --- @param n The length of the shortest path we are looking for +-- @param n The length of the shortest path we are looking for -- -- @return An arc table function PreprocessClass.overMaxNPairs(vertices, arcs, n) - assert(n >= 0, 'n (value: ' .. n.. ') needs to be greater or equal 0') - local p = Digraph.new{} - local oneHop = Digraph.new{} - if n> 0 then - for _, arc in ipairs(arcs) do - local vertex = arc.head - local vertex2 = arc.tail - if not p:contains(vertex) then - p:add {vertex} - oneHop:add {vertex} - end - if not p:contains(vertex2) then - p:add {vertex2} - oneHop:add {vertex2} - end - if p:arc(vertex, vertex2) == nil and p:arc(vertex2, vertex) == nil then - p:connect(vertex, vertex2) - oneHop:connect(vertex, vertex2) - end - end - end + assert(n >= 0, 'n (value: ' .. n.. ') needs to be greater or equal 0') + local p = Digraph.new{} + local oneHop = Digraph.new{} + if n> 0 then + for _, arc in ipairs(arcs) do + local vertex = arc.head + local vertex2 = arc.tail + if not p:contains(vertex) then + p:add {vertex} + oneHop:add {vertex} + end + if not p:contains(vertex2) then + p:add {vertex2} + oneHop:add {vertex2} + end + if p:arc(vertex, vertex2) == nil and p:arc(vertex2, vertex) == nil then + p:connect(vertex, vertex2) + oneHop:connect(vertex, vertex2) + end + end + end - n = n-1 - while n > 0 do - for _, paar in ipairs(p.arcs) do - for _, vertex in ipairs(vertices) do - if paar.head ~= vertex and p:arc(paar.head, vertex) == nil and p:arc(vertex, paar.head) == nil and (oneHop:arc(paar.tail, vertex) ~= nil or oneHop:arc(vertex, paar.tail) ~= nil) then - p:connect(paar.head, vertex) - end - end - end - n = n-1 - end - return p.arcs, p + n = n-1 + while n > 0 do + for _, paar in ipairs(p.arcs) do + for _, vertex in ipairs(vertices) do + if paar.head ~= vertex and p:arc(paar.head, vertex) == nil and p:arc(vertex, paar.head) == nil and (oneHop:arc(paar.tail, vertex) ~= nil or oneHop:arc(vertex, paar.tail) ~= nil) then + p:connect(paar.head, vertex) + end + end + end + n = n-1 + end + return p.arcs, p end -return PreprocessClass
\ No newline at end of file +return PreprocessClass diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/doc.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/doc.lua index 620c035d523..19baca73336 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/doc.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/doc.lua @@ -19,17 +19,17 @@ key "maximum step" summary [[ -This option determines the maximum ditance every vertex is allowed to travel -in one iteration. +This option determines the maximum distance every vertex is allowed to travel +in one iteration. ]] documentation [[ -No matter how large the forces influencing a vertex, the effect -on the drawing should be limited to avoid vertices "jumping" from one side of -the canvas to each other due to a strong force pulling them further than their -ideal destination. The amount of space a vertex is allowed to travel in one -iteration is limited by the \lstinline{maximum step} parameter. It is $5000$ +No matter how large the forces influencing a vertex, the effect +on the drawing should be limited to avoid vertices "jumping" from one side of +the canvas to each other due to a strong force pulling them further than their +ideal destination. The amount of space a vertex is allowed to travel in one +iteration is limited by the \lstinline{maximum step} parameter. It is $5000$ by default. That means by default, this parameter should not get in your way. ]] @@ -40,7 +40,7 @@ example \graph[social degree layout, iterations = 2, maximum time = 2, maximum step = 6pt, coarsen = false]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -49,7 +49,7 @@ example \graph[social degree layout, iterations = 2, maximum time = 2, maximum step = 12pt, coarsen = false]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -61,13 +61,15 @@ example key "speed" summary -[[ This is a factor every calculated step is multiplied by.]] +[[ +This is a factor every calculated step is multiplied by. +]] documentation [[ The speed is the distance a vertex travels if it is influenced by a force of -$1$N$\cdot\gamma$. The speed is only a factor that will influence the total -amount every vertex can move: Half the speed makes half the movement, twice +$1$N$\cdot\gamma$. The speed is only a factor that will influence the total +amount every vertex can move: Half the speed makes half the movement, twice the speed doubles the distance traveled. ]] @@ -77,7 +79,7 @@ example \graph[social degree layout, iterations = 1, maximum time = 1, maximum step = 100, speed = 0.2, coarsen = false]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -86,7 +88,7 @@ example \graph[social degree layout, iterations = 1, maximum time= 1, maximum step = 100, speed = 0.4, coarsen = false]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -96,17 +98,19 @@ example key "maximum time" summary -[[ The highest amount of virtual time the algorithm is allowed to take.]] +[[ +The highest amount of virtual time the algorithm is allowed to take. +]] documentation [[ -This option is part of the virtual time construct of Jedi. The virtual time -concept allows graph drawing algorithm engineers to switch forces on and of -after a relative or absolute amount of time has elapsed. If the iterations -stay the same, doubling the maximum time has the same effect as doubling the -speed: Vertices move faster, but it is possible they miss their intended -destination. Also increasing the iterations changes the "resolution" of the -graph drawing algorithm: More steps are simulated in the same time. +This option is part of the virtual time construct of Jedi. The virtual time +concept allows graph drawing algorithm engineers to switch forces on and of +after a relative or absolute amount of time has elapsed. If the iterations +stay the same, doubling the maximum time has the same effect as doubling the +speed: Vertices move faster, but it is possible they miss their intended +destination. Also increasing the iterations changes the "resolution" of the +graph drawing algorithm: More steps are simulated in the same time. ]] example @@ -115,7 +119,7 @@ example \graph[social degree layout, iterations = 20, maximum time = 100, coarsen = false, maximum step = 0.5, gravity = 2]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -124,29 +128,31 @@ example \graph[social degree layout, iterations = 20, maximum time = 200, coarsen = false, maximum step = 0.5, gravity = 2]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- - + -------------------------------------------------------------------- key "find equilibrium" summary -[[ If this option is |true|, the framework checks the vertex movment to detect -low movement near the equilibrium and stop the algorithm]] +[[ +If this option is |true|, the framework checks the vertex movement to detect +low movement near the equilibrium and stop the algorithm. +]] documentation [[ -Since we often do not know how many iterations are enough, the framework will -detect when the vertices (almost) stop moving and stop the algorithm. After -each iteration, the framework adds up the net force influencing all the -vertices. If it falls below the threshold |epsilon|, the algorithm -will ignore the left over iterations and terminate. You can disable this -behavior by setting this parameter to |false|. Allowing the framework to find -the equilibrium usually saves you time, while allowing more iterations (or a - lower threshold) generates higher quality drawings. +Since we often do not know how many iterations are enough, the framework will +detect when the vertices (almost) stop moving and stop the algorithm. After +each iteration, the framework adds up the net force influencing all the +vertices. If it falls below the threshold |epsilon|, the algorithm +will ignore the left over iterations and terminate. You can disable this +behavior by setting this parameter to |false|. Allowing the framework to find +the equilibrium usually saves you time, while allowing more iterations (or a +lower threshold) generates higher quality drawings. ]] example @@ -155,7 +161,7 @@ example \graph[social degree layout, iterations = 300, maximum time = 300, coarsen = false, maximum step = 10, epsilon = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -164,7 +170,7 @@ example \graph[social degree layout, iterations = 300, maximum time = 300, maximum step = 10, find equilibrium = false]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -174,13 +180,15 @@ example key "epsilon" summary -[[ The threshold for the |find equilibrium| option.]] +[[ +The threshold for the |find equilibrium| option. +]] documentation [[ -This key specifies the threshold for the |find equilibrium| option. The lower -epsilon, the longer the graph drawing algorithm will take, but the closer the -resulting drawing will be to the true energy minimum. +This key specifies the threshold for the |find equilibrium| option. The lower +epsilon, the longer the graph drawing algorithm will take, but the closer the +resulting drawing will be to the true energy minimum. ]] example @@ -189,7 +197,7 @@ example \graph[social degree layout, iterations = 200, maximum time = 200, maximum step = 10, coarsen = false, epsilon = 2]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -198,7 +206,7 @@ example \graph[social degree layout, iterations = 200, maximum time = 200, maximum step = 10, epsilon = 12, coarsen = false]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -208,15 +216,17 @@ example key "snap to grid" summary -[[ This option enables the post-processing step |snap to grid|.]] +[[ +This option enables the post-processing step |snap to grid|. +]] documentation [[ -This key is the on/off-switch for the grid forces. The |snap to grid| option -triggers a form of post-processing were all vertices are pulled to the closest -point on a virtual grid. Please note that there is no repulsive force between -the vertices, so it is possible that two vertices are pulled to the same grid -point. The grid size is determined by the parameters |grid x length| and +This key is the on/off-switch for the grid forces. The |snap to grid| option +triggers a form of post-processing were all vertices are pulled to the closest +point on a virtual grid. Please note that there is no repulsive force between +the vertices, so it is possible that two vertices are pulled to the same grid +point. The grid size is determined by the parameters |grid x length| and |grid y length|. ]] @@ -226,7 +236,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, maximum step = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -235,7 +245,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 5mm, maximum step = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -245,13 +255,15 @@ example key "grid x length" summary -[[ This option determines the cell size in $x$ direction for the |snap to grid| -option.]] +[[ +This option determines the cell size in $x$ direction for the |snap to grid| +option. +]] documentation [[ -The size of the cells of the virtual grid can be configured by the user. This -key allows a configuration of the horizontal cell width. +The size of the cells of the virtual grid can be configured by the user. This +key allows a configuration of the horizontal cell width. ]] example @@ -260,7 +272,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 5mm, maximum step = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -269,7 +281,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 9mm, grid y length = 5mm, maximum step = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -279,8 +291,10 @@ example key "grid y length" summary -[[ This option determines the cell size in $x$ direction for the |snap to grid| -option.]] +[[ +This option determines the cell size in $x$ direction for the |snap to grid| +option. +]] documentation [[ @@ -293,7 +307,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 5mm, maximum step = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -302,7 +316,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, snap to grid =true, grid x length = 5mm, grid y length = 9mm, maximum step = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -312,18 +326,18 @@ key "mass" summary [[ - The mass of a vertex determines how fast it can move. Vertices - with higher mass move slower. + The mass of a vertex determines how fast it can move. Vertices + with higher mass move slower. ]] documentation [[ - The mass of a vertex determines how fast this vertex - moves. Mass is directly inverse proportional to the distance the vertex - moves. In contrast to the global speed factor, mass usually only affects a - single vertex. A vertex with a higher mass will move slower if affected by - the same mass than a vertex with a lower mass. By default, each vertex has a - mass of $1$. + The mass of a vertex determines how fast this vertex + moves. Mass is directly inverse proportional to the distance the vertex + moves. In contrast to the global speed factor, mass usually only affects a + single vertex. A vertex with a higher mass will move slower if affected by + the same mass than a vertex with a lower mass. By default, each vertex has a + mass of $1$. ]] example @@ -332,7 +346,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, maximum displacement per step = 10]{ a1 -- {a2, a3, a4, a5}, b1 -- {b2 -- {b3, b4}, b5} - }; + }; ]] example @@ -341,7 +355,7 @@ example \graph[social degree layout, iterations = 100, maximum time = 100, maximum displacement per step = 10]{ a1 -- {a2, a3, a4, a5}, b1[mass = 4] -- {b2 -- {b3, b4}, b5} - }; + }; ]] -------------------------------------------------------------------- @@ -351,13 +365,13 @@ key "coarsening weight" summary [[ - The coarsening weight of a vertex determines when it will be - coarsened. + The coarsening weight of a vertex determines when it will be + coarsened. ]] documentation [[ - Vertices with higher coarsening weight are considered more important and - will be coarsened later, or not at all. + Vertices with higher coarsening weight are considered more important and + will be coarsened later, or not at all. ]] -------------------------------------------------------------------- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua index 774743e52e6..4634b701235 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceAbsoluteValue.lua @@ -7,9 +7,9 @@ -- -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is a subclass of ForceTemplate, which is used to implement forces --- that work on individual vertices. Forces of this kind simply add an --- absolute value set in the force data to each vertex' $x$ and $y$ coodinate +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices. Forces of this kind simply add an +-- absolute value set in the force data to each vertex' $x$ and $y$ coordinate -- Imports local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" @@ -31,11 +31,11 @@ function ForceAbsoluteValue:constructor () end --- This force class works on a vertex array that is part of the force data --- defined when adding the force. This array is copied into p. All vertices of --- the graph are saved in the local variable |ver|. +-- This force class works on a vertex array that is part of the force data +-- defined when adding the force. This array is copied into p. All vertices of +-- the graph are saved in the local variable |ver|. -- --- @param v The vertices of the graph we are trying to find a layout for. +-- @param v The vertices of the graph we are trying to find a layout for. function ForceAbsoluteValue:preprocess(v) self.ver = v @@ -43,12 +43,12 @@ function ForceAbsoluteValue:preprocess(v) end --- Applying the force to the vertices and adding the effect to the passed net +-- Applying the force to the vertices and adding the effect to the passed net -- force array --- --- @param data The parameters needed to aplly the force: The options table, --- the current time stamp, an array containing the summed up net --- forces +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces function ForceAbsoluteValue:applyTo(data) -- locals for speed @@ -61,13 +61,13 @@ function ForceAbsoluteValue:applyTo(data) local time_fun = self.force.time_fun -- Evaluate time function - local time_factor = time_fun(t_max, t_now) + local time_factor = time_fun(t_max, t_now) if time_factor == 0 then return end for _,v in ipairs(self.ver) do - for _, i in ipairs (self.p) do + for _, i in ipairs (self.p) do -- Is the vertex in the list? if v.name == i then diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua index 6d9e69745ed..8cea1aec6a8 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasDistance.lua @@ -8,9 +8,9 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is a subclass of ForceTemplate, which is used to implement forces between --- vertex pairs. The forces depend on the canvas distance of the vertices in --- the pair. This class is e.~g.~ used for electric forces. +--- This is a subclass of ForceTemplate, which is used to implement forces between +-- vertex pairs. The forces depend on the canvas distance of the vertices in +-- the pair. This class is e.~g.~ used for electric forces. -- Imports local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" @@ -22,7 +22,7 @@ local max = math.max local sqrt = math.sqrt local min = math.min --- Implementation starts here: +-- Implementation starts here: local ForceCanvasDistance = lib.class { base_class = ForceTemplate } function ForceCanvasDistance:constructor () @@ -31,24 +31,24 @@ function ForceCanvasDistance:constructor () end --- This force class works on all pairwise disjoint vertex pairs. This --- function generates a new graph object containing all vertices from the --- original graph and arcs between all pairwise disjoint vertex pairs. The --- arcs-table of this new object will be saved in the variable |p|. --- --- @param v The vertices of the graph we are trying to find a layout for. +-- This force class works on all pairwise disjoint vertex pairs. This +-- function generates a new graph object containing all vertices from the +-- original graph and arcs between all pairwise disjoint vertex pairs. The +-- arcs-table of this new object will be saved in the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. function ForceCanvasDistance:preprocess(v) self.p = Preprocessing.allPairs(v) end --- Applying the force to the vertices and adding the effect to the passed net +-- Applying the force to the vertices and adding the effect to the passed net -- force array --- --- @param data The parameters needed to aplly the force: The options table, --- the current time stamp, an array containing the summed up net --- forces +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces function ForceCanvasDistance:applyTo(data) -- locals for speed @@ -68,7 +68,7 @@ function ForceCanvasDistance:applyTo(data) if time_factor == 0 then return end - + if not fun_v then local data = { k = k, attributes = fw_attributes } for _, i in ipairs(p) do @@ -103,7 +103,7 @@ function ForceCanvasDistance:applyTo(data) else x = min(cap, g) end - + if h <= 0 then y = max(-cap, h) else @@ -168,7 +168,7 @@ function ForceCanvasDistance:applyTo(data) else x_tail = min(cap, g_tail) end - + if h_head <= 0 then y_head = max(-cap, h_head) else diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua index 377ab22c348..41edaba3588 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceCanvasPosition.lua @@ -8,9 +8,9 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is a subclass of ForceTemplate, which is used to implement forces --- that work on individual vertices. The forces depend on the canvas position --- of the vertices. This class is e.~g.~ used for gravitational forces. +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices. The forces depend on the canvas position +-- of the vertices. This class is e.~g.~ used for gravitational forces. local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" local lib = require "pgf.gd.lib" @@ -30,23 +30,23 @@ function ForceCanvasPosition:constructor () end --- This force class works on individual vertices and only depends on their --- current position. Thus the vertex table of the current graph is simply --- copied to the variable |p|. --- --- @param v The vertices of the graph we are trying to find a layout for. +-- This force class works on individual vertices and only depends on their +-- current position. Thus the vertex table of the current graph is simply +-- copied to the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. function ForceCanvasPosition:preprocess(v) self.p = v end --- Applying the force to the vertices and adding the effect to the passed net +-- Applying the force to the vertices and adding the effect to the passed net -- force array --- --- @param data The parameters needed to aplly the force: The options table, --- the current time stamp, an array containing the summed up net --- forces +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces function ForceCanvasPosition:applyTo(data) --localize diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua index 628f1192ac0..86d67f2678f 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua @@ -8,9 +8,9 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is a subclass of ForceTemplate, which is used to implement forces between --- vertex pairs. The forces depend on the graph distance of the vertices in --- the pair. This class is e.~g.~ used for spring forces. +--- This is a subclass of ForceTemplate, which is used to implement forces between +-- vertex pairs. The forces depend on the graph distance of the vertices in +-- the pair. This class is e.\,g.\ used for spring forces. local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate" @@ -32,26 +32,26 @@ function ForceGraphDistance:constructor () end --- This force class works on all pairwise disjoint vertex pairs connected by --- a path of length maximum $n$. The parameter $n$ is given by the engineer in --- the force declaration. This function generates a new graph object --- containing all vertices from the original graph and arcs between all --- pairwise disjoint vertex pairs. The arcs-table of this new object will be --- saved in the variable |p|. --- --- @param v The vertices of the graph we are trying to find a layout for. +-- This force class works on all pairwise disjoint vertex pairs connected by +-- a path of length maximum $n$. The parameter $n$ is given by the engineer in +-- the force declaration. This function generates a new graph object +-- containing all vertices from the original graph and arcs between all +-- pairwise disjoint vertex pairs. The arcs-table of this new object will be +-- saved in the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. function ForceGraphDistance:preprocess(v, a) self.p = Preprocessing.overExactlyNPairs(v, a, self.force.n) end --- Applying the force to the vertices andadding the effect to the passed net +-- Applying the force to the vertices and adding the effect to the passed net -- force array --- --- @param data The parameters needed to aplly the force: The options table, --- the current time stamp, an array containing the summed up net --- forces +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces function ForceGraphDistance:applyTo(data) -- locals for speed @@ -86,12 +86,12 @@ function ForceGraphDistance:applyTo(data) local y = p2_pos.y - p1_pos.y local d = max(sqrt(x*x+y*y),0.1) - -- apply force function to distance and k (natural spring length) + -- apply force function to distance and k (natural spring length) data.u = p2 data.v = p1 data.d = d local e = fun_u(data) - + -- Include time function local f = e * time_factor / d @@ -106,7 +106,7 @@ function ForceGraphDistance:applyTo(data) else x = min(cap, g) end - + if g <= 0 then y = max(-cap, h) else @@ -147,7 +147,7 @@ function ForceGraphDistance:applyTo(data) data.d = d local e_head = fun_u(data) local e_tail = fun_v(data) - + -- Include time function local f_head = time_factor * e_head / d local f_tail = time_factor * e_tail / d @@ -172,7 +172,7 @@ function ForceGraphDistance:applyTo(data) else x_tail = min(cap, g_tail) end - + if h_head <= 0 then y_head = max(-cap, h_head) else diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua index b196a8a6a95..5f53f5da784 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToGrid.lua @@ -8,12 +8,12 @@ -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is a subclass of ForceTemplate, which is used to implement forces --- that work on individual vertices and pulls them to a virtual grid with --- cells of the size determined by the user options |grid x length| and --- |grid y length|. The forces depend on the canvas position --- of the vertices relative to th next grid point. This class is e.~g.~ used --- for the post-processing technique |snap to grid|. +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices and pulls them to a virtual grid with +-- cells of the size determined by the user options |grid x length| and +-- |grid y length|. The forces depend on the canvas position +-- of the vertices relative to th next grid point. This class is e.\,g.\ used +-- for the post-processing technique |snap to grid|. -- Imports @@ -40,22 +40,22 @@ function ForcePullToGrid:constructor () self.p = {} end --- This force class works on individual vertices and only depends on their --- current position. Thus the vertex table of the current graph is simply --- copied to the variable |p|. --- --- @param v The vertices of the graph we are trying to find a layout for. +-- This force class works on individual vertices and only depends on their +-- current position. Thus the vertex table of the current graph is simply +-- copied to the variable |p|. +-- +-- @param v The vertices of the graph we are trying to find a layout for. function ForcePullToGrid:preprocess(v) self.p = v end --- Applying the force to the vertices andadding the effect to the passed net +-- Applying the force to the vertices and adding the effect to the passed net -- force array --- --- @param data The parameters needed to aplly the force: The options table, --- the current time stamp, an array containing the summed up net +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net -- forces function ForcePullToGrid:applyTo(data) @@ -71,7 +71,7 @@ function ForcePullToGrid:applyTo(data) local length = 5--self.options["node distance"] -- Evaluate time function - local time_factor = time_fun(t_max, t_now) + local time_factor = time_fun(t_max, t_now) if time_factor == 0 then return end @@ -89,7 +89,7 @@ function ForcePullToGrid:applyTo(data) local l = -d/(length*length) -- Include time function - local h = l * time_factor + local h = l * time_factor -- scale effect according to direction local f = x * h @@ -102,7 +102,7 @@ function ForcePullToGrid:applyTo(data) else x = min(cap, f) end - + if g <= 0 then y = max(-cap, g) else diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua index 908fdcf6b2e..985b8eec2e5 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForcePullToPoint.lua @@ -7,11 +7,11 @@ -- -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This is a subclass of ForceTemplate, which is used to implement forces --- that work on individual vertices and pulls them to a specific point on the --- canvas. This point is given by the |desired at| option. The forces depend --- on the canvas position of the vertices relative to the canvas point it is --- pulled to. +--- This is a subclass of ForceTemplate, which is used to implement forces +-- that work on individual vertices and pulls them to a specific point on the +-- canvas. This point is given by the |desired at| option. The forces depend +-- on the canvas position of the vertices relative to the canvas point it is +-- pulled to. -- Imports @@ -33,17 +33,17 @@ function ForcePullToPoint:constructor () self.p = {} end --- This force class works on individual vertices and depends on their --- current position as well as the point it is desired at. Thus all vertices --- where the |desired at| option is set are added to the table |p| together --- with the point where they are wanted. --- --- @param v The vertices of the graph we are trying to find a layout for. +-- This force class works on individual vertices and depends on their +-- current position as well as the point it is desired at. Thus all vertices +-- where the |desired at| option is set are added to the table |p| together +-- with the point where they are wanted. +-- +-- @param v The vertices of the graph we are trying to find a layout for. function ForcePullToPoint:preprocess(v) for _,vertex in ipairs(v) do if vertex.options then - local da = vertex.options["desired at"] + local da = vertex.options["desired at"] if da then self.p[vertex]= {da} end @@ -52,12 +52,12 @@ function ForcePullToPoint:preprocess(v) end --- Applying the force to the vertices andadding the effect to the passed net +-- Applying the force to the vertices and adding the effect to the passed net -- force array --- --- @param data The parameters needed to aplly the force: The options table, --- the current time stamp, an array containing the summed up net --- forces +-- +-- @param data The parameters needed to apply the force: The options table, +-- the current time stamp, an array containing the summed up net +-- forces function ForcePullToPoint:applyTo(data) -- locals for speed @@ -69,7 +69,7 @@ function ForcePullToPoint:applyTo(data) local time_fun = self.force.time_fun -- Evaluate time function - local time_factor = time_fun(t_max, t_now) + local time_factor = time_fun(t_max, t_now) if time_factor == 0 then return end @@ -85,7 +85,7 @@ function ForcePullToPoint:applyTo(data) local d = max(sqrt(x*x+y*y),0.1) -- Include time function - local h = d * time_factor + local h = d * time_factor -- scale effect according to direction local f = x * h @@ -98,7 +98,7 @@ function ForcePullToPoint:applyTo(data) else x = min(cap, f) end - + if g <= 0 then y = max(-cap, g) else diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua index 1ed35653c93..ab8f1fad9a6 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/CircularInitialPositioning.lua @@ -7,7 +7,7 @@ -- -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This class implements an inital position algorithm for graph drawing, placing the vertices on +--- This class implements an initial position algorithm for graph drawing, placing the vertices on -- a circle with th radius given by the |radius| key local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare local InitialTemplate = require "pgf.gd.force.jedi.base.InitialTemplate" @@ -21,7 +21,7 @@ declare { key = "circular initial position", algorithm = CircularInitialPositioning, phase = "initial positioning force framework", - phase_default = true + phase_default = true } -- Implementation starts here: @@ -33,7 +33,7 @@ end function CircularInitialPositioning:run() -- locals for speed local vertices = self.vertices - local tmp = (self.options["node pre sep"] + self.options["node post sep"]) + + local tmp = (self.options["node pre sep"] + self.options["node post sep"]) + (self.options["sibling pre sep"] + self.options["sibling post sep"]) local min_radius = tmp * #self.vertices/2/math.pi local radius = math.max(self.options.radius, min_radius) diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua index cb710b35d60..2b131e8ad9f 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/GridInitialPositioning.lua @@ -7,8 +7,8 @@ -- -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This class implements an inital position algorithm for graph drawing, placing the vertices on --- a grid with square cells with width |node distance| +--- This class implements an initial position algorithm for graph drawing, +-- placing the vertices on a grid with square cells with width |node distance| local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare local InitialTemplate = require "pgf.gd.force.jedi.base.InitialTemplate" local lib = require "pgf.gd.lib" @@ -45,7 +45,7 @@ function GridInitialPositioning:run() if placed[vertex] == nil then if i <= (y/dist+1)*n then x = x + dist - else + else x = 0 y = y + dist end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua index 39a58b9e2bd..ce3a40582c5 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/initialpositioning/RandomInitialPositioning.lua @@ -7,8 +7,8 @@ -- -- See the file doc/generic/pgf/licenses/LICENSE for more information ---- This class implements an inital position algorithm for graph drawing, placing the vertices at --- random positions. +--- This class implements an initial position algorithm for graph drawing, +-- placing the vertices at random positions. local declare = require "pgf.gd.interface.InterfaceToAlgorithms".declare local InitialTemplate = require "pgf.gd.force.jedi.base.InitialTemplate" local lib = require "pgf.gd.lib" @@ -30,7 +30,7 @@ end function RandomInitialPositioning:run() -- locals for speed - local random = math.random + local random = lib.random local vertices = self.vertices local desired_vertices = self.desired_vertices -- place vertices where the |desired at | option has been set first @@ -39,11 +39,11 @@ function RandomInitialPositioning:run() for _, vertex in ipairs(vertices) do -- place all other vertices with respect to the one already placed if placed[vertex] == nil then - p = vertex.pos + p = vertex.pos p.x = 100 * random() + centroid_x p.y = 100 * random() + centroid_y end end end -return RandomInitialPositioning
\ No newline at end of file +return RandomInitialPositioning diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/library.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/library.lua index 4cc7128b16a..5d5554ce351 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/library.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/library.lua @@ -9,14 +9,14 @@ --- The library providing the graph drawing framework Jedi --- This labrary requires all graph drawing algorithms and inital --- positioning algorithms provided with the first release of Jedi. --- It also defines the mass key attached to all vertices. +-- This library requires all graph drawing algorithms and initial +-- positioning algorithms provided with the first release of Jedi. +-- It also defines the mass key attached to all vertices. -- Library name local jedi --- require inital positioning algorithms +-- require initial positioning algorithms require "pgf.gd.force.jedi.initialpositioning.CircularInitialPositioning" require "pgf.gd.force.jedi.initialpositioning.RandomInitialPositioning" require "pgf.gd.force.jedi.initialpositioning.GridInitialPositioning" @@ -101,7 +101,7 @@ declare { key = "mass", type = "number", initial = "1", - + documentation_in = "pgf.gd.force.jedi.doc" } @@ -110,6 +110,6 @@ declare { key = "coarsening weight", type = "number", initial = "1", - + documentation_in = "pgf.gd.force.jedi.doc" } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/library.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/library.lua index be0faf465c1..acfda34ffce 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/library.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/library.lua @@ -24,43 +24,43 @@ -- When you start thinking about for a moment, it turns out that there -- are endless variations of the force model. All of these models have -- the following in common, however: +-- % -- \begin{itemize} --- \item ``Forces'' pull and push at the nodes in different --- directions. --- \item The effect of these forces is simulated by iteratively moving --- all the nodes simultaneously a little in the direction of the forces --- and by then recalculating the forces. --- \item The iteration is stopped either after a certain number of --- iterations or when a \emph{global energy minimum} is reached (a very --- scientific way of saying that nothing happens anymore). +-- \item ``Forces'' pull and push at the nodes in different directions. +-- \item The effect of these forces is simulated by iteratively moving +-- all the nodes simultaneously a little in the direction of the forces +-- and by then recalculating the forces. +-- \item The iteration is stopped either after a certain number of +-- iterations or when a \emph{global energy minimum} is reached (a very +-- scientific way of saying that nothing happens anymore). -- \end{itemize} -- -- The main difference between the different force-based approaches is -- how the forces are determined. Here are some ideas what could cause a -- force to be exerted between two nodes (and there are more): +-- % -- \begin{itemize} --- \item If the nodes are connected by an edge, one can treat the edge as --- a ``spring'' that has a ``natural spring dimension.'' If the nodes --- are nearer than the spring dimension, they are push apart; if they --- are farther aways than the spring dimension, they are pulled --- together. --- \item If two nodes are connected by a path of a certain length, the --- nodes may ``wish to be at a distance proportional to the path --- length''. If they are nearer, they are pushed apart; if they are --- farther, they are pulled together. (This is obviously a --- generalization of the previous idea.) --- \item There may be a general force field that pushes nodes apart (an --- electrical field), so that nodes do not tend to ``cluster''. --- \item There may be a general force field that pulls nodes together (a --- gravitational field), so that nodes are not too loosely scattered. --- \item There may be highly nonlinear forces depending on the distance of --- nodes, so that nodes very near to each get pushed apart strongly, --- but the effect wears of rapidly at a distance. (Such forces are --- known as strong nuclear forces.) --- \item There rotational forces caused by the angles between the edges --- leaving a node. Such forces try to create a \emph{perfect angular --- resolution} (a very scientific way of saying that all angles --- at a node are equal). +-- \item If the nodes are connected by an edge, one can treat the edge as +-- a ``spring'' that has a ``natural spring dimension''. If the nodes +-- are nearer than the spring dimension, they are push apart; if they +-- are farther aways than the spring dimension, they are pulled together. +-- \item If two nodes are connected by a path of a certain length, the +-- nodes may ``wish to be at a distance proportional to the path +-- length''. If they are nearer, they are pushed apart; if they are +-- farther, they are pulled together. (This is obviously a +-- generalization of the previous idea.) +-- \item There may be a general force field that pushes nodes apart (an +-- electrical field), so that nodes do not tend to ``cluster''. +-- \item There may be a general force field that pulls nodes together (a +-- gravitational field), so that nodes are not too loosely scattered. +-- \item There may be highly nonlinear forces depending on the distance of +-- nodes, so that nodes very near to each get pushed apart strongly, +-- but the effect wears of rapidly at a distance. (Such forces are +-- known as strong nuclear forces.) +-- \item There rotational forces caused by the angles between the edges +-- leaving a node. Such forces try to create a \emph{perfect angular +-- resolution} (a very scientific way of saying that all angles +-- at a node are equal). -- \end{itemize} -- -- Force-based algorithms combine one or more of the above ideas into a @@ -70,33 +70,33 @@ -- Currently, three algorithms are implemented in this library, two of -- which are from the first of the following paper, while the third is -- from the third paper: --- +-- % -- \begin{itemize} --- \item --- Y. Hu. --- \newblock Efficient, high-quality force-directed graph drawing. --- \newblock \emph{The Mathematica Journal}, 2006. --- \item --- C. Walshaw. --- \newblock A multilevel algorithm for force-directed graph --- drawing. --- \newblock In J. Marks, editor, \emph{Graph Drawing}, Lecture Notes in --- Computer Science, 1984:31--55, 2001. +-- \item +-- Y. Hu. +-- \newblock Efficient, high-quality force-directed graph drawing. +-- \newblock \emph{The Mathematica Journal}, 2006. +-- \item +-- C. Walshaw. +-- \newblock A multilevel algorithm for force-directed graph +-- drawing. +-- \newblock In J. Marks, editor, \emph{Graph Drawing}, Lecture Notes in +-- Computer Science, 1984:31--55, 2001. -- \end{itemize} -- -- Our implementation is described in detail in the following -- diploma thesis: --- +-- % -- \begin{itemize} --- \item --- Jannis Pohlmann, --- \newblock \emph{Configurable Graph Drawing Algorithms --- for the \tikzname\ Graphics Description Language,} --- \newblock Diploma Thesis, --- \newblock Institute of Theoretical Computer Science, Univerist\"at --- zu L\"ubeck, 2011.\\[.5em] --- \newblock Online at --- \url{http://www.tcs.uni-luebeck.de/downloads/papers/2011/}\\ \url{2011-configurable-graph-drawing-algorithms-jannis-pohlmann.pdf} +-- \item +-- Jannis Pohlmann, +-- \newblock \emph{Configurable Graph Drawing Algorithms +-- for the \tikzname\ Graphics Description Language,} +-- \newblock Diploma Thesis, +-- \newblock Institute of Theoretical Computer Science, Universit\"at +-- zu L\"ubeck, 2011.\\[.5em] +-- \newblock Online at +-- \url{http://www.tcs.uni-luebeck.de/downloads/papers/2011/}\\ \url{2011-configurable-graph-drawing-algorithms-jannis-pohlmann.pdf} -- \end{itemize} -- -- In the future, I hope that most, if not all, of the force-based diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua index 8dfbae44850..8473eb3f109 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceCore.lua @@ -18,7 +18,7 @@ -- |InterfaceToDisplay| use, in particular, the data structures -- provided by this class. -- --- @field binding This field stores the ``binding.'' The graph drawing +-- @field binding This field stores the ``binding''. The graph drawing -- system is ``bound'' to the display layer through such a binding (a -- subclass of |Binding|). Such a binding can be thought of as a -- ``driver'' in operating systems terminology: It is a small set of @@ -28,7 +28,7 @@ -- completely new Lua instance. -- -- @field scopes This is a stack of graph drawing scopes. All --- interface methods refer to the top of this stack. +-- interface methods refer to the top of this stack. -- -- @field collection_kinds This table stores which collection kinds -- have been defined together with their properties. @@ -59,7 +59,7 @@ local InterfaceCore = { -- The phase kinds phase_kinds = {}, - + -- Internals for handling the options stack option_stack = {}, option_cache_height = nil, @@ -186,6 +186,6 @@ function InterfaceCore.convert(s,t) end --- Done +-- Done return InterfaceCore 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 index f1b203e550c..1187fbc3136 100644 --- 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 @@ -15,13 +15,13 @@ -- 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''. +-- 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. +-- parameter will become available on the display layer. local InterfaceToAlgorithms = {} @@ -58,7 +58,7 @@ local declare_handlers -- 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. +-- finishes. Otherwise, the next handler is tried. function InterfaceToAlgorithms.addHandler(test, handler) table.insert(declare_handlers, 1, { test = test, handler = handler }) @@ -76,7 +76,7 @@ local key_metatable = {} -- 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} @@ -84,11 +84,11 @@ local key_metatable = {} -- 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 +-- 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: --- +-- example of how a declaration is done: +-- % --\begin{codeexample}[code only, tikz syntax=false] -- --- -- declare { @@ -126,7 +126,7 @@ local key_metatable = {} -- 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 { @@ -138,7 +138,7 @@ local key_metatable = {} --\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 +-- 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. @@ -146,14 +146,15 @@ local key_metatable = {} -- \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|. +-- \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 { @@ -176,8 +177,8 @@ local key_metatable = {} -- 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: --- +-- originally passed to the original key. Here is a typical example: +-- % --\begin{codeexample}[code only, tikz syntax=false] -- --- -- declare { @@ -193,7 +194,7 @@ local key_metatable = {} -- -- 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. +-- 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 @@ -209,7 +210,7 @@ local key_metatable = {} 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 @@ -219,14 +220,14 @@ function InterfaceToAlgorithms.declare (t) for _,h in ipairs (declare_handlers) do if h.test(t) then if h.handler(t) then - break + break end end end -- Attach metatable: setmetatable (t, key_metatable) - + -- Set! keys[t.key] = t keys[#keys + 1] = t @@ -246,10 +247,10 @@ end --- --- This function is called by |declare| for ``normal parameter keys,'' +-- 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 { @@ -266,6 +267,7 @@ end -- 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} @@ -273,40 +275,40 @@ end -- 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 |time| A ``time'' in the sense of |\pgfparsetime|. Examples --- are |6s| or |0.1min| or |6000ms|, all of which will map to |6|. --- \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). +-- \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 |time| A ``time'' in the sense of |\pgfparsetime|. Examples +-- are |6s| or |0.1min| or |6000ms|, all of which will map to |6|. +-- \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"|. +-- |"string"|. -- -- A parameter can have an |initial| value. This value will be used -- whenever the parameter has not been set explicitly for an object. @@ -316,7 +318,7 @@ end -- 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 +-- A parameter can have 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| @@ -324,7 +326,7 @@ end -- 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. +-- 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 @@ -332,7 +334,7 @@ end -- 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", @@ -349,7 +351,7 @@ end -- -- 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", @@ -366,7 +368,7 @@ end -- -- 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", @@ -377,9 +379,9 @@ end -- } --\end{codeexample} -- --- As a special curtesy to C code, you can also set the key +-- As a special courtesy 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|. +-- a string that is read using |loadstring|. -- -- (You cannot call this function directly, it is included for -- documentation purposes only.) @@ -389,36 +391,36 @@ end 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 + 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 + count = count + 1 + if count == 1 then + return "return " + elseif count == 2 then + return t.alias_function_string + else + return nil + end end)() end @@ -435,16 +437,17 @@ end --- -- This function is called by |declare| for ``algorithm --- keys.'' These keys are normally used without a value as in just +-- keys''. These keys are normally used without a value as in just -- |\graph[tree layout]|, but you can optionally pass a value to -- them. In this case, this value must be the name of a \emph{phase} -- and the algorithm of this phase will be set (and not the -- default phase of the key), see the description of phases below for --- details. +-- details. -- -- Algorithm keys 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 = {} -- @@ -497,7 +500,7 @@ end -- 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. +-- will be set; algorithms of other phases will not be changed. -- 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 @@ -505,7 +508,7 @@ end -- 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. +-- 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| @@ -519,12 +522,12 @@ end -- -- 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 = { +-- algorithm = { -- run = -- function (self) -- return SpanningTreeComputation.computeSpanningTree(self.ugraph, false, self.events) @@ -538,7 +541,7 @@ end -- -- 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"] @@ -567,7 +570,7 @@ end 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 () @@ -578,7 +581,7 @@ local function declare_algorithm (t) else class = lib.class(require(t.algorithm)) end - + -- Now, save pre- and postconditions class.preconditions = t.preconditions or {} class.postconditions = t.postconditions or {} @@ -602,26 +605,26 @@ local function declare_algorithm (t) -- Save in the algorithm_classes table: InterfaceCore.algorithm_classes[t.key] = store_me - + assert(t.type == nil, "type may not be set for an algorithm key") t.type = "string" - + -- 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") + "default algorithm for phase already set") assert (type(store_me) == "table", - "default algorithms must be loaded immediately") + "default algorithms must be loaded immediately") InterfaceCore.option_initial.algorithm_phases[t.phase] = store_me InterfaceCore.option_initial.algorithm_phases[t.phase .. " stack"] = { store_me } else InterfaceCore.option_initial.algorithm_phases[t.phase .. " stack"] = { dummy = true -- Remove once Lua Link Bug is fixed - } - end - + } + end + return true end @@ -629,42 +632,44 @@ end --- --- This function is called by |declare| for ``collection kinds.'' They --- are detected by the presence of the field |layer| +-- 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. +-- belongs to a collection. -- -- \medskip -- \noindent\textbf{The Display Layer.} --- Let us first have a look at what happens on 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|. --- +-- 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] +-- % +--\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. +-- collections. -- -- The effect of declaring a collection kind on the algorithm layer -- it, first of all, that |scope.collections| will have a field named @@ -674,37 +679,37 @@ end -- 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 +-- ``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. +-- 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 +-- the binding layer will ask the display 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 @@ -712,7 +717,7 @@ end -- -- (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) @@ -722,11 +727,11 @@ local function declare_collection_kind (t) 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: + -- 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 @@ -736,7 +741,7 @@ local function declare_collection_kind (t) end kinds[#kinds+1] = new_entry - + -- Bind InterfaceCore.binding:declareCallback(t) @@ -808,22 +813,22 @@ local unique_count = 1 -- -- 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. +-- \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 +-- should be added -- @param init A table of initial values for the node that is passed --- to |Binding:createVertex|, see that function for details. +-- to |Binding:createVertex|, see that function for details. -- -- @return The newly created node -- @@ -832,7 +837,7 @@ 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 @@ -841,29 +846,29 @@ function InterfaceToAlgorithms.createVertex(algorithm, init) -- 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.syntactic_component:add {v} + algorithm.digraph:add {v} algorithm.ugraph:add {v} - - -- Compute bounding boxes: + + -- 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 @@ -873,40 +878,41 @@ 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 +-- all layouts on the layout stack. Furthermore, appropriate edges are -- added to the |digraph| and the |ugraph| of the algorithm currently --- running. +-- running. -- --- @param algorithm An algorithm for whose syntactic digraph the node should be added +-- @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|. +-- \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") - + 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, @@ -916,16 +922,16 @@ function InterfaceToAlgorithms.createEdge(algorithm, tail, head, init) generated_options = init.generated_options } - -- Add to arc + -- 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) @@ -934,7 +940,7 @@ function InterfaceToAlgorithms.createEdge(algorithm, tail, head, init) -- Call binding binding.storage[edge] = {} binding:everyEdgeCreation(edge) - + -- Add edge to digraph and ugraph local direction = edge.direction if direction == "->" then @@ -950,13 +956,13 @@ function InterfaceToAlgorithms.createEdge(algorithm, tail, head, init) -- Add edge to layouts add_to_collections(algorithm.layout, "edges", edge) - + end --- Done +-- Done return InterfaceToAlgorithms diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua index 2aeb2e6a7aa..282727b66a3 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToC.lua @@ -32,16 +32,17 @@ local lib = require "pgf.gd.lib" -- |algorithm| field is set to an algorithm class object whose |run| -- method calls the function passed via the -- |algorithm_written_in_c| field. It will be called with the --- following parameters (in that order): +-- following parameters (in that order): +-- % -- \begin{enumerate} --- \item The to-be-laid out digraph. This will not be the whole layout --- graph (syntactic digraph) if preprocessing like decomposition into --- connected components is used. --- \item An array of the digraph's vertices, but with the table part --- hashing vertex objects to their indices in the array part. --- \item An array of the syntactic edges of the digraph. Like the --- array, the table part will hash back the indices of the edge objects. --- \item The algorithm object. +-- \item The to-be-laid out digraph. This will not be the whole layout +-- graph (syntactic digraph) if preprocessing like decomposition into +-- connected components is used. +-- \item An array of the digraph's vertices, but with the table part +-- hashing vertex objects to their indices in the array part. +-- \item An array of the syntactic edges of the digraph. Like the +-- array, the table part will hash back the indices of the edge objects. +-- \item The algorithm object. -- \end{enumerate} -- -- @param t The table originally passed to |declare|. @@ -49,29 +50,29 @@ local lib = require "pgf.gd.lib" function InterfaceToC.declare_algorithm_written_in_c (t) t.algorithm = { run = function (self) - local back_table = lib.icopy(self.ugraph.vertices) - for i,v in ipairs(self.ugraph.vertices) do - back_table[v] = i - end - local edges = {} - for _,a in ipairs(self.ugraph.arcs) do - local b = self.layout_graph:arc(a.tail,a.head) - if b then - lib.icopy(b.syntactic_edges, edges) - end - end - for i=1,#edges do - edges[edges[i]] = i - end - collectgarbage("stop") -- Remove once Lua Link Bug is fixed - t.algorithm_written_in_c (self.digraph, back_table, edges, self) - collectgarbage("restart") -- Remove once Lua Link Bug is fixed - end - } + local back_table = lib.icopy(self.ugraph.vertices) + for i,v in ipairs(self.ugraph.vertices) do + back_table[v] = i + end + local edges = {} + for _,a in ipairs(self.ugraph.arcs) do + local b = self.layout_graph:arc(a.tail,a.head) + if b then + lib.icopy(b.syntactic_edges, edges) + end + end + for i=1,#edges do + edges[edges[i]] = i + end + collectgarbage("stop") -- Remove once Lua Link Bug is fixed + t.algorithm_written_in_c (self.digraph, back_table, edges, self) + collectgarbage("restart") -- Remove once Lua Link Bug is fixed + end + } end -- Done -return InterfaceToC
\ No newline at end of file +return InterfaceToC diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua index c0ddf0dc8ce..23018efcaa5 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/InterfaceToDisplay.lua @@ -73,10 +73,10 @@ local option_cache = nil -- The option cache --- --- Initiliaze the binding. This function is called once by the display +-- Initialize the binding. This function is called once by the display -- layer at the very beginning. For instance, \tikzname\ does the -- following call: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] --InterfaceToDisplay.bind(require "pgf.gd.bindings.BindingToPGF") --\end{codeexample} @@ -90,10 +90,10 @@ local option_cache = nil -- The option cache function InterfaceToDisplay.bind(class) assert (not InterfaceCore.binding, "binding already initialized") - + -- Create a new object InterfaceCore.binding = setmetatable({}, class) - + -- Load these libraries, which contain many standard declarations: require "pgf.gd.model.library" require "pgf.gd.control.library" @@ -113,7 +113,7 @@ end -- once more. -- -- Each graph drawing scope comes with a syntactic digraph that is --- build using methods like |addVertex| or |addEdge|. +-- build using methods like |addVertex| or |addEdge|. -- -- @param height The to-be-used height of the options stack. All -- options above this height will be popped prior to attacking the @@ -123,14 +123,14 @@ function InterfaceToDisplay.beginGraphDrawingScope(height) -- Create a new scope table local scope = Scope.new {} - + -- Setup syntactic digraph: local g = scope.syntactic_digraph - + g.options = get_current_options_table(height) g.syntactic_digraph = g g.scope = scope - + -- Push scope: InterfaceCore.scopes[#InterfaceCore.scopes + 1] = scope end @@ -138,7 +138,7 @@ end --- --- Arranges the current graph using the specified algorithm and options. +-- Arranges the current graph using the specified algorithm and options. -- -- This function should be called after the graph drawing scope has -- been opened and the syntactic digraph has been completely @@ -165,22 +165,22 @@ function InterfaceToDisplay.runGraphDrawingAlgorithm() -- Setup local scope = InterfaceCore.topScope() assert(not scope.coroutine, "coroutine already created for current gd scope") - + -- The actual drawing function local function run () if #scope.syntactic_digraph.vertices == 0 then -- Nothing needs to be done return end - + LayoutPipeline.run(scope) end - + scope.coroutine = coroutine.create(run) -- Run it: - InterfaceToDisplay.resumeGraphDrawingCoroutine() - + InterfaceToDisplay.resumeGraphDrawingCoroutine() + -- End timing: local stop = os.clock() @@ -204,10 +204,10 @@ function InterfaceToDisplay.resumeGraphDrawingCoroutine() -- Setup local scope = InterfaceCore.topScope() local binding = InterfaceCore.binding - + -- Asserts assert(scope.coroutine, "coroutine not created for current gd scope") - + -- Run local ok, text = coroutine.resume(scope.coroutine) assert(ok, text) @@ -258,7 +258,7 @@ end -- to the current |Binding|. -- -- @param anchors A table of anchors (mapping anchor positions to --- |Coordinates|). +-- |Coordinates|). function InterfaceToDisplay.createVertex(name, shape, path, height, binding_infos, anchors) @@ -266,7 +266,7 @@ function InterfaceToDisplay.createVertex(name, shape, path, height, binding_info -- Setup local scope = InterfaceCore.topScope() local binding = InterfaceCore.binding - + -- Does vertex already exist? local v = scope.node_names[name] assert (not v or not v.created_on_display_layer, "node already created") @@ -304,18 +304,18 @@ function vertex_created(v,scope) -- Create Event local e = InterfaceToDisplay.createEvent ("node", v) v.event = e - + -- Create name lookup scope.node_names[v.name] = v - + -- Add vertex to graph scope.syntactic_digraph:add {v} - + -- Add to collections for _,c in ipairs(v.options.collections) do LookupTable.addOne(c.vertices, v) end - + end @@ -326,9 +326,9 @@ end -- ``surrounds'' the vertices 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 availble immediately as +-- 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 display level and on the algorithm level, -- but the actual node is only created inside the layout pipeline @@ -339,7 +339,7 @@ end -- contains all vertices (and edges) being part of the subgraph. For -- this reason, this method is a |push...| method, since it pushes -- something on the options stack. --- +-- -- The |init| parameter will be used during the creation of the node, -- see |Binding:createVertex| for details on the fields. Note that -- |init.text| is often not displayed for such ``vast'' nodes as those @@ -350,34 +350,34 @@ end -- -- The |init.generated_options| will be augmented by additional -- key--value pairs when the vertex is created: --- +-- % -- \begin{itemize} --- \item The key |subgraph point cloud| will have as its value a --- string that is be a list of points (without --- separating commas) like |"(10pt,20pt)(0pt,0pt)(30pt,40pt)"|, always in --- this syntax. The list will contain all points inside the --- subgraph. In particular, a bounding box around these points will --- encompass all nodes and bend points of the subgraph. --- The bounding box of this point cloud is guaranteed to be centered on --- the origin. --- \item The key |subgraph bounding box width| will have as its value --- the width of a bounding box (in \TeX\ points, as a string with the --- suffix |"pt"|). --- \item The key |subgraph bounding box height| stores the height of a --- bounding box. --- \end{itemize} --- +-- \item The key |subgraph point cloud| will have as its value a +-- string that is be a list of points (without separating commas) +-- like |"(10pt,20pt)(0pt,0pt)(30pt,40pt)"|, always in +-- this syntax. The list will contain all points inside the +-- subgraph. In particular, a bounding box around these points will +-- encompass all nodes and bend points of the subgraph. +-- The bounding box of this point cloud is guaranteed to be centered on +-- the origin. +-- \item The key |subgraph bounding box width| will have as its value +-- the width of a bounding box (in \TeX\ points, as a string with the +-- suffix |"pt"|). +-- \item The key |subgraph bounding box height| stores the height of a +-- bounding box. +-- \end{itemize} +-- -- @param name The name of the node. -- @param height Height of the options stack. Note that this method -- pushes something (namely a collection) on the options stack. -- @param info A table passed to |Binding:createVertex|, see that function. -- function InterfaceToDisplay.pushSubgraphVertex(name, height, info) - + -- Setup local scope = InterfaceCore.topScope() local binding = InterfaceCore.binding - + -- Does vertex already exist? assert (not scope.node_names[name], "node already created") @@ -387,7 +387,7 @@ function InterfaceToDisplay.pushSubgraphVertex(name, height, info) kind = "subgraph node", options = get_current_options_table(height-1) } - + vertex_created(v,scope) -- Store info @@ -429,12 +429,12 @@ function InterfaceToDisplay.addToVertexOptions(name, height) -- Setup local scope = InterfaceCore.topScope() - + -- Does vertex already exist? local v = assert (scope.node_names[name], "node is missing, cannot add options") - + v.options = get_current_options_table(height, v.options) - + -- Add to collections for _,c in ipairs(v.options.collections) do LookupTable.addOne(c.vertices, v) @@ -464,8 +464,8 @@ end -- -- @param tail Name of the node the edge begins at. -- @param head Name of the node the edge ends at. --- @param direction Direction of the edge (e.g. |--| for an undirected edge --- or |->| for a directed edge from the first to the second +-- @param direction Direction of the edge (e.g. |--| for an undirected edge +-- or |->| for a directed edge from the first to the second -- node). -- @param height The option stack height, see for instance |createVertex|. -- @@ -477,12 +477,12 @@ function InterfaceToDisplay.createEdge(tail, head, direction, height, binding_in -- Setup local scope = InterfaceCore.topScope() local binding = InterfaceCore.binding - + -- Does vertex already exist? local h = scope.node_names[head] local t = scope.node_names[tail] assert (h and t, "attempting to create edge between nodes that are not in the graph") - + -- Create Arc object local arc = scope.syntactic_digraph:connect(t, h) @@ -493,14 +493,14 @@ function InterfaceToDisplay.createEdge(tail, head, direction, height, binding_in direction = direction, options = get_current_options_table(height) } - - -- Add to arc + + -- Add to arc arc.syntactic_edges[#arc.syntactic_edges+1] = edge - + -- 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) @@ -509,15 +509,15 @@ function InterfaceToDisplay.createEdge(tail, head, direction, height, binding_in -- Call binding binding.storage[edge] = binding_infos binding:everyEdgeCreation(edge) - + end - + --- --- Push an option to the stack of options. +-- Push an option to the stack of options. -- -- As a graph is parsed, a stack of ``current options'' -- is created. To add something to this table, the display layers may @@ -533,7 +533,7 @@ end -- resulting stack height. -- -- In addition to this stack height, this function returns a Boolean --- value indicating whether a ``main algorithm phase was set.'' This +-- value indicating whether a ``main algorithm phase was set''. This -- happens whenever a key is executed (directly or indirectly through -- the |use| field) that selects an algorithm for the ``main'' -- algorithm phase. This information may help the caller to setup the @@ -546,7 +546,7 @@ end -- above this height will be removed. -- -- @return A new stack height --- @return A Boolean that is |true| iff the main algorithm phase was +-- @return A Boolean that is |true| if the main algorithm phase was -- set by the option or one option |use|d by it. -- @return The newly created entry on the stack. If more entries are -- created through the use of the |use| field, the original entry is @@ -555,65 +555,65 @@ end function InterfaceToDisplay.pushOption(key, value, height) assert(type(key) == "string", "illegal key") - + local key_record = assert(InterfaceCore.keys[key], "unknown key") local main_phase_set = false - + if value == nil and key_record.default then value = key_record.default end - + -- Find out what kind of key we are pushing: - + if key_record.algorithm then -- Push a phase if type(InterfaceCore.algorithm_classes[key]) == "function" then - -- Call the constructor function + -- Call the constructor function InterfaceCore.algorithm_classes[key] = InterfaceCore.algorithm_classes[key]() end local algorithm = InterfaceCore.algorithm_classes[key] - + assert (algorithm, "algorithm class not found") - + push_on_option_stack(phase_unique, - { phase = value or key_record.phase, algorithm = algorithm }, - height) - + { phase = value or key_record.phase, algorithm = algorithm }, + height) + if key_record.phase == "main" then main_phase_set = true end - + elseif key_record.layer then -- Push a collection local stack = InterfaceCore.option_stack local scope = InterfaceCore.topScope() - + -- Get the stack above "height": local options = get_current_options_table(height-1) - + -- Create the collection event local event = InterfaceToDisplay.createEvent ("collection", key) - + -- Create collection object: local collection = Collection.new { kind = key, options = options, event = event } - + -- Store in collections table of current scope: local collections = scope.collections[key] or {} collections[#collections + 1] = collection scope.collections[key] = collections - + -- Build collection tree collection:registerAsChildOf(options.collections[#options.collections]) - + -- Push on stack push_on_option_stack(collections_unique, collection, height) - + else - + -- A normal key push_on_option_stack(key, InterfaceCore.convert(value, InterfaceCore.keys[key].type), height) - + end local newly_created = InterfaceCore.option_stack[#InterfaceCore.option_stack] @@ -626,10 +626,10 @@ function InterfaceToDisplay.pushOption(key, value, height) local use_k = u.key local use_v = u.value if type(use_k) == "function" then - use_k = use_k(value) + use_k = use_k(value) end if type(use_v) == "function" then - use_v = use_v(value) + use_v = use_v(value) end height, flag = InterfaceToDisplay.pushOption(use_k, use_v, height+1) main_phase_set = main_phase_set or flag @@ -655,7 +655,7 @@ end --- --- Creates an event and adds it to the event string of the current scope. +-- Creates an event and adds it to the event string of the current scope. -- -- @param kind Name/kind of the event. -- @param parameters Parameters of the event. @@ -679,7 +679,7 @@ end -- keys's names. In particular, you can then iterate over it using -- |ipairs| and you can check whether a key is defined by accessing -- the table at the key's name. Each entry of the table is the --- original table passed to |InterfaceToAlgorithms.declare|. +-- original table passed to |InterfaceToAlgorithms.declare|. -- -- @return A lookup table of all declared keys. @@ -699,7 +699,7 @@ end -- whole graph. -- -- In detail, this function calls: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] --local binding = InterfaceCore.binding -- @@ -719,14 +719,14 @@ end function InterfaceToDisplay.renderGraph() local scope = InterfaceCore.topScope() local syntactic_digraph = scope.syntactic_digraph - + local binding = InterfaceCore.binding - + binding:renderStart() render_vertices(syntactic_digraph.vertices) render_edges(syntactic_digraph.arcs) render_collections(scope.collections) - binding:renderStop() + binding:renderStop() end @@ -743,15 +743,16 @@ end -- binding layer. -- -- Consider the following code: ---\begin{codeexample}[code only] +-- % +--\begin{codeexample}[code only] --\graph [... layout] { -- a -- b -- c -- d; --}; --\end{codeexample} --- +-- -- In this case, after the graph drawing algorithm has run, the -- present function will call: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] --local binding = InterfaceCore.binding -- @@ -779,24 +780,25 @@ end -- function is called to render the different collection kinds. -- -- Collection kinds rendered in the order provided by the |layer| --- field passed to |declare| during the declaration of the colleciton +-- field passed to |declare| during the declaration of the collection -- kind, see also |declare_collection|. If several collection kinds -- have the same layer, they are rendered in lexicographical ordering -- (to ensure that they are always rendered in the same order). -- -- Consider the following code: +-- % --\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] +--\begin{codeexample}[code only] --\graph { -- a, b, c, d; -- { [hyper] a, b, c } -- { [hyper] b, c, d } --}; --\end{codeexample} --- +-- -- In this case, after the graph drawing algorithm has run, the -- present function will call: -- @@ -809,12 +811,12 @@ end --binding:renderCollectionStopKind("hyper", 1) --\end{codeexample} -- --- @param collections The |collections| table of the current scope. +-- @param collections The |collections| table of the current scope. function render_collections(collections) local kinds = InterfaceCore.collection_kinds local binding = InterfaceCore.binding - + for i=1,#kinds do local kind = kinds[i].kind local layer = kinds[i].layer @@ -822,7 +824,7 @@ function render_collections(collections) if layer ~= 0 then binding:renderCollectionStartKind(kind, layer) for _,c in ipairs(collections[kind] or {}) do - binding:renderCollection(c) + binding:renderCollection(c) end binding:renderCollectionStopKind(kind, layer) end @@ -837,19 +839,20 @@ end -- -- When the graph drawing algorithm is done, the interface will first -- rendering the vertices using |render_vertices|, followed by calling --- this function, which in turn calls appropriate callbacks to the +-- this function, which in turn calls appropriate callbacks to the -- binding layer. -- -- Consider the following code: ---\begin{codeexample}[code only] +-- % +--\begin{codeexample}[code only] -- \graph [... layout] { -- a -- b -- c -- d; -- }; --\end{codeexample} --- +-- -- In this case, after the graph drawing algorithm has run, the -- present function will call: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] -- local binding = InterfaceCore.binding -- @@ -877,14 +880,14 @@ local aliases = InterfaceCore.option_aliases local option_initial = InterfaceCore.option_initial local option_metatable = { - __index = + __index = function (t, key) local k = aliases[key] if k then - local v = (type(k) == "string" and t[k]) or (type(k) == "function" and k(t)) or nil - if v ~= nil then - return v - end + local v = (type(k) == "string" and t[k]) or (type(k) == "function" and k(t)) or nil + if v ~= nil then + return v + end end return option_initial[key] end @@ -901,19 +904,19 @@ local option_metatable = { -- with object.) -- -- (This function is local and internal and included only for documentation --- purposes.) +-- purposes.) -- -- @param height The stack height for which the option table is -- required. -- @param table If non |nil|, the options will be added to this --- table. +-- table. -- -- @return The option table as described above. function get_current_options_table (height, table) local stack = InterfaceCore.option_stack assert (height >= 0 and height <= #stack, "height value out of bounds") - + if height == InterfaceCore.option_cache_height and not table then return option_cache else @@ -926,49 +929,49 @@ function get_current_options_table (height, table) local cache if not table then cache = setmetatable( - { - algorithm_phases = setmetatable({}, InterfaceCore.option_initial.algorithm_phases), - collections = {} - }, option_metatable) + { + algorithm_phases = setmetatable({}, InterfaceCore.option_initial.algorithm_phases), + collections = {} + }, option_metatable) else cache = lib.copy(table) cache.algorithm_phases = lib.copy(cache.algorithm_phases) cache.collections = lib.copy(cache.collections) end - + local algorithm_phases = cache.algorithm_phases local collections = cache.collections local keys = InterfaceCore.keys - + local function handle (k, v) if k == phase_unique then - algorithm_phases[v.phase] = v.algorithm - local phase_stack = v.phase .. " stack" - local t = rawget(algorithm_phases, phase_stack) - if not t then - t = algorithm_phases[phase_stack] - assert(type(t) == "table", "unknown phase") - t = lib.copy(t) - algorithm_phases[phase_stack] = t - end - t[#t + 1] = v.algorithm + algorithm_phases[v.phase] = v.algorithm + local phase_stack = v.phase .. " stack" + local t = rawget(algorithm_phases, phase_stack) + if not t then + t = algorithm_phases[phase_stack] + assert(type(t) == "table", "unknown phase") + t = lib.copy(t) + algorithm_phases[phase_stack] = t + end + t[#t + 1] = v.algorithm elseif k == collections_unique then - LookupTable.addOne(collections, v) + LookupTable.addOne(collections, v) else - cache[k] = v + cache[k] = v end end - + for _,s in ipairs(stack) do handle (s.key, s.value) end - + -- Cache it, if this was not added: if not table then InterfaceCore.option_cache_height = height option_cache = cache end - + return cache end end @@ -979,21 +982,21 @@ end function push_on_option_stack(key, value, height) local stack = InterfaceCore.option_stack - - assert (type(height) == "number" and height > 0 and height <= #stack + 1, - "height value out of bounds") - + + assert (type(height) == "number" and height > 0 and height <= #stack + 1, + "height value out of bounds") + -- Clear superfluous part of stack for i=#stack,height+1,-1 do stack[i] = nil end stack[height] = { key = key, value = value } - InterfaceCore.option_cache_height = nil -- invalidate cache + InterfaceCore.option_cache_height = nil -- invalidate cache end --- Done +-- Done -return InterfaceToDisplay
\ No newline at end of file +return InterfaceToDisplay diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/Scope.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/Scope.lua index 438925a2213..a750308e692 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/Scope.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/interface/Scope.lua @@ -25,8 +25,8 @@ -- inform an algorithm about the input. -- -- For each graph drawing scope, a new |Scope| object is --- created. Graph drawing scopes are kepts track of using a stack, but --- only the top of this stack is available to the interface classes. +-- created. Graph drawing scopes are kept track of using a stack, but +-- only the top of this stack is available to the interface classes. -- -- @field syntactic_digraph The syntactic digraph is a digraph that -- faithfully encodes the way the input graph is represented @@ -77,16 +77,16 @@ local Digraph = require "pgf.gd.model.Digraph" function Scope.new(initial) return setmetatable(lib.copy(initial, - { - syntactic_digraph = Digraph.new{}, - events = {}, - node_names = {}, - coroutine = nil, - collections = {}, - }), Scope) + { + syntactic_digraph = Digraph.new{}, + events = {}, + node_names = {}, + coroutine = nil, + collections = {}, + }), Scope) end --- Done +-- Done -return Scope
\ No newline at end of file +return Scope diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered.lua index dd897fbe8ac..6988e7a3d9d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered.lua @@ -20,7 +20,7 @@ require("pgf.gd").layered = layered local lib = require "pgf.gd.lib" local Storage = require "pgf.gd.lib.Storage" --- +-- -- This file defines some basic functions to compute and/or set the -- ideal distances between nodes of any kind of layered drawing of a -- graph. @@ -30,7 +30,7 @@ local Storage = require "pgf.gd.lib.Storage" -- Compute the ideal distance between two siblings -- -- @param paddings A |Storage| object in which the computed distances --- (paddings) are stored. +-- (paddings) are stored. -- @param graph The graph object -- @param n1 The first node -- @param n2 The second node @@ -55,9 +55,9 @@ function layered.ideal_sibling_distance (paddings, graph, n1, n2) sep = (n1_is_node and lib.lookup_option('sibling post sep', n1, graph) or 0) + (n2_is_node and lib.lookup_option('sibling pre sep', n2, graph) or 0) end - - return math.max(ideal_distance, sep + - ((n1_is_node and paddings[n1].sibling_post) or 0) - + + return math.max(ideal_distance, sep + + ((n1_is_node and paddings[n1].sibling_post) or 0) - ((n2_is_node and paddings[n2].sibling_pre) or 0)) end @@ -88,7 +88,7 @@ function layered.baseline_distance (paddings, graph, l1, l2) if #l1 == 0 or #l2 == 0 then return 0 end - + local layer_distance = -math.huge local layer_pre_sep = -math.huge local layer_post_sep = -math.huge @@ -110,7 +110,7 @@ function layered.baseline_distance (paddings, graph, l1, l2) min_pre = math.min(min_pre, paddings[n].layer_pre) end end - + return math.max(layer_distance, layer_post_sep + layer_pre_sep + max_post - min_pre) end @@ -121,18 +121,18 @@ end -- -- @param layers A |Storage| object assigning layers to vertices. -- @param paddings A |Storage| object storing the computed distances --- (paddings). +-- (paddings). -- @param graph The graph in which the nodes reside function layered.arrange_layers_by_baselines (layers, paddings, graph) local layer_vertices = Storage.newTableStorage() - + -- Decompose into layers: for _,v in ipairs(graph.vertices) do table.insert(layer_vertices[layers[v]], v) end - + if #layer_vertices > 0 then -- sanity check -- Now compute ideal distances and store local height = 0 @@ -140,12 +140,12 @@ function layered.arrange_layers_by_baselines (layers, paddings, graph) for _,v in ipairs(layer_vertices[1]) do v.pos.y = 0 end - + for i=2,#layer_vertices do height = height + layered.baseline_distance(paddings, graph, layer_vertices[i-1], layer_vertices[i]) for _,v in ipairs(layer_vertices[i]) do - v.pos.y = height + v.pos.y = height end end end @@ -156,4 +156,4 @@ end -- Done -return layered
\ No newline at end of file +return layered diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua index 3fe3eac2552..da9ff9698c0 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua @@ -58,7 +58,7 @@ function CrossingMinimizationGansnerKNV1993:computeInitialRankOrdering() local function init(search) for i=#self.graph.nodes,1,-1 do - local node = self.graph.nodes[i] + local node = self.graph.nodes[i] if direction == 'down' then if node:getInDegree() == 0 then search:push(node) @@ -81,7 +81,7 @@ function CrossingMinimizationGansnerKNV1993:computeInitialRankOrdering() self.ranking:setRankPosition(node, pos) if direction == 'down' then - local out = node:getOutgoingEdges() + local out = node:getOutgoingEdges() for i=#out,1,-1 do local neighbour = out[i]:getNeighbour(node) if not search:getDiscovered(neighbour) then @@ -90,9 +90,9 @@ function CrossingMinimizationGansnerKNV1993:computeInitialRankOrdering() end end else - local into = node:getIncomingEdges() - for i=#into,1,-1 do - local neighbour = into[i]:getNeighbour(node) + local into = node:getIncomingEdges() + for i=#into,1,-1 do + local neighbour = into[i]:getNeighbour(node) if not search:getDiscovered(neighbour) then search:push(neighbour) search:setDiscovered(neighbour) @@ -122,7 +122,7 @@ function CrossingMinimizationGansnerKNV1993:countRankCrossings(ranking) local crossings = 0 local ranks = ranking:getRanks() - + for rank_index = 2, #ranks do local nodes = ranking:getNodes(ranks[rank_index]) for i = 1, #nodes-1 do @@ -170,7 +170,7 @@ function CrossingMinimizationGansnerKNV1993:countNodeCrossings(ranking, left_nod left_edges = left_node:getOutgoingEdges() right_edges = right_node:getOutgoingEdges() end - + local crossings = 0 local function left_neighbour_on_other_rank(edge) @@ -186,20 +186,20 @@ function CrossingMinimizationGansnerKNV1993:countNodeCrossings(ranking, left_nod for _,left_edge in ipairs(left_edges) do if left_neighbour_on_other_rank(left_edge) then local left_neighbour = left_edge:getNeighbour(left_node) - + for _,right_edge in ipairs(right_edges) do - if right_neighbour_on_other_rank(right_edge) then - local right_neighbour = right_edge:getNeighbour(right_node) - - local left_position = ranking:getRankPosition(left_neighbour) - local right_position = ranking:getRankPosition(right_neighbour) - - local neighbour_diff = right_position - left_position - - if neighbour_diff < 0 then - crossings = crossings + 1 - end - end + if right_neighbour_on_other_rank(right_edge) then + local right_neighbour = right_edge:getNeighbour(right_node) + + local left_position = ranking:getRankPosition(left_neighbour) + local right_position = ranking:getRankPosition(right_neighbour) + + local neighbour_diff = right_position - left_position + + if neighbour_diff < 0 then + crossings = crossings + 1 + end + end end end end @@ -252,7 +252,7 @@ function CrossingMinimizationGansnerKNV1993:computeMedianPosition(node, prev_ran function (edge) local n = edge:getNeighbour(node) if self.ranking:getRank(n) == prev_rank then - return self.ranking:getRankPosition(n) + return self.ranking:getRankPosition(n) end end) diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua index 55207b845d3..76deb8adaf6 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990a.lua @@ -10,7 +10,6 @@ -- @release $Header$ - local CycleRemovalBergerS1990a = {} local lib = require("pgf.gd.lib") @@ -27,20 +26,20 @@ function CycleRemovalBergerS1990a:run() for _,node in ipairs(self.graph.nodes) do -- get all outgoing edges that have not been removed yet local out_edges = lib.imap(node:getOutgoingEdges(), - function (edge) - if not removed[edge] then return edge end - end) + function (edge) + if not removed[edge] then return edge end + end) -- get all incoming edges that have not been removed yet local in_edges = lib.imap(node:getIncomingEdges(), - function (edge) - if not removed[edge] then return edge end - end) + function (edge) + if not removed[edge] then return edge end + end) if #out_edges >= #in_edges then - -- we have more outgoing than incoming edges, reverse all incoming + -- we have more outgoing than incoming edges, reverse all incoming -- edges and mark all incident edges as removed - + for _,edge in ipairs(out_edges) do removed[edge] = true end @@ -72,4 +71,4 @@ end -- done -return CycleRemovalBergerS1990a
\ No newline at end of file +return CycleRemovalBergerS1990a diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua index 218ecbd2099..d8f28980c87 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalBergerS1990b.lua @@ -28,20 +28,20 @@ function CycleRemovalBergerS1990b:run() -- get all outgoing edges that have not been removed yet -- get all outgoing edges that have not been removed yet local out_edges = lib.imap(node:getOutgoingEdges(), - function (edge) - if not removed[edge] then return edge end - end) + function (edge) + if not removed[edge] then return edge end + end) -- get all incoming edges that have not been removed yet local in_edges = lib.imap(node:getIncomingEdges(), - function (edge) - if not removed[edge] then return edge end - end) + function (edge) + if not removed[edge] then return edge end + end) if #out_edges >= #in_edges then - -- we have more outgoing than incoming edges, reverse all incoming + -- we have more outgoing than incoming edges, reverse all incoming -- edges and mark all incident edges as removed - + for _,edge in ipairs(out_edges) do removed[edge] = true end @@ -73,4 +73,4 @@ end -- done -return CycleRemovalBergerS1990b
\ No newline at end of file +return CycleRemovalBergerS1990b diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua index b480b7c4e70..e52b0d38d1a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CycleRemovalGansnerKNV1993.lua @@ -23,10 +23,10 @@ function CycleRemovalGansnerKNV1993:run () -- -- ignore self-loops -- - -- merge multiple edges into one edge each, whose weight is the sum of the + -- merge multiple edges into one edge each, whose weight is the sum of the -- individual edge weights -- - -- ignore leaf nodes that are not part of the user-defined sets (their ranks + -- ignore leaf nodes that are not part of the user-defined sets (their ranks -- are trivially determined) -- -- ensure that supernodes S_min and S_max are assigned first and last ranks @@ -36,10 +36,10 @@ function CycleRemovalGansnerKNV1993:run () -- ensure the supernodes S_min and S_max are are the only nodes in these ranks -- for all nodes with indegree of 0, insert temporary edge (S_min, v) with delta=0 -- for all nodes with outdegree of 0, insert temporary edge (v, S_max) with delta=0 - + -- classify edges as tree/forward, cross and back edges using a DFS traversal local tree_or_forward_edges, cross_edges, back_edges = Simplifiers:classifyEdges(self.graph) - + -- reverse the back edges in order to make the graph acyclic for _,edge in ipairs(back_edges) do edge.reversed = true diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua index 40078405f90..0ccf7694cae 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NetworkSimplex.lua @@ -14,10 +14,10 @@ --- This file contains an implementation of the network simplex method ---- for node ranking and x coordinate optimization in layered drawing +--- for node ranking and x coordinate optimization in layered drawing --- algorithms, as proposed in --- ---- "A Technique for Drawing Directed Graphs" +--- "A Technique for Drawing Directed Graphs" -- by Gansner, Koutsofios, North, Vo, 1993. @@ -57,7 +57,7 @@ end function NetworkSimplex:run() assert (#self.graph.nodes > 0, "graph must contain at least one node") - + -- initialize the tree edge search index self.search_index = 1 @@ -72,7 +72,7 @@ function NetworkSimplex:run() self.low = {} self.parent_edge = {} self.ranking = Ranking.new() - + if #self.graph.nodes == 1 then self.ranking:setRank(self.graph.nodes[1], 1) else @@ -86,19 +86,19 @@ function NetworkSimplex:rankNodes() -- construct feasible tree of tight edges self:constructFeasibleTree() - -- iteratively replace edges with negative cut values + -- iteratively replace edges with negative cut values -- with non-tree edges (chosen by minimum slack) local leave_edge = self:findNegativeCutEdge() while leave_edge do local enter_edge = self:findReplacementEdge(leave_edge) - + assert(enter_edge, 'no non-tree edge to replace ' .. tostring(leave_edge) .. ' could be found') -- exchange leave_edge and enter_edge in the tree, updating -- the ranks and cut values of all nodes self:exchangeTreeEdges(leave_edge, enter_edge) - -- find the next tree edge with a negative cut value, if + -- find the next tree edge with a negative cut value, if -- there are any left leave_edge = self:findNegativeCutEdge() end @@ -108,7 +108,7 @@ function NetworkSimplex:rankNodes() self.ranking:normalizeRanks() -- move nodes to feasible ranks with the least number of nodes - -- in order to avoid crowding and to improve the overall aspect + -- in order to avoid crowding and to improve the overall aspect -- ratio of the drawing self:balanceRanksTopBottom() elseif self.balancing == NetworkSimplex.BALANCE_LEFT_RIGHT then @@ -140,7 +140,7 @@ function NetworkSimplex:constructFeasibleTree() if min_slack_edge then local delta = self:edgeSlack(min_slack_edge) - + if delta > 0 then local head = min_slack_edge:getHead() local tail = min_slack_edge:getTail() @@ -193,7 +193,7 @@ function NetworkSimplex:findReplacementEdge(leave_edge) local v = nil local direction = nil - + if self.lim[tail] < self.lim[head] then v = tail direction = 'in' @@ -206,7 +206,7 @@ function NetworkSimplex:findReplacementEdge(leave_edge) local enter_edge = nil local slack = math.huge - -- TODO Janns: Get rid of this recursion: + -- TODO Jannis: Get rid of this recursion: local function find_edge(v, direction) @@ -250,7 +250,7 @@ function NetworkSimplex:findReplacementEdge(leave_edge) local tree_tail = self.tree_node[tail] assert(tail and tree_tail) - + if not self.tree_edge[edge] then if not self:inTailComponentOf(tree_tail, search_root) then if self:edgeSlack(edge) < slack or not enter_edge then @@ -280,7 +280,7 @@ function NetworkSimplex:findReplacementEdge(leave_edge) end find_edge(v, direction) - + return enter_edge end @@ -293,7 +293,7 @@ function NetworkSimplex:exchangeTreeEdges(leave_edge, enter_edge) local cutval = self.cut_value[leave_edge] local head = self.tree_node[enter_edge:getHead()] local tail = self.tree_node[enter_edge:getTail()] - + local ancestor = self:updateCutValuesUpToCommonAncestor(tail, head, cutval, true) local other_ancestor = self:updateCutValuesUpToCommonAncestor(head, tail, cutval, false) @@ -322,7 +322,7 @@ function NetworkSimplex:balanceRanksTopBottom() -- node to in/out weight mappings local in_weight = {} local out_weight = {} - + -- node to lowest/highest possible rank mapping local min_rank = {} local max_rank = {} @@ -335,22 +335,22 @@ function NetworkSimplex:balanceRanksTopBottom() for _,edge in ipairs(node:getIncomingEdges()) do -- accumulate the weights of all incoming edges in_weight[node] = (in_weight[node] or 0) + edge.weight - + -- update the minimum allowed rank (which is the maximum of - -- the ranks of all parent neighbours plus the minimum level + -- the ranks of all parent neighbors plus the minimum level -- separation caused by the connecting edges) local neighbour = edge:getNeighbour(node) local neighbour_rank = self.ranking:getRank(neighbour) min_rank[node] = math.max(min_rank[node], neighbour_rank + edge.minimum_levels) end - + for _,edge in ipairs(node:getOutgoingEdges()) do -- accumulate the weights of all outgoing edges out_weight[node] = (out_weight[node] or 0) + edge.weight -- update the maximum allowed rank (which is the minimum of - -- the ranks of all child neighbours minus the minimum level - -- sparation caused by the connecting edges) + -- the ranks of all child neighbors minus the minimum level + -- separation caused by the connecting edges) local neighbour = edge:getNeighbour(node) local neighbour_rank = self.ranking:getRank(neighbour) max_rank[node] = math.min(max_rank[node], neighbour_rank - edge.minimum_levels) @@ -400,7 +400,7 @@ end function NetworkSimplex:computeInitialRanking() - + -- queue for nodes to rank next local queue = {} @@ -408,7 +408,7 @@ function NetworkSimplex:computeInitialRanking() local function enqueue(node) table.insert(queue, node) end local function dequeue() return table.remove(queue, 1) end - -- reset the two-dimensional mapping from ranks to lists + -- reset the two-dimensional mapping from ranks to lists -- of corresponding nodes self.ranking:reset() @@ -418,7 +418,7 @@ function NetworkSimplex:computeInitialRanking() -- add all sinks to the queue for _,node in ipairs(self.graph.nodes) do local edges = node:getIncomingEdges() - + remaining_edges[node] = #edges if #edges == 0 then @@ -428,23 +428,23 @@ function NetworkSimplex:computeInitialRanking() -- run long as there are nodes to be ranked while #queue > 0 do - + -- fetch the next unranked node from the queue local node = dequeue() -- get a list of its incoming edges local in_edges = node:getIncomingEdges() - + -- determine the minimum possible rank for the node local rank = 1 for _,edge in ipairs(in_edges) do local neighbour = edge:getNeighbour(node) if self.ranking:getRank(neighbour) then - -- the minimum possible rank is the maximum of all neighbour ranks plus + -- the minimum possible rank is the maximum of all neighbor ranks plus -- the corresponding edge lengths rank = math.max(rank, self.ranking:getRank(neighbour) + edge.minimum_levels) end - end + end -- rank the node self.ranking:setRank(node, rank) @@ -452,7 +452,7 @@ function NetworkSimplex:computeInitialRanking() -- get a list of the node's outgoing edges local out_edges = node:getOutgoingEdges() - -- queue neighbours of nodes for which all incoming edges have been scanned + -- queue neighbors of nodes for which all incoming edges have been scanned for _,edge in ipairs(out_edges) do local head = edge:getHead() remaining_edges[head] = remaining_edges[head] - 1 @@ -480,7 +480,7 @@ function NetworkSimplex:findTightTree() for _,v in ipairs(in_edges) do edges[#edges + 1] = v end - + for _,edge in ipairs(edges) do local neighbour = edge:getNeighbour(node) if (not marked[neighbour]) and math.abs(self:edgeSlack(edge)) < 0.00001 then @@ -489,7 +489,7 @@ function NetworkSimplex:findTightTree() for _,node in ipairs(edge.nodes) do marked[node] = true end - + if #self.tree.edges == #self.graph.nodes-1 then return true end @@ -502,7 +502,7 @@ function NetworkSimplex:findTightTree() return false end - + for _,node in ipairs(self.graph.nodes) do self.tree = Graph.new() self.tree_node = {} @@ -511,7 +511,7 @@ function NetworkSimplex:findTightTree() self.orig_edge = {} build_tight_tree(node) - + if #self.tree.edges > 0 then break end @@ -561,10 +561,10 @@ function NetworkSimplex:initializeCutValues() local function visit(search, data) search:setVisited(data, true) - + local into = data.node:getIncomingEdges() local out = data.node:getOutgoingEdges() - + for i=#into,1,-1 do local edge = into[i] if edge ~= data.parent_edge then @@ -621,10 +621,10 @@ function NetworkSimplex:calculateDFSRange(root, edge_from_parent, lowest) -- next we push all outgoing and incoming edges in reverse order -- to simulate recursive calls - + local into = data.node:getIncomingEdges() local out = data.node:getOutgoingEdges() - + for i=#into,1,-1 do local edge = into[i] if edge ~= data.parent_edge then @@ -748,8 +748,8 @@ end function NetworkSimplex:nextSearchIndex() local index = 1 - - -- avoid tree edge index out of bounds by resetting the search index + + -- avoid tree edge index out of bounds by resetting the search index -- as soon as it leaves the range of edge indices in the tree if self.search_index > #self.tree.edges then self.search_index = 1 @@ -774,10 +774,10 @@ function NetworkSimplex:rerank(node, delta) local orig_node = self.orig_node[data.node] self.ranking:setRank(orig_node, self.ranking:getRank(orig_node) - data.delta) - + local into = data.node:getIncomingEdges() local out = data.node:getOutgoingEdges() - + for i=#into,1,-1 do local edge = into[i] if edge ~= self.parent_edge[data.node] then @@ -800,10 +800,10 @@ end function NetworkSimplex:rerankBeforeReplacingEdge(leave_edge, enter_edge) local delta = self:edgeSlack(enter_edge) - + if delta > 0 then local tail = leave_edge:getTail() - + if #tail.edges == 1 then self:rerank(tail, delta) else @@ -863,8 +863,8 @@ function NetworkSimplex:addEdgeToTree(edge) -- create tree nodes if necessary for _,node in ipairs(edge.nodes) do - local tree_node - + local tree_node + if self.tree_node[node] then tree_node = self.tree_node[node] else diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua index 3af15ad1593..3e5a0f8f873 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodePositioningGansnerKNV1993.lua @@ -32,9 +32,9 @@ function NodePositioningGansnerKNV1993:run() local simplex = NetworkSimplex.new(auxiliary_graph, NetworkSimplex.BALANCE_LEFT_RIGHT) simplex:run() local x_ranking = simplex.ranking - + local layers = Storage.new() - + local ranks = self.ranking:getRanks() for _,rank in ipairs(ranks) do local nodes = self.ranking:getNodes(rank) @@ -45,7 +45,7 @@ function NodePositioningGansnerKNV1993:run() end layered.arrange_layers_by_baselines(layers, self.main_algorithm.adjusted_bb, self.main_algorithm.ugraph) - + -- Copy back for _,rank in ipairs(ranks) do local nodes = self.ranking:getNodes(rank) diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua index 4a53acf8646..d6765ae2f0a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingGansnerKNV1993.lua @@ -142,7 +142,7 @@ function NodeRankingGansnerKNV1993:expandClusters() end self.graph:addEdge(edge) end - + for _,node in ipairs(self.cluster_nodes) do self.ranking:setRank(node, nil) self.graph:deleteNode(node) diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua index 8aa98bd03ad..644b99c28a9 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/NodeRankingMinimumHeight.lua @@ -28,8 +28,8 @@ function NodeRankingMinimumHeight:run() ranking:setRank(node, 1) else local max_rank = -math.huge - for _,edge in ipairs(edge) do - max_rank = math.max(max_rank, ranking:getRank(edge:getNeighbour(node))) + for _,edge in ipairs(edges) do + max_rank = math.max(max_rank, ranking:getRank(edge:getNeighbour(node))) end assert(max_rank >= 1) @@ -44,4 +44,4 @@ end -- done -return NodeRankingMinimumHeight
\ No newline at end of file +return NodeRankingMinimumHeight diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Ranking.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Ranking.lua index 228039b536f..6ed63b0249d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Ranking.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Ranking.lua @@ -12,8 +12,8 @@ ---- The Ranking class is used by the Sugiyama algorithm to compute an ordering on the --- nodes of a layer +--- The Ranking class is used by the Sugiyama algorithm to compute an +-- ordering on the nodes of a layer local Ranking = {} Ranking.__index = Ranking @@ -43,7 +43,7 @@ end function Ranking:copy() local copied_ranking = Ranking.new() - + -- copy rank to nodes mapping for rank, nodes in pairs(self.rank_to_nodes) do copied_ranking.rank_to_nodes[rank] = lib.copy(self.rank_to_nodes[rank]) @@ -113,7 +113,7 @@ function Ranking:setRank(node, new_rank) if rank == new_rank then return end - + if rank then for n = pos+1, #self.rank_to_nodes[rank] do local other_node = self.rank_to_nodes[rank][n] @@ -196,7 +196,7 @@ function Ranking:normalizeRanks() for node in pairs(self.position_in_rank) do local rank, pos = self:getNodeInfo(node) local new_rank = rank - (min_rank - 1) - + self.rank_to_nodes[new_rank] = self.rank_to_nodes[new_rank] or {} self.rank_to_nodes[new_rank][pos] = node diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua index 3ab9596322d..c91818dc300 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/Sugiyama.lua @@ -42,7 +42,7 @@ local Vector = require "pgf.gd.deprecated.Vector" declare { key = "layered layout", algorithm = Sugiyama, - + preconditions = { connected = true, loop_free = true, @@ -54,46 +54,44 @@ declare { old_graph_model = true, - summary = [[" - The |layered layout| is the key used to select the modular Sugiyama - layout algorithm. + summary = [[" + The |layered layout| is the key used to select the modular Sugiyama + layout algorithm. "]], documentation = [[" - This algorithm consists of five consecutive steps, each of which can be - configured independently of the other ones (how this is done is - explained later in this section). Naturally, the ``best'' heuristics - are selected by default, so there is typically no need to change the - settings, but what is the ``best'' method for one graph need not be - the best one for another graph. - - As can be seen in the first example, the algorithm will not only - position the nodes of a graph, but will also perform an edge - routing. This will look visually quite pleasing if you add the - |rounded corners| option: + This algorithm consists of five consecutive steps, each of which can be + configured independently of the other ones (how this is done is + explained later in this section). Naturally, the ``best'' heuristics + are selected by default, so there is typically no need to change the + settings, but what is the ``best'' method for one graph need not be + the best one for another graph. + + As can be seen in the first example, the algorithm will not only + position the nodes of a graph, but will also perform an edge + routing. This will look visually quite pleasing if you add the + |rounded corners| option: "]], - examples = { - [[" - \tikz \graph [layered layout, sibling distance=7mm] - { - a -> { - b, - c -> { d, e, f } - } -> - h -> - a - }; - "]], - [[" - \tikz [rounded corners] \graph [layered layout, sibling distance=7mm] - { - a -> { - b, - c -> { d, e, f } - } -> - h -> - a - }; - "]] + examples = {[[" + \tikz \graph [layered layout, sibling distance=7mm] + { + a -> { + b, + c -> { d, e, f } + } -> + h -> + a + }; + "]],[[" + \tikz [rounded corners] \graph [layered layout, sibling distance=7mm] + { + a -> { + b, + c -> { d, e, f } + } -> + h -> + a + }; + "]] } } @@ -104,16 +102,16 @@ declare { type = "number", initial = "1", - summary = [[" - The minimum number of levels that an edge must span. It is a bit of - the opposite of the |weight| parameter: While a large |weight| - causes an edge to become shorter, a larger |minimum layers| value - causes an edge to be longer. + summary = [[" + The minimum number of levels that an edge must span. It is a bit of + the opposite of the |weight| parameter: While a large |weight| + causes an edge to become shorter, a larger |minimum layers| value + causes an edge to be longer. "]], examples = [[" - \tikz \graph [layered layout] { - a -- {b [> minimum layers=3], c, d} -- e -- a; - }; + \tikz \graph [layered layout] { + a -- {b [> minimum layers=3], c, d} -- e -- a; + }; "]] } @@ -124,48 +122,48 @@ declare { key = "same layer", layer = 0, - summary = [[" - The |same layer| collection allows you to enforce that several nodes - a on the same layer of a layered layout (this option is also known - as |same rank|). You use it like this: + summary = [[" + The |same layer| collection allows you to enforce that several nodes + a on the same layer of a layered layout (this option is also known + as |same rank|). You use it like this: "]], examples = {[[" - \tikz \graph [layered layout] { - a -- b -- c -- d -- e; - - { [same layer] a, b }; - { [same layer] d, e }; - }; + \tikz \graph [layered layout] { + a -- b -- c -- d -- e; + + { [same layer] a, b }; + { [same layer] d, e }; + }; "]],[[" - \tikz [rounded corners] \graph [layered layout] { - 1972 -> 1976 -> 1978 -> 1980 -> 1982 -> 1984 -> 1986 -> 1988 -> 1990 -> future; - - { [same layer] 1972, Thompson }; - { [same layer] 1976, Mashey, Bourne }, - { [same layer] 1978, Formshell, csh }, - { [same layer] 1980, esh, vsh }, - { [same layer] 1982, ksh, "System-V" }, - { [same layer] 1984, v9sh, tcsh }, - { [same layer] 1986, "ksh-i" }, - { [same layer] 1988, KornShell ,Perl, rc }, - { [same layer] 1990, tcl, Bash }, - { [same layer] "future", POSIX, "ksh-POSIX" }, - - Thompson -> { Mashey, Bourne, csh -> tcsh}, - Bourne -> { ksh, esh, vsh, "System-V", v9sh -> rc, Bash}, - { "ksh-i", KornShell } -> Bash, - { esh, vsh, Formshell, csh } -> ksh, - { KornShell, "System-V" } -> POSIX, - ksh -> "ksh-i" -> KornShell -> "ksh-POSIX", - Bourne -> Formshell, - - { [edge={draw=none}] - Bash -> tcl, - KornShell -> Perl - } - }; - "]] - } + \tikz [rounded corners] \graph [layered layout] { + 1972 -> 1976 -> 1978 -> 1980 -> 1982 -> 1984 -> 1986 -> 1988 -> 1990 -> future; + + { [same layer] 1972, Thompson }; + { [same layer] 1976, Mashey, Bourne }, + { [same layer] 1978, Formshell, csh }, + { [same layer] 1980, esh, vsh }, + { [same layer] 1982, ksh, "System-V" }, + { [same layer] 1984, v9sh, tcsh }, + { [same layer] 1986, "ksh-i" }, + { [same layer] 1988, KornShell ,Perl, rc }, + { [same layer] 1990, tcl, Bash }, + { [same layer] "future", POSIX, "ksh-POSIX" }, + + Thompson -> { Mashey, Bourne, csh -> tcsh}, + Bourne -> { ksh, esh, vsh, "System-V", v9sh -> rc, Bash}, + { "ksh-i", KornShell } -> Bash, + { esh, vsh, Formshell, csh } -> ksh, + { KornShell, "System-V" } -> POSIX, + ksh -> "ksh-i" -> KornShell -> "ksh-POSIX", + Bourne -> Formshell, + + { [edge={draw=none}] + Bash -> tcl, + KornShell -> Perl + } + }; + "]] + } } @@ -176,15 +174,15 @@ function Sugiyama:run() if #self.graph.nodes <= 1 then return end - + local options = self.digraph.options - - local cycle_removal_algorithm_class = options.algorithm_phases['cycle removal'] + + local cycle_removal_algorithm_class = options.algorithm_phases['cycle removal'] local node_ranking_algorithm_class = options.algorithm_phases['node ranking'] local crossing_minimization_algorithm_class = options.algorithm_phases['crossing minimization'] local node_positioning_algorithm_class = options.algorithm_phases['node positioning'] local edge_routing_algorithm_class = options.algorithm_phases['layer edge routing'] - + self:preprocess() -- Helper function for collapsing multiedges @@ -197,14 +195,14 @@ function Sugiyama:run() -- Create a subalgorithm object. Needed so that removed loops -- are not stored on top of removed loops from main call. - local cluster_subalgorithm = { graph = self.graph } + local cluster_subalgorithm = { graph = self.graph } self.graph:registerAlgorithm(cluster_subalgorithm) self:mergeClusters() Simplifiers:removeLoopsOldModel(cluster_subalgorithm) Simplifiers:collapseMultiedgesOldModel(cluster_subalgorithm, collapse) - + cycle_removal_algorithm_class.new { main_algorithm = self, graph = self.graph }:run() self.ranking = node_ranking_algorithm_class.new{ main_algorithm = self, graph = self.graph }:run() self:restoreCycles() @@ -213,12 +211,12 @@ function Sugiyama:run() Simplifiers:restoreLoopsOldModel(cluster_subalgorithm) self:expandClusters() - + -- Now do actual computation Simplifiers:collapseMultiedgesOldModel(cluster_subalgorithm, collapse) cycle_removal_algorithm_class.new{ main_algorithm = self, graph = self.graph }:run() self:insertDummyNodes() - + -- Main algorithm crossing_minimization_algorithm_class.new{ main_algorithm = self, @@ -230,13 +228,13 @@ function Sugiyama:run() graph = self.graph, ranking = self.ranking }:run() - + -- Cleanup self:removeDummyNodes() Simplifiers:expandMultiedgesOldModel(cluster_subalgorithm) edge_routing_algorithm_class.new{ main_algorithm = self, graph = self.graph }:run() self:restoreCycles() - + end @@ -281,14 +279,14 @@ function Sugiyama:insertDummyNodes() local dummy = Node.new{ pos = Vector.new(), name = 'dummy@' .. neighbour.name .. '@to@' .. node.name .. '@at@' .. rank, - kind = "dummy", - orig_vertex = pgf.gd.model.Vertex.new{} + kind = "dummy", + orig_vertex = pgf.gd.model.Vertex.new{} } dummy_id = dummy_id + 1 self.graph:addNode(dummy) - self.ugraph:add {dummy.orig_vertex} + self.ugraph:add {dummy.orig_vertex} self.ranking:setRank(dummy, rank) @@ -306,7 +304,7 @@ function Sugiyama:insertDummyNodes() local target = dummies[i] local dummy_edge = Edge.new{ - direction = Edge.RIGHT, + direction = Edge.RIGHT, reversed = false, weight = edge.weight, -- TODO or should we divide the weight of the original edge by the number of virtual edges? } @@ -354,8 +352,8 @@ function Sugiyama:removeDummyNodes() if edge.reversed then local bp = edge.bend_points for i=1,#bp/2 do - local j = #bp + 1 - i - bp[i], bp[j] = bp[j], bp[i] + local j = #bp + 1 - i + bp[i], bp[j] = bp[j], bp[i] end end @@ -375,7 +373,7 @@ function Sugiyama:mergeClusters() self.original_nodes = {} for _,cluster in ipairs(self.graph.clusters) do - + local cluster_node = cluster.nodes[1] table.insert(self.cluster_nodes, cluster_node) @@ -475,4 +473,4 @@ end -- done -return Sugiyama
\ No newline at end of file +return Sugiyama diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua index 6bede7eb015..54a1fafb231 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua @@ -48,11 +48,11 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- the nodes of a specific layer are reordered using a neighbored -- layer as a fixed reference. This problem is known as one-sided -- crossing minimization, which unfortunately is NP-hard. In the --- following various heuristics to solve this problem are +-- following various heuristics to solve this problem are -- presented. -- -- For more details, please see Section 4.1.4 of Pohlmann's Diploma --- thesis. +-- thesis. -- -- @end @@ -66,16 +66,16 @@ declare { phase = "crossing minimization", phase_default = true, - summary = [[" - Gansner et al. combine an initial ordering based on a depth-first - search with the median and greedy switch heuristics applied in the - form of an alternating layer-by-layer sweep based on a weighted - median. + summary = [[" + Gansner et al. combine an initial ordering based on a depth-first + search with the median and greedy switch heuristics applied in the + form of an alternating layer-by-layer sweep based on a weighted + median. "]], - documentation = [[" - For more details, please see Section 4.1.4 of Pohlmann's Diploma - thesis. - - This is the default algorithm for crossing minimization. - "]] - } + documentation = [[" + For more details, please see Section~4.1.4 of Pohlmann's Diploma + thesis. + + This is the default algorithm for crossing minimization. + "]] +} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua index 63c43f5b14f..18670df14e8 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/cycle_removal.lua @@ -34,39 +34,38 @@ declare { phase = "cycle removal", phase_default = true, - summary = [[" - Selects a cycle removal algorithm that is especially - appropriate for graphs specified ``by hand''. + summary = [[" + Selects a cycle removal algorithm that is especially + appropriate for graphs specified ``by hand''. "]], - documentation = [[" - When graphs are created by humans manually, one can - make assumptions about the input graph that would otherwise not - be possible. For instance, it seems reasonable to assume that the - order in which nodes and edges are entered by the user somehow - reflects the natural flow the user has had in mind for the graph. - - In order to preserve the natural flow of the input graph, Gansner - et al.\ propose to remove cycles by performing a series of - depth-first searches starting at individual nodes in the order they - appear in the graph. This algorithm - implicitly constructs a spanning tree of the nodes reached during - the searches. It thereby partitions the edges of the graph into - tree edges and non-tree edges. The non-tree edges are further - subdivided into forward edges, cross edges, and back edges. Forward - edges point from a tree nodes to one of their descendants. Cross - edges connect unrelated branches in - the search tree. Back edges connect descendants to one of their - ancestors. It is not hard to see that reversing back edges will not - only introduce no new cycles but will also make any directed graph - acyclic. Gansner et al.\ argue that this approach is more stable - than others in that fewer inappropriate edges are reversed compared - to other methods, despite the lack of a provable upper bound - for the number of reversed edges. - - See section 4.1.1 of Pohlmann's Diplom thesis for more details. - - This is the default algorithm for cycle removals. - "]] + documentation = [[" + When graphs are created by humans manually, one can + make assumptions about the input graph that would otherwise not + be possible. For instance, it seems reasonable to assume that the + order in which nodes and edges are entered by the user somehow + reflects the natural flow the user has had in mind for the graph. + + In order to preserve the natural flow of the input graph, Gansner + et al.\ propose to remove cycles by performing a series of + depth-first searches starting at individual nodes in the order they + appear in the graph. This algorithm implicitly constructs a spanning + tree of the nodes reached during the searches. It thereby partitions + the edges of the graph into tree edges and non-tree edges. The + non-tree edges are further subdivided into forward edges, cross edges, + and back edges. Forward edges point from a tree nodes to one of their + descendants. Cross edges connect unrelated branches in the search tree. + Back edges connect descendants to one of their ancestors. It is not + hard to see that reversing back edges will not only introduce no new + cycles but will also make any directed graph acyclic. + Gansner et al.\ argue that this approach is more stable than others + in that fewer inappropriate edges are reversed compared to other + methods, despite the lack of a provable upper bound for the number + of reversed edges. + + See section~4.1.1 of Pohlmann's Diplom thesis for more details. + + This is the default algorithm for cycle removals. + "]] } --- @@ -76,12 +75,12 @@ declare { algorithm = "pgf.gd.layered.CycleRemovalEadesLS1993", phase = "cycle removal", - summary = [[" - This algorithm implements a greedy heuristic of Eades et al.\ for - cycle removal that prioritizes sources and sinks. + summary = [[" + This algorithm implements a greedy heuristic of Eades et al.\ for + cycle removal that prioritizes sources and sinks. "]], - documentation = [[" - See section 4.1.1 of Pohlmann's Diploma theses for details. + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. "]] } @@ -93,12 +92,12 @@ declare { algorithm = "pgf.gd.layered.CycleRemovalEadesLS1993", phase = "cycle removal", - summary = [[" - This algorithm implements a greedy heuristic of Eades et al.\ for - cycle removal that prioritizes sources and sinks. + summary = [[" + This algorithm implements a greedy heuristic of Eades et al.\ for + cycle removal that prioritizes sources and sinks. "]], - documentation = [[" - See section 4.1.1 of Pohlmann's Diploma theses for details. + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. "]] } @@ -109,14 +108,13 @@ declare { algorithm = "pgf.gd.layered.CycleRemovalBergerS1990a", phase = "cycle removal", - summary = [[" - This algorithm implements a greedy heuristic of Berger and Shor for - cycle removal. It - is not really compared to the other heuristics and only included - for demonstration purposes. + summary = [[" + This algorithm implements a greedy heuristic of Berger and Shor for + cycle removal. It is not really compared to the other heuristics and + only included for demonstration purposes. "]], - documentation = [[" - See section 4.1.1 of Pohlmann's Diploma theses for details. + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. "]] } @@ -127,13 +125,12 @@ declare { algorithm = "pgf.gd.layered.CycleRemovalBergerS1990b", phase = "cycle removal", - summary = [[" - This algorithm implements a randomized greedy heuristic of Berger - and Shor for cycle removal. It, too, is not really compared to - the other heuristics and only included for demonstration purposes. + summary = [[" + This algorithm implements a randomized greedy heuristic of Berger + and Shor for cycle removal. It, too, is not really compared to + the other heuristics and only included for demonstration purposes. "]], - documentation = [[" - See section 4.1.1 of Pohlmann's Diploma theses for details. + documentation = [[" + See section~4.1.1 of Pohlmann's Diploma theses for details. "]] - } - + }
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/edge_routing.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/edge_routing.lua index b790d527e3d..eb9939c74ce 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/edge_routing.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/edge_routing.lua @@ -21,10 +21,10 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- step. This makes sense if all nodes have the same size and -- shape. In practical scenarios, however, this assumption often does -- not hold. In these cases, advanced techniques may have to be --- applied in order to avoid overlaps of nodes and edges. +-- applied in order to avoid overlaps of nodes and edges. -- --- For more details, please see Section 4.1.5 of Pohlmann's Diploma --- thesis. +-- For more details, please see Section~4.1.5 of Pohlmann's Diploma +-- thesis. -- -- @end @@ -38,13 +38,12 @@ declare { phase = "layer edge routing", phase_default = true, - summary = [[" - This edge routing algorithm uses polygonal lines to connect nodes. + summary = [[" + This edge routing algorithm uses polygonal lines to connect nodes. "]], - documentation = [[" - For more details, please see Section 4.1.5 of Pohlmann's Diploma - thesis. - - This is the default algorithm for edge routing. - "]] - } + documentation = [[" + For more details, please see Section~4.1.5 of Pohlmann's Diploma thesis. + + This is the default algorithm for edge routing. + "]] +} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/library.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/library.lua index 9f681929ecb..950e02ffa36 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/library.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/library.lua @@ -30,34 +30,37 @@ -- implemented it as part of his Diploma thesis. Please consult this -- thesis for a detailed explanation of the Sugiyama method and its -- history: --- +-- % -- \begin{itemize} --- \item --- Jannis Pohlmann, --- \newblock \emph{Configurable Graph Drawing Algorithms --- for the \tikzname\ Graphics Description Language,} --- \newblock Diploma Thesis, --- \newblock Institute of Theoretical Computer Science, Univerist\"at --- zu L\"ubeck, 2011.\\[.5em] --- \newblock Available online via --- \url{http://www.tcs.uni-luebeck.de/downloads/papers/2011/}\\ \url{2011-configurable-graph-drawing-algorithms-jannis-pohlmann.pdf} --- \\[.5em] --- (Note that since the publication of this thesis some option names --- have been changed. Most noticeably, the option name --- |layered drawing| was changed to |layered layout|, which is somewhat --- more consistent with other names used in the graph drawing --- libraries. Furthermore, the keys for choosing individual --- algorithms for the different algorithm phases, have all changed.) +-- \item +-- Jannis Pohlmann, +-- \newblock \emph{Configurable Graph Drawing Algorithms +-- for the \tikzname\ Graphics Description Language,} +-- \newblock Diploma Thesis, +-- \newblock Institute of Theoretical Computer Science, Universit\"at +-- zu L\"ubeck, 2011.\\[.5em] +-- \newblock Available online via +-- \url{http://www.tcs.uni-luebeck.de/downloads/papers/2011/}\\ +-- \url{2011-configurable-graph-drawing-algorithms-jannis-pohlmann.pdf} +-- \\[.5em] +-- (Note that since the publication of this thesis some option names +-- have been changed. Most noticeably, the option name +-- |layered drawing| was changed to |layered layout|, which is somewhat +-- more consistent with other names used in the graph drawing +-- libraries. Furthermore, the keys for choosing individual +-- algorithms for the different algorithm phases, have all changed.) -- \end{itemize} -- -- The Sugiyama methods lays out a graph in five steps: +-- % -- \begin{enumerate} --- \item Cycle removal. --- \item Layer assignment (sometimes called node ranking). --- \item Crossing minimization (also referred to as node ordering). --- \item Node positioning (or coordinate assignment). --- \item Edge routing. +-- \item Cycle removal. +-- \item Layer assignment (sometimes called node ranking). +-- \item Crossing minimization (also referred to as node ordering). +-- \item Node positioning (or coordinate assignment). +-- \item Edge routing. -- \end{enumerate} +-- % -- It turns out that behind each of these steps there lurks an -- NP-complete problem, which means, in practice, that each step is -- impossible to perform optimally for larger graphs. For this reason, @@ -67,11 +70,11 @@ -- A distinctive feature of Pohlmann's implementation of the Sugiyama -- method for \tikzname\ is that the algorithms used for each of the -- steps can easily be exchanged, just specify a different option. For --- the user, this means that by specifying a different --- option and thereby using a different heuristic for one of the steps, a --- better layout can often be found. For the researcher, this means that --- one can very easily test new approaches and new heuristics without --- having to implement all of the other steps anew. +-- the user, this means that by specifying a different option and thereby +-- using a different heuristic for one of the steps, a better layout can +-- often be found. For the researcher, this means that one can very +-- easily test new approaches and new heuristics without having to +-- implement all of the other steps anew. -- -- @library diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_positioning.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_positioning.lua index 8fa55f9cbb9..e51382d6427 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_positioning.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_positioning.lua @@ -22,15 +22,14 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- small and edges are drawn as vertically as possible. Another goal -- is to avoid node and edge overlaps which is crucial in particular -- if the nodes are allowed to have non-uniform sizes. The --- y-coordinates of the nodes have no influence on the number of +-- $y$-coordinates of the nodes have no influence on the number of -- bends. Obviously, nodes need to be separated enough geometrically -- so that they do not overlap. It feels natural to aim at separating -- all layers in the drawing by the same amount. Large nodes, however, -- may force node positioning algorithms to override this uniform --- level distance in order to avoid overlaps. +-- level distance in order to avoid overlaps. -- --- For more details, please see Section 4.1.2 of Pohlmann's Diploma --- thesis. +-- For more details, please see Section~4.1.2 of Pohlmann's Diploma thesis. -- -- @end @@ -44,14 +43,13 @@ declare { phase = "node positioning", phase_default = true, - summary = [[" - This node positioning method, due to Gasner et al., is based on a - linear optimization problem. + summary = [[" + This node positioning method, due to Gasner et al., is based on a + linear optimization problem. "]], - documentation = [[" - For more details, please see Section 4.1.3 of Pohlmann's Diploma - thesis. - - This is the default algorithm for layer assignments. - "]] - } + documentation = [[" + For more details, please see Section~4.1.3 of Pohlmann's Diploma thesis. + + This is the default algorithm for layer assignments. + "]] +} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_ranking.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_ranking.lua index 7aef0bde5fc..c663d9ce366 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_ranking.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/node_ranking.lua @@ -18,15 +18,15 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- -- Algorithms for producing layered drawings place nodes on discrete -- layers from top to bottom. Layer assignment is the problem of --- finding a partition so that for all edges $e = (u,v) \in E(G)$ the +-- finding a partition so that for all edges $e = (u,v) \in E(G)$ the -- equation $\mathit{layer}(u) < \mathit{layer}(v)$ holds. Such a -- partition is called a \emph{layering}. This definition can be extended by -- introducing edge weights or priorities and minimum length -- constraints which has practical applications and allows users to -- fine-tune the results. -- --- For more details, please see Section 4.1.2 of Pohlmann's Diploma --- thesis. +-- For more details, please see Section~4.1.2 of Pohlmann's Diploma +-- thesis. -- -- @end @@ -40,17 +40,17 @@ declare { phase = "node ranking", phase_default = true, - summary = [[" - This layer assigment method, due to Gasner et al., is based on a - linear optimization problem. + summary = [[" + This layer assignment method, due to Gasner et al., is based on a + linear optimization problem. "]], - documentation = [[" - For more details, please see Section 4.1.2 of Pohlmann's Diploma - thesis. - - This is the default algorithm for layer assignments. - "]] - } + documentation = [[" + For more details, please see Section~4.1.2 of Pohlmann's Diploma + thesis. + + This is the default algorithm for layer assignments. + "]] +} @@ -61,14 +61,12 @@ declare { algorithm = "pgf.gd.layered.NodeRankingMinimumHeight", phase = "node ranking", - summary = [[" - This layer assigment method minimizes the height of the resulting - graph. + summary = [[" + This layer assignment method minimizes the height of the resulting graph. "]], - documentation = [[" - For more details, please see Section 4.1.3 of Pohlmann's Diploma - thesis. - "]] - } + documentation = [[" + For more details, please see Section~4.1.3 of Pohlmann's Diploma thesis. + "]] +} diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua index bcd4f6cfc1e..cc39ddd6070 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib.lua @@ -67,7 +67,7 @@ end function lib.find_min(array, f) local best = math.huge local best_result - local best_index + local best_index for i=1,#array do local t = array[i] local result, p = f(t,i,array) @@ -89,9 +89,9 @@ end -- Copies a table while preserving its metatable. -- -- @param source The table to copy. --- @param target The table to which values are to be copied or |nil| if a new +-- @param target The table to which values are to be copied or |nil| if a new -- table is to be allocated. --- +-- -- @return The |target| table or a newly allocated table containing all -- keys and values of the |source| table. -- @@ -110,10 +110,10 @@ end -- Copies an array while preserving its metatable. -- -- @param source The array to copy. --- @param target The array to which values are to be copied or |nil| if a new +-- @param target The array to which values are to be copied or |nil| if a new -- table is to be allocated. The elements of the -- |source| array will be added at the end. --- +-- -- @return The |target| table or a newly allocated table containing all -- keys and values of the |source| table. -- @@ -129,7 +129,7 @@ end --- --- Apply a function to all pairs of a table, resulting in a new table. +-- Apply a function to all pairs of a table, resulting in a new table. -- -- @param source The table. -- @param fun A function taking two arguments (|val| and |key|, in @@ -140,7 +140,7 @@ end -- takes only a single argument and returns only a single argument, -- you have a ``classical'' value mapper. Also note that if -- |new_value| is |nil|, the value is removed from the table. --- +-- -- @return The new table. -- function lib.map(source, fun) @@ -159,7 +159,7 @@ end --- -- Apply a function to all elements of an array, resulting in a new --- array. +-- array. -- -- @param source The array. -- @param fun A function taking two arguments (|val| and |i|, the @@ -169,14 +169,14 @@ end -- element is skipped. If this function is not provided (is |nil|), -- the identity function is used. -- @param new The target array (if |nil|, a new array is create). --- +-- % --\begin{codeexample}[code only] -- local a = lib.imap(array, function(v) if some_test(v) then return v end end) --\end{codeexample} -- -- The above code is a filter that will remove all elements from the -- array that do not pass |some_test|. --- +-- % --\begin{codeexample}[code only] -- lib.imap(a, lib.id, b) --\end{codeexample} @@ -238,23 +238,27 @@ end -- option table of an object contains the name field is done using -- |rawget| for all but the last parameter. This means that when you -- write +-- % --\begin{codeexample}[code only] --lib.lookup_option("foo", vertex, graph) --\end{codeexample} --- and if |/graph drawin/foo| has an inital value set, if the +-- % +-- and if |/graph drawing/foo| has an initial value set, if the -- parameter is not explicitly set in a vertex, you will get the value -- set for the graph or, if it is not set there either, the initial --- value. In contrast, if you write +-- value. In contrast, if you write +-- % --\begin{codeexample}[code only] -- vertex.options["foo"] or graph.options["foo"] --\end{codeexample} +-- % -- what happens is that the first access to |.options| will -- \emph{always} return something when an initial parameter has been --- set for the option |foo|. +-- set for the option |foo|. -- --- @param name The name of the options +-- @param name The name of the options -- @param ... Any number of objects. Each must have an options --- field. +-- field. -- -- @return The found option @@ -262,10 +266,10 @@ function lib.lookup_option(name, ...) local list = {...} for i=1,#list-1 do local o = list[i].options - if o then + if o then local v = rawget(o, name) if v then - return v + return v end end end @@ -280,12 +284,12 @@ end -- a |new| function, which takes an optional table of |initial| values -- and which outputs a new table whose metatable is the -- class. The |new| function will call the function |constructor| if --- it exsist. Furthermore, the class object's |__index| is set to itself +-- it exists. Furthermore, the class object's |__index| is set to itself -- and its meta table is set to the |base_class| field of the -- table. If |t| is |nil|, a new table is created. -- -- Here is a typical usage of this function: --- +-- % --\begin{codeexample}[code only] --local Point = lib.class {} -- @@ -297,13 +301,14 @@ end -- --print(p:length()) --\end{codeexample} +-- % -- We can subclass this as follows: --- +-- % --\begin{codeexample}[code only] --local Point3D = lib.class { base_class = Point } -- --function Point3D:length() --- local l = Point.length(self) -- Call base class's function +-- local l = Point.length(self) -- Call base class's function -- return math.sqrt(l*l + self.z*self.zdy) --end -- @@ -318,31 +323,31 @@ end function lib.class(t) t = t or {} - + -- First, setup indexing, if necessary if not t.__index then t.__index = t end - + -- Second, setup new method, if necessary - t.new = t.new or - function (initial) - + t.new = t.new or + function (initial) + -- Create new object local obj = {} for k,v in pairs(initial or {}) do - obj[k] = v + obj[k] = v end setmetatable(obj, t) if obj.constructor then - obj:constructor() + obj:constructor() end - + return obj end - - -- Third, setup inheritence, if necessary + + -- Third, setup inheritance, if necessary if not getmetatable(t) then setmetatable(t, t.base_class) end @@ -359,8 +364,8 @@ end -- a table) for which some methods are needed only seldomly. In this -- case, you can put these methods in a separate file and then use -- |ondemand| to indicate that the methods are found in a --- another file. --- +-- another file. +-- % --\begin{codeexample}[code only] -- -- File Foo.lua -- local Foo = {} @@ -388,23 +393,24 @@ end function lib.ondemand(filename, table, name) return function(...) - require (filename) - return table[name] (...) - end + require (filename) + return table[name] (...) + end end --- --- This implements the legacy random number generator of Lua 5.2 in --- pure Lua. This is needed for Lua 5.3 compatibility to obtain --- consitent results. +-- This implements the a random number generator similar to the one +-- provided by Lua, but based on the tex.uniformdeviate primitive to +-- avoid differences in random numbers due to platform specifics. -- -- @param l Lower bound -- @param u Upper bound -- @return A random number function lib.random(l,u) - local r = math.random() + local fraction_one = 268435456 + local r = tex.uniform_rand(fraction_one)/fraction_one if l and u then assert(l <= u) return math.floor(r*(u-l+1)) + l @@ -416,6 +422,14 @@ function lib.random(l,u) end end +--- +-- Provide the seed for the random number generator +-- +-- @param seed random seed +function lib.randomseed(seed) + tex.init_rand(seed) +end + -- Done return lib diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Bezier.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Bezier.lua index 292f9e56bf2..e4fe21d9422 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Bezier.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Bezier.lua @@ -13,7 +13,7 @@ --- -- This library offers a number of methods for working with Bezi\'er --- curves. +-- curves. local Bezier = {} @@ -29,7 +29,7 @@ local Coordinate = require 'pgf.gd.model.Coordinate' --- -- Compute a point ``along a curve at a time''. You provide the four -- coordinates of the curve and a time. You get a point on the curve --- as return value as well as the two suport vector for curve +-- as return value as well as the two support vector for curve -- before this point and two support vectors for the curve after the -- point. -- @@ -115,7 +115,7 @@ function Bezier.supportsForPointsAtTime(from, p1, t1, p2, t2, to) local f1b = t1 * s1^2 * 3 local f1c = t1^2 * s1 * 3 local f1d = t1^3 - + local f2a = s2^3 local f2b = t2 * s2^2 * 3 local f2c = t2^2 * s2 * 3 @@ -127,7 +127,7 @@ function Bezier.supportsForPointsAtTime(from, p1, t1, p2, t2, to) -- -- p1.y - from.y * f1a - to.y * f1d = sup1.y * f1b + sup2.y * f1c -- p2.y - from.y * f2a - to.y * f2d = sup1.y * f2b + sup2.y * f2c - + local a = f1b local b = f1c local c = p1.x - from.x * f1a - to.x * f1d @@ -138,16 +138,16 @@ function Bezier.supportsForPointsAtTime(from, p1, t1, p2, t2, to) local det = a*e - b*d local x1 = -(b*f - e*c)/det local x2 = -(c*d - a*f)/det - + local c = p1.y - from.y * f1a - to.y * f1d local f = p2.y - from.y * f2a - to.y * f2d - + local det = a*e - b*d local y1 = -(b*f - e*c)/det local y2 = -(c*d - a*f)/det return Coordinate.new(x1,y1), Coordinate.new(x2,y2) - + end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Direct.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Direct.lua index aaad047c702..81728a1a444 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Direct.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Direct.lua @@ -30,12 +30,12 @@ local Digraph = require "pgf.gd.model.Digraph" -- arrows. For instance, while "a <- b" will cause an arc from a to be -- to be added to the syntactic digraph, calling this function will -- return a digraph in which there is an arc from b to a rather than --- the other way round. In detail, "a <- b" is tranlated as just +-- the other way round. In detail, "a <- b" is translated as just -- described, "a -> b" yields an arc from a to b as expected, "a <-> b" -- and "a -- b" yield arcs in both directions and, finally, "a -!- b" -- yields no arc at all. -- --- @param syntactic_digraph A syntacitic digraph, usually the "input" +-- @param syntactic_digraph A syntactic digraph, usually the "input" -- graph as specified syntactically be the user. -- -- @return A new "semantic" digraph object. @@ -49,12 +49,12 @@ function Direct.digraphFromSyntacticDigraph(syntactic_digraph) for _,m in ipairs(a.syntactic_edges) do local direction = m.direction if direction == "->" then - digraph:connect(a.tail, a.head) + digraph:connect(a.tail, a.head) elseif direction == "<-" then - digraph:connect(a.head, a.tail) + digraph:connect(a.head, a.tail) elseif direction == "--" or direction == "<->" then - digraph:connect(a.tail, a.head) - digraph:connect(a.head, a.tail) + digraph:connect(a.tail, a.head) + digraph:connect(a.head, a.tail) end -- Case -!-: No edges... end @@ -92,4 +92,4 @@ end -- Done -return Direct
\ No newline at end of file +return Direct diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Event.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Event.lua index 952f37796eb..880796ce973 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Event.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Event.lua @@ -19,7 +19,7 @@ -- arcs, and a digraph object representing this graph get -- constructed. However, even though syntactic annotations such as -- options for the vertices and arcs are attached to them and can be --- accessed through the graph objects, some syntactic inforamtion is +-- accessed through the graph objects, some syntactic information is -- neither represented in the digraph object nor in the vertices and -- the arcs. A typical example is a ``missing'' node in a tree: Since -- it is missing, there is neither a vertex object nor arc objects @@ -35,37 +35,37 @@ -- -- The following events are created during the parsing process by the -- standard parsers of \tikzname: --- +-- % -- \begin{itemize} --- \item[|node|] When a node of the input graph has been parsed and --- a |Vertex| object has been created for it, an event with kind --- |node| is created. The |parameter| of this event is the --- just-created vertex. +-- \item[|node|] When a node of the input graph has been parsed and +-- a |Vertex| object has been created for it, an event with kind +-- |node| is created. The |parameter| of this event is the +-- just-created vertex. -- --- The same kind of event is used to indicate ``missing'' nodes. In --- this case, the |parameters| field is |nil|. --- \item[|edge|] When an edge of the input graph has been parsed, an --- event is created of kind |edge|. The |parameters| field will store --- an array with two entries: The first is the |Arc| object whose --- |syntactic_edges| field stores the |edge|. The second is the index --- of the edge inside the |syntactic_edges| field. --- \item[|begin|] --- Signals the beginning of a group, which will be ended with a --- corresponding |end| event later on. The |parameters| field will --- indicate the kind of group. Currently, only the string --- |"descendants"| is used as |parameters|, indicating the start of --- several nodes that are descendants of a given node. This --- information can be used by algorithms for reconstructing the --- input structure of trees. --- \item[|end|] Signals the end of a group begun by a |begin| event --- earlier on. +-- The same kind of event is used to indicate ``missing'' nodes. In +-- this case, the |parameters| field is |nil|. +-- \item[|edge|] When an edge of the input graph has been parsed, an +-- event is created of kind |edge|. The |parameters| field will store +-- an array with two entries: The first is the |Arc| object whose +-- |syntactic_edges| field stores the |edge|. The second is the index +-- of the edge inside the |syntactic_edges| field. +-- \item[|begin|] +-- Signals the beginning of a group, which will be ended with a +-- corresponding |end| event later on. The |parameters| field will +-- indicate the kind of group. Currently, only the string +-- |"descendants"| is used as |parameters|, indicating the start of +-- several nodes that are descendants of a given node. This +-- information can be used by algorithms for reconstructing the +-- input structure of trees. +-- \item[|end|] Signals the end of a group begun by a |begin| event +-- earlier on. -- \end{itemize} --- --- @field kind A string representing the kind of the events. +-- +-- @field kind A string representing the kind of the events. -- @field parameters Kind-specific parameters. -- @field index A number that stores the events logical position in -- the sequence of events. The number need not be an integer array --- index. +-- index. -- local Event = {} Event.__index = Event diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/LookupTable.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/LookupTable.lua index 0014c94a375..fc2043d5237 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/LookupTable.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/LookupTable.lua @@ -13,7 +13,7 @@ --- -- This table provides two utility functions for managing ``lookup --- tables.'' Such a table is a mixture of an array and a hashtable: +-- tables''. Such a table is a mixture of an array and a hashtable: -- It stores (only) tables. Each table is stored once in a normal -- array position. Additionally, the lookup table is also indexed at -- the position of the table (used as a key) and this position is set @@ -30,7 +30,7 @@ require("pgf.gd.lib").LookupTable = LookupTable --- -- Add all elements in the |array| to a lookup table. If an element of -- the array is already present in the table, it will not be added --- again. +-- again. -- -- This operation takes time $O(|\verb!array!|)$. -- @@ -50,7 +50,7 @@ end --- -- Add one element to a lookup table. If it is already present in the --- table, it will not be added again. +-- table, it will not be added again. -- -- This operation takes time $O(1)$. -- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PathLengths.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PathLengths.lua index 05b480713b0..4bfa896ef95 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PathLengths.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PathLengths.lua @@ -27,11 +27,11 @@ local PriorityQueue = require "pgf.gd.lib.PriorityQueue" --- --- Performs the Dijkstra algorithm to solve the single-source shortes path problem. +-- Performs the Dijkstra algorithm to solve the single-source shortest path problem. -- --- The algorithm computes the shortest paths from |source| to all nodes --- in the graph. It also generates a table with distance level sets, each of --- which contain all nodes that have the same corresponding distance to +-- The algorithm computes the shortest paths from |source| to all nodes +-- in the graph. It also generates a table with distance level sets, each of +-- which contain all nodes that have the same corresponding distance to -- |source|. Finally, a mapping of nodes to their parents along the -- shortest paths is generated to allow the reconstruction of the paths -- that were chosen by the Dijkstra algorithm. @@ -39,7 +39,7 @@ local PriorityQueue = require "pgf.gd.lib.PriorityQueue" -- @param graph The graph to compute the shortest paths for. -- @param source The node to compute the distances to. -- --- @return A mapping of nodes to their distance to |source|. +-- @return A mapping of nodes to their distance to |source|. -- @return An array of distance level sets. The set at index |i| contains -- all nodes that have a distance of |i| to |source|. -- @return A mapping of nodes to their parents to allow the reconstruction @@ -95,7 +95,7 @@ end --- --- Performs the Floyd-Warshall algorithm to solve the all-source shortes path problem. +-- Performs the Floyd-Warshall algorithm to solve the all-source shortest path problem. -- -- @param graph The graph to compute the shortest paths for. -- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua index 378800fbf5b..3fd29cdb748 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/PriorityQueue.lua @@ -107,7 +107,7 @@ end --- Internals: An implementation of fibonacci heaps. +-- Internals: An implementation of Fibonacci heaps. FibonacciHeap.__index = FibonacciHeap @@ -200,7 +200,7 @@ function FibonacciHeap:decreaseValue(node, value) assert(value <= node.value) node.value = value - + if node.value < node.parent.value then local parent = node.parent self:cutFromParent(node) @@ -231,7 +231,7 @@ end function FibonacciHeap:linkRoots(root, child) child.root = root child.parent = root - + child = self:removeTableElement(self.trees, child) table.insert(root.children, child) diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua index abb428b8725..bcb72761909 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Simplifiers.lua @@ -12,7 +12,7 @@ --- The Simplifiers class is a singleton object. --- Its methods allow implement methods for simplifing graphs, for instance +-- Its methods allow implement methods for simplifying graphs, for instance -- for removing loops or multiedges or computing spanning trees. local Simplifiers = {} @@ -104,7 +104,7 @@ function Simplifiers:classifyEdges(graph) completed[node] = true pop() else - for i=#edges_to_traverse,1,-1 do + for i=#edges_to_traverse,1,-1 do local neighbour = edges_to_traverse[i]:getNeighbour(node) discovered[neighbour] = true push(neighbour) @@ -199,9 +199,9 @@ function Simplifiers:collapseMultiedgesOldModel(algorithm, collapse_action) collapsed_edges[multiedge[neighbour]] = {} end - if collapse_action then - collapse_action(multiedge[neighbour], edge, graph) - end + if collapse_action then + collapse_action(multiedge[neighbour], edge, graph) + end table.insert(collapsed_edges[multiedge[neighbour]], edge) end @@ -251,12 +251,12 @@ function Simplifiers:expandMultiedgesOldModel(algorithm) -- Copy bend points for _,p in ipairs(multiedge.bend_points) do - edge.bend_points[#edge.bend_points+1] = p:copy() + edge.bend_points[#edge.bend_points+1] = p:copy() end -- Copy options for k,v in pairs(multiedge.algorithmically_generated_options) do - edge.algorithmically_generated_options[k] = v + edge.algorithmically_generated_options[k] = v end for _,node in ipairs(edge.nodes) do @@ -276,4 +276,4 @@ end -- Done -return Simplifiers
\ No newline at end of file +return Simplifiers diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Stack.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Stack.lua index dfab15697de..75084b6e38b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Stack.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Stack.lua @@ -13,7 +13,7 @@ --- A Stack is a very simple wrapper around an array -- --- +-- local Stack = {} Stack.__index = Stack diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Storage.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Storage.lua index eb520e77452..e029fdf7ff8 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Storage.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Storage.lua @@ -19,12 +19,12 @@ -- storage. Also, you can specify that for each object of the storage -- you store a table. In this case, there is no need to initialize -- this table for each object; rather, when you write into such a --- table and it does not yet exist, it is created ``on the fly''. +-- table and it does not yet exist, it is created ``on the fly''. -- -- The typical way you use storages is best explained with the -- following example: Suppose you want to write a depth-first search -- algorithm for a graph. This algorithm might wish to mark all nodes --- it has visisted. It could just say |v.marked = true|, but this might +-- it has visited. It could just say |v.marked = true|, but this might -- clash with someone else also using the |marked| key. The solution is -- to create a |marked| storage. The algorithm can first say --\begin{codeexample}[code only, tikz syntax=false] @@ -40,13 +40,13 @@ -- no longer in use get removed automatically. You can also make it a -- member variable of the algorithm class, which allows you make the -- information about which objects are marked globally --- accessible. +-- accessible. -- -- Now suppose the algorithm would like to store even more stuff in -- the storage. For this, we might use a table and can use the fact -- that a storage will automatically create a table when necessary: --\begin{codeexample}[code only, tikz syntax=false] ---local info = Storage.newTableStorage() +--local info = Storage.newTableStorage() -- --info[v].marked = true -- the "info[v]" table is -- -- created automatically here @@ -66,7 +66,7 @@ require("pgf.gd.lib").Storage = Storage local SimpleStorageMetaTable = { __mode = "k" } --- The adcanved metatable for table storages: +-- The advanced metatable for table storages: local TableStorageMetaTable = { __mode = "k", @@ -91,7 +91,7 @@ end --- -- Create a new storage object which will install a table for every --- entry automatilly. +-- entry automatically. -- -- @return A new |Storage| instance. diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Transform.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Transform.lua index 1f81b269202..7695b1b2395 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Transform.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Transform.lua @@ -42,7 +42,7 @@ function Transform.new(a,b,c,d,x,y) end ---- Creates a new transformation object that represents a shift. +--- Creates a new transformation object that represents a shift. -- -- @param x An x-shift -- @param y A y-shift @@ -54,7 +54,7 @@ function Transform.new_shift(x,y) end ---- Creates a new transformation object that represents a rotation. +--- Creates a new transformation object that represents a rotation. -- -- @param angle An angle -- @@ -67,7 +67,7 @@ function Transform.new_rotation(angle) end ---- Creates a new transformation object that represents a scaling. +--- Creates a new transformation object that represents a scaling. -- -- @param x The horizontal scaling -- @param y The vertical scaling (if missing, the horizontal scaling is used) @@ -94,8 +94,8 @@ function Transform.concat(a,b) local a1, a2, a3, a4, a5, a6, b1, b2, b3, b4, b5, b6 = a[1], a[2], a[3], a[4], a[5], a[6], b[1], b[2], b[3], b[4], b[5], b[6] return { a1*b1 + a2*b3, a1*b2 + a2*b4, - a3*b1 + a4*b3, a3*b2 + a4*b4, - a1*b5 + a2*b6 + a5, a3*b5 + a4*b6 + a6 } + a3*b1 + a4*b3, a3*b2 + a4*b4, + a1*b5 + a2*b6 + a5, a3*b5 + a4*b6 + a6 } end @@ -117,4 +117,4 @@ end -- Done -return Transform
\ No newline at end of file +return Transform diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Arc.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Arc.lua index 997a452399f..e007e9b59b7 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Arc.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Arc.lua @@ -14,10 +14,10 @@ -- An arc is a light-weight object representing an arc from a vertex -- in a graph to another vertex. You may not create an |Arc| by -- yourself, which is why there is no |new| method, arc creation is --- done by the Digraph class. +-- done by the Digraph class. -- -- Every arc belongs to exactly one graph. If you want the same arc in --- another graph, you need to newly connect two vertices in the other graph. +-- another graph, you need to newly connect two vertices in the other graph. -- -- You may read the |head| and |tail| fields, but you may not write -- them. In order to store data for an arc, use |Storage| objects. @@ -28,7 +28,7 @@ -- be multiple edges between two vertices. This means, in particular, -- that an arc has no |options| field. Rather, it has several -- |optionsXxxx| functions, that will search for options in all of the --- synactic edges that ``belong'' to an edge. +-- syntactic edges that ``belong'' to an edge. -- -- In order to \emph{set} options of the edges, you can set the -- |generated_options| field of an arc (which is |nil| by default), see @@ -72,7 +72,7 @@ -- @field animations If non-nil, some animations to be passed back -- to the original syntactic edges. See the description of the -- |animations| field for |Vertex| for details on the syntax. --- @field syntactic_edges In case this arc is an arc in the syntatic +-- @field syntactic_edges In case this arc is an arc in the syntactic -- digraph (and only then), this field contains an array containing -- syntactic edges (``real'' edges in the syntactic digraph) that -- underly this arc. Otherwise, the field will be empty or |nil|. @@ -106,15 +106,17 @@ local lib = require 'pgf.gd.lib' -- If your algorithm gets confused by multiple edges, try saying -- |a:options(your_option)|. This will always give the ``most -- sensible'' choice of the option if there are multiple edges --- corresponding to the same arc. +-- corresponding to the same arc. -- -- @param option A string option like |"length"|. -- --- @return A table with the following contents: +-- @return A table with the following contents: +-- % -- \begin{enumerate} --- \item It is an array of all values the option has for edges --- corresponding to |self| in the syntactic digraph. Suppose, for --- instance, you write the following: +-- \item It is an array of all values the option has for edges +-- corresponding to |self| in the syntactic digraph. Suppose, for +-- instance, you write the following: +-- % --\begin{codeexample}[code only] --graph { -- tail -- [length=1] head, % multi edge 1 @@ -125,31 +127,32 @@ local lib = require 'pgf.gd.lib' -- tail -- [length=2] head, % multi edge 6 --} --\end{codeexample} --- Suppose, furthermore, that |length| has been setup as an edge --- option. Now suppose that |a| is the arc from the vertex |tail| to --- the vertex |head|. Calling |a:optionsArray('length')| will --- yield the array part |{1,3,2,8,7}|. The reason for the ordering is --- as follows: First come all values |length| had for syntactic edges --- going from |self.tail| to |self.head| in the order they appear in the graph --- description. Then come all values the options has for syntactic --- edges going from |self.head| to |self.tail|. The reason for this --- slightly strange behaviour is that many algorithms do not really --- care whether someone writes |a --[length=1] b| or --- |b --[length=1] a|; in both cases they would ``just'' like to know --- that the length is~|1|. --- --- \item There is field called |aligned|, which is an array storing --- the actual syntactic edge objects whose values can be found in the --- array part of the returned table. However, |aligned| contains only --- the syntactic edges pointing ``in the same direction'' as the arc, --- that is, the tail and head of the syntactic edge are the same as --- those of the arc. In the above example, this array would contain --- the edges with the comment numbers |1|, |2|, and |6|. --- --- Using the length of this array and the fact that the ``aligned'' --- values come first in the table, you can easily iterate over the --- |option|'s values of only those edges that are aligned with the arc: --- +-- % +-- Suppose, furthermore, that |length| has been setup as an edge +-- option. Now suppose that |a| is the arc from the vertex |tail| to +-- the vertex |head|. Calling |a:optionsArray('length')| will +-- yield the array part |{1,3,2,8,7}|. The reason for the ordering is +-- as follows: First come all values |length| had for syntactic edges +-- going from |self.tail| to |self.head| in the order they appear in the +-- graph description. Then come all values the options has for syntactic +-- edges going from |self.head| to |self.tail|. The reason for this +-- slightly strange behavior is that many algorithms do not really +-- care whether someone writes |a --[length=1] b| or +-- |b --[length=1] a|; in both cases they would ``just'' like to know +-- that the length is~|1|. +-- +-- \item There is field called |aligned|, which is an array storing +-- the actual syntactic edge objects whose values can be found in the +-- array part of the returned table. However, |aligned| contains only +-- the syntactic edges pointing ``in the same direction'' as the arc, +-- that is, the tail and head of the syntactic edge are the same as +-- those of the arc. In the above example, this array would contain +-- the edges with the comment numbers |1|, |2|, and |6|. +-- +-- Using the length of this array and the fact that the ``aligned'' +-- values come first in the table, you can easily iterate over the +-- |option|'s values of only those edges that are aligned with the arc: +-- % --\begin{codeexample}[code only, tikz syntax=false] --local a = g:arc(tail.head) -- some arc --local opt = a:optionsArray('length') @@ -158,17 +161,16 @@ local lib = require 'pgf.gd.lib' -- sum = sum + opt[i] --end --\end{codeexample} --- ---\item There is a field called |anti_aligned|, which is an array --- containing exactly the edges in the array part of the table not --- aligned with the arc. The numbering start at |1| as usual, so the --- $i$th entry of this table corresponds to the entry at position $i + --- \verb!#opt.aligned!$ of the table. --- ---\end{enumerate} +-- % +-- \item There is a field called |anti_aligned|, which is an array +-- containing exactly the edges in the array part of the table not +-- aligned with the arc. The numbering start at |1| as usual, so the +-- $i$th entry of this table corresponds to the entry at position $i + +-- \verb!#opt.aligned!$ of the table. +-- \end{enumerate} -- function Arc:optionsArray(option) - + local cache = self.option_cache local t = cache[option] if t then @@ -185,23 +187,23 @@ function Arc:optionsArray(option) if arc then for _,m in ipairs(arc.syntactic_edges) do if m.options[option] ~= nil then - aligned[#aligned + 1] = m + aligned[#aligned + 1] = m end end table.sort(aligned, function (a,b) return a.event.index < b.event.index end) end - + local arc = head ~= tail and s_graph:arc(head, tail) local anti_aligned = {} if arc then for _,m in ipairs(arc.syntactic_edges) do if m.options[option] ~= nil then - anti_aligned[#anti_aligned + 1] = m + anti_aligned[#anti_aligned + 1] = m end end table.sort(anti_aligned, function (a,b) return a.event.index < b.event.index end) end - + -- Now merge them together local t = { aligned = aligned, anti_aligned = anti_aligned } for i=1,#aligned do @@ -211,7 +213,7 @@ function Arc:optionsArray(option) t[#t+1] = anti_aligned[i].options[option] end cache[option] = t - + return t end @@ -221,11 +223,11 @@ end -- Returns the first option, that is, the first entry of -- |Arc:optionsArray(option)|. However, if the |only_aligned| -- parameter is set to true and there is no option with any aligned --- synactic edge, |nil| is returned. +-- syntactic edge, |nil| is returned. -- -- @param option An option -- @param only_aligned If true, only aligned syntactic edges will be --- considered. +-- considered. -- @return The first entry of the |optionsArray| function Arc:options(option, only_aligned) if only_aligned then @@ -256,7 +258,7 @@ end -- edges will be considered. -- -- @return If the option is not set for any (aligned) syntactic edges --- corresponding to |self|, |nil| is returned. If there is exectly one +-- corresponding to |self|, |nil| is returned. If there is exactly one -- edge, the value of this edge is returned. Otherwise, the result of -- repeatedly applying the |accumulator| function as described -- above. @@ -265,6 +267,7 @@ end -- |accumulator| function again. -- -- @usage Here is typical usage: +-- % --\begin{codeexample}[code only, tikz syntax=false] --local total_length = a:optionsAccumulated('length', function (a,b) return a+b end) or 0 --\end{codeexample} @@ -277,7 +280,7 @@ function Arc:optionsAccumulated(option, accumulator, only_aligned) if v == nil then v = opt[1] for i=2,#aligned do - v = accumulator(v, opt[i]) + v = accumulator(v, opt[i]) end align[accumulator] = v end @@ -287,7 +290,7 @@ function Arc:optionsAccumulated(option, accumulator, only_aligned) if v == nil then v = opt[1] for i=2,#opt do - v = accumulator(v, opt[i]) + v = accumulator(v, opt[i]) end opt[accumulator] = v end @@ -301,7 +304,7 @@ end -- Compute the syntactic head and tail of an arc. For this, we have a -- look at the syntactic digraph underlying the arc. If there is at -- least once syntactic edge going from the arc's tail to the arc's --- head, the arc's tail and head are returned. Otherweise, we test +-- head, the arc's tail and head are returned. Otherwise, we test -- whether there is a syntactic edge in the other direction and, if -- so, return head and tail in reverse order. Finally, if there is no -- syntactic edge at all corresponding to the arc in either direction, @@ -338,15 +341,15 @@ function Arc:pointCloud () if a then for _,e in ipairs(a.syntactic_edges) do for _,p in ipairs(e.path) do - if type(p) == "table" then - cloud[#cloud + 1] = p - end + if type(p) == "table" then + cloud[#cloud + 1] = p + end end end end self.cached_point_cloud = cloud return cloud -end +end @@ -377,7 +380,7 @@ function Arc:eventIndex () end self.cached_event_index = e return e -end +end @@ -389,21 +392,16 @@ end -- edge involved in the arc. -- -- The priority of an edge is computed as follows: --- +-- % -- \begin{enumerate} --- \item If the option |"span priority"| is set, this number --- will be used. --- --- \item If the edge has the same head as the arc, we lookup the key\\ --- |"span priority " .. edge.direction|. If set, we use --- this value. --- --- \item If the edge has a different head from the arc (the arc is --- ``reversed'' with respect to the syntactic edge), we lookup the key --- |"span priority reversed " .. edge.direction|. If set, --- we use this value. --- --- \item Otherwise, we use priority 5. +-- \item If the option |"span priority"| is set, this number +-- will be used. +-- \item If the edge has the same head as the arc, we lookup the key\\ +-- |"span priority " .. edge.direction|. If set, we use this value. +-- \item If the edge has a different head from the arc (the arc is +-- ``reversed'' with respect to the syntactic edge), we lookup the key +-- |"span priority reversed " .. edge.direction|. If set, we use this value. +-- \item Otherwise, we use priority 5. -- \end{enumerate} -- -- @return The priority of the arc, as described above. @@ -412,7 +410,7 @@ function Arc:spanPriority() if self.cached_span_priority then return self.cached_span_priority end - + local head = self.head local tail = self.tail local min @@ -422,8 +420,8 @@ function Arc:spanPriority() if a then for _,m in ipairs(a.syntactic_edges) do local p = - m.options["span priority"] or - lib.lookup_option("span priority " .. m.direction, m, g) + m.options["span priority"] or + lib.lookup_option("span priority " .. m.direction, m, g) min = math.min(p or 5, min or math.huge) end @@ -433,15 +431,15 @@ function Arc:spanPriority() if a then for _,m in ipairs(a.syntactic_edges) do local p = - m.options["span priority"] or - lib.lookup_option("span priority reversed " .. m.direction, m, g) - + m.options["span priority"] or + lib.lookup_option("span priority reversed " .. m.direction, m, g) + min = math.min(p or 5, min or math.huge) end end - + self.cached_span_priority = min or 5 - + return min or 5 end @@ -461,6 +459,7 @@ end -- which will replace the function in the |Path|. -- -- You use this method like this: +-- % --\begin{codeexample}[code only, tikz syntax=false] --... --local arc = g:connect(s,t) @@ -485,34 +484,34 @@ function Arc:sync() local a = self.syntactic_digraph:arc(tail,head) if a and #a.syntactic_edges>0 then for _,e in ipairs(a.syntactic_edges) do - local clone = path:clone() - for i=1,#clone do - local p = clone[i] - if type(p) == "function" then - clone[i] = p(e) - if type(clone[i]) == "table" then - clone[i] = clone[i]:clone() - end - end - end - e.path = clone + local clone = path:clone() + for i=1,#clone do + local p = clone[i] + if type(p) == "function" then + clone[i] = p(e) + if type(clone[i]) == "table" then + clone[i] = clone[i]:clone() + end + end + end + e.path = clone end end local a = head ~= tail and self.syntactic_digraph:arc(head,tail) if a and #a.syntactic_edges>0 then for _,e in ipairs(a.syntactic_edges) do - local clone = path:reversed() - for i=1,#clone do - local p = clone[i] - if type(p) == "function" then - clone[i] = p(e) - if type(clone[i]) == "table" then - clone[i] = clone[i]:clone() - end - end - end - e.path = clone - end + local clone = path:reversed() + for i=1,#clone do + local p = clone[i] + if type(p) == "function" then + clone[i] = p(e) + if type(clone[i]) == "table" then + clone[i] = clone[i]:clone() + end + end + end + e.path = clone + end end end if self.generated_options then @@ -521,19 +520,19 @@ function Arc:sync() local a = self.syntactic_digraph:arc(tail,head) if a and #a.syntactic_edges>0 then for _,e in ipairs(a.syntactic_edges) do - for _,o in ipairs(self.generated_options) do - e.generated_options[#e.generated_options+1] = o - end + for _,o in ipairs(self.generated_options) do + e.generated_options[#e.generated_options+1] = o + end end end local a = head ~= tail and self.syntactic_digraph:arc(head,tail) if a and #a.syntactic_edges>0 then for _,e in ipairs(a.syntactic_edges) do - for _,o in ipairs(self.generated_options) do - e.generated_options[#e.generated_options+1] = o - end + for _,o in ipairs(self.generated_options) do + e.generated_options[#e.generated_options+1] = o + end end - end + end end if self.animations then local head = self.head @@ -541,17 +540,17 @@ function Arc:sync() local a = self.syntactic_digraph:arc(tail,head) if a and #a.syntactic_edges>0 then for _,e in ipairs(a.syntactic_edges) do - for _,o in ipairs(self.animations) do - e.animations[#e.animations+1] = o - end + for _,o in ipairs(self.animations) do + e.animations[#e.animations+1] = o + end end end local a = head ~= tail and self.syntactic_digraph:arc(head,tail) if a and #a.syntactic_edges>0 then for _,e in ipairs(a.syntactic_edges) do - for _,o in ipairs(self.animations) do - e.animations[#e.animations+1] = o - end + for _,o in ipairs(self.animations) do + e.animations[#e.animations+1] = o + end end end end @@ -572,8 +571,8 @@ end -- method to get a function that will, later on, compute the correct -- position of the anchor as needed. -- --- Here is the code you would use to create the abovementioned path: --- +-- Here is the code you would use to create the above-mentioned path: +-- % --\begin{codeexample}[code only, tikz syntax=false] --local a = g:connect(tail,head) --... @@ -585,19 +584,19 @@ end -- -- Normally, however, you will not write code as detailed as the above -- and you would just write instead of the last three lines: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] --arc:setPolylinePath { Coordinate.new (10, 10) } --\end{codeexample} function Arc:tailAnchorForArcPath() return function (edge) - local a = edge.options['tail anchor'] - if a == "" then - a = "center" - end - return self.tail:anchor(a) + self.tail.pos - end + local a = edge.options['tail anchor'] + if a == "" then + a = "center" + end + return self.tail:anchor(a) + self.tail.pos + end end --- @@ -605,12 +604,12 @@ end function Arc:headAnchorForArcPath() return function (edge) - local a = edge.options['head anchor'] - if a == "" then - a = "center" - end - return self.head:anchor(a) + self.head.pos - end + local a = edge.options['head anchor'] + if a == "" then + a = "center" + end + return self.head:anchor(a) + self.head.pos + end end @@ -633,7 +632,7 @@ function Arc:setPolylinePath(coordinates) end p:appendLineto(self:headAnchorForArcPath()) - + self.path = p end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Collection.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Collection.lua index 8ebb6f144cf..abc454b7dbb 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Collection.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Collection.lua @@ -20,11 +20,11 @@ -- vertices that should be on the same level in a layered algorithm, -- or, indeed, subgraphs that are rendered in a special way. -- --- Collections are grouped into ``kinds.'' All collections of a given +-- Collections are grouped into ``kinds''. All collections of a given -- kind can be accessed by algorithms through an array whose elements --- are the collections. On the displya layer, for each kind a separate --- key is available to indicate that a node or an edge belongs to a --- collection. +-- are the collections. On the display layer, for each kind a separate +-- key is available to indicate that a node or an edge belongs to a +-- collection. -- -- Collections serve two purposes: First, they can be seen as ``hints'' -- to graph drawing algorithms that certain nodes and/or edges ``belong @@ -48,14 +48,14 @@ -- was in force when the collection was created. -- -- @field child_collections An array of all collections that are --- direct children of this collection (that is, +-- direct children of this collection (that is, -- they were defined while the current collection was the most -- recently defined collection on the options stack). However, you -- should use the methods |children|, |descendants|, and so to access -- this field. -- -- @field parent_collection The parent collection of the current --- colleciton. This field may be |nil| in case a collection has no parent. +-- collection. This field may be |nil| in case a collection has no parent. -- -- @field event An |Event| object that was create for this -- collection. Its |kind| will be |"collection"| while its |parameter| @@ -86,7 +86,7 @@ local Storage = require "pgf.gd.lib.Storage" -- function Collection.new(t) assert (type(t.kind) == "string" and t.kind ~= "", "collection kind not set") - + return setmetatable( { vertices = t.vertices or {}, @@ -111,7 +111,7 @@ end function Collection:registerAsChildOf(parent) self.parent = parent - if parent then + if parent then assert (getmetatable(parent) == Collection, "parent must be a collection") parent.child_collections[#parent.child_collections+1] = self end @@ -149,10 +149,10 @@ end function Collection:childrenOfKind(kind) local function rec (c, a) for _,d in ipairs(c.child_collections) do - if d.kind == kind then - a[#a + 1] = d + if d.kind == kind then + a[#a + 1] = d else - rec (d, a) + rec (d, a) end end return a @@ -163,7 +163,7 @@ end --- -- The descendants of a collection are its children, plus their --- children, plus their children, and so on. +-- children, plus their children, and so on. -- -- @return An array of all descendants of |self|. It will be in -- preorder. @@ -184,15 +184,15 @@ end --- -- The descendants of a collection of the given |kind|. -- --- @param kind A colleciton kind. +-- @param kind A collection kind. -- -- @return An array of all descendants of |self| of the given |kind|. function Collection:descendantsOfKind(kind) local function rec (c, a) for _,d in ipairs(c.child_collections) do - if d.kind == kind then - a[#a + 1] = d + if d.kind == kind then + a[#a + 1] = d end rec (d, a) end @@ -205,4 +205,4 @@ end -- Done -return Collection
\ No newline at end of file +return Collection diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Coordinate.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Coordinate.lua index 815544ee705..3a4448ab089 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Coordinate.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Coordinate.lua @@ -10,17 +10,17 @@ -- @release $Header$ ---- +--- -- A Coordinate models a position on the drawing canvas. -- -- It has an |x| field and a |y| field, which are numbers that will be -- interpreted as \TeX\ points (1/72.27th of an inch). The $x$-axis goes -- right and the $y$-axis goes up. -- --- @field x +-- @field x -- @field y -- --- There is also a static field called |origin| that is always equal to the origin. +-- There is also a static field called |origin| that is always equal to the origin. local Coordinate = {} Coordinate.__index = Coordinate @@ -61,7 +61,7 @@ end --- Apply a transformation matrix to a coordinate, -- see |pgf.gd.lib.Transform| for details. -- --- @param t A tansformation. +-- @param t A transformation. function Coordinate:apply(t) local x = self.x @@ -74,7 +74,7 @@ end --- Shift a coordinate -- -- @param a An $x$ offset --- @param b A $y$ offset +-- @param b A $y$ offset function Coordinate:shift(a,b) self.x = self.x + a @@ -87,7 +87,7 @@ end -- inversed coordinate; only faster). -- -- @param a An $x$ offset --- @param b A $y$ offset +-- @param b A $y$ offset function Coordinate:unshift(a,b) self.x = self.x - a @@ -110,7 +110,7 @@ end --- -- Like |unshift|, only for coordinate parameters. -- --- @param c Another coordinate. +-- @param c Another coordinate. function Coordinate:unshiftByCoordinate(c) self.x = self.x - c.x @@ -119,7 +119,7 @@ end --- --- Moves the coordinate a fraction of |f| along a straight line to |c|. +-- Moves the coordinate a fraction of |f| along a straight line to |c|. -- -- @param c Another coordinate -- @param f A fraction @@ -268,13 +268,13 @@ end -- @return |max_x| -- @return |max_y| -- @return |center_x| The center of the bounding box --- @return |center_y| +-- @return |center_y| function Coordinate.boundingBox(array) if #array > 0 then local min_x, min_y = math.huge, math.huge local max_x, max_y = -math.huge, -math.huge - + for i=1,#array do local c = array[i] local x = c.x @@ -284,7 +284,7 @@ function Coordinate.boundingBox(array) if x > max_x then max_x = x end if y > max_y then max_y = y end end - + return min_x, min_y, max_x, max_y, (min_x+max_x) / 2, (min_y+max_y) / 2 end end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Digraph.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Digraph.lua index 5c48059a605..30b600e308d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Digraph.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Digraph.lua @@ -12,12 +12,12 @@ ---- +--- -- Each |Digraph| instance models a \emph{directed, simple} -- graph. ``Directed'' means that all edges ``point'' from a head node -- to a tail node. ``Simple'' means that between any nodes there can be -- (at most) one edge. Since these properties are a bit at odds with --- the normal behaviour of ``nodes'' and ``edges'' in \tikzname, +-- the normal behavior of ``nodes'' and ``edges'' in \tikzname, -- different names are used for them inside the |model| namespace: -- The class modeling ``edges'' is actually called |Arc| to stress -- that an arc has a specific ``start'' (the tail) and a specific @@ -31,14 +31,17 @@ -- Since digraphs are constantly created and modified inside the graph -- drawing engine, some care was taken to ensure that all operations -- work as quickly as possible. In particular: +-- % -- \begin{itemize} --- \item Adding an array of $k$ vertices using the |add| method needs --- time $O(k)$. --- \item Adding an arc between two vertices needs time $O(1)$. --- \item Accessing both the |vertices| and the |arcs| fields takes time --- $O(1)$, provided only the above operations are used. +-- \item Adding an array of $k$ vertices using the |add| method needs +-- time $O(k)$. +-- \item Adding an arc between two vertices needs time $O(1)$. +-- \item Accessing both the |vertices| and the |arcs| fields takes time +-- $O(1)$, provided only the above operations are used. -- \end{itemize} +-- % -- Deleting vertices and arcs takes more time: +-- % -- \begin{itemize} -- \item Deleting the vertices given in an array of $k$ vertices from a -- graph with $n$ vertices takes time $O(\max\{n,c\})$ where $c$ is the @@ -50,12 +53,12 @@ -- number of outgoing arcs at the arc's tail and $h_i$ is the number -- of incoming arcs at the arc's head. After a call to |disconnect|, -- the next use of the |arcs| field will take time $O(|V| + |E|)$, --- while subsequent accesses take time $O(1)$ -- till the +-- while subsequent accesses take time $O(1)$ -- till the -- next use of |disconnect|. This means that once you start deleting -- arcs using |disconnect|, you should perform as many additional -- |disconnect|s as possible before accessing |arcs| one more. -- \end{itemize} --- +-- -- \medskip -- \noindent\emph{Stability.} The |vertices| field and the array -- returned by |Digraph:incoming| and |Digraph:outgoing| are @@ -63,7 +66,7 @@ -- when you use |ipairs| on the will be the ordering in which the -- vertices or arcs were added to the graph. Even when you remove a -- vertex or an arc, the ordering of the remaining elements stays the --- same. +-- same. -- -- @field vertices This array contains the vertices that are part of -- the digraph. Internally, this array @@ -103,15 +106,18 @@ -- given vertex |v|, you cannot say something like |v.outgoings| or -- perhaps |v:getOutgoings()|. Rather, you have to say |g:outgoing(v)| -- to get this list: +-- % --\begin{codeexample}[code only, tikz syntax=false] ---for _,a in ipairs(g:outgoing(v)) do -- g is a Digraph object. +--for _,a in ipairs(g:outgoing(v)) do -- g is a Digraph object. -- pgf.debug ("There is an arc leaving " .. tostring(v) .. -- " heading to " .. tostring(a.head)) --end --\end{codeexample} --- Naturally, there is also a method |g:incoming()|. --- --- To iterate over all arcs of a graph you can say: +-- % +-- Naturally, there is also a method |g:incoming()|. +-- +-- To iterate over all arcs of a graph you can say: +-- % --\begin{codeexample}[code only, tikz syntax=false] --for _,v in ipairs(g.vertices) do -- for _,a in ipairs(g:outgoing(v)) do @@ -122,7 +128,7 @@ -- -- However, it will often be more convenient and, in case the there -- are far less arcs than vertices, also faster to write --- +-- --\begin{codeexample}[code only, tikz syntax=false] --for _,a in ipairs(g.arcs) do -- ... @@ -130,7 +136,7 @@ --\end{codeexample} -- -- @field arcs For any two vertices |t| and |h| of a graph, there may --- or may not be +-- or may not be -- an arc from |t| to |h|. If this is the case, there is an |Arc| -- object that represents this arc. Note that, since |Digraph|s are -- always simple graphs, there can be at most one such object for every @@ -138,7 +144,7 @@ -- an |Arc| through a |Storage|, see the |Storage| class for -- details. Each |Arc| for an edge of the syntactic digraph stores -- an array called |syntactic_edges| of all the multiple edges that --- are present in the user's input. +-- are present in the user's input. -- -- Unlike vertices, the arc objects of a graph are always local to a -- graph; an |Arc| object can never be part of two digraphs at the same @@ -164,7 +170,7 @@ -- point, the |arcs| array is reconstructed by adding all arcs of all -- nodes to it. -- --- The bottom line of the behaviour of the |arcs| field is that (a) the +-- The bottom line of the behavior of the |arcs| field is that (a) the -- ordering of the elements may change abruptly whenever you remove an -- arc from a graph and (b) performing $k$ |disconnect| operations in -- sequence takes time $O(k)$, provided you do not access the |arcs| @@ -188,12 +194,12 @@ local function recalc_arcs (digraph) end end digraph.arcs = arcs - return arcs + return arcs end -Digraph.__index = +Digraph.__index = function (t, k) - if k == "arcs" then + if k == "arcs" then return recalc_arcs(t) else return rawget(Digraph,k) @@ -223,7 +229,7 @@ local Vertex = require "pgf.gd.model.Vertex" -- created graphs always have an empty arcs set. This means that -- writing |Digraph.new(g)| where |g| is a graph creates a new graph -- whose vertex set is the same as |g|'s, but where there are no edges: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] --local g = Digraph.new {} --g:add { v1, v2, v3 } @@ -239,8 +245,8 @@ local Vertex = require "pgf.gd.model.Vertex" --local h = Digraph.new (g) --for _,a in ipairs(g.arcs) do h:connect(a.tail, a.head) end --\end{codeexample} --- --- This operation takes time $O(1)$. +-- +-- This operation takes time $O(1)$. -- -- @param initial A table of initial values. It is permissible that -- this array contains a |vertices| field. In this @@ -268,7 +274,7 @@ function Digraph.new(initial) digraph.vertices = {} digraph.arcs = {} - if vertices then + if vertices then digraph:add(vertices) end return digraph @@ -309,25 +315,25 @@ end -- function Digraph:remove(array) local vertices = self.vertices - + -- Mark all to-be-deleted nodes for i=1,#array do local v = array[i] assert(vertices[v], "to-be-deleted node is not in graph") vertices[v] = false end - + -- Disconnect them for i=1,#array do self:disconnect(array[i]) end - + LookupTable.remove(self.vertices, array) end ---- Test, whether a graph contains a given vertex. +--- Test, whether a graph contains a given vertex. -- -- This operation takes time $O(1)$. -- @@ -342,7 +348,7 @@ end --- -- Returns the arc between two nodes, provided it exists. Otherwise, --- |nil| is retured. +-- |nil| is returned. -- -- This operation takes time $O(1)$. -- @@ -360,7 +366,7 @@ end ---- +--- -- Returns an array containing the outgoing arcs of a vertex. You may -- only iterate over his array using ipairs, not using pairs. -- @@ -415,7 +421,7 @@ function Digraph:orderOutgoing(v, vertices) -- Compute ordering of the arcs local reordered = {} for _,arc in ipairs(outgoing) do - reordered [lookup[arc.head]] = arc + reordered [lookup[arc.head]] = arc end -- Copy back @@ -457,7 +463,7 @@ function Digraph:orderIncoming(v, vertices) -- Compute ordering of the arcs local reordered = {} for _,arc in ipairs(incoming) do - reordered [lookup[arc.head]] = arc + reordered [lookup[arc.head]] = arc end -- Copy back @@ -470,9 +476,9 @@ end ---- +--- -- Connects two nodes by an arc and returns the newly created arc --- object. If they are already connected, the existing arc is returned. +-- object. If they are already connected, the existing arc is returned. -- -- This operation takes time $O(1)$. -- @@ -522,10 +528,10 @@ end ---- +--- -- Disconnect either a single vertex |v| from all its neighbors (remove all -- incoming and outgoing arcs of this vertex) or, in case two nodes --- are given as parameter, remove the arc between them, if it exsits. +-- are given as parameter, remove the arc between them, if it exists. -- -- This operation takes time $O(|I_v| + |I_t|)$, where $I_x$ is the set -- of vertices incident to $x$, to remove the single arc between $v$ and @@ -545,23 +551,23 @@ function Digraph:disconnect(v, t) -- Remove: s_outgoings[t] = nil for i=1,#s_outgoings do - if s_outgoings[i].head == t then - table.remove (s_outgoings, i) - break - end + if s_outgoings[i].head == t then + table.remove (s_outgoings, i) + break + end end t_incomings[v] = nil for i=1,#t_incomings do - if t_incomings[i].tail == v then - table.remove (t_incomings, i) - break - end + if t_incomings[i].tail == v then + table.remove (t_incomings, i) + break + end end self.arcs = nil -- invalidate arcs field end else -- Case 1: Remove all arcs incident to v: - + -- Step 1: Delete all incomings arcs: local incomings = assert(v.incomings[self], "node not in graph") local vertices = self.vertices @@ -569,15 +575,15 @@ function Digraph:disconnect(v, t) for i=1,#incomings do local s = incomings[i].tail if s ~= v and vertices[s] then -- skip self-loop and to-be-deleted nodes - -- Remove this arc from s: - local s_outgoings = s.outgoings[self] - s_outgoings[v] = nil - for i=1,#s_outgoings do - if s_outgoings[i].head == v then - table.remove (s_outgoings, i) - break - end - end + -- Remove this arc from s: + local s_outgoings = s.outgoings[self] + s_outgoings[v] = nil + for i=1,#s_outgoings do + if s_outgoings[i].head == v then + table.remove (s_outgoings, i) + break + end + end end end @@ -586,14 +592,14 @@ function Digraph:disconnect(v, t) for i=1,#outgoings do local t = outgoings[i].head if t ~= v and vertices[t] then - local t_incomings = t.incomings[self] - t_incomings[v] = nil - for i=1,#t_incomings do - if t_incomings[i].tail == v then - table.remove (t_incomings, i) - break - end - end + local t_incomings = t.incomings[self] + t_incomings[v] = nil + for i=1,#t_incomings do + if t_incomings[i].tail == v then + table.remove (t_incomings, i) + break + end + end end end @@ -610,12 +616,12 @@ end ---- +--- -- An arc is changed so that instead of connecting |self.tail| -- and |self.head|, it now connects a new |head| and |tail|. The -- difference to first disconnecting and then reconnecting is that all -- fields of the arc (other than |head| and |tail|, of course), will --- be ``moved along.'' Reconnecting an arc in the same way as before has no +-- be ``moved along''. Reconnecting an arc in the same way as before has no -- effect. -- -- If there is already an arc at the new position, fields of the @@ -637,16 +643,16 @@ end -- function Digraph:reconnect(arc, tail, head) assert (arc and tail and head, "connect with nil parameters") - + if arc.head == head and arc.tail == tail then -- Nothing to be done return arc else local new_arc = self:connect(tail, head) - + for k,v in pairs(arc) do if k ~= "head" and k ~= "tail" then - new_arc[k] = v + new_arc[k] = v end end @@ -682,11 +688,11 @@ end -- A collapse vertex will store the collapsed vertices so that you can -- call |expand| later on to ``restore'' the vertices and arcs that -- were saved during a collapse. This storage is \emph{not} local to --- the graph in which the collapse occured. +-- the graph in which the collapse occurred. -- -- @param collapse_vertices An array of to-be-collapsed vertices -- @param collapse_vertex The vertex that represents the collapse. If --- missing, a vertex will be created automatically and added to the graph. +-- missing, a vertex will be created automatically and added to the graph. -- @param vertex_fun This function is called for each to-be-collapsed -- vertex. The parameters are the collapse vertex and the -- to-be-collapsed vertex. May be |nil|. @@ -694,7 +700,7 @@ end -- between |rep| and some other vertex. The arguments are the new arc -- and the original arc. May be |nil|. -- --- @return The new vertex that represents the collapsed vertices. +-- @return The new vertex that represents the collapsed vertices. function Digraph:collapse(collapse_vertices, collapse_vertex, vertex_fun, arc_fun) @@ -704,7 +710,7 @@ function Digraph:collapse(collapse_vertices, collapse_vertex, vertex_fun, arc_fu collapse_vertex = Vertex.new {} end self:add {collapse_vertex} - + -- Copy the collapse_vertices and create lookup local cvs = {} for i=1,#collapse_vertices do @@ -716,29 +722,29 @@ function Digraph:collapse(collapse_vertices, collapse_vertex, vertex_fun, arc_fu -- Connected collapse_vertex appropriately local collapsed_arcs = {} - + if not arc_fun then arc_fun = function () end end - + for _,v in ipairs(cvs) do if vertex_fun then vertex_fun (collapse_vertex, v) end for _,a in ipairs(v.outgoings[self]) do if cvs[a.head] ~= true then - arc_fun (self:connect(collapse_vertex, a.head), a) - collapsed_arcs[#collapsed_arcs + 1] = a + arc_fun (self:connect(collapse_vertex, a.head), a) + collapsed_arcs[#collapsed_arcs + 1] = a end end for _,a in ipairs(v.incomings[self]) do if cvs[a.tail] ~= true then - arc_fun (self:connect(a.tail, collapse_vertex), a) + arc_fun (self:connect(a.tail, collapse_vertex), a) end collapsed_arcs[#collapsed_arcs + 1] = a end end - + -- Remember the old vertices. collapse_vertex.collapsed_vertices = cvs collapse_vertex.collapsed_arcs = collapsed_arcs @@ -770,7 +776,7 @@ function Digraph:expand(vertex, vertex_fun, arc_fun) -- Add all vertices: self:add(cvs) - if vertex_fun then + if vertex_fun then for _,v in ipairs(cvs) do vertex_fun(vertex, v) end @@ -779,13 +785,13 @@ function Digraph:expand(vertex, vertex_fun, arc_fun) -- Add all arcs: for _,arc in ipairs(vertex.collapsed_arcs) do local new_arc = self:connect(arc.tail, arc.head) - + for k,v in pairs(arc) do if k ~= "head" and k ~= "tail" then - new_arc[k] = v + new_arc[k] = v end end - + if arc_fun then arc_fun(new_arc, vertex) end @@ -809,7 +815,7 @@ end ---- +--- -- Computes a string representation of this graph including all nodes -- and edges. The syntax of this representation is such that it can be -- used directly in \tikzname's |graph| syntax. @@ -825,13 +831,13 @@ function Digraph:__tostring() if #out_arcs > 0 then local t = {} for j,a in ipairs(out_arcs) do - t[j] = tostring(a.head) + t[j] = tostring(a.head) end astrings[#astrings + 1] = " " .. tostring(v) .. " -> { " .. table.concat(t,", ") .. " }" end end return "graph [id=" .. tostring(self.vertices) .. "] {\n {\n" .. - table.concat(vstrings, ",\n") .. "\n }; \n" .. + table.concat(vstrings, ",\n") .. "\n }; \n" .. table.concat(astrings, ";\n") .. "\n}"; end @@ -840,4 +846,4 @@ end -- Done -return Digraph
\ No newline at end of file +return Digraph diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Edge.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Edge.lua index 87b06661e54..45cbc60f9f7 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Edge.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Edge.lua @@ -10,12 +10,12 @@ -- @release $Header$ ---- +--- -- An |Edge| is a ``syntactic'' connection between two -- vertices that represents a connection present in the syntactic -- digraph. Unlike an |Arc|, |Edge| objects are not controlled by the -- |Digraph| class. Also unlike |Arc| objects, there can be several --- edges betwen the same vertices, namely whenever several such edges +-- edges between the same vertices, namely whenever several such edges -- are present in the syntactic digraph. -- -- In detail, the relationship between arcs and edges is as follows: @@ -33,15 +33,15 @@ -- second one. Whether -- an edge is directed or not depends on the |direction| of the edge, which -- may be one of the following: --- +-- % -- \begin{enumerate} --- \item |"->"| --- \item |"--"| --- \item |"<-"| --- \item |"<->"| --- \item |"-!-"| +-- \item |"->"| +-- \item |"--"| +-- \item |"<-"| +-- \item |"<->"| +-- \item |"-!-"| -- \end{enumerate} --- +-- -- -- @field head The head vertex of this edge. -- @@ -63,7 +63,7 @@ -- |InterfaceToAlgorithms|. -- -- @field animations An array of animations, see the |animations| --- field of the |Vertex| class for the syntax. +-- field of the |Vertex| class for the syntax. local Edge = {} Edge.__index = Edge @@ -79,14 +79,14 @@ require("pgf.gd.model").Edge = Edge local Path = require "pgf.gd.model.Path" ---- +--- -- Create a new edge. The |initial| parameter allows you to setup -- some initial values. -- -- @usage --\begin{codeexample}[code only, tikz syntax=false] --local v = Edge.new { tail = v1, head = v2 } ---\end{codeexample} +--\end{codeexample} -- -- @param initial Values to override defaults. -- -- @return A new edge object. @@ -125,10 +125,10 @@ end -- Note that you typically do not use this function, but use the -- corresponding function of the |Arc| class. Use this function only -- if there are multiple edges between two vertices that need to be --- routed differently. --- --- Here is the code you would use to create the abovementioned path: +-- routed differently. -- +-- Here is the code you would use to create the above-mentioned path: +-- % --\begin{codeexample}[code only, tikz syntax=false] --local a = g:connect(tail,head) --local e = a.syntactic_edges[1] @@ -140,19 +140,19 @@ end --\end{codeexample} -- -- As for the |Arc| class, you can also setup a polyline more easily: --- +-- % --\begin{codeexample}[code only, tikz syntax=false] --e:setPolylinePath { Coordinate.new (10, 10) } --\end{codeexample} function Edge:tailAnchorForEdgePath() return function () - local a = self.options['tail anchor'] - if a == "" then - a = "center" - end - return self.tail:anchor(a) + self.tail.pos - end + local a = self.options['tail anchor'] + if a == "" then + a = "center" + end + return self.tail:anchor(a) + self.tail.pos + end end --- @@ -160,12 +160,12 @@ end function Edge:headAnchorForEdgePath() return function () - local a = self.options['head anchor'] - if a == "" then - a = "center" - end - return self.head:anchor(a) + self.head.pos - end + local a = self.options['head anchor'] + if a == "" then + a = "center" + end + return self.head:anchor(a) + self.head.pos + end end @@ -188,7 +188,7 @@ function Edge:setPolylinePath(coordinates) end p:appendLineto(self:headAnchorForEdgePath()) - + self.path = p end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Hyperedge.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Hyperedge.lua index 3819e193689..cc265023fa5 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Hyperedge.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Hyperedge.lua @@ -11,7 +11,7 @@ ---- +--- -- @section subsection {Hyperedges} -- -- @end @@ -28,19 +28,19 @@ declare { key = "hyper", layer = -10, - summary = [[" - A \emph{hyperedge} of a graph does not connect just two nodes, but - is any subset of the node set (although a normal edge is also a - hyperedge that happens to contain just two nodes). Internally, a - collection of kind |hyper| is created. Currently, there is - no default renderer for hyper edges. + summary = [[" + A \emph{hyperedge} of a graph does not connect just two nodes, but + is any subset of the node set (although a normal edge is also a + hyperedge that happens to contain just two nodes). Internally, a + collection of kind |hyper| is created. Currently, there is + no default renderer for hyper edges. "]], documentation = [[" \begin{codeexample}[code only] \graph { % The nodes: a, b, c, d; - + % The edges: {[hyper] a,b,c}; {[hyper] b,c,d}; @@ -50,7 +50,7 @@ declare { \end{codeexample} "]] } - --- Done + +-- Done return Hyperedge
\ No newline at end of file diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path.lua index 93cd44cc218..cbd0f079bfb 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path.lua @@ -10,32 +10,32 @@ -- @release $Header$ ---- +--- -- A Path models a path in the plane. -- -- Following the PostScript/\textsc{pdf}/\textsc{svg} convention, a -- path consists of a series of path segments, each of which can be --- closed or not. Each path segement, in turn, consists of a series of --- Bézier curvers and straight line segments; see +-- closed or not. Each path segment, in turn, consists of a series of +-- Bézier curves and straight line segments; see -- Section~\ref{section-paths} for an introduction to paths in -- general. -- -- A |Path| object is a table whose array part stores --- |Coordinate| objects, |strings|, and |function|s that --- describe the path of the edge. The following strings are allowed in +-- |Coordinate| objects, |strings|, and |function|s that +-- describe the path of the edge. The following strings are allowed in -- this array: --- +-- % -- \begin{itemize} --- \item |"moveto"| The line's path should stop at the current --- position and then start anew at the next coordinate in the array. --- \item |"lineto"| The line should continue from the current position --- to the next coordinate in the array. --- \item |"curveto"| The line should continue form the current --- position with a Bézier curve that is specified bz the next three --- |Coordinate| objects (in the usual manner). --- \item |"closepath"| The line's path should be ``closed'' in the sense --- that the current subpath that was started with the most recent --- moveto operation should now form a closed curve. +-- \item |"moveto"| The line's path should stop at the current +-- position and then start anew at the next coordinate in the array. +-- \item |"lineto"| The line should continue from the current position +-- to the next coordinate in the array. +-- \item |"curveto"| The line should continue form the current +-- position with a Bézier curve that is specified by the next three +-- |Coordinate| objects (in the usual manner). +-- \item |"closepath"| The line's path should be ``closed'' in the sense +-- that the current subpath that was started with the most recent +-- moveto operation should now form a closed curve. -- \end{itemize} -- -- Instead of a |Coordinate|, a |Path| may also contain a function. In @@ -93,36 +93,36 @@ function Path.new(initial) while i <= #initial do local e = initial[i] if type(e) == "string" then - assert (count == 0, "illformed path") - if e == "moveto" then - count = 1 - elseif e == "lineto" then - count = 1 - elseif e == "closepath" then - count = 0 - elseif e == "curveto" then - count = 3 - else - error ("unknown path command " .. e) - end - new[#new+1] = e + assert (count == 0, "illformed path") + if e == "moveto" then + count = 1 + elseif e == "lineto" then + count = 1 + elseif e == "closepath" then + count = 0 + elseif e == "curveto" then + count = 3 + else + error ("unknown path command " .. e) + end + new[#new+1] = e elseif type(e) == "number" then - if count == 0 then - new[#new+1] = "lineto" - else - count = count - 1 - end - new[#new+1] = Coordinate.new(e,initial[i+1]) - i = i + 1 + if count == 0 then + new[#new+1] = "lineto" + else + count = count - 1 + end + new[#new+1] = Coordinate.new(e,initial[i+1]) + i = i + 1 elseif type(e) == "table" or type(e) == "function" then - if count == 0 then - new[#new+1] = "lineto" - else - count = count - 1 - end - new[#new+1] = e + if count == 0 then + new[#new+1] = "lineto" + else + count = count - 1 + end + new[#new+1] = e else - error ("invalid object on path") + error ("invalid object on path") end i = i + 1 end @@ -158,7 +158,7 @@ end -- @return A copy of the reversed path function Path:reversed() - + -- First, build segments local subpaths = {} local subpath = {} @@ -169,7 +169,7 @@ function Path:reversed() subpath = {} end end - + local prev local start @@ -178,9 +178,9 @@ function Path:reversed() local x = self[i] if x == "lineto" then subpath[#subpath+1] = { - action = 'lineto', - from = prev, - to = self[i+1] + action = 'lineto', + from = prev, + to = self[i+1] } prev = self[i+1] i = i + 2 @@ -192,9 +192,9 @@ function Path:reversed() i = i + 2 elseif x == "closepath" then subpath [#subpath + 1] = { - action = "closepath", - from = prev, - to = start, + action = "closepath", + from = prev, + to = start, } prev = nil start = nil @@ -203,11 +203,11 @@ function Path:reversed() elseif x == "curveto" then local s1, s2, to = self[i+1], self[i+2], self[i+3] subpath [#subpath + 1] = { - action = "curveto", - from = prev, - to = to, - support_1 = s1, - support_2 = s2, + action = "curveto", + from = prev, + to = to, + support_1 = s1, + support_2 = s2, } prev = self[i+3] i = i + 4 @@ -216,7 +216,7 @@ function Path:reversed() end end closepath () - + local new = Path.new () for _,subpath in ipairs(subpaths) do @@ -226,29 +226,29 @@ function Path:reversed() else -- We start with a moveto to the end point: new:appendMoveto(subpath[#subpath].to) - + -- Now walk backwards: for i=#subpath,1,-1 do - if subpath[i].action == "lineto" then - new:appendLineto(subpath[i].from) - elseif subpath[i].action == "closepath" then - new:appendLineto(subpath[i].from) - elseif subpath[i].action == "curveto" then - new:appendCurveto(subpath[i].support_2, - subpath[i].support_1, - subpath[i].from) - else - error("illegal path command") - end + if subpath[i].action == "lineto" then + new:appendLineto(subpath[i].from) + elseif subpath[i].action == "closepath" then + new:appendLineto(subpath[i].from) + elseif subpath[i].action == "curveto" then + new:appendCurveto(subpath[i].support_2, + subpath[i].support_1, + subpath[i].from) + else + error("illegal path command") + end end -- Append a closepath, if necessary if subpath[#subpath].action == "closepath" then - new:appendClosepath() + new:appendClosepath() end end end - + return new end @@ -314,7 +314,7 @@ end -- Appends a |moveto| to the path. -- -- @param x A |Coordinate| or |function| or, if the |y| parameter is --- not |nil|, a number that is the $x$-part of a coordiante . +-- not |nil|, a number that is the $x$-part of a coordinate. -- @param y The $y$-part of the coordinate. function Path:appendMoveto(x,y) @@ -327,7 +327,7 @@ end -- Appends a |lineto| to the path. -- -- @param x A |Coordinate| or |function|, if the |y| parameter is not --- |nil|, a number that is the $x$-part of a coordiante . +-- |nil|, a number that is the $x$-part of a coordinate. -- @param y The $y$-part of the coordinate. function Path:appendLineto(x,y) @@ -362,7 +362,7 @@ function Path:appendCurveto(a,b,c,d,e,f) self[#self + 1] = a self[#self + 1] = b self[#self + 1] = c - end + end end @@ -371,7 +371,7 @@ end --- --- Makes a path ``rigid,'' meaning that all coordinates that are only +-- Makes a path ``rigid'', meaning that all coordinates that are only -- given as functions are replaced by the values these functions -- yield. @@ -406,7 +406,7 @@ end -- Returns a bounding box of the path. This will not necessarily be -- the minimal bounding box in case the path contains curves because, -- then, the support points of the curve are used for the computation --- rather than the actual boinding box of the path. +-- rather than the actual bounding box of the path. -- -- If the path contains no coordinates, all return values are 0. -- @@ -415,22 +415,22 @@ end -- @return |max_x| -- @return |max_y| -- @return |center_x| The center of the bounding box --- @return |center_y| +-- @return |center_y| function Path:boundingBox() if #self > 0 then local min_x, min_y = math.huge, math.huge local max_x, max_y = -math.huge, -math.huge - + for i=1,#self do local c = rigid(self[i]) if type(c) == "table" then - local x = c.x - local y = c.y - if x < min_x then min_x = x end - if y < min_y then min_y = y end - if x > max_x then max_x = x end - if y > max_y then max_y = y end + local x = c.x + local y = c.y + if x < min_x then min_x = x end + if y < min_y then min_y = y end + if x > max_x then max_x = x end + if y > max_y then max_y = y end end end @@ -453,21 +453,22 @@ local eps = 0.0001 --- -- Computes all intersections of a path with another path and returns -- them as an array of coordinates. The intersections will be sorted --- ``along the path |self|.'' The implementation uses a +-- ``along the path |self|''. The implementation uses a -- divide-and-conquer approach that should be reasonably fast in --- practice. +-- practice. -- -- @param path Another path -- -- @return Array of all intersections of |path| with |self| in the -- order they appear on |self|. Each entry of this array is a table -- with the following fields: +-- % -- \begin{itemize} --- \item |index| The index of the segment in |self| where --- the intersection occurs. --- \item |time| The ``time'' at which a point travelling along the --- segment from its start point to its end point. --- \item |point| The point itself. +-- \item |index| The index of the segment in |self| where +-- the intersection occurs. +-- \item |time| The ``time'' at which a point traveling along the +-- segment from its start point to its end point. +-- \item |point| The point itself. -- \end{itemize} function Path:intersectionsWith(path) @@ -478,13 +479,13 @@ function Path:intersectionsWith(path) local memo2 = prepare_memo(p2) local intersections = {} - + local function intersect_segments(i1, i2) - + local s1 = p1[i1] local s2 = p2[i2] local r = {} - + if s1.action == 'lineto' and s2.action == 'lineto' then local a = s2.to.x - s2.from.x local b = s1.from.x - s1.to.x @@ -492,103 +493,103 @@ function Path:intersectionsWith(path) local d = s2.to.y - s2.from.y local e = s1.from.y - s1.to.y local f = s2.from.y - s1.from.y - + local det = a*e - b*d - + if math.abs(det) > eps*eps then - local t, s = (c*d - a*f)/det, (b*f - e*c)/det + local t, s = (c*d - a*f)/det, (b*f - e*c)/det - if t >= 0 and t<=1 and s>=0 and s <= 1 then - local p = s1.from:clone() - p:moveTowards(s1.to, t) - return { { time = t, point = p } } - end + if t >= 0 and t<=1 and s>=0 and s <= 1 then + local p = s1.from:clone() + p:moveTowards(s1.to, t) + return { { time = t, point = p } } + end end elseif s1.action == 'lineto' and s2.action == 'curveto' then intersect_curves (0, 1, - s1.from.x, s1.from.y, - s1.from.x*2/3+s1.to.x*1/3, s1.from.y*2/3+s1.to.y*1/3, - s1.from.x*1/3+s1.to.x*2/3, s1.from.y*1/3+s1.to.y*2/3, - s1.to.x, s1.to.y, - s2.from.x, s2.from.y, - s2.support_1.x, s2.support_1.y, - s2.support_2.x, s2.support_2.y, - s2.to.x, s2.to.y, - r) + s1.from.x, s1.from.y, + s1.from.x*2/3+s1.to.x*1/3, s1.from.y*2/3+s1.to.y*1/3, + s1.from.x*1/3+s1.to.x*2/3, s1.from.y*1/3+s1.to.y*2/3, + s1.to.x, s1.to.y, + s2.from.x, s2.from.y, + s2.support_1.x, s2.support_1.y, + s2.support_2.x, s2.support_2.y, + s2.to.x, s2.to.y, + r) elseif s1.action == 'curveto' and s2.action == 'lineto' then intersect_curves (0, 1, - s1.from.x, s1.from.y, - s1.support_1.x, s1.support_1.y, - s1.support_2.x, s1.support_2.y, - s1.to.x, s1.to.y, - s2.from.x, s2.from.y, - s2.from.x*2/3+s2.to.x*1/3, s2.from.y*2/3+s2.to.y*1/3, - s2.from.x*1/3+s2.to.x*2/3, s2.from.y*1/3+s2.to.y*2/3, - s2.to.x, s2.to.y, - r) + s1.from.x, s1.from.y, + s1.support_1.x, s1.support_1.y, + s1.support_2.x, s1.support_2.y, + s1.to.x, s1.to.y, + s2.from.x, s2.from.y, + s2.from.x*2/3+s2.to.x*1/3, s2.from.y*2/3+s2.to.y*1/3, + s2.from.x*1/3+s2.to.x*2/3, s2.from.y*1/3+s2.to.y*2/3, + s2.to.x, s2.to.y, + r) else intersect_curves (0, 1, - s1.from.x, s1.from.y, - s1.support_1.x, s1.support_1.y, - s1.support_2.x, s1.support_2.y, - s1.to.x, s1.to.y, - s2.from.x, s2.from.y, - s2.support_1.x, s2.support_1.y, - s2.support_2.x, s2.support_2.y, - s2.to.x, s2.to.y, - r) + s1.from.x, s1.from.y, + s1.support_1.x, s1.support_1.y, + s1.support_2.x, s1.support_2.y, + s1.to.x, s1.to.y, + s2.from.x, s2.from.y, + s2.support_1.x, s2.support_1.y, + s2.support_2.x, s2.support_2.y, + s2.to.x, s2.to.y, + r) end return r end - + local function intersect (i1, j1, i2, j2) if i1 > j1 or i2 > j2 then return end - + local bb1 = bb(i1, j1, memo1) local bb2 = bb(i2, j2, memo2) - + if boxes_intersect(bb1, bb2) then -- Ok, need to do something if i1 == j1 and i2 == j2 then - local intersects = intersect_segments (i1, i2) - for _,t in ipairs(intersects) do - intersections[#intersections+1] = { - time = t.time, - index = p1[i1].path_pos, - point = t.point - } - end + local intersects = intersect_segments (i1, i2) + for _,t in ipairs(intersects) do + intersections[#intersections+1] = { + time = t.time, + index = p1[i1].path_pos, + point = t.point + } + end elseif i1 == j1 then - local m2 = math.floor((i2 + j2) / 2) - intersect(i1, j1, i2, m2) - intersect(i1, j1, m2+1, j2) + local m2 = math.floor((i2 + j2) / 2) + intersect(i1, j1, i2, m2) + intersect(i1, j1, m2+1, j2) elseif i2 == j2 then - local m1 = math.floor((i1 + j1) / 2) - intersect(i1, m1, i2, j2) - intersect(m1+1, j1, i2, j2) + local m1 = math.floor((i1 + j1) / 2) + intersect(i1, m1, i2, j2) + intersect(m1+1, j1, i2, j2) else - local m1 = math.floor((i1 + j1) / 2) - local m2 = math.floor((i2 + j2) / 2) - intersect(i1, m1, i2, m2) - intersect(m1+1, j1, i2, m2) - intersect(i1, m1, m2+1, j2) - intersect(m1+1, j1, m2+1, j2) + local m1 = math.floor((i1 + j1) / 2) + local m2 = math.floor((i2 + j2) / 2) + intersect(i1, m1, i2, m2) + intersect(m1+1, j1, i2, m2) + intersect(i1, m1, m2+1, j2) + intersect(m1+1, j1, m2+1, j2) end - end + end end - + -- Run the recursion intersect(1, #p1, 1, #p2) -- Sort table.sort(intersections, function(a,b) - return a.index < b.index or - a.index == b.index and a.time < b.time - end) - + return a.index < b.index or + a.index == b.index and a.time < b.time + end) + -- Remove duplicates local remains = {} remains[1] = intersections[1] @@ -608,15 +609,15 @@ end function boxes_intersect (bb1, bb2) return (bb1.max_x >= bb2.min_x - eps*eps and - bb1.min_x <= bb2.max_x + eps*eps and - bb1.max_y >= bb2.min_y - eps*eps and - bb1.min_y <= bb2.max_y + eps*eps) + bb1.min_x <= bb2.max_x + eps*eps and + bb1.max_y >= bb2.min_y - eps*eps and + bb1.min_y <= bb2.max_y + eps*eps) end -- Turns a path into a sequence of segments, each being either a -- lineto or a curveto from some point to another point. It also sets --- up a memoization array for the bounding boxes. +-- up a memorization array for the bounding boxes. function segmentize (path) @@ -627,20 +628,20 @@ function segmentize (path) local i = 1 while i <= #path do local x = path[i] - + if x == "lineto" then x = rigid(path[i+1]) s [#s + 1] = { - path_pos = i, - action = "lineto", - from = prev, - to = x, - bb = { - min_x = math.min(prev.x, x.x), - max_x = math.max(prev.x, x.x), - min_y = math.min(prev.y, x.y), - max_y = math.max(prev.y, x.y), - } + path_pos = i, + action = "lineto", + from = prev, + to = x, + bb = { + min_x = math.min(prev.x, x.x), + max_x = math.max(prev.x, x.x), + min_y = math.min(prev.y, x.y), + max_y = math.max(prev.y, x.y), + } } prev = x i = i + 2 @@ -650,16 +651,16 @@ function segmentize (path) i = i + 2 elseif x == "closepath" then s [#s + 1] = { - path_pos = i, - action = "lineto", - from = prev, - to = start, - bb = { - min_x = math.min(prev.x, start.x), - max_x = math.max(prev.x, start.x), - min_y = math.min(prev.y, start.y), - max_y = math.max(prev.y, start.y), - } + path_pos = i, + action = "lineto", + from = prev, + to = start, + bb = { + min_x = math.min(prev.x, start.x), + max_x = math.max(prev.x, start.x), + min_y = math.min(prev.y, start.y), + max_y = math.max(prev.y, start.y), + } } prev = nil start = nil @@ -667,18 +668,18 @@ function segmentize (path) elseif x == "curveto" then local s1, s2, to = rigid(path[i+1]), rigid(path[i+2]), rigid(path[i+3]) s [#s + 1] = { - action = "curveto", - path_pos = i, - from = prev, - to = to, - support_1 = s1, - support_2 = s2, - bb = { - min_x = math.min(prev.x, s1.x, s2.x, to.x), - max_x = math.max(prev.x, s1.x, s2.x, to.x), - min_y = math.min(prev.y, s1.y, s2.y, to.y), - max_y = math.max(prev.y, s1.y, s2.y, to.y), - } + action = "curveto", + path_pos = i, + from = prev, + to = to, + support_1 = s1, + support_2 = s2, + bb = { + min_x = math.min(prev.x, s1.x, s2.x, to.x), + max_x = math.max(prev.x, s1.x, s2.x, to.x), + min_y = math.min(prev.y, s1.y, s2.y, to.y), + max_y = math.max(prev.y, s1.y, s2.y, to.y), + } } prev = path[i+3] i = i + 4 @@ -692,16 +693,16 @@ end function prepare_memo (s) - + local memo = {} - + memo.base = #s - + -- Fill memo table for i,e in ipairs (s) do memo[i*#s + i] = e.bb end - + return memo end @@ -712,8 +713,8 @@ end function bb (i, j, memo) local b = memo[memo.base*i + j] if not b then - assert (i < j, "memoization table filled incorrectly") - + assert (i < j, "memorization table filled incorrectly") + local mid = math.floor((i+j)/2) local bb1 = bb (i, mid, memo) local bb2 = bb (mid+1, j, memo) @@ -725,21 +726,21 @@ function bb (i, j, memo) } memo[memo.base*i + j] = b end - + return b end --- Intersect two Bezier curves. +-- Intersect two Bézier curves. function intersect_curves(t0, t1, - c1_ax, c1_ay, c1_bx, c1_by, - c1_cx, c1_cy, c1_dx, c1_dy, - c2_ax, c2_ay, c2_bx, c2_by, - c2_cx, c2_cy, c2_dx, c2_dy, - intersections) - + c1_ax, c1_ay, c1_bx, c1_by, + c1_cx, c1_cy, c1_dx, c1_dy, + c2_ax, c2_ay, c2_bx, c2_by, + c2_cx, c2_cy, c2_dx, c2_dy, + intersections) + -- Only do something, if the bounding boxes intersect: local c1_min_x = math.min(c1_ax, c1_bx, c1_cx, c1_dx) local c1_max_x = math.max(c1_ax, c1_bx, c1_cx, c1_dx) @@ -749,12 +750,12 @@ function intersect_curves(t0, t1, local c2_max_x = math.max(c2_ax, c2_bx, c2_cx, c2_dx) local c2_min_y = math.min(c2_ay, c2_by, c2_cy, c2_dy) local c2_max_y = math.max(c2_ay, c2_by, c2_cy, c2_dy) - + if c1_max_x >= c2_min_x and c1_min_x <= c2_max_x and c1_max_y >= c2_min_y and - c1_min_y <= c2_max_y then - + c1_min_y <= c2_max_y then + -- Everything "near together"? if c1_max_x - c1_min_x < eps and c1_max_y - c1_min_y < eps then @@ -765,57 +766,57 @@ function intersect_curves(t0, t1, local d = c2_dy - c2_ay local e = c1_ay - c1_dy local f = c2_ay - c1_ay - + local det = a*e - b*d local t - + t = (c*d - a*f)/det if t<0 then - t=0 + t=0 elseif t>1 then - t=1 + t=1 end intersections [#intersections + 1] = { - time = t0 + t*(t1-t0), - point = Coordinate.new(c1_ax + t*(c1_dx-c1_ax), c1_ay+t*(c1_dy-c1_ay)) + time = t0 + t*(t1-t0), + point = Coordinate.new(c1_ax + t*(c1_dx-c1_ax), c1_ay+t*(c1_dy-c1_ay)) } else -- Cut 'em in half! local c1_ex, c1_ey = (c1_ax + c1_bx)/2, (c1_ay + c1_by)/2 local c1_fx, c1_fy = (c1_bx + c1_cx)/2, (c1_by + c1_cy)/2 local c1_gx, c1_gy = (c1_cx + c1_dx)/2, (c1_cy + c1_dy)/2 - + local c1_hx, c1_hy = (c1_ex + c1_fx)/2, (c1_ey + c1_fy)/2 local c1_ix, c1_iy = (c1_fx + c1_gx)/2, (c1_fy + c1_gy)/2 - + local c1_jx, c1_jy = (c1_hx + c1_ix)/2, (c1_hy + c1_iy)/2 - + local c2_ex, c2_ey = (c2_ax + c2_bx)/2, (c2_ay + c2_by)/2 local c2_fx, c2_fy = (c2_bx + c2_cx)/2, (c2_by + c2_cy)/2 local c2_gx, c2_gy = (c2_cx + c2_dx)/2, (c2_cy + c2_dy)/2 - + local c2_hx, c2_hy = (c2_ex + c2_fx)/2, (c2_ey + c2_fy)/2 local c2_ix, c2_iy = (c2_fx + c2_gx)/2, (c2_fy + c2_gy)/2 - + local c2_jx, c2_jy = (c2_hx + c2_ix)/2, (c2_hy + c2_iy)/2 intersect_curves (t0, (t0+t1)/2, - c1_ax, c1_ay, c1_ex, c1_ey, c1_hx, c1_hy, c1_jx, c1_jy, - c2_ax, c2_ay, c2_ex, c2_ey, c2_hx, c2_hy, c2_jx, c2_jy, - intersections) + c1_ax, c1_ay, c1_ex, c1_ey, c1_hx, c1_hy, c1_jx, c1_jy, + c2_ax, c2_ay, c2_ex, c2_ey, c2_hx, c2_hy, c2_jx, c2_jy, + intersections) intersect_curves (t0, (t0+t1)/2, - c1_ax, c1_ay, c1_ex, c1_ey, c1_hx, c1_hy, c1_jx, c1_jy, - c2_jx, c2_jy, c2_ix, c2_iy, c2_gx, c2_gy, c2_dx, c2_dy, - intersections) + c1_ax, c1_ay, c1_ex, c1_ey, c1_hx, c1_hy, c1_jx, c1_jy, + c2_jx, c2_jy, c2_ix, c2_iy, c2_gx, c2_gy, c2_dx, c2_dy, + intersections) intersect_curves ((t0+t1)/2, t1, - c1_jx, c1_jy, c1_ix, c1_iy, c1_gx, c1_gy, c1_dx, c1_dy, - c2_ax, c2_ay, c2_ex, c2_ey, c2_hx, c2_hy, c2_jx, c2_jy, - intersections) + c1_jx, c1_jy, c1_ix, c1_iy, c1_gx, c1_gy, c1_dx, c1_dy, + c2_ax, c2_ay, c2_ex, c2_ey, c2_hx, c2_hy, c2_jx, c2_jy, + intersections) intersect_curves ((t0+t1)/2, t1, - c1_jx, c1_jy, c1_ix, c1_iy, c1_gx, c1_gy, c1_dx, c1_dy, - c2_jx, c2_jy, c2_ix, c2_iy, c2_gx, c2_gy, c2_dx, c2_dy, - intersections) + c1_jx, c1_jy, c1_ix, c1_iy, c1_gx, c1_gy, c1_dx, c1_dy, + c2_jx, c2_jy, c2_ix, c2_iy, c2_gx, c2_gy, c2_dx, c2_dy, + intersections) end end end @@ -828,30 +829,30 @@ end -- segment and everything in the segment before the given time is -- removed from the path. -- --- @param index The index of a path segment. +-- @param index The index of a path segment. -- @param time A time along the specified path segment. function Path:cutAtBeginning(index, time) - + local cut_path = Path:new () - + -- Ok, first, we need to find the segment *before* the current -- one. Usually, this will be a moveto or a lineto, but things could -- be different. assert (type(self[index-1]) == "table" or type(self[index-1]) == "function", - "segment before intersection does not end with a coordinate") + "segment before intersection does not end with a coordinate") local from = rigid(self[index-1]) local action = self[index] - + -- Now, depending on the type of segment, we do different things: if action == "lineto" then - + -- Ok, compute point: local to = rigid(self[index+1]) from:moveTowards(to, time) - + -- Ok, this is easy: We start with a fresh moveto ... cut_path[1] = "moveto" cut_path[2] = from @@ -888,20 +889,20 @@ function Path:cutAtBeginning(index, time) for i=index+4,#self do cut_path[#cut_path+1] = self[i] end - + elseif action == "closepath" then -- Let us find the start point: - local found + local found for i=index,1,-1 do if self[i] == "moveto" then - -- Bingo: - found = i - break + -- Bingo: + found = i + break end end assert(found, "no moveto found in path") - + local to = rigid(self[found+1]) from:moveTowards(to,time) @@ -934,36 +935,36 @@ end -- Shorten a path at the end. This method works like |cutAtBeginning|, -- only the path is cut at the end. -- --- @param index The index of a path segment. +-- @param index The index of a path segment. -- @param time A time along the specified path segment. function Path:cutAtEnd(index, time) local cut_path = Path:new () - + -- Ok, first, we need to find the segment *before* the current -- one. Usually, this will be a moveto or a lineto, but things could -- be different. assert (type(self[index-1]) == "table" or type(self[index-1]) == "function", - "segment before intersection does not end with a coordinate") + "segment before intersection does not end with a coordinate") local from = rigid(self[index-1]) local action = self[index] - + -- Now, depending on the type of segment, we do different things: if action == "lineto" then - + -- Ok, compute point: local to = rigid(self[index+1]) to:moveTowards(from, 1-time) - + for i=1,index do cut_path[i] = self[i] end cut_path[index+1] = to - + elseif action == "curveto" then - + local s1 = rigid(self[index+1]) local s2 = rigid(self[index+2]) local to = rigid(self[index+3]) @@ -986,20 +987,20 @@ function Path:cutAtEnd(index, time) cut_path[index+1] = s1 cut_path[index+2] = s2 cut_path[index+3] = to - + elseif action == "closepath" then -- Let us find the start point: - local found + local found for i=index,1,-1 do if self[i] == "moveto" then - -- Bingo: - found = i - break + -- Bingo: + found = i + break end end assert(found, "no moveto found in path") - + local to = rigid(self[found+1]:clone()) to:moveTowards(from,1-time) @@ -1028,7 +1029,7 @@ end -- ``Pads'' the path. The idea is the following: Suppose we stroke the -- path with a pen whose width is twice the value |padding|. The outer -- edge of this stroked drawing is now a path by itself. The path will --- be a bit longer and ``larger.'' The present function tries to +-- be a bit longer and ``larger''. The present function tries to -- compute an approximation to this resulting path. -- -- The algorithm used to compute the enlarged part does not necessarily @@ -1040,29 +1041,29 @@ end -- function Path:pad(padding) - + local padded = self:clone() padded:makeRigid() if padding == 0 then return padded end - + -- First, decompose the path into subpaths: local subpaths = {} local subpath = {} local start_index = 1 - + local function closepath(end_index) if #subpath >= 1 then subpath.start_index = start_index subpath.end_index = end_index start_index = end_index + 1 - + local start = 1 if (subpath[#subpath] - subpath[1]):norm() < 0.01 and subpath[2] then - start = 2 - subpath.skipped = subpath[1] + start = 2 + subpath.skipped = subpath[1] end subpath[#subpath + 1] = subpath[start] subpath[#subpath + 1] = subpath[start+1] @@ -1070,11 +1071,11 @@ function Path:pad(padding) subpath = {} end end - + for i,p in ipairs(padded) do if p ~= "closepath" then if type(p) == "table" then - subpath[#subpath + 1] = p + subpath[#subpath + 1] = p end else closepath (i) @@ -1087,7 +1088,7 @@ function Path:pad(padding) local new_coordinates = {} local _,_,_,_,c_x,c_y = Coordinate.boundingBox(subpath) local c = Coordinate.new(c_x,c_y) - + -- Find out the orientation of the path local count = 0 for i=1,#subpath-2 do @@ -1095,19 +1096,19 @@ function Path:pad(padding) local d1 = subpath[i+2] - subpath[i+1] local diff = math.atan2(d2.y,d2.x) - math.atan2(d1.y,d1.x) - + if diff < -math.pi then - count = count + 1 + count = count + 1 elseif diff > math.pi then - count = count - 1 + count = count - 1 end end - + for i=2,#subpath-1 do local p = subpath[i] local d1 = subpath[i] - subpath[i-1] local d2 = subpath[i+1] - subpath[i] - + local orth1 = Coordinate.new(-d1.y, d1.x) local orth2 = Coordinate.new(-d2.y, d2.x) @@ -1115,21 +1116,21 @@ function Path:pad(padding) orth2:normalize() if count < 0 then - orth1:scale(-1) - orth2:scale(-1) + orth1:scale(-1) + orth2:scale(-1) end -- Ok, now we want to compute the intersection of the lines -- perpendicular to p + padding*orth1 and p + padding*orth2: - + local det = orth1.x * orth2.y - orth1.y * orth2.x local c if math.abs(det) < 0.1 then - c = orth1 + orth2 - c:scale(padding/2) + c = orth1 + orth2 + c:scale(padding/2) else - c = Coordinate.new (padding*(orth2.y-orth1.y)/det, padding*(orth1.x-orth2.x)/det) + c = Coordinate.new (padding*(orth2.y-orth1.y)/det, padding*(orth1.x-orth2.x)/det) end new_coordinates[i] = c+p @@ -1146,50 +1147,50 @@ function Path:pad(padding) local p = subpath[1] local new_p = new_coordinates[#subpath-2] p.x = new_p.x - p.y = new_p.y + p.y = new_p.y end - + -- Now, we need to correct the curveto fields: for i=subpath.start_index,subpath.end_index do if self[i] == 'curveto' then - local from = rigid(self[i-1]) - local s1 = rigid(self[i+1]) - local s2 = rigid(self[i+2]) - local to = rigid(self[i+3]) - - local p1x, p1y, _, _, h1x, h1y = - Bezier.atTime(from.x, from.y, s1.x, s1.y, s2.x, s2.y, - to.x, to.y, 1/3) - - local p2x, p2y, _, _, _, _, h2x, h2y = - Bezier.atTime(from.x, from.y, s1.x, s1.y, s2.x, s2.y, - to.x, to.y, 2/3) - - local orth1 = Coordinate.new (p1y - h1y, -(p1x - h1x)) - orth1:normalize() - orth1:scale(-padding) - - local orth2 = Coordinate.new (p2y - h2y, -(p2x - h2x)) - orth2:normalize() - orth2:scale(padding) - - if count < 0 then - orth1:scale(-1) - orth2:scale(-1) - end - - local new_s1, new_s2 = - Bezier.supportsForPointsAtTime(padded[i-1], - Coordinate.new(p1x+orth1.x,p1y+orth1.y), 1/3, - Coordinate.new(p2x+orth2.x,p2y+orth2.y), 2/3, - padded[i+3]) - - padded[i+1] = new_s1 - padded[i+2] = new_s2 + local from = rigid(self[i-1]) + local s1 = rigid(self[i+1]) + local s2 = rigid(self[i+2]) + local to = rigid(self[i+3]) + + local p1x, p1y, _, _, h1x, h1y = + Bezier.atTime(from.x, from.y, s1.x, s1.y, s2.x, s2.y, + to.x, to.y, 1/3) + + local p2x, p2y, _, _, _, _, h2x, h2y = + Bezier.atTime(from.x, from.y, s1.x, s1.y, s2.x, s2.y, + to.x, to.y, 2/3) + + local orth1 = Coordinate.new (p1y - h1y, -(p1x - h1x)) + orth1:normalize() + orth1:scale(-padding) + + local orth2 = Coordinate.new (p2y - h2y, -(p2x - h2x)) + orth2:normalize() + orth2:scale(padding) + + if count < 0 then + orth1:scale(-1) + orth2:scale(-1) + end + + local new_s1, new_s2 = + Bezier.supportsForPointsAtTime(padded[i-1], + Coordinate.new(p1x+orth1.x,p1y+orth1.y), 1/3, + Coordinate.new(p2x+orth2.x,p2y+orth2.y), 2/3, + padded[i+3]) + + padded[i+1] = new_s1 + padded[i+2] = new_s2 end end end - + return padded end @@ -1202,12 +1203,12 @@ end -- the following happens: We first invert the transformation -- and apply it to the start point. Then we compute the arc -- ``normally'', as if no transformation matrix were present. Then we --- apply the transformation matrix to all computed points. +-- apply the transformation matrix to all computed points. -- -- @function Path:appendArc(start_angle,end_angle,radius,trans) -- -- @param start_angle The start angle of the arc. Must be specified in --- degrees. +-- degrees. -- @param end_angle the end angle of the arc. -- @param radius The radius of the circle on which this arc lies. -- @param trans A transformation matrix. If |nil|, the identity @@ -1232,7 +1233,7 @@ Path.appendArc = lib.ondemand("Path_arced", Path, "appendArc") -- of the circle. -- @param clockwise If true, the arc will be clockwise. Otherwise (the -- default, if nothing or |nil| is given), the arc will be counter --- clockise. +-- clockwise. -- @param trans A transformation matrix. If missing, -- the identity matrix is assumed. @@ -1249,7 +1250,7 @@ function Path:__tostring() local i = 1 while i <= #self do local p = self[i] - + if p == "lineto" then r [#r+1] = " -- " .. tostring(rigid(self[i+1])) i = i + 1 @@ -1274,4 +1275,4 @@ end -- Done -return Path
\ No newline at end of file +return Path diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path_arced.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path_arced.lua index 92dd8ad87ac..1875b8d1a50 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path_arced.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Path_arced.lua @@ -61,7 +61,7 @@ local function cos_quarter(x) end local function atan2deg(y,x) - + -- Works like atan2, but returns the angle in degrees and, returns -- exactly a multiple of 90 if x or y are zero @@ -80,14 +80,14 @@ local function atan2deg(y,x) else return atan2(y,x) * to_deg end - + end local function subarc (path, startx, starty, start_angle, delta, radius, trans, center_x, center_y) - + local end_angle = start_angle + delta local factor = tan (delta*to_rad/4) * 1.333333333333333333333 * radius - + local s1, c1, s190, c190, s2, c2, s290, c290 if start_angle % 90 == 0 then @@ -103,7 +103,7 @@ local function subarc (path, startx, starty, start_angle, delta, radius, trans, local a2 = end_angle * to_rad s2, c2, s290, c290 = sin(a2), cos(a2), sin(a2-pi_half), cos(a2-pi_half) end - + local lastx, lasty = center_x + c2*radius, center_y + s2*radius path[#path + 1] = "curveto" @@ -116,14 +116,14 @@ local function subarc (path, startx, starty, start_angle, delta, radius, trans, path[#path-1]:apply(trans) path[#path ]:apply(trans) end - + return lastx, lasty, end_angle end local function arc (path, start, start_angle, end_angle, radius, trans, centerx, centery) - + -- @param path is the path object -- @param start is the start coordinate -- @param start_angle is given in degrees @@ -132,65 +132,65 @@ local function arc (path, start, start_angle, end_angle, radius, trans, centerx, -- @param trans is an optional transformation matrix that gets applied to all computed points -- @param centerx optionally: x-part of the center of the circle -- @param centery optionally: y-part of the center of the circle - + local startx, starty = start.x, start.y - + -- Compute center: centerx = centerx or startx - cos(start_angle*to_rad)*radius centery = centery or starty - sin(start_angle*to_rad)*radius - + if start_angle < end_angle then -- First, ensure that the angles are in a reasonable range: start_angle = start_angle % 360 end_angle = end_angle % 360 - + if end_angle <= start_angle then - -- In case the modulo has inadvertedly moved the end angle + -- In case the modulo has inadvertently moved the end angle -- before the start angle: end_angle = end_angle + 360 end - + -- Ok, now create a series of arcs that are at most quarter-cycles: while start_angle < end_angle do if start_angle + 179 < end_angle then - -- Add a quarter cycle: - startx, starty, start_angle = subarc(path, startx, starty, start_angle, 90, radius, trans, centerx, centery) + -- Add a quarter cycle: + startx, starty, start_angle = subarc(path, startx, starty, start_angle, 90, radius, trans, centerx, centery) elseif start_angle + 90 < end_angle then - -- Add 60 degrees to ensure that there are no small segments - -- at the end - startx, starty, start_angle = subarc(path, startx, starty, start_angle, (end_angle-start_angle)/2, radius, trans, centerx, centery) + -- Add 60 degrees to ensure that there are no small segments + -- at the end + startx, starty, start_angle = subarc(path, startx, starty, start_angle, (end_angle-start_angle)/2, radius, trans, centerx, centery) else - subarc(path, startx, starty, start_angle, end_angle - start_angle, radius, trans, centerx, centery) - break + subarc(path, startx, starty, start_angle, end_angle - start_angle, radius, trans, centerx, centery) + break end end - + elseif start_angle > end_angle then -- First, ensure that the angles are in a reasonable range: start_angle = start_angle % 360 end_angle = end_angle % 360 - + if end_angle >= start_angle then -- In case the modulo has inadvertedly moved the end angle -- before the start angle: end_angle = end_angle - 360 end - + -- Ok, now create a series of arcs that are at most quarter-cycles: while start_angle > end_angle do if start_angle - 179 > end_angle then - -- Add a quarter cycle: - startx, starty, start_angle = subarc(path, startx, starty, start_angle, -90, radius, trans, centerx, centery) + -- Add a quarter cycle: + startx, starty, start_angle = subarc(path, startx, starty, start_angle, -90, radius, trans, centerx, centery) elseif start_angle - 90 > end_angle then - -- Add 60 degrees to ensure that there are no small segments - -- at the end - startx, starty, start_angle = subarc(path, startx, starty, start_angle, (end_angle-start_angle)/2, radius, trans, centerx, centery) + -- Add 60 degrees to ensure that there are no small segments + -- at the end + startx, starty, start_angle = subarc(path, startx, starty, start_angle, (end_angle-start_angle)/2, radius, trans, centerx, centery) else - subarc(path, startx, starty, start_angle, end_angle - start_angle, radius, trans, centerx, centery) - break + subarc(path, startx, starty, start_angle, end_angle - start_angle, radius, trans, centerx, centery) + break end end - + -- else, do nothing end end @@ -199,10 +199,10 @@ end -- Doc see Path.lua function Path:appendArc(start_angle,end_angle,radius, trans) - + local start = rigid(self[#self]) assert(type(start) == "table", "trying to append an arc to a path that does not end with a coordinate") - + if trans then start = start:clone() start:apply(Transform.invert(trans)) @@ -223,13 +223,13 @@ function Path:appendArcTo (target, radius_or_center, clockwise, trans) local trans_target = target local centerx, centery, radius - + if type(radius_or_center) == "number" then radius = radius_or_center else centerx, centery = radius_or_center.x, radius_or_center.y end - + if trans then start = start:clone() trans_target = target:clone() @@ -242,56 +242,56 @@ function Path:appendArcTo (target, radius_or_center, clockwise, trans) centerx, centery = t.x, t.y end end - + if not centerx then -- Compute center local dx, dy = target.x - start.x, target.y - start.y if abs(dx) == abs(dy) and abs(dx) == radius then if (dx < 0 and dy < 0) or (dx > 0 and dy > 0) then - centerx = start.x - centery = trans_target.y + centerx = start.x + centery = trans_target.y else - centerx = trans_target.x - centery = start.y + centerx = trans_target.x + centery = start.y end else local l_sq = dx*dx + dy*dy if l_sq >= radius*radius*4*0.999999 then - centerx = (start.x+trans_target.x) / 2 - centery = (start.y+trans_target.y) / 2 - assert(l_sq <= radius*radius*4/0.999999, "radius too small for arc") + centerx = (start.x+trans_target.x) / 2 + centery = (start.y+trans_target.y) / 2 + assert(l_sq <= radius*radius*4/0.999999, "radius too small for arc") else -- Normalize - local l = sqrt(l_sq) - local nx = dx / l - local ny = dy / l - - local e = sqrt(radius*radius - 0.25*l_sq) - - centerx = start.x + 0.5*dx - ny*e - centery = start.y + 0.5*dy + nx*e + local l = sqrt(l_sq) + local nx = dx / l + local ny = dy / l + + local e = sqrt(radius*radius - 0.25*l_sq) + + centerx = start.x + 0.5*dx - ny*e + centery = start.y + 0.5*dy + nx*e end end end - + local start_dx, start_dy, target_dx, target_dy = start.x - centerx, start.y - centery, trans_target.x - centerx, trans_target.y - centery - + if not radius then -- Center is given, compute radius: radius_sq = start_dx^2 + start_dy^2 -- Ensure that the circle is, indeed, centered: assert (abs(target_dx^2 + target_dy^2 - radius_sq)/radius_sq < 1e-5, "attempting to add an arc with incorrect center") - + radius = sqrt(radius_sq) end -- Compute start and end angle: - local start_angle = atan2deg(start_dy, start_dx) - local end_angle = atan2deg(target_dy, target_dx) + local start_angle = atan2deg(start_dy, start_dx) + local end_angle = atan2deg(target_dy, target_dx) if clockwise then if end_angle > start_angle then @@ -302,7 +302,7 @@ function Path:appendArcTo (target, radius_or_center, clockwise, trans) end_angle = end_angle + 360 end end - + arc (self, start, start_angle, end_angle, radius, trans, centerx, centery) -- Patch last point to avoid rounding problems: @@ -313,4 +313,4 @@ end -- Done -return true
\ No newline at end of file +return true diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Vertex.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Vertex.lua index c287181992f..677ea4fbd06 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Vertex.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/model/Vertex.lua @@ -39,12 +39,12 @@ -- path lives in a special ``local'' coordinate system, that is, all -- coordinates of this path should actually be considered relative to -- the vertex' |pos| field. Note that the path is typically, but not --- alwyas, ``centered'' on the origin. A graph drawing algorithm +-- always, ``centered'' on the origin. A graph drawing algorithm -- should arrange the vertices in such a way that the origins in the -- path coordinate systems are aligned. -- -- To illustrate the difference between the origin and the vertex --- center, conside a tree drawing algorithm in which a node |root| has +-- center, consider a tree drawing algorithm in which a node |root| has -- three children |a|, |b|, and |g|. Now, if we were to simply center -- these three letters vertically and arrange them in a line, the -- letters would appear to ``jump up and down'' since the height of @@ -100,7 +100,7 @@ -- |options|, which must be a table of the same syntax as the -- |options| field. For the |entries| array, each element must be -- table with two field: |t| must be set to a number, representing a --- time in secondds, and |value|, which must be set to a value that +-- time in seconds, and |value|, which must be set to a value that -- the |attribute| should have at the given time. The entries and the -- options will then be interpreted as described in \pgfname's basic -- layer animation system, except that where a |\pgfpoint| is expected @@ -207,29 +207,29 @@ local anchor_cache = Storage.new () local directions = { north = function(min_x, min_y, max_x, max_y) - return (min_x+max_x)/2, max_y - end, + return (min_x+max_x)/2, max_y + end, south = function(min_x, min_y, max_x, max_y) - return (min_x+max_x)/2, min_y - end, + return (min_x+max_x)/2, min_y + end, east = function(min_x, min_y, max_x, max_y) - return max_x, (min_y+max_y)/2 - end, + return max_x, (min_y+max_y)/2 + end, west = function(min_x, min_y, max_x, max_y) - return min_x, (min_y+max_y)/2 - end, + return min_x, (min_y+max_y)/2 + end, ["north west"] = function(min_x, min_y, max_x, max_y) - return min_x, max_y - end, + return min_x, max_y + end, ["north east"] = function(min_x, min_y, max_x, max_y) - return max_x, max_y - end, + return max_x, max_y + end, ["south west"] = function(min_x, min_y, max_x, max_y) - return min_x, min_y - end, + return min_x, min_y + end, ["south east"] = function(min_x, min_y, max_x, max_y) - return max_x, min_y - end, + return max_x, min_y + end, } --- @@ -260,10 +260,10 @@ function Vertex:anchor(anchor) else local n = tonumber(anchor) if n then - local x1, y1, x2, y2 = self:boundingBox() - local r = math.max(x2-x1, y2-y1) - b = Coordinate.new(r*math.cos(n/180*math.pi),r*math.sin(n/180*math.pi)) - b:shiftByCoordinate(self.anchors.center) + local x1, y1, x2, y2 = self:boundingBox() + local r = math.max(x2-x1, y2-y1) + b = Coordinate.new(r*math.cos(n/180*math.pi),r*math.sin(n/180*math.pi)) + b:shiftByCoordinate(self.anchors.center) end end if not b then diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua index df366a31687..32927530a29 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/pedigrees/Koerner2015.lua @@ -29,9 +29,9 @@ local declare = InterfaceToAlgorithms.declare declare { key = "mate", type = "boolean", - - summary = [[" - Edges of type |mate| join mates. + + summary = [[" + Edges of type |mate| join mates. "]], } @@ -41,50 +41,51 @@ declare { key = "child", type = "boolean", - summary = [[" - Edges of type |child| join a parent to a child. The parent is the tail of the edge, the child is the head. + summary = [[" + Edges of type |child| join a parent to a child. The parent is the tail + of the edge, the child is the head. "]], } - + --- declare { key = "sibling", type = "boolean", - summary = [[" - Edges of type |sibling| join a siblings (persons with identical parents). + summary = [[" + Edges of type |sibling| join a siblings (persons with identical parents). "]], } - + --- declare { key = "simple pedigree layout", algorithm = Koerner2015, - + postconditions = { upward_oriented = true }, - summary = [[" - A simple algorithm for drawing a pedigree. + summary = [[" + A simple algorithm for drawing a pedigree. "]], documentation = [[" ... "]], examples = [[" - \tikz \graph [simple pedigree layout, default edge operator=complete bipartite] - { - Eve -- [mate] Felix; - { Eve, Felix } -> [child] { George, Hank }; - - Alice -- [mate] Bob; - { Alice, Bob } -> [child] { Charly, Dave, Eve }; - }; + \tikz \graph [simple pedigree layout, default edge operator=complete bipartite] + { + Eve -- [mate] Felix; + { Eve, Felix } -> [child] { George, Hank }; + + Alice -- [mate] Bob; + { Alice, Bob } -> [child] { Charly, Dave, Eve }; + }; "]] } - - + + function Koerner2015:run() local g = self.digraph @@ -93,9 +94,9 @@ function Koerner2015:run() local visited = {} local ranks = {} - + local queue = { { g.vertices[1], 1 } } - + local queue_start = 1 local queue_end = 1 @@ -110,51 +111,51 @@ function Koerner2015:run() queue_start = queue_start + 1 return v,r end - + while queue_start <= queue_end do -- Pop local v, rank = get() ranks[v] = rank - + visited [v] = true -- Follow mates: for _,a in ipairs(g:outgoing(v)) do if a:options("sibling") then - if not visited[a.head] then - put(a.head, rank) - end + if not visited[a.head] then + put(a.head, rank) + end end end for _,a in ipairs(g:incoming(v)) do if a:options("child") then - if not visited[a.tail] then - put(a.tail, rank-1) - end + if not visited[a.tail] then + put(a.tail, rank-1) + end end end for _,a in ipairs(g:outgoing(v)) do if a:options("child") then - if not visited[a.head] then - put(a.head, rank+1) - end + if not visited[a.head] then + put(a.head, rank+1) + end end end for _,a in ipairs(g:outgoing(v)) do if a:options("mate") then - if not visited[a.head] then - put(a.head, rank) - end + if not visited[a.head] then + put(a.head, rank) + end end end end - + for i,v in ipairs(g.vertices) do v.pos.x = i*50 v.pos.y = ranks[v] * 50 end - + end return Koerner2015 diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua index f1acbd71281..04e1ca49f1a 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/AuthorDefinedPhylogeny.lua @@ -34,22 +34,22 @@ declare { phase_default = true, summary = [[" - When this key is used, the phylogenetic tree must be specified - by the author (rather than being generated algorithmically). + When this key is used, the phylogenetic tree must be specified + by the author (rather than being generated algorithmically). "]], documentation = [[" - A spanning tree of the input graph will be computed first (it - must be connected, otherwise errors will result). - The evolutionary length of the edges must be specified through - the use of the |length| key for each edge. + A spanning tree of the input graph will be computed first (it + must be connected, otherwise errors will result). + The evolutionary length of the edges must be specified through + the use of the |length| key for each edge. "]], examples = [[" - \tikz \graph [phylogenetic tree layout] { - a -- { - b [>length=2] --[length=1] { c, d }, - e [>length=3] - } - }; + \tikz \graph [phylogenetic tree layout] { + a -- { + b [>length=2] --[length=1] { c, d }, + e [>length=3] + } + }; "]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua index d2b64270796..ef40f0ee60d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedMinimumEvolution.lua @@ -34,44 +34,44 @@ declare { algorithm = BalancedMinimumEvolution, phase = "phylogenetic tree generation", - summary = [[" - The BME (Balanced Minimum Evolution) algorithm tries to minimize - the total tree length. + summary = [[" + The BME (Balanced Minimum Evolution) algorithm tries to minimize + the total tree length. "]], documentation = [[" - This algorithm is from Desper and Gascuel, \emph{Fast and - Accurate Phylogeny Reconstruction Algorithms Based on the - Minimum-Evolution Principle}, 2002. The tree is built in a way - that minimizes the total tree length. The leaves are inserted - into the tree one after another, creating new edges and new - nodes. After every insertion the distance matrix has to be - updated. + This algorithm is from Desper and Gascuel, \emph{Fast and + Accurate Phylogeny Reconstruction Algorithms Based on the + Minimum-Evolution Principle}, 2002. The tree is built in a way + that minimizes the total tree length. The leaves are inserted + into the tree one after another, creating new edges and new + nodes. After every insertion the distance matrix has to be + updated. "]], examples = [[" - \tikz \graph [phylogenetic tree layout, - balanced minimum evolution, - grow'=right, sibling distance=0pt, - distance matrix={ - 0 4 9 9 9 9 9 - 4 0 9 9 9 9 9 - 9 9 0 2 7 7 7 - 9 9 2 0 7 7 7 - 9 9 7 7 0 3 5 - 9 9 7 7 3 0 5 - 9 9 7 7 5 5 0}] - { a, b, c, d, e, f, g }; + \tikz \graph [phylogenetic tree layout, + balanced minimum evolution, + grow'=right, sibling distance=0pt, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; "]] } - - - - + + + + function BalancedMinimumEvolution:run() - + self.tree = Digraph.new(self.main_algorithm.digraph) - + self.distances = Storage.newTableStorage() - + local vertices = self.tree.vertices -- Sanity checks: @@ -79,25 +79,25 @@ function BalancedMinimumEvolution:run() self.tree:connect(vertices[1],vertices[2]) return self.tree elseif #vertices > 2 then - + -- Setup storages: self.is_leaf = Storage.new() - + -- First, build the initial distance matrix: local matrix = DistanceMatrix.graphDistanceMatrix(self.tree) - + -- Store distance information in the distance fields of the storages: for _,u in ipairs(vertices) do for _,v in ipairs(vertices) do self.distances[u][v] = matrix[u][v] end end - + -- Run BME self:runBME() -- Run postoptimizations - local optimization_class = self.tree.options.algorithm_phases['phylogenetic tree optimization'] + local optimization_class = self.tree.options.algorithm_phases['phylogenetic tree optimization'] optimization_class.new { main_algorithm = self.main_algorithm, tree = self.tree, @@ -106,11 +106,11 @@ function BalancedMinimumEvolution:run() is_leaf = self.is_leaf, }:run() end - - -- Finish + + -- Finish self:computeFinalLengths() self:createFinalEdges() - + return self.tree end @@ -119,8 +119,8 @@ end -- the BME (Balanced Minimum Evolution) algorithm -- [DESPER and GASCUEL: Fast and Accurate Phylogeny Reconstruction --- Algorithms Based on the Minimum-Evolution Principle, 2002] --- +-- Algorithms Based on the Minimum-Evolution Principle, 2002] +-- -- The tree is built in a way that minimizes the total tree length. -- The leaves are inserted into the tree one after another, creating new edges and new nodes. -- After every insertion the distance matrix has to be updated. @@ -129,14 +129,14 @@ function BalancedMinimumEvolution:runBME() local leaves = {} local is_leaf = self.is_leaf local distances = self.distances - + -- get user input for i, vertex in ipairs (g.vertices) do leaves[i] = vertex is_leaf[vertex] = true end - -- create the new node which will be connected to the first three leaves + -- create the new node which will be connected to the first three leaves local new_node = InterfaceToAlgorithms.createVertex( self.main_algorithm, { @@ -147,12 +147,12 @@ function BalancedMinimumEvolution:runBME() g:add {new_node} -- set the distances of new_node to subtrees local distance_1_2 = self:distance(leaves[1],leaves[2]) - local distance_1_3 = self:distance(leaves[1],leaves[3]) - local distance_2_3 = self:distance(leaves[2],leaves[3]) + local distance_1_3 = self:distance(leaves[1],leaves[3]) + local distance_2_3 = self:distance(leaves[2],leaves[3]) distances[new_node][leaves[1]] = 0.5*(distance_1_2 + distance_1_3) - distances[new_node][leaves[2]] = 0.5*(distance_1_2 + distance_2_3) - distances[new_node][leaves[3]] = 0.5*(distance_1_3 + distance_2_3) - + distances[new_node][leaves[2]] = 0.5*(distance_1_2 + distance_2_3) + distances[new_node][leaves[3]] = 0.5*(distance_1_3 + distance_2_3) + --connect the first three leaves to the new node for i = 1,3 do g:connect(new_node, leaves[i]) @@ -166,7 +166,7 @@ function BalancedMinimumEvolution:runBME() -- note that the function called stores the k_dists before they are overwritten self:computeAverageDistancesToAllSubtreesForK(g.vertices[i], { }, k,k_dists) end - + -- find the best insertion point local best_arc = self:findBestEdge(g.vertices[1],nil,k_dists) local head = best_arc.head @@ -175,8 +175,8 @@ function BalancedMinimumEvolution:runBME() -- remove the old arc g:disconnect(tail, head) g:disconnect(head, tail) - - -- create the new node + + -- create the new node local new_node = InterfaceToAlgorithms.createVertex( self.main_algorithm, { @@ -187,28 +187,28 @@ function BalancedMinimumEvolution:runBME() } ) g:add{new_node} - + -- gather the vertices that will be connected to the new node... local vertices_to_connect = { head, tail, leaves[k] } - + -- ...and connect them for _, vertex in pairs (vertices_to_connect) do g:connect(new_node, vertex) g:connect(vertex, new_node) end - + if not is_leaf[tail] then - distances[leaves[k]][tail] = k_dists[head][tail] + distances[leaves[k]][tail] = k_dists[head][tail] end if not is_leaf[head] then - distances[leaves[k]][head] = k_dists[tail][head] + distances[leaves[k]][head] = k_dists[tail][head] end -- insert distances from k to subtrees into actual matrix... self:setAccurateDistancesForK(new_node,nil,k,k_dists,leaves) - + -- set the distance from k to the new node, which was created by inserting k into the graph - distances[leaves[k]][new_node] = 0.5*( self:distance(leaves[k], head) + self:distance(leaves[k],tail)) - + distances[leaves[k]][new_node] = 0.5*( self:distance(leaves[k], head) + self:distance(leaves[k],tail)) + -- update the average distances local values = {} values.s = head -- s--u is the arc into which k has been inserted @@ -218,9 +218,9 @@ function BalancedMinimumEvolution:runBME() end end --- +-- -- Updates the average distances from k to all subtrees --- +-- -- @param vertex The starting point of the recursion -- @param values The values needed for the recursion -- - s, u The nodes which span the edge into which k has been @@ -228,27 +228,27 @@ end -- - new_node The new_node which has been created to insert k -- - l (l-1) is the number of edges between the -- new_node and the current subtree Y --- +-- -- values.new_node, values.u and values.s must be set -- the depth first search must begin at the new node, thus vertex --- must be set to the newly created node +-- must be set to the newly created node function BalancedMinimumEvolution:updateAverageDistances(vertex, values, k, leaves) local g = self.tree local leaf_k = leaves[k] local y, z, x if not values.visited then values.visited = {} - values.visited[leaf_k] = leaf_k -- we don't want to visit k! + values.visited[leaf_k] = leaf_k -- we don't want to visit k! end -- there are (l-1) edges between new_node and y if not values.l then values.l = 1 end if not values.new_node then values.new_node = g:outgoing(leaf_k)[1].head end --values.s and values.u must be set - + -- the two nodes which connect the edge on which k was inserted: s,u local new_node = values.new_node - local l = values.l + local l = values.l local visited = values.visited visited[vertex] = vertex @@ -258,7 +258,7 @@ function BalancedMinimumEvolution:updateAverageDistances(vertex, values, k, leav local l = values.l local y1= values.y1 - -- calculate distance between Y{k} and X + -- calculate distance between Y{k} and X local old_distance -- the distance between Y{/k} and X needed for calculating the new distance if y == new_node then -- this y didn't exist in the former tree; so use y1 (see below) old_distance = self:distance(x,y1) @@ -269,7 +269,7 @@ function BalancedMinimumEvolution:updateAverageDistances(vertex, values, k, leav local new_distance = old_distance + math.pow(2,-l) * ( self:distance(leaf_k,x) - self:distance(x,y1) ) self.distances[x][y] = new_distance self.distances[y][x] = new_distance -- symmetric matrix - + values.x_visited[x] = x --go deeper to next x for _, x_arc in ipairs (self.tree:outgoing(x)) do @@ -292,7 +292,7 @@ function BalancedMinimumEvolution:updateAverageDistances(vertex, values, k, leav else assert(values.y1,"no y1 set!") end - + z = arc.head -- root of the subtree we're looking at y = arc.tail -- the root of the subtree-complement of Z @@ -300,7 +300,7 @@ function BalancedMinimumEvolution:updateAverageDistances(vertex, values, k, leav values.x_visited = {} values.x_visited[y] = y -- we don't want to go there, as we want to stay within Z loop_over_x( z,y, values ) -- visit all possible subtrees of Z - + -- go to next Z values.l = values.l+1 -- moving further away from the new_node self:updateAverageDistances(z,values,k,leaves) @@ -321,18 +321,18 @@ end -- stored -- - outgoing_arcs The table containing the outgoing arcs -- of the current vertex --- +-- -- @return The average distance of the new node #k to any subtree -- The distances are stored as follows: -- example: distances[center][a] -- center is any vertex, thus if center is an inner vertex --- it has 3 neighbours a,b and c, which can all be seen as the +-- it has 3 neighbors a,b and c, which can all be seen as the -- roots of subtrees A,B,C. -- distances[center][a] gives us the distance of the new -- node k to the subtree A. --- if center is a leaf, it has only one neighbour, which +-- if center is a leaf, it has only one neighbor, which -- can also be seen as the root of the subtree T\{center} --- +-- function BalancedMinimumEvolution:computeAverageDistancesToAllSubtreesForK(vertex, values, k, k_dists) local is_leaf = self.is_leaf local arcs = self.tree.arcs @@ -340,13 +340,13 @@ function BalancedMinimumEvolution:computeAverageDistancesToAllSubtreesForK(verte local center_vertex = vertex -- for every vertex a table is created, in which the distances to all -- its subtrees will be stored - + values.outgoing_arcs = values.outgoing_arcs or self.tree:outgoing(center_vertex) for _, arc in ipairs (values.outgoing_arcs) do local root = arc.head -- this vertex can be seen as the root of a subtree if is_leaf[root] then -- we know the distance of k to the leaf! k_dists[center_vertex][root] = self:distance(vertices[k], root) - else -- to compute the distance we need the root's neighbouring vertices, which we can access by its outgoing arcs + else -- to compute the distance we need the root's neighboring vertices, which we can access by its outgoing arcs local arc1, arc2 local arc_back -- the arc we came from for _, next_arc in ipairs (self.tree:outgoing(root)) do @@ -356,25 +356,25 @@ function BalancedMinimumEvolution:computeAverageDistancesToAllSubtreesForK(verte else arc_back = next_arc end - end - + end + values.outgoing_arcs = { arc1, arc2, arc_back } -- go deeper, if the distances for the next center node haven't been set yet - if not (k_dists[root][arc1.head] and k_dists[root][arc2.head]) then + if not (k_dists[root][arc1.head] and k_dists[root][arc2.head]) then self:computeAverageDistancesToAllSubtreesForK(root, values, k,k_dists) end - + -- set the distance between k and subtree - k_dists[center_vertex][root] = 1/2 * (k_dists[root][arc1.head] + k_dists[root][arc2.head]) - end + k_dists[center_vertex][root] = 1/2 * (k_dists[root][arc1.head] + k_dists[root][arc2.head]) + end end end -- -- Sets the distances from k to subtrees --- In computeAverageDistancesToAllSubtreesForK the distances to ALL possbile +-- In computeAverageDistancesToAllSubtreesForK the distances to ALL possible -- subtrees are computed. Once k is inserted many of those subtrees don't -- exist for k, as k is now part of them. In this function all -- still accurate subtrees and their distances to k are @@ -386,7 +386,7 @@ end function BalancedMinimumEvolution:setAccurateDistancesForK(center,visited,k,k_dists,leaves) local visited = visited or {} local distances = self.distances - + visited[center] = center local outgoings = self.tree:outgoing(center) for _,arc in ipairs (outgoings) do @@ -395,11 +395,11 @@ function BalancedMinimumEvolution:setAccurateDistancesForK(center,visited,k,k_di local distance -- set the distance if not distances[leaves[k]][vertex] and k_dists[center] then - distance = k_dists[center][vertex] -- use previously calculated distance + distance = k_dists[center][vertex] -- use previously calculated distance distances[leaves[k]][vertex] = distance distances[vertex][leaves[k]] = distance end - -- go deeper + -- go deeper if not visited[vertex] then self:setAccurateDistancesForK(vertex,visited,k,k_dists,leaves) end @@ -419,7 +419,7 @@ end -- - visited: The vertices that already have been visited -- - tree_length: The current tree_length -- - best_arc: The current best_arc, such that the tree --- length is minimzed +-- length is minimized -- - min_length: The smallest tree_length found so far function BalancedMinimumEvolution:findBestEdge(vertex, values, k_dists) local arcs = self.tree.arcs @@ -437,9 +437,9 @@ function BalancedMinimumEvolution:findBestEdge(vertex, values, k_dists) c = arc.head --last visited arc end end - + for i, arc in ipairs (unvisited_arcs) do - local change_in_tree_length = 0 + local change_in_tree_length = 0 -- set tree length to 0 for first insertion arc if not values.tree_length then values.tree_length = 0 @@ -456,15 +456,15 @@ function BalancedMinimumEvolution:findBestEdge(vertex, values, k_dists) values.tree_length = values.tree_length + change_in_tree_length end -- if the tree length becomes shorter, this is the new best arc - -- for the insertion of leaf k + -- for the insertion of leaf k if values.tree_length < values.min_length then values.best_arc = arc values.min_length = values.tree_length end - + -- go deeper self:findBestEdge(arc.head, values, k_dists) - + values.tree_length = values.tree_length - change_in_tree_length end return values.best_arc @@ -527,7 +527,7 @@ function BalancedMinimumEvolution:distance(a, b) else local distances = self.distances return distances[a][b] or distances[b][a] - end + end end @@ -543,7 +543,7 @@ function BalancedMinimumEvolution:computeFinalLengths() for _, arc in ipairs(g.arcs) do local head = arc.head local tail = arc.tail - local distance + local distance local a,b,c,d -- assert, that the length hasn't already been computed for this arc if not lengths[head][tail] then diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua index 8077790224a..1980afe7ad0 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/BalancedNearestNeighbourInterchange.lua @@ -25,7 +25,7 @@ local lib = require("pgf.gd.lib") -- Shorthand: local declare = InterfaceToAlgorithms.declare - + --- declare { key = "balanced nearest neighbour interchange", @@ -33,45 +33,45 @@ declare { phase = "phylogenetic tree optimization", phase_default = true, - summary = [[" - The BNNI (Balanced Nearest Neighbour Interchange) is a - postprocessing algorithm for phylogenetic trees. It swaps two - distant 3-subtrees if the total tree length is reduced by doing - so, until no such swaps are left. + summary = [[" + The BNNI (Balanced Nearest Neighbor Interchange) is a + postprocessing algorithm for phylogenetic trees. It swaps two + distant 3-subtrees if the total tree length is reduced by doing + so, until no such swaps are left. "]], documentation = [[" - This algorithm is from Desper and Gascuel, \emph{Fast and - Accurate Phylogeny Reconstruction Algorithms Based on the - Minimum-Evolution Principle}, 2002. + This algorithm is from Desper and Gascuel, \emph{Fast and + Accurate Phylogeny Reconstruction Algorithms Based on the + Minimum-Evolution Principle}, 2002. "]] } - + --- declare { key = "no phylogenetic tree optimization", algorithm = { run = function(self) end }, phase = "phylogenetic tree optimization", - summary = [[" - Switches off any phylogenetic tree optimization. + summary = [[" + Switches off any phylogenetic tree optimization. "]], } - - + + -- creates a binary heap, implementation as an array as described in --- the respective wikipedia article +-- the respective wikipedia article local function new_heap() local heap = {} - + function heap:insert(element, value) local object = { element = element, value = value } heap[#heap+1]= object - + local i = #heap local parent = math.floor(i/2) - + -- sort the new object into its correct place while heap[parent] and heap[parent].value < heap[i].value do heap[i] = heap[parent] @@ -80,43 +80,43 @@ local function new_heap() parent = math.floor(i/2) end end - + -- deletes the top element from the heap function heap:remove_top_element() -- replace first element with last and delete the last element local element = heap[1].element heap[1] = heap[#heap] heap[#heap] = nil - + local i = 1 - local left_child = 2*i + local left_child = 2*i local right_child = 2*i +1 -- sort the new top element into its correct place by swapping it -- against its largest child - while heap[left_child] do + while heap[left_child] do local largest_child = left_child if heap[right_child] and heap[left_child].value < heap[right_child].value then - largest_child = right_child + largest_child = right_child end if heap[largest_child].value > heap[i].value then heap[largest_child], heap[i] = heap[i], heap[largest_child] i = largest_child - left_child = 2*i + left_child = 2*i right_child = 2*i +1 - else + else return element end end return element end - return heap + return heap end --- BNNI (Balanced Nearest Neighbour Interchange) +-- BNNI (Balanced Nearest Neighbor Interchange) -- [DESPER and GASCUEL: Fast and Accurate Phylogeny Reconstruction Algorithms Based on the Minimum-Evolution Principle, 2002] -- swaps two distant-3 subtrees if the total tree length is reduced by doing so, until no such swaps are left -- @@ -140,21 +140,21 @@ function BalancedNearestNeighbourInterchange:run() -- achieve best swap and update the distance matrix, until there is -- no more swap to perform - while #possible_swaps > 0 do + while #possible_swaps > 0 do -- get the best swap and delete it from the heap local swap = possible_swaps:remove_top_element() --[part of step 3 (a)] - + -- Check if the indicated swap is still possible. Another swap may -- have interfered. if g:arc(swap.v, swap.subtree1) and g:arc(swap.w, swap.subtree2) and g:arc(swap.v, swap.w) and g:arc(swap.a, swap.v) and g:arc(swap.d, swap.w) then -- insert new arcs and delete the old ones to perform the swap [part of step 3 (a)] - + -- disconnect old arcs g:disconnect(swap.v, swap.subtree1) g:disconnect(swap.subtree1, swap.v) g:disconnect(swap.w, swap.subtree2) g:disconnect(swap.subtree2, swap.w) - + -- connect new arcs g:connect(swap.v, swap.subtree2) g:connect(swap.subtree2, swap.v) @@ -164,7 +164,7 @@ function BalancedNearestNeighbourInterchange:run() --update distance matrix self:updateBNNI(swap) - -- update heap: check neighbouring arcs for new possible swaps + -- update heap: check neighboring arcs for new possible swaps -- [step 3 (e)] self:getBestSwap(g:arc(swap.a,swap.v), possible_swaps) self:getBestSwap(g:arc(swap.subtree2, swap.v), possible_swaps) @@ -179,7 +179,7 @@ end -- -- Gets the distance between two nodes as specified in the distances -- fields. Note: this function assumes that the distance from a to b --- is the +-- is the -- same as the distance from b to a. -- -- @param a,b The nodes @@ -196,11 +196,11 @@ end -- updates the distance matrix after a swap has been performed [step3(b),(c),(d)] -- -- @param swap A table containing the information on the performed swap --- subtree1, subtree2: the two subtrees, which --- were swapped --- a, d: The other two subtrees bordering the --- swapping edge --- v, w : the two nodes connecting the swapping edge +-- subtree1, subtree2: the two subtrees, which +-- were swapped +-- a, d: The other two subtrees bordering the +-- swapping edge +-- v, w : the two nodes connecting the swapping edge function BalancedNearestNeighbourInterchange:updateBNNI(swap) local g = self.tree @@ -211,7 +211,7 @@ function BalancedNearestNeighbourInterchange:updateBNNI(swap) local v = swap.v local w = swap.w local distances = self.distances - + -- updates the distances in one of the four subtrees adjacent to the -- swapping edge function update_BNNI_subtree(swap, values) @@ -222,10 +222,10 @@ function BalancedNearestNeighbourInterchange:updateBNNI(swap) local v = swap.v local d = swap.same local w = swap.w - + if not values then values = { - visited = {[v] = v}, + visited = {[v] = v}, possible_ys = {v}, x = a, y = v @@ -239,16 +239,16 @@ function BalancedNearestNeighbourInterchange:updateBNNI(swap) local y = values.y local ys = values.possible_ys local l = 0 -- number of edges between y and v - + local dist_x_b = self:distance(x,b) local dist_x_c = self:distance(x,c) visited[x] = x --mark current x as visited - + -- loop over possible y's: for _, y in ipairs (ys) do -- update distance [step 3(b)] - local distance = self:distance(x,y) - 2^(-l-2)*dist_x_b + 2^(-l-2)*dist_x_c - + local distance = self:distance(x,y) - 2^(-l-2)*dist_x_b + 2^(-l-2)*dist_x_c + if y == w then y = v end -- the old distance w,x was used for the new distance calculation, but it needs to be -- saved under its appropriate new name according to its new root. this case only arises when looking at x's -- in one of the swapped subtrees (b or c) @@ -257,13 +257,13 @@ function BalancedNearestNeighbourInterchange:updateBNNI(swap) distances[y][x] = distance l = l+1 -- length + 1, as the next y will be further away from v end - + -- update the distance between x and w (root of subtree c and d) -- [step 3(c)] local distance = 1/2 * (self:distance(x,b) + self:distance(x,d)) distances[x][w] = distance distances[w][x] = distance - + -- go to next possible x's table.insert(ys, x) -- when we're at the next possible x, y can also be the current x for _,arc in ipairs (g:outgoing(x)) do @@ -274,13 +274,13 @@ function BalancedNearestNeighbourInterchange:updateBNNI(swap) end end end - + -- name the nodes/subtrees in a general way that allows the use of the function update_BNNI_subtree local update_a = {subtree = a, farther = b, nearer = c, v = v, same = d, w = w} local update_b = {subtree = b, farther = a, nearer = d, v = w, same = c, w = v, swapped_branch = true} local update_c = {subtree = c, farther = d, nearer = a, v = v, same = b, w = w, swapped_branch = true} local update_d = {subtree = d, farther = c, nearer = b, v = w, same = a, w = v} - + -- update the distances within the subtrees a,b,c,d respectively update_BNNI_subtree(update_a) update_BNNI_subtree(update_b) @@ -288,7 +288,7 @@ function BalancedNearestNeighbourInterchange:updateBNNI(swap) update_BNNI_subtree(update_d) -- update the distance between subtrees v and w [step 3 (d)]: - local distance = 1/4*( self:distance(a,b) + self:distance(a,d) + self:distance(c,b) + self:distance(c,d) ) + local distance = 1/4*( self:distance(a,b) + self:distance(a,d) + self:distance(c,b) + self:distance(c,d) ) distances[v][w] = distance distances[w][v] = distance end @@ -314,19 +314,19 @@ function BalancedNearestNeighbourInterchange:getBestSwap(arc, heap_of_swaps) local v = arc.tail local w = arc.head local is_leaf = self.is_leaf - + -- only look at inner edges: if not is_leaf[v] and not is_leaf[w] then -- get the roots of the adjacent subtrees local a, b, c, d - for _,outgoing in ipairs (g:outgoing(v)) do + for _,outgoing in ipairs (g:outgoing(v)) do local head = outgoing.head if head ~= w then a = a or head b = head end end - + for _,outgoing in ipairs (g:outgoing(w)) do local head = outgoing.head if head ~= v then @@ -334,7 +334,7 @@ function BalancedNearestNeighbourInterchange:getBestSwap(arc, heap_of_swaps) d = head end end - + -- get the distances between the four subtrees local a_b = self:distance(a,b) local a_c = self:distance(a,c) @@ -349,9 +349,9 @@ function BalancedNearestNeighbourInterchange:getBestSwap(arc, heap_of_swaps) -- difference in total tree length between old tree and new tree when nodes b and d are swapped local swap2 = 1/4*(a_b + c_d - a_d - b_c) - + -- choose the best swap that reduces the total tree length most (T-T' > 0) - if swap1 > swap2 and swap1 > 0 then + if swap1 > swap2 and swap1 > 0 then -- v,w = the nodes connecting the edge across which the swap is performed -- subtree1 = one of the nodes to be swapped; connected to v -- subtree2 = the other node to be swapped; connected to w @@ -360,7 +360,7 @@ function BalancedNearestNeighbourInterchange:getBestSwap(arc, heap_of_swaps) local swap = { v = v, w = w, subtree1 = b, subtree2 = c, a = a, d = d } -- insert the swap into the heap possible_swaps:insert(swap, swap1) - elseif swap2 > 0 then + elseif swap2 > 0 then local swap = { v = v, w = w, subtree1 = b, subtree2 = d, d = c, a = a } possible_swaps:insert(swap, swap2) end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua index d44f098161f..a65a83da17b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/DistanceMatrix.lua @@ -27,22 +27,22 @@ declare { type = "string", summary = [[" - A list of vertices that are used in the parsing of the - |distance matrix| key. If this key is not used at all, all - vertices of the graph will be used for the computation of a - distance matrix. + A list of vertices that are used in the parsing of the + |distance matrix| key. If this key is not used at all, all + vertices of the graph will be used for the computation of a + distance matrix. "]], documentation = [[" - The vertices must be separated by spaces and/or - commas. For vertices containing spaces or commas, the vertex - names may be surrounded by single or double quotes (as in - Lua). Typical examples are |a, b, c| or |"hello world", 'foo'|. + The vertices must be separated by spaces and/or + commas. For vertices containing spaces or commas, the vertex + names may be surrounded by single or double quotes (as in + Lua). Typical examples are |a, b, c| or |"hello world", 'foo'|. "]] } - - + + --- declare { @@ -50,88 +50,95 @@ declare { type = "string", summary = [[" - A distance matrix specifies ``desired distances'' between - vertices in a graph. These distances are used, in particular, in - algorithms for computing phylogenetic trees. + A distance matrix specifies ``desired distances'' between + vertices in a graph. These distances are used, in particular, in + algorithms for computing phylogenetic trees. "]], documentation = [[" - When this key is parsed, the key |distance matrix vertices| is - considered first. It is used to determine a list of vertices - for which a distance matrix is computed, see that key for - details. Let $n$ be the number of vertices derived from that - key. - - The string passed to the |distance matrix| key is basically - a sequence of numbers that are used to fill an $n \times n$ - matrix. This works as follows: We keep track of a \emph{current - position $p$} in the matrix, starting at the upper left corner - of the matrix. We read the numbers in the string - one by one, write it to the current position of the matrix, and - advance the current position by going right one step; if we go - past the right end of the matrix, we ``wrap around'' by going - back to the left border of the matrix, but one line down. If we - go past the bottom of the matrix, we start at the beginning once - more. - - This basic behaviour can be modified in different ways. First, - when a number is followed by a semicolon instead of a comma or a - space (which are the ``usual'' ways of indicating the end of a - number), we immediately go down to the next line. Second, - instead of a number you can directly provide a \emph{position} - in the matrix and the current position will be set to this - position. Such a position information is detected by a - greater-than sign (|>|). It must be followed by - \begin{itemize} + When this key is parsed, the key |distance matrix vertices| is + considered first. It is used to determine a list of vertices + for which a distance matrix is computed, see that key for + details. Let $n$ be the number of vertices derived from that + key. + + The string passed to the |distance matrix| key is basically + a sequence of numbers that are used to fill an $n \times n$ + matrix. This works as follows: We keep track of a \emph{current + position $p$} in the matrix, starting at the upper left corner + of the matrix. We read the numbers in the string + one by one, write it to the current position of the matrix, and + advance the current position by going right one step; if we go + past the right end of the matrix, we ``wrap around'' by going + back to the left border of the matrix, but one line down. If we + go past the bottom of the matrix, we start at the beginning once + more. + + This basic behavior can be modified in different ways. First, + when a number is followed by a semicolon instead of a comma or a + space (which are the ``usual'' ways of indicating the end of a + number), we immediately go down to the next line. Second, + instead of a number you can directly provide a \emph{position} + in the matrix and the current position will be set to this + position. Such a position information is detected by a + greater-than sign (|>|). It must be followed by + % + \begin{itemize} \item a number or a vertex name or \item a number or a vertex name, a comma, and another number or vertex name or \item a comma and a number and a vertex name. - \end{itemize} - Examples of the respective cases are |>1|, |>a,b|, and - |>,5|. The semantics is as follows: In all cases, if a vertex - name rather than a number is given, it is converted into a - number (namely the index of the vertex inside the matrix). Then, - in the first case, the column of the current position is set to - the given number; in the second case, the columns is set to the - first number and the column is set to the second number; and in - the third case only the row is set to the given number. (This - idea is that following the |>|-sign comes a ``coordinate pair'' - whose components are separated by a comma, but part of that pair - may be missing.) If a vertex name contains special symbols like - a space or a comma, you must surround it by single or double - quotation marks (as in Lua). - - Once the string has been parsed completely, the matrix may be - filled only partially. In this case, for each missing entry - $(x,y)$, we try to set it to the value of the entry $(y,x)$, - provided that entry is set. If neither are set, the entry is set - to $0$. - - Let us now have a look at several examples that all produce the - same matrix. The vertices are |a|, |b|, |c|. + \end{itemize} + % + Examples of the respective cases are |>1|, |>a,b|, and + |>,5|. The semantics is as follows: In all cases, if a vertex + name rather than a number is given, it is converted into a + number (namely the index of the vertex inside the matrix). Then, + in the first case, the column of the current position is set to + the given number; in the second case, the columns is set to the + first number and the column is set to the second number; and in + the third case only the row is set to the given number. (This + idea is that following the |>|-sign comes a ``coordinate pair'' + whose components are separated by a comma, but part of that pair + may be missing.) If a vertex name contains special symbols like + a space or a comma, you must surround it by single or double + quotation marks (as in Lua). + + Once the string has been parsed completely, the matrix may be + filled only partially. In this case, for each missing entry + $(x,y)$, we try to set it to the value of the entry $(y,x)$, + provided that entry is set. If neither are set, the entry is set + to $0$. + + Let us now have a look at several examples that all produce the + same matrix. The vertices are |a|, |b|, |c|. + % \begin{codeexample}[code only, tikz syntax=false] 0, 1, 2 1, 0, 3 2, 3, 0 \end{codeexample} + % \begin{codeexample}[code only, tikz syntax=false] 0 1 2 1 0 3 2 3 0 \end{codeexample} + % \begin{codeexample}[code only, tikz syntax=false] ; 1; 2 3 \end{codeexample} + % \begin{codeexample}[code only, tikz syntax=false] >,b 1; 2 3 \end{codeexample} + % \begin{codeexample}[code only, tikz syntax=false] >b 1 2 >c 3 \end{codeexample} "]] } - + --- @@ -140,34 +147,38 @@ declare { type = "string", summary = [[" - This key is used to specify the ``desired distances'' between - a vertex and the other vertices in a graph. + This key is used to specify the ``desired distances'' between + a vertex and the other vertices in a graph. "]], documentation = [[" - This key works similar to the |distance matrix| key, only it is - passed to a vertex instead of to a whole graph. The syntax is - the same, only the notion of different ``rows'' is not - used. Here are some examples that all have the same effect, - provided the nodes are |a|, |b|, and |c|. + This key works similar to the |distance matrix| key, only it is + passed to a vertex instead of to a whole graph. The syntax is + the same, only the notion of different ``rows'' is not + used. Here are some examples that all have the same effect, + provided the nodes are |a|, |b|, and |c|. + % \begin{codeexample}[code only, tikz syntax=false] 0, 1, 2 \end{codeexample} + % \begin{codeexample}[code only, tikz syntax=false] 0 1 2 \end{codeexample} + % \begin{codeexample}[code only, tikz syntax=false] >b 1 2 \end{codeexample} + % \begin{codeexample}[code only, tikz syntax=false] >c 2, >b 1 \end{codeexample} "]] } - -local function to_index(s, indices) + +local function to_index(s, indices) if s and s ~= "" then if s:sub(1,1) == '"' then local _, _, m = s:find('"(.*)"') @@ -178,9 +189,9 @@ local function to_index(s, indices) else local num = tonumber(s) if not num then - return indices[InterfaceToAlgorithms.findVertexByName(s)] + return indices[InterfaceToAlgorithms.findVertexByName(s)] else - return num + return num end end end @@ -188,7 +199,7 @@ end local function compute_indices(vertex_string, vertices) local indices = {} - + if not vertex_string then for i,v in ipairs(vertices) do indices[i] = v @@ -200,17 +211,17 @@ local function compute_indices(vertex_string, vertices) while pos <= #vertex_string do local start = vertex_string:sub(pos,pos) if not start:find("[%s,]") then - local _, vertex - if start == '"' then - _, pos, vertex = vertex_string:find('"(.-)"', pos) - elseif start == "'" then - _, pos, vertex = vertex_string:find("'(.-)'", pos) - else - _, pos, vertex = vertex_string:find("([^,%s'\"]*)", pos) - end - local v = assert(InterfaceToAlgorithms.findVertexByName(vertex), "unknown vertex name '" .. vertex .. "'") - indices [#indices + 1] = v - indices [v] = #indices + local _, vertex + if start == '"' then + _, pos, vertex = vertex_string:find('"(.-)"', pos) + elseif start == "'" then + _, pos, vertex = vertex_string:find("'(.-)'", pos) + else + _, pos, vertex = vertex_string:find("([^,%s'\"]*)", pos) + end + local v = assert(InterfaceToAlgorithms.findVertexByName(vertex), "unknown vertex name '" .. vertex .. "'") + indices [#indices + 1] = v + indices [v] = #indices end pos = pos + 1 end @@ -222,24 +233,24 @@ end --- -- Compute a distance matrix based on the values of a --- |distance matrix| and a |distance matrix vertices|. +-- |distance matrix| and a |distance matrix vertices|. -- -- @param matrix_string A distance matrix string -- @param vertex_string A distance matrix vertex string -- @param vertices An array of all vertices in the graph. -- -- @return A distance matrix. This matrix will contain both a --- two-dimensional array (accessed through numbers) and also a +-- two-dimensional array (accessed through numbers) and also a -- two-dimensional hash table (accessed through vertex indices). Thus, -- you can write both |m[1][1]| and also |m[v][v]| to access the first -- entry of this matrix, provided |v == vertices[1]|. -- @return An index vector. This is an array of the vertices -- identified for the |vertex_string| parameter. -function DistanceMatrix.computeDistanceMatrix(matrix_string, vertex_string, vertices) +function DistanceMatrix.computeDistanceMatrix(matrix_string, vertex_string, vertices) -- First, we create a table of the vertices we need to consider: local indices = compute_indices(vertex_string, vertices) - + -- Second, build matrix. local n = #indices local m = {} @@ -255,29 +266,29 @@ function DistanceMatrix.computeDistanceMatrix(matrix_string, vertex_string, vert local start = matrix_string:sub(pos,pos) if not start:find("[%s,]") then if start == '>' then - local _, parse - _, pos, parse = matrix_string:find(">([^%s>;]*)", pos) - local a, b - if parse:find(",") then - _,_,a,b = parse:find("(.*),(.*)") - else - a = parse - end - x = to_index(a, indices) or x - y = to_index(b, indices) or y + local _, parse + _, pos, parse = matrix_string:find(">([^%s>;]*)", pos) + local a, b + if parse:find(",") then + _,_,a,b = parse:find("(.*),(.*)") + else + a = parse + end + x = to_index(a, indices) or x + y = to_index(b, indices) or y elseif start == ';' then - x = 1 - y = y + 1 + x = 1 + y = y + 1 elseif start == ',' then - x = x + 1 + x = x + 1 else - local _, n - _, pos, n = matrix_string:find("([^,;%s>]*)", pos) - local num = assert(tonumber(n), "number expected in distance matrix") - m[x][y] = num - x = x + 1 - -- Skip everything up to first comma: - _, pos = matrix_string:find("(%s*,?)", pos+1) + local _, n + _, pos, n = matrix_string:find("([^,;%s>]*)", pos) + local num = assert(tonumber(n), "number expected in distance matrix") + m[x][y] = num + x = x + 1 + -- Skip everything up to first comma: + _, pos = matrix_string:find("(%s*,?)", pos+1) end end pos = pos + 1 @@ -294,7 +305,7 @@ function DistanceMatrix.computeDistanceMatrix(matrix_string, vertex_string, vert for x=1,n do for y=1,n do if not m[x][y] then - m[x][y] = m[y][x] or 0 + m[x][y] = m[y][x] or 0 end end end @@ -326,11 +337,11 @@ end -- double indexed, once by numbers and once be vertex objects. -- @return An index vector. This is an array of the vertices -- identified for the |vertex_string| parameter. - -function DistanceMatrix.computeDistanceVector(vector_string, vertex_string, vertices) + +function DistanceMatrix.computeDistanceVector(vector_string, vertex_string, vertices) -- First, we create a table of the vertices we need to consider: local indices = compute_indices(vertex_string, vertices) - + -- Second, build matrix. local n = #indices local m = {} @@ -341,19 +352,19 @@ function DistanceMatrix.computeDistanceVector(vector_string, vertex_string, vert local start = vector_string:sub(pos,pos) if not start:find("[%s,]") then if start == '>' then - local _, parse - _, pos, parse = vector_string:find(">([^%s>;]*)", pos) - x = to_index(parse, indices) or x + local _, parse + _, pos, parse = vector_string:find(">([^%s>;]*)", pos) + x = to_index(parse, indices) or x elseif start == ',' then - x = x + 1 + x = x + 1 else - local _, n - _, pos, n = vector_string:find("([^,;%s>]*)", pos) - local num = assert(tonumber(n), "number expected in distance matrix") - m[x] = num - x = x + 1 - -- Skip everything up to first comma: - _, pos = vector_string:find("(%s*,?)", pos+1) + local _, n + _, pos, n = vector_string:find("([^,;%s>]*)", pos) + local num = assert(tonumber(n), "number expected in distance matrix") + m[x] = num + x = x + 1 + -- Skip everything up to first comma: + _, pos = vector_string:find("(%s*,?)", pos+1) end end pos = pos + 1 @@ -376,7 +387,7 @@ end --- -- Compute a distance matrix for a graph that incorporates all -- information stored in the different options of the graph and the --- vertices. +-- vertices. -- -- @param graph A digraph object. -- @@ -396,7 +407,7 @@ function DistanceMatrix.graphDistanceMatrix(digraph) indices[i] = v indices[v] = i end - + if digraph.options['distance matrix'] then local sub, vers = DistanceMatrix.computeDistanceMatrix( digraph.options['distance matrix'], @@ -406,7 +417,7 @@ function DistanceMatrix.graphDistanceMatrix(digraph) for x=1,#vers do for y=1,#vers do - m[vers[x]][vers[y]] = sub[x][y] + m[vers[x]][vers[y]] = sub[x][y] end end end @@ -414,24 +425,24 @@ function DistanceMatrix.graphDistanceMatrix(digraph) for i,v in ipairs(vertices) do if v.options['distances'] then local sub, vers = DistanceMatrix.computeDistanceVector( - v.options['distances'], - v.options['distance matrix vertices'], - vertices + v.options['distances'], + v.options['distance matrix vertices'], + vertices ) - + for x=1,#vers do - m[vers[x]][v] = sub[x] + m[vers[x]][v] = sub[x] end end end - + -- Fill up number versions: for x,vx in ipairs(vertices) do for y,vy in ipairs(vertices) do m[x][y] = m[vx][vy] end end - + return m end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua index 528110b57ea..a9acc488652 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/Maeusle2012.lua @@ -39,36 +39,36 @@ declare { algorithm = { base_class = Maeusle2012, run = function (self) - local root = self:getRoot() - self:setPosForRectangularLayout(root) - end + local root = self:getRoot() + self:setPosForRectangularLayout(root) + end }, phase = "phylogenetic tree layout", phase_default = true, - summary = [[" - A rooted rectangular phylogram is... + summary = [[" + A rooted rectangular phylogram is... "]], documentation = [[" - ... + ... "]], examples = [[" - \tikz \graph [phylogenetic tree layout, - rooted rectangular phylogram, - balanced minimum evolution, - distance matrix={ - 0 4 9 9 9 9 9 - 4 0 9 9 9 9 9 - 9 9 0 2 7 7 7 - 9 9 2 0 7 7 7 - 9 9 7 7 0 3 5 - 9 9 7 7 3 0 5 - 9 9 7 7 5 5 0}] - { a, b, c, d, e, f, g }; + \tikz \graph [phylogenetic tree layout, + rooted rectangular phylogram, + balanced minimum evolution, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; "]] } - ---- + +--- declare { key = "rectangular phylogram", use = { { key = "rooted rectangular phylogram" } }, @@ -81,35 +81,35 @@ declare { algorithm = { base_class = Maeusle2012, run = function (self) - local root = self:getRoot() - self:setXPos(root) - self:setYPosForStraightLayout(root) - end + local root = self:getRoot() + self:setXPos(root) + self:setYPosForStraightLayout(root) + end }, phase = "phylogenetic tree layout", - summary = [[" - A rooted straight phylogram is... + summary = [[" + A rooted straight phylogram is... "]], documentation = [[" - ... + ... "]], examples = [[" - \tikz \graph [phylogenetic tree layout, - rooted straight phylogram, - balanced minimum evolution, grow=right, - distance matrix={ - 0 4 9 9 9 9 9 - 4 0 9 9 9 9 9 - 9 9 0 2 7 7 7 - 9 9 2 0 7 7 7 - 9 9 7 7 0 3 5 - 9 9 7 7 3 0 5 - 9 9 7 7 5 5 0}] - { a, b, c, d, e, f, g }; + \tikz \graph [phylogenetic tree layout, + rooted straight phylogram, + balanced minimum evolution, grow=right, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; "]]} - ---- + +--- declare { key = "straight phylogram", use = { { key = "rooted straight phylogram" } }, @@ -122,91 +122,91 @@ declare { algorithm = { base_class = Maeusle2012, run = function (self) - local root1, root2 = self:getRoot() - self:setPosForUnrootedRectangular(root2, root1) - end + local root1, root2 = self:getRoot() + self:setPosForUnrootedRectangular(root2, root1) + end }, phase = "phylogenetic tree layout", - summary = [[" - A unrooted rectangular phylogram is... + summary = [[" + A unrooted rectangular phylogram is... "]], documentation = [[" - ... + ... "]], examples = [[" - \tikz \graph [phylogenetic tree layout, - unrooted rectangular phylogram, - balanced minimum evolution, grow=right, - distance matrix={ - 0 4 9 9 9 9 9 - 4 0 9 9 9 9 9 - 9 9 0 2 7 7 7 - 9 9 2 0 7 7 7 - 9 9 7 7 0 3 5 - 9 9 7 7 3 0 5 - 9 9 7 7 5 5 0}] - { a, b, c, d, e, f, g }; + \tikz \graph [phylogenetic tree layout, + unrooted rectangular phylogram, + balanced minimum evolution, grow=right, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; "]] } - + --- declare { key = "unrooted straight phylogram", algorithm = { base_class = Maeusle2012, run = function (self) - local root1, root2 = self:getRoot() - self:setPosForUnrootedStraight(root2, root1) - end + local root1, root2 = self:getRoot() + self:setPosForUnrootedStraight(root2, root1) + end }, phase = "phylogenetic tree layout", - summary = [[" - A unrooted straight phylogram is... + summary = [[" + A unrooted straight phylogram is... "]], documentation = [[" - ... + ... "]], examples = [[" - \tikz \graph [phylogenetic tree layout, - unrooted straight phylogram, - balanced minimum evolution, grow=right, - distance matrix={ - 0 4 9 9 9 9 9 - 4 0 9 9 9 9 9 - 9 9 0 2 7 7 7 - 9 9 2 0 7 7 7 - 9 9 7 7 0 3 5 - 9 9 7 7 3 0 5 - 9 9 7 7 5 5 0}] - { a, b, c, d, e, f, g }; + \tikz \graph [phylogenetic tree layout, + unrooted straight phylogram, + balanced minimum evolution, grow=right, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; "]] } - - + + --- declare { key = "evolutionary unit length", type = "length", initial = "1cm", - summary = [[" - Specifies how long a ``unit'' of evolutionary time should be on - paper. For instance, if two nodes in a phylogenetic tree have an - evolutionary distance of 3 and this length is set to |1cm|, then - they will be |3cm| apart in a straight-line phylogram. + summary = [[" + Specifies how long a ``unit'' of evolutionary time should be on + paper. For instance, if two nodes in a phylogenetic tree have an + evolutionary distance of 3 and this length is set to |1cm|, then + they will be |3cm| apart in a straight-line phylogram. "]], documentation = [[" - (This key used to be called |distance scaling factor|.) + (This key used to be called |distance scaling factor|.) "]], } - - + + -- -- Gets the edge length between two nodes --- +-- -- @param vertex1, vertex2 The two nodes -- -- @return The length of the edge between the two nodes @@ -221,12 +221,12 @@ end -- @param vertex The starting point; should usually be the root -- @param values Values needed for the recursion -- @param vertex2 A node that will not be visited; this parameter should only be set --- for an unrooted layout to ensure that only the half of the tree is set. +-- for an unrooted layout to ensure that only the half of the tree is set. function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) local arcs = self.tree.arcs local vertices = self.tree.vertices local adjusted_bb = self.main_algorithm.adjusted_bb - + values = values or { length = 0, -- current path length visited = {}, -- all nodes that have already been visited @@ -235,10 +235,10 @@ function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) local vertex_is_leaf = true values.visited[vertex] = true - + local children = {} -- a table containing all children of the - --current vertex (for the later determination of inner vertices - --x-positions) + -- current vertex (for the later determination of inner vertices + -- x-positions) for _, arc in ipairs (self.tree:outgoing(vertex)) do @@ -251,10 +251,10 @@ function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) -- go deeper self:setPosForRectangularLayout(arc.head, values, vertex2) - + -- get the children of the current vertex children[#children+1] = arc.head - + values.length = values.length - arc_length end end @@ -263,9 +263,9 @@ function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) -- subtract layer_pre, thus the leaf itself is NOT part of the -- edge length vertex.pos.y = - adjusted_bb[vertex].layer_pre - + values.leaves[#values.leaves+1] = vertex - + -- x coordinate: -- the x coordinates of the leaves are the first to be set; the -- first leave stays at x = 0, the x coordinates for the other @@ -276,7 +276,7 @@ function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) local ideal_distance = layered.ideal_sibling_distance(adjusted_bb, self.tree, vertex, left_sibling ) vertex.pos.x = left_sibling.pos.x + ideal_distance end - + else -- the vertex is an inner node -- the x position of an inner vertex is at the center of its children. @@ -287,12 +287,12 @@ function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) if child.pos.x < left_child.pos.x then left_child = child end if child.pos.x > right_child.pos.x then right_child = child end end - + -- position between child with highest and child with lowest x-value, -- if number of children is even local index_of_middle_child = math.ceil(#children/2) local even = #children/2 == index_of_middle_child - + if even then vertex.pos.x = (left_child.pos.x + right_child.pos.x) / 2 index_of_middle_child = 0 @@ -301,33 +301,33 @@ function Maeusle2012:setPosForRectangularLayout(vertex, values, vertex2) table.remove(children, index_of_middle_child) -- don't bend the edge to this node, as it it above it anyway end end - + -- set the node's y-coordinate, using the calculated length - -- and a scaling factor + -- and a scaling factor vertex.pos.y = vertex.pos.y + (values.length * self.tree.options['evolutionary unit length']) - + -- if this is the second subtree to be set of an unrooted tree, have -- it grow in the other direction if values.second_subtree then vertex.pos.y = -vertex.pos.y end - + -- bend the edges for the rectangular layout for i,child in ipairs(children) do self:bendEdge90Degree(child, vertex) end - + return values end -- Sets only the x-positions of all nodes using a depth-first search. -- This is necessary for straight-edge layouts. --- +-- -- @param vertex The starting point of the depth-first search; should usually be the root -- @param values Values needed for the recursion -- @param vertex2 A node that will not be visited; this parameter should only be set --- for an unrooted layout to ensure that only the half of the tree is set. +-- for an unrooted layout to ensure that only the half of the tree is set. function Maeusle2012:setXPos(vertex, values, vertex2) local arcs = self.tree.arcs local vertices = self.tree.vertices @@ -349,26 +349,26 @@ function Maeusle2012:setXPos(vertex, values, vertex2) -- go deeper self:setXPos(arc.head, values, vertex2) - + -- get the children of the current vertex - table.insert(children, arc.head) + table.insert(children, arc.head) end end -- set the x-position of a leaf if vertex_is_leaf then - + table.insert(values.leaves, vertex) - + if #values.leaves > 1 then local left_sibling = values.leaves[#values.leaves-1] local ideal_distance = layered.ideal_sibling_distance(self.main_algorithm.adjusted_bb, self.tree, vertex, left_sibling ) vertex.pos.x = left_sibling.pos.x + ideal_distance end - + -- set x position of an inner node, which is at the center of its -- children - else + else -- determine the outer children local left_child = children[1] local right_child = left_child @@ -376,12 +376,12 @@ function Maeusle2012:setXPos(vertex, values, vertex2) if child.pos.x < left_child.pos.x then left_child = child end if child.pos.x > right_child.pos.x then right_child = child end end - + -- position between child with highest and child with lowest x-value, -- if number of children is even local index_of_middle_child = math.ceil(#children/2) local even = #children/2 == index_of_middle_child - + if even then vertex.pos.x = (left_child.pos.x + right_child.pos.x) / 2 else -- if number of children is odd, position above the middle child @@ -406,7 +406,7 @@ function Maeusle2012:setYPosForStraightLayout(vertex, values, vertex2) local arcs = self.tree.arcs local vertices = self.tree.vertices local adjusted_bb = self.main_algorithm.adjusted_bb - + values = values or { length = 0, -- current path length visited = {}, -- all nodes that have already been visited @@ -421,7 +421,7 @@ function Maeusle2012:setYPosForStraightLayout(vertex, values, vertex2) if not values.visited[arc.head] and arc.head ~= vertex2 then -- if arc.head hasn't been visited, the current vertex cannot be a leaf vertex_is_leaf = false - + -- calculate the arc length with the help of the Pythagorean -- theorem local a @@ -439,10 +439,10 @@ function Maeusle2012:setYPosForStraightLayout(vertex, values, vertex2) -- go deeper self:setYPosForStraightLayout(arc.head, values, vertex2) - + -- get the children of the current vertex - table.insert(children, arc.head) - + table.insert(children, arc.head) + values.length = values.length - arc_length end end @@ -451,13 +451,13 @@ function Maeusle2012:setYPosForStraightLayout(vertex, values, vertex2) -- subtract layer_pre, thus the leaf itself is NOT part of the -- edge length vertex.pos.y = - adjusted_bb[vertex].layer_pre - + table.insert(values.leaves, vertex) end - - -- set the node's y-coordinate, using the calculated length + + -- set the node's y-coordinate, using the calculated length vertex.pos.y = vertex.pos.y + values.length - + -- if this is the second subtree to be set of an unrooted tree, have -- it grow in the other direction if values.second_subtree then vertex.pos.y = -vertex.pos.y end @@ -472,7 +472,7 @@ end -- @param vertex1 The root of the first subtree -- @param vertex2 The root of the second subtree. function Maeusle2012:correctXPos(vertex1, vertex2, straight) - + -- correct the x-positions -- -- @param vertex Starting point of the depth-first search @@ -484,12 +484,12 @@ function Maeusle2012:correctXPos(vertex1, vertex2, straight) for _, arc in ipairs (self.tree:outgoing(vertex)) do if not values.visited[arc.head] and arc.head ~= vertex2 then - - table.insert(children, arc.head) + + table.insert(children, arc.head) x_correction(arc.head, values, vertex2) end end - + vertex.pos.x = vertex.pos.x + values.diff if not straight then for i,child in ipairs(children) do @@ -499,9 +499,9 @@ function Maeusle2012:correctXPos(vertex1, vertex2, straight) return values end - + -- compute the difference of the x-positions of the two subtrees' - -- roots + -- roots local diff = vertex1.pos.x - vertex2.pos.x local values = { visited = {} } if diff < 0 then @@ -510,7 +510,7 @@ function Maeusle2012:correctXPos(vertex1, vertex2, straight) elseif diff > 0 then values.diff = diff x_correction(vertex2, values, vertex1) - end + end end @@ -521,10 +521,10 @@ end -- Two neighboring vertices are chosen as roots; one half of the tree -- is drawn in one direction, the other half 180° to the other -- direction. --- --- @param vertex1, vertex2: The vertices functioning as roots +-- +-- @param vertex1, vertex2: The vertices functioning as roots function Maeusle2012:setPosForUnrootedRectangular(vertex1, vertex2) - -- set positions for first half of the tree... + -- set positions for first half of the tree... self:setPosForRectangularLayout(vertex2,false,vertex1) local vals={ length = self:edgeLength(vertex1, vertex2), -- the length between the two roots @@ -547,14 +547,14 @@ end -- Two neighboring vertices are chosen as roots; one half of the tree -- is drawn in one direction, the other half 180° to the other -- direction. --- +-- -- @param vertex1, vertex2: The vertices functioning as roots function Maeusle2012:setPosForUnrootedStraight(vertex1, vertex2) -- first set the x-positions of the two subtrees... local vals = {visited = {}, leaves = {} } self:setXPos(vertex2, vals, vertex1) self:setXPos(vertex1, vals, vertex2) - + -- ... and then the y-positions self:setYPosForStraightLayout(vertex2, false, vertex1) local vals={ @@ -576,7 +576,7 @@ end -- Bends the arc between two nodes by 90 degree by updating the arc's -- path --- +-- -- @param head The head of the arc -- @param tail The tail of the arc function Maeusle2012:bendEdge90Degree(head, tail) @@ -597,7 +597,7 @@ function Maeusle2012:findLongestPath() local paths_to_leaves = self:getPathLengthsToLeaves(starting_point) local path_lengths = paths_to_leaves.path_lengths local paths = paths_to_leaves.paths - + -- looks for the longest path and identifies its end-point local function find_head_of_longest_path(path_lengths, paths) local longest_path @@ -615,7 +615,7 @@ function Maeusle2012:findLongestPath() end return node end - + -- find the longest path leading away from the starting point and identify -- the leaf it leads to. Use that leaf as the tail for the next path -- search @@ -626,11 +626,11 @@ function Maeusle2012:findLongestPath() path_lengths = paths_to_leaves.path_lengths paths = paths_to_leaves.paths local head = find_head_of_longest_path(path_lengths, paths) - + local path_information = { path = paths_to_leaves.paths[head], -- longest path length = path_lengths[head] } -- length of that path - + return path_information end @@ -659,7 +659,7 @@ function Maeusle2012:getPathLengthsToLeaves(vertex, values) } table.insert(values.path,vertex) end - + local vertex_is_leaf = true values.visited[vertex] = true @@ -671,13 +671,13 @@ function Maeusle2012:getPathLengthsToLeaves(vertex, values) vertex_is_leaf = false local arc_length = self.lengths[vertex][arc.head] values.length = values.length + arc_length - + -- add arc.head to path... table.insert(values.path,arc.head) - + -- ... and go down that path self:getPathLengthsToLeaves(arc.head, values) - + -- remove arc.head again to go a different path table.remove(values.path) values.length = values.length - arc_length @@ -699,7 +699,7 @@ function Maeusle2012:getPathLengthsToLeaves(vertex, values) paths = values.paths, leaves = values.leaves } return path_information -end +end -- Gets the root of a tree @@ -732,13 +732,13 @@ function Maeusle2012:computeCenterOfPath() local node3 = path[i+2] local dist_node_1_2, dist_node_2_3 --distances between node1 and node2, and node2 and node3 - dist_node_1_2 = self:edgeLength(node1, node2) - if node3 then dist_node_2_3 = self:edgeLength(node2, node3) end - length = length + dist_node_1_2 -- length between first vertex on the path and current node2 - + dist_node_1_2 = self:edgeLength(node1, node2) + if node3 then dist_node_2_3 = self:edgeLength(node2, node3) end + length = length + dist_node_1_2 -- length between first vertex on the path and current node2 + if length == longest_path.length/2 then root = node2 -- if there is a node exactly at the half of the path, use this node as root - + -- and find nearest neighbor of the root if node3 == nil or dist_node_1_2 < dist_node_2_3 then -- neu 3.8 neighbor_of_root = node1 @@ -765,12 +765,12 @@ function Maeusle2012:computeCenterOfPath() node0 = path[i-1] dist_node_0_1 = self:edgeLength(node0, node1) if dist_node_0_1 < dist_node_1_2 then neighbor_of_root = node0 end - end + end end break end end - + return root, neighbor_of_root end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua index f66f2553306..242ccf183ff 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/PhylogeneticTree.lua @@ -29,53 +29,53 @@ local declare = InterfaceToAlgorithms.declare declare { key = "phylogenetic tree layout", algorithm = PhylogeneticTree, - + postconditions = { upward_oriented = true }, - summary = [[" - Layout for drawing phylogenetic trees. + summary = [[" + Layout for drawing phylogenetic trees. "]], documentation = [[" - ... + ... "]], examples = [[" - \tikz \graph [phylogenetic tree layout, upgma, - distance matrix={ - 0 4 9 9 9 9 9 - 4 0 9 9 9 9 9 - 9 9 0 2 7 7 7 - 9 9 2 0 7 7 7 - 9 9 7 7 0 3 5 - 9 9 7 7 3 0 5 - 9 9 7 7 5 5 0}] - { a, b, c, d, e, f, g }; + \tikz \graph [phylogenetic tree layout, upgma, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; "]] } - - + + -- Computes a phylogenetic tree and/or visualizes it -- - computes a phylogenetic tree according to what the "phylogenetic -- algorithm" key is set to -- - invokes a graph drawing algorithm according to what the --- "phylogenetic layout" key is set to +-- "phylogenetic layout" key is set to function PhylogeneticTree:run() - + local options = self.digraph.options - + -- Two storages for some information computed by the phylogenetic - -- tree generation algorithm + -- tree generation algorithm local lengths = Storage.newTableStorage() - + -- First, compute the phylogenetic tree local tree = options.algorithm_phases['phylogenetic tree generation'].new { main_algorithm = self, lengths = lengths }:run() - + tree = Direct.ugraphFromDigraph(tree) - + -- Second, layout the tree local layout_class = options.algorithm_phases['phylogenetic tree layout'] layout_class.new { diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua index 8be5c1d51e9..6a665b67322 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/SokalMichener1958.lua @@ -35,33 +35,33 @@ declare { algorithm = SokalMichener1958, phase = "phylogenetic tree generation", - summary = [[" - The UPGMA (Unweighted Pair Group Method using arithmetic - Averages) algorithm of Sokal and Michener, 1958. It generates a - graph on the basis of such a distance matrix by generating nodes - and computing the edge lengths. - "]], + summary = [[" + The UPGMA (Unweighted Pair Group Method using arithmetic + Averages) algorithm of Sokal and Michener, 1958. It generates a + graph on the basis of such a distance matrix by generating nodes + and computing the edge lengths. + "]], documentation = [[" - This algorithm uses a distance matrix, ideally an ultrametric - one, to compute the graph. + This algorithm uses a distance matrix, ideally an ultrametric + one, to compute the graph. "]], examples = [[" - \tikz \graph [phylogenetic tree layout, sibling distance=0pt, sibling sep=2pt, - unweighted pair group method using arithmetic averages, - distance matrix={ - 0 4 9 9 9 9 9 - 4 0 9 9 9 9 9 - 9 9 0 2 7 7 7 - 9 9 2 0 7 7 7 - 9 9 7 7 0 3 5 - 9 9 7 7 3 0 5 - 9 9 7 7 5 5 0}] - { a, b, c, d, e, f, g }; + \tikz \graph [phylogenetic tree layout, sibling distance=0pt, sibling sep=2pt, + unweighted pair group method using arithmetic averages, + distance matrix={ + 0 4 9 9 9 9 9 + 4 0 9 9 9 9 9 + 9 9 0 2 7 7 7 + 9 9 2 0 7 7 7 + 9 9 7 7 0 3 5 + 9 9 7 7 3 0 5 + 9 9 7 7 5 5 0}] + { a, b, c, d, e, f, g }; "]] } - - ---- + + +--- declare { key = "upgma", use = { { key = "unweighted pair group method using arithmetic averages" } }, @@ -79,14 +79,14 @@ declare { -- field must be a |Storage| object that will get filled with the -- distances computed by this algorithm. The |lengths| field must also -- be a |Storage| for the computed distances. --- +-- function SokalMichener1958:run() self.distances = Storage.newTableStorage() - + self.tree = Digraph.new(self.main_algorithm.digraph) - - -- store the phylogentic tree object, containing all user-specified + + -- store the phylogenetic tree object, containing all user-specified -- graph information self:runUPGMA() self:createFinalEdges() @@ -109,19 +109,19 @@ function SokalMichener1958:runUPGMA() local g = self.tree local clusters = {} - + -- create the clusters for _,v in ipairs(g.vertices) do clusters[#clusters+1] = self:newCluster(v) end - -- Iniitialise the distances of these clusters: + -- Initialize the distances of these clusters: for _,cx in ipairs(clusters) do for _,cy in ipairs(clusters) do cx.distances[cy] = matrix[cx.root][cy.root] end end - + -- search for clusters with smallest distance and merge them while #clusters > 1 do local minimum_distance = math.huge @@ -153,7 +153,7 @@ function SokalMichener1958:newCluster(vertex) distances = {}, -- cached cluster distances to all other clusters cluster_height = 0 -- this value is equivalent to half the distance of the last two clusters -- that have been merged to form the current cluster; - -- necessary for determining the distances of newly generated nodes to their children. + -- necessary for determining the distances of newly generated nodes to their children. } end @@ -184,7 +184,7 @@ end -- @param distance The distance between the two clusters function SokalMichener1958:mergeClusters(clusters, index_of_first_cluster, index_of_second_cluster, distance) - + local g = self.tree local cluster1 = clusters[index_of_first_cluster] local cluster2 = clusters[index_of_second_cluster] @@ -199,7 +199,7 @@ function SokalMichener1958:mergeClusters(clusters, index_of_first_cluster, index cluster.distances[cluster1] = dist end end - + -- delete cluster2 table.remove(clusters, index_of_second_cluster) @@ -218,8 +218,8 @@ function SokalMichener1958:mergeClusters(clusters, index_of_first_cluster, index local distance1 = distance/2-cluster1.cluster_height self.distances[new_node][cluster1.root] = distance1 local distance2 = distance/2-cluster2.cluster_height - self.distances[new_node][cluster2.root] = distance2 - + self.distances[new_node][cluster2.root] = distance2 + -- these distances are also the final edge lengths, thus: self.lengths[new_node][cluster1.root] = distance1 self.lengths[cluster1.root][new_node] = distance1 @@ -229,7 +229,7 @@ function SokalMichener1958:mergeClusters(clusters, index_of_first_cluster, index g:connect(new_node, cluster1.root) g:connect(new_node, cluster2.root) - + cluster1.root = new_node cluster1.size = cluster1.size + cluster2.size cluster1.cluster_height = distance/2 -- set new height of the cluster @@ -252,7 +252,7 @@ function SokalMichener1958:createFinalEdges() InterfaceToAlgorithms.createEdge( self.main_algorithm, arc.tail, arc.head, { generated_options = { - { key = "phylogenetic edge", value = tostring(self.lengths[arc.tail][arc.head]) } + { key = "phylogenetic edge", value = tostring(self.lengths[arc.tail][arc.head]) } }}) end end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/library.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/library.lua index 29183a57739..5ab821c4a81 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/library.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/phylogenetics/library.lua @@ -12,7 +12,7 @@ --- --- A phylogenetic tree (or network) depicts the evolutionary histroy +-- A phylogenetic tree (or network) depicts the evolutionary history -- of species or, more generally, so called taxa. The present library -- includes a number of algorithms for drawing phylogenetic trees. -- diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua index f30c940a921..f587861d79d 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/BoyerMyrvold2004.lua @@ -41,7 +41,7 @@ first in the dfs) -leastancestor Dfi of the vertex with lowest dfi that can be reached using one back edge -(non-tree edge) +(non-tree edge) -lowpoint Dfi of the vertex with lowest dfi that can be reached using any number of @@ -119,143 +119,143 @@ local Embedding = require "pgf.gd.planar.Embedding" BM.__index = BM function BM.new() - local t = {} - setmetatable(t, BM) - return t + local t = {} + setmetatable(t, BM) + return t end -- initializes some data structures at the beginning -- takes the ugraph of the layout algorithm as input function BM:init(g) - self.inputgraph = g - self.numvertices = #g.vertices - self.vertices = {} - self.verticesbyinputvertex = Storage.new() - self.verticesbylowpoint = Storage.newTableStorage() - self.shortcircuitedges = {} - for _, inputvertex in ipairs(self.inputgraph.vertices) do - local vertex = { - sign = 1, - childlist = LinkedList.new(), - adjlistlinks = {}, - pertinentroots = LinkedList.new(), - inputvertex = inputvertex, - } - setmetatable(vertex, Embedding.vertexmetatable) - self.verticesbyinputvertex[inputvertex] = vertex - end + self.inputgraph = g + self.numvertices = #g.vertices + self.vertices = {} + self.verticesbyinputvertex = Storage.new() + self.verticesbylowpoint = Storage.newTableStorage() + self.shortcircuitedges = {} + for _, inputvertex in ipairs(self.inputgraph.vertices) do + local vertex = { + sign = 1, + childlist = LinkedList.new(), + adjlistlinks = {}, + pertinentroots = LinkedList.new(), + inputvertex = inputvertex, + } + setmetatable(vertex, Embedding.vertexmetatable) + self.verticesbyinputvertex[inputvertex] = vertex + end end --[[ local function nilmax(a, b) - if a == nil then return b end - if b == nil then return a end - return math.max(a, b) + if a == nil then return b end + if b == nil then return a end + return math.max(a, b) end local function nilmin(a, b) - if a == nil then return b end - if b == nil then return a end - return math.min(a, b) + if a == nil then return b end + if b == nil then return a end + return math.min(a, b) end --]] -- the depth-first search of the preprocessing function BM:predfs(inputvertex, parent) - local dfi = #self.vertices + 1 - local vertex = self.verticesbyinputvertex[inputvertex] - self.vertices[dfi] = vertex - -- set the dfs infos in the vertex - vertex.dfi = dfi - vertex.dfsparent = parent - vertex.leastancestor = dfi - vertex.lowpoint = dfi - -- find neighbors - for _, arc in ipairs(self.inputgraph:outgoing(inputvertex)) do - local ninputvertex = arc.head - assert(ninputvertex ~= inputvertex, "Self-loop detected!") - local nvertex = self.verticesbyinputvertex[ninputvertex] - if nvertex.dfi == nil then - -- new vertex discovered - self:predfs(ninputvertex, vertex) -- recursive call - vertex.lowpoint = math.min(vertex.lowpoint, nvertex.lowpoint) - elseif parent and ninputvertex ~= parent.inputvertex then - -- back edge found - vertex.leastancestor = math.min(vertex.leastancestor, nvertex.dfi) - vertex.lowpoint = math.min(vertex.lowpoint, nvertex.dfi) - end - end - -- put vertex into lowpoint sort bucket - table.insert(self.verticesbylowpoint[vertex.lowpoint], vertex) + local dfi = #self.vertices + 1 + local vertex = self.verticesbyinputvertex[inputvertex] + self.vertices[dfi] = vertex + -- set the dfs infos in the vertex + vertex.dfi = dfi + vertex.dfsparent = parent + vertex.leastancestor = dfi + vertex.lowpoint = dfi + -- find neighbors + for _, arc in ipairs(self.inputgraph:outgoing(inputvertex)) do + local ninputvertex = arc.head + assert(ninputvertex ~= inputvertex, "Self-loop detected!") + local nvertex = self.verticesbyinputvertex[ninputvertex] + if nvertex.dfi == nil then + -- new vertex discovered + self:predfs(ninputvertex, vertex) -- recursive call + vertex.lowpoint = math.min(vertex.lowpoint, nvertex.lowpoint) + elseif parent and ninputvertex ~= parent.inputvertex then + -- back edge found + vertex.leastancestor = math.min(vertex.leastancestor, nvertex.dfi) + vertex.lowpoint = math.min(vertex.lowpoint, nvertex.dfi) + end + end + -- put vertex into lowpoint sort bucket + table.insert(self.verticesbylowpoint[vertex.lowpoint], vertex) end -- the preprocessing at the beginning of the algorithm -- does the depth-first search and the bucket sort for the child lists function BM:preprocess() - -- make dfs starting at an arbitrary vertex - self:predfs(self.inputgraph.vertices[1]) - -- create separated child lists with bucket sort - for i = 1, self.numvertices do - for _, vertex in ipairs(self.verticesbylowpoint[i]) do - if vertex.dfsparent then - vertex.childlistelement - = vertex.dfsparent.childlist:addback(vertex) - end - end - end + -- make dfs starting at an arbitrary vertex + self:predfs(self.inputgraph.vertices[1]) + -- create separated child lists with bucket sort + for i = 1, self.numvertices do + for _, vertex in ipairs(self.verticesbylowpoint[i]) do + if vertex.dfsparent then + vertex.childlistelement + = vertex.dfsparent.childlist:addback(vertex) + end + end + end end -- adds tree edges and the corresponding virtual root vertices -- of the currentvertex function BM:add_trivial_edges(vertex) - -- find all dfs children - for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do - local nvertex = self.verticesbyinputvertex[arc.head] - if nvertex.dfsparent == vertex then - -- create root vertex - local rootvertex = { - isroot = true, - rootparent = vertex, - rootchild = nvertex, - adjlistlinks = {}, - name = tostring(vertex) .. "^" .. tostring(nvertex) - } - setmetatable(rootvertex, Embedding.vertexmetatable) - nvertex.parentroot = rootvertex - -- create half edges - local halfedge1 = {target = nvertex, links = {}} - local halfedge2 = {target = rootvertex, links = {}} - halfedge1.twin = halfedge2 - halfedge2.twin = halfedge1 - -- create circular adjacency lists - halfedge1.links[0] = halfedge1 - halfedge1.links[1] = halfedge1 - halfedge2.links[0] = halfedge2 - halfedge2.links[1] = halfedge2 - -- create links to adjacency lists - rootvertex.adjlistlinks[0] = halfedge1 - rootvertex.adjlistlinks[1] = halfedge1 - nvertex.adjlistlinks[0] = halfedge2 - nvertex.adjlistlinks[1] = halfedge2 - end - end + -- find all dfs children + for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do + local nvertex = self.verticesbyinputvertex[arc.head] + if nvertex.dfsparent == vertex then + -- create root vertex + local rootvertex = { + isroot = true, + rootparent = vertex, + rootchild = nvertex, + adjlistlinks = {}, + name = tostring(vertex) .. "^" .. tostring(nvertex) + } + setmetatable(rootvertex, Embedding.vertexmetatable) + nvertex.parentroot = rootvertex + -- create half edges + local halfedge1 = {target = nvertex, links = {}} + local halfedge2 = {target = rootvertex, links = {}} + halfedge1.twin = halfedge2 + halfedge2.twin = halfedge1 + -- create circular adjacency lists + halfedge1.links[0] = halfedge1 + halfedge1.links[1] = halfedge1 + halfedge2.links[0] = halfedge2 + halfedge2.links[1] = halfedge2 + -- create links to adjacency lists + rootvertex.adjlistlinks[0] = halfedge1 + rootvertex.adjlistlinks[1] = halfedge1 + nvertex.adjlistlinks[0] = halfedge2 + nvertex.adjlistlinks[1] = halfedge2 + end + end end -- for the external face vertex which was entered through link vin -- returns the successor on the external face and the link through -- which it was entered local function get_successor_on_external_face(vertex, vin) - local halfedge = vertex.adjlistlinks[1 - vin] - local svertex = halfedge.target - local sin - if vertex.adjlistlinks[0] == vertex.adjlistlinks[1] then - sin = vin - elseif svertex.adjlistlinks[0].twin == halfedge then - sin = 0 - else - sin = 1 - end - return svertex, sin + local halfedge = vertex.adjlistlinks[1 - vin] + local svertex = halfedge.target + local sin + if vertex.adjlistlinks[0] == vertex.adjlistlinks[1] then + sin = vin + elseif svertex.adjlistlinks[0].twin == halfedge then + sin = 0 + else + sin = 1 + end + return svertex, sin end -- the "walkup", used to identify the pertinent subgraph, @@ -266,63 +266,63 @@ end -- currentvertex: the vertex of the current step -- returns a root vertex of the current step, if one was found local function walkup(backvertex, currentvertex) - local currentindex = currentvertex.dfi - -- set the backedgeflag - backvertex.backedgeindex = currentindex - -- initialize traversal variables for both directions - local x, xin, y, yin = backvertex, 1, backvertex, 0 - while x ~= currentvertex do - if x.visited == currentindex or y.visited == currentindex then - -- we found a path that already has the pertinent roots marked - return nil - end - -- mark vertices as visited for later calls - x.visited = currentindex - y.visited = currentindex - - -- check for rootvertex - local rootvertex - if x.isroot then - rootvertex = x - elseif y.isroot then - rootvertex = y - end - if rootvertex then - local rootchild = rootvertex.rootchild - local rootparent = rootvertex.rootparent - if rootvertex.rootparent == currentvertex then - -- we found the other end of the back edge - return rootvertex - elseif rootchild.lowpoint < currentindex then - -- the block we just traversed is externally active - rootvertex.pertinentrootselement - = rootparent.pertinentroots:addback(rootvertex) - else - -- the block we just traversed is internally active - rootvertex.pertinentrootselement - = rootparent.pertinentroots:addfront(rootvertex) - end - -- jump to parent block - x, xin, y, yin = rootvertex.rootparent, 1, rootvertex.rootparent, 0 - else - -- just continue on the external face - x, xin = get_successor_on_external_face(x, xin) - y, yin = get_successor_on_external_face(y, yin) - end - end + local currentindex = currentvertex.dfi + -- set the backedgeflag + backvertex.backedgeindex = currentindex + -- initialize traversal variables for both directions + local x, xin, y, yin = backvertex, 1, backvertex, 0 + while x ~= currentvertex do + if x.visited == currentindex or y.visited == currentindex then + -- we found a path that already has the pertinent roots marked + return nil + end + -- mark vertices as visited for later calls + x.visited = currentindex + y.visited = currentindex + + -- check for rootvertex + local rootvertex + if x.isroot then + rootvertex = x + elseif y.isroot then + rootvertex = y + end + if rootvertex then + local rootchild = rootvertex.rootchild + local rootparent = rootvertex.rootparent + if rootvertex.rootparent == currentvertex then + -- we found the other end of the back edge + return rootvertex + elseif rootchild.lowpoint < currentindex then + -- the block we just traversed is externally active + rootvertex.pertinentrootselement + = rootparent.pertinentroots:addback(rootvertex) + else + -- the block we just traversed is internally active + rootvertex.pertinentrootselement + = rootparent.pertinentroots:addfront(rootvertex) + end + -- jump to parent block + x, xin, y, yin = rootvertex.rootparent, 1, rootvertex.rootparent, 0 + else + -- just continue on the external face + x, xin = get_successor_on_external_face(x, xin) + y, yin = get_successor_on_external_face(y, yin) + end + end end -- inverts the adjacency of a vertex -- i. e. reverses the order of the adjacency list and flips the links local function invert_adjacency(vertex) - -- reverse the list - for halfedge in Embedding.adjacency_iterator(vertex.adjlistlinks[0]) do - halfedge.links[0], halfedge.links[1] - = halfedge.links[1], halfedge.links[0] - end - -- flip links - vertex.adjlistlinks[0], vertex.adjlistlinks[1] - = vertex.adjlistlinks[1], vertex.adjlistlinks[0] + -- reverse the list + for halfedge in Embedding.adjacency_iterator(vertex.adjlistlinks[0]) do + halfedge.links[0], halfedge.links[1] + = halfedge.links[1], halfedge.links[0] + end + -- flip links + vertex.adjlistlinks[0], vertex.adjlistlinks[1] + = vertex.adjlistlinks[1], vertex.adjlistlinks[0] end -- merges two blocks by merging the virtual root of the child block @@ -336,76 +336,76 @@ end -- pin - the link of the parent through which we have entered it -- during the walkdown local function mergeblocks(mergeinfo) - local root = mergeinfo.root - local parent = mergeinfo.parent - local rout = mergeinfo.rootout - local pin = mergeinfo.parentin - if pin == rout then - -- flip required - invert_adjacency(root) - root.rootchild.sign = -1 - --rout = 1 - rout -- not needed - end - - -- redirect edges of the root vertex - for halfedge in Embedding.adjacency_iterator(root.adjlistlinks[0]) do - halfedge.twin.target = parent - end - - -- remove block from data structures - root.rootchild.parentroot = nil - parent.pertinentroots:remove(root.pertinentrootselement) - parent.childlist:remove(root.rootchild.childlistelement) - - -- merge adjacency lists - parent.adjlistlinks[0].links[1] = root.adjlistlinks[1] - parent.adjlistlinks[1].links[0] = root.adjlistlinks[0] - root.adjlistlinks[0].links[1] = parent.adjlistlinks[1] - root.adjlistlinks[1].links[0] = parent.adjlistlinks[0] - parent.adjlistlinks[pin] = root.adjlistlinks[pin] + local root = mergeinfo.root + local parent = mergeinfo.parent + local rout = mergeinfo.rootout + local pin = mergeinfo.parentin + if pin == rout then + -- flip required + invert_adjacency(root) + root.rootchild.sign = -1 + --rout = 1 - rout -- not needed + end + + -- redirect edges of the root vertex + for halfedge in Embedding.adjacency_iterator(root.adjlistlinks[0]) do + halfedge.twin.target = parent + end + + -- remove block from data structures + root.rootchild.parentroot = nil + parent.pertinentroots:remove(root.pertinentrootselement) + parent.childlist:remove(root.rootchild.childlistelement) + + -- merge adjacency lists + parent.adjlistlinks[0].links[1] = root.adjlistlinks[1] + parent.adjlistlinks[1].links[0] = root.adjlistlinks[0] + root.adjlistlinks[0].links[1] = parent.adjlistlinks[1] + root.adjlistlinks[1].links[0] = parent.adjlistlinks[0] + parent.adjlistlinks[pin] = root.adjlistlinks[pin] end -- inserts a half edge pointing to "to" into the adjacency list of "from", -- replacing the link "linkindex" local function insert_half_edge(from, linkindex, to) - local halfedge = {target = to, links = {}} - halfedge.links[ linkindex] = from.adjlistlinks[ linkindex] - halfedge.links[1 - linkindex] = from.adjlistlinks[1 - linkindex] - from.adjlistlinks[ linkindex].links[1 - linkindex] = halfedge - from.adjlistlinks[1 - linkindex].links[ linkindex] = halfedge - from.adjlistlinks[linkindex] = halfedge - return halfedge + local halfedge = {target = to, links = {}} + halfedge.links[ linkindex] = from.adjlistlinks[ linkindex] + halfedge.links[1 - linkindex] = from.adjlistlinks[1 - linkindex] + from.adjlistlinks[ linkindex].links[1 - linkindex] = halfedge + from.adjlistlinks[1 - linkindex].links[ linkindex] = halfedge + from.adjlistlinks[linkindex] = halfedge + return halfedge end -- connect the vertices x and y through the links xout and yin -- if shortcircuit is true, the edge will be marked as a short circuit edge -- and removed at the end of the algorithm function BM:embed_edge(x, xout, y, yin, shortcircuit) - -- create half edges - local halfedgex = insert_half_edge(x, xout, y) - local halfedgey = insert_half_edge(y, yin, x) - halfedgex.twin = halfedgey - halfedgey.twin = halfedgex - -- short circuit handling - if shortcircuit then - halfedgex.shortcircuit = true - halfedgey.shortcircuit = true - table.insert(self.shortcircuitedges, halfedgex) - table.insert(self.shortcircuitedges, halfedgey) - end + -- create half edges + local halfedgex = insert_half_edge(x, xout, y) + local halfedgey = insert_half_edge(y, yin, x) + halfedgex.twin = halfedgey + halfedgey.twin = halfedgex + -- short circuit handling + if shortcircuit then + halfedgex.shortcircuit = true + halfedgey.shortcircuit = true + table.insert(self.shortcircuitedges, halfedgex) + table.insert(self.shortcircuitedges, halfedgey) + end end -- returns true if the given vertex is pertinent at the current step local function pertinent(vertex, currentindex) - return vertex.backedgeindex == currentindex - or not vertex.pertinentroots:empty() + return vertex.backedgeindex == currentindex + or not vertex.pertinentroots:empty() end --- returns ttue if the given vertex is externally active at the current step +-- returns true if the given vertex is externally active at the current step local function externally_active(vertex, currentindex) - return vertex.leastancestor < currentindex - or (not vertex.childlist:empty() - and vertex.childlist:first().lowpoint < currentindex) + return vertex.leastancestor < currentindex + or (not vertex.childlist:empty() + and vertex.childlist:first().lowpoint < currentindex) end -- the "walkdown", which merges the pertinent subgraph and embeds @@ -414,148 +414,148 @@ end -- which the walkdown will start at -- currentvertex - the vertex of the current step function BM:walkdown(childrootvertex, currentvertex) - local currentindex = currentvertex.dfi - local mergestack = {} - local numinsertededges = 0 -- to return the number for count check - -- two walkdowns into both directions - for vout = 0,1 do - -- initialize the traversal variables - local w, win = get_successor_on_external_face(childrootvertex, 1 - vout) - while w ~= childrootvertex do - if w.backedgeindex == currentindex then - -- we found a backedge endpoint - -- merge all pertinent roots we found - while #mergestack > 0 do - mergeblocks(table.remove(mergestack)) - end - -- embed the back edge - self:embed_edge(childrootvertex, vout, w, win) - numinsertededges = numinsertededges + 1 - w.backedgeindex = 0 -- this shouldn't be necessary - end - if not w.pertinentroots:empty() then - -- we found a pertinent vertex with child blocks - -- create merge info for the later merge - local mergeinfo = {} - mergeinfo.parent = w - mergeinfo.parentin = win - local rootvertex = w.pertinentroots:first() - mergeinfo.root = rootvertex - -- check both directions for active vertices - local x, xin = get_successor_on_external_face(rootvertex, 1) - local y, yin = get_successor_on_external_face(rootvertex, 0) - local xpertinent = pertinent(x, currentindex) - local xexternallyactive = externally_active(x, currentindex) - local ypertinent = pertinent(y, currentindex) - local yexternallyactive = externally_active(y, currentindex) - -- chose the direction with the best vertex - if xpertinent and not xexternallyactive then - w, win = x, xin - mergeinfo.rootout = 0 - elseif ypertinent and not yexternallyactive then - w, win = y, yin - mergeinfo.rootout = 1 - elseif xpertinent then - w, win = x, xin - mergeinfo.rootout = 0 - else - w, win = y, yin - mergeinfo.rootout = 1 - end - -- this is what the paper sais, but it might cause problems - -- not sure though... - --[[if w == x then - mergeinfo.rootout = 0 - else - mergeinfo.rootout = 1 - end--]] - table.insert(mergestack, mergeinfo) - elseif not pertinent(w, currentindex) - and not externally_active(w, currentindex) then - -- nothing to see here, just continue on the external face - w, win = get_successor_on_external_face(w, win) - else - -- this is a stopping vertex, walkdown will end here - -- paper puts this into the if, - -- but this should always be the case, i think - assert(childrootvertex.rootchild.lowpoint < currentindex) - if #mergestack == 0 then - -- we're in the block we started at, so we embed a back edge - self:embed_edge(childrootvertex, vout, w, win, true) - end - break - end - end - if #mergestack > 0 then - -- this means, there is a pertinent vertex blocked by stop vertices, - -- so the graph is not planar and we can skip the second walkdown - break - end - end - return numinsertededges + local currentindex = currentvertex.dfi + local mergestack = {} + local numinsertededges = 0 -- to return the number for count check + -- two walkdowns into both directions + for vout = 0,1 do + -- initialize the traversal variables + local w, win = get_successor_on_external_face(childrootvertex, 1 - vout) + while w ~= childrootvertex do + if w.backedgeindex == currentindex then + -- we found a backedge endpoint + -- merge all pertinent roots we found + while #mergestack > 0 do + mergeblocks(table.remove(mergestack)) + end + -- embed the back edge + self:embed_edge(childrootvertex, vout, w, win) + numinsertededges = numinsertededges + 1 + w.backedgeindex = 0 -- this shouldn't be necessary + end + if not w.pertinentroots:empty() then + -- we found a pertinent vertex with child blocks + -- create merge info for the later merge + local mergeinfo = {} + mergeinfo.parent = w + mergeinfo.parentin = win + local rootvertex = w.pertinentroots:first() + mergeinfo.root = rootvertex + -- check both directions for active vertices + local x, xin = get_successor_on_external_face(rootvertex, 1) + local y, yin = get_successor_on_external_face(rootvertex, 0) + local xpertinent = pertinent(x, currentindex) + local xexternallyactive = externally_active(x, currentindex) + local ypertinent = pertinent(y, currentindex) + local yexternallyactive = externally_active(y, currentindex) + -- chose the direction with the best vertex + if xpertinent and not xexternallyactive then + w, win = x, xin + mergeinfo.rootout = 0 + elseif ypertinent and not yexternallyactive then + w, win = y, yin + mergeinfo.rootout = 1 + elseif xpertinent then + w, win = x, xin + mergeinfo.rootout = 0 + else + w, win = y, yin + mergeinfo.rootout = 1 + end + -- this is what the paper says, but it might cause problems + -- not sure though... + --[[if w == x then + mergeinfo.rootout = 0 + else + mergeinfo.rootout = 1 + end--]] + table.insert(mergestack, mergeinfo) + elseif not pertinent(w, currentindex) + and not externally_active(w, currentindex) then + -- nothing to see here, just continue on the external face + w, win = get_successor_on_external_face(w, win) + else + -- this is a stopping vertex, walkdown will end here + -- paper puts this into the if, + -- but this should always be the case, i think + assert(childrootvertex.rootchild.lowpoint < currentindex) + if #mergestack == 0 then + -- we're in the block we started at, so we embed a back edge + self:embed_edge(childrootvertex, vout, w, win, true) + end + break + end + end + if #mergestack > 0 then + -- this means, there is a pertinent vertex blocked by stop vertices, + -- so the graph is not planar and we can skip the second walkdown + break + end + end + return numinsertededges end -- embeds the back edges for the current vertex -- walkup and walkdown are called from here -- returns true, if all back edges could be embedded function BM:add_back_edges(vertex) - local pertinentroots = {} -- not in the paper - local numbackedges = 0 - -- find all back edges to vertices with lower dfi - for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do - local nvertex = self.verticesbyinputvertex[arc.head] - if nvertex.dfi > vertex.dfi - and nvertex.dfsparent ~= vertex - and nvertex ~= vertex.dfsparent then - numbackedges = numbackedges + 1 - -- do the walkup - local rootvertex = walkup(nvertex, vertex) - if rootvertex then - -- remember the root vertex the walkup found, so we don't - -- have to call the walkdown for all root vertices - -- (or even know what the root vertices are) - table.insert(pertinentroots, rootvertex) - end - end - end - -- for all root vertices the walkup found - local insertededges = 0 - while #pertinentroots > 0 do - -- do the walkdown - insertededges = insertededges - + self:walkdown(table.remove(pertinentroots), vertex) - end - if insertededges ~= numbackedges then - -- not all back edges could be embedded -> graph is not planar - return false - end - return true + local pertinentroots = {} -- not in the paper + local numbackedges = 0 + -- find all back edges to vertices with lower dfi + for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do + local nvertex = self.verticesbyinputvertex[arc.head] + if nvertex.dfi > vertex.dfi + and nvertex.dfsparent ~= vertex + and nvertex ~= vertex.dfsparent then + numbackedges = numbackedges + 1 + -- do the walkup + local rootvertex = walkup(nvertex, vertex) + if rootvertex then + -- remember the root vertex the walkup found, so we don't + -- have to call the walkdown for all root vertices + -- (or even know what the root vertices are) + table.insert(pertinentroots, rootvertex) + end + end + end + -- for all root vertices the walkup found + local insertededges = 0 + while #pertinentroots > 0 do + -- do the walkdown + insertededges = insertededges + + self:walkdown(table.remove(pertinentroots), vertex) + end + if insertededges ~= numbackedges then + -- not all back edges could be embedded -> graph is not planar + return false + end + return true end -- the depth-first search of the postprocessing -- flips the blocks according to the sign field function BM:postdfs(vertex, sign) - sign = sign or 1 - local root = vertex.parentroot - if root then - sign = 1 - else - sign = sign * vertex.sign - end - - if sign == -1 then - -- number of flips is odd, so we need to flip here - invert_adjacency(vertex) - end - - -- for all dfs children - for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do - local nvertex = self.verticesbyinputvertex[arc.head] - if nvertex.dfsparent == vertex then - -- recursive call - self:postdfs(nvertex, sign) - end - end + sign = sign or 1 + local root = vertex.parentroot + if root then + sign = 1 + else + sign = sign * vertex.sign + end + + if sign == -1 then + -- number of flips is odd, so we need to flip here + invert_adjacency(vertex) + end + + -- for all dfs children + for _, arc in ipairs(self.inputgraph:outgoing(vertex.inputvertex)) do + local nvertex = self.verticesbyinputvertex[arc.head] + if nvertex.dfsparent == vertex then + -- recursive call + self:postdfs(nvertex, sign) + end + end end -- the postprocessing at the end of the algorithm @@ -565,91 +565,91 @@ end -- merges root vertices -- and cleans up the vertices function BM:postprocess() - -- flip components - self:postdfs(self.vertices[1]) - - -- unlink the short circuit edges - for _, halfedge in ipairs(self.shortcircuitedges) do - halfedge.links[0].links[1] = halfedge.links[1] - halfedge.links[1].links[0] = halfedge.links[0] - end - - -- vertex loop - local rootvertices = {} - local edgetoface = {} - for _, vertex in ipairs(self.vertices) do - -- check for root vertex and save it - local root = vertex.parentroot - if root then - table.insert(rootvertices, root) - end - - -- clean up links and create adjacency matrix - local link = vertex.adjlistlinks[0] - local adjmat = {} - vertex.adjmat = adjmat - if link then - -- make sure the link points to a half edge - -- that is no short circuit edge - while link.shortcircuit do - link = link.links[0] - end - -- create link - vertex.link = link - - -- create adjacency matrix - for halfedge in Embedding.adjacency_iterator(link) do - setmetatable(halfedge, Embedding.halfedgemetatable) - local target = halfedge.target - if target.isroot then - target = target.rootparent - end - adjmat[target] = halfedge - end - end - - -- clean up vertex - vertex.sign = nil - vertex.childlist = nil - vertex.adjlistlinks = nil - vertex.pertinentroots = nil - vertex.dfi = nil - vertex.dfsparent = nil - vertex.leastancestor = nil - vertex.lowpoint = nil - vertex.parentroot = nil - end - - -- root vertex loop - for _, root in ipairs(rootvertices) do - -- make sure the links point to a half edges - -- that are no short circuit edge - local link = root.adjlistlinks[0] - while link.shortcircuit do - link = link.links[0] - end - - -- merge into parent - local rootparent = root.rootparent - local parentlink = rootparent.link - local adjmat = rootparent.adjmat - for halfedge in Embedding.adjacency_iterator(link) do - setmetatable(halfedge, Embedding.halfedgemetatable) - halfedge.twin.target = rootparent - adjmat[halfedge.target] = halfedge - end - if parentlink == nil then - assert(rootparent.link == nil) - rootparent.link = link - else - -- merge adjacency lists - parentlink.links[0].links[1] = link - link.links[0].links[1] = parentlink - local tmp = link.links[0] - link.links[0] = parentlink.links[0] - parentlink.links[0] = tmp - end - end + -- flip components + self:postdfs(self.vertices[1]) + + -- unlink the short circuit edges + for _, halfedge in ipairs(self.shortcircuitedges) do + halfedge.links[0].links[1] = halfedge.links[1] + halfedge.links[1].links[0] = halfedge.links[0] + end + + -- vertex loop + local rootvertices = {} + local edgetoface = {} + for _, vertex in ipairs(self.vertices) do + -- check for root vertex and save it + local root = vertex.parentroot + if root then + table.insert(rootvertices, root) + end + + -- clean up links and create adjacency matrix + local link = vertex.adjlistlinks[0] + local adjmat = {} + vertex.adjmat = adjmat + if link then + -- make sure the link points to a half edge + -- that is no short circuit edge + while link.shortcircuit do + link = link.links[0] + end + -- create link + vertex.link = link + + -- create adjacency matrix + for halfedge in Embedding.adjacency_iterator(link) do + setmetatable(halfedge, Embedding.halfedgemetatable) + local target = halfedge.target + if target.isroot then + target = target.rootparent + end + adjmat[target] = halfedge + end + end + + -- clean up vertex + vertex.sign = nil + vertex.childlist = nil + vertex.adjlistlinks = nil + vertex.pertinentroots = nil + vertex.dfi = nil + vertex.dfsparent = nil + vertex.leastancestor = nil + vertex.lowpoint = nil + vertex.parentroot = nil + end + + -- root vertex loop + for _, root in ipairs(rootvertices) do + -- make sure the links point to a half edges + -- that are no short circuit edge + local link = root.adjlistlinks[0] + while link.shortcircuit do + link = link.links[0] + end + + -- merge into parent + local rootparent = root.rootparent + local parentlink = rootparent.link + local adjmat = rootparent.adjmat + for halfedge in Embedding.adjacency_iterator(link) do + setmetatable(halfedge, Embedding.halfedgemetatable) + halfedge.twin.target = rootparent + adjmat[halfedge.target] = halfedge + end + if parentlink == nil then + assert(rootparent.link == nil) + rootparent.link = link + else + -- merge adjacency lists + parentlink.links[0].links[1] = link + link.links[0].links[1] = parentlink + local tmp = link.links[0] + link.links[0] = parentlink.links[0] + parentlink.links[0] = tmp + end + end end -- the entry point of the algorithm @@ -659,20 +659,20 @@ end -- from the respective adjacency list -- the adjacency lists are in a circular order in respect to the plane graph function BM:run() - self:preprocess() - -- main loop over all vertices from lowest dfi to highest - for i = self.numvertices, 1, -1 do - local vertex = self.vertices[i] - self:add_trivial_edges(vertex) - if not self:add_back_edges(vertex) then - -- graph not planar - return nil - end - end - self:postprocess() - local embedding = Embedding.new() - embedding.vertices = self.vertices - return embedding + self:preprocess() + -- main loop over all vertices from lowest dfi to highest + for i = self.numvertices, 1, -1 do + local vertex = self.vertices[i] + self:add_trivial_edges(vertex) + if not self:add_back_edges(vertex) then + -- graph not planar + return nil + end + end + self:postprocess() + local embedding = Embedding.new() + embedding.vertices = self.vertices + return embedding end return BM diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/Embedding.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/Embedding.lua index 50fc3672207..8d9d3b53b14 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/Embedding.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/Embedding.lua @@ -6,782 +6,783 @@ require("pgf.gd.planar").Embedding = E local LinkedList = require("pgf.gd.planar.LinkedList") E.vertexmetatable = { - __tostring = function(v) - if v.name then - return v.name - elseif v.inputvertex then - return v.inputvertex.name - else - return tostring(v) - end - end + __tostring = function(v) + if v.name then + return v.name + elseif v.inputvertex then + return v.inputvertex.name + else + return tostring(v) + end + end } E.halfedgemetatable = { - __tostring = function(e) - return tostring(e.twin.target) - .. " -> " - .. tostring(e.target) - end + __tostring = function(e) + return tostring(e.twin.target) + .. " -> " + .. tostring(e.target) + end } -- create class properties E.__index = E function E.new() - local t = { - vertices = {}, - } - setmetatable(t, E) - return t + local t = { + vertices = {}, + } + setmetatable(t, E) + return t end function E:add_vertex(name, inputvertex, virtual) - virtual = virtual or nil - local vertex = { - adjmat = {}, - name = name, - inputvertex = inputvertex, - virtual = virtual, - } - setmetatable(vertex, E.vertexmetatable) - table.insert(self.vertices, vertex) - return vertex + virtual = virtual or nil + local vertex = { + adjmat = {}, + name = name, + inputvertex = inputvertex, + virtual = virtual, + } + setmetatable(vertex, E.vertexmetatable) + table.insert(self.vertices, vertex) + return vertex end function E:add_edge(v1, v2, after1, after2, virtual) - assert(v1.link == nil or v1 == after1.twin.target) - assert(v2.link == nil or v2 == after2.twin.target) - assert(v1.adjmat[v2] == nil) - assert(v2.adjmat[v1] == nil) - - virtual = virtual or nil - - local halfedge1 = { - target = v2, - virtual = virtual, - links = {}, - } - local halfedge2 = { - target = v1, - virtual = virtual, - links = {}, - } - halfedge1.twin = halfedge2 - halfedge2.twin = halfedge1 - - setmetatable(halfedge1, E.halfedgemetatable) - setmetatable(halfedge2, E.halfedgemetatable) - - if v1.link == nil then - v1.link = halfedge1 - halfedge1.links[0] = halfedge1 - halfedge1.links[1] = halfedge1 - else - halfedge1.links[0] = after1.links[0] - after1.links[0].links[1] = halfedge1 - halfedge1.links[1] = after1 - after1.links[0] = halfedge1 - end - - if v2.link == nil then - v2.link = halfedge2 - halfedge2.links[0] = halfedge2 - halfedge2.links[1] = halfedge2 - else - halfedge2.links[0] = after2.links[0] - after2.links[0].links[1] = halfedge2 - halfedge2.links[1] = after2 - after2.links[0] = halfedge2 - end - - v1.adjmat[v2] = halfedge1 - v2.adjmat[v1] = halfedge2 - - return halfedge1, halfedge2 + assert(v1.link == nil or v1 == after1.twin.target) + assert(v2.link == nil or v2 == after2.twin.target) + assert(v1.adjmat[v2] == nil) + assert(v2.adjmat[v1] == nil) + + virtual = virtual or nil + + local halfedge1 = { + target = v2, + virtual = virtual, + links = {}, + } + local halfedge2 = { + target = v1, + virtual = virtual, + links = {}, + } + halfedge1.twin = halfedge2 + halfedge2.twin = halfedge1 + + setmetatable(halfedge1, E.halfedgemetatable) + setmetatable(halfedge2, E.halfedgemetatable) + + if v1.link == nil then + v1.link = halfedge1 + halfedge1.links[0] = halfedge1 + halfedge1.links[1] = halfedge1 + else + halfedge1.links[0] = after1.links[0] + after1.links[0].links[1] = halfedge1 + halfedge1.links[1] = after1 + after1.links[0] = halfedge1 + end + + if v2.link == nil then + v2.link = halfedge2 + halfedge2.links[0] = halfedge2 + halfedge2.links[1] = halfedge2 + else + halfedge2.links[0] = after2.links[0] + after2.links[0].links[1] = halfedge2 + halfedge2.links[1] = after2 + after2.links[0] = halfedge2 + end + + v1.adjmat[v2] = halfedge1 + v2.adjmat[v1] = halfedge2 + + return halfedge1, halfedge2 end function E:remove_virtual() - local virtuals = {} - for i, v in ipairs(self.vertices) do - if v.virtual then - table.insert(virtuals, i) - else - local start = v.link - local current = start - repeat - current = current.links[0] - if current.virtual then - current.links[0].links[1] = current.links[1] - current.links[1].links[0] = current.links[0] - v.adjmat[current.target] = nil - current.target.adjmat[v] = nil - end - until current == start - end - end - for i = #virtuals, 1, -1 do - self.vertices[virtuals[i]] = self.vertices[#self.vertices] - table.remove(self.vertices) - end + local virtuals = {} + for i, v in ipairs(self.vertices) do + if v.virtual then + table.insert(virtuals, i) + else + local start = v.link + local current = start + repeat + current = current.links[0] + if current.virtual then + current.links[0].links[1] = current.links[1] + current.links[1].links[0] = current.links[0] + v.adjmat[current.target] = nil + current.target.adjmat[v] = nil + end + until current == start + end + end + for i = #virtuals, 1, -1 do + self.vertices[virtuals[i]] = self.vertices[#self.vertices] + table.remove(self.vertices) + end end -- for the use in for-loops -- iterates over the adjacency list of a vertex -- given a half edge to start and a direction (0 or 1, default 0) function E.adjacency_iterator(halfedge, direction) - direction = direction or 0 - local function next_edge(startedge, prevedge) - if prevedge == nil then - return startedge - else - local nextedge = prevedge.links[direction] - if nextedge ~= startedge then - return nextedge - else - return nil - end - end - end - return next_edge, halfedge, nil + direction = direction or 0 + local function next_edge(startedge, prevedge) + if prevedge == nil then + return startedge + else + local nextedge = prevedge.links[direction] + if nextedge ~= startedge then + return nextedge + else + return nil + end + end + end + return next_edge, halfedge, nil end function E.face_iterator(halfedge, direction) - direction = direction or 0 - local function next_edge(startedge, prevedge) - if prevedge == nil then - return startedge - else - local nextedge = prevedge.twin.links[1 - direction] - if nextedge ~= startedge then - return nextedge - else - return nil - end - end - end - return next_edge, halfedge, nil + direction = direction or 0 + local function next_edge(startedge, prevedge) + if prevedge == nil then + return startedge + else + local nextedge = prevedge.twin.links[1 - direction] + if nextedge ~= startedge then + return nextedge + else + return nil + end + end + end + return next_edge, halfedge, nil end function E:triangulate() - local visited = {} - for _, vertex in ipairs(self.vertices) do - for start in E.adjacency_iterator(vertex.link) do - if not visited[start] then - local prev = start - local beforestart = start.links[0].twin - local current = start.twin.links[1] - local next = current.twin.links[1] - visited[start] = true - visited[current] = true - visited[next] = true - while next ~= beforestart do - local halfedge1, halfedge2 - if vertex ~= current.target - and not vertex.adjmat[current.target] then - halfedge1, halfedge2 = self:add_edge( - vertex, current.target, - prev, next, - true - ) - - prev = halfedge1 - current = next - next = next.twin.links[1] - elseif not prev.target.adjmat[next.target] then - halfedge1, halfedge2 = self:add_edge( - prev.target, next.target, - current, next.twin.links[1], - true - ) - - current = halfedge1 - next = halfedge2.links[1] - else - local helper = next.twin.links[1] - halfedge1, halfedge2 = self:add_edge( - current.target, helper.target, - next, helper.twin.links[1], - true - ) - - next = halfedge1 - end - - visited[next] = true - visited[halfedge1] = true - visited[halfedge2] = true - end - end - end - end + local visited = {} + for _, vertex in ipairs(self.vertices) do + for start in E.adjacency_iterator(vertex.link) do + if not visited[start] then + local prev = start + local beforestart = start.links[0].twin + local current = start.twin.links[1] + local next = current.twin.links[1] + visited[start] = true + visited[current] = true + visited[next] = true + while next ~= beforestart do + local halfedge1, halfedge2 + if vertex ~= current.target + and not vertex.adjmat[current.target] then + halfedge1, halfedge2 = self:add_edge( + vertex, current.target, + prev, next, + true + ) + + prev = halfedge1 + current = next + next = next.twin.links[1] + elseif not prev.target.adjmat[next.target] then + halfedge1, halfedge2 = self:add_edge( + prev.target, next.target, + current, next.twin.links[1], + true + ) + + current = halfedge1 + next = halfedge2.links[1] + else + local helper = next.twin.links[1] + halfedge1, halfedge2 = self:add_edge( + current.target, helper.target, + next, helper.twin.links[1], + true + ) + + next = halfedge1 + end + + visited[next] = true + visited[halfedge1] = true + visited[halfedge2] = true + end + end + end + end end function E:canonical_order(v1, v2, vn) - local n = #self.vertices - local order = { v1 } - local marks = { [v1] = "ordered", [v2] = 0 } - local visited = {} - local vk = v1 - local candidates = LinkedList.new() - local listelements = {} - for k = 1, n-2 do - for halfedge in E.adjacency_iterator(vk.link) do - local vertex = halfedge.target - if vertex ~= vn then - local twin = halfedge.twin - visited[twin] = true - if marks[vertex] == nil then - marks[vertex] = "visited" - elseif marks[vertex] ~= "ordered" then - local neighbor1 = visited[twin.links[0]] - local neighbor2 = visited[twin.links[1]] - if marks[vertex] == "visited" then - if neighbor1 or neighbor2 then - marks[vertex] = 1 - listelements[vertex] = candidates:addback(vertex) - else - marks[vertex] = 2 - end - else - if neighbor1 == neighbor2 then - if neighbor1 and neighbor2 then - marks[vertex] = marks[vertex] - 1 - else - marks[vertex] = marks[vertex] + 1 - end - if marks[vertex] == 1 then - listelements[vertex] - = candidates:addback(vertex) - elseif listelements[vertex] then - candidates:remove(listelements[vertex]) - listelements[vertex] = nil - end - end - end - end - end - end - vk = candidates:popfirst() - order[k+1] = vk - marks[vk] = "ordered" - end - order[n] = vn - return order + local n = #self.vertices + local order = { v1 } + local marks = { [v1] = "ordered", [v2] = 0 } + local visited = {} + local vk = v1 + local candidates = LinkedList.new() + local listelements = {} + for k = 1, n-2 do + for halfedge in E.adjacency_iterator(vk.link) do + local vertex = halfedge.target + if vertex ~= vn then + local twin = halfedge.twin + visited[twin] = true + if marks[vertex] == nil then + marks[vertex] = "visited" + elseif marks[vertex] ~= "ordered" then + local neighbor1 = visited[twin.links[0]] + local neighbor2 = visited[twin.links[1]] + if marks[vertex] == "visited" then + if neighbor1 or neighbor2 then + marks[vertex] = 1 + listelements[vertex] = candidates:addback(vertex) + else + marks[vertex] = 2 + end + else + if neighbor1 == neighbor2 then + if neighbor1 and neighbor2 then + marks[vertex] = marks[vertex] - 1 + else + marks[vertex] = marks[vertex] + 1 + end + if marks[vertex] == 1 then + listelements[vertex] + = candidates:addback(vertex) + elseif listelements[vertex] then + candidates:remove(listelements[vertex]) + listelements[vertex] = nil + end + end + end + end + end + end + vk = candidates:popfirst() + order[k+1] = vk + marks[vk] = "ordered" + end + order[n] = vn + return order end function E:get_biggest_face() - local number = 0 - local edge - local visited = {} - for _, vertex in ipairs(self.vertices) do - for start in E.adjacency_iterator(vertex.link) do - local count = 0 - if not visited[start] then - visited[start] = true - local current = start - repeat - count = count + 1 - current = current.twin.links[1] - until current == start - if count > number then - number = count - edge = start - end - end - end - end - return edge, number + local number = 0 + local edge + local visited = {} + for _, vertex in ipairs(self.vertices) do + for start in E.adjacency_iterator(vertex.link) do + local count = 0 + if not visited[start] then + visited[start] = true + local current = start + repeat + count = count + 1 + current = current.twin.links[1] + until current == start + if count > number then + number = count + edge = start + end + end + end + end + return edge, number end function E:surround_by_triangle(faceedge, facesize) - local divisor = 3 - if facesize > 3 then - divisor = 4 - end - local basenodes = math.floor(facesize / divisor) - local extranodes = facesize % divisor - local attachnodes = { basenodes, basenodes, basenodes } - if facesize > 3 then - attachnodes[2] = basenodes * 2 - end - for i = 1,extranodes do - attachnodes[i] = attachnodes[i] + 1 - end - - local v = { - self:add_vertex("$v_1$", nil, true), - self:add_vertex("$v_n$", nil, true), - self:add_vertex("$v_2$", nil, true) - } - for i = 1,3 do - local currentv = v[i] - local nextv = v[i % 3 + 1] - self:add_edge(currentv, nextv, currentv.link, nextv.link, true) - end - - local current = faceedge - local next = current.twin.links[1] - for i = 1,3 do - local vertex = v[i] - local otheredge = vertex.adjmat[v[i % 3 + 1]] - local previnserted = otheredge.links[1] - for count = 1, attachnodes[i] do - if not vertex.adjmat[current.target] then - previnserted, _ = self:add_edge(vertex, current.target, - previnserted, next, - true - ) - end - - current = next - next = next.twin.links[1] - end - if not vertex.adjmat[current.target] then - previnserted, _ = self:add_edge( - vertex, current.target, - previnserted, next, - true - ) - current = previnserted - end - end - return v[1], v[3], v[2] + local divisor = 3 + if facesize > 3 then + divisor = 4 + end + local basenodes = math.floor(facesize / divisor) + local extranodes = facesize % divisor + local attachnodes = { basenodes, basenodes, basenodes } + if facesize > 3 then + attachnodes[2] = basenodes * 2 + end + for i = 1,extranodes do + attachnodes[i] = attachnodes[i] + 1 + end + + local v = { + self:add_vertex("$v_1$", nil, true), + self:add_vertex("$v_n$", nil, true), + self:add_vertex("$v_2$", nil, true) + } + for i = 1,3 do + local currentv = v[i] + local nextv = v[i % 3 + 1] + self:add_edge(currentv, nextv, currentv.link, nextv.link, true) + end + + local current = faceedge + local next = current.twin.links[1] + for i = 1,3 do + local vertex = v[i] + local otheredge = vertex.adjmat[v[i % 3 + 1]] + local previnserted = otheredge.links[1] + for count = 1, attachnodes[i] do + if not vertex.adjmat[current.target] then + previnserted, _ = self:add_edge( + vertex, current.target, + previnserted, next, + true + ) + end + + current = next + next = next.twin.links[1] + end + if not vertex.adjmat[current.target] then + previnserted, _ = self:add_edge( + vertex, current.target, + previnserted, next, + true + ) + current = previnserted + end + end + return v[1], v[3], v[2] end function E:improve() - local pairdata = {} - local inpair = {} - for i, v1 in ipairs(self.vertices) do - for j = i + 1, #self.vertices do - local v2 = self.vertices[j] - local pd = self:find_pair_components(v1, v2) - if pd then - inpair[v1] = true - inpair[v2] = true - table.insert(pairdata, pd) - end - end - if not inpair[v1] then - local pd = self:find_pair_components(v1, nil) - if pd then - inpair[v1] = true - table.insert(pairdata, pd) - end - end - end - - local changed - local runs = 1 - local edgepositions = {} - repeat - changed = false - for i, pd in ipairs(pairdata) do - self:improve_separation_pair(pd) - end - -- check for changes - for i, v in ipairs(self.vertices) do - local start = v.link - local current = start - local counter = 1 - repeat - if counter ~= edgepositions[current] then - changed = true - edgepositions[current] = counter - end - counter = counter + 1 - current = current.links[0] - until current == start - end - runs = runs + 1 - until changed == false or runs > 100 + local pairdata = {} + local inpair = {} + for i, v1 in ipairs(self.vertices) do + for j = i + 1, #self.vertices do + local v2 = self.vertices[j] + local pd = self:find_pair_components(v1, v2) + if pd then + inpair[v1] = true + inpair[v2] = true + table.insert(pairdata, pd) + end + end + if not inpair[v1] then + local pd = self:find_pair_components(v1, nil) + if pd then + inpair[v1] = true + table.insert(pairdata, pd) + end + end + end + + local changed + local runs = 1 + local edgepositions = {} + repeat + changed = false + for i, pd in ipairs(pairdata) do + self:improve_separation_pair(pd) + end + -- check for changes + for i, v in ipairs(self.vertices) do + local start = v.link + local current = start + local counter = 1 + repeat + if counter ~= edgepositions[current] then + changed = true + edgepositions[current] = counter + end + counter = counter + 1 + current = current.links[0] + until current == start + end + runs = runs + 1 + until changed == false or runs > 100 end function E:find_pair_components(v1, v2) - local visited = {} - local companchors = {} - local edgecomps = {} - local compvertices = {} - local islinear = {} - local edgeindices = {} - - local pair = { v1, v2 } - local start = v1.link - local current = start - local edgeindex = 1 - -- start searches from v1 - repeat - edgeindices[current] = edgeindex - edgeindex = edgeindex + 1 - if not edgecomps[current] then - local compindex = #companchors + 1 - local ca, il - edgecomps[current] = compindex - compvertices[compindex] = {} - local target = current.target - if target == v2 then - edgecomps[current.twin] = compindex - ca = 3 - il = true - else - ca, il = self:component_dfs( - target, - pair, - visited, - edgecomps, - compvertices[compindex], - compindex - ) - end - companchors[compindex] = ca - islinear[compindex] = il - end - current = current.links[0] - until current == start - - if v2 then - start = v2.link - current = start - local lastincomp = true - local edgeindex = 1 - -- now find the remaining blocks at v2 - repeat - edgeindices[current] = edgeindex - edgeindex = edgeindex + 1 - if not edgecomps[current] then - local compindex = #companchors + 1 - edgecomps[current] = compindex - compvertices[compindex] = {} - self:component_dfs( - current.target, - pair, - visited, - edgecomps, - compvertices[compindex], - compindex - ) - companchors[compindex] = 2 - end - current = current.links[0] - until current == start - end - - -- init compedges, tricomps, twocomps - local tricomps = {} - local twocomps = {{}, {}} - for i, anchors in ipairs(companchors) do - if anchors == 3 then - table.insert(tricomps, i) - else - table.insert(twocomps[anchors], i) - end - end - - local flipimmune = #tricomps == 2 - and (islinear[tricomps[1]] or islinear[tricomps[2]]) - if (#tricomps < 2 or flipimmune) - and (v2 ~= nil or #twocomps[1] < 2) then - return nil - end - - -- order tri comps cyclic - local function sorter(a, b) - return #compvertices[a] < #compvertices[b] - end - - table.sort(tricomps, sorter) - - -- determine order of comps - local numtricomps = #tricomps - local comporder = { {}, {} } - local bottom = math.ceil(numtricomps / 2) - local top = bottom + 1 - for i, comp in ipairs(tricomps) do - if i % 2 == 1 then - comporder[1][bottom] = comp - comporder[2][numtricomps - bottom + 1] = comp - bottom = bottom - 1 - else - comporder[1][top] = comp - comporder[2][numtricomps - top + 1] = comp - top = top + 1 - end - end - - local pairdata = { - pair = pair, - companchors = companchors, - edgecomps = edgecomps, - edgeindices = edgeindices, - compvertices = compvertices, - tricomps = tricomps, - twocomps = twocomps, - comporder = comporder, - } - return pairdata + local visited = {} + local companchors = {} + local edgecomps = {} + local compvertices = {} + local islinear = {} + local edgeindices = {} + + local pair = { v1, v2 } + local start = v1.link + local current = start + local edgeindex = 1 + -- start searches from v1 + repeat + edgeindices[current] = edgeindex + edgeindex = edgeindex + 1 + if not edgecomps[current] then + local compindex = #companchors + 1 + local ca, il + edgecomps[current] = compindex + compvertices[compindex] = {} + local target = current.target + if target == v2 then + edgecomps[current.twin] = compindex + ca = 3 + il = true + else + ca, il = self:component_dfs( + target, + pair, + visited, + edgecomps, + compvertices[compindex], + compindex + ) + end + companchors[compindex] = ca + islinear[compindex] = il + end + current = current.links[0] + until current == start + + if v2 then + start = v2.link + current = start + local lastincomp = true + local edgeindex = 1 + -- now find the remaining blocks at v2 + repeat + edgeindices[current] = edgeindex + edgeindex = edgeindex + 1 + if not edgecomps[current] then + local compindex = #companchors + 1 + edgecomps[current] = compindex + compvertices[compindex] = {} + self:component_dfs( + current.target, + pair, + visited, + edgecomps, + compvertices[compindex], + compindex + ) + companchors[compindex] = 2 + end + current = current.links[0] + until current == start + end + + -- init compedges, tricomps, twocomps + local tricomps = {} + local twocomps = {{}, {}} + for i, anchors in ipairs(companchors) do + if anchors == 3 then + table.insert(tricomps, i) + else + table.insert(twocomps[anchors], i) + end + end + + local flipimmune = #tricomps == 2 + and (islinear[tricomps[1]] or islinear[tricomps[2]]) + if (#tricomps < 2 or flipimmune) + and (v2 ~= nil or #twocomps[1] < 2) then + return nil + end + + -- order tri comps cyclic + local function sorter(a, b) + return #compvertices[a] < #compvertices[b] + end + + table.sort(tricomps, sorter) + + -- determine order of comps + local numtricomps = #tricomps + local comporder = { {}, {} } + local bottom = math.ceil(numtricomps / 2) + local top = bottom + 1 + for i, comp in ipairs(tricomps) do + if i % 2 == 1 then + comporder[1][bottom] = comp + comporder[2][numtricomps - bottom + 1] = comp + bottom = bottom - 1 + else + comporder[1][top] = comp + comporder[2][numtricomps - top + 1] = comp + top = top + 1 + end + end + + local pairdata = { + pair = pair, + companchors = companchors, + edgecomps = edgecomps, + edgeindices = edgeindices, + compvertices = compvertices, + tricomps = tricomps, + twocomps = twocomps, + comporder = comporder, + } + return pairdata end function E:component_dfs(v, pair, visited, edgecomps, compvertices, compindex) - visited[v] = true - local start = v.link - local current = start - local companchors = 1 - local numedges = 0 - local islinear = true - table.insert(compvertices, v) - repeat - numedges = numedges + 1 - local target = current.target - if target == pair[1] or target == pair[2] then - edgecomps[current.twin] = compindex - if target == pair[2] then - companchors = 3 - end - elseif not visited[target] then - local ca, il = self:component_dfs( - target, - pair, - visited, - edgecomps, - compvertices, - compindex - ) - if ca == 3 then - companchors = 3 - end - islinear = islinear and il - end - current = current.links[0] - until current == start - return companchors, islinear and numedges == 2 + visited[v] = true + local start = v.link + local current = start + local companchors = 1 + local numedges = 0 + local islinear = true + table.insert(compvertices, v) + repeat + numedges = numedges + 1 + local target = current.target + if target == pair[1] or target == pair[2] then + edgecomps[current.twin] = compindex + if target == pair[2] then + companchors = 3 + end + elseif not visited[target] then + local ca, il = self:component_dfs( + target, + pair, + visited, + edgecomps, + compvertices, + compindex + ) + if ca == 3 then + companchors = 3 + end + islinear = islinear and il + end + current = current.links[0] + until current == start + return companchors, islinear and numedges == 2 end function E:improve_separation_pair(pairdata) - local pair = pairdata.pair - local companchors = pairdata.companchors - local edgecomps = pairdata.edgecomps - local edgeindices = pairdata.edgeindices - local compvertices = pairdata.compvertices - local tricomps = pairdata.tricomps - local twocomps = pairdata.twocomps - local comporder = pairdata.comporder - local v1 = pair[1] - local v2 = pair[2] - - local compedges = {} - for i = 1, #companchors do - compedges[i] = {{}, {}} - end - - local numtricomps = #tricomps - local numtwocomps = { #twocomps[1], #twocomps[2] } - - -- find compedges - for i = 1, #pair do - -- first find an edge that is the first of a triconnected component - local start2 - if v2 then - start = pair[i].link - current = start - local last - repeat - local comp = edgecomps[current] - if companchors[comp] == 3 then - if last == nil then - last = comp - elseif last ~= comp then - start2 = current - break - end - end - current = current.links[0] - until current == start - else - start2 = pair[i].link - end - -- now list the edges by components - current = start2 - repeat - table.insert(compedges[edgecomps[current]][i], current) - current = current.links[0] - until current == start2 - end - - -- count edges on each side of tri comps - local edgecount = {} - for _, comp in ipairs(tricomps) do - edgecount[comp] = {} - for i = 1, #pair do - local count = 1 - local current = compedges[comp][i][1] - local other = pair[3 - i] - while current.target ~= other do - count = count + 1 - current = current.twin.links[0] - end - edgecount[comp][i] = count - end - end - - -- determine which comps have to be flipped - local flips = {} - local numflips = 0 - local allflipped = true - for i, comp in ipairs(comporder[1]) do - local side1, side2 - if i > numtricomps / 2 then - side1 = edgecount[comp][1] - side2 = edgecount[comp][2] - else - side1 = edgecount[comp][2] - side2 = edgecount[comp][1] - end - if side1 > side2 then - numflips = numflips + 1 - flips[comp] = true - elseif side1 < side2 then - allflipped = false - end - end - - if allflipped then - for i, comp in ipairs(tricomps) do - flips[comp] = false - end - else - for i, comp in ipairs(tricomps) do - if flips[comp] then - for _, v in ipairs(compvertices[comp]) do - local start = v.link - local current = start - repeat - current.links[0], current.links[1] - = current.links[1], current.links[0] - current = current.links[1] - until current == start - end - end - end - end - - -- order edges cyclic per component (one cycle for all tri comps) - for i = 1, #pair do - if v2 then - local co - if allflipped then - co = comporder[3 - i] - else - co = comporder[i] - end - - local id = co[numtricomps] - lastedges = compedges[id][i] - if flips[id] then - lastedge = lastedges[1] - else - lastedge = lastedges[#lastedges] - end - - -- tri comps - for _, id in ipairs(co) do - local edges = compedges[id][i] - local from - local to - local step - if flips[id] then - from = #edges - to = 1 - step = -1 - else - from = 1 - to = #edges - step = 1 - end - for k = from, to, step do - local edge = edges[k] - lastedge.links[0] = edge - edge.links[1] = lastedge - lastedge = edge - end - end - end - - -- two comps - for _, id in ipairs(twocomps[i]) do - lastedges = compedges[id][i] - lastedge = lastedges[#lastedges] - for _, edge in ipairs(compedges[id][i]) do - lastedge.links[0] = edge - edge.links[1] = lastedge - lastedge = edge - end - end - end - - -- now merge the cycles - for i = 1, #pair do - local outeredges = {} - -- find the biggest face of the tri comps - if v2 then - local biggestedge - local biggestsize - local biggestindex - local start = compedges[tricomps[1]][i][1] - local current = start - repeat - local size = self:get_face_size(current) - if not biggestedge or size > biggestsize - or (size == biggestsize - and edgeindices[current] > biggestindex) then - biggestedge = current - biggestsize = size - biggestindex = edgeindices[current] - end - current = current.links[0] - until current == start - outeredges[1] = biggestedge - end - - -- now for every two comp - for _, id in ipairs(twocomps[i]) do - local biggestedge - local biggestsize - local biggestindex - local start = compedges[id][i][1] - local current = start - repeat - local size = self:get_face_size(current) - if not biggestedge or size > biggestsize - or (size == biggestsize - and edgeindices[current] > biggestindex) then - biggestedge = current - biggestsize = size - biggestindex = edgeindices[current] - end - current = current.links[0] - until current == start - table.insert(outeredges, biggestedge) - end - - -- now merge all comps at the outer edges - local lastedge = outeredges[#outeredges].links[0] - for _, edge in ipairs(outeredges) do - local nextlastedge = edge.links[0] - lastedge.links[1] = edge - edge.links[0] = lastedge - lastedge = nextlastedge - end - end + local pair = pairdata.pair + local companchors = pairdata.companchors + local edgecomps = pairdata.edgecomps + local edgeindices = pairdata.edgeindices + local compvertices = pairdata.compvertices + local tricomps = pairdata.tricomps + local twocomps = pairdata.twocomps + local comporder = pairdata.comporder + local v1 = pair[1] + local v2 = pair[2] + + local compedges = {} + for i = 1, #companchors do + compedges[i] = {{}, {}} + end + + local numtricomps = #tricomps + local numtwocomps = { #twocomps[1], #twocomps[2] } + + -- find compedges + for i = 1, #pair do + -- first find an edge that is the first of a triconnected component + local start2 + if v2 then + start = pair[i].link + current = start + local last + repeat + local comp = edgecomps[current] + if companchors[comp] == 3 then + if last == nil then + last = comp + elseif last ~= comp then + start2 = current + break + end + end + current = current.links[0] + until current == start + else + start2 = pair[i].link + end + -- now list the edges by components + current = start2 + repeat + table.insert(compedges[edgecomps[current]][i], current) + current = current.links[0] + until current == start2 + end + + -- count edges on each side of tri comps + local edgecount = {} + for _, comp in ipairs(tricomps) do + edgecount[comp] = {} + for i = 1, #pair do + local count = 1 + local current = compedges[comp][i][1] + local other = pair[3 - i] + while current.target ~= other do + count = count + 1 + current = current.twin.links[0] + end + edgecount[comp][i] = count + end + end + + -- determine which comps have to be flipped + local flips = {} + local numflips = 0 + local allflipped = true + for i, comp in ipairs(comporder[1]) do + local side1, side2 + if i > numtricomps / 2 then + side1 = edgecount[comp][1] + side2 = edgecount[comp][2] + else + side1 = edgecount[comp][2] + side2 = edgecount[comp][1] + end + if side1 > side2 then + numflips = numflips + 1 + flips[comp] = true + elseif side1 < side2 then + allflipped = false + end + end + + if allflipped then + for i, comp in ipairs(tricomps) do + flips[comp] = false + end + else + for i, comp in ipairs(tricomps) do + if flips[comp] then + for _, v in ipairs(compvertices[comp]) do + local start = v.link + local current = start + repeat + current.links[0], current.links[1] + = current.links[1], current.links[0] + current = current.links[1] + until current == start + end + end + end + end + + -- order edges cyclic per component (one cycle for all tri comps) + for i = 1, #pair do + if v2 then + local co + if allflipped then + co = comporder[3 - i] + else + co = comporder[i] + end + + local id = co[numtricomps] + lastedges = compedges[id][i] + if flips[id] then + lastedge = lastedges[1] + else + lastedge = lastedges[#lastedges] + end + + -- tri comps + for _, id in ipairs(co) do + local edges = compedges[id][i] + local from + local to + local step + if flips[id] then + from = #edges + to = 1 + step = -1 + else + from = 1 + to = #edges + step = 1 + end + for k = from, to, step do + local edge = edges[k] + lastedge.links[0] = edge + edge.links[1] = lastedge + lastedge = edge + end + end + end + + -- two comps + for _, id in ipairs(twocomps[i]) do + lastedges = compedges[id][i] + lastedge = lastedges[#lastedges] + for _, edge in ipairs(compedges[id][i]) do + lastedge.links[0] = edge + edge.links[1] = lastedge + lastedge = edge + end + end + end + + -- now merge the cycles + for i = 1, #pair do + local outeredges = {} + -- find the biggest face of the tri comps + if v2 then + local biggestedge + local biggestsize + local biggestindex + local start = compedges[tricomps[1]][i][1] + local current = start + repeat + local size = self:get_face_size(current) + if not biggestedge or size > biggestsize + or (size == biggestsize + and edgeindices[current] > biggestindex) then + biggestedge = current + biggestsize = size + biggestindex = edgeindices[current] + end + current = current.links[0] + until current == start + outeredges[1] = biggestedge + end + + -- now for every two comp + for _, id in ipairs(twocomps[i]) do + local biggestedge + local biggestsize + local biggestindex + local start = compedges[id][i][1] + local current = start + repeat + local size = self:get_face_size(current) + if not biggestedge or size > biggestsize + or (size == biggestsize + and edgeindices[current] > biggestindex) then + biggestedge = current + biggestsize = size + biggestindex = edgeindices[current] + end + current = current.links[0] + until current == start + table.insert(outeredges, biggestedge) + end + + -- now merge all comps at the outer edges + local lastedge = outeredges[#outeredges].links[0] + for _, edge in ipairs(outeredges) do + local nextlastedge = edge.links[0] + lastedge.links[1] = edge + edge.links[0] = lastedge + lastedge = nextlastedge + end + end end function E:get_face_size(halfedge) - local size = 0 - local current = halfedge - repeat - size = size + 1 - current = current.twin.links[1] - until current == halfedge - return size + local size = 0 + local current = halfedge + repeat + size = size + 1 + current = current.twin.links[1] + until current == halfedge + return size end return E diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/LinkedList.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/LinkedList.lua index 99a23501858..35f8418fdf0 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/LinkedList.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/LinkedList.lua @@ -3,86 +3,86 @@ local LinkedList = {} LinkedList.__index = LinkedList function LinkedList.new() - local list = {elements = {}} - setmetatable(list, LinkedList) - return list + local list = {elements = {}} + setmetatable(list, LinkedList) + return list end function LinkedList:addback(payload) - if payload == nil then - error("Need a payload!", 2) - end - local element = { payload = payload } - if self.head then - local tail = self.head.prev - self.head.prev = element - tail.next = element - element.next = self.head - element.prev = tail - else - self.head = element - element.next = element - element.prev = element - end - self.elements[element] = true - return element + if payload == nil then + error("Need a payload!", 2) + end + local element = { payload = payload } + if self.head then + local tail = self.head.prev + self.head.prev = element + tail.next = element + element.next = self.head + element.prev = tail + else + self.head = element + element.next = element + element.prev = element + end + self.elements[element] = true + return element end function LinkedList:addfront(payload) - self.head = self:addback(payload) - return self.head + self.head = self:addback(payload) + return self.head end function LinkedList:remove(element) - if self.elements[element] == nil then - error("Element not in list!", 2) - end - if self.head == element then - if element.next == element then - self.head = nil - else - self.head = element.next - end - end - element.prev.next = element.next - element.next.prev = element.prev - self.elements[element] = nil + if self.elements[element] == nil then + error("Element not in list!", 2) + end + if self.head == element then + if element.next == element then + self.head = nil + else + self.head = element.next + end + end + element.prev.next = element.next + element.next.prev = element.prev + self.elements[element] = nil end function LinkedList:popfirst() - if self.head == nil then - return nil - end - local element = self.head - if element.next == element then - self.head = nil - else - self.head = element.next - element.next.prev = element.prev - element.prev.next = element.next - end - self.elements[element] = nil - return element.payload + if self.head == nil then + return nil + end + local element = self.head + if element.next == element then + self.head = nil + else + self.head = element.next + element.next.prev = element.prev + element.prev.next = element.next + end + self.elements[element] = nil + return element.payload end function LinkedList:poplast() - if self.head == nil then - return nil - end - self.head = self.head.prev - return self:popfirst() + if self.head == nil then + return nil + end + self.head = self.head.prev + return self:popfirst() end function LinkedList:first() - return self.head and self.head.payload + return self.head and self.head.payload end function LinkedList:last() - return self.head and self.head.prev.payload + return self.head and self.head.prev.payload end function LinkedList:empty() - return self.head == nil + return self.head == nil end return LinkedList diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/List.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/List.lua index 564216a8c37..22a91e65710 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/List.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/List.lua @@ -3,47 +3,47 @@ local List = {} List.__index = List function List.new() - local t = {first = 0, last = -1} - setmetatable(t, List) - return t + local t = {first = 0, last = -1} + setmetatable(t, List) + return t end function List:pushleft(value) - local first = self.first - 1 - self.first = first - self[first] = value + local first = self.first - 1 + self.first = first + self[first] = value end function List:pushright(value) - local last = self.last + 1 - self.last = last - self[last] = value + local last = self.last + 1 + self.last = last + self[last] = value end function List:popleft() - local first = self.first - if first > self.last then error("List is empty") end - local value = self[first] - self[first] = nil - self.first = first + 1 - return value + local first = self.first + if first > self.last then error("List is empty") end + local value = self[first] + self[first] = nil + self.first = first + 1 + return value end function List:popright() - local last = self.last - if self.first > last then error("List is empty") end - local value = self[last] - self[last] = nil - self.last = last - 1 - return value + local last = self.last + if self.first > last then error("List is empty") end + local value = self[last] + self[last] = nil + self.last = last - 1 + return value end function List:size() - return self.last - self.first + 1 + return self.last - self.first + 1 end function List:empty() - return self.last < self.first + return self.last < self.first end return List diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PDP.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PDP.lua index fbf94a52502..8c159cf61dc 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PDP.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PDP.lua @@ -11,564 +11,564 @@ local Path = require "pgf.gd.model.Path" PDP.__index = PDP function PDP.new(ugraph, embedding, - delta, gamma, coolingfactor, - expiterations, - startrepexp, endrepexp, - startattexp, endattexp, - appthreshold, stretchthreshold, - stresscounterthreshold, - numdivisions) - local t = { - ugraph = ugraph, - embedding = embedding, - delta = delta , - gamma = gamma, - coolingfactor = coolingfactor, - expiterations = expiterations, - startrepexp = startrepexp, - endrepexp = endrepexp, - startattexp = startattexp, - endattexp = endattexp, - appthreshold = appthreshold, - stretchthreshold = stretchthreshold, - stresscounterthreshold = stresscounterthreshold, - numdivisions = numdivisions, - posxs = {}, - posys = {}, - cvsxs = {}, - cvsys = {}, - embeddingedges = {}, - edgeids = {}, - numedgeids = 0, - vertexids = {}, - numvertexids = 0, - vertexpairs1 = {}, - vertexpairs2 = {}, - pairconnected = {}, - edgepairsvertex = {}, - edgepairsedge = {}, - edgevertex1 = {}, - edgevertex2 = {}, - edgedeprecated = {}, - subdivisionedges = {}, - subdivisionvertices = {}, - temperature = 1, - } - - setmetatable(t, PDP) - return t + delta, gamma, coolingfactor, + expiterations, + startrepexp, endrepexp, + startattexp, endattexp, + appthreshold, stretchthreshold, + stresscounterthreshold, + numdivisions) + local t = { + ugraph = ugraph, + embedding = embedding, + delta = delta , + gamma = gamma, + coolingfactor = coolingfactor, + expiterations = expiterations, + startrepexp = startrepexp, + endrepexp = endrepexp, + startattexp = startattexp, + endattexp = endattexp, + appthreshold = appthreshold, + stretchthreshold = stretchthreshold, + stresscounterthreshold = stresscounterthreshold, + numdivisions = numdivisions, + posxs = {}, + posys = {}, + cvsxs = {}, + cvsys = {}, + embeddingedges = {}, + edgeids = {}, + numedgeids = 0, + vertexids = {}, + numvertexids = 0, + vertexpairs1 = {}, + vertexpairs2 = {}, + pairconnected = {}, + edgepairsvertex = {}, + edgepairsedge = {}, + edgevertex1 = {}, + edgevertex2 = {}, + edgedeprecated = {}, + subdivisionedges = {}, + subdivisionvertices = {}, + temperature = 1, + } + + setmetatable(t, PDP) + return t end function PDP:run() - self:normalize_size() - self:find_force_pairs() - - local delta = self.delta - local gamma = self.gamma - local coolingfactor = self.coolingfactor - local expiterations = self.expiterations - local startrepexp = self.startrepexp - local endattexp = self.endattexp - local startattexp = self.startattexp - local endrepexp = self.endrepexp - - local vertexpairs1 = self.vertexpairs1 - local vertexpairs2 = self.vertexpairs2 - local pairconnected = self.pairconnected - local edgepairsvertex = self.edgepairsvertex - local edgepairsedge = self.edgepairsedge - local edgevertex1 = self.edgevertex1 - local edgevertex2 = self.edgevertex2 - local edgedeprecated = self.edgedeprecated - - local forcexs = {} - local forceys = {} - local posxs = self.posxs - local posys = self.posys - local cvsxs = self.cvsxs - local cvsys = self.cvsys - local numcvs = {} - for i, v in ipairs(self.embedding.vertices) do - cvsxs[i] = {} - cvsys[i] = {} - posxs[i] = v.inputvertex.pos.x - posys[i] = v.inputvertex.pos.y - end - - local numorigvertices = self.numvertexids - local numorigedges = self.numedgeids - local numdivisions = self.numdivisions - local divdelta = delta / (numdivisions + 1) - local stresscounter = {} - for i = 1, self.numedgeids do - stresscounter[i] = 0 - end - - local appthreshold = self.appthreshold - local stretchthreshold = self.stretchthreshold - local stresscounterthreshold = self.stresscounterthreshold - - for i = 1, numorigedges do - local iv1 = self.embedding.vertices[edgevertex1[i]].inputvertex - local iv2 = self.embedding.vertices[edgevertex2[i]].inputvertex - local arc = self.ugraph:arc(iv1, iv2) - --TODO subdivide edge if desired - --self:subdivide_edge(i) - end - - -- main loop - local iteration = 0 - repeat - iteration = iteration + 1 - local temperature = self.temperature - local ratio = math.min(1, iteration / expiterations) - local repexp = startrepexp + (endrepexp - startrepexp) * ratio - local attexp = startattexp + (endattexp - startattexp) * ratio - for i = 1, self.numvertexids do - forcexs[i] = 0 - forceys[i] = 0 - numcvs[i] = 0 - end - -- vertex-vertex forces - for i = 1, #vertexpairs1 do - local id1 = vertexpairs1[i] - local id2 = vertexpairs2[i] - local diffx = posxs[id2] - posxs[id1] - local diffy = posys[id2] - posys[id1] - local dist2 = diffx * diffx + diffy * diffy - local dist = math.sqrt(dist2) - local dirx = diffx / dist - local diry = diffy / dist - assert(dist ~= 0) - - local useddelta = delta - local hasdivvertex = id1 > numorigvertices or id2 > numorigvertices - - -- calculate attractive force - if pairconnected[i] then - if hasdivvertex then - useddelta = divdelta - end - local mag = (dist / useddelta) ^ attexp * useddelta - local fax = mag * dirx - local fay = mag * diry - forcexs[id1] = forcexs[id1] + fax - forceys[id1] = forceys[id1] + fay - forcexs[id2] = forcexs[id2] - fax - forceys[id2] = forceys[id2] - fay - elseif hasdivvertex then - useddelta = gamma - end - - -- calculate repulsive force - local mag = (useddelta / dist) ^ repexp * useddelta - local frx = mag * dirx - local fry = mag * diry - forcexs[id1] = forcexs[id1] - frx - forceys[id1] = forceys[id1] - fry - forcexs[id2] = forcexs[id2] + frx - forceys[id2] = forceys[id2] + fry - end - - -- edge-vertex forces and collisions - for i = 1, #edgepairsvertex do - local edgeid = edgepairsedge[i] - if not edgedeprecated[edgeid] then - local id1 = edgepairsvertex[i] - local id2 = edgevertex1[edgeid] - local id3 = edgevertex2[edgeid] - assert(id2 ~= id1 and id3 ~= id1) - - local abx = posxs[id3] - posxs[id2] - local aby = posys[id3] - posys[id2] - local dab2 = abx * abx + aby * aby - local dab = math.sqrt(dab2) - assert(dab ~= 0) - local abnx = abx / dab - local abny = aby / dab - local avx = posxs[id1] - posxs[id2] - local avy = posys[id1] - posys[id2] - local daiv = abnx * avx + abny * avy - local ivx = posxs[id2] + abnx * daiv - local ivy = posys[id2] + abny * daiv - local vivx = ivx - posxs[id1] - local vivy = ivy - posys[id1] - local dviv2 = vivx * vivx + vivy * vivy - local dviv = math.sqrt(dviv2) - local afactor, bfactor = 1, 1 - local cvx - local cvy - if daiv < 0 then - cvx = -avx / 2 - cvy = -avy / 2 - local norm2 = cvx * cvx + cvy * cvy - bfactor = 1 + (cvx * abx + cvy * aby) / norm2 - elseif daiv > dab then - cvx = (abx - avx) / 2 - cvy = (aby - avy) / 2 - local norm2 = cvx * cvx + cvy * cvy - afactor = 1 - (cvx * abx + cvy * aby) / norm2 - else - if edgeid < numorigedges - and dviv < gamma * appthreshold - and dab > delta * stretchthreshold then - stresscounter[edgeid] = stresscounter[edgeid] + 1 - end - assert(dviv > 0) - cvx = vivx / 2 - cvy = vivy / 2 - -- calculate edge repulsive force - local dirx = -vivx / dviv - local diry = -vivy / dviv - local mag = (gamma / dviv) ^ repexp * gamma - local fex = mag * dirx - local fey = mag * diry - local abratio = daiv / dab - forcexs[id1] = forcexs[id1] + fex - forceys[id1] = forceys[id1] + fey - forcexs[id2] = forcexs[id2] - fex * (1 - abratio) - forceys[id2] = forceys[id2] - fey * (1 - abratio) - forcexs[id3] = forcexs[id3] - fex * abratio - forceys[id3] = forceys[id3] - fey * abratio - end - local nv = numcvs[id1] + 1 - local na = numcvs[id2] + 1 - local nb = numcvs[id3] + 1 - numcvs[id1] = nv - numcvs[id2] = na - numcvs[id3] = nb - cvsxs[id1][nv] = cvx - cvsys[id1][nv] = cvy - cvsxs[id2][na] = -cvx * afactor - cvsys[id2][na] = -cvy * afactor - cvsxs[id3][nb] = -cvx * bfactor - cvsys[id3][nb] = -cvy * bfactor - end - end - - -- clamp forces - local scalefactor = 1 - local collision = false - for i = 1, self.numvertexids do - local forcex = forcexs[i] - local forcey = forceys[i] - forcex = forcex * temperature - forcey = forcey * temperature - forcexs[i] = forcex - forceys[i] = forcey - local forcenorm2 = forcex * forcex + forcey * forcey - local forcenorm = math.sqrt(forcenorm2) - scalefactor = math.min(scalefactor, delta * 3 * temperature / forcenorm) - local cvys = cvsys[i] - for j, cvx in ipairs(cvsxs[i]) do - local cvy = cvys[j] - local cvnorm2 = cvx * cvx + cvy * cvy - local cvnorm = math.sqrt(cvnorm2) - local projforcenorm = (cvx * forcex + cvy * forcey) / cvnorm - if projforcenorm > 0 then - local factor = cvnorm * 0.9 / projforcenorm - if factor < scalefactor then - scalefactor = factor - collision = true - end - end - end - end - local moved = false - for i = 1, self.numvertexids do - local forcex = forcexs[i] * scalefactor - local forcey = forceys[i] * scalefactor - posxs[i] = posxs[i] + forcex - posys[i] = posys[i] + forcey - local forcenorm2 = forcex * forcex + forcey * forcey - if forcenorm2 > 0.0001 * delta * delta then moved = true end - end - - -- subdivide stressed edges - if numdivisions > 0 then - for i = 1, numorigedges do - if stresscounter[i] > stresscounterthreshold then - self:subdivide_edge(i) - stresscounter[i] = 0 - end - end - end - self.temperature = self.temperature * coolingfactor - until not collision and not moved - print("\nfinished PDP after " .. iteration .. " iterations") - - -- write the positions back - for i, v in ipairs(self.embedding.vertices) do - v.inputvertex.pos.x = posxs[i] - v.inputvertex.pos.y = posys[i] - end - - -- route the edges - for i = 1, self.numedgeids do - if self.subdivisionvertices[i] then - local iv1 = self.embedding.vertices[self.edgevertex1[i]].inputvertex - local iv2 = self.embedding.vertices[self.edgevertex2[i]].inputvertex - local arc = self.ugraph:arc(iv1, iv2) - local p = Path.new() - p:appendMoveto(arc.tail.pos:clone()) - for _, vid in ipairs(self.subdivisionvertices[i]) do - p:appendLineto(self.posxs[vid], self.posys[vid]) - end - p:appendLineto(arc.head.pos:clone()) - arc.path = p - end - end + self:normalize_size() + self:find_force_pairs() + + local delta = self.delta + local gamma = self.gamma + local coolingfactor = self.coolingfactor + local expiterations = self.expiterations + local startrepexp = self.startrepexp + local endattexp = self.endattexp + local startattexp = self.startattexp + local endrepexp = self.endrepexp + + local vertexpairs1 = self.vertexpairs1 + local vertexpairs2 = self.vertexpairs2 + local pairconnected = self.pairconnected + local edgepairsvertex = self.edgepairsvertex + local edgepairsedge = self.edgepairsedge + local edgevertex1 = self.edgevertex1 + local edgevertex2 = self.edgevertex2 + local edgedeprecated = self.edgedeprecated + + local forcexs = {} + local forceys = {} + local posxs = self.posxs + local posys = self.posys + local cvsxs = self.cvsxs + local cvsys = self.cvsys + local numcvs = {} + for i, v in ipairs(self.embedding.vertices) do + cvsxs[i] = {} + cvsys[i] = {} + posxs[i] = v.inputvertex.pos.x + posys[i] = v.inputvertex.pos.y + end + + local numorigvertices = self.numvertexids + local numorigedges = self.numedgeids + local numdivisions = self.numdivisions + local divdelta = delta / (numdivisions + 1) + local stresscounter = {} + for i = 1, self.numedgeids do + stresscounter[i] = 0 + end + + local appthreshold = self.appthreshold + local stretchthreshold = self.stretchthreshold + local stresscounterthreshold = self.stresscounterthreshold + + for i = 1, numorigedges do + local iv1 = self.embedding.vertices[edgevertex1[i]].inputvertex + local iv2 = self.embedding.vertices[edgevertex2[i]].inputvertex + local arc = self.ugraph:arc(iv1, iv2) + --TODO subdivide edge if desired + --self:subdivide_edge(i) + end + + -- main loop + local iteration = 0 + repeat + iteration = iteration + 1 + local temperature = self.temperature + local ratio = math.min(1, iteration / expiterations) + local repexp = startrepexp + (endrepexp - startrepexp) * ratio + local attexp = startattexp + (endattexp - startattexp) * ratio + for i = 1, self.numvertexids do + forcexs[i] = 0 + forceys[i] = 0 + numcvs[i] = 0 + end + -- vertex-vertex forces + for i = 1, #vertexpairs1 do + local id1 = vertexpairs1[i] + local id2 = vertexpairs2[i] + local diffx = posxs[id2] - posxs[id1] + local diffy = posys[id2] - posys[id1] + local dist2 = diffx * diffx + diffy * diffy + local dist = math.sqrt(dist2) + local dirx = diffx / dist + local diry = diffy / dist + assert(dist ~= 0) + + local useddelta = delta + local hasdivvertex = id1 > numorigvertices or id2 > numorigvertices + + -- calculate attractive force + if pairconnected[i] then + if hasdivvertex then + useddelta = divdelta + end + local mag = (dist / useddelta) ^ attexp * useddelta + local fax = mag * dirx + local fay = mag * diry + forcexs[id1] = forcexs[id1] + fax + forceys[id1] = forceys[id1] + fay + forcexs[id2] = forcexs[id2] - fax + forceys[id2] = forceys[id2] - fay + elseif hasdivvertex then + useddelta = gamma + end + + -- calculate repulsive force + local mag = (useddelta / dist) ^ repexp * useddelta + local frx = mag * dirx + local fry = mag * diry + forcexs[id1] = forcexs[id1] - frx + forceys[id1] = forceys[id1] - fry + forcexs[id2] = forcexs[id2] + frx + forceys[id2] = forceys[id2] + fry + end + + -- edge-vertex forces and collisions + for i = 1, #edgepairsvertex do + local edgeid = edgepairsedge[i] + if not edgedeprecated[edgeid] then + local id1 = edgepairsvertex[i] + local id2 = edgevertex1[edgeid] + local id3 = edgevertex2[edgeid] + assert(id2 ~= id1 and id3 ~= id1) + + local abx = posxs[id3] - posxs[id2] + local aby = posys[id3] - posys[id2] + local dab2 = abx * abx + aby * aby + local dab = math.sqrt(dab2) + assert(dab ~= 0) + local abnx = abx / dab + local abny = aby / dab + local avx = posxs[id1] - posxs[id2] + local avy = posys[id1] - posys[id2] + local daiv = abnx * avx + abny * avy + local ivx = posxs[id2] + abnx * daiv + local ivy = posys[id2] + abny * daiv + local vivx = ivx - posxs[id1] + local vivy = ivy - posys[id1] + local dviv2 = vivx * vivx + vivy * vivy + local dviv = math.sqrt(dviv2) + local afactor, bfactor = 1, 1 + local cvx + local cvy + if daiv < 0 then + cvx = -avx / 2 + cvy = -avy / 2 + local norm2 = cvx * cvx + cvy * cvy + bfactor = 1 + (cvx * abx + cvy * aby) / norm2 + elseif daiv > dab then + cvx = (abx - avx) / 2 + cvy = (aby - avy) / 2 + local norm2 = cvx * cvx + cvy * cvy + afactor = 1 - (cvx * abx + cvy * aby) / norm2 + else + if edgeid < numorigedges + and dviv < gamma * appthreshold + and dab > delta * stretchthreshold then + stresscounter[edgeid] = stresscounter[edgeid] + 1 + end + assert(dviv > 0) + cvx = vivx / 2 + cvy = vivy / 2 + -- calculate edge repulsive force + local dirx = -vivx / dviv + local diry = -vivy / dviv + local mag = (gamma / dviv) ^ repexp * gamma + local fex = mag * dirx + local fey = mag * diry + local abratio = daiv / dab + forcexs[id1] = forcexs[id1] + fex + forceys[id1] = forceys[id1] + fey + forcexs[id2] = forcexs[id2] - fex * (1 - abratio) + forceys[id2] = forceys[id2] - fey * (1 - abratio) + forcexs[id3] = forcexs[id3] - fex * abratio + forceys[id3] = forceys[id3] - fey * abratio + end + local nv = numcvs[id1] + 1 + local na = numcvs[id2] + 1 + local nb = numcvs[id3] + 1 + numcvs[id1] = nv + numcvs[id2] = na + numcvs[id3] = nb + cvsxs[id1][nv] = cvx + cvsys[id1][nv] = cvy + cvsxs[id2][na] = -cvx * afactor + cvsys[id2][na] = -cvy * afactor + cvsxs[id3][nb] = -cvx * bfactor + cvsys[id3][nb] = -cvy * bfactor + end + end + + -- clamp forces + local scalefactor = 1 + local collision = false + for i = 1, self.numvertexids do + local forcex = forcexs[i] + local forcey = forceys[i] + forcex = forcex * temperature + forcey = forcey * temperature + forcexs[i] = forcex + forceys[i] = forcey + local forcenorm2 = forcex * forcex + forcey * forcey + local forcenorm = math.sqrt(forcenorm2) + scalefactor = math.min(scalefactor, delta * 3 * temperature / forcenorm) + local cvys = cvsys[i] + for j, cvx in ipairs(cvsxs[i]) do + local cvy = cvys[j] + local cvnorm2 = cvx * cvx + cvy * cvy + local cvnorm = math.sqrt(cvnorm2) + local projforcenorm = (cvx * forcex + cvy * forcey) / cvnorm + if projforcenorm > 0 then + local factor = cvnorm * 0.9 / projforcenorm + if factor < scalefactor then + scalefactor = factor + collision = true + end + end + end + end + local moved = false + for i = 1, self.numvertexids do + local forcex = forcexs[i] * scalefactor + local forcey = forceys[i] * scalefactor + posxs[i] = posxs[i] + forcex + posys[i] = posys[i] + forcey + local forcenorm2 = forcex * forcex + forcey * forcey + if forcenorm2 > 0.0001 * delta * delta then moved = true end + end + + -- subdivide stressed edges + if numdivisions > 0 then + for i = 1, numorigedges do + if stresscounter[i] > stresscounterthreshold then + self:subdivide_edge(i) + stresscounter[i] = 0 + end + end + end + self.temperature = self.temperature * coolingfactor + until not collision and not moved + print("\nfinished PDP after " .. iteration .. " iterations") + + -- write the positions back + for i, v in ipairs(self.embedding.vertices) do + v.inputvertex.pos.x = posxs[i] + v.inputvertex.pos.y = posys[i] + end + + -- route the edges + for i = 1, self.numedgeids do + if self.subdivisionvertices[i] then + local iv1 = self.embedding.vertices[self.edgevertex1[i]].inputvertex + local iv2 = self.embedding.vertices[self.edgevertex2[i]].inputvertex + local arc = self.ugraph:arc(iv1, iv2) + local p = Path.new() + p:appendMoveto(arc.tail.pos:clone()) + for _, vid in ipairs(self.subdivisionvertices[i]) do + p:appendLineto(self.posxs[vid], self.posys[vid]) + end + p:appendLineto(arc.head.pos:clone()) + arc.path = p + end + end end function PDP:subdivide_edge(edgeid) - assert(self.subdivisionedges[edgeid] == nil) - local numdivisions = self.numdivisions - local subdivisionedges = {} - local subdivisionvertices = {} - local id1 = self.edgevertex1[edgeid] - local id2 = self.edgevertex2[edgeid] - local x1 = self.posxs[id1] - local y1 = self.posys[id1] - local x2 = self.posxs[id2] - local y2 = self.posys[id2] - local prevvertexid = id1 - for i = 1, numdivisions do - -- create new edge and vertex - local newvertexid1 = self.numvertexids + i - table.insert(subdivisionvertices, newvertexid1) - self.posxs[newvertexid1] = (x1 * (numdivisions + 1 - i) + x2 * i) - / (numdivisions + 1) - self.posys[newvertexid1] = (y1 * (numdivisions + 1 - i) + y2 * i) - / (numdivisions + 1) - self.cvsxs[newvertexid1] = {} - self.cvsys[newvertexid1] = {} - - local newedgeid = self.numedgeids + i - table.insert(subdivisionedges, newedgeid) - table.insert(self.edgevertex1, prevvertexid) - table.insert(self.edgevertex2, newvertexid1) - prevvertexid = newvertexid1 - - -- pair the new vertex - -- with first vertex of the edge being devided - table.insert(self.vertexpairs1, self.edgevertex1[edgeid]) - table.insert(self.vertexpairs2, newvertexid1) - table.insert(self.pairconnected, i == 1) - - -- with second vertex of the edge being devided - table.insert(self.vertexpairs1, self.edgevertex2[edgeid]) - table.insert(self.vertexpairs2, newvertexid1) - table.insert(self.pairconnected, i == numdivisions) - - -- with each other - for j = i + 1, numdivisions do - local newvertexid2 = self.numvertexids + j - table.insert(self.vertexpairs1, newvertexid1) - table.insert(self.vertexpairs2, newvertexid2) - table.insert(self.pairconnected, j == i + 1) - end - - -- with new edges - -- before vertex - for j = 1, i - 1 do - local newedgeid = self.numedgeids + j - table.insert(self.edgepairsvertex, newvertexid1) - table.insert(self.edgepairsedge, newedgeid) - end - -- after vertex - for j = i + 2, numdivisions + 1 do - local newedgeid = self.numedgeids + j - table.insert(self.edgepairsvertex, newvertexid1) - table.insert(self.edgepairsedge, newedgeid) - end - - -- pair the new edges with vertices of the edge being devided - if i > 1 then - table.insert(self.edgepairsvertex, id1) - table.insert(self.edgepairsedge, newedgeid) - end - table.insert(self.edgepairsvertex, id2) - table.insert(self.edgepairsedge, newedgeid) - end - -- create last edge - table.insert(subdivisionedges, self.numedgeids + numdivisions + 1) - table.insert(self.edgevertex1, prevvertexid) - table.insert(self.edgevertex2, id2) - - -- pair last edge with first vertex of the edge being devided - table.insert(self.edgepairsvertex, id1) - table.insert(self.edgepairsedge, self.numedgeids + numdivisions + 1) - - self.subdivisionedges[edgeid] = subdivisionedges - self.subdivisionvertices[edgeid] = subdivisionvertices - - -- pair new edges and vertices with existing edges and vertices - local sameface = false - local start = self.embeddingedges[edgeid] - local twin = start.twin - local donevertices = { [start.target] = true, [twin.target] = true } - local doneedges = { [start] = true, [twin] = true } - local current = start.twin.links[1] - for twice = 1, 2 do - while current ~= start do - if current == twin then - sameface = true - end - - -- pair edge with the new vertices - -- or pair subdivision of edge with new vertices and edges - if not doneedges[current] then - local currentedgeid = self.edgeids[current] - if self.subdivisionvertices[currentedgeid] then - for _, vid in ipairs(self.subdivisionvertices[currentedgeid]) do - for i = 1, numdivisions do - local newvertexid = self.numvertexids + i - table.insert(self.vertexpairs1, vid) - table.insert(self.vertexpairs2, newvertexid) - self.pairconnected[#self.vertexpairs1] = false - end - for i = 1, numdivisions + 1 do - local newedgeid = self.numedgeids + i - table.insert(self.edgepairsvertex, vid) - table.insert(self.edgepairsedge, newedgeid) - end - end - for _, eid in ipairs(self.subdivisionedges[currentedgeid]) do - for i = 1, numdivisions do - local newvertexid = self.numvertexids + i - table.insert(self.edgepairsvertex, newvertexid) - table.insert(self.edgepairsedge, eid) - end - end - else - for i = 1, numdivisions do - local newvertexid = self.numvertexids + i - table.insert(self.edgepairsvertex, newvertexid) - table.insert(self.edgepairsedge, currentedgeid) - end - end - doneedges[current] = true - end - - -- pair target vertex with the new vertices and edges - local vertexid = self.vertexids[current.target] - if not donevertices[current.target] then - for i = 1, numdivisions do - local newvertexid = self.numvertexids + i - table.insert(self.vertexpairs1, vertexid) - table.insert(self.vertexpairs2, newvertexid) - self.pairconnected[#self.vertexpairs1] = false - end - for i = 1, numdivisions + 1 do - local newedgeid = self.numedgeids + i - table.insert(self.edgepairsvertex, vertexid) - table.insert(self.edgepairsedge, newedgeid) - end - end - current = current.twin.links[1] - end - start = self.embeddingedges[edgeid].twin - current = start.twin.links[1] - if sameface then - break - end - end - - self.edgedeprecated[edgeid] = true - self.numvertexids = self.numvertexids + numdivisions - self.numedgeids = self.numedgeids + numdivisions + 1 + assert(self.subdivisionedges[edgeid] == nil) + local numdivisions = self.numdivisions + local subdivisionedges = {} + local subdivisionvertices = {} + local id1 = self.edgevertex1[edgeid] + local id2 = self.edgevertex2[edgeid] + local x1 = self.posxs[id1] + local y1 = self.posys[id1] + local x2 = self.posxs[id2] + local y2 = self.posys[id2] + local prevvertexid = id1 + for i = 1, numdivisions do + -- create new edge and vertex + local newvertexid1 = self.numvertexids + i + table.insert(subdivisionvertices, newvertexid1) + self.posxs[newvertexid1] = (x1 * (numdivisions + 1 - i) + x2 * i) + / (numdivisions + 1) + self.posys[newvertexid1] = (y1 * (numdivisions + 1 - i) + y2 * i) + / (numdivisions + 1) + self.cvsxs[newvertexid1] = {} + self.cvsys[newvertexid1] = {} + + local newedgeid = self.numedgeids + i + table.insert(subdivisionedges, newedgeid) + table.insert(self.edgevertex1, prevvertexid) + table.insert(self.edgevertex2, newvertexid1) + prevvertexid = newvertexid1 + + -- pair the new vertex + -- with first vertex of the edge being divided + table.insert(self.vertexpairs1, self.edgevertex1[edgeid]) + table.insert(self.vertexpairs2, newvertexid1) + table.insert(self.pairconnected, i == 1) + + -- with second vertex of the edge being divided + table.insert(self.vertexpairs1, self.edgevertex2[edgeid]) + table.insert(self.vertexpairs2, newvertexid1) + table.insert(self.pairconnected, i == numdivisions) + + -- with each other + for j = i + 1, numdivisions do + local newvertexid2 = self.numvertexids + j + table.insert(self.vertexpairs1, newvertexid1) + table.insert(self.vertexpairs2, newvertexid2) + table.insert(self.pairconnected, j == i + 1) + end + + -- with new edges + -- before vertex + for j = 1, i - 1 do + local newedgeid = self.numedgeids + j + table.insert(self.edgepairsvertex, newvertexid1) + table.insert(self.edgepairsedge, newedgeid) + end + -- after vertex + for j = i + 2, numdivisions + 1 do + local newedgeid = self.numedgeids + j + table.insert(self.edgepairsvertex, newvertexid1) + table.insert(self.edgepairsedge, newedgeid) + end + + -- pair the new edges with vertices of the edge being divided + if i > 1 then + table.insert(self.edgepairsvertex, id1) + table.insert(self.edgepairsedge, newedgeid) + end + table.insert(self.edgepairsvertex, id2) + table.insert(self.edgepairsedge, newedgeid) + end + -- create last edge + table.insert(subdivisionedges, self.numedgeids + numdivisions + 1) + table.insert(self.edgevertex1, prevvertexid) + table.insert(self.edgevertex2, id2) + + -- pair last edge with first vertex of the edge being divided + table.insert(self.edgepairsvertex, id1) + table.insert(self.edgepairsedge, self.numedgeids + numdivisions + 1) + + self.subdivisionedges[edgeid] = subdivisionedges + self.subdivisionvertices[edgeid] = subdivisionvertices + + -- pair new edges and vertices with existing edges and vertices + local sameface = false + local start = self.embeddingedges[edgeid] + local twin = start.twin + local donevertices = { [start.target] = true, [twin.target] = true } + local doneedges = { [start] = true, [twin] = true } + local current = start.twin.links[1] + for twice = 1, 2 do + while current ~= start do + if current == twin then + sameface = true + end + + -- pair edge with the new vertices + -- or pair subdivision of edge with new vertices and edges + if not doneedges[current] then + local currentedgeid = self.edgeids[current] + if self.subdivisionvertices[currentedgeid] then + for _, vid in ipairs(self.subdivisionvertices[currentedgeid]) do + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.vertexpairs1, vid) + table.insert(self.vertexpairs2, newvertexid) + self.pairconnected[#self.vertexpairs1] = false + end + for i = 1, numdivisions + 1 do + local newedgeid = self.numedgeids + i + table.insert(self.edgepairsvertex, vid) + table.insert(self.edgepairsedge, newedgeid) + end + end + for _, eid in ipairs(self.subdivisionedges[currentedgeid]) do + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.edgepairsvertex, newvertexid) + table.insert(self.edgepairsedge, eid) + end + end + else + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.edgepairsvertex, newvertexid) + table.insert(self.edgepairsedge, currentedgeid) + end + end + doneedges[current] = true + end + + -- pair target vertex with the new vertices and edges + local vertexid = self.vertexids[current.target] + if not donevertices[current.target] then + for i = 1, numdivisions do + local newvertexid = self.numvertexids + i + table.insert(self.vertexpairs1, vertexid) + table.insert(self.vertexpairs2, newvertexid) + self.pairconnected[#self.vertexpairs1] = false + end + for i = 1, numdivisions + 1 do + local newedgeid = self.numedgeids + i + table.insert(self.edgepairsvertex, vertexid) + table.insert(self.edgepairsedge, newedgeid) + end + end + current = current.twin.links[1] + end + start = self.embeddingedges[edgeid].twin + current = start.twin.links[1] + if sameface then + break + end + end + + self.edgedeprecated[edgeid] = true + self.numvertexids = self.numvertexids + numdivisions + self.numedgeids = self.numedgeids + numdivisions + 1 end function PDP:find_force_pairs() - local donevertices = {} - -- number all vertices - local vertexids = self.vertexids - for i, v in ipairs(self.embedding.vertices) do - vertexids[v] = i - end - self.numvertexids = #self.embedding.vertices - - local edgeids = self.edgeids - local numedgeids = 0 - -- number all edges - for _, v in ipairs(self.embedding.vertices) do - local id = vertexids[v] - local start = v.link - local current = start - repeat - local targetid = vertexids[current.target] - if edgeids[current] == nil then - table.insert(self.edgevertex1, id) - table.insert(self.edgevertex2, targetid) - numedgeids = numedgeids + 1 - edgeids[current] = numedgeids - edgeids[current.twin] = numedgeids - self.embeddingedges[numedgeids] = current - end - current = current.links[0] - until current == start - end - - -- find all force pairs - for _, v in ipairs(self.embedding.vertices) do - local id = vertexids[v] - donevertices[id] = true - local vertexset = {} - local edgeset = {} - local start = v.link - repeat - local targetid = vertexids[start.target] - if vertexset[targetid] == nil and not donevertices[targetid] then - table.insert(self.pairconnected, true) - table.insert(self.vertexpairs1, id) - table.insert(self.vertexpairs2, targetid) - vertexset[targetid] = true - end - local current = start.twin.links[1] - while current.target ~= v do - local targetid = vertexids[current.target] - if vertexset[targetid] == nil and not donevertices[targetid] then - table.insert(self.pairconnected, self.ugraph:arc(v.inputvertex, current.target.inputvertex) ~= nil) - table.insert(self.vertexpairs1, id) - table.insert(self.vertexpairs2, targetid) - vertexset[targetid] = true - end - if edgeset[current] == nil then - table.insert(self.edgepairsvertex, id) - table.insert(self.edgepairsedge, edgeids[current]) - edgeset[current] = true - edgeset[current.twin] = true - end - current = current.twin.links[1] - end - start = start.links[0] - until start == v.link - end - - self.numedgeids = numedgeids + local donevertices = {} + -- number all vertices + local vertexids = self.vertexids + for i, v in ipairs(self.embedding.vertices) do + vertexids[v] = i + end + self.numvertexids = #self.embedding.vertices + + local edgeids = self.edgeids + local numedgeids = 0 + -- number all edges + for _, v in ipairs(self.embedding.vertices) do + local id = vertexids[v] + local start = v.link + local current = start + repeat + local targetid = vertexids[current.target] + if edgeids[current] == nil then + table.insert(self.edgevertex1, id) + table.insert(self.edgevertex2, targetid) + numedgeids = numedgeids + 1 + edgeids[current] = numedgeids + edgeids[current.twin] = numedgeids + self.embeddingedges[numedgeids] = current + end + current = current.links[0] + until current == start + end + + -- find all force pairs + for _, v in ipairs(self.embedding.vertices) do + local id = vertexids[v] + donevertices[id] = true + local vertexset = {} + local edgeset = {} + local start = v.link + repeat + local targetid = vertexids[start.target] + if vertexset[targetid] == nil and not donevertices[targetid] then + table.insert(self.pairconnected, true) + table.insert(self.vertexpairs1, id) + table.insert(self.vertexpairs2, targetid) + vertexset[targetid] = true + end + local current = start.twin.links[1] + while current.target ~= v do + local targetid = vertexids[current.target] + if vertexset[targetid] == nil and not donevertices[targetid] then + table.insert(self.pairconnected, self.ugraph:arc(v.inputvertex, current.target.inputvertex) ~= nil) + table.insert(self.vertexpairs1, id) + table.insert(self.vertexpairs2, targetid) + vertexset[targetid] = true + end + if edgeset[current] == nil then + table.insert(self.edgepairsvertex, id) + table.insert(self.edgepairsedge, edgeids[current]) + edgeset[current] = true + edgeset[current.twin] = true + end + current = current.twin.links[1] + end + start = start.links[0] + until start == v.link + end + + self.numedgeids = numedgeids end function PDP:normalize_size() - local minx = math.huge - local maxx = -math.huge - local miny = math.huge - local maxy = -math.huge - - for _, v in ipairs(self.ugraph.vertices) do - minx = math.min(minx, v.pos.x) - maxx = math.max(maxx, v.pos.x) - miny = math.min(miny, v.pos.y) - maxy = math.max(maxy, v.pos.y) - end - - local area = (maxx - minx) * (maxy - miny) - local gridarea = #self.ugraph.vertices * self.delta * self.delta - - local scale = math.sqrt(gridarea) / math.sqrt(area) - - for _, v in ipairs(self.ugraph.vertices) do - v.pos = v.pos * scale - end + local minx = math.huge + local maxx = -math.huge + local miny = math.huge + local maxy = -math.huge + + for _, v in ipairs(self.ugraph.vertices) do + minx = math.min(minx, v.pos.x) + maxx = math.max(maxx, v.pos.x) + miny = math.min(miny, v.pos.y) + maxy = math.max(maxy, v.pos.y) + end + + local area = (maxx - minx) * (maxy - miny) + local gridarea = #self.ugraph.vertices * self.delta * self.delta + + local scale = math.sqrt(gridarea) / math.sqrt(area) + + for _, v in ipairs(self.ugraph.vertices) do + v.pos = v.pos * scale + end end -- done diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua index 8796148de80..9e5b8d72ec0 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/PlanarLayout.lua @@ -15,145 +15,145 @@ local createEdge = InterfaceToAlgorithms.createEdge local createVertex = InterfaceToAlgorithms.createVertex InterfaceToAlgorithms.declare { - key = "planar layout", - algorithm = PlanarLayout, - preconditions = { - connected = true, - loop_free = true, - simple = true, - }, - postconditions = { - fixed = true, - }, - summary = [[" - The planar layout draws planar graphs without edge crossings. - "]], - documentation = [[" - The planar layout is a pipeline of algorithms to produce - a crossings-free drawing of a planar graph. - First a combinatorical embedding of the graph is created using - the Algorithm from Boyer and Myrvold. - The combinatorical Embedding is then being improved by - by the Sort and Flip algorithm and triangulated afterwards. - To determine the actual node positions the shift method - by de Fraysseix, Pach and Pollack is used. - Finally the force based Planar Drawing Postprocessing improves the drawing. - "]], - examples = { - [[" - \tikz \graph [nodes={draw, circle}] { - a -- { - b -- { - d -- i, - e, - f - }, - c -- { - g, - h - } - }, - f --[no span edge] a, - h --[no span edge] a, - i --[no span edge] g, - f --[no span edge] g, - c --[no span edge] d, - e --[no span edge] c - } - "]] - } + key = "planar layout", + algorithm = PlanarLayout, + preconditions = { + connected = true, + loop_free = true, + simple = true, + }, + postconditions = { + fixed = true, + }, + summary = [[" + The planar layout draws planar graphs without edge crossings. + "]], + documentation = [[" + The planar layout is a pipeline of algorithms to produce + a crossings-free drawing of a planar graph. + First a combinatorical embedding of the graph is created using + the Algorithm from Boyer and Myrvold. + The combinatorical Embedding is then being improved by + by the Sort and Flip algorithm and triangulated afterwards. + To determine the actual node positions the shift method + by de Fraysseix, Pach and Pollack is used. + Finally the force based Planar Drawing Postprocessing improves the drawing. + "]], + examples = { + [[" + \tikz \graph [nodes={draw, circle}] { + a -- { + b -- { + d -- i, + e, + f + }, + c -- { + g, + h + } + }, + f --[no span edge] a, + h --[no span edge] a, + i --[no span edge] g, + f --[no span edge] g, + c --[no span edge] d, + e --[no span edge] c + } + "]] + } } function PlanarLayout:run() - --local file = io.open("timing.txt", "a") - - local options = self.digraph.options - - -- get embedding - local bm = BoyerMyrvold.new() - bm:init(self.ugraph) - local embedding = bm:run() - - assert(embedding, "Graph is not planar") - - --local start = os.clock() - if options["use sf"] then - embedding:improve() - end - - -- choose external face - local exedge, exsize = embedding:get_biggest_face() - - -- surround graph with triangle - local v1, v2, vn = embedding:surround_by_triangle(exedge, exsize) - - -- make maximal planar - embedding:triangulate() - - if options["show virtual"] then - -- add virtual vertices to input graph - for _, vertex in ipairs(embedding.vertices) do - if vertex.virtual then - vertex.inputvertex = createVertex(self, { - name = nil,--vertex.name, - generated_options = {}, - text = vertex.name - }) - vertex.virtual = false - end - end - - -- add virtual edges to input graph - for _, vertex in ipairs(embedding.vertices) do - for halfedge in Embedding.adjacency_iterator(vertex.link) do - if halfedge.virtual then - createEdge( - self, - vertex.inputvertex, - halfedge.target.inputvertex - ) - end - halfedge.virtual = false - end - end - end - - -- create canonical ordering - local order = embedding:canonical_order(v1, v2, vn) - - local sm = ShiftMethod.new() - sm:init(order) - local gridpos = sm:run() - - local gridspacing = options["grid spacing"] - for _, v in ipairs(order) do - if not v.virtual then - local iv = v.inputvertex - iv.pos.x = gridpos[v].x * gridspacing - iv.pos.y = gridpos[v].y * gridspacing - end - end - - embedding:remove_virtual() - - --start = os.clock() - if options["use pdp"] then - local pdp = PDP.new( - self.ugraph, embedding, - options["node distance"], - options["node distance"], - options["pdp cooling factor"], - options["exponent change iterations"], - options["start repulsive exponent"], - options["end repulsive exponent"], - options["start attractive exponent"], - options["end attractive exponent"], - options["edge approach threshold"], - options["edge stretch threshold"], - options["stress counter threshold"], - options["edge divisions"] - ) - pdp:run() - end + --local file = io.open("timing.txt", "a") + + local options = self.digraph.options + + -- get embedding + local bm = BoyerMyrvold.new() + bm:init(self.ugraph) + local embedding = bm:run() + + assert(embedding, "Graph is not planar") + + --local start = os.clock() + if options["use sf"] then + embedding:improve() + end + + -- choose external face + local exedge, exsize = embedding:get_biggest_face() + + -- surround graph with triangle + local v1, v2, vn = embedding:surround_by_triangle(exedge, exsize) + + -- make maximal planar + embedding:triangulate() + + if options["show virtual"] then + -- add virtual vertices to input graph + for _, vertex in ipairs(embedding.vertices) do + if vertex.virtual then + vertex.inputvertex = createVertex(self, { + name = nil,--vertex.name, + generated_options = {}, + text = vertex.name + }) + vertex.virtual = false + end + end + + -- add virtual edges to input graph + for _, vertex in ipairs(embedding.vertices) do + for halfedge in Embedding.adjacency_iterator(vertex.link) do + if halfedge.virtual then + createEdge( + self, + vertex.inputvertex, + halfedge.target.inputvertex + ) + end + halfedge.virtual = false + end + end + end + + -- create canonical ordering + local order = embedding:canonical_order(v1, v2, vn) + + local sm = ShiftMethod.new() + sm:init(order) + local gridpos = sm:run() + + local gridspacing = options["grid spacing"] + for _, v in ipairs(order) do + if not v.virtual then + local iv = v.inputvertex + iv.pos.x = gridpos[v].x * gridspacing + iv.pos.y = gridpos[v].y * gridspacing + end + end + + embedding:remove_virtual() + + --start = os.clock() + if options["use pdp"] then + local pdp = PDP.new( + self.ugraph, embedding, + options["node distance"], + options["node distance"], + options["pdp cooling factor"], + options["exponent change iterations"], + options["start repulsive exponent"], + options["end repulsive exponent"], + options["start attractive exponent"], + options["end attractive exponent"], + options["edge approach threshold"], + options["edge stretch threshold"], + options["stress counter threshold"], + options["edge divisions"] + ) + pdp:run() + end end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua index 9716aa27e4a..c568ca56964 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/ShiftMethod.lua @@ -8,121 +8,121 @@ local Embedding = require("pgf.gd.planar.Embedding") SM.__index = SM function SM.new() - local t = {} - setmetatable(t, SM) - return t + local t = {} + setmetatable(t, SM) + return t end function SM:init(vertices) - self.vertices = vertices - self.xoff = {} - self.pos = {} - for _, v in ipairs(vertices) do - self.pos[v] = {} - end - self.left = {} - self.right = {} + self.vertices = vertices + self.xoff = {} + self.pos = {} + for _, v in ipairs(vertices) do + self.pos[v] = {} + end + self.left = {} + self.right = {} end function SM:run() - local v1 = self.vertices[1] - local v2 = self.vertices[2] - local v3 = self.vertices[3] + local v1 = self.vertices[1] + local v2 = self.vertices[2] + local v3 = self.vertices[3] - self.xoff[v1] = 0 - self.pos[v1].y = 0 - self.right[v1] = v3 + self.xoff[v1] = 0 + self.pos[v1].y = 0 + self.right[v1] = v3 - self.xoff[v3] = 1 - self.pos[v3].y = 1 - self.right[v3] = v2 + self.xoff[v3] = 1 + self.pos[v3].y = 1 + self.right[v3] = v2 - self.xoff[v2] = 1 - self.pos[v2].y = 0 + self.xoff[v2] = 1 + self.pos[v2].y = 0 - local n = #self.vertices - for k = 4, n do - local vk = self.vertices[k] - local wplink, wqlink, wp1qsum - if k ~= n then - wplink, wqlink, wp1qsum = self:get_attachments(vk) - else - wplink, wqlink, wp1qsum = self:get_last_attachments(vk, v1, v2) - end - local wp, wq = wplink.target, wqlink.target - local wp1 = wplink.links[0].target - local wq1 = wqlink.links[1 - 0].target - self.xoff[wp1] = self.xoff[wp1] + 1 - self.xoff[wq] = self.xoff[wq] + 1 - wp1qsum = wp1qsum + 2 - self.xoff[vk] = (wp1qsum + self.pos[wq].y - self.pos[wp].y) / 2 - self.pos[vk].y = (wp1qsum + self.pos[wq].y + self.pos[wp].y) / 2 - -- = self.xoff[vk] + self.pos[wp].y ? - self.right[wp] = vk - if wp ~= wq1 then - self.left[vk] = wp1 - self.right[wq1] = nil - self.xoff[wp1] = self.xoff[wp1] - self.xoff[vk] - end - self.right[vk] = wq - self.xoff[wq] = wp1qsum - self.xoff[vk] - end - self.pos[v1].x = 0 - self:accumulate_offset(v1, 0) - return self.pos + local n = #self.vertices + for k = 4, n do + local vk = self.vertices[k] + local wplink, wqlink, wp1qsum + if k ~= n then + wplink, wqlink, wp1qsum = self:get_attachments(vk) + else + wplink, wqlink, wp1qsum = self:get_last_attachments(vk, v1, v2) + end + local wp, wq = wplink.target, wqlink.target + local wp1 = wplink.links[0].target + local wq1 = wqlink.links[1 - 0].target + self.xoff[wp1] = self.xoff[wp1] + 1 + self.xoff[wq] = self.xoff[wq] + 1 + wp1qsum = wp1qsum + 2 + self.xoff[vk] = (wp1qsum + self.pos[wq].y - self.pos[wp].y) / 2 + self.pos[vk].y = (wp1qsum + self.pos[wq].y + self.pos[wp].y) / 2 + -- = self.xoff[vk] + self.pos[wp].y ? + self.right[wp] = vk + if wp ~= wq1 then + self.left[vk] = wp1 + self.right[wq1] = nil + self.xoff[wp1] = self.xoff[wp1] - self.xoff[vk] + end + self.right[vk] = wq + self.xoff[wq] = wp1qsum - self.xoff[vk] + end + self.pos[v1].x = 0 + self:accumulate_offset(v1, 0) + return self.pos end function SM:get_attachments(vk) - local wplink, wqlink - local wp1qsum = 0 - local start = vk.link - local startattach = self.xoff[start.target] ~= nil - local current = start.links[0] - local last = start - repeat - local currentattach = self.xoff[current.target] ~= nil - local lastattach = self.xoff[last.target] ~= nil - if currentattach ~= lastattach then - if currentattach then - wplink = current - else - wqlink = last - end - if currentattach == startattach and not startattach then - break - end - currentattach = lastattach - elseif currentattach then - wp1qsum = wp1qsum + self.xoff[current.target] - end - last = current - current = current.links[0] - until last == start - return wplink, wqlink, wp1qsum + local wplink, wqlink + local wp1qsum = 0 + local start = vk.link + local startattach = self.xoff[start.target] ~= nil + local current = start.links[0] + local last = start + repeat + local currentattach = self.xoff[current.target] ~= nil + local lastattach = self.xoff[last.target] ~= nil + if currentattach ~= lastattach then + if currentattach then + wplink = current + else + wqlink = last + end + if currentattach == startattach and not startattach then + break + end + currentattach = lastattach + elseif currentattach then + wp1qsum = wp1qsum + self.xoff[current.target] + end + last = current + current = current.links[0] + until last == start + return wplink, wqlink, wp1qsum end function SM:get_last_attachments(vn, v1, v2) - local wplink, wqlink - local wp1qsum = 0 - for halfedge in Embedding.adjacency_iterator(vn.link, ccwdir) do - local target = halfedge.target - if target == v1 then - wplink = halfedge - elseif target == v2 then - wqlink = halfedge - end - wp1qsum = wp1qsum + self.xoff[target] - end - return wplink, wqlink, wp1qsum + local wplink, wqlink + local wp1qsum = 0 + for halfedge in Embedding.adjacency_iterator(vn.link, ccwdir) do + local target = halfedge.target + if target == v1 then + wplink = halfedge + elseif target == v2 then + wqlink = halfedge + end + wp1qsum = wp1qsum + self.xoff[target] + end + return wplink, wqlink, wp1qsum end function SM:accumulate_offset(v, x) - x = x + self.xoff[v] - self.pos[v].x = x - local l = self.left[v] - local r = self.right[v] - if l then self:accumulate_offset(l, x) end - if r then self:accumulate_offset(r, x) end + x = x + self.xoff[v] + self.pos[v].x = x + local l = self.left[v] + local r = self.right[v] + if l then self:accumulate_offset(l, x) end + if r then self:accumulate_offset(r, x) end end return SM diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/parameters.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/parameters.lua index 9e18eb07246..603f2ee7cce 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/parameters.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/planar/parameters.lua @@ -2,143 +2,143 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare declare { - key = "use pdp", - type = "boolean", - initial = "true", - - summary = [[" - Whether or not to use the Planar Drawing Postprocessing - to improve the drawing. - "]] + key = "use pdp", + type = "boolean", + initial = "true", + + summary = [[" + Whether or not to use the Planar Drawing Postprocessing + to improve the drawing. + "]] } declare { - key = "use sf", - type = "boolean", - initial = "true", - - summary = [[" - Whether or not to use the Sort and Flip Algorithm - to improve the combinatorical embedding. - "]] + key = "use sf", + type = "boolean", + initial = "true", + + summary = [[" + Whether or not to use the Sort and Flip Algorithm + to improve the combinatorical embedding. + "]] } declare { - key = "grid spacing", - type = "number", - initial = "10", - - summary = [[" - If the |use pdp| option is not set, - this sets the spacing of the grid used by the shift method. - A bigger grid spacing will result in a bigger drawing. - "]] + key = "grid spacing", + type = "number", + initial = "10", + + summary = [[" + If the |use pdp| option is not set, + this sets the spacing of the grid used by the shift method. + A bigger grid spacing will result in a bigger drawing. + "]] } declare { - key = "pdp cooling factor", - type = "number", - initial = "0.98", - - summary = [[" - This sets the cooling factor used by the Planar Drawing Postprocessing. - A higher cooling factor can result in better quality of the drawing, - but will increase the run time of the algorithm. - "]] + key = "pdp cooling factor", + type = "number", + initial = "0.98", + + summary = [[" + This sets the cooling factor used by the Planar Drawing Postprocessing. + A higher cooling factor can result in better quality of the drawing, + but will increase the run time of the algorithm. + "]] } declare { - key = "start repulsive exponent", - type = "number", - initial = "2", + key = "start repulsive exponent", + type = "number", + initial = "2", - summary = [[" - Start value of the exponent used in the calculation of all repulsive forces in PDP - "]] + summary = [[" + Start value of the exponent used in the calculation of all repulsive forces in PDP + "]] } declare { - key = "end repulsive exponent", - type = "number", - initial = "2", + key = "end repulsive exponent", + type = "number", + initial = "2", - summary = [[" - End value of the exponent used in the calculation of all repulsive forces in PDP. - "]] + summary = [[" + End value of the exponent used in the calculation of all repulsive forces in PDP. + "]] } declare { - key = "start attractive exponent", - type = "number", - initial = "2", - - summary = [[" - Start value of the exponent used in PDP's calculation of the attractive force between - nodes connected by an edge. - "]] + key = "start attractive exponent", + type = "number", + initial = "2", + + summary = [[" + Start value of the exponent used in PDP's calculation of the attractive force between + nodes connected by an edge. + "]] } declare { - key = "end attractive exponent", - type = "number", - initial = "2", - - summary = [[" - End value of the exponent used in PDP's calculation of the attractive force between - nodes connected by an edge. - "]] + key = "end attractive exponent", + type = "number", + initial = "2", + + summary = [[" + End value of the exponent used in PDP's calculation of the attractive force between + nodes connected by an edge. + "]] } declare { - key = "exponent change iterations", - type = "number", - initial = "1", - - summary = [[" - The number of iterations over which to modify the force exponents. - In iteration one the exponents will have their start value and in iteration - |exponent change iterations| they will have their end value. - "]] + key = "exponent change iterations", + type = "number", + initial = "1", + + summary = [[" + The number of iterations over which to modify the force exponents. + In iteration one the exponents will have their start value and in iteration + |exponent change iterations| they will have their end value. + "]] } declare { - key = "edge approach threshold", - type = "number", - initial = "0.3", - - summary = [[" - The maximum ration between the actual and the desired node-edge distance - which is required to count an edge as stressed. - "]] + key = "edge approach threshold", + type = "number", + initial = "0.3", + + summary = [[" + The maximum ration between the actual and the desired node-edge distance + which is required to count an edge as stressed. + "]] } declare { - key = "edge stretch threshold", - type = "number", - initial = "1.5", - - summary = [[" - The minimum ration between the actual and the desired edge length - which is required to count an edge as stressed. - "]] + key = "edge stretch threshold", + type = "number", + initial = "1.5", + + summary = [[" + The minimum ration between the actual and the desired edge length + which is required to count an edge as stressed. + "]] } declare { - key = "stress counter threshold", - type = "number", - initial = "30", + key = "stress counter threshold", + type = "number", + initial = "30", - summary = [[" - The number of iterations an edge has to be under stress before it will be subdevided. - "]] + summary = [[" + The number of iterations an edge has to be under stress before it will be subdivided. + "]] } declare { - key = "edge divisions", - type = "number", - initial = "0", + key = "edge divisions", + type = "number", + initial = "0", - summary = [[" - The number of edges in which stressed edges will be subdivided. - "]] + summary = [[" + The number of edges in which stressed edges will be subdivided. + "]] } diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/Hints.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/Hints.lua index 1f68bd99f5f..7d34726f47b 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/Hints.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/Hints.lua @@ -17,7 +17,7 @@ -- vertex positioning algorithms from the choice of edge routing -- algorithm. For instance, for a simple necklace routing, it is -- unclear whether the edges on the necklace should be routing ``along --- the necklace'' or not. Thus, necklace routing algoirthms will +-- the necklace'' or not. Thus, necklace routing algorithms will -- ``hint'' that a necklace is present and only when the -- |necklace routing| algorithm is selected will these hints lead to -- actual bending of edges. @@ -47,14 +47,14 @@ local necklaces = Storage.new() -- Adds a necklace hint. In this case, the hint indicates that the -- given sequence of vertices lie on a circle. -- --- The idea is that an algorithm may specify that in a --- given graph certain sequences of nodes form a ``necklace,'' which +-- The idea is that an algorithm may specify that in a +-- given graph certain sequences of nodes form a ``necklace'', which -- is typically a circle. There may be more than one necklace inside a --- given graph. For each necklace, +-- given graph. For each necklace, -- whenever an arc connects subsequent nodes on the necklace, they get -- bend in such a way that they lie follow the path of the -- necklace. If an arc lies on more than one necklace, the ``last one --- wins.'' +-- wins''. -- -- @param ugraph The ugraph to which this hint is added -- @param necklace The sequence of vertices that form the necklace. If @@ -68,7 +68,7 @@ local necklaces = Storage.new() function Hints.addNecklaceCircleHint(ugraph, necklace, center, clockwise) local a = necklaces[ugraph] or {} necklaces[ugraph] = a - + a[#a+1] = { necklace = necklace, center = center or Coordinate.origin, @@ -95,6 +95,6 @@ function Hints.getNecklaceHints(ugraph) end -- done - + return Hints diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua index 9a99ea2275f..defcf9f8c61 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/routing/NecklaceRouting.lua @@ -35,28 +35,28 @@ declare { summary = "Bends all edges of a graph that lie on ``necklaces'' along these necklaces.", documentation = [[" - Some graph drawing algorithms lay out some or all nodes along a - path, which is then called a \emph{necklace.} For instance, the - |simple necklace layout| places all nodes on a circle and that - circle is the ``necklace.'' When the |necklace rounting| edge - routing algorithm is selected, all edges that connect subsequent - nodes on such a necklace are bend in such a way that the - ``follow the necklace path.'' In the example case, this will - cause all edges that connect adjacent nodes to become arcs on - of the circle on which the nodes lie. - - Note that local edge routing options for an edge may overrule - the edge routing computed by the algorithm as in the edge from 6 - to 7 in the example. + Some graph drawing algorithms lay out some or all nodes along a + path, which is then called a \emph{necklace}. For instance, the + |simple necklace layout| places all nodes on a circle and that + circle is the ``necklace''. When the |necklace routing| edge + routing algorithm is selected, all edges that connect subsequent + nodes on such a necklace are bend in such a way that the + ``follow the necklace path''. In the example case, this will + cause all edges that connect adjacent nodes to become arcs on + of the circle on which the nodes lie. + + Note that local edge routing options for an edge may overrule + the edge routing computed by the algorithm as in the edge from 6 + to 7 in the example. "]], - + examples = [[" - \tikz \graph [simple necklace layout, node distance=1.5cm, - necklace routing, - nodes={draw,circle}, edges={>={Stealth[round,sep,bend]}}] - { 1 -> 2 [minimum size=30pt] <- 3 <-> 4 -- - 5 -- 6 -- [bend left] 7 -- 1 -- 4 }; - "]] + \tikz \graph [simple necklace layout, node distance=1.5cm, + necklace routing, + nodes={draw,circle}, edges={>={Stealth[round,sep,bend]}}] + { 1 -> 2 [minimum size=30pt] <- 3 <-> 4 -- + 5 -- 6 -- [bend left] 7 -- 1 -- 4 }; + "]] } @@ -65,19 +65,19 @@ declare { function NecklaceRouting:run() local ugraph = self.ugraph - + for _,entry in ipairs(Hints.getNecklaceHints(ugraph)) do assert (entry.center) -- no other necklace types, yet local prev for _,vertex in ipairs(entry.necklace) do if prev then - local a = ugraph:arc(prev, vertex) - if a then - local p = Path.new() - p:appendMoveto(a.tail.pos:clone()) - p:appendArcTo(a.head.pos:clone(), entry.center, entry.clockwise) - a.path = p - end + local a = ugraph:arc(prev, vertex) + if a then + local p = Path.new() + p:appendMoveto(a.tail.pos:clone()) + p:appendArcTo(a.head.pos:clone(), entry.center, entry.clockwise) + a.path = p + end end prev = vertex end @@ -87,4 +87,4 @@ end -- done -return NecklaceRouting
\ No newline at end of file +return NecklaceRouting diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua index b13dcb9abb4..a0aee6501cc 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/tools/make_gd_wrap.lua @@ -17,7 +17,7 @@ -- algorithm implemented in C and wish to invoke it from Lua, you need -- a wrapper that manages the translation between Lua and C. This -- program is intended to make it (reasonably) easy to produce such a --- wraper. +-- wrapper. @@ -29,7 +29,7 @@ Usage: make_gd_wrap library1 library2 ... libraryn template library_name target_ This program will read all of the graph drawing library files using Lua's require. Then, it will iterate over all declared algorithm keys -(declared using declare { algorithm_written_in_c = ... }) and will +(declared using declare { algorithm_written_in_c = ... }) and will produce the code for library for the required target C files based on the template. "]]) @@ -82,79 +82,79 @@ local factories = {} local factories_reg = {} for _,k in ipairs(keys) do - + if k.algorithm_written_in_c and k.code then local library, fun_name = k.algorithm_written_in_c:match("(.*)%.(.*)") - - if target == library then + + if target == library then -- First, gather the includes: if type(k.includes) == "string" then - if not includes[k.includes] then - includes[#includes + 1] = k.includes - includes[k.includes] = true - end + if not includes[k.includes] then + includes[#includes + 1] = k.includes + includes[k.includes] = true + end elseif type(k.includes) == "table" then - for _,i in ipairs(k.includes) do - if not includes[i] then - includes[#includes + 1] = i - includes[i] = true - end - end + for _,i in ipairs(k.includes) do + if not includes[i] then + includes[#includes + 1] = i + includes[i] = true + end + end end - + -- Second, create a code block: functions[#functions+1] = functions_dec:gsub("%$([%w_]-)%b{}", - { - function_name = fun_name, - function_body = k.code - }) - + { + function_name = fun_name, + function_body = k.code + }) + -- Third, create functions_registry entry functions_registry[#functions_registry + 1] = functions_reg_dec:gsub("%$([%w_]-)%b{}", - { - function_name = fun_name, - function_body = k.code - }) + { + function_name = fun_name, + function_body = k.code + }) end end - + if k.module_class then - + -- First, gather the includes: if type(k.includes) == "string" then if not includes[k.includes] then - includes[#includes + 1] = k.includes - includes[k.includes] = true + includes[#includes + 1] = k.includes + includes[k.includes] = true end elseif type(k.includes) == "table" then for _,i in ipairs(k.includes) do - if not includes[i] then - includes[#includes + 1] = i - includes[i] = true - end + if not includes[i] then + includes[#includes + 1] = i + includes[i] = true + end end end - + -- Second, create a code block: factories[#factories+1] = factories_dec:gsub( "%$([%w_]-)%b{}", { - factory_class = k.module_class, - factory_code = k.code, - factory_base = k.module_base, - factory_name = k.module_class .. '_factory' + factory_class = k.module_class, + factory_code = k.code, + factory_base = k.module_base, + factory_name = k.module_class .. '_factory' }) - + -- Third, create factories_registry entry factories_reg[#factories_reg + 1] = factories_reg_dec:gsub( "%$([%w_]-)%b{}", { - factory_class = k.module_class, - factory_code = k.code, - factory_base = k.module_base, - factory_name = k.module_class .. '_factory' + factory_class = k.module_class, + factory_code = k.code, + factory_base = k.module_base, + factory_name = k.module_class .. '_factory' }) end end @@ -180,4 +180,4 @@ file:write ((template:gsub( }))) file:close() -
\ No newline at end of file + diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua index 0b975fd3291..5af36428858 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ChildSpec.lua @@ -33,10 +33,11 @@ -- of specifying ``missing first children'' or, more generally, missing -- children that are not ``at the end'' of the list of children. For -- this, there are three methods: --- +-- % -- \begin{enumerate} --- \item When you use the |child| syntax, you can use the |missing| key --- with the |child| command to indicate a missing child: +-- \item When you use the |child| syntax, you can use the |missing| key +-- with the |child| command to indicate a missing child: +-- % -- \begin{codeexample}[] -- \tikz [binary tree layout, level distance=5mm] -- \node {a} @@ -51,15 +52,18 @@ -- child { node {g} -- } } }; -- \end{codeexample} --- \item When using the |graph| syntax, you can use an ``empty node'', --- which really must be completely empty and may not even contain a --- slash, to indicate a missing node: +-- % +-- \item When using the |graph| syntax, you can use an ``empty node'', +-- which really must be completely empty and may not even contain a +-- slash, to indicate a missing node: +-- % -- \begin{codeexample}[] -- \tikz [binary tree layout, level distance=5mm] -- \graph { a -> { b -> c -> d, e -> { , f -> { , g} } } }; -- \end{codeexample} --- \item You can simply specify the index of a child directly using --- the key |desired child index|. +-- % +-- \item You can simply specify the index of a child directly using +-- the key |desired child index|. -- \end{enumerate} -- -- @end @@ -78,27 +82,27 @@ declare { initial = "0", summary = [[" - Specifies how many children a tree node must have at least. If - there are less, ``virtual'' children are added. + Specifies how many children a tree node must have at least. If + there are less, ``virtual'' children are added. "]], - documentation = [[" - When this key is set to |2| or more, the following happens: We first - compute a spanning tree for the graph, see - Section~\ref{subsection-gd-spanning-tree}. Then, whenever a node is - not a leaf in this spanning tree (when it has at least one child), - we add ``virtual'' or ``dummy'' nodes as children of the node until - the total number of real and dummy children is at least - \meta{number}. If there where at least \meta{number} children at the - beginning, nothing happens. - - The new children are added after the existing children. This means - that, for instance, in a tree with \meta{number} set to |2|, for - every node with a single child, this child will be the first child - and the second child will be missing. + documentation = [[" + When this key is set to |2| or more, the following happens: We first + compute a spanning tree for the graph, see + Section~\ref{subsection-gd-spanning-tree}. Then, whenever a node is + not a leaf in this spanning tree (when it has at least one child), + we add ``virtual'' or ``dummy'' nodes as children of the node until + the total number of real and dummy children is at least + \meta{number}. If there where at least \meta{number} children at the + beginning, nothing happens. + + The new children are added after the existing children. This means + that, for instance, in a tree with \meta{number} set to |2|, for + every node with a single child, this child will be the first child + and the second child will be missing. "]], examples = [[" - \tikz \graph [binary tree layout,level distance=5mm] - { a -> { b->c->d, e->f->g } }; + \tikz \graph [binary tree layout,level distance=5mm] + { a -> { b->c->d, e->f->g } }; "]] } @@ -108,65 +112,60 @@ declare { key = "desired child index", type = "number", - summary = [[" - Pass this key to a node to tell the graph drawing engine which child - number you ``desired'' for the node. Whenever all desires for the - children of a node are conflict-free, they will all be met; children - for which no desired indices were given will remain at their - position, whenever possible, but will ``make way'' for children with - a desired position. + summary = [[" + Pass this key to a node to tell the graph drawing engine which child + number you ``desired'' for the node. Whenever all desires for the + children of a node are conflict-free, they will all be met; children + for which no desired indices were given will remain at their + position, whenever possible, but will ``make way'' for children with + a desired position. "]], documentation = [[" - In detail, the following happens: We first - determine the total number of children (real or dummy) needed, which - is the maximum of the actual number of children, of the - \texttt{minimum number of children}, and of the highest desired - child index. Then we go over all children that have a desired child - index and put they at this position. If the position is already - taken (because some other child had the same desired index), the - next free position is used with a wrap-around occurring at the - end. Next, all children without a desired index are place using the - same mechanism, but they want to be placed at the position they had - in the original spanning tree. - - While all of this might sound a bit complicated, the application of - the key in a binary tree is pretty straightforward: To indicate that - a node is a ``right'' child in a tree, just add \texttt{desired child index=2} - to it. This will make it a second child, possibly causing the fist - child to be missing. If there are two nodes specified as children of - a node, by saying \texttt{desired child index=}\meta{number} for one - of them, you will cause it be first or second child, depending on - \meta{number}, and cause the \emph{other} child to become the other - child. - - Since |desired child index=2| is a bit long, the following shortcuts - are available: |first|, |second|, |third|, and |fourth|. - You might wonder why |second| is used rather than |right|. The - reason is that trees may also grow left and right and, additionally, - the |right| and |left| keys are already in use for - anchoring. Naturally, you can locally redefine them, if you want. + In detail, the following happens: We first + determine the total number of children (real or dummy) needed, which + is the maximum of the actual number of children, of the + \texttt{minimum number of children}, and of the highest desired + child index. Then we go over all children that have a desired child + index and put they at this position. If the position is already + taken (because some other child had the same desired index), the + next free position is used with a wrap-around occurring at the + end. Next, all children without a desired index are place using the + same mechanism, but they want to be placed at the position they had + in the original spanning tree. + + While all of this might sound a bit complicated, the application of + the key in a binary tree is pretty straightforward: To indicate that + a node is a ``right'' child in a tree, just add \texttt{desired child index=2} + to it. This will make it a second child, possibly causing the fist + child to be missing. If there are two nodes specified as children of + a node, by saying \texttt{desired child index=}\meta{number} for one + of them, you will cause it be first or second child, depending on + \meta{number}, and cause the \emph{other} child to become the other + child. + + Since |desired child index=2| is a bit long, the following shortcuts + are available: |first|, |second|, |third|, and |fourth|. + You might wonder why |second| is used rather than |right|. The + reason is that trees may also grow left and right and, additionally, + the |right| and |left| keys are already in use for + anchoring. Naturally, you can locally redefine them, if you want. "]], - examples = { - [[" - \tikz \graph [binary tree layout, level distance=5mm] - { a -> b[second] }; - "]], - [[" - \tikz \graph [binary tree layout, level distance=5mm] - { a -> { b[second], c} }; - "]], - [[" - \tikz \graph [binary tree layout, level distance=5mm] - { a -> { b, c[first]} }; - "]], - [[" - \tikz \graph [binary tree layout, level distance=5mm] - { a -> { b[second], c[second]} }; - "]], - [[" - \tikz \graph [binary tree layout, level distance=5mm] - { a -> { b[third], c[first], d} }; - "]] + examples = {[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> b[second] }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b[second], c} }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b, c[first]} }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b[second], c[second]} }; + "]],[[" + \tikz \graph [binary tree layout, level distance=5mm] + { a -> { b[third], c[first], d} }; + "]] } } @@ -179,9 +178,9 @@ declare { { key = "desired child index", value = 1}, }, - summary = [[" - A shorthand for setting the desired child number to |1|. - "]] + summary = [[" + A shorthand for setting the desired child number to |1|. + "]] } --- @@ -192,11 +191,11 @@ declare { { key = "desired child index", value = 2}, }, - summary = [[" - A shorthand for setting the desired child number to |2|. - "]] + summary = [[" + A shorthand for setting the desired child number to |2|. + "]] } - + --- @@ -206,11 +205,11 @@ declare { { key = "desired child index", value = 3}, }, - summary = [[" - A shorthand for setting the desired child number to |3|. + summary = [[" + A shorthand for setting the desired child number to |3|. "]] } - + --- @@ -220,8 +219,7 @@ declare { { key = "desired child index", value = 4} }, - summary = [[" - A shorthand for setting the desired child number to |4|. + summary = [[" + A shorthand for setting the desired child number to |4|. "]] } - diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua index 8eba23a2106..69babd443c7 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/ReingoldTilford1981.lua @@ -27,7 +27,7 @@ local Storage = require "pgf.gd.lib.Storage" declare { key = "tree layout", algorithm = ReingoldTilford1981, - + preconditions = { connected = true, tree = true @@ -69,7 +69,7 @@ declare { }, documentation_in = "pgf.gd.trees.doc" } - + --- declare { key = "extended binary tree layout", @@ -86,16 +86,16 @@ declare { -- Now comes the implementation: - + function ReingoldTilford1981:run() local root = self.spanning_tree.root local layers = Storage.new() local descendants = Storage.new() - + self.extended_version = self.digraph.options['missing nodes get space'] - + self:precomputeDescendants(root, 1, layers, descendants) self:computeHorizontalPosition(root, layers, descendants) layered.arrange_layers_by_baselines(layers, self.adjusted_bb, self.ugraph) @@ -113,7 +113,7 @@ function ReingoldTilford1981:precomputeDescendants(node, depth, layers, descenda my_descendants[#my_descendants + 1] = d end end - + layers[node] = depth descendants[node] = my_descendants end @@ -121,7 +121,7 @@ end function ReingoldTilford1981:computeHorizontalPosition(node, layers, descendants) - + local children = self.spanning_tree:outgoing(node) node.pos.x = 0 @@ -133,19 +133,19 @@ function ReingoldTilford1981:computeHorizontalPosition(node, layers, descendants for i=1,#children do self:computeHorizontalPosition(children[i].head, layers, descendants) end - + -- Now, compute minimum distances and shift them local right_borders = {} for i=1,#children-1 do - + local local_right_borders = {} - + -- Advance "right border" of the subtree rooted at -- the i-th child for _,d in ipairs(descendants[children[i].head]) do local layer = layers[d] - local x = d.pos.x + local x = d.pos.x if self.extended_version or not (layer > child_depth and d.kind == "dummy") then if not right_borders[layer] or right_borders[layer].pos.x < x then right_borders[layer] = d @@ -160,7 +160,7 @@ function ReingoldTilford1981:computeHorizontalPosition(node, layers, descendants -- Now left for i+1 st child for _,d in ipairs(descendants[children[i+1].head]) do local layer = layers[d] - local x = d.pos.x + local x = d.pos.x if self.extended_version or not (layer > child_depth and d.kind == "dummy") then if not left_borders[layer] or left_borders[layer].pos.x > x then left_borders[layer] = d @@ -179,13 +179,13 @@ function ReingoldTilford1981:computeHorizontalPosition(node, layers, descendants local n1 = right_borders[layer] if n1 then shift = math.max( - shift, + shift, layered.ideal_sibling_distance(self.adjusted_bb, self.ugraph, n1, n2) + n1.pos.x - n2.pos.x ) end if local_right_borders[layer] then if layer > child_depth and - (left_borders[layer].pos.x - local_right_borders[layer].pos.x <= first_dist) then + (left_borders[layer].pos.x - local_right_borders[layer].pos.x <= first_dist) then is_significant = true end end @@ -200,7 +200,7 @@ function ReingoldTilford1981:computeHorizontalPosition(node, layers, descendants d.pos.x = d.pos.x + shift end end - + -- Finally, position root in the middle: node.pos.x = (children[1].head.pos.x + children[#children].head.pos.x) / 2 end diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua index 791fb81e658..8951ce0538c 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/SpanningTreeComputation.lua @@ -18,7 +18,7 @@ -- Although the algorithms of this library are tailored to layout trees, -- they will work for any graph as input. First, if the graph is not -- connected, it is decomposed into connected components and these are --- laid out individiually. Second, for each component, a spanning tree of +-- laid out individually. Second, for each component, a spanning tree of -- the graph is computed first and the layout is computed for this -- spanning tree; all other edges will still be drawn, but they have no -- impact on the placement of the nodes. If the graph is already a tree, @@ -28,9 +28,9 @@ -- a non-tree graph has many different possible spanning trees. You can -- choose between different methods for deciding on a spanning tree, it -- is even possible to implement new algorithms. (In the future, the --- computation of spanning trees and the cylce removal in layered graph +-- computation of spanning trees and the cycle removal in layered graph -- drawing algorithms will be unified, but, currently, they are --- implemented differently.) +-- implemented differently.) -- -- Selects the (sub)algorithm that is to be used for computing spanning -- trees whenever this is requested by a tree layout algorithm. The @@ -39,15 +39,15 @@ --\begin{codeexample}[] --\tikz \graph [tree layout, breadth first spanning tree] --{ --- 1 -- {2,3,4,5} -- 6; ---}; +-- 1 -- {2,3,4,5} -- 6; +--}; --\end{codeexample} --\begin{codeexample}[] --\tikz \graph [tree layout, depth first spanning tree] --{ --- 1 --[bend right] {2,3,4,5 [>bend left]} -- 6; ---}; ---\end{codeexample} +-- 1 --[bend right] {2,3,4,5 [>bend left]} -- 6; +--}; +--\end{codeexample} -- -- @end @@ -82,90 +82,91 @@ local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare -- declare { key = "breadth first spanning tree", - algorithm = { + algorithm = { run = function (self) - return SpanningTreeComputation.computeSpanningTree(self.ugraph, false, self.events) + return SpanningTreeComputation.computeSpanningTree(self.ugraph, false, self.events) end }, phase = "spanning tree computation", phase_default = true, - summary = [[" - This key selects ``breadth first'' as the (sub)algorithm for - computing spanning trees. Note that this key does not cause a graph - drawing scope to start; the key only has an effect in conjunction - with keys like |tree layout|. - "]], - documentation = [[" - The algorithm will be called whenever a graph drawing algorithm - needs a spanning tree on which to operate. It works as follows: - \begin{enumerate} - \item It looks for a node for which the |root| parameter is - set. If there are several such nodes, the first one is used. If there - are no such nodes, the first node is used. - - Let call the node determined in this way the \emph{root node}. - \item For every edge, a \emph{priority} is determined, which is a - number between 1 and 10. How this happens, exactly, will be - explained in a moment. Priority 1 means ``most important'' while - priority 10 means ``least important''. - \item Starting from the root node, we now perform a breadth first - search through the tree, thereby implicitly building a spanning - tree: Suppose for a moment that all edges have priority~1. Then, - the algorithm works just the way that a normal breadth first - search is performed: We keep a queue of to-be-visited nodes and - while this queue is not empty, we remove its first node. If this - node has not yet been visited, we add all its neighbors at the - end of the queue. When a node is taken out of the queue, we make - it the child of the node whose neighbor it was when it was - added. Since the queue follows the ``first in, first out'' - principle (it is a fifo queue), the children of the root will be - all nodes at distance $1$ form the root, their children will be - all nodes at distance $2$, and so on. - \item Now suppose that some edges have a priority different - from~1, in which case things get more complicated. We now keep - track of one fifo queue for each of the ten possible - priorities. When we consider the neighbors of a node, we actually - consider all its incident edges. Each of these edges has a certain - priority and the neighbor is put into the queue of the edge's - priority. Now, we still remove nodes normally from the queue for - priority~1; only if this queue is empty and there is still a node - in the queue for priority~2 we remove the first element from this - queue (and proceed as before). If the second queue is also empty, - we try the third, and so on up to the tenth queue. If all queues - are empty, the algorithm stops. - \end{enumerate} - - The effect of the ten queues is the following: If the edges of - priority $1$ span the whole graph, a spanning tree consisting solely - of these edges will be computed. However, if they do not, once we - have visited reachable using only priority 1 edges, we will extend - the spanning tree using a priority 2 edge; but then we once switch - back to using only priority 1 edges. If neither priority~1 nor - priority~2 edges suffice to cover the whole graph, priority~3 edges - are used, and so on. + summary = [[" + This key selects ``breadth first'' as the (sub)algorithm for + computing spanning trees. Note that this key does not cause a graph + drawing scope to start; the key only has an effect in conjunction + with keys like |tree layout|. +"]], + documentation = [[" + The algorithm will be called whenever a graph drawing algorithm + needs a spanning tree on which to operate. It works as follows: + % + \begin{enumerate} + \item It looks for a node for which the |root| parameter is + set. If there are several such nodes, the first one is used. + If there are no such nodes, the first node is used. + + Let call the node determined in this way the \emph{root node}. + \item For every edge, a \emph{priority} is determined, which is a + number between 1 and 10. How this happens, exactly, will be + explained in a moment. Priority 1 means ``most important'' while + priority 10 means ``least important''. + \item Starting from the root node, we now perform a breadth first + search through the tree, thereby implicitly building a spanning + tree: Suppose for a moment that all edges have priority~1. Then, + the algorithm works just the way that a normal breadth first + search is performed: We keep a queue of to-be-visited nodes and + while this queue is not empty, we remove its first node. If this + node has not yet been visited, we add all its neighbors at the + end of the queue. When a node is taken out of the queue, we make + it the child of the node whose neighbor it was when it was + added. Since the queue follows the ``first in, first out'' + principle (it is a fifo queue), the children of the root will be + all nodes at distance $1$ form the root, their children will be + all nodes at distance $2$, and so on. + \item Now suppose that some edges have a priority different + from~1, in which case things get more complicated. We now keep + track of one fifo queue for each of the ten possible + priorities. When we consider the neighbors of a node, we actually + consider all its incident edges. Each of these edges has a certain + priority and the neighbor is put into the queue of the edge's + priority. Now, we still remove nodes normally from the queue for + priority~1; only if this queue is empty and there is still a node + in the queue for priority~2 we remove the first element from this + queue (and proceed as before). If the second queue is also empty, + we try the third, and so on up to the tenth queue. If all queues + are empty, the algorithm stops. + \end{enumerate} + + The effect of the ten queues is the following: If the edges of + priority $1$ span the whole graph, a spanning tree consisting solely + of these edges will be computed. However, if they do not, once we + have visited reachable using only priority 1 edges, we will extend + the spanning tree using a priority 2 edge; but then we once switch + back to using only priority 1 edges. If neither priority~1 nor + priority~2 edges suffice to cover the whole graph, priority~3 edges + are used, and so on. "]] - } +} --- declare { key = "depth first spanning tree", - algorithm = { + algorithm = { run = function (self) - return SpanningTreeComputation.computeSpanningTree(self.ugraph, true, self.events) + return SpanningTreeComputation.computeSpanningTree(self.ugraph, true, self.events) end }, phase = "spanning tree computation", - summary = [[" - Works exactly like |breadth first spanning tree| (same handling of - priorities), only the queues are now lifo instead of - fifo. - "]] - } + summary = [[" + Works exactly like |breadth first spanning tree| (same handling of + priorities), only the queues are now lifo instead of + fifo. + "]] +} --- -- @@ -174,13 +175,13 @@ declare { type = "boolean", default = true, - summary = [[" - This Boolean parameter is used in the computation of spanning - trees. When can be set for a node, this node will be used as the - root for the spanning tree computation. If several nodes have this - option set, the first node will be used. - "]] - } + summary = [[" + This Boolean parameter is used in the computation of spanning + trees. When can be set for a node, this node will be used as the + root for the spanning tree computation. If several nodes have this + option set, the first node will be used. + "]] +} --- @@ -189,29 +190,29 @@ declare { key = "span priority", type = "number", - summary = [[" - Explicitly sets the ``span priority'' of an edge to \meta{number}, which must be - a number between |1| and |10|. The priority of edges is used by - spanning tree computations, see |breadth first spanning tree|. - "]] - } - + summary = [[" + Explicitly sets the ``span priority'' of an edge to \meta{number}, which must be + a number between |1| and |10|. The priority of edges is used by + spanning tree computations, see |breadth first spanning tree|. + "]] +} + --- --- when it comes to choosing which edges are part of the spanning tree. +-- when it comes to choosing which edges are part of the spanning tree. declare { key = "span edge", use = { { key = "span priority", value = 1 }, }, - summary = [[" - An easy-to-remember shorthand for |span priority=1|. When this key - is used with an edge, it will always be preferred over other edges - "]] - } - + summary = [[" + An easy-to-remember shorthand for |span priority=1|. When this key + is used with an edge, it will always be preferred over other edges + "]] +} + @@ -223,29 +224,29 @@ declare { { key = "span priority", value = 10 }, }, - summary = [[" - An easy-to-remember shorthand for |span priority=10|. This causes - the edge to be used only as a last resort as part of a spanning - tree. - "]], - documentation = [[" - In the example, we add lots of edges that would normally be - preferred in the computation of the spanning tree, but use - |no span edge| to cause the algorithm to ignore these edges. - "]], - examples = [[" - \tikz \graph [tree layout, nodes={draw}, sibling distance=0pt, - every group/.style={ - default edge kind=->, no span edge, - path=source}] - { - 5 -> { - "1,3" -> {0,2,4}, - 11 -> { - "7,9" -> { 6, 8, 10 } - } + summary = [[" + An easy-to-remember shorthand for |span priority=10|. This causes + the edge to be used only as a last resort as part of a spanning + tree. + "]], + documentation = [[" + In the example, we add lots of edges that would normally be + preferred in the computation of the spanning tree, but use + |no span edge| to cause the algorithm to ignore these edges. + "]], + examples = [[" + \tikz \graph [tree layout, nodes={draw}, sibling distance=0pt, + every group/.style={ + default edge kind=->, no span edge, + path=source}] + { + 5 -> { + "1,3" -> {0,2,4}, + 11 -> { + "7,9" -> { 6, 8, 10 } } - }; + } + }; "]] } @@ -257,79 +258,85 @@ declare { type = "number", initial = "3", - summary = [[" - This key stores the span priority of all edges whose direction is - |->|. There are similar keys for all other directions, such as - |span priority <-| and so on. + summary = [[" + This key stores the span priority of all edges whose direction is + |->|. There are similar keys for all other directions, such as + |span priority <-| and so on. "]], - documentation = [[" - When you write + documentation = [[" + When you write + % \begin{codeexample}[code only] -graph { a -> b -- c <- [span priority=2] d } +graph { a -> b -- c <- [span priority=2] d } \end{codeexample} - the priority of the edge from |a| to |b| would be the current - value of the key |span priority ->|, the priority of the edge from - |b| to |c| would be the current value of |span priority --|, and - the priority of the edge from |c| to |d| would be |2|, regardless - of the value of |span priority <-|. - - The defaults for the priorities are: - \begin{itemize} - \item |span priority -> = 3| - \item |span priority -- = 5| - \item |span priority <-> = 5| - \item |span priority <- = 8| - \item |span priority -!- = 10| - \end{itemize} + % + the priority of the edge from |a| to |b| would be the current + value of the key |span priority ->|, the priority of the edge from + |b| to |c| would be the current value of |span priority --|, and + the priority of the edge from |c| to |d| would be |2|, regardless + of the value of |span priority <-|. + + The defaults for the priorities are: + % + \begin{itemize} + \item |span priority -> = 3| + \item |span priority -- = 5| + \item |span priority <-> = 5| + \item |span priority <- = 8| + \item |span priority -!- = 10| + \end{itemize} "]] } - + --- - + declare { key = "span priority reversed ->", type = "number", initial = "9", - documentation = [[" - This key stores the span priority of traveling across reversed - edges whose actual direction is |->| (again, there are similar keys - for all other directions). + documentation = [[" + This key stores the span priority of traveling across reversed + edges whose actual direction is |->| (again, there are similar keys + for all other directions). "]], - documentation = [[" - When you write + documentation = [[" + When you write + % \begin{codeexample}[code only] -graph { a -> b -- c <- [span priority=2] d } +graph { a -> b -- c <- [span priority=2] d } \end{codeexample} - there are, in addition to the priorities indicated above, also - further edge priorities: The priority of the (reversed) edge |b| - to |a| is |span priority reversed ->|, the priority of the - (reversed) edge |c| to |b| is |span priority reversed --|, and the - span priority of the reversed edge |d| to |c| is |2|, regardless - of the value of |span priority reversed <-|. - - The defaults for the priorities are: - \begin{itemize} - \item |span priority reversed -> = 9| - \item |span priority reversed -- = 5| - \item |span priority reversed <-> = 5| - \item |span priority reversed <- = 7| - \item |span priority reversed -!- = 10| - \end{itemize} - - The default priorities are set in such a way, that non-reversed |->| - edges have top priorities, |--| and |<->| edges have the same - priorities in either direction, and |<-| edges have low priority in - either direction (but going |a <- b| from |b| to |a| is given higher - priority than going from |a| to |b| via this edge and also higher - priority than going from |b| to |a| in |a -> b|). - - Keys like |span using directed| change the priorities ``en bloc''. + % + there are, in addition to the priorities indicated above, also + further edge priorities: The priority of the (reversed) edge |b| + to |a| is |span priority reversed ->|, the priority of the + (reversed) edge |c| to |b| is |span priority reversed --|, and the + span priority of the reversed edge |d| to |c| is |2|, regardless + of the value of |span priority reversed <-|. + + The defaults for the priorities are: + % + \begin{itemize} + \item |span priority reversed -> = 9| + \item |span priority reversed -- = 5| + \item |span priority reversed <-> = 5| + \item |span priority reversed <- = 7| + \item |span priority reversed -!- = 10| + \end{itemize} + + The default priorities are set in such a way, that non-reversed |->| + edges have top priorities, |--| and |<->| edges have the same + priorities in either direction, and |<-| edges have low priority in + either direction (but going |a <- b| from |b| to |a| is given higher + priority than going from |a| to |b| via this edge and also higher + priority than going from |b| to |a| in |a -> b|). + + Keys like |span using directed| change the priorities ``en bloc''. "]] } - + declare { key = "span priority <-", @@ -388,23 +395,23 @@ declare { { key = "span priority <->", value = 3}, { key = "span priority reversed <->", value = 3}, }, - summary = [[" - This style sets a priority of |3| for all edges that are directed - and ``go along the arrow direction'', that is, we go from |a| to - |b| with a priority of |3| for the cases |a -> b|, |b <- a|, - |a <-> b|, and |b <-> a|. - This strategy is nice with trees specified with both forward and - backward edges. + summary = [[" + This style sets a priority of |3| for all edges that are directed + and ``go along the arrow direction'', that is, we go from |a| to + |b| with a priority of |3| for the cases |a -> b|, |b <- a|, + |a <-> b|, and |b <-> a|. + This strategy is nice with trees specified with both forward and + backward edges. "]], - examples = [[" - \tikz \graph [tree layout, nodes={draw}, sibling distance=0pt, - span using directed] - { - 3 <- 5[root] -> 8, - 1 <- 3 -> 4, - 7 <- 8 -> 9, - 1 -- 4 -- 7 -- 9 - }; + examples = [[" + \tikz \graph [tree layout, nodes={draw}, sibling distance=0pt, + span using directed] + { + 3 <- 5[root] -> 8, + 1 <- 3 -> 4, + 7 <- 8 -> 9, + 1 -- 4 -- 7 -- 9 + }; "]] } @@ -424,9 +431,9 @@ declare { { key = "span priority reversed --", value = 5}, { key = "span priority reversed -!-", value = 5}, }, - - summary = [[" - Assings a uniform priority of 5 to all edges. + + summary = [[" + Assings a uniform priority of 5 to all edges. "]] } @@ -440,7 +447,7 @@ declare { -- determined through an edge priority function. -- -- @param ugraph An undirected graph for which the spanning tree --- should be computed +-- should be computed -- @param dfs True if depth first should be used, false if breadth -- first should be used. -- @@ -449,7 +456,7 @@ declare { function SpanningTreeComputation.computeSpanningTree (ugraph, dfs, events) local tree = Digraph.new (ugraph) -- copy vertices - + local edge_priorities = ugraph.options['/graph drawing/edge priorities'] local root = lib.find(ugraph.vertices, function (v) return v.options['root'] end) or ugraph.vertices[1] @@ -460,7 +467,7 @@ function SpanningTreeComputation.computeSpanningTree (ugraph, dfs, events) local marked = {} local stacks = { -- 10 stacks for 10 priorities, with 1 being the highest - { { parent = nil, node = root}, top = 1, bottom = 1 }, + { { parent = nil, node = root}, top = 1, bottom = 1 }, { top = 0, bottom = 1}, { top = 0, bottom = 1}, { top = 0, bottom = 1}, @@ -471,51 +478,51 @@ function SpanningTreeComputation.computeSpanningTree (ugraph, dfs, events) { top = 0, bottom = 1}, { top = 0, bottom = 1} } - + local function stack_is_non_empty (s) return s.top >= s.bottom end - + while lib.find(stacks, stack_is_non_empty) do local parent, node - + for _,stack in ipairs(stacks) do if stack_is_non_empty(stack) then - -- Pop - parent = stack[stack.top].parent - node = stack[stack.top].node - - stack[stack.top] = nil - stack.top = stack.top - 1 - - break + -- Pop + parent = stack[stack.top].parent + node = stack[stack.top].node + + stack[stack.top] = nil + stack.top = stack.top - 1 + + break end end - + if not marked[node] then - + -- The node is good! marked[node] = true - + if parent then - tree:connect(parent,node) + tree:connect(parent,node) end - + local arcs = ugraph:outgoing(node) - + for j=1,#arcs do - local arc = arcs[dfs and j or #arcs - j + 1] - local head = arc.head - - if not marked[head] then - local priority = arc:spanPriority() - local stack = assert(stacks[priority], "illegal edge priority") - if dfs then - stack.top = stack.top + 1 - stack[stack.top] = { parent = node, node = head} - else - stack.bottom = stack.bottom - 1 - stack[stack.bottom] = { parent = node, node = head} - end - end + local arc = arcs[dfs and j or #arcs - j + 1] + local head = arc.head + + if not marked[head] then + local priority = arc:spanPriority() + local stack = assert(stacks[priority], "illegal edge priority") + if dfs then + stack.top = stack.top + 1 + stack[stack.top] = { parent = node, node = head} + else + stack.bottom = stack.bottom - 1 + stack[stack.bottom] = { parent = node, node = head} + end + end end end end @@ -525,106 +532,105 @@ function SpanningTreeComputation.computeSpanningTree (ugraph, dfs, events) for i,v in ipairs(tree.vertices) do copy[i] = v end - + -- Now, setup child lists for _,v in ipairs(copy) do -- Children as they come from the spanning tree computation tree:sortOutgoing(v, function (a,b) return a:eventIndex() < b:eventIndex() end) local outgoings = tree:outgoing(v) - + -- Compute children as they come in the event list: local children = {} - + local i = (v.event.index or 0)+1 while i <= #events and events[i].kind == "edge" do i = i + 1 end - + if events[i] and events[i].kind == "begin" and events[i].parameters == "descendants" then -- Ok, the node is followed by a descendants group -- Now scan for nodes that are not inside a descendants group local stop = events[i].end_index local j = i+1 while j <= stop do - if events[j].kind == "node" then - children[#children+1] = events[j].parameters - elseif events[j].kind == "begin" and events[j].parameters == "descendants" then - j = events[j].end_index - end - j = j + 1 + if events[j].kind == "node" then + children[#children+1] = events[j].parameters + elseif events[j].kind == "begin" and events[j].parameters == "descendants" then + j = events[j].end_index + end + j = j + 1 end -- Test, whether outgoings and children contain the same nodes: local function same_elements() - local hash = {} - for v,c in ipairs(outgoings) do - hash[c.head] = true - end - local count = 0 - for _,c in pairs(children) do - if c ~= "" then - count = count + 1 - if not hash[c] or count > #outgoings then - return false - end - end - end - return count == #outgoings + local hash = {} + for v,c in ipairs(outgoings) do + hash[c.head] = true + end + local count = 0 + for _,c in pairs(children) do + if c ~= "" then + count = count + 1 + if not hash[c] or count > #outgoings then + return false + end + end + end + return count == #outgoings end if same_elements() and #outgoings > 0 then - - -- increase number of children, if necessary - local needed = math.max(#children, lib.lookup_option('minimum number of children', v, ugraph)) - for i=1,#children do - if children[i] ~= "" then - local d = children[i].options['desired child index'] - needed = d and math.max(needed, d) or needed - end - end - - local new_children = {} - for i=1,#children do - if children[i] ~= "" then - local d = children[i].options['desired child index'] - if d then - local target = d - - while new_children[target] do - target = 1 + (target % #children) - end - new_children[target] = children[i] - end - end - end - for i=1,#children do - if children[i] ~= "" then - local d = children[i].options['desired child index'] - if not d then - local target = i - - while new_children[target] do - target = 1 + (target % #children) - end - new_children[target] = children[i] - end - end - end - for i=1,needed do - if not new_children[i] then - local new_child = Vertex.new{ kind = "dummy" } - new_children[i] = new_child - tree:add {new_child} - tree:connect(v,new_child) - end - end - - tree:orderOutgoing(v,new_children) + -- increase number of children, if necessary + local needed = math.max(#children, lib.lookup_option('minimum number of children', v, ugraph)) + for i=1,#children do + if children[i] ~= "" then + local d = children[i].options['desired child index'] + needed = d and math.max(needed, d) or needed + end + end + + local new_children = {} + for i=1,#children do + if children[i] ~= "" then + local d = children[i].options['desired child index'] + if d then + local target = d + + while new_children[target] do + target = 1 + (target % #children) + end + new_children[target] = children[i] + end + end + end + for i=1,#children do + if children[i] ~= "" then + local d = children[i].options['desired child index'] + if not d then + local target = i + + while new_children[target] do + target = 1 + (target % #children) + end + new_children[target] = children[i] + end + end + end + for i=1,needed do + if not new_children[i] then + local new_child = Vertex.new{ kind = "dummy" } + new_children[i] = new_child + tree:add {new_child} + tree:connect(v,new_child) + end + end + + tree:orderOutgoing(v,new_children) end end end - + tree.root = root return tree diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/doc.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/doc.lua index 753f386bb9e..169c7ff5e19 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/doc.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/doc.lua @@ -25,49 +25,55 @@ documentation [[ The Reingold--Tilford method is a standard method for drawing trees. It is described in: +% \begin{itemize} -\item - E.~M.\ Reingold and J.~S.\ Tilford, - \newblock Tidier drawings of trees, - \newblock \emph{IEEE Transactions on Software Engineering,} - 7(2), 223--228, 1981. + \item + E.~M.\ Reingold and J.~S.\ Tilford, + \newblock Tidier drawings of trees, + \newblock \emph{IEEE Transactions on Software Engineering,} + 7(2), 223--228, 1981. \end{itemize} +% My implementation in |graphdrawing.trees| follows the following paper, which introduces some nice extensions of the basic algorithm: +% \begin{itemize} -\item - A.\ Br\"uggemann-Klein, D.\ Wood, - \newblock Drawing trees nicely with \TeX, - \emph{Electronic Publishing,} 2(2), 101--115, 1989. + \item + A.\ Br\"uggemann-Klein, D.\ Wood, + \newblock Drawing trees nicely with \TeX, + \emph{Electronic Publishing,} 2(2), 101--115, 1989. \end{itemize} +% As a historical remark, Br\"uggemann-Klein and Wood have implemented their version of the Reingold--Tilford algorithm directly in \TeX\ (resulting in the Tree\TeX\ style). With the power of Lua\TeX\ at our disposal, the 2012 implementation in the |graphdrawing.tree| library is somewhat more powerful and cleaner, but it really was an impressive achievement to implement this algorithm back in 1989 -directly in \TeX. +directly in \TeX. The basic idea of the Reingold--Tilford algorithm is to use the following rules to position the nodes of a tree (the following description assumes that the tree grows downwards, other growth directions are handled by the automatic orientation mechanisms of -the graph drawing library): +the graph drawing library): +% \begin{enumerate} -\item For a node, recursively compute a layout for each of its children. -\item Place the tree rooted at the first child somewhere on the page. -\item Place the tree rooted at the second child to the right of the - first one as near as possible so that no two nodes touch (and such - that the |sibling sep| padding is not violated). -\item Repeat for all subsequent children. -\item Then place the root above the child trees at the middle - position, that is, at the half-way point between the left-most and - the right-most child of the node. + \item For a node, recursively compute a layout for each of its children. + \item Place the tree rooted at the first child somewhere on the page. + \item Place the tree rooted at the second child to the right of the + first one as near as possible so that no two nodes touch (and such + that the |sibling sep| padding is not violated). + \item Repeat for all subsequent children. + \item Then place the root above the child trees at the middle + position, that is, at the half-way point between the left-most and + the right-most child of the node. \end{enumerate} +% The standard keys |level distance|, |level sep|, |sibling distance|, and |sibling sep|, as well as the |pre| and |post| versions of these keys, as taken into consideration when nodes are positioned. See also -Section~\ref{subsection-gd-dist-pad} for details on these keys. +Section~\ref{subsection-gd-dist-pad} for details on these keys. \noindent\textbf{Handling of Missing Children.} As described in Section~\ref{section-gd-missing-children}, you can @@ -76,6 +82,7 @@ space should be reserved for them. This is exactly what happens: When the subtrees of the children of a node are arranged, each position with a missing child is treated as if a zero-width, zero-height subtree were present at that positions: +% \begin{codeexample}[] \tikz [tree layout, nodes={draw,circle}] \node {r} @@ -85,7 +92,9 @@ zero-height subtree were present at that positions: } child[missing]; \end{codeexample} +% or in |graph| syntax: +% \begin{codeexample}[] \tikz \graph [tree layout, nodes={draw,circle}] { @@ -97,31 +106,36 @@ or in |graph| syntax: } }; \end{codeexample} +% More than one child can go missing: +% \begin{codeexample}[] \tikz \graph [tree layout, nodes={draw,circle}, sibling sep=0pt] { r -> { a, , ,b -> {c,d}, ,e} }; \end{codeexample} +% Although missing children are taken into consideration for the computation of the placement of the children of a root node relative to one another and also for the computation of the position of the root node, they are usually \emph{not} considered as part of the ``outline'' of a subtree (the \texttt{minimum number of children} key ensures that |b|, |c|, |e|, and |f| all have a missing right -child): +child): +% \begin{codeexample}[] \tikz \graph [tree layout, minimum number of children=2, nodes={draw,circle}] { a -> { b -> c -> d, e -> f -> g } }; \end{codeexample} +% This behaviour of ``ignoring'' missing children in later stages of -the recursion can be changed using the key |missing nodes get space|. +the recursion can be changed using the key |missing nodes get space|. \noindent\textbf{Significant Pairs of Siblings.} Br\"uggemann-Klein and Wood have proposed an extension of the Reingold--Tilford method that is intended to better highlight the overall structure of a tree. Consider the following two trees: - +% \begin{codeexample}[] \tikz [baseline=(a.base), tree layout, minimum number of children=2, sibling distance=5mm, level distance=5mm] @@ -133,7 +147,8 @@ overall structure of a tree. Consider the following two trees: \graph [nodes={circle, inner sep=0pt, minimum size=2mm, fill, as=}]{ a -- { b -- c -- d -- e, i -- j -- { f -- {g,h}, k } } }; -\end{codeexample} +\end{codeexample} +% As observed by Br\"uggemann-Klein and Wood, the two trees are structurally quite different, but the Reingold--Tilford method places the nodes at exactly the same positions and only one edge @@ -149,6 +164,7 @@ example. A \emph{significant pair} is a pair of siblings where the minimum distance is encountered on any level other than the first level. Thus, in the first example there is no significant pair, while in the second example |a| and |b| form such a pair. +% \begin{codeexample}[] \tikz \graph [tree layout, minimum number of children=2, level distance=5mm, nodes={circle,draw}] @@ -158,6 +174,7 @@ while in the second example |a| and |b| form such a pair. level distance=5mm, nodes={circle,draw}] { / -> { a -> / -> /, b -> / -> / }}; \end{codeexample} +% Whenever the algorithm encounters a significant pair, it adds extra space between the siblings as specified by the |significant sep| key. @@ -190,9 +207,8 @@ key "missing nodes get space" summary [[ -When set to true, missing children are treated as if they -where zero-width, zero-height nodes during the whole tree layout -process. +When set to true, missing children are treated as if they where +zero-width, zero-height nodes during the whole tree layout process. ]] @@ -212,8 +228,10 @@ example key "significant sep" summary -[[ This space is added to signifcant pairs by the modified -Reingold--Tilford algorithm. ]] +[[ +This space is added to significant pairs by the modified +Reingold--Tilford algorithm. +]] example [[ @@ -238,18 +256,22 @@ example key "binary tree layout" summary -[[ A layout based on the Reingold--Tilford method for drawing -binary trees. ]] +[[ +A layout based on the Reingold--Tilford method for drawing +binary trees. +]] documentation [[ This key executes: +% \begin{enumerate} -\item |tree layout|, thereby selecting the Reingold--Tilford method, -\item |minimum number of children=2|, thereby ensuring the all nodes - have (at least) two children or none at all, and -\item |significant sep=10pt| to highlight significant pairs. + \item |tree layout|, thereby selecting the Reingold--Tilford method, + \item |minimum number of children=2|, thereby ensuring the all nodes + have (at least) two children or none at all, and + \item |significant sep=10pt| to highlight significant pairs. \end{enumerate} +% In the examples, the last one is taken from the paper of Br\"uggemann-Klein and Wood. It demonstrates nicely the advantages of having the full power of \tikzname's anchoring and the @@ -270,31 +292,33 @@ example \tikz \graph [binary tree layout] { Knuth -> { Beeton -> Kellermann [second] -> Carnes, - Tobin -> Plass -> { Lamport, Spivak } + Tobin -> Plass -> { Lamport, Spivak } } };\qquad \tikz [>=spaced stealth'] \graph [binary tree layout, grow'=right, level sep=1.5em, nodes={right, fill=blue!50, text=white, chamfered rectangle}, - edges={decorate,decoration={snake, post length=5pt}}] + edges={decorate,decoration={snake, post length=5pt}}] { Knuth -> { Beeton -> Kellermann [second] -> Carnes, - Tobin -> Plass -> { Lamport, Spivak } + Tobin -> Plass -> { Lamport, Spivak } } }; ]] -------------------------------------------------------------------- - + -------------------------------------------------------------------- key "extended binary tree layout" summary -[[ This algorithm is similar to |binary tree layout|, only the +[[ +This algorithm is similar to |binary tree layout|, only the option \texttt{missing nodes get space} is executed and the -\texttt{significant sep} is zero. ]] +\texttt{significant sep} is zero. +]] example [[ @@ -305,5 +329,3 @@ example }; ]] -------------------------------------------------------------------- - - diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/library.lua b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/library.lua index b8e36982cfc..a0019666ac8 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/library.lua +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/trees/library.lua @@ -16,7 +16,7 @@ -- Sections \ref{section-library-graphs} -- and~\ref{section-trees}). The job of the graph drawing algorithms from -- this library is to turn the specification of trees into beautiful --- layouts. +-- layouts. -- -- We start this section with a description of algorithms, then we have a -- look at how missing children can be specified and at what happens when diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex index 61f2e4bed00..cdcd7a54cb3 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.circular.code.tex @@ -11,6 +11,6 @@ \ProvidesFileRCS{pgflibrarygraphdrawing.circular.code.tex} -\usegdlibrary{circular} +\usegdlibrary{circular}% \endinput diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex index c5c4997d627..90ebe0f15af 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.examples.code.tex @@ -9,9 +9,9 @@ \ProvidesFileRCS{pgflibrarygraphdrawing.examples.code.tex} -\usepgflibrary{graphdrawing} +\usepgflibrary{graphdrawing}% -\usegdlibrary{examples} +\usegdlibrary{examples}% \endinput diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex index cd6851466a3..2ffad530012 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.force.code.tex @@ -11,9 +11,9 @@ -\usepgflibrary{graphdrawing} +\usepgflibrary{graphdrawing}% -\usegdlibrary{force} +\usegdlibrary{force}% \endinput @@ -81,7 +81,7 @@ % % Edge parameters for spring algorithms. % -} +}% \pgfgddeclareforwardedkeys{/graph drawing}{ % diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex index 794fff40275..940c8236cf3 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.layered.code.tex @@ -9,9 +9,9 @@ \ProvidesFileRCS{pgflibrarygraphdrawing.layered.code.tex} -\usepgflibrary{graphdrawing} +\usepgflibrary{graphdrawing}% -\usegdlibrary{layered} +\usegdlibrary{layered}% \endinput diff --git a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex index 10231f221ad..87ff6eee233 100644 --- a/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex +++ b/Master/texmf-dist/tex/generic/pgf/graphdrawing/tex/pgflibrarygraphdrawing.trees.code.tex @@ -11,9 +11,9 @@ \ProvidesFileRCS{pgflibrarygraphdrawing.trees.code.tex} -\usepgflibrary{graphdrawing} -\usepgflibrary{graphdrawing.layered} +\usepgflibrary{graphdrawing}% +\usepgflibrary{graphdrawing.layered}% -\usegdlibrary{trees} +\usegdlibrary{trees}% \endinput |