1 /** \file
2 * \brief Implementation of class Multilevel (used by FMMMLayout).
3 *
4 * \author Stefan Hachul
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32
33 #include <ogdf/energybased/fmmm/Multilevel.h>
34 #include <ogdf/energybased/fmmm/Set.h>
35 #include <ogdf/basic/simple_graph_alg.h>
36
37 namespace ogdf {
38 namespace energybased {
39 namespace fmmm {
40
create_multilevel_representations(Graph & G,NodeArray<NodeAttributes> & A,EdgeArray<EdgeAttributes> & E,int rand_seed,FMMMOptions::GalaxyChoice galaxy_choice,int min_Graph_size,int random_tries,Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,int & max_level)41 void Multilevel::create_multilevel_representations(
42 Graph& G,
43 NodeArray<NodeAttributes>& A,
44 EdgeArray<EdgeAttributes>& E,
45 int rand_seed,
46 FMMMOptions::GalaxyChoice galaxy_choice,
47 int min_Graph_size,
48 int random_tries,
49 Array<Graph*> &G_mult_ptr,
50 Array<NodeArray <NodeAttributes>*> &A_mult_ptr,
51 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
52 int & max_level)
53 {
54 setSeed(rand_seed);
55 G_mult_ptr[0] = &G; //init graph at level 0 to the original undirected simple
56 A_mult_ptr[0] = &A; //and loopfree connected graph G/A/E
57 E_mult_ptr[0] = &E;
58
59 int bad_edgenr_counter = 0;
60 int act_level = 0;
61 Graph* act_Graph_ptr = G_mult_ptr[0];
62
63 while( (act_Graph_ptr->numberOfNodes() > min_Graph_size) &&
64 edgenumbersum_of_all_levels_is_linear(G_mult_ptr,act_level,bad_edgenr_counter) )
65 {
66 Graph* G_new = new (Graph);
67 NodeArray<NodeAttributes>* A_new = new NodeArray<NodeAttributes>;
68 EdgeArray<EdgeAttributes>* E_new = new EdgeArray<EdgeAttributes>;
69 G_mult_ptr[act_level+1] = G_new;
70 A_mult_ptr[act_level+1] = A_new;
71 E_mult_ptr[act_level+1] = E_new;
72
73 init_multilevel_values(*G_mult_ptr[act_level], *A_mult_ptr[act_level], *E_mult_ptr[act_level]);
74 partition_galaxy_into_solar_systems(G_mult_ptr,A_mult_ptr,E_mult_ptr,rand_seed,
75 galaxy_choice,random_tries,act_level);
76 collaps_solar_systems(G_mult_ptr,A_mult_ptr,E_mult_ptr,act_level);
77
78 act_level++;
79 act_Graph_ptr = G_mult_ptr[act_level];
80 }
81 max_level = act_level;
82 }
83
84
edgenumbersum_of_all_levels_is_linear(Array<Graph * > & G_mult_ptr,int act_level,int & bad_edgenr_counter)85 bool Multilevel::edgenumbersum_of_all_levels_is_linear(
86 Array<Graph*> &G_mult_ptr,
87 int act_level,
88 int& bad_edgenr_counter)
89 {
90 if(act_level == 0)
91 return true;
92 else
93 {
94 if(G_mult_ptr[act_level]->numberOfEdges()<=
95 0.8 * double (G_mult_ptr[act_level-1]->numberOfEdges()))
96 return true;
97 else if(bad_edgenr_counter < 5)
98 {
99 bad_edgenr_counter++;
100 return true;
101 }
102 return false;
103 }
104 }
105
106
init_multilevel_values(const Graph & G_mult,NodeArray<NodeAttributes> & A_mult,EdgeArray<EdgeAttributes> & E_mult)107 void Multilevel::init_multilevel_values(const Graph &G_mult,
108 NodeArray<NodeAttributes> &A_mult,
109 EdgeArray<EdgeAttributes> &E_mult) {
110 for(node v : G_mult.nodes) {
111 A_mult[v].init_mult_values();
112 }
113
114 for(edge e : G_mult.edges) {
115 E_mult[e].init_mult_values();
116 }
117 }
118
119
partition_galaxy_into_solar_systems(Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,int rand_seed,FMMMOptions::GalaxyChoice galaxy_choice,int random_tries,int act_level)120 inline void Multilevel::partition_galaxy_into_solar_systems(
121 Array<Graph*> &G_mult_ptr,
122 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
123 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
124 int rand_seed,
125 FMMMOptions::GalaxyChoice galaxy_choice,
126 int random_tries,
127 int act_level)
128 {
129 create_suns_and_planets(G_mult_ptr, A_mult_ptr, E_mult_ptr, rand_seed, galaxy_choice,
130 random_tries, act_level);
131 create_moon_nodes_and_pm_nodes(*G_mult_ptr[act_level], *A_mult_ptr[act_level], *E_mult_ptr[act_level]);
132 }
133
134
create_suns_and_planets(Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,int rand_seed,FMMMOptions::GalaxyChoice galaxy_choice,int random_tries,int act_level)135 void Multilevel::create_suns_and_planets(
136 Array<Graph*> &G_mult_ptr,
137 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
138 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
139 int rand_seed,
140 FMMMOptions::GalaxyChoice galaxy_choice,
141 int random_tries,
142 int act_level)
143 {
144 Set Node_Set;
145 List<node> planet_nodes;
146 List<node> sun_nodes;
147
148 //make initialisations
149 sun_nodes.clear();
150 Node_Set.set_seed(rand_seed); //set seed for random number generator
151
152 for (node v : G_mult_ptr[act_level]->nodes)
153 if (act_level == 0)
154 (*A_mult_ptr[act_level])[v].set_mass(1);
155 switch (galaxy_choice) {
156 case FMMMOptions::GalaxyChoice::UniformProb:
157 Node_Set.init_node_set(*G_mult_ptr[act_level]);
158 break;
159 case FMMMOptions::GalaxyChoice::NonUniformProbLowerMass:
160 case FMMMOptions::GalaxyChoice::NonUniformProbHigherMass:
161 Node_Set.init_node_set(*G_mult_ptr[act_level], *A_mult_ptr[act_level]);
162 }
163
164 while (!Node_Set.empty_node_set()) {
165 //randomly select a sun node
166 planet_nodes.clear();
167 node sun_node = nullptr;
168 switch (galaxy_choice) {
169 case FMMMOptions::GalaxyChoice::UniformProb:
170 sun_node = Node_Set.get_random_node();
171 break;
172 case FMMMOptions::GalaxyChoice::NonUniformProbLowerMass:
173 sun_node = Node_Set.get_random_node_with_lowest_star_mass(random_tries);
174 break;
175 case FMMMOptions::GalaxyChoice::NonUniformProbHigherMass:
176 sun_node = Node_Set.get_random_node_with_highest_star_mass(random_tries);
177 break;
178 }
179 sun_nodes.pushBack(sun_node);
180
181 //create new node at higher level that represents the collapsed solar_system
182 node newNode = G_mult_ptr[act_level + 1]->newNode();
183
184 //update information for sun_node
185 (*A_mult_ptr[act_level])[sun_node].set_higher_level_node(newNode);
186 (*A_mult_ptr[act_level])[sun_node].set_type(1);
187 (*A_mult_ptr[act_level])[sun_node].set_dedicated_sun_node(sun_node);
188 (*A_mult_ptr[act_level])[sun_node].set_dedicated_sun_distance(0);
189
190 //update information for planet_nodes
191 for(adjEntry adj : sun_node->adjEntries) {
192 edge sun_edge = adj->theEdge();
193 double dist_to_sun = (*E_mult_ptr[act_level])[sun_edge].get_length();
194 node planet_node;
195 if (sun_edge->source() != sun_node)
196 planet_node = sun_edge->source();
197 else
198 planet_node = sun_edge->target();
199 (*A_mult_ptr[act_level])[planet_node].set_type(2);
200 (*A_mult_ptr[act_level])[planet_node].set_dedicated_sun_node(sun_node);
201 (*A_mult_ptr[act_level])[planet_node].set_dedicated_sun_distance(dist_to_sun);
202 planet_nodes.pushBack(planet_node);
203 }
204
205 //delete all planet_nodes and possible_moon_nodes from Node_Set
206
207 for (node planet_node : planet_nodes)
208 if (!Node_Set.is_deleted(planet_node))
209 Node_Set.delete_node(planet_node);
210
211 for (node planet_node : planet_nodes)
212 {
213 for(adjEntry adj : planet_node->adjEntries) {
214 edge e = adj->theEdge();
215
216 node pos_moon_node = (e->source() == planet_node) ? e->target() : e->source();
217 if (!Node_Set.is_deleted(pos_moon_node))
218 Node_Set.delete_node(pos_moon_node);
219 }
220 }
221 }
222
223 //init *A_mult_ptr[act_level+1] and set NodeAttributes information for new nodes
224 A_mult_ptr[act_level + 1]->init(*G_mult_ptr[act_level + 1]);
225 for (node sun_node : sun_nodes)
226 {
227 node newNode = (*A_mult_ptr[act_level])[sun_node].get_higher_level_node();
228 (*A_mult_ptr[act_level + 1])[newNode].set_NodeAttributes(
229 (*A_mult_ptr[act_level])[sun_node].get_width(),
230 (*A_mult_ptr[act_level])[sun_node].get_height(),
231 (*A_mult_ptr[act_level])[sun_node].get_position(),
232 sun_node, nullptr);
233 (*A_mult_ptr[act_level + 1])[newNode].set_mass(0);
234 }
235 }
236
237
create_moon_nodes_and_pm_nodes(const Graph & G_mult,NodeArray<NodeAttributes> & A_mult,EdgeArray<EdgeAttributes> & E_mult)238 void Multilevel::create_moon_nodes_and_pm_nodes(const Graph &G_mult,
239 NodeArray<NodeAttributes> &A_mult,
240 EdgeArray<EdgeAttributes> &E_mult)
241 {
242 for (node v : G_mult.nodes) {
243 if (A_mult[v].get_type() == 0) { // a moon node
244 node nearest_neighbour_node = nullptr;
245 double dist_to_nearest_neighbour(0);
246 edge moon_edge = nullptr;
247
248 // find nearest neighbour node
249 for (adjEntry adj : v->adjEntries) {
250 edge e = adj->theEdge();
251 node neighbour_node = (v == e->source()) ? e->target() : e->source();
252 int neighbour_type = A_mult[neighbour_node].get_type();
253 const double dist = E_mult[e].get_length();
254 if ((neighbour_type == 2
255 || neighbour_type == 3)
256 && (nearest_neighbour_node == nullptr
257 || dist_to_nearest_neighbour > dist)) {
258 moon_edge = e;
259 dist_to_nearest_neighbour = dist;
260 nearest_neighbour_node = neighbour_node;
261 }
262 }
263 // find dedic. solar system for v and update information
264 // in A_mult and E_mult
265
266 OGDF_ASSERT(nearest_neighbour_node != nullptr);
267 E_mult[moon_edge].make_moon_edge(); //mark this edge
268 node dedicated_sun_node = A_mult[nearest_neighbour_node].get_dedicated_sun_node();
269 double dedicated_sun_distance = dist_to_nearest_neighbour
270 + A_mult[nearest_neighbour_node].get_dedicated_sun_distance();
271 A_mult[v].set_type(4);
272 A_mult[v].set_dedicated_sun_node(dedicated_sun_node);
273 A_mult[v].set_dedicated_sun_distance(dedicated_sun_distance);
274 A_mult[v].set_dedicated_pm_node(nearest_neighbour_node);
275
276 // identify nearest_neighbour_node as a pm_node and update its information
277 A_mult[nearest_neighbour_node].set_type(3);
278 A_mult[nearest_neighbour_node].get_dedicated_moon_node_List_ptr()->pushBack(v);
279 }
280 }
281 }
282
283
collaps_solar_systems(Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,int act_level)284 inline void Multilevel::collaps_solar_systems(
285 Array<Graph*> &G_mult_ptr,
286 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
287 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
288 int act_level)
289 {
290 EdgeArray<double> new_edgelength;
291 calculate_mass_of_collapsed_nodes(G_mult_ptr, A_mult_ptr, act_level);
292 create_edges_edgedistances_and_lambda_Lists(G_mult_ptr, A_mult_ptr, E_mult_ptr,
293 new_edgelength, act_level);
294 delete_parallel_edges_and_update_edgelength(G_mult_ptr, E_mult_ptr, new_edgelength,
295 act_level);
296 }
297
298
calculate_mass_of_collapsed_nodes(Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,int act_level)299 void Multilevel::calculate_mass_of_collapsed_nodes(
300 Array<Graph*> &G_mult_ptr,
301 Array<NodeArray <NodeAttributes>*> &A_mult_ptr,
302 int act_level)
303 {
304 for (node v : G_mult_ptr[act_level]->nodes)
305 {
306 node dedicated_sun = (*A_mult_ptr[act_level])[v].get_dedicated_sun_node();
307 node high_level_node = (*A_mult_ptr[act_level])[dedicated_sun].get_higher_level_node();
308 (*A_mult_ptr[act_level + 1])[high_level_node].set_mass((*A_mult_ptr[act_level + 1])
309 [high_level_node].get_mass() + 1);
310 }
311 }
312
313
create_edges_edgedistances_and_lambda_Lists(Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,EdgeArray<double> & new_edgelength,int act_level)314 void Multilevel::create_edges_edgedistances_and_lambda_Lists(
315 Array<Graph*> &G_mult_ptr,
316 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
317 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
318 EdgeArray<double>& new_edgelength, int
319 act_level)
320 {
321 edge e_new;
322 List<edge> inter_solar_system_edges;
323
324 //create new edges at act_level+1 and create for each inter solar system edge at
325 //act_level a link to its corresponding edge
326
327 for (edge e : G_mult_ptr[act_level]->edges) {
328 node s_node = e->source();
329 node t_node = e->target();
330 node s_sun_node = (*A_mult_ptr[act_level])[s_node].get_dedicated_sun_node();
331 node t_sun_node = (*A_mult_ptr[act_level])[t_node].get_dedicated_sun_node();
332 if (s_sun_node != t_sun_node) //a inter solar system edge
333 {
334 node high_level_sun_s = (*A_mult_ptr[act_level])[s_sun_node].get_higher_level_node();
335 node high_level_sun_t = (*A_mult_ptr[act_level])[t_sun_node].get_higher_level_node();
336
337 //create new edge in *G_mult_ptr[act_level+1]
338 e_new = G_mult_ptr[act_level + 1]->newEdge(high_level_sun_s, high_level_sun_t);
339 (*E_mult_ptr[act_level])[e].set_higher_level_edge(e_new);
340 inter_solar_system_edges.pushBack(e);
341 }
342 }
343
344 //init new_edgelength calculate the values of new_edgelength and the lambda Lists
345
346 new_edgelength.init(*G_mult_ptr[act_level + 1]);
347 for (edge e : inter_solar_system_edges) {
348 node s_node = e->source();
349 node t_node = e->target();
350 node s_sun_node = (*A_mult_ptr[act_level])[s_node].get_dedicated_sun_node();
351 node t_sun_node = (*A_mult_ptr[act_level])[t_node].get_dedicated_sun_node();
352 double length_e = (*E_mult_ptr[act_level])[e].get_length();
353 double length_s_edge = (*A_mult_ptr[act_level])[s_node].get_dedicated_sun_distance();
354 double length_t_edge = (*A_mult_ptr[act_level])[t_node].get_dedicated_sun_distance();
355 double newlength = length_s_edge + length_e + length_t_edge;
356
357 //set new edge_length in *G_mult_ptr[act_level+1]
358 e_new = (*E_mult_ptr[act_level])[e].get_higher_level_edge();
359 new_edgelength[e_new] = newlength;
360
361 //create entries in lambda Lists
362 double lambda_s = length_s_edge / newlength;
363 double lambda_t = length_t_edge / newlength;
364 (*A_mult_ptr[act_level])[s_node].get_lambda_List_ptr()->pushBack(lambda_s);
365 (*A_mult_ptr[act_level])[t_node].get_lambda_List_ptr()->pushBack(lambda_t);
366 (*A_mult_ptr[act_level])[s_node].get_neighbour_sun_node_List_ptr()->pushBack(t_sun_node);
367 (*A_mult_ptr[act_level])[t_node].get_neighbour_sun_node_List_ptr()->pushBack(s_sun_node);
368 }
369 }
370
delete_parallel_edges_and_update_edgelength(Array<Graph * > & G_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,EdgeArray<double> & new_edgelength,int act_level)371 void Multilevel::delete_parallel_edges_and_update_edgelength(
372 Array<Graph*> &G_mult_ptr,
373 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
374 EdgeArray<double>& new_edgelength, int
375 act_level)
376 {
377 EdgeMaxBucketFunc get_max_index;
378 EdgeMinBucketFunc get_min_index;
379 edge e_save;
380 Edge f_act;
381 List<Edge> sorted_edges;
382 Graph* Graph_ptr = G_mult_ptr[act_level + 1];
383 int save_s_index, save_t_index;
384 int counter = 1;
385
386 //make *G_mult_ptr[act_level+1] undirected
387 makeSimpleUndirected(*G_mult_ptr[act_level + 1]);
388
389 //sort the List sorted_edges
390 for (edge e_act : Graph_ptr->edges)
391 {
392 f_act.set_Edge(e_act, Graph_ptr);
393 sorted_edges.pushBack(f_act);
394 }
395
396 sorted_edges.bucketSort(0, Graph_ptr->numberOfNodes() - 1, get_max_index);
397 sorted_edges.bucketSort(0, Graph_ptr->numberOfNodes() - 1, get_min_index);
398
399 //now parallel edges are consecutive in sorted_edges
400 bool firstEdge = true;
401 for (const Edge &ei : sorted_edges) {
402 edge e_act = ei.get_edge();
403 int act_s_index = e_act->source()->index();
404 int act_t_index = e_act->target()->index();
405
406 if (!firstEdge)
407 {
408 if ((act_s_index == save_s_index && act_t_index == save_t_index) ||
409 (act_s_index == save_t_index && act_t_index == save_s_index))
410 {
411 new_edgelength[e_save] += new_edgelength[e_act];
412 Graph_ptr->delEdge(e_act);
413 counter++;
414 } else {
415 if (counter > 1)
416 {
417 new_edgelength[e_save] /= counter;
418 counter = 1;
419 }
420 save_s_index = act_s_index;
421 save_t_index = act_t_index;
422 e_save = e_act;
423 }
424 } else { //first edge
425 firstEdge = false;
426 save_s_index = act_s_index;
427 save_t_index = act_t_index;
428 e_save = e_act;
429 }
430 }
431
432 //treat special case (last edges were multiple edges)
433 if (counter > 1)
434 new_edgelength[e_save] /= counter;
435
436 //init *E_mult_ptr[act_level+1] and import EdgeAttributes
437 E_mult_ptr[act_level + 1]->init(*G_mult_ptr[act_level + 1]);
438 for (edge e_act : Graph_ptr->edges)
439 (*E_mult_ptr[act_level + 1])[e_act].set_length(new_edgelength[e_act]);
440 }
441
442
find_initial_placement_for_level(int level,FMMMOptions::InitialPlacementMult init_placement_way,Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr)443 void Multilevel::find_initial_placement_for_level(
444 int level,
445 FMMMOptions::InitialPlacementMult init_placement_way,
446 Array<Graph*> &G_mult_ptr,
447 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
448 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr)
449 {
450 List<node> pm_nodes;
451 set_initial_positions_of_sun_nodes(level, G_mult_ptr, A_mult_ptr);
452 set_initial_positions_of_planet_and_moon_nodes(level, init_placement_way, G_mult_ptr,
453 A_mult_ptr, E_mult_ptr, pm_nodes);
454 set_initial_positions_of_pm_nodes(level, init_placement_way, A_mult_ptr,
455 E_mult_ptr, pm_nodes);
456 }
457
458
set_initial_positions_of_sun_nodes(int level,Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr)459 void Multilevel::set_initial_positions_of_sun_nodes(
460 int level,
461 Array<Graph*> &G_mult_ptr,
462 Array<NodeArray <NodeAttributes>*> &A_mult_ptr)
463 {
464 for (node v_high : G_mult_ptr[level + 1]->nodes)
465 {
466 node v_act = (*A_mult_ptr[level + 1])[v_high].get_lower_level_node();
467 DPoint new_pos = (*A_mult_ptr[level + 1])[v_high].get_position();
468 (*A_mult_ptr[level])[v_act].set_position(new_pos);
469 (*A_mult_ptr[level])[v_act].place();
470 }
471 }
472
473
set_initial_positions_of_planet_and_moon_nodes(int level,FMMMOptions::InitialPlacementMult init_placement_way,Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,List<node> & pm_nodes)474 void Multilevel::set_initial_positions_of_planet_and_moon_nodes(
475 int level,
476 FMMMOptions::InitialPlacementMult init_placement_way,
477 Array<Graph*> &G_mult_ptr,
478 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
479 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
480 List<node>& pm_nodes)
481 {
482 DPoint new_pos;
483 List<DPoint> L;
484
485 create_all_placement_sectors(G_mult_ptr, A_mult_ptr, E_mult_ptr, level);
486 for (node v : G_mult_ptr[level]->nodes)
487 {
488 int node_type = (*A_mult_ptr[level])[v].get_type();
489 if (node_type == 3)
490 pm_nodes.pushBack(v);
491 else if (node_type == 2 || node_type == 4) //a planet_node or moon_node
492 {
493 L.clear();
494 node dedicated_sun = (*A_mult_ptr[level])[v].get_dedicated_sun_node();
495 DPoint dedicated_sun_pos = (*A_mult_ptr[level])[dedicated_sun].get_position();
496 double dedicated_sun_distance = (*A_mult_ptr[level])[v].get_dedicated_sun_distance();
497
498 switch (init_placement_way) {
499 case FMMMOptions::InitialPlacementMult::Simple:
500 break;
501 case FMMMOptions::InitialPlacementMult::Advanced:
502 for(adjEntry adj : v->adjEntries) {
503 edge e = adj->theEdge();
504 node v_adj = (e->source() != v) ? e->source() : e->target();
505 if (((*A_mult_ptr[level])[v].get_dedicated_sun_node() ==
506 (*A_mult_ptr[level])[v_adj].get_dedicated_sun_node()) &&
507 ((*A_mult_ptr[level])[v_adj].get_type() != 1) &&
508 ((*A_mult_ptr[level])[v_adj].is_placed()))
509 {
510 new_pos = calculate_position(dedicated_sun_pos, (*A_mult_ptr[level])
511 [v_adj].get_position(), dedicated_sun_distance,
512 (*E_mult_ptr[level])[e].get_length());
513 L.pushBack(new_pos);
514 }
515 }
516 }
517 if ((*A_mult_ptr[level])[v].get_lambda_List_ptr()->empty())
518 {//special case
519 if (L.empty())
520 {
521 new_pos = create_random_pos(dedicated_sun_pos, (*A_mult_ptr[level])
522 [v].get_dedicated_sun_distance(),
523 (*A_mult_ptr[level])[v].get_angle_1(),
524 (*A_mult_ptr[level])[v].get_angle_2());
525 L.pushBack(new_pos);
526 }
527 } else { // usual case
528 ListIterator<double> lambdaIterator = (*A_mult_ptr[level])[v].get_lambda_List_ptr()->begin();
529
530 for (node adj_sun : *(*A_mult_ptr[level])[v].get_neighbour_sun_node_List_ptr())
531 {
532 double lambda = *lambdaIterator;
533 DPoint adj_sun_pos = (*A_mult_ptr[level])[adj_sun].get_position();
534 new_pos = get_waggled_inbetween_position(dedicated_sun_pos, adj_sun_pos, lambda);
535 L.pushBack(new_pos);
536 if (lambdaIterator != (*A_mult_ptr[level])[v].get_lambda_List_ptr()->rbegin())
537 lambdaIterator = (*A_mult_ptr[level])[v].get_lambda_List_ptr()->cyclicSucc(lambdaIterator);
538 }
539 }
540
541 (*A_mult_ptr[level])[v].set_position(get_barycenter_position(L));
542 (*A_mult_ptr[level])[v].place();
543 }
544 }
545 }
546
547
create_all_placement_sectors(Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,int level)548 void Multilevel::create_all_placement_sectors(
549 Array<Graph*> &G_mult_ptr,
550 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
551 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
552 int level)
553 {
554 for(node v_high : G_mult_ptr[level+1]->nodes) {
555 double angle_1(0), angle_2(0);
556 //find pos of adjacent nodes
557 List<DPoint> adj_pos;
558 DPoint v_high_pos((*A_mult_ptr[level+1])[v_high].get_x(), (*A_mult_ptr[level+1])[v_high].get_y());
559
560 for(adjEntry adj : v_high->adjEntries) {
561 edge e_high = adj->theEdge();
562
563 if (!(*E_mult_ptr[level+1])[e_high].is_extra_edge()) {
564 node w_high;
565 if (v_high == e_high->source())
566 w_high = e_high->target();
567 else
568 w_high = e_high->source();
569
570 DPoint w_high_pos ((*A_mult_ptr[level+1])[w_high].get_x(),
571 (*A_mult_ptr[level+1])[w_high].get_y());
572 adj_pos.pushBack(w_high_pos);
573 }
574 }
575 const DPoint x_parallel_pos(v_high_pos.m_x + 1, v_high_pos.m_y);
576 if (adj_pos.empty()) { //easy case
577 angle_2 = 2.0 * Math::pi;
578 } else if (adj_pos.size() == 1) { //special case
579 angle_1 = v_high_pos.angle(x_parallel_pos, *adj_pos.begin());
580 angle_2 = angle_1 + Math::pi;
581 } else { //usual case
582 const int MAX = 10; //the biggest of at most MAX random selected sectors is choosen
583 int steps = 1;
584 ListIterator<DPoint> it = adj_pos.begin();
585 do {
586 double act_angle_1 = v_high_pos.angle(x_parallel_pos, *it);
587 double min_next_angle = std::numeric_limits<double>::max();
588 for (const auto &next_pos : adj_pos) {
589 if (*it != next_pos) {
590 Math::updateMin(min_next_angle, v_high_pos.angle(*it, next_pos));
591 }
592 }
593 OGDF_ASSERT(min_next_angle < std::numeric_limits<double>::max());
594
595 if ((it == adj_pos.begin())
596 || (min_next_angle > angle_2 - angle_1)) {
597 angle_1 = act_angle_1;
598 angle_2 = act_angle_1 + min_next_angle;
599 }
600 if (it.valid() && it.succ().valid())
601 it = adj_pos.cyclicSucc(it);
602 steps++;
603 } while (steps <= MAX && it.valid() && it.succ().valid());
604
605 if (angle_1 == angle_2)
606 angle_2 = angle_1 + Math::pi;
607 }
608
609 //import angle_1 and angle_2 to the dedicated suns at level level
610 node sun_node = (*A_mult_ptr[level+1])[v_high].get_lower_level_node();
611 (*A_mult_ptr[level])[sun_node].set_angle_1(angle_1);
612 (*A_mult_ptr[level])[sun_node].set_angle_2(angle_2);
613 }
614
615 //import the angle values from the values of the dedicated sun nodes
616 for(node v : G_mult_ptr[level]->nodes)
617 {
618 node ded_sun = (*A_mult_ptr[level])[v].get_dedicated_sun_node();
619 (*A_mult_ptr[level])[v].set_angle_1((*A_mult_ptr[level])[ded_sun].get_angle_1());
620 (*A_mult_ptr[level])[v].set_angle_2((*A_mult_ptr[level])[ded_sun].get_angle_2());
621 }
622 }
623
624
set_initial_positions_of_pm_nodes(int level,FMMMOptions::InitialPlacementMult init_placement_way,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,List<node> & pm_nodes)625 void Multilevel::set_initial_positions_of_pm_nodes(
626 int level,
627 FMMMOptions::InitialPlacementMult init_placement_way,
628 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
629 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
630 List<node>& pm_nodes)
631 {
632 double moon_dist, lambda;
633 node v_adj, sun_node;
634 DPoint sun_pos, moon_pos, new_pos, adj_sun_pos;
635 List<DPoint> L;
636 ListIterator<double> lambdaIterator;
637
638 for (node v : pm_nodes) {
639 L.clear();
640 sun_node = (*A_mult_ptr[level])[v].get_dedicated_sun_node();
641 sun_pos = (*A_mult_ptr[level])[sun_node].get_position();
642 double sun_dist = (*A_mult_ptr[level])[v].get_dedicated_sun_distance();
643
644 switch (init_placement_way) {
645 case FMMMOptions::InitialPlacementMult::Simple:
646 break;
647 case FMMMOptions::InitialPlacementMult::Advanced:
648 for(adjEntry adj : v->adjEntries) {
649 edge e = adj->theEdge();
650
651 if(e->source() != v)
652 v_adj = e->source();
653 else
654 v_adj = e->target();
655 if( (!(*E_mult_ptr[level])[e].is_moon_edge()) &&
656 ( (*A_mult_ptr[level])[v].get_dedicated_sun_node() ==
657 (*A_mult_ptr[level])[v_adj].get_dedicated_sun_node() ) &&
658 ( (*A_mult_ptr[level])[v_adj].get_type() != 1 ) &&
659 ( (*A_mult_ptr[level])[v_adj].is_placed() ) )
660 {
661 new_pos = calculate_position(sun_pos,(*A_mult_ptr[level])[v_adj].
662 get_position(),sun_dist,(*E_mult_ptr[level])
663 [e].get_length());
664 L.pushBack(new_pos);
665 }
666 }
667 }
668 for(node moon_node : *(*A_mult_ptr[level])[v].get_dedicated_moon_node_List_ptr())
669 {
670 moon_pos = (*A_mult_ptr[level])[moon_node].get_position();
671 moon_dist = (*A_mult_ptr[level])[moon_node].get_dedicated_sun_distance();
672 lambda = sun_dist/moon_dist;
673 new_pos = get_waggled_inbetween_position(sun_pos,moon_pos,lambda);
674 L.pushBack(new_pos);
675 }
676
677 if (!(*A_mult_ptr[level])[v].get_lambda_List_ptr()->empty())
678 {
679 lambdaIterator = (*A_mult_ptr[level])[v].get_lambda_List_ptr()->begin();
680
681 for(node adj_sun : *(*A_mult_ptr[level])[v].get_neighbour_sun_node_List_ptr())
682 {
683 lambda = *lambdaIterator;
684 adj_sun_pos = (*A_mult_ptr[level])[adj_sun].get_position();
685 new_pos = get_waggled_inbetween_position(sun_pos,adj_sun_pos,lambda);
686 L.pushBack(new_pos);
687 if(lambdaIterator != (*A_mult_ptr[level])[v].get_lambda_List_ptr()->rbegin())
688 lambdaIterator = (*A_mult_ptr[level])[v].get_lambda_List_ptr()->cyclicSucc(lambdaIterator);
689 }
690 }
691
692 (*A_mult_ptr[level])[v].set_position(get_barycenter_position(L));
693 (*A_mult_ptr[level])[v].place();
694 }
695 }
696
create_random_pos(DPoint center,double radius,double angle_1,double angle_2)697 inline DPoint Multilevel::create_random_pos(DPoint center,double radius,double angle_1,
698 double angle_2)
699 {
700 const int BILLION = 1000000000;
701 DPoint new_point;
702 double rnd = double(randomNumber(1,BILLION)+1)/(BILLION+2);//rand number in (0,1)
703 double rnd_angle = angle_1 +(angle_2-angle_1)*rnd;
704 double dx = cos(rnd_angle) * radius;
705 double dy = sin(rnd_angle) * radius;
706 new_point.m_x = center.m_x + dx ;
707 new_point.m_y = center.m_y + dy;
708 return new_point;
709 }
710
711
get_waggled_inbetween_position(DPoint s,DPoint t,double lambda)712 inline DPoint Multilevel::get_waggled_inbetween_position(DPoint s, DPoint t, double lambda)
713 {
714 const double WAGGLEFACTOR = 0.05;
715 const int BILLION = 1000000000;
716 DPoint inbetween_point;
717 inbetween_point.m_x = s.m_x + lambda*(t.m_x - s.m_x);
718 inbetween_point.m_y = s.m_y + lambda*(t.m_y - s.m_y);
719 double radius = WAGGLEFACTOR * (t-s).norm();
720 double rnd = double(randomNumber(1,BILLION)+1)/(BILLION+2);//rand number in (0,1)
721 double rand_radius = radius * rnd;
722 return create_random_pos(inbetween_point,rand_radius,0,2.0*Math::pi);
723 }
724
725
get_barycenter_position(List<DPoint> & L)726 inline DPoint Multilevel::get_barycenter_position(List<DPoint>& L)
727 {
728 DPoint sum (0,0);
729 DPoint barycenter;
730
731 for(const DPoint &act_point : L)
732 sum = sum + act_point;
733 barycenter.m_x = sum.m_x/L.size();
734 barycenter.m_y = sum.m_y/L.size();
735 return barycenter;
736 }
737
738
calculate_position(DPoint P,DPoint Q,double dist_P,double dist_Q)739 inline DPoint Multilevel::calculate_position(DPoint P, DPoint Q, double dist_P, double dist_Q)
740 {
741 double dist_PQ = (P-Q).norm();
742 double lambda = (dist_P + (dist_PQ - dist_P - dist_Q)/2)/dist_PQ;
743 return get_waggled_inbetween_position(P,Q,lambda);
744 }
745
746
delete_multilevel_representations(Array<Graph * > & G_mult_ptr,Array<NodeArray<NodeAttributes> * > & A_mult_ptr,Array<EdgeArray<EdgeAttributes> * > & E_mult_ptr,int max_level)747 void Multilevel::delete_multilevel_representations(
748 Array<Graph*> &G_mult_ptr,
749 Array<NodeArray<NodeAttributes>*> &A_mult_ptr,
750 Array<EdgeArray<EdgeAttributes>*> &E_mult_ptr,
751 int max_level)
752 {
753 for(int i=1; i<= max_level; i++)
754 {
755 delete G_mult_ptr[i];
756 delete A_mult_ptr[i];
757 delete E_mult_ptr[i];
758 }
759 }
760
761 }
762 }
763 }
764