Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
DTreeEmbedder.h
Go to the documentation of this file.
1
29#pragma once
30
31#include <ogdf/basic/Graph.h>
32#include <ogdf/basic/Logger.h>
35
36#include <cmath>
37#include <ostream>
38
39namespace ogdf {
40namespace energybased {
41namespace dtree {
42
43template<int Dim>
45public:
47 explicit DTreeEmbedder(const Graph& graph);
48
50 virtual ~DTreeEmbedder();
51
53 double position(node v, int d) const;
54
56 void setPosition(node v, int d, double coord);
57
59 double mass(node v) const;
60
62 void setMass(node v, double mass);
63
65 double edgeWeight(edge e) const;
66
68 void setEdgeWeight(edge e, double weight);
69
71 void resetForces();
72
74 template<typename ForceFunc, bool UseForcePrime>
75 void computeRepForces(ForceFunc forceFunc);
76
78 template<typename ForceFunc, bool UseForcePrime>
79 void computeRepForcesExact(ForceFunc forceFunc);
80
82 template<typename ForceFunc, bool UseForcePrime>
83 void computeRepForcesApprox(ForceFunc forceFunc);
84
86 template<typename AttrForceFunc, bool UseForcePrime>
87 void computeEdgeForces(AttrForceFunc attrForceFunc);
88
89#if 0
91 void computeEdgeForcesSq();
92#endif
93
95 double moveNodes(double timeStep);
96 double moveNodesByForcePrime();
97
98#if 0
100 template<typename RepForceFunc>
101 double doIteration(RepForceFunc repForceFunc);
102
104 double doIteration() { return doIteration(RepForceFunctionInvDist<Dim>); };
105
107 template<typename RepForceFunc>
108 void doIterations(int numIterations, double epsilon, RepForceFunc repForceFunc);
109
111 template<typename RepForceFunc>
112 void doIterations(int numIterations, double epsilon);
113#endif
114
116 template<typename RepForceFunc, typename AttrForceFunc, bool UseForcePrime>
117 void doIterationsTempl(int numIterations, double epsilon, RepForceFunc repForceFunc,
118 AttrForceFunc attrForceFunc);
119
120 template<typename RepForceFunc, typename AttrForceFunc>
121 void doIterationsStandard(int numIterations, double epsilon, RepForceFunc repForceFunc,
122 AttrForceFunc attrForceFunc);
123
124 template<typename RepForceFunc, typename AttrForceFunc>
125 void doIterationsNewton(int numIterations, double epsilon, RepForceFunc repForceFunc,
126 AttrForceFunc attrForceFunc);
127
128#if 0
129 template<typename RepForceFunc>
130 void doIterationsAdaptive(int numIterations, double epsilon, RepForceFunc repForceFunc);
131#endif
132
134 const Graph& graph() const;
135
137 void centerNodesAt(double centerBBox[Dim]);
138
140 void scaleNodes(double scaleFactor);
141
142private:
144 struct NodeInfo {
146 double position[Dim];
147
149 double force[Dim];
150
153
155 double mass;
156 };
157
160
163
166
169
171
173};
174
177
178template<int Dim>
179DTreeEmbedder<Dim>::DTreeEmbedder(const Graph& graph) : m_graph(graph) {
181 m_nodeInfo.init(m_graph);
182 for (node v = m_graph.firstNode(); v; v = v->succ()) {
183 m_nodeInfo[v].mass = 1.0;
184 }
185
186 m_edgeWeight.init(m_graph, 1.0);
188 m_defaultTimeStep = 0.125;
189}
190
191template<int Dim>
193 delete m_pTreeForce;
194}
195
196template<int Dim>
197template<typename ForceFunc, bool UseForcePrime>
199 double delta[Dim];
200 double force;
201 double force_prime;
202 for (node s = m_graph.firstNode(); s; s = s->succ()) {
203 for (node t = s->succ(); t; t = t->succ()) {
204 double dist = computeDeltaAndDistance<Dim>(m_nodeInfo[s].position,
205 m_nodeInfo[t].position, delta);
206
207 // evaluate the force function
208 forceFunc(dist, force, force_prime);
209
210 force = force / dist * mass(s) * mass(t);
211
212 // add the force to the existing
213 for (int d = 0; d < Dim; d++) {
214 m_nodeInfo[s].force[d] += force * delta[d];
215 m_nodeInfo[t].force[d] -= force * delta[d];
216 }
217
218 if (UseForcePrime) {
219 force_prime = force_prime * mass(s) * mass(t);
220 m_nodeInfo[s].force_prime += force_prime;
221 m_nodeInfo[t].force_prime += force_prime;
222 }
223 }
224 }
225}
226
227#if 0
228template<int Dim>
229template<typename ForceFunc>
230void DTreeEmbedder<Dim>::computeRepForcesExact(ForceFunc forceFunc)
231{
232 double delta[Dim];
233 double force;
234 for (node s = m_graph.firstNode(); s; s = s->succ()) {
235 for (node t = s->succ(); t; t = t->succ()) {
236 double dist = computeDeltaAndDistance<Dim>(m_nodeInfo[s].position, m_nodeInfo[t].position, delta);
237
238 // evaluate the force function
239 forceFunc(dist, force);
240
241 force = force / dist * mass(s) * mass(t);
242
243 // add the force to the existing
244 for (int d = 0; d < Dim; d++) {
245 m_nodeInfo[s].force[d] += force * delta[d];
246 m_nodeInfo[s].force[d] += force * delta[d];
247 }
248 }
249 }
250}
251#endif
252
253template<int Dim>
254template<typename ForceFunc, bool UseForcePrime>
256 int currIndex = 0;
257 // loop over all nodes
258 for (node v = m_graph.firstNode(); v; v = v->succ()) {
259 // update the node pos in the tree data structure
260 for (int d = 0; d < Dim; d++) {
261 m_pTreeForce->setPosition(currIndex, d, m_nodeInfo[v].position[d]);
262 }
263
264 // update the mass
265 m_pTreeForce->setMass(currIndex, m_nodeInfo[v].mass);
266 currIndex++;
267 }
268
269 // run the approximation
270 m_pTreeForce->template computeForces<ForceFunc, UseForcePrime>(forceFunc);
271
272 // reset the index
273 currIndex = 0;
274
275 // loop over all nodes
276 for (node v = m_graph.firstNode(); v; v = v->succ()) {
277 // read back the forces
278 for (int d = 0; d < Dim; d++) {
279 m_nodeInfo[v].force[d] += m_pTreeForce->force(currIndex, d);
280 }
281
282 if (UseForcePrime) {
283 m_nodeInfo[v].force_prime += m_pTreeForce->force_prime(currIndex);
284 }
285
286 currIndex++;
287 }
288}
289
290#if 0
291template<int Dim>
292template<typename ForceFunc>
294{
295 int currIndex = 0;
296 // loop over all nodes
297 for (node v = m_graph.firstNode(); v; v = v->succ()) {
298 // update the node pos in the tree data structure
299 for (int d = 0; d < Dim; d++) {
300 m_pTreeForce->setPosition(currIndex, d, m_nodeInfo[v].position[d]);
301 }
302
303 // update the mass
304 m_pTreeForce->setMass(currIndex, m_nodeInfo[v].mass);
305 currIndex++;
306 }
307
308 // run the approximation
309 m_pTreeForce->template computeForces<ForceFunc, true>(forceFunc);
310
311 // reset the index
312 currIndex = 0;
313
314 // loop over all nodes
315 for (node v = m_graph.firstNode(); v; v = v->succ()) {
316 // read back the forces
317 for (int d = 0; d < Dim; d++) {
318 m_nodeInfo[v].force[d] += m_pTreeForce->force(currIndex, d);
319 }
320
321 currIndex++;
322 }
323}
324#endif
325
326template<int Dim>
327template<typename ForceFunc, bool UseForcePrime>
328void DTreeEmbedder<Dim>::computeRepForces(ForceFunc forceFunc) {
329 if (m_graph.numberOfNodes() <= m_maxNumNodesExactRepForces) {
330 computeRepForcesExact<ForceFunc, UseForcePrime>(forceFunc);
331 } else {
332 computeRepForcesApprox<ForceFunc, UseForcePrime>(forceFunc);
333 }
334}
335
336#if 0
337template<int Dim>
338template<typename ForceFunc>
339void DTreeEmbedder<Dim>::computeRepForcesNewton(ForceFunc forceFunc)
340{
341 if (m_graph.numberOfNodes() <= m_maxNumNodesExactRepForces) {
342 computeRepForcesExactNewton(forceFunc);
343 } else {
344 computeRepForcesApproxNewton(forceFunc);
345 }
346}
347#endif
348
349template<int Dim>
350template<typename AttrForceFunc, bool UseForcePrime>
351void DTreeEmbedder<Dim>::computeEdgeForces(AttrForceFunc attrForceFunc) {
352 // for all edges
353 for (edge e = m_graph.firstEdge(); e; e = e->succ()) {
354 node s = e->source();
355 node t = e->target();
356
357 // check if this is a self loop
358 if (s == t) {
359 continue;
360 }
361
362 // s t delta vector
363 double delta[Dim];
364
365 // var for the squared distance of s and t
366 double dist_sq = 0.0;
367
368 // compute delta and sum up dist_sq
369 for (int d = 0; d < Dim; d++) {
370 delta[d] = m_nodeInfo[t].position[d] - m_nodeInfo[s].position[d];
371 dist_sq += delta[d] * delta[d];
372 }
373
374 // we take the log of the squared distance here
375#if 0
376 double f = log(dist_sq) * 0.5;
377#endif
378 double dist = (sqrt(dist_sq));
379
380 double f;
381 double f_prime;
382
383 if (UseForcePrime) {
384 attrForceFunc(dist, f, f_prime);
385
386 f_prime *= m_edgeWeight[e];
387
388 m_nodeInfo[s].force_prime += f_prime;
389 m_nodeInfo[t].force_prime += f_prime;
390 } else {
391 attrForceFunc(dist, f, f_prime);
392 }
393
394 f *= m_edgeWeight[e];
395
396 // compute delta and sum up dist_sq
397 for (int d = 0; d < Dim; d++) {
398 m_nodeInfo[s].force[d] += f * delta[d] / dist; // * s_scale;
399 m_nodeInfo[t].force[d] -= f * delta[d] / dist; // * t_scale;
400 }
401 }
402}
403
404#if 0
405template<int Dim>
406template<typename AttrForceFunc>
407void DTreeEmbedder<Dim>::computeEdgeForces(AttrForceFunc attrForceFunc)
408{
409 // for all edges
410 for (edge e = m_graph.firstEdge(); e; e = e->succ()) {
411 node s = e->source();
412 node t = e->target();
413
414 // check if this is a self loop
415 if (s == t) {
416 continue;
417 }
418
419 // s t delta vector
420 double delta[Dim];
421
422 // var for the squared distance of s and t
423 double dist_sq = 0.0;
424
425 // compute delta and sum up dist_sq
426 for (int d = 0; d < Dim; d++) {
427 delta[d] = m_nodeInfo[t].position[d] - m_nodeInfo[s].position[d];
428 dist_sq += delta[d] * delta[d];
429 }
430
431 // we take the log of the squared distance here
432# if 0
433 double f = log(dist_sq) * 0.5;
434# endif
435 double dist = (sqrt(dist_sq));
436 double f = (dist) * (dist) * m_edgeWeight[e];
437 double f_prime = 2.0 * dist * m_edgeWeight[e];
438 // for scaling the force accordingly
439# if 0
440 double s_scale = 1.0/(double)s->degree();
441 double t_scale = 1.0/(double)t->degree();
442# endif
443
444 m_nodeInfo[s].force_prime += f_prime;
445 m_nodeInfo[t].force_prime += f_prime;
446
447 // compute delta and sum up dist_sq
448 for (int d = 0; d < Dim; d++) {
449 m_nodeInfo[s].force[d] += f * delta[d] / dist;// * s_scale;
450 m_nodeInfo[t].force[d] -= f * delta[d] / dist;// * t_scale;
451 }
452 }
453}
454
455template<int Dim>
456void DTreeEmbedder<Dim>::computeEdgeForcesSq()
457{
458 for (node s = m_graph.firstNode(); s; s = s->succ()) {
459 double sum_f[Dim];
460 double sum_df[Dim];
461
462 double sum_ddf = 0.0;
463 // compute delta and sum up dist_sq
464 for (int d = 0; d < Dim; d++) {
465 sum_f[d] = 0.0;
466 sum_df[d] = 0.0;
467 }
468
469 for (adjEntry adj = s->firstAdj(); adj; adj = adj->succ()) {
470 node t = adj->twinNode();
471
472 // check if this is a self loop
473 if (s == t)
474 continue;
475
476 // s t delta vector
477 double delta[Dim];
478
479 // var for the squared distance of s and t
480 double dist_sq = 0.0;
481
482 // compute delta and sum up dist_sq
483 for (int d = 0; d < Dim; d++) {
484 delta[d] = m_nodeInfo[t].position[d] - m_nodeInfo[s].position[d];
485 dist_sq += delta[d] * delta[d];
486 }
487
488 double dist = sqrt(dist_sq);
489
490 double f = 1.0;
491 double df = 1.0;
492 // compute delta and sum up dist_sq
493 for (int d = 0; d < Dim; d++) {
494 sum_f[d] += f * delta[d] / dist;
495
496 }
497 sum_ddf += df;
498 }
499 for (int d = 0; d < Dim; d++) {
500 m_nodeInfo[s].force[d] = m_nodeInfo[s].force[d] + sum_f[d] / sum_ddf;
501 }
502 }
503}
504#endif
505
506template<int Dim>
508 // the maximum displacement
509 double maxDispl = 0.0;
510
511 // loop over all nodes
512 for (node v = m_graph.firstNode(); v; v = v->succ()) {
513 double displ_sq = 0.0;
514 // update the position by the force vec
515 for (int d = 0; d < Dim; d++) {
516 double displ = m_nodeInfo[v].force[d] / m_nodeInfo[v].force_prime;
517 m_nodeInfo[v].position[d] += displ;
518 displ_sq += displ * displ;
519 }
520
521 // we compare the square of the distance to save the sqrt here
522 if (maxDispl < displ_sq) {
523 maxDispl = displ_sq;
524 }
525 }
526 Logger::slout() << "sqrt(maxDispl)=" << sqrt(maxDispl) << std::endl;
527 return sqrt(maxDispl);
528}
529
530template<int Dim>
531double DTreeEmbedder<Dim>::moveNodes(double timeStep) {
532 // the maximum displacement
533 double maxDispl = 0.0;
534
535 // loop over all nodes
536 for (node v = m_graph.firstNode(); v; v = v->succ()) {
537 double displ_sq = 0.0;
538 // update the position by the force vec
539 for (int d = 0; d < Dim; d++) {
540 double displ = m_nodeInfo[v].force[d] * timeStep;
541 m_nodeInfo[v].position[d] += displ;
542 displ_sq += displ * displ;
543 }
544
545 // we compare the square of the distance to save the sqrt here
546 if (maxDispl < displ_sq) {
547 maxDispl = displ_sq;
548 }
549 }
550
551 Logger::slout() << "sqrt(maxDispl)=" << sqrt(maxDispl) << std::endl;
552 return sqrt(maxDispl);
553}
554
555template<int Dim>
557 // loop over all nodes
558 for (node v = m_graph.firstNode(); v; v = v->succ()) {
559 // reset the force vector
560 for (int d = 0; d < Dim; d++) {
561 m_nodeInfo[v].force[d] = 0.0;
562 }
563 m_nodeInfo[v].force_prime = 0.0;
564 }
565}
566
567#if 0
568template<int Dim>
569template<typename RepForceFunc, bool>
570double DTreeEmbedder<Dim>::doIteration(RepForceFunc repForceFunc)
571{
572 // reset forces
573 resetForces();
574
575 // the repulsive forces
576 computeRepForces(repForceFunc);
577
578 // edge forces
579 computeEdgeForces();
580
581 // move the nodes
582 return moveNodes(m_defaultTimeStep);
583}
584
585template<int Dim>
586template<typename RepForceFunc>
587void DTreeEmbedder<Dim>::doIterations(int numIterations, double epsilon, RepForceFunc repForceFunc)
588{
589 // init the error with epsilon
590 double maxDisplacement = epsilon;
591
592 // while error too big and we have iterations left
593 for (int i = 0; i < numIterations && maxDisplacement >= epsilon; ++i) {
594 // run it
595 maxDisplacement = doIteration(repForceFunc);
596 }
597}
598
599template<int Dim>
600template<typename RepForceFunc>
601void DTreeEmbedder<Dim>::doIterationsAdaptive(int numIterations, double epsilon, RepForceFunc repForceFunc)
602{
603 int iterationsUsed = 0;
604 // the current timeStep
605
606 double maxTimeStep = 1.0;
607 double timeStep = m_defaultTimeStep;
608
609 int progress = 0;
610 // scaling factor for the adaptive timeStep
611 double t = 0.99;
612
613 // init the error with epsilon
614 double maxDisplacement = 100000000.0;
615
616 // value that keeps track of the displacement
617 double lastMaxDisplacement = 0.0;
618
619 // while error too big and we have iterations left
620 for (int i = 0; i < numIterations && maxDisplacement >= epsilon; ++i) {
621 // reset forces
622 resetForces();
623
624 // the repulsive forces
625 computeRepForces(repForceFunc);
626
627 // edge forces
628 computeEdgeForces();
629
630 // move the nodes
631 maxDisplacement = moveNodes(timeStep);
632
633 // if this is not the first iteration
634 if (i > 0) {
635 if (maxDisplacement < lastMaxDisplacement * t) {
636 progress++;
637 timeStep = std::min(timeStep / t, maxTimeStep);
638 } else if (maxDisplacement > lastMaxDisplacement / t) {
639 timeStep = timeStep * t;
640 }
641 }
642 // save the maxDisplacement
643 lastMaxDisplacement = maxDisplacement;
644 iterationsUsed++;
645# if 0
646 Logger::slout() << maxDisplacement << std::endl;
647# endif
648 }
649 Logger::slout() << "IterationsUsed: " << iterationsUsed << " of " << numIterations << " energy: " << lastMaxDisplacement << std::endl;
650}
651
652template<int Dim>
653struct MyVec
654{
655 double x[Dim];
656};
657#endif
658
659template<int Dim>
660template<typename RepForceFunc, typename AttrForceFunc, bool UseForcePrime>
661void DTreeEmbedder<Dim>::doIterationsTempl(int numIterations, double epsilon,
662 RepForceFunc repForceFunc, AttrForceFunc attrForceFunc) {
663 if (m_graph.numberOfNodes() < 2) {
664 return;
665 }
666
667 int numIterationsUsed = 0;
669 << "doIterationsNewton: V = " << m_graph.numberOfNodes()
670 << " E = " << m_graph.numberOfEdges() << " Iterations " << numIterations << std::endl;
671
672 // init the error with epsilon
673 double maxDisplacement = 10000.0;
674
675 // while error too big and we have iterations left
676 for (int i = 0; i < numIterations && maxDisplacement > epsilon; ++i) {
677 numIterationsUsed++;
678 // reset forces
679 resetForces();
680
681 // the repulsive forces
682 computeRepForces<RepForceFunc, UseForcePrime>(repForceFunc);
683
684 // edge forces
685 computeEdgeForces<AttrForceFunc, UseForcePrime>(attrForceFunc);
686
687 // move the nodes
688 if (UseForcePrime) {
689 maxDisplacement = moveNodesByForcePrime();
690 } else {
691 maxDisplacement = moveNodes(0.1);
692 }
693 }
694
695 Logger::slout() << "Needed " << numIterationsUsed << " of " << numIterations << std::endl;
696}
697
698template<int Dim>
699template<typename RepForceFunc, typename AttrForceFunc>
700void DTreeEmbedder<Dim>::doIterationsStandard(int numIterations, double epsilon,
701 RepForceFunc repForceFunc, AttrForceFunc attrForceFunc) {
702 doIterationsTempl<RepForceFunc, AttrForceFunc, false>(numIterations, epsilon, repForceFunc,
703 attrForceFunc);
704}
705
706template<int Dim>
707template<typename RepForceFunc, typename AttrForceFunc>
708void DTreeEmbedder<Dim>::doIterationsNewton(int numIterations, double epsilon,
709 RepForceFunc repForceFunc, AttrForceFunc attrForceFunc) {
710 doIterationsTempl<RepForceFunc, AttrForceFunc, true>(numIterations, epsilon, repForceFunc,
711 attrForceFunc);
712}
713
714template<int Dim>
715void DTreeEmbedder<Dim>::centerNodesAt(double centerBBox[Dim]) {
716 double bboxMin[Dim];
717 double bboxMax[Dim];
718
719 // initial values
720 for (int d = 0; d < Dim; d++) {
721 bboxMin[d] = bboxMax[d] = position(m_graph.firstEdge(), d);
722 }
723
724 // no magic here
725 for (node v = m_graph.firstNode(); v; v = v->succ()) {
726 for (int d = 0; d < Dim; d++) {
727 bboxMin[d] = std::min(bboxMin[d], position(v, d));
728 bboxMax[d] = std::max(bboxMax[d], position(v, d));
729 }
730 }
731
732 double delta[Dim];
733 for (int d = 0; d < Dim; d++) {
734 delta[d] = -(bboxMin[d] + bboxMax[d]) * 0.5;
735 }
736
737 for (node v = m_graph.firstNode(); v; v = v->succ()) {
738 for (int d = 0; d < Dim; d++) {
739 setPosition(v, d, delta[d]);
740 }
741 }
742}
743
744template<int Dim>
745void DTreeEmbedder<Dim>::scaleNodes(double scaleFactor) {
746 for (node v = m_graph.firstNode(); v; v = v->succ()) {
747 for (int d = 0; d < Dim; d++) {
748 setPosition(v, d, position(v, d) * scaleFactor);
749 }
750 }
751}
752
753template<int Dim>
754double DTreeEmbedder<Dim>::position(node v, int d) const {
755 return m_nodeInfo[v].position[d];
756}
757
758template<int Dim>
759void DTreeEmbedder<Dim>::setPosition(node v, int d, double coord) {
760 m_nodeInfo[v].position[d] = coord;
761}
762
763template<int Dim>
765 return m_nodeInfo[v].mass;
766}
767
768template<int Dim>
769void DTreeEmbedder<Dim>::setMass(node v, double mass) {
770 m_nodeInfo[v].mass = mass;
771}
772
773template<int Dim>
775 return m_graph;
776}
777
778template<int Dim>
780 m_edgeWeight[e] = weight;
781}
782
783template<int Dim>
785 return m_edgeWeight[e];
786}
787
788}
789}
790}
Includes declaration of graph class.
Contains logging functionality.
adjEntry succ() const
Returns the successor in the adjacency list.
Definition Graph_d.h:219
Class for the representation of edges.
Definition Graph_d.h:364
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:866
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition Graph_d.h:979
node firstNode() const
Returns the first node in the list of all nodes.
Definition Graph_d.h:994
static std::ostream & slout(Level level=Level::Default)
stream for logging-output (global)
Definition Logger.h:193
Class for the representation of nodes.
Definition Graph_d.h:241
int degree() const
Returns the degree of the node (indegree + outdegree).
Definition Graph_d.h:284
node succ() const
Returns the successor in the list of all nodes.
Definition Graph_d.h:293
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Definition Graph_d.h:287
void centerNodesAt(double centerBBox[Dim])
computes the bounding box and all nodes are translated such that bbox center is at centerBBox
NodeArray< NodeInfo > m_nodeInfo
node states of all nodes
void doIterationsNewton(int numIterations, double epsilon, RepForceFunc repForceFunc, AttrForceFunc attrForceFunc)
void setMass(node v, double mass)
sets the mass of a node v
DTreeEmbedder(const Graph &graph)
constructor with a given graph, allocates memory and does initialization
void computeEdgeForces(AttrForceFunc attrForceFunc)
computes the edge forces for one iteration
void computeRepForces(ForceFunc forceFunc)
computes the repulsive forces
void setPosition(node v, int d, double coord)
sets the d-th coordinate of node v to coord
void doIterationsTempl(int numIterations, double epsilon, RepForceFunc repForceFunc, AttrForceFunc attrForceFunc)
does multiple iterations using the given repulsive force function
void resetForces()
sets the forces of all nodes to 0
void doIterationsStandard(int numIterations, double epsilon, RepForceFunc repForceFunc, AttrForceFunc attrForceFunc)
double position(node v, int d) const
returns the d-th coordinate of node v
const Graph & graph() const
returns the graph
double moveNodes(double timeStep)
moves the nodes by the computed force vector
DTreeForce< Dim > * m_pTreeForce
the tree force approx
void computeRepForcesExact(ForceFunc forceFunc)
computes the repulsive forces for one iteration in O(n^2)
EdgeArray< double > m_edgeWeight
the weight of the edges
void computeRepForcesApprox(ForceFunc forceFunc)
uses the tree code to approximate the repulsive forces in O(nlogn) for one iteration
double mass(node v) const
returns the mass of node v
double edgeWeight(edge e) const
returns the edge weight
void setEdgeWeight(edge e, double weight)
sets the weight of an edge
void scaleNodes(double scaleFactor)
changes the position of nodes according to a given scale factor
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition Graph_d.h:717
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition Graph_d.h:659
AdjElement * adjEntry
The type of adjacency entries.
Definition Graph_d.h:79
NodeElement * node
The type of nodes.
Definition Graph_d.h:71
The namespace for all OGDF objects.