summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/force/jedi/forcetypes/ForceGraphDistance.lua
blob: 628f1192ac0f4db04d0106f3826bafd472197759 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
-- Copyright 2014 by Ida Bruhns
--
-- This file may be distributed and/or modified
--
-- 1. under the LaTeX Project Public License and/or
-- 2. under the GNU Public License
--
-- See the file doc/generic/pgf/licenses/LICENSE for more 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. 


local ForceTemplate = require "pgf.gd.force.jedi.base.ForceTemplate"
local lib = require "pgf.gd.lib"
local Preprocessing = require "pgf.gd.force.jedi.base.Preprocessing"

-- Localize math functions
local max = math.max
local sqrt = math.sqrt
local min = math.min

-- Implementation starts here:

local ForceGraphDistance = lib.class { base_class = ForceTemplate }

function ForceGraphDistance:constructor ()
  ForceTemplate.constructor(self)
  self.p = {}
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. 

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 
-- 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

function ForceGraphDistance:applyTo(data)
  -- locals for speed
  local cap = self.force.cap
  local fun_u = self.force.fun_u
  local fun_v = self.force.fun_v
  local net_forces = data.net_forces
  local t_max = self.options["maximum time"]
  local t_now = data.t_now
  local k = data.k
  local p = self.p
  local time_fun = self.force.time_fun
  local fw_attributes = self.fw_attributes

  -- Evaluate time function
  local time_factor = time_fun(t_max, t_now)
  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
      -- dereference
      local p2 = i.head
      local p1 = i.tail
      local p2_pos = p2.pos
      local p1_pos = p1.pos

      -- calculate distance between two points
      local x = p2_pos.x - p1_pos.x
      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) 
      data.u = p2
      data.v = p1
      data.d = d
      local e = fun_u(data)
      
      -- Include time function
      local f = e * time_factor / d

      -- calculate effect on x/y
      local g = x * f
      local h = y * f

      -- cap effect if necessary
      if cap then
        if g <= 0 then
          x = max(-cap, g)
        else
          x = min(cap, g)
        end
        
        if g <= 0 then
          y = max(-cap, h)
        else
          y = min(cap, h)
        end
      else
        x = g
        y = h
      end

      -- add calculated effect to net forces
      local c1 = net_forces[p1]
      c1.x = c1.x - x
      c1.y = c1.y - y
      local c2 = net_forces[p2]
      c2.x = c2.x + x
      c2.y = c2.y + y
    end
  else
    -- There are different functions for head and tail vertex
    local data = { k = k, attributes = fw_attributes }
    for _, i in ipairs(p) do
      -- dereference
      local p2 = i.head
      local p1 = i.tail
      local p2_pos = p2.pos
      local p1_pos = p1.pos

      -- calculate distance between two points
      local x = p2_pos.x - p1_pos.x
      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
      data.u = p2
      data.v = p1
      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

      -- calculate effect on x/y
      local g_head = x * f_head
      local g_tail = x * f_tail
      local h_head = y * f_head
      local h_tail = y * f_tail

      -- cap effect if necessary
      local x_head, x_tail, y_head, y_tail
      if cap then
        if g_head <= 0 then
          x_head = max(-cap, g_head)
        else
          x_head = min(cap, g_head)
        end

        if g_tail <= 0 then
          x_tail = max(-cap, g_tail)
        else
          x_tail = min(cap, g_tail)
        end
        
        if h_head <= 0 then
          y_head = max(-cap, h_head)
        else
          y_head = min(cap, h_head)
        end

        if h_tail <= 0 then
          y_tail = max(-cap, h_tail)
        else
          y_tail = min(cap, h_tail)
        end
      else
        x_head = g_head
        x_tail = g_tail
        y_head = h_head
        y_tail = h_tail
      end

      -- add calculated effect to net forces
      local c1 = net_forces[p1]
      c1.x = c1.x - x_tail
      c1.y = c1.y - y_tail
      local c2 = net_forces[p2]
      c2.x = c2.x + x_head
      c2.y = c2.y + y_head
    end
  end
end

return ForceGraphDistance