Current File : //usr/share/texlive/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/deprecated/Edge.lua |
-- Copyright 2010 by Renée Ahrens, Olof Frahm, Jens Kluttig, Matthias Schulz, Stephan Schuster
-- Copyright 2011 by Jannis Pohlmann
-- Copyright 2012 by Till Tantau
--
-- This file may be distributed an/or modified
--
-- 1. under the LaTeX Project Public License and/or
-- 2. under the GNU Public License
--
-- See the file doc/generic/pgf/licenses/LICENSE for more information
-- @release $Header$
--- The Edge class
--
--
local Edge = {}
Edge.__index = Edge
-- Namespace
local lib = require "pgf.gd.lib"
-- Definitions
Edge.UNDIRECTED = "--"
Edge.LEFT = "<-"
Edge.RIGHT = "->"
Edge.BOTH = "<->"
Edge.NONE = "-!-"
--- Creates an edge between nodes of a graph.
--
-- @param values Values to override default edge settings.
-- The following parameters can be set:\par
-- |nodes|: TODO \par
-- |edge_nodes|: TODO \par
-- |options|: TODO \par
-- |tikz_options|: TODO \par
-- |direction|: TODO \par
-- |bend_points|: TODO \par
-- |bend_nodes|: TODO \par
-- |reversed|: TODO \par
--
-- @return A newly-allocated edge.
--
function Edge.new(values)
local defaults = {
nodes = {},
edge_nodes = '',
options = {},
tikz_options = {},
direction = Edge.DIRECTED,
bend_points = {},
bend_nodes = {},
reversed = false,
algorithmically_generated_options = {},
index = nil,
event_index = nil,
}
setmetatable(defaults, Edge)
if values then
for k,v in pairs(values) do
defaults[k] = v
end
end
return defaults
end
--- Sets the edge option \meta{name} to \meta{value}.
--
-- @param name Name of the option to be changed.
-- @param value New value for the edge option \meta{name}.
--
function Edge:setOption(name, value)
self.options[name] = value
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,
-- 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)
end
--- Checks whether or not the edge is a loop edge.
--
-- An edge is a loop if it one node multiple times and no other node.
--
-- @return |true| if the edge is a loop, |false| otherwise.
--
function Edge:isLoop()
local nodes = self.nodes
for i=1,#nodes do
if nodes[i] ~= nodes[1] then
return false
end
end
return true
end
--- Returns whether or not the edge is a hyperedge.
--
-- A hyperedge is an edge with more than two adjacent nodes.
--
-- @return |true| if the edge is a hyperedge. |false| otherwise.
--
function Edge:isHyperedge()
return self:getDegree() > 2
end
--- Returns all nodes of the edge.
--
-- Instead of calling |edge:getNodes()| the nodes can alternatively be
-- accessed directly with |edge.nodes|.
--
-- @return All edges of the node.
--
function Edge:getNodes()
return self.nodes
end
--- Returns whether or not a node is adjacent to the edge.
--
-- @param node The node to check.
--
-- @return |true| if the node is adjacent to the edge. |false| otherwise.
--
function Edge:containsNode(node)
return lib.find(self.nodes, function (other) return other == node end) ~= nil
end
--- If possible, adds a node to the edge.
--
-- @param node The node to be added to the edge.
--
function Edge:addNode(node)
table.insert(self.nodes, node)
node:addEdge(self)
end
--- Gets first neighbor of the node (disregarding hyperedges).
--
-- @param node The node which first neighbor should be returned.
--
-- @return The first neighbor of the node.
--
function Edge:getNeighbour(node)
if node == self.nodes[1] then
return self.nodes[#self.nodes]
else
return self.nodes[1]
end
end
--- Counts the nodes on this edge.
--
-- @return The number of nodes on the edge.
--
function Edge:getDegree()
return #self.nodes
end
function Edge:getHead()
-- by default, the head of -> edges is the last node and the head
-- 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
-- tail positions
if self.reversed then
head_index = (head_index == 1) and #self.nodes or 1
end
return self.nodes[head_index]
end
function Edge:getTail()
-- 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
-- if the edge should be assumed reversed, we simply switch head
-- and tail positions
if self.reversed then
tail_index = (tail_index == 1) and #self.nodes or 1
end
return self.nodes[tail_index]
end
--- Checks whether a node is the head of the edge. Does not work for hyperedges.
--
-- 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
-- which is |false| by default.
--
-- @param node The node to check.
--
-- @return True if the node is the head of the edge.
--
function Edge:isHead(node)
local result = false
-- by default, the head of -> edges is the last node and the head
-- 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
-- tail positions
if self.reversed then
head_index = (head_index == 1) and #self.nodes or 1
end
-- check if the head node equals the input node
if self.nodes[head_index].name == node.name then
result = true
end
return result
end
--- Checks whether a node is the tail of the edge. Does not work for hyperedges.
--
-- 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
-- which is |false| by default.
--
-- @param node The node to check.
-- @param ignore_reversed Optional parameter. Set this to true if reversed edges
-- should not be considered reversed for this method call.
--
-- @return True if the node is the tail of the edge.
--
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
-- if the edge should be assumed reversed, we simply switch head
-- and tail positions
if self.reversed then
tail_index = (tail_index == 1) and #self.nodes or 1
end
-- check if the tail node equals the input node
if self.nodes[tail_index].name == node.name then
result = true
end
return result
end
--- Copies an edge (preventing accidental use).
--
-- The nodes of the edge are not preserved and have to be added
-- to the copy manually if necessary.
--
-- @return Shallow copy of the edge.
--
function Edge:copy()
local result = lib.copy(self, Edge.new())
result.nodes = {}
return result
end
local function reverse_values(source)
local copy = {}
for i = 1,#source do
copy[i] = source[#source-i+1]
end
return copy
end
--- Returns a readable string representation of the edge.
--
-- @ignore This should not appear in the documentation.
--
-- @return String representation of the edge.
--
function Edge:__tostring()
local result = "Edge(" .. self.direction .. ", reversed = " .. tostring(self.reversed) .. ", "
if #self.nodes > 0 then
local node_strings = lib.imap(self.nodes, function (node) return node.name end)
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:
--
local node_strings = lib.imap(self.nodes, function (node) return node.name end)
if self.reversed then
return table.concat(reverse_values(node_strings), ' ' .. self.direction .. ' ')
else
return table.concat(node_strings, ' ' .. self.direction .. ' ')
end
end
-- Done
return Edge