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